diff options
Diffstat (limited to 'drivers/media')
156 files changed, 11166 insertions, 3693 deletions
diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 772d6112fb3b..c578a529e7a8 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,4 +2,7 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := video/ radio/ dvb/ common/ +obj-y := common/ +obj-$(CONFIG_VIDEO_DEV) += video/ +obj-$(CONFIG_VIDEO_DEV) += radio/ +obj-$(CONFIG_DVB) += dvb/ diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c index ab7a1fba4427..a0e700d7a4a4 100644 --- a/drivers/media/common/ir-common.c +++ b/drivers/media/common/ir-common.c @@ -1,5 +1,4 @@ /* - * $Id: ir-common.c,v 1.11 2005/07/07 14:44:43 mchehab Exp $ * * some common structs and functions to handle infrared remotes via * input layer ... @@ -335,6 +334,72 @@ int ir_dump_samples(u32 *samples, int count) return 0; } +/* decode raw samples, pulse distance coding used by NEC remotes */ +int ir_decode_pulsedistance(u32 *samples, int count, int low, int high) +{ + int i,last,bit,len; + u32 curBit; + u32 value; + + /* find start burst */ + for (i = len = 0; i < count * 32; i++) { + bit = getbit(samples,i); + if (bit) { + len++; + } else { + if (len >= 29) + break; + len = 0; + } + } + + /* start burst to short */ + if (len < 29) + return 0xffffffff; + + /* find start silence */ + for (len = 0; i < count * 32; i++) { + bit = getbit(samples,i); + if (bit) { + break; + } else { + len++; + } + } + + /* silence to short */ + if (len < 7) + return 0xffffffff; + + /* go decoding */ + len = 0; + last = 1; + value = 0; curBit = 1; + for (; i < count * 32; i++) { + bit = getbit(samples,i); + if (last) { + if(bit) { + continue; + } else { + len = 1; + } + } else { + if (bit) { + if (len > (low + high) /2) + value |= curBit; + curBit <<= 1; + if (curBit == 1) + break; + } else { + len++; + } + } + last = bit; + } + + return value; +} + /* decode raw samples, biphase coding, used by rc5 for example */ int ir_decode_biphase(u32 *samples, int count, int low, int high) { @@ -383,6 +448,7 @@ EXPORT_SYMBOL_GPL(ir_input_keydown); EXPORT_SYMBOL_GPL(ir_extract_bits); EXPORT_SYMBOL_GPL(ir_dump_samples); EXPORT_SYMBOL_GPL(ir_decode_biphase); +EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); /* * Local variables: diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index c04fd11526e0..37888989ea2e 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -1,5 +1,4 @@ #include <media/saa7146_vv.h> -#include <linux/version.h> #define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1) diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 781f23f0cbcc..fec6beab8c28 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -1,4 +1,3 @@ -#include <linux/version.h> #include <media/saa7146_vv.h> static u32 saa7146_i2c_func(struct i2c_adapter *adapter) @@ -387,8 +386,6 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in /* exported algorithm data */ static struct i2c_algorithm saa7146_algo = { - .name = "saa7146 i2c algorithm", - .id = I2C_ALGO_SAA7146, .master_xfer = saa7146_i2c_xfer, .functionality = saa7146_i2c_func, }; @@ -404,15 +401,12 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c saa7146_i2c_reset(dev); if( NULL != i2c_adapter ) { -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) - i2c_adapter->data = dev; -#else BUG_ON(!i2c_adapter->class); i2c_set_adapdata(i2c_adapter,dev); -#endif + i2c_adapter->dev.parent = &dev->pci->dev; i2c_adapter->algo = &saa7146_algo; i2c_adapter->algo_data = NULL; - i2c_adapter->id = I2C_ALGO_SAA7146; + i2c_adapter->id = I2C_HW_SAA7146; i2c_adapter->timeout = SAA7146_I2C_TIMEOUT; i2c_adapter->retries = SAA7146_I2C_RETRIES; } diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 0410cc96a48e..47e28b0ee951 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -164,12 +164,11 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, return 0; } -static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct flexcop_device *fc = fe->dvb->priv; div = params->frequency / 125; @@ -180,7 +179,7 @@ static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_fronten if (params->frequency < 1500000) buf[3] |= 0x10; - if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } @@ -335,8 +334,103 @@ static struct mt312_config skystar23_samsung_tbdu18132_config = { .pll_set = skystar23_samsung_tbdu18132_pll_set, }; + +static u8 alps_tdee4_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0xf8, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, + 0xff, 0xff, +}; + static struct stv0297_config alps_tdee4_stv0297_config = { .demod_address = 0x1c, + .inittab = alps_tdee4_stv0297_inittab, // .invert = 1, // .pll_set = alps_tdee4_stv0297_pll_set, }; @@ -370,7 +464,7 @@ int flexcop_frontend_init(struct flexcop_device *fc) info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address); } else /* try the cable dvb (stv0297) */ - if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) { + if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_CABLE; info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address); } else diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index be4266d4ae91..56495cb6cd02 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -172,8 +172,6 @@ static u32 flexcop_i2c_func(struct i2c_adapter *adapter) } static struct i2c_algorithm flexcop_algo = { - .name = "FlexCop I2C algorithm", - .id = I2C_ALGO_BIT, .master_xfer = flexcop_master_xfer, .functionality = flexcop_i2c_func, }; @@ -192,7 +190,6 @@ int flexcop_i2c_init(struct flexcop_device *fc) fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL; fc->i2c_adap.algo = &flexcop_algo; fc->i2c_adap.algo_data = NULL; - fc->i2c_adap.id = I2C_ALGO_BIT; if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0) return ret; diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index b12545f093f8..1e85d16491b0 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -1,5 +1,5 @@ config DVB_BT8XX - tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards" + tristate "BT8xx based PCI cards" depends on DVB_CORE && PCI && VIDEO_BT848 select DVB_MT352 select DVB_SP887X @@ -8,8 +8,8 @@ config DVB_BT8XX select DVB_OR51211 help Support for PCI cards based on the Bt8xx PCI bridge. Examples are - the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards and - pcHDTV HD2000 cards. + the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, + the pcHDTV HD2000 cards, and certain AVerMedia cards. Since these cards have no MPEG decoder onboard, they transmit only compressed MPEG data over the PCI bus, so you need diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 3c5a8e273c4a..f29571450038 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -1,7 +1,7 @@ /* * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card * - * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> + * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> * * large parts based on the bttv driver * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de) @@ -219,7 +219,7 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin, controlreg &= ~0x1f; controlreg |= 0x1b; - btwrite(cpu_to_le32(bt->risc_dma), BT878_ARISC_START); + btwrite(bt->risc_dma, BT878_ARISC_START); /* original int mask had : * 6 2 8 4 0 diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index 837623f7fcdf..a73baf00ca39 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -1,7 +1,7 @@ /* bt878.h - Bt878 audio module (register offsets) - Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> + Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 07a0b0a968a6..34a837a1abf4 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1,5 +1,4 @@ /* - Frontend/Card driver for TwinHan DST Frontend Copyright (C) 2003 Jamie Honan Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) @@ -19,7 +18,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -28,31 +26,45 @@ #include <linux/vmalloc.h> #include <linux/delay.h> #include <asm/div64.h> - #include "dvb_frontend.h" #include "dst_priv.h" #include "dst_common.h" - static unsigned int verbose = 1; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); -static unsigned int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug messages, default is 0 (yes)"); - static unsigned int dst_addons; module_param(dst_addons, int, 0644); MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); -#define dprintk if (debug) printk - -#define HAS_LOCK 1 -#define ATTEMPT_TUNE 2 -#define HAS_POWER 4 - -static void dst_packsize(struct dst_state* state, int psize) +#define HAS_LOCK 1 +#define ATTEMPT_TUNE 2 +#define HAS_POWER 4 + +#define DST_ERROR 0 +#define DST_NOTICE 1 +#define DST_INFO 2 +#define DST_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while(0) + + +static void dst_packsize(struct dst_state *state, int psize) { union dst_gpio_packet bits; @@ -60,7 +72,7 @@ static void dst_packsize(struct dst_state* state, int psize) bt878_device_control(state->bt, DST_IG_TS, &bits); } -int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay) +int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay) { union dst_gpio_packet enb; union dst_gpio_packet bits; @@ -68,63 +80,55 @@ int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int enb.enb.mask = mask; enb.enb.enable = enbb; - if (verbose > 4) - dprintk("%s: mask=[%04x], enbb=[%04x], outhigh=[%04x]\n", __FUNCTION__, mask, enbb, outhigh); + dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk("%s: dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n", __FUNCTION__, err, mask, enbb); + dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); return -EREMOTEIO; } udelay(1000); /* because complete disabling means no output, no need to do output packet */ if (enbb == 0) return 0; - if (delay) msleep(10); - bits.outp.mask = enbb; bits.outp.highvals = outhigh; - if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk("%s: dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)\n", __FUNCTION__, err, enbb, outhigh); + dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); return -EREMOTEIO; } + return 0; } EXPORT_SYMBOL(dst_gpio_outb); -int dst_gpio_inb(struct dst_state *state, u8 * result) +int dst_gpio_inb(struct dst_state *state, u8 *result) { union dst_gpio_packet rd_packet; int err; *result = 0; - if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err); return -EREMOTEIO; } - *result = (u8) rd_packet.rd.value; + return 0; } EXPORT_SYMBOL(dst_gpio_inb); int rdc_reset_state(struct dst_state *state) { - if (verbose > 1) - dprintk("%s: Resetting state machine\n", __FUNCTION__); - + dprintk(verbose, DST_INFO, 1, "Resetting state machine"); if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } - msleep(10); - if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); msleep(10); return -1; } @@ -135,16 +139,14 @@ EXPORT_SYMBOL(rdc_reset_state); int rdc_8820_reset(struct dst_state *state) { - if (verbose > 1) - dprintk("%s: Resetting DST\n", __FUNCTION__); - + dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } udelay(1000); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } @@ -155,10 +157,11 @@ EXPORT_SYMBOL(rdc_8820_reset); int dst_pio_enable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } udelay(1000); + return 0; } EXPORT_SYMBOL(dst_pio_enable); @@ -166,7 +169,7 @@ EXPORT_SYMBOL(dst_pio_enable); int dst_pio_disable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { - dprintk("%s: dst_gpio_outb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) @@ -183,19 +186,16 @@ int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) for (i = 0; i < 200; i++) { if (dst_gpio_inb(state, &reply) < 0) { - dprintk("%s: dst_gpio_inb ERROR !\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); return -1; } - if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { - if (verbose > 4) - dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); + dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); return 1; } msleep(10); } - if (verbose > 1) - dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); + dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); return 0; } @@ -203,7 +203,7 @@ EXPORT_SYMBOL(dst_wait_dst_ready); int dst_error_recovery(struct dst_state *state) { - dprintk("%s: Trying to return from previous errors...\n", __FUNCTION__); + dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); dst_pio_disable(state); msleep(10); dst_pio_enable(state); @@ -215,7 +215,7 @@ EXPORT_SYMBOL(dst_error_recovery); int dst_error_bailout(struct dst_state *state) { - dprintk("%s: Trying to bailout from previous error...\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); rdc_8820_reset(state); dst_pio_disable(state); msleep(10); @@ -224,17 +224,15 @@ int dst_error_bailout(struct dst_state *state) } EXPORT_SYMBOL(dst_error_bailout); - -int dst_comm_init(struct dst_state* state) +int dst_comm_init(struct dst_state *state) { - if (verbose > 1) - dprintk ("%s: Initializing DST..\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Initializing DST."); if ((dst_pio_enable(state)) < 0) { - dprintk("%s: PIO Enable Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); return -1; } if ((rdc_reset_state(state)) < 0) { - dprintk("%s: RDC 8820 State RESET Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) @@ -246,36 +244,33 @@ int dst_comm_init(struct dst_state* state) } EXPORT_SYMBOL(dst_comm_init); - int write_dst(struct dst_state *state, u8 *data, u8 len) { struct i2c_msg msg = { - .addr = state->config->demod_address,.flags = 0,.buf = data,.len = len + .addr = state->config->demod_address, + .flags = 0, + .buf = data, + .len = len }; int err; - int cnt; - if (debug && (verbose > 4)) { - u8 i; - if (verbose > 4) { - dprintk("%s writing [ ", __FUNCTION__); - for (i = 0; i < len; i++) - dprintk("%02x ", data[i]); - dprintk("]\n"); - } - } + u8 cnt, i; + + dprintk(verbose, DST_NOTICE, 0, "writing [ "); + for (i = 0; i < len; i++) + dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); + dprintk(verbose, DST_NOTICE, 0, "]\n"); + for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk("%s: _write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); + dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); dst_error_recovery(state); continue; } else break; } - if (cnt >= 2) { - if (verbose > 1) - printk("%s: RDC 8820 RESET...\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); dst_error_bailout(state); return -1; @@ -285,36 +280,37 @@ int write_dst(struct dst_state *state, u8 *data, u8 len) } EXPORT_SYMBOL(write_dst); -int read_dst(struct dst_state *state, u8 * ret, u8 len) +int read_dst(struct dst_state *state, u8 *ret, u8 len) { - struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len }; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = ret, + .len = len + }; + int err; int cnt; for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - - dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]); + dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); dst_error_recovery(state); - continue; } else break; } if (cnt >= 2) { - if (verbose > 1) - printk("%s: RDC 8820 RESET...\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); dst_error_bailout(state); return -1; } - if (debug && (verbose > 4)) { - dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); - for (err = 1; err < len; err++) - dprintk(" 0x%x", ret[err]); - if (err > 1) - dprintk("\n"); - } + dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); + for (err = 1; err < len; err++) + dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); + if (err > 1) + dprintk(verbose, DST_DEBUG, 0, "\n"); return 0; } @@ -323,19 +319,16 @@ EXPORT_SYMBOL(read_dst); static int dst_set_polarization(struct dst_state *state) { switch (state->voltage) { - case SEC_VOLTAGE_13: // vertical - printk("%s: Polarization=[Vertical]\n", __FUNCTION__); - state->tx_tuna[8] &= ~0x40; //1 - break; - - case SEC_VOLTAGE_18: // horizontal - printk("%s: Polarization=[Horizontal]\n", __FUNCTION__); - state->tx_tuna[8] |= 0x40; // 0 - break; - - case SEC_VOLTAGE_OFF: - - break; + case SEC_VOLTAGE_13: /* Vertical */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); + state->tx_tuna[8] &= ~0x40; + break; + case SEC_VOLTAGE_18: /* Horizontal */ + dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); + state->tx_tuna[8] |= 0x40; + break; + case SEC_VOLTAGE_OFF: + break; } return 0; @@ -344,14 +337,12 @@ static int dst_set_polarization(struct dst_state *state) static int dst_set_freq(struct dst_state *state, u32 freq) { state->frequency = freq; - if (debug > 4) - dprintk("%s: set Frequency %u\n", __FUNCTION__, freq); + dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); if (state->dst_type == DST_TYPE_IS_SAT) { freq = freq / 1000; if (freq < 950 || freq > 2150) return -EINVAL; - state->tx_tuna[2] = (freq >> 8); state->tx_tuna[3] = (u8) freq; state->tx_tuna[4] = 0x01; @@ -360,27 +351,25 @@ static int dst_set_freq(struct dst_state *state, u32 freq) if (freq < 1531) state->tx_tuna[8] |= 0x04; } - } else if (state->dst_type == DST_TYPE_IS_TERR) { freq = freq / 1000; if (freq < 137000 || freq > 858000) return -EINVAL; - state->tx_tuna[2] = (freq >> 16) & 0xff; state->tx_tuna[3] = (freq >> 8) & 0xff; state->tx_tuna[4] = (u8) freq; - } else if (state->dst_type == DST_TYPE_IS_CABLE) { + freq = freq / 1000; state->tx_tuna[2] = (freq >> 16) & 0xff; state->tx_tuna[3] = (freq >> 8) & 0xff; state->tx_tuna[4] = (u8) freq; - } else return -EINVAL; + return 0; } -static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) +static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) { state->bandwidth = bandwidth; @@ -388,103 +377,95 @@ static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) return 0; switch (bandwidth) { - case BANDWIDTH_6_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x06; - else { - state->tx_tuna[6] = 0x06; - state->tx_tuna[7] = 0x00; - } - break; - - case BANDWIDTH_7_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x07; - else { - state->tx_tuna[6] = 0x07; - state->tx_tuna[7] = 0x00; - } - break; - - case BANDWIDTH_8_MHZ: - if (state->dst_hw_cap & DST_TYPE_HAS_CA) - state->tx_tuna[7] = 0x08; - else { - state->tx_tuna[6] = 0x08; - state->tx_tuna[7] = 0x00; - } - break; - - default: - return -EINVAL; + case BANDWIDTH_6_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x06; + else { + state->tx_tuna[6] = 0x06; + state->tx_tuna[7] = 0x00; + } + break; + case BANDWIDTH_7_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x07; + else { + state->tx_tuna[6] = 0x07; + state->tx_tuna[7] = 0x00; + } + break; + case BANDWIDTH_8_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x08; + else { + state->tx_tuna[6] = 0x08; + state->tx_tuna[7] = 0x00; + } + break; + default: + return -EINVAL; } + return 0; } -static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion) +static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) { state->inversion = inversion; switch (inversion) { - case INVERSION_OFF: // Inversion = Normal - state->tx_tuna[8] &= ~0x80; - break; - - case INVERSION_ON: - state->tx_tuna[8] |= 0x80; - break; - default: - return -EINVAL; + case INVERSION_OFF: /* Inversion = Normal */ + state->tx_tuna[8] &= ~0x80; + break; + case INVERSION_ON: + state->tx_tuna[8] |= 0x80; + break; + default: + return -EINVAL; } + return 0; } -static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec) +static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) { state->fec = fec; return 0; } -static fe_code_rate_t dst_get_fec(struct dst_state* state) +static fe_code_rate_t dst_get_fec(struct dst_state *state) { return state->fec; } -static int dst_set_symbolrate(struct dst_state* state, u32 srate) +static int dst_set_symbolrate(struct dst_state *state, u32 srate) { - u8 *val; u32 symcalc; u64 sval; state->symbol_rate = srate; - if (state->dst_type == DST_TYPE_IS_TERR) { return 0; } - if (debug > 4) - dprintk("%s: set symrate %u\n", __FUNCTION__, srate); + dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); srate /= 1000; - val = &state->tx_tuna[0]; - if (state->type_flags & DST_TYPE_HAS_SYMDIV) { sval = srate; sval <<= 20; do_div(sval, 88000); symcalc = (u32) sval; - - if (debug > 4) - dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); - - val[5] = (u8) (symcalc >> 12); - val[6] = (u8) (symcalc >> 4); - val[7] = (u8) (symcalc << 4); + dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); + state->tx_tuna[5] = (u8) (symcalc >> 12); + state->tx_tuna[6] = (u8) (symcalc >> 4); + state->tx_tuna[7] = (u8) (symcalc << 4); } else { - val[5] = (u8) (srate >> 16) & 0x7f; - val[6] = (u8) (srate >> 8); - val[7] = (u8) srate; + state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } + state->tx_tuna[8] &= ~0x20; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (srate > 8000) + state->tx_tuna[8] |= 0x20; } - val[8] &= ~0x20; - if (srate > 8000) - val[8] |= 0x20; return 0; } @@ -496,32 +477,27 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio state->modulation = modulation; switch (modulation) { - case QAM_16: - state->tx_tuna[8] = 0x10; - break; - - case QAM_32: - state->tx_tuna[8] = 0x20; - break; - - case QAM_64: - state->tx_tuna[8] = 0x40; - break; - - case QAM_128: - state->tx_tuna[8] = 0x80; - break; - - case QAM_256: - state->tx_tuna[8] = 0x00; - break; - - case QPSK: - case QAM_AUTO: - case VSB_8: - case VSB_16: - default: - return -EINVAL; + case QAM_16: + state->tx_tuna[8] = 0x10; + break; + case QAM_32: + state->tx_tuna[8] = 0x20; + break; + case QAM_64: + state->tx_tuna[8] = 0x40; + break; + case QAM_128: + state->tx_tuna[8] = 0x80; + break; + case QAM_256: + state->tx_tuna[8] = 0x00; + break; + case QPSK: + case QAM_AUTO: + case VSB_8: + case VSB_16: + default: + return -EINVAL; } @@ -534,7 +510,7 @@ static fe_modulation_t dst_get_modulation(struct dst_state *state) } -u8 dst_check_sum(u8 * buf, u32 len) +u8 dst_check_sum(u8 *buf, u32 len) { u32 i; u8 val = 0; @@ -549,26 +525,24 @@ EXPORT_SYMBOL(dst_check_sum); static void dst_type_flags_print(u32 type_flags) { - printk("DST type flags :"); + dprintk(verbose, DST_ERROR, 0, "DST type flags :"); if (type_flags & DST_TYPE_HAS_NEWTUNE) - printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); if (type_flags & DST_TYPE_HAS_TS204) - printk(" 0x%x ts204", DST_TYPE_HAS_TS204); + dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); if (type_flags & DST_TYPE_HAS_SYMDIV) - printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); if (type_flags & DST_TYPE_HAS_FW_1) - printk(" 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); if (type_flags & DST_TYPE_HAS_FW_2) - printk(" 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); if (type_flags & DST_TYPE_HAS_FW_3) - printk(" 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); -// if ((type_flags & DST_TYPE_HAS_FW_BUILD) && new_fw) - - printk("\n"); + dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); + dprintk(verbose, DST_ERROR, 0, "\n"); } -static int dst_type_print (u8 type) +static int dst_type_print(u8 type) { char *otype; switch (type) { @@ -585,10 +559,10 @@ static int dst_type_print (u8 type) break; default: - printk("%s: invalid dst type %d\n", __FUNCTION__, type); + dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); return -EINVAL; } - printk("DST type : %s\n", otype); + dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); return 0; } @@ -700,7 +674,7 @@ struct dst_types dst_tlist[] = { .offset = 1, .dst_type = DST_TYPE_IS_CABLE, .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 - | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + | DST_TYPE_HAS_FW_2, .dst_feature = DST_TYPE_HAS_CA }, @@ -708,7 +682,7 @@ struct dst_types dst_tlist[] = { .device_id = "DCTNEW", .offset = 1, .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD, .dst_feature = 0 }, @@ -716,7 +690,7 @@ struct dst_types dst_tlist[] = { .device_id = "DTT-CI", .offset = 1, .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, .dst_feature = 0 }, @@ -756,6 +730,71 @@ struct dst_types dst_tlist[] = { }; +static int dst_get_mac(struct dst_state *state) +{ + u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_mac[7] = dst_check_sum(get_mac, 7); + if (dst_command(state, get_mac, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->mac_address, '\0', 8); + memcpy(&state->mac_address, &state->rxbuffer, 6); + dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]", + state->mac_address[0], state->mac_address[1], state->mac_address[2], + state->mac_address[4], state->mac_address[5], state->mac_address[6]); + + return 0; +} + +static int dst_fw_ver(struct dst_state *state) +{ + u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_ver[7] = dst_check_sum(get_ver, 7); + if (dst_command(state, get_ver, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->fw_version, '\0', 8); + memcpy(&state->fw_version, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", + state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, + state->fw_version[1], + state->fw_version[5], state->fw_version[6], + state->fw_version[4], state->fw_version[3], state->fw_version[2]); + + return 0; +} + +static int dst_card_type(struct dst_state *state) +{ + u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_type[7] = dst_check_sum(get_type, 7); + if (dst_command(state, get_type, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->card_info, '\0', 8); + memcpy(&state->card_info, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); + + return 0; +} + +static int dst_get_vendor(struct dst_state *state) +{ + u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + get_vendor[7] = dst_check_sum(get_vendor, 7); + if (dst_command(state, get_vendor, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + memset(&state->vendor, '\0', 8); + memcpy(&state->vendor, &state->rxbuffer, 8); + dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); + + return 0; +} static int dst_get_device_id(struct dst_state *state) { @@ -772,53 +811,45 @@ static int dst_get_device_id(struct dst_state *state) if (write_dst(state, device_type, FIXED_COMM)) return -1; /* Write failed */ - if ((dst_pio_disable(state)) < 0) return -1; - if (read_dst(state, &reply, GET_ACK)) return -1; /* Read failure */ - if (reply != ACK) { - dprintk("%s: Write not Acknowledged! [Reply=0x%02x]\n", __FUNCTION__, reply); + dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); return -1; /* Unack'd write */ } - if (!dst_wait_dst_ready(state, DEVICE_INIT)) return -1; /* DST not ready yet */ - if (read_dst(state, state->rxbuffer, FIXED_COMM)) return -1; dst_pio_disable(state); - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk("%s: Checksum failure! \n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Checksum failure!"); return -1; /* Checksum failure */ } - state->rxbuffer[7] = '\0'; - for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE (dst_tlist); i++, p_dst_type++) { + for (i = 0, p_dst_type = dst_tlist; i < ARRAY_SIZE(dst_tlist); i++, p_dst_type++) { if (!strncmp (&state->rxbuffer[p_dst_type->offset], p_dst_type->device_id, strlen (p_dst_type->device_id))) { use_type_flags = p_dst_type->type_flags; use_dst_type = p_dst_type->dst_type; /* Card capabilities */ state->dst_hw_cap = p_dst_type->dst_feature; - printk ("%s: Recognise [%s]\n", __FUNCTION__, p_dst_type->device_id); + dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id); break; } } if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) { - printk("%s: Unable to recognize %s or %s\n", __FUNCTION__, &state->rxbuffer[0], &state->rxbuffer[1]); - printk("%s: please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); + dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); use_dst_type = DST_TYPE_IS_SAT; use_type_flags = DST_TYPE_HAS_SYMDIV; } - dst_type_print(use_dst_type); state->type_flags = use_type_flags; state->dst_type = use_dst_type; @@ -834,7 +865,7 @@ static int dst_get_device_id(struct dst_state *state) static int dst_probe(struct dst_state *state) { if ((rdc_8820_reset(state)) < 0) { - dprintk("%s: RDC 8820 RESET Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); return -1; } if (dst_addons & DST_TYPE_HAS_CA) @@ -843,80 +874,87 @@ static int dst_probe(struct dst_state *state) msleep(100); if ((dst_comm_init(state)) < 0) { - dprintk("%s: DST Initialization Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); return -1; } msleep(100); if (dst_get_device_id(state) < 0) { - dprintk("%s: unknown device.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "unknown device."); return -1; } + if (dst_get_mac(state) < 0) { + dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); + return 0; + } + if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { + if (dst_fw_ver(state) < 0) { + dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); + return 0; + } + if (dst_card_type(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); + return 0; + } + if (dst_get_vendor(state) < 0) { + dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); + return 0; + } + } return 0; } -int dst_command(struct dst_state* state, u8 * data, u8 len) +int dst_command(struct dst_state *state, u8 *data, u8 len) { u8 reply; if ((dst_comm_init(state)) < 0) { - dprintk("%s: DST Communication Initialization Failed.\n", __FUNCTION__); + dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); return -1; } - if (write_dst(state, data, len)) { - if (verbose > 1) - dprintk("%s: Tring to recover.. \n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Tring to recover.. "); if ((dst_error_recovery(state)) < 0) { - dprintk("%s: Recovery Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); return -1; } return -1; } if ((dst_pio_disable(state)) < 0) { - dprintk("%s: PIO Disable Failed.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) udelay(3000); - if (read_dst(state, &reply, GET_ACK)) { - if (verbose > 1) - dprintk("%s: Trying to recover.. \n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { - dprintk("%s: Recovery Failed.\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Recovery Failed."); return -1; } return -1; } - if (reply != ACK) { - dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply); + dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); return -1; } if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) return 0; - -// udelay(3000); if (state->type_flags & DST_TYPE_HAS_FW_1) udelay(3000); else udelay(2000); - if (!dst_wait_dst_ready(state, NO_DELAY)) return -1; - if (read_dst(state, state->rxbuffer, FIXED_COMM)) { - if (verbose > 1) - dprintk("%s: Trying to recover.. \n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { - dprintk("%s: Recovery failed.\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "Recovery failed."); return -1; } return -1; } - if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk("%s: checksum failure\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "checksum failure"); return -1; } @@ -924,11 +962,11 @@ int dst_command(struct dst_state* state, u8 * data, u8 len) } EXPORT_SYMBOL(dst_command); -static int dst_get_signal(struct dst_state* state) +static int dst_get_signal(struct dst_state *state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); + //dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { state->decode_lock = state->decode_strength = state->decode_snr = 0; return 0; @@ -955,13 +993,12 @@ static int dst_get_signal(struct dst_state* state) return 0; } -static int dst_tone_power_cmd(struct dst_state* state) +static int dst_tone_power_cmd(struct dst_state *state) { u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; if (state->dst_type == DST_TYPE_IS_TERR) return 0; - paket[4] = state->tx_tuna[4]; paket[2] = state->tx_tuna[2]; paket[3] = state->tx_tuna[3]; @@ -971,61 +1008,53 @@ static int dst_tone_power_cmd(struct dst_state* state) return 0; } -static int dst_get_tuna(struct dst_state* state) +static int dst_get_tuna(struct dst_state *state) { int retval; if ((state->diseq_flags & ATTEMPT_TUNE) == 0) return 0; - state->diseq_flags &= ~(HAS_LOCK); if (!dst_wait_dst_ready(state, NO_DELAY)) return 0; - - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) /* how to get variable length reply ???? */ retval = read_dst(state, state->rx_tuna, 10); - } else { + else retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); - } - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "read not successful"); return 0; } - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "checksum failure ? "); return 0; } } else { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); + dprintk(verbose, DST_INFO, 1, "checksum failure? "); return 0; } } if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) return 0; state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; - state->decode_lock = 1; state->diseq_flags |= HAS_LOCK; return 1; } -static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage); +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); -static int dst_write_tuna(struct dvb_frontend* fe) +static int dst_write_tuna(struct dvb_frontend *fe) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; int retval; u8 reply; - if (debug > 4) - dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags); - + dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); state->decode_freq = 0; state->decode_lock = state->decode_strength = state->decode_snr = 0; if (state->dst_type == DST_TYPE_IS_SAT) { @@ -1035,35 +1064,31 @@ static int dst_write_tuna(struct dvb_frontend* fe) state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); if ((dst_comm_init(state)) < 0) { - dprintk("%s: DST Communication initialization failed.\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); return -1; } - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); retval = write_dst(state, &state->tx_tuna[0], 10); - } else { state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); retval = write_dst(state, &state->tx_tuna[2], FIXED_COMM); } if (retval < 0) { dst_pio_disable(state); - dprintk("%s: write not successful\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "write not successful"); return retval; } - if ((dst_pio_disable(state)) < 0) { - dprintk("%s: DST PIO disable failed !\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); return -1; } - if ((read_dst(state, &reply, GET_ACK) < 0)) { - dprintk("%s: read verify not successful.\n", __FUNCTION__); + dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); return -1; } if (reply != ACK) { - dprintk("%s: write not acknowledged 0x%02x \n", __FUNCTION__, reply); + dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); return 0; } state->diseq_flags |= ATTEMPT_TUNE; @@ -1085,14 +1110,13 @@ static int dst_write_tuna(struct dvb_frontend* fe) * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 */ -static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; if (state->dst_type != DST_TYPE_IS_SAT) return 0; - if (cmd->msg_len == 0 || cmd->msg_len > 4) return -EINVAL; memcpy(&paket[3], cmd->msg, cmd->msg_len); @@ -1101,65 +1125,61 @@ static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* return 0; } -static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { int need_cmd; - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; state->voltage = voltage; - if (state->dst_type != DST_TYPE_IS_SAT) return 0; need_cmd = 0; - switch (voltage) { - case SEC_VOLTAGE_13: - case SEC_VOLTAGE_18: - if ((state->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - state->diseq_flags |= HAS_POWER; - state->tx_tuna[4] = 0x01; - break; - case SEC_VOLTAGE_OFF: + switch (voltage) { + case SEC_VOLTAGE_13: + case SEC_VOLTAGE_18: + if ((state->diseq_flags & HAS_POWER) == 0) need_cmd = 1; - state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); - state->tx_tuna[4] = 0x00; - break; - - default: - return -EINVAL; + state->diseq_flags |= HAS_POWER; + state->tx_tuna[4] = 0x01; + break; + case SEC_VOLTAGE_OFF: + need_cmd = 1; + state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); + state->tx_tuna[4] = 0x00; + break; + default: + return -EINVAL; } + if (need_cmd) dst_tone_power_cmd(state); return 0; } -static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; state->tone = tone; - if (state->dst_type != DST_TYPE_IS_SAT) return 0; switch (tone) { - case SEC_TONE_OFF: - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) - state->tx_tuna[2] = 0x00; - else - state->tx_tuna[2] = 0xff; - - break; - - case SEC_TONE_ON: - state->tx_tuna[2] = 0x02; - break; + case SEC_TONE_OFF: + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + state->tx_tuna[2] = 0x00; + else + state->tx_tuna[2] = 0xff; + break; - default: - return -EINVAL; + case SEC_TONE_ON: + state->tx_tuna[2] = 0x02; + break; + default: + return -EINVAL; } dst_tone_power_cmd(state); @@ -1172,16 +1192,14 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) if (state->dst_type != DST_TYPE_IS_SAT) return 0; - state->minicmd = minicmd; - switch (minicmd) { - case SEC_MINI_A: - state->tx_tuna[3] = 0x02; - break; - case SEC_MINI_B: - state->tx_tuna[3] = 0xff; - break; + case SEC_MINI_A: + state->tx_tuna[3] = 0x02; + break; + case SEC_MINI_B: + state->tx_tuna[3] = 0xff; + break; } dst_tone_power_cmd(state); @@ -1189,42 +1207,37 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) } -static int dst_init(struct dvb_frontend* fe) +static int dst_init(struct dvb_frontend *fe) { - struct dst_state* state = fe->demodulator_priv; - static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 }; - static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 }; - static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; -// state->inversion = INVERSION_ON; + struct dst_state *state = fe->demodulator_priv; + + static u8 sat_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x00, 0x73, 0x21, 0x00, 0x00 }; + static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; + static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + state->inversion = INVERSION_OFF; state->voltage = SEC_VOLTAGE_13; state->tone = SEC_TONE_OFF; - state->symbol_rate = 29473000; - state->fec = FEC_AUTO; state->diseq_flags = 0; state->k22 = 0x02; state->bandwidth = BANDWIDTH_7_MHZ; state->cur_jiff = jiffies; - if (state->dst_type == DST_TYPE_IS_SAT) { - state->frequency = 950000; - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna)); - } else if (state->dst_type == DST_TYPE_IS_TERR) { - state->frequency = 137000000; - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna)); - } else if (state->dst_type == DST_TYPE_IS_CABLE) { - state->frequency = 51000000; - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna)); - } + if (state->dst_type == DST_TYPE_IS_SAT) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_TERR) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_CABLE) + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); return 0; } -static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; *status = 0; if (state->diseq_flags & HAS_LOCK) { @@ -1236,9 +1249,9 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) return 0; } -static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) +static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; dst_get_signal(state); *strength = state->decode_strength; @@ -1246,9 +1259,9 @@ static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) return 0; } -static int dst_read_snr(struct dvb_frontend* fe, u16* snr) +static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; dst_get_signal(state); *snr = state->decode_snr; @@ -1256,28 +1269,24 @@ static int dst_read_snr(struct dvb_frontend* fe, u16* snr) return 0; } -static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; dst_set_freq(state, p->frequency); - if (verbose > 4) - dprintk("Set Frequency=[%d]\n", p->frequency); + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); -// dst_set_inversion(state, p->inversion); if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); dst_set_symbolrate(state, p->u.qpsk.symbol_rate); dst_set_polarization(state); - if (verbose > 4) - dprintk("Set Symbolrate=[%d]\n", p->u.qpsk.symbol_rate); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); - } else if (state->dst_type == DST_TYPE_IS_TERR) { + } else if (state->dst_type == DST_TYPE_IS_TERR) dst_set_bandwidth(state, p->u.ofdm.bandwidth); - } else if (state->dst_type == DST_TYPE_IS_CABLE) { + else if (state->dst_type == DST_TYPE_IS_CABLE) { dst_set_fec(state, p->u.qam.fec_inner); dst_set_symbolrate(state, p->u.qam.symbol_rate); dst_set_modulation(state, p->u.qam.modulation); @@ -1287,16 +1296,14 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet return 0; } -static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; p->frequency = state->decode_freq; -// p->inversion = state->inversion; if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) p->inversion = state->inversion; - p->u.qpsk.symbol_rate = state->symbol_rate; p->u.qpsk.fec_inner = dst_get_fec(state); } else if (state->dst_type == DST_TYPE_IS_TERR) { @@ -1304,16 +1311,15 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet } else if (state->dst_type == DST_TYPE_IS_CABLE) { p->u.qam.symbol_rate = state->symbol_rate; p->u.qam.fec_inner = dst_get_fec(state); -// p->u.qam.modulation = QAM_AUTO; p->u.qam.modulation = dst_get_modulation(state); } return 0; } -static void dst_release(struct dvb_frontend* fe) +static void dst_release(struct dvb_frontend *fe) { - struct dst_state* state = fe->demodulator_priv; + struct dst_state *state = fe->demodulator_priv; kfree(state); } @@ -1321,9 +1327,8 @@ static struct dvb_frontend_ops dst_dvbt_ops; static struct dvb_frontend_ops dst_dvbs_ops; static struct dvb_frontend_ops dst_dvbc_ops; -struct dst_state* dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) +struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) { - /* check if the ASIC is there */ if (dst_probe(state) < 0) { if (state) @@ -1336,17 +1341,14 @@ struct dst_state* dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad case DST_TYPE_IS_TERR: memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); break; - case DST_TYPE_IS_CABLE: memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); break; - case DST_TYPE_IS_SAT: memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); break; - default: - printk("%s: unknown DST type. please report to the LinuxTV.org DVB mailinglist.\n", __FUNCTION__); + dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); if (state) kfree(state); @@ -1374,12 +1376,9 @@ static struct dvb_frontend_ops dst_dvbt_ops = { }, .release = dst_release, - .init = dst_init, - .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, - .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, @@ -1401,16 +1400,12 @@ static struct dvb_frontend_ops dst_dvbs_ops = { }, .release = dst_release, - .init = dst_init, - .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, - .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, - .diseqc_send_burst = dst_send_burst, .diseqc_send_master_cmd = dst_set_diseqc, .set_voltage = dst_set_voltage, @@ -1432,18 +1427,14 @@ static struct dvb_frontend_ops dst_dvbc_ops = { }, .release = dst_release, - .init = dst_init, - .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, - .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, }; - MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver"); MODULE_AUTHOR("Jamie Honan, Manu Abraham"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index bfaacd5fc20f..6776a592045f 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -18,30 +18,42 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - - #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/string.h> - #include <linux/dvb/ca.h> #include "dvbdev.h" #include "dvb_frontend.h" - #include "dst_ca.h" #include "dst_common.h" +#define DST_CA_ERROR 0 +#define DST_CA_NOTICE 1 +#define DST_CA_INFO 2 +#define DST_CA_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_CA_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_CA_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_CA_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \ + else if ((x > DST_CA_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ## arg); \ + } \ +} while(0) + + static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); -static unsigned int debug = 1; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug messages, default is 1 (yes)"); - -#define dprintk if (debug) printk - /* Need some more work */ static int ca_set_slot_descr(void) { @@ -61,27 +73,20 @@ static int put_checksum(u8 *check_string, int length) { u8 i = 0, checksum = 0; - if (verbose > 3) { - dprintk("%s: ========================= Checksum calculation ===========================\n", __FUNCTION__); - dprintk("%s: String Length=[0x%02x]\n", __FUNCTION__, length); + dprintk(verbose, DST_CA_DEBUG, 1, " ========================= Checksum calculation ==========================="); + dprintk(verbose, DST_CA_DEBUG, 1, " String Length=[0x%02x]", length); + dprintk(verbose, DST_CA_DEBUG, 1, " String=["); - dprintk("%s: String=[", __FUNCTION__); - } while (i < length) { - if (verbose > 3) - dprintk(" %02x", check_string[i]); + dprintk(verbose, DST_CA_DEBUG, 0, " %02x", check_string[i]); checksum += check_string[i]; i++; } - if (verbose > 3) { - dprintk(" ]\n"); - dprintk("%s: Sum=[%02x]\n", __FUNCTION__, checksum); - } + dprintk(verbose, DST_CA_DEBUG, 0, " ]\n"); + dprintk(verbose, DST_CA_DEBUG, 1, "Sum=[%02x]\n", checksum); check_string[length] = ~checksum + 1; - if (verbose > 3) { - dprintk("%s: Checksum=[%02x]\n", __FUNCTION__, check_string[length]); - dprintk("%s: ==========================================================================\n", __FUNCTION__); - } + dprintk(verbose, DST_CA_DEBUG, 1, " Checksum=[%02x]", check_string[length]); + dprintk(verbose, DST_CA_DEBUG, 1, " =========================================================================="); return 0; } @@ -94,30 +99,26 @@ static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 msleep(65); if (write_dst(state, data, len)) { - dprintk("%s: Write not successful, trying to recover\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); dst_error_recovery(state); return -1; } - if ((dst_pio_disable(state)) < 0) { - dprintk("%s: DST PIO disable failed.\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); return -1; } - if (read_dst(state, &reply, GET_ACK) < 0) { - dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); dst_error_recovery(state); return -1; } - if (read) { if (! dst_wait_dst_ready(state, LONG_DELAY)) { - dprintk("%s: 8820 not ready\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); return -1; } - if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ - dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); dst_error_recovery(state); return -1; } @@ -133,8 +134,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, while (dst_ca_comm_err < RETRIES) { dst_comm_init(state); - if (verbose > 2) - dprintk("%s: Put Command\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); if (dst_ci_command(state, data, ca_string, len, read)) { // If error dst_error_recovery(state); dst_ca_comm_err++; // work required here. @@ -153,18 +153,15 @@ static int ca_get_app_info(struct dst_state *state) put_checksum(&command[0], command[0]); if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { - dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); return -1; } - if (verbose > 1) { - dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); - - dprintk("%s: ================================ CI Module Application Info ======================================\n", __FUNCTION__); - dprintk("%s: Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]\n", - __FUNCTION__, state->messages[7], (state->messages[8] << 8) | state->messages[9], - (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12])); - dprintk("%s: ==================================================================================================\n", __FUNCTION__); - } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); + dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]", + state->messages[7], (state->messages[8] << 8) | state->messages[9], + (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12])); + dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); return 0; } @@ -177,31 +174,26 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, put_checksum(&slot_command[0], slot_command[0]); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { - dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); return -1; } - if (verbose > 1) - dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); /* Will implement the rest soon */ - if (verbose > 1) { - dprintk("%s: Slot cap = [%d]\n", __FUNCTION__, slot_cap[7]); - dprintk("===================================\n"); - for (i = 0; i < 8; i++) - dprintk(" %d", slot_cap[i]); - dprintk("\n"); - } + dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < 8; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); p_ca_caps->slot_num = 1; p_ca_caps->slot_type = 1; p_ca_caps->descr_num = slot_cap[7]; p_ca_caps->descr_type = 1; - - if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) { + if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) return -EFAULT; - } return 0; } @@ -222,46 +214,37 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s put_checksum(&slot_command[0], 7); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { - dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); return -1; } - if (verbose > 1) - dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__); + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); /* Will implement the rest soon */ - if (verbose > 1) { - dprintk("%s: Slot info = [%d]\n", __FUNCTION__, slot_info[3]); - dprintk("===================================\n"); - for (i = 0; i < 8; i++) - dprintk(" %d", slot_info[i]); - dprintk("\n"); - } + dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]); + dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); + for (i = 0; i < 8; i++) + dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]); + dprintk(verbose, DST_CA_INFO, 0, "\n"); if (slot_info[4] & 0x80) { p_ca_slot_info->flags = CA_CI_MODULE_PRESENT; p_ca_slot_info->num = 1; p_ca_slot_info->type = CA_CI; - } - else if (slot_info[4] & 0x40) { + } else if (slot_info[4] & 0x40) { p_ca_slot_info->flags = CA_CI_MODULE_READY; p_ca_slot_info->num = 1; p_ca_slot_info->type = CA_CI; - } - else { + } else p_ca_slot_info->flags = 0; - } - if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) { + if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) return -EFAULT; - } return 0; } - - static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) { u8 i = 0; @@ -270,24 +253,21 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) return -EFAULT; - if (p_ca_message->msg) { - if (verbose > 3) - dprintk("Message = [%02x %02x %02x]\n", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]); + dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]); for (i = 0; i < 3; i++) { command = command | p_ca_message->msg[i]; if (i < 2) command = command << 8; } - if (verbose > 3) - dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command); + dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); switch (command) { - case CA_APP_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; + case CA_APP_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; break; } } @@ -298,10 +278,13 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) { if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { - hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ - hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ - } - else { + hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ + hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ + } else { + if (length > 247) { + dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); + return -1; + } hw_buffer->msg[0] = (length & 0xff) + 7; hw_buffer->msg[1] = 0x40; hw_buffer->msg[2] = 0x03; @@ -309,6 +292,11 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, hw_buffer->msg[4] = 0x03; hw_buffer->msg[5] = length & 0xff; hw_buffer->msg[6] = 0x00; + /* + * Need to compute length for EN50221 section 8.3.2, for the time being + * assuming 8.3.2 is not applicable + */ + memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length); } return 0; } @@ -317,13 +305,12 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) { if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { - dprintk("%s: DST-CI Command failed.\n", __FUNCTION__); - dprintk("%s: Resetting DST.\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); + dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); rdc_reset_state(state); return -1; } - if (verbose > 2) - dprintk("%s: DST-CI Command succes.\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes."); return 0; } @@ -334,130 +321,47 @@ u32 asn_1_decode(u8 *asn_1_array) u32 length = 0; length_field = asn_1_array[0]; - dprintk("%s: Length field=[%02x]\n", __FUNCTION__, length_field); + dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field); if (length_field < 0x80) { length = length_field & 0x7f; - dprintk("%s: Length=[%02x]\n", __FUNCTION__, length); + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length); } else { word_count = length_field & 0x7f; for (count = 0; count < word_count; count++) { length = (length | asn_1_array[count + 1]) << 8; - dprintk("%s: Length=[%04x]\n", __FUNCTION__, length); + dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); } } return length; } -static int init_buffer(u8 *buffer, u32 length) -{ - u32 i; - for (i = 0; i < length; i++) - buffer[i] = 0; - - return 0; -} - static int debug_string(u8 *msg, u32 length, u32 offset) { u32 i; - dprintk(" String=[ "); + dprintk(verbose, DST_CA_DEBUG, 0, " String=[ "); for (i = offset; i < length; i++) - dprintk("%02x ", msg[i]); - dprintk("]\n"); - - return 0; -} - -static int copy_string(u8 *destination, u8 *source, u32 dest_offset, u32 source_offset, u32 length) -{ - u32 i; - dprintk("%s: Copying [", __FUNCTION__); - for (i = 0; i < length; i++) { - destination[i + dest_offset] = source[i + source_offset]; - dprintk(" %02x", source[i + source_offset]); - } - dprintk("]\n"); - - return i; -} - -static int modify_4_bits(u8 *message, u32 pos) -{ - message[pos] &= 0x0f; + dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]); + dprintk(verbose, DST_CA_DEBUG, 0, "]\n"); return 0; } - - static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) { - u32 length = 0, count = 0; - u8 asn_1_words, program_header_length; - u16 program_info_length = 0, es_info_length = 0; - u32 hw_offset = 0, buf_offset = 0, i; - u8 dst_tag_length; + u32 length = 0; + u8 tag_length = 8; length = asn_1_decode(&p_ca_message->msg[3]); - dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length); - dprintk("%s: ASN.1 ", __FUNCTION__); - debug_string(&p_ca_message->msg[4], length, 0); // length does not include tag and length + dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length); + debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */ - init_buffer(hw_buffer->msg, length); + memset(hw_buffer->msg, '\0', length); handle_dst_tag(state, p_ca_message, hw_buffer, length); + put_checksum(hw_buffer->msg, hw_buffer->msg[0]); - hw_offset = 7; - asn_1_words = 1; // just a hack to test, should compute this one - buf_offset = 3; - program_header_length = 6; - dst_tag_length = 7; - -// debug_twinhan_ca_params(state, p_ca_message, hw_buffer, reply, query, length, hw_offset, buf_offset); -// dprintk("%s: Program Header(BUF)", __FUNCTION__); -// debug_string(&p_ca_message->msg[4], program_header_length, 0); -// dprintk("%s: Copying Program header\n", __FUNCTION__); - copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + asn_1_words), program_header_length); - buf_offset += program_header_length, hw_offset += program_header_length; - modify_4_bits(hw_buffer->msg, (hw_offset - 2)); - if (state->type_flags & DST_TYPE_HAS_INC_COUNT) { // workaround - dprintk("%s: Probably an ASIC bug !!!\n", __FUNCTION__); - debug_string(hw_buffer->msg, (hw_offset + program_header_length), 0); - hw_buffer->msg[hw_offset - 1] += 1; - } - -// dprintk("%s: Program Header(HW), Count=[%d]", __FUNCTION__, count); -// debug_string(hw_buffer->msg, hw_offset, 0); - - program_info_length = ((program_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; - dprintk("%s: Program info length=[%02x]\n", __FUNCTION__, program_info_length); - if (program_info_length) { - count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + 1), (program_info_length + 1) ); // copy next elem, not current - buf_offset += count, hw_offset += count; -// dprintk("%s: Program level ", __FUNCTION__); -// debug_string(hw_buffer->msg, hw_offset, 0); - } - - buf_offset += 1;// hw_offset += 1; - for (i = buf_offset; i < length; i++) { -// dprintk("%s: Stream Header ", __FUNCTION__); - count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, buf_offset, 5); - modify_4_bits(hw_buffer->msg, (hw_offset + 3)); - - hw_offset += 5, buf_offset += 5, i += 4; -// debug_string(hw_buffer->msg, hw_offset, (hw_offset - 5)); - es_info_length = ((es_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; - dprintk("%s: ES info length=[%02x]\n", __FUNCTION__, es_info_length); - if (es_info_length) { - // copy descriptors @ STREAM level - dprintk("%s: Descriptors @ STREAM level...!!! \n", __FUNCTION__); - } - - } - hw_buffer->msg[length + dst_tag_length] = dst_check_sum(hw_buffer->msg, (length + dst_tag_length)); -// dprintk("%s: Total length=[%d], Checksum=[%02x]\n", __FUNCTION__, (length + dst_tag_length), hw_buffer->msg[length + dst_tag_length]); - debug_string(hw_buffer->msg, (length + dst_tag_length + 1), 0); // dst tags also - write_to_8820(state, hw_buffer, (length + dst_tag_length + 1), reply); // checksum + debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */ + write_to_8820(state, hw_buffer, (length + tag_length), reply); return 0; } @@ -471,26 +375,24 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message /* Do test board */ /* Not there yet but soon */ - /* CA PMT Reply capable */ if (ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { - dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); return -1; } /* Process CA PMT Reply */ /* will implement soon */ - dprintk("%s: Not there yet\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Not there yet"); } /* CA PMT Reply not capable */ if (!ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { - dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); return -1; } - if (verbose > 3) - dprintk("%s: ca_set_pmt.. success !\n", __FUNCTION__); + dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); /* put a dummy message */ } @@ -506,11 +408,10 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer; if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - if (verbose > 3) - dprintk("%s\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " "); if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) return -EFAULT; @@ -525,51 +426,35 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, if (i < 2) command = command << 8; } - if (verbose > 3) - dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command); + dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); switch (command) { - case CA_PMT: - if (verbose > 3) -// dprintk("Command = SEND_CA_PMT\n"); - dprintk("Command = SEND_CA_PMT\n"); -// if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started - dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 3) - dprintk("%s: -->CA_PMT Success !\n", __FUNCTION__); -// retval = dummy_set_pmt(state, p_ca_message, hw_buffer, 0, 0); - - break; - - case CA_PMT_REPLY: - if (verbose > 3) - dprintk("Command = CA_PMT_REPLY\n"); - /* Have to handle the 2 basic types of cards here */ - if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { - dprintk("%s: -->CA_PMT_REPLY Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 3) - dprintk("%s: -->CA_PMT_REPLY Success !\n", __FUNCTION__); - - /* Certain boards do behave different ? */ -// retval = ca_set_pmt(state, p_ca_message, hw_buffer, 1, 1); - - case CA_APP_INFO_ENQUIRY: // only for debugging - if (verbose > 3) - dprintk("%s: Getting Cam Application information\n", __FUNCTION__); - - if ((ca_get_app_info(state)) < 0) { - dprintk("%s: -->CA_APP_INFO_ENQUIRY Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 3) - dprintk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__); - - break; + case CA_PMT: + dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); + break; + case CA_PMT_REPLY: + dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); + /* Have to handle the 2 basic types of cards here */ + if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); + break; + case CA_APP_INFO_ENQUIRY: // only for debugging + dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); + + if ((ca_get_app_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); + break; } } return 0; @@ -584,121 +469,88 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct ca_msg *p_ca_message; if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) { - dprintk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); return -ENOMEM; } - /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ switch (cmd) { - case CA_SEND_MSG: - if (verbose > 1) - dprintk("%s: Sending message\n", __FUNCTION__); - if ((ca_send_message(state, p_ca_message, arg)) < 0) { - dprintk("%s: -->CA_SEND_MSG Failed !\n", __FUNCTION__); - return -1; - } - - break; - - case CA_GET_MSG: - if (verbose > 1) - dprintk("%s: Getting message\n", __FUNCTION__); - if ((ca_get_message(state, p_ca_message, arg)) < 0) { - dprintk("%s: -->CA_GET_MSG Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_MSG Success !\n", __FUNCTION__); - - break; - - case CA_RESET: - if (verbose > 1) - dprintk("%s: Resetting DST\n", __FUNCTION__); - dst_error_bailout(state); - msleep(4000); - - break; - - case CA_GET_SLOT_INFO: - if (verbose > 1) - dprintk("%s: Getting Slot info\n", __FUNCTION__); - if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { - dprintk("%s: -->CA_GET_SLOT_INFO Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_SLOT_INFO Success !\n", __FUNCTION__); - - break; - - case CA_GET_CAP: - if (verbose > 1) - dprintk("%s: Getting Slot capabilities\n", __FUNCTION__); - if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { - dprintk("%s: -->CA_GET_CAP Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_CAP Success !\n", __FUNCTION__); - - break; - - case CA_GET_DESCR_INFO: - if (verbose > 1) - dprintk("%s: Getting descrambler description\n", __FUNCTION__); - if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { - dprintk("%s: -->CA_GET_DESCR_INFO Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_GET_DESCR_INFO Success !\n", __FUNCTION__); - - break; - - case CA_SET_DESCR: - if (verbose > 1) - dprintk("%s: Setting descrambler\n", __FUNCTION__); - if ((ca_set_slot_descr()) < 0) { - dprintk("%s: -->CA_SET_DESCR Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_SET_DESCR Success !\n", __FUNCTION__); - - break; - - case CA_SET_PID: - if (verbose > 1) - dprintk("%s: Setting PID\n", __FUNCTION__); - if ((ca_set_pid()) < 0) { - dprintk("%s: -->CA_SET_PID Failed !\n", __FUNCTION__); - return -1; - } - if (verbose > 1) - dprintk("%s: -->CA_SET_PID Success !\n", __FUNCTION__); - - default: - return -EOPNOTSUPP; - }; + case CA_SEND_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Sending message"); + if ((ca_send_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); + return -1; + } + break; + case CA_GET_MSG: + dprintk(verbose, DST_CA_INFO, 1, " Getting message"); + if ((ca_get_message(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); + break; + case CA_RESET: + dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST"); + dst_error_bailout(state); + msleep(4000); + break; + case CA_GET_SLOT_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); + if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); + break; + case CA_GET_CAP: + dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); + if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); + break; + case CA_GET_DESCR_INFO: + dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); + if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); + break; + case CA_SET_DESCR: + dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); + if ((ca_set_slot_descr()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); + break; + case CA_SET_PID: + dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); + if ((ca_set_pid()) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); + default: + return -EOPNOTSUPP; + }; return 0; } static int dst_ca_open(struct inode *inode, struct file *file) { - if (verbose > 4) - dprintk("%s:Device opened [%p]\n", __FUNCTION__, file); + dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file); try_module_get(THIS_MODULE); return 0; @@ -706,27 +558,24 @@ static int dst_ca_open(struct inode *inode, struct file *file) static int dst_ca_release(struct inode *inode, struct file *file) { - if (verbose > 4) - dprintk("%s:Device closed.\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " Device closed."); module_put(THIS_MODULE); return 0; } -static int dst_ca_read(struct file *file, char __user * buffer, size_t length, loff_t * offset) +static int dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { int bytes_read = 0; - if (verbose > 4) - dprintk("%s:Device read.\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); return bytes_read; } -static int dst_ca_write(struct file *file, const char __user * buffer, size_t length, loff_t * offset) +static int dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) { - if (verbose > 4) - dprintk("%s:Device write.\n", __FUNCTION__); + dprintk(verbose, DST_CA_DEBUG, 1, " Device write."); return 0; } @@ -751,8 +600,7 @@ static struct dvb_device dvbdev_ca = { int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter) { struct dvb_device *dvbdev; - if (verbose > 4) - dprintk("%s:registering DST-CA device\n", __FUNCTION__); + dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA); return 0; } diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index ef532a6aceaa..3281a6ca3685 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -61,7 +61,6 @@ #define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ #define DST_TYPE_HAS_SESSION 128 - #define RDC_8820_PIO_0_DISABLE 0 #define RDC_8820_PIO_0_ENABLE 1 #define RDC_8820_INT 2 @@ -114,6 +113,10 @@ struct dst_state { fe_sec_mini_cmd_t minicmd; fe_modulation_t modulation; u8 messages[256]; + u8 mac_address[8]; + u8 fw_version[8]; + u8 card_info[8]; + u8 vendor[8]; }; struct dst_types { @@ -124,15 +127,12 @@ struct dst_types { u32 dst_feature; }; - - struct dst_config { /* the ASIC i2c address */ u8 demod_address; }; - int rdc_reset_state(struct dst_state *state); int rdc_8820_reset(struct dst_state *state); diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 6f857c6091f3..c5c7672cd538 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -32,9 +32,7 @@ #include "dvbdev.h" #include "dvb_demux.h" #include "dvb_frontend.h" - #include "dvb-bt8xx.h" - #include "bt878.h" static int debug; @@ -43,9 +41,11 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define dprintk( args... ) \ - do { \ + do \ if (debug) printk(KERN_DEBUG args); \ - } while (0) + while (0) + +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ static void dvb_bt8xx_task(unsigned long data) { @@ -119,14 +119,12 @@ static struct bt878 __init *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci unsigned int card_nr; /* Hmm, n squared. Hope n is small */ - for (card_nr = 0; card_nr < bt878_num; card_nr++) { + for (card_nr = 0; card_nr < bt878_num; card_nr++) if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) return &bt878[card_nr]; - } return NULL; } - static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) { static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; @@ -154,16 +152,21 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ unsigned char bs = 0; unsigned char cp = 0; - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 542000000) cp = 0xb4; - else if (params->frequency < 771000000) cp = 0xbc; - else cp = 0xf4; + if (params->frequency < 542000000) + cp = 0xb4; + else if (params->frequency < 771000000) + cp = 0xbc; + else + cp = 0xf4; - if (params->frequency == 0) bs = 0x03; - else if (params->frequency < 443250000) bs = 0x02; - else bs = 0x08; + if (params->frequency == 0) + bs = 0x03; + else if (params->frequency < 443250000) + bs = 0x02; + else + bs = 0x08; pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address pllbuf[1] = div >> 8; @@ -175,7 +178,6 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ } static struct mt352_config thomson_dtt7579_config = { - .demod_address = 0x0f, .demod_init = thomson_dtt7579_demod_init, .pll_set = thomson_dtt7579_pll_set, @@ -183,25 +185,26 @@ static struct mt352_config thomson_dtt7579_config = { static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { - u32 freq = params->frequency; - - int i, a, n, pump; - u32 band, pll; + u32 freq = params->frequency; + int i, a, n, pump; + u32 band, pll; - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, - 1576000,1718000,1856000,2036000,2150000}; - u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, - 0x00102000,0x00104000,0x00108000,0x00110000, - 0x00120000,0x00140000}; + u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, + 1576000,1718000,1856000,2036000,2150000}; + u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, + 0x00102000,0x00104000,0x00108000,0x00110000, + 0x00120000,0x00140000}; -#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ + #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); /* This is really the bit driving the tuner chip cx24108 */ - if(freq<950000) freq=950000; /* kHz */ - if(freq>2150000) freq=2150000; /* satellite IF is 950..2150MHz */ + if (freq<950000) + freq = 950000; /* kHz */ + else if (freq>2150000) + freq = 2150000; /* satellite IF is 950..2150MHz */ /* decide which VCO to use for the input frequency */ for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++); @@ -228,25 +231,22 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete cx24110_pll_write(fe,0x500c0000); cx24110_pll_write(fe,0x83f1f800); cx24110_pll_write(fe,pll); -/* writereg(client,0x56,0x7f);*/ + //writereg(client,0x56,0x7f); return 0; } static int pinnsat_pll_init(struct dvb_frontend* fe) { - return 0; + return 0; } - static struct cx24110_config pctvsat_config = { - .demod_address = 0x55, .pll_init = pinnsat_pll_init, .pll_set = cx24108_pll_set, }; - static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; @@ -258,15 +258,23 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front div = (36000000 + params->frequency + 83333) / 166666; cfg = 0x88; - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 2; - else cpump = 3; + if (params->frequency < 175000000) + cpump = 2; + else if (params->frequency < 390000000) + cpump = 1; + else if (params->frequency < 470000000) + cpump = 2; + else if (params->frequency < 750000000) + cpump = 2; + else + cpump = 3; - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; + if (params->frequency < 175000000) + band_select = 0x0e; + else if (params->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; @@ -285,14 +293,11 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s } static struct sp887x_config microtune_mt7202dtf_config = { - .demod_address = 0x70, .pll_set = microtune_mt7202dtf_pll_set, .request_firmware = microtune_mt7202dtf_request_firmware, }; - - static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) { static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; @@ -303,7 +308,6 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); udelay(2000); mt352_write(fe, mt352_reset, sizeof(mt352_reset)); @@ -323,28 +327,45 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct unsigned char bs = 0; unsigned char cp = 0; - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 150000000) cp = 0xB4; - else if (params->frequency < 173000000) cp = 0xBC; - else if (params->frequency < 250000000) cp = 0xB4; - else if (params->frequency < 400000000) cp = 0xBC; - else if (params->frequency < 420000000) cp = 0xF4; - else if (params->frequency < 470000000) cp = 0xFC; - else if (params->frequency < 600000000) cp = 0xBC; - else if (params->frequency < 730000000) cp = 0xF4; - else cp = 0xFC; - - if (params->frequency < 150000000) bs = 0x01; - else if (params->frequency < 173000000) bs = 0x01; - else if (params->frequency < 250000000) bs = 0x02; - else if (params->frequency < 400000000) bs = 0x02; - else if (params->frequency < 420000000) bs = 0x02; - else if (params->frequency < 470000000) bs = 0x02; - else if (params->frequency < 600000000) bs = 0x08; - else if (params->frequency < 730000000) bs = 0x08; - else bs = 0x08; + if (params->frequency < 150000000) + cp = 0xB4; + else if (params->frequency < 173000000) + cp = 0xBC; + else if (params->frequency < 250000000) + cp = 0xB4; + else if (params->frequency < 400000000) + cp = 0xBC; + else if (params->frequency < 420000000) + cp = 0xF4; + else if (params->frequency < 470000000) + cp = 0xFC; + else if (params->frequency < 600000000) + cp = 0xBC; + else if (params->frequency < 730000000) + cp = 0xF4; + else + cp = 0xFC; + + if (params->frequency < 150000000) + bs = 0x01; + else if (params->frequency < 173000000) + bs = 0x01; + else if (params->frequency < 250000000) + bs = 0x02; + else if (params->frequency < 400000000) + bs = 0x02; + else if (params->frequency < 420000000) + bs = 0x02; + else if (params->frequency < 470000000) + bs = 0x02; + else if (params->frequency < 600000000) + bs = 0x08; + else if (params->frequency < 730000000) + bs = 0x08; + else + bs = 0x08; pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address pllbuf[1] = div >> 8; @@ -356,19 +377,15 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct } static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { - .demod_address = 0x0f, .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, .pll_set = advbt771_samsung_tdtc9251dh0_pll_set, }; - static struct dst_config dst_config = { - .demod_address = 0x55, }; - static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) { struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; @@ -398,10 +415,8 @@ static void or51211_reset(struct dvb_frontend * fe) */ /* reset & PRM1,2&4 are outputs */ int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); - if (ret != 0) { - printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR " - "(%i)\n", ret); - } + if (ret != 0) + printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ msleep(20); /* Now set for normal operation */ @@ -417,7 +432,6 @@ static void or51211_sleep(struct dvb_frontend * fe) } static struct or51211_config or51211_config = { - .demod_address = 0x15, .request_firmware = or51211_request_firmware, .setmode = or51211_setmode, @@ -425,7 +439,6 @@ static struct or51211_config or51211_config = { .sleep = or51211_sleep, }; - static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; @@ -454,12 +467,84 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten } static struct nxt6000_config vp3021_alps_tded4_config = { - .demod_address = 0x0a, .clock_inversion = 1, .pll_set = vp3021_alps_tded4_pll_set, }; +static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; + + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + pllbuf[0] = 0xc2; + pllbuf[1] = (div >> 8) & 0x7F; + pllbuf[2] = div & 0xFF; + pllbuf[3] = 0x85; + + dprintk("frequency %u, div %u\n", params->frequency, div); + + if (params->frequency < 470000000) + pllbuf[4] = 0x02; + else if (params->frequency > 823000000) + pllbuf[4] = 0x88; + else + pllbuf[4] = 0x08; + + if (op->bandwidth == 8) + pllbuf[4] |= 0x04; + + return 0; +} + +static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) +{ + /* + * Reset the frontend, must be called before trying + * to initialise the MT352 or mt352_attach + * will fail. + * + * Presumably not required for the NXT6000 frontend. + * + */ + + int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); + if (ret != 0) + printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); + + /* Pulse the reset line */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ + bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ + msleep(100); + + bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ +} + +static struct mt352_config digitv_alps_tded4_config = { + .demod_address = 0x0a, + .demod_init = digitv_alps_tded4_demod_init, + .pll_set = digitv_alps_tded4_pll_set, +}; static void frontend_init(struct dvb_bt8xx_card *card, u32 type) { @@ -473,7 +558,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; card->fe->ops->info.frequency_max = 862000000; - break; } break; #endif @@ -483,17 +567,28 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) #else case BTTV_NEBULA_DIGITV: #endif + /* + * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); + * this would be a cleaner solution than trying each frontend in turn. + */ + + /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); if (card->fe != NULL) { + dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); break; } + + /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ + digitv_alps_tded4_reset(card); + card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter); + + if (card->fe != NULL) + dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); break; case BTTV_AVDVBT_761: card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter); - if (card->fe != NULL) { - break; - } break; case BTTV_AVDVBT_771: @@ -501,7 +596,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; card->fe->ops->info.frequency_max = 862000000; - break; } break; @@ -522,54 +616,41 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) /* Attach other DST peripherals if any */ /* Conditional Access device */ - if (state->dst_hw_cap & DST_TYPE_HAS_CA) { + if (state->dst_hw_cap & DST_TYPE_HAS_CA) ret = dst_ca_attach(state, &card->dvb_adapter); - } - if (card->fe != NULL) { - break; - } break; case BTTV_PINNACLESAT: card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter); - if (card->fe != NULL) { - break; - } break; case BTTV_PC_HDTV: card->fe = or51211_attach(&or51211_config, card->i2c_adapter); - if (card->fe != NULL) { - break; - } break; } - if (card->fe == NULL) { + if (card->fe == NULL) printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", card->bt->dev->vendor, card->bt->dev->device, card->bt->dev->subsystem_vendor, card->bt->dev->subsystem_device); - } else { + else if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { printk("dvb-bt8xx: Frontend registration failed!\n"); if (card->fe->ops->release) card->fe->ops->release(card->fe); card->fe = NULL; } - } } static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) { int result; - if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, - THIS_MODULE)) < 0) { + if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) { printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); return result; - } card->dvb_adapter.priv = card; @@ -664,8 +745,7 @@ static int dvb_bt8xx_probe(struct device *dev) strncpy(card->card_name, sub->core->name, sizeof(sub->core->name)); card->i2c_adapter = &sub->core->i2c_adap; - switch(sub->core->type) - { + switch(sub->core->type) { case BTTV_PINNACLESAT: card->gpio_mode = 0x0400c060; /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, @@ -751,7 +831,6 @@ static int dvb_bt8xx_probe(struct device *dev) kfree(card); return -EFAULT; - } init_MUTEX(&card->bt->gpio_lock); @@ -779,7 +858,8 @@ static int dvb_bt8xx_remove(struct device *dev) card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); - if (card->fe) dvb_unregister_frontend(card->fe); + if (card->fe) + dvb_unregister_frontend(card->fe); dvb_unregister_adapter(&card->dvb_adapter); kfree(card); diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h index 2923b3b0dd3c..9ec8e5bd6c1f 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h @@ -2,7 +2,7 @@ * Bt8xx based DVB adapter driver * * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org> - * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> + * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> * Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> * diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig index 226714085f58..7cf4c4a888ec 100644 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ b/drivers/media/dvb/cinergyT2/Kconfig @@ -77,7 +77,7 @@ config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE config DVB_CINERGYT2_RC_QUERY_INTERVAL int "Infrared Remote Controller update interval [milliseconds]" depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE - default "100" + default "50" help If you have a very fast-repeating remote control you can try lower values, for normal consumer receivers the default value should be diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 7d8b3cad350b..6db0929ef53d 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -25,7 +25,6 @@ #include <linux/config.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/version.h> #include <linux/slab.h> #include <linux/usb.h> #include <linux/pci.h> @@ -36,7 +35,6 @@ #include "dvb_demux.h" #include "dvb_net.h" - #ifdef CONFIG_DVB_CINERGYT2_TUNING #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT) #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE) @@ -49,7 +47,7 @@ #define STREAM_URB_COUNT (32) #define STREAM_BUF_SIZE (512) /* bytes */ #define ENABLE_RC (1) - #define RC_QUERY_INTERVAL (100) /* milliseconds */ + #define RC_QUERY_INTERVAL (50) /* milliseconds */ #define QUERY_INTERVAL (333) /* milliseconds */ #endif @@ -142,6 +140,8 @@ struct cinergyt2 { struct input_dev rc_input_dev; struct work_struct rc_query_work; int rc_input_event; + u32 rc_last_code; + unsigned long last_event_jiffies; #endif }; @@ -156,7 +156,7 @@ struct cinergyt2_rc_event { uint32_t value; } __attribute__((packed)); -static const uint32_t rc_keys [] = { +static const uint32_t rc_keys[] = { CINERGYT2_RC_EVENT_TYPE_NEC, 0xfe01eb04, KEY_POWER, CINERGYT2_RC_EVENT_TYPE_NEC, 0xfd02eb04, KEY_1, CINERGYT2_RC_EVENT_TYPE_NEC, 0xfc03eb04, KEY_2, @@ -685,52 +685,68 @@ static struct dvb_device cinergyt2_fe_template = { #ifdef ENABLE_RC static void cinergyt2_query_rc (void *data) { - struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data; - char buf [1] = { CINERGYT2_EP1_GET_RC_EVENTS }; + struct cinergyt2 *cinergyt2 = data; + char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS }; struct cinergyt2_rc_event rc_events[12]; - int n, len; + int n, len, i; if (down_interruptible(&cinergyt2->sem)) return; len = cinergyt2_command(cinergyt2, buf, sizeof(buf), - (char *) rc_events, sizeof(rc_events)); - - for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) { - int i; + (char *) rc_events, sizeof(rc_events)); + if (len < 0) + goto out; + if (len == 0) { + if (time_after(jiffies, cinergyt2->last_event_jiffies + + msecs_to_jiffies(150))) { + /* stop key repeat */ + if (cinergyt2->rc_input_event != KEY_MAX) { + dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); + input_report_key(&cinergyt2->rc_input_dev, + cinergyt2->rc_input_event, 0); + cinergyt2->rc_input_event = KEY_MAX; + } + cinergyt2->rc_last_code = ~0; + } + goto out; + } + cinergyt2->last_event_jiffies = jiffies; -/* dprintk(1,"rc_events[%d].value = %x, type=%x\n",n,le32_to_cpu(rc_events[n].value),rc_events[n].type);*/ + for (n = 0; n < (len / sizeof(rc_events[0])); n++) { + dprintk(1, "rc_events[%d].value = %x, type=%x\n", + n, le32_to_cpu(rc_events[n].value), rc_events[n].type); if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC && - rc_events[n].value == ~0) - { - /** - * keyrepeat bit. If we would handle this properly - * we would need to emit down events as long the - * keyrepeat goes, a up event if no further - * repeat bits occur. Would need a timer to implement - * and no other driver does this, so we simply - * emit the last key up/down sequence again. - */ + rc_events[n].value == ~0) { + /* keyrepeat bit -> just repeat last rc_input_event */ } else { cinergyt2->rc_input_event = KEY_MAX; - for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) { - if (rc_keys[i+0] == rc_events[n].type && - rc_keys[i+1] == le32_to_cpu(rc_events[n].value)) - { - cinergyt2->rc_input_event = rc_keys[i+2]; + for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) { + if (rc_keys[i + 0] == rc_events[n].type && + rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) { + cinergyt2->rc_input_event = rc_keys[i + 2]; break; } } } if (cinergyt2->rc_input_event != KEY_MAX) { - input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1); - input_report_key(&cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); - input_sync(&cinergyt2->rc_input_dev); + if (rc_events[n].value == cinergyt2->rc_last_code && + cinergyt2->rc_last_code != ~0) { + /* emit a key-up so the double event is recognized */ + dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event); + input_report_key(&cinergyt2->rc_input_dev, + cinergyt2->rc_input_event, 0); + } + dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); + input_report_key(&cinergyt2->rc_input_dev, + cinergyt2->rc_input_event, 1); + cinergyt2->rc_last_code = rc_events[n].value; } } +out: schedule_delayed_work(&cinergyt2->rc_query_work, msecs_to_jiffies(RC_QUERY_INTERVAL)); @@ -772,7 +788,10 @@ static int cinergyt2_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct cinergyt2 *cinergyt2; - int i, err; + int err; +#ifdef ENABLE_RC + int i; +#endif if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { dprintk(1, "out of memory?!?\n"); @@ -828,19 +847,18 @@ static int cinergyt2_probe (struct usb_interface *intf, DVB_DEVICE_FRONTEND); #ifdef ENABLE_RC - init_input_dev(&cinergyt2->rc_input_dev); - - cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY); - cinergyt2->rc_input_dev.keycodesize = sizeof(unsigned char); - cinergyt2->rc_input_dev.keycodemax = KEY_MAX; + cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + cinergyt2->rc_input_dev.keycodesize = 0; + cinergyt2->rc_input_dev.keycodemax = 0; cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control"; - for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) - set_bit(rc_keys[i+2], cinergyt2->rc_input_dev.keybit); + for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) + set_bit(rc_keys[i + 2], cinergyt2->rc_input_dev.keybit); input_register_device(&cinergyt2->rc_input_dev); cinergyt2->rc_input_event = KEY_MAX; + cinergyt2->rc_last_code = ~0; INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); @@ -888,7 +906,7 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) if (down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; - if (state > 0) { /* state 0 seems to mean DEVICE_PM_ON */ + if (state.event > PM_EVENT_ON) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); #ifdef ENABLE_RC cancel_delayed_work(&cinergyt2->rc_query_work); diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index fb55eaa5c8e7..9719a3b30f78 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -30,6 +30,7 @@ #include <linux/errno.h> #include <linux/list.h> #include <linux/time.h> +#include <linux/dvb/dmx.h> /*--------------------------------------------------------------------------*/ /* Common definitions */ @@ -124,9 +125,7 @@ struct dmx_ts_feed { u16 pid, int type, enum dmx_ts_pes pes_type, - size_t callback_length, size_t circular_buffer_size, - int descramble, struct timespec timeout); int (*start_filtering) (struct dmx_ts_feed* feed); int (*stop_filtering) (struct dmx_ts_feed* feed); @@ -159,7 +158,6 @@ struct dmx_section_feed { int (*set) (struct dmx_section_feed* feed, u16 pid, size_t circular_buffer_size, - int descramble, int check_crc); int (*allocate_filter) (struct dmx_section_feed* feed, struct dmx_section_filter** filter); @@ -207,7 +205,6 @@ struct dmx_frontend { struct list_head connectivity_list; /* List of front-ends that can be connected to a particular demux */ - void* priv; /* Pointer to private data of the API client */ enum dmx_frontend_source source; }; @@ -225,8 +222,6 @@ struct dmx_frontend { #define DMX_MEMORY_BASED_FILTERING 8 /* write() available */ #define DMX_CRC_CHECKING 16 #define DMX_TS_DESCRAMBLING 32 -#define DMX_SECTION_PAYLOAD_DESCRAMBLING 64 -#define DMX_MAC_ADDRESS_DESCRAMBLING 128 /* * Demux resource type identifier. @@ -244,9 +239,7 @@ struct dmx_frontend { struct dmx_demux { u32 capabilities; /* Bitfield of capability flags */ struct dmx_frontend* frontend; /* Front-end connected to the demux */ - struct list_head reg_list; /* List of registered demuxes */ void* priv; /* Pointer to private data of the API client */ - int users; /* Number of users */ int (*open) (struct dmx_demux* demux); int (*close) (struct dmx_demux* demux); int (*write) (struct dmx_demux* demux, const char* buf, size_t count); @@ -260,17 +253,6 @@ struct dmx_demux { dmx_section_cb callback); int (*release_section_feed) (struct dmx_demux* demux, struct dmx_section_feed* feed); - int (*descramble_mac_address) (struct dmx_demux* demux, - u8* buffer1, - size_t buffer1_length, - u8* buffer2, - size_t buffer2_length, - u16 pid); - int (*descramble_section_payload) (struct dmx_demux* demux, - u8* buffer1, - size_t buffer1_length, - u8* buffer2, size_t buffer2_length, - u16 pid); int (*add_frontend) (struct dmx_demux* demux, struct dmx_frontend* frontend); int (*remove_frontend) (struct dmx_demux* demux, @@ -282,20 +264,12 @@ struct dmx_demux { int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids); + int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps); + + int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src); + int (*get_stc) (struct dmx_demux* demux, unsigned int num, u64 *stc, unsigned int *base); }; -/*--------------------------------------------------------------------------*/ -/* Demux directory */ -/*--------------------------------------------------------------------------*/ - -/* - * DMX_DIR_ENTRY(): Casts elements in the list of registered - * demuxes from the generic type struct list_head* to the type struct dmx_demux - *. - */ - -#define DMX_DIR_ENTRY(list) list_entry(list, struct dmx_demux, reg_list) - #endif /* #ifndef __DEMUX_H */ diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 68050cd527cb..8028c3a5e287 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -571,7 +571,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) return ret; } - ret=(*secfeed)->set(*secfeed, para->pid, 32768, 0, + ret=(*secfeed)->set(*secfeed, para->pid, 32768, (para->flags & DMX_CHECK_CRC) ? 1 : 0); if (ret<0) { @@ -654,7 +654,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) (*tsfeed)->priv = (void *) filter; ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, - 188, 32768, 0, timeout); + 32768, timeout); if (ret < 0) { dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); @@ -929,6 +929,22 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)parg); break; + case DMX_GET_CAPS: + if (!dmxdev->demux->get_caps) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->get_caps(dmxdev->demux, parg); + break; + + case DMX_SET_SOURCE: + if (!dmxdev->demux->set_source) { + ret = -EINVAL; + break; + } + ret = dmxdev->demux->set_source(dmxdev->demux, parg); + break; + case DMX_GET_STC: if (!dmxdev->demux->get_stc) { ret=-EINVAL; diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 0eb9aa711fb0..88757e2634e5 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -47,7 +47,7 @@ MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); #define dprintk if (dvb_ca_en50221_debug) printk -#define INIT_TIMEOUT_SECS 5 +#define INIT_TIMEOUT_SECS 10 #define HOST_LINK_BUF_SIZE 0x200 diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index ac9889d22288..dc476dda2b71 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -38,82 +38,52 @@ */ // #define DVB_DEMUX_SECTION_LOSS_LOG - -static LIST_HEAD(dmx_muxs); - - -static int dmx_register_demux(struct dmx_demux *demux) -{ - demux->users = 0; - list_add(&demux->reg_list, &dmx_muxs); - return 0; -} - -static int dmx_unregister_demux(struct dmx_demux* demux) -{ - struct list_head *pos, *n, *head=&dmx_muxs; - - list_for_each_safe (pos, n, head) { - if (DMX_DIR_ENTRY(pos) == demux) { - if (demux->users>0) - return -EINVAL; - list_del(pos); - return 0; - } - } - - return -ENODEV; -} - - /****************************************************************************** * static inlined helper functions ******************************************************************************/ - static inline u16 section_length(const u8 *buf) { - return 3+((buf[1]&0x0f)<<8)+buf[2]; + return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; } - static inline u16 ts_pid(const u8 *buf) { - return ((buf[1]&0x1f)<<8)+buf[2]; + return ((buf[1] & 0x1f) << 8) + buf[2]; } - static inline u8 payload(const u8 *tsp) { - if (!(tsp[3] & 0x10)) // no payload? + if (!(tsp[3] & 0x10)) // no payload? return 0; - if (tsp[3] & 0x20) { // adaptation field? - if (tsp[4] > 183) // corrupted data? + + if (tsp[3] & 0x20) { // adaptation field? + if (tsp[4] > 183) // corrupted data? return 0; else - return 184-1-tsp[4]; + return 184 - 1 - tsp[4]; } + return 184; } - -static u32 dvb_dmx_crc32 (struct dvb_demux_feed *f, const u8 *src, size_t len) +static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len) { - return (f->feed.sec.crc_val = crc32_be (f->feed.sec.crc_val, src, len)); + return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len)); } - -static void dvb_dmx_memcopy (struct dvb_demux_feed *f, u8 *d, const u8 *s, size_t len) +static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, + size_t len) { - memcpy (d, s, len); + memcpy(d, s, len); } - /****************************************************************************** * Software filter functions ******************************************************************************/ -static inline int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u8 *buf) +static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, + const u8 *buf) { int count = payload(buf); int p; @@ -123,32 +93,31 @@ static inline int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u if (count == 0) return -1; - p = 188-count; + p = 188 - count; /* - cc=buf[3]&0x0f; - ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0; - dvbdmxfeed->cc=cc; + cc = buf[3] & 0x0f; + ccok = ((feed->cc + 1) & 0x0f) == cc; + feed->cc = cc; if (!ccok) printk("missed packet!\n"); */ - if (buf[1] & 0x40) // PUSI ? + if (buf[1] & 0x40) // PUSI ? feed->peslen = 0xfffa; feed->peslen += count; - return feed->cb.ts (&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); + return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); } - -static int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed, - struct dvb_demux_filter *f) +static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, + struct dvb_demux_filter *f) { u8 neq = 0; int i; - for (i=0; i<DVB_DEMUX_MASK_MAX; i++) { + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i]; if (f->maskandmode[i] & xor) @@ -160,12 +129,11 @@ static int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed, if (f->doneq && !neq) return 0; - return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen, - NULL, 0, &f->filter, DMX_OK); + return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, + NULL, 0, &f->filter, DMX_OK); } - -static inline int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed) +static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct dvb_demux_filter *f = feed->filter; @@ -195,26 +163,24 @@ static inline int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed) return 0; } - static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { struct dmx_section_feed *sec = &feed->feed.sec; #ifdef DVB_DEMUX_SECTION_LOSS_LOG - if(sec->secbufp < sec->tsfeedp) - { + if (sec->secbufp < sec->tsfeedp) { int i, n = sec->tsfeedp - sec->secbufp; - /* section padding is done with 0xff bytes entirely. - ** due to speed reasons, we won't check all of them - ** but just first and last - */ - if(sec->secbuf[0] != 0xff || sec->secbuf[n-1] != 0xff) - { + /* + * Section padding is done with 0xff bytes entirely. + * Due to speed reasons, we won't check all of them + * but just first and last. + */ + if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { printk("dvb_demux.c section ts padding loss: %d/%d\n", n, sec->tsfeedp); printk("dvb_demux.c pad data:"); - for(i = 0; i < n; i++) + for (i = 0; i < n; i++) printk(" %02x", sec->secbuf[i]); printk("\n"); } @@ -226,82 +192,81 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) } /* -** Losless Section Demux 1.4.1 by Emard -** Valsecchi Patrick: -** - middle of section A (no PUSI) -** - end of section A and start of section B -** (with PUSI pointing to the start of the second section) -** -** In this case, without feed->pusi_seen you'll receive a garbage section -** consisting of the end of section A. Basically because tsfeedp -** is incemented and the use=0 condition is not raised -** when the second packet arrives. -** -** Fix: -** when demux is started, let feed->pusi_seen = 0 to -** prevent initial feeding of garbage from the end of -** previous section. When you for the first time see PUSI=1 -** then set feed->pusi_seen = 1 -*/ -static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len) + * Losless Section Demux 1.4.1 by Emard + * Valsecchi Patrick: + * - middle of section A (no PUSI) + * - end of section A and start of section B + * (with PUSI pointing to the start of the second section) + * + * In this case, without feed->pusi_seen you'll receive a garbage section + * consisting of the end of section A. Basically because tsfeedp + * is incemented and the use=0 condition is not raised + * when the second packet arrives. + * + * Fix: + * when demux is started, let feed->pusi_seen = 0 to + * prevent initial feeding of garbage from the end of + * previous section. When you for the first time see PUSI=1 + * then set feed->pusi_seen = 1 + */ +static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, + const u8 *buf, u8 len) { struct dvb_demux *demux = feed->demux; struct dmx_section_feed *sec = &feed->feed.sec; u16 limit, seclen, n; - if(sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) + if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) return 0; - if(sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) - { + if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { #ifdef DVB_DEMUX_SECTION_LOSS_LOG printk("dvb_demux.c section buffer full loss: %d/%d\n", - sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE); + sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, + DMX_MAX_SECFEED_SIZE); #endif len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; } - if(len <= 0) + if (len <= 0) return 0; demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len); sec->tsfeedp += len; - /* ----------------------------------------------------- - ** Dump all the sections we can find in the data (Emard) - */ - + /* + * Dump all the sections we can find in the data (Emard) + */ limit = sec->tsfeedp; - if(limit > DMX_MAX_SECFEED_SIZE) - return -1; /* internal error should never happen */ + if (limit > DMX_MAX_SECFEED_SIZE) + return -1; /* internal error should never happen */ /* to be sure always set secbuf */ sec->secbuf = sec->secbuf_base + sec->secbufp; - for(n = 0; sec->secbufp + 2 < limit; n++) - { + for (n = 0; sec->secbufp + 2 < limit; n++) { seclen = section_length(sec->secbuf); - if(seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE - || seclen + sec->secbufp > limit) + if (seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE + || seclen + sec->secbufp > limit) return 0; sec->seclen = seclen; sec->crc_val = ~0; /* dump [secbuf .. secbuf+seclen) */ - if(feed->pusi_seen) + if (feed->pusi_seen) dvb_dmx_swfilter_section_feed(feed); #ifdef DVB_DEMUX_SECTION_LOSS_LOG else printk("dvb_demux.c pusi not seen, discarding section data\n"); #endif - sec->secbufp += seclen; /* secbufp and secbuf moving together is */ - sec->secbuf += seclen; /* redundand but saves pointer arithmetic */ + sec->secbufp += seclen; /* secbufp and secbuf moving together is */ + sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ } return 0; } - -static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) +static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, + const u8 *buf) { u8 p, count; int ccok, dc_i = 0; @@ -309,10 +274,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 count = payload(buf); - if (count == 0) /* count == 0 if no payload or out of range */ + if (count == 0) /* count == 0 if no payload or out of range */ return -1; - p = 188 - count; /* payload start */ + p = 188 - count; /* payload start */ cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; @@ -326,52 +291,53 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 if (!ccok || dc_i) { #ifdef DVB_DEMUX_SECTION_LOSS_LOG - printk("dvb_demux.c discontinuity detected %d bytes lost\n", count); - /* those bytes under sume circumstances will again be reported - ** in the following dvb_dmx_swfilter_section_new - */ + printk("dvb_demux.c discontinuity detected %d bytes lost\n", + count); + /* + * those bytes under sume circumstances will again be reported + * in the following dvb_dmx_swfilter_section_new + */ #endif - /* Discontinuity detected. Reset pusi_seen = 0 to - ** stop feeding of suspicious data until next PUSI=1 arrives - */ + /* + * Discontinuity detected. Reset pusi_seen = 0 to + * stop feeding of suspicious data until next PUSI=1 arrives + */ feed->pusi_seen = 0; dvb_dmx_swfilter_section_new(feed); - return 0; } if (buf[1] & 0x40) { - // PUSI=1 (is set), section boundary is here + /* PUSI=1 (is set), section boundary is here */ if (count > 1 && buf[p] < count) { - const u8 *before = buf+p+1; + const u8 *before = &buf[p + 1]; u8 before_len = buf[p]; - const u8 *after = before+before_len; - u8 after_len = count-1-before_len; + const u8 *after = &before[before_len]; + u8 after_len = count - 1 - before_len; - dvb_dmx_swfilter_section_copy_dump(feed, before, before_len); + dvb_dmx_swfilter_section_copy_dump(feed, before, + before_len); /* before start of new section, set pusi_seen = 1 */ feed->pusi_seen = 1; dvb_dmx_swfilter_section_new(feed); - dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); + dvb_dmx_swfilter_section_copy_dump(feed, after, + after_len); } #ifdef DVB_DEMUX_SECTION_LOSS_LOG - else - if (count > 0) - printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); + else if (count > 0) + printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); #endif } else { - // PUSI=0 (is not set), no section boundary - const u8 *entire = buf+p; - u8 entire_len = count; - - dvb_dmx_swfilter_section_copy_dump(feed, entire, entire_len); + /* PUSI=0 (is not set), no section boundary */ + dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); } + return 0; } - -static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, const u8 *buf) +static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, + const u8 *buf) { - switch(feed->type) { + switch (feed->type) { case DMX_TYPE_TS: if (!feed->feed.ts.is_filtering) break; @@ -379,7 +345,8 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con if (feed->ts_type & TS_PAYLOAD_ONLY) dvb_dmx_swfilter_payload(feed, buf); else - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, + DMX_OK); } if (feed->ts_type & TS_DECODER) if (feed->demux->write_to_decoder) @@ -390,7 +357,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con if (!feed->feed.sec.is_filtering) break; if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) - feed->feed.sec.seclen = feed->feed.sec.secbufp=0; + feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; break; default: @@ -406,7 +373,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) { struct dvb_demux_feed *feed; - struct list_head *pos, *head=&demux->feed_list; + struct list_head *pos, *head = &demux->feed_list; u16 pid = ts_pid(buf); int dvr_done = 0; @@ -432,21 +399,21 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) } } -void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count) +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, + size_t count) { spin_lock(&demux->lock); while (count--) { - if(buf[0] == 0x47) { - dvb_dmx_swfilter_packet(demux, buf); - } + if (buf[0] == 0x47) + dvb_dmx_swfilter_packet(demux, buf); buf += 188; } spin_unlock(&demux->lock); } -EXPORT_SYMBOL(dvb_dmx_swfilter_packets); +EXPORT_SYMBOL(dvb_dmx_swfilter_packets); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) { @@ -454,8 +421,10 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) spin_lock(&demux->lock); - if ((i = demux->tsbufp)) { - if (count < (j=188-i)) { + if (demux->tsbufp) { + i = demux->tsbufp; + j = 188 - i; + if (count < j) { memcpy(&demux->tsbuf[i], buf, count); demux->tsbufp += count; goto bailout; @@ -469,13 +438,13 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) while (p < count) { if (buf[p] == 0x47) { - if (count-p >= 188) { - dvb_dmx_swfilter_packet(demux, buf+p); + if (count - p >= 188) { + dvb_dmx_swfilter_packet(demux, &buf[p]); p += 188; } else { - i = count-p; - memcpy(demux->tsbuf, buf+p, i); - demux->tsbufp=i; + i = count - p; + memcpy(demux->tsbuf, &buf[p], i); + demux->tsbufp = i; goto bailout; } } else @@ -485,24 +454,29 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) bailout: spin_unlock(&demux->lock); } + EXPORT_SYMBOL(dvb_dmx_swfilter); void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) { - int p = 0,i, j; + int p = 0, i, j; u8 tmppack[188]; + spin_lock(&demux->lock); - if ((i = demux->tsbufp)) { - if (count < (j=204-i)) { + if (demux->tsbufp) { + i = demux->tsbufp; + j = 204 - i; + if (count < j) { memcpy(&demux->tsbuf[i], buf, count); demux->tsbufp += count; goto bailout; } memcpy(&demux->tsbuf[i], buf, j); - if ((demux->tsbuf[0] == 0x47)|(demux->tsbuf[0]==0xB8)) { + if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) { memcpy(tmppack, demux->tsbuf, 188); - if (tmppack[0] == 0xB8) tmppack[0] = 0x47; + if (tmppack[0] == 0xB8) + tmppack[0] = 0x47; dvb_dmx_swfilter_packet(demux, tmppack); } demux->tsbufp = 0; @@ -510,16 +484,17 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) } while (p < count) { - if ((buf[p] == 0x47)|(buf[p] == 0xB8)) { - if (count-p >= 204) { - memcpy(tmppack, buf+p, 188); - if (tmppack[0] == 0xB8) tmppack[0] = 0x47; + if ((buf[p] == 0x47) | (buf[p] == 0xB8)) { + if (count - p >= 204) { + memcpy(tmppack, &buf[p], 188); + if (tmppack[0] == 0xB8) + tmppack[0] = 0x47; dvb_dmx_swfilter_packet(demux, tmppack); p += 204; } else { - i = count-p; - memcpy(demux->tsbuf, buf+p, i); - demux->tsbufp=i; + i = count - p; + memcpy(demux->tsbuf, &buf[p], i); + demux->tsbufp = i; goto bailout; } } else { @@ -530,14 +505,14 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) bailout: spin_unlock(&demux->lock); } -EXPORT_SYMBOL(dvb_dmx_swfilter_204); +EXPORT_SYMBOL(dvb_dmx_swfilter_204); -static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux) +static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) { int i; - for (i=0; i<demux->filternum; i++) + for (i = 0; i < demux->filternum; i++) if (demux->filter[i].state == DMX_STATE_FREE) break; @@ -549,11 +524,11 @@ static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux) return &demux->filter[i]; } -static struct dvb_demux_feed * dvb_dmx_feed_alloc(struct dvb_demux *demux) +static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) { int i; - for (i=0; i<demux->feednum; i++) + for (i = 0; i < demux->feednum; i++) if (demux->feed[i].state == DMX_STATE_FREE) break; @@ -581,7 +556,7 @@ static void dvb_demux_feed_add(struct dvb_demux_feed *feed) spin_lock_irq(&feed->demux->lock); if (dvb_demux_feed_find(feed)) { printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", - __FUNCTION__, feed->type, feed->state, feed->pid); + __FUNCTION__, feed->type, feed->state, feed->pid); goto out; } @@ -595,7 +570,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed) spin_lock_irq(&feed->demux->lock); if (!(dvb_demux_feed_find(feed))) { printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", - __FUNCTION__, feed->type, feed->state, feed->pid); + __FUNCTION__, feed->type, feed->state, feed->pid); goto out; } @@ -604,18 +579,17 @@ out: spin_unlock_irq(&feed->demux->lock); } -static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, - enum dmx_ts_pes pes_type, size_t callback_length, - size_t circular_buffer_size, int descramble, - struct timespec timeout) +static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, + enum dmx_ts_pes pes_type, + size_t circular_buffer_size, struct timespec timeout) { - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; if (pid > DMX_MAX_PID) return -EINVAL; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (ts_type & TS_DECODER) { @@ -638,20 +612,13 @@ static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, feed->pid = pid; feed->buffer_size = circular_buffer_size; - feed->descramble = descramble; feed->timeout = timeout; - feed->cb_length = callback_length; feed->ts_type = ts_type; feed->pes_type = pes_type; - if (feed->descramble) { - up(&demux->mutex); - return -ENOSYS; - } - if (feed->buffer_size) { #ifdef NOBUFS - feed->buffer=NULL; + feed->buffer = NULL; #else feed->buffer = vmalloc(feed->buffer_size); if (!feed->buffer) { @@ -667,14 +634,13 @@ static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, return 0; } - -static int dmx_ts_feed_start_filtering(struct dmx_ts_feed* ts_feed) +static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) { - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; int ret; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { @@ -701,13 +667,13 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed* ts_feed) return 0; } -static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed* ts_feed) +static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) { - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; int ret; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (feed->state < DMX_STATE_GO) { @@ -731,13 +697,14 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed* ts_feed) return ret; } -static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed **ts_feed, - dmx_ts_cb callback) +static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, + struct dmx_ts_feed **ts_feed, + dmx_ts_cb callback) { - struct dvb_demux *demux = (struct dvb_demux *) dmx; + struct dvb_demux *demux = (struct dvb_demux *)dmx; struct dvb_demux_feed *feed; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (!(feed = dvb_dmx_feed_alloc(demux))) { @@ -760,7 +727,6 @@ static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed ** (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; (*ts_feed)->set = dmx_ts_feed_set; - if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { feed->state = DMX_STATE_FREE; up(&demux->mutex); @@ -776,22 +742,22 @@ static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed ** return 0; } -static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_feed) +static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, + struct dmx_ts_feed *ts_feed) { - struct dvb_demux *demux = (struct dvb_demux *) dmx; - struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed; + struct dvb_demux *demux = (struct dvb_demux *)dmx; + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; - if (down_interruptible (&demux->mutex)) + if (down_interruptible(&demux->mutex)) return -ERESTARTSYS; if (feed->state == DMX_STATE_FREE) { up(&demux->mutex); return -EINVAL; } - #ifndef NOBUFS vfree(feed->buffer); - feed->buffer=0; + feed->buffer = NULL; #endif feed->state = DMX_STATE_FREE; @@ -808,19 +774,18 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_ return 0; } - /****************************************************************************** * dmx_section_feed API calls ******************************************************************************/ -static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed, - struct dmx_section_filter** filter) +static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, + struct dmx_section_filter **filter) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdemux = dvbdmxfeed->demux; struct dvb_demux_filter *dvbdmxfilter; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux); @@ -844,36 +809,29 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed, return 0; } - -static int dmx_section_feed_set(struct dmx_section_feed* feed, - u16 pid, size_t circular_buffer_size, - int descramble, int check_crc) +static int dmx_section_feed_set(struct dmx_section_feed *feed, + u16 pid, size_t circular_buffer_size, + int check_crc) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; if (pid > 0x1fff) return -EINVAL; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; dvb_demux_feed_add(dvbdmxfeed); dvbdmxfeed->pid = pid; dvbdmxfeed->buffer_size = circular_buffer_size; - dvbdmxfeed->descramble = descramble; - if (dvbdmxfeed->descramble) { - up(&dvbdmx->mutex); - return -ENOSYS; - } - dvbdmxfeed->feed.sec.check_crc = check_crc; #ifdef NOBUFS dvbdmxfeed->buffer = NULL; #else - dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); + dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); if (!dvbdmxfeed->buffer) { up(&dvbdmx->mutex); return -ENOMEM; @@ -885,7 +843,6 @@ static int dmx_section_feed_set(struct dmx_section_feed* feed, return 0; } - static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) { int i; @@ -893,12 +850,12 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) struct dmx_section_filter *sf; u8 mask, mode, doneq; - if (!(f=dvbdmxfeed->filter)) + if (!(f = dvbdmxfeed->filter)) return; do { sf = &f->filter; doneq = 0; - for (i=0; i<DVB_DEMUX_MASK_MAX; i++) { + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { mode = sf->filter_mode[i]; mask = sf->filter_mask[i]; f->maskandmode[i] = mask & mode; @@ -908,14 +865,13 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) } while ((f = f->next)); } - static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; int ret; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (feed->is_filtering) { @@ -954,14 +910,13 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) return 0; } - -static int dmx_section_feed_stop_filtering(struct dmx_section_feed* feed) +static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; int ret; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (!dvbdmx->stop_feed) { @@ -980,15 +935,14 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed* feed) return ret; } - static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, - struct dmx_section_filter* filter) + struct dmx_section_filter *filter) { - struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *) filter, *f; - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; + struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (dvbdmxfilter->feed != dvbdmxfeed) { @@ -1005,7 +959,7 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, if (f == dvbdmxfilter) { dvbdmxfeed->filter = dvbdmxfilter->next; } else { - while(f->next != dvbdmxfilter) + while (f->next != dvbdmxfilter) f = f->next; f->next = f->next->next; } @@ -1020,10 +974,10 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, struct dmx_section_feed **feed, dmx_section_cb callback) { - struct dvb_demux *dvbdmx = (struct dvb_demux *) demux; + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; struct dvb_demux_feed *dvbdmxfeed; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { @@ -1041,7 +995,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, dvbdmxfeed->filter = NULL; dvbdmxfeed->buffer = NULL; - (*feed)=&dvbdmxfeed->feed.sec; + (*feed) = &dvbdmxfeed->feed.sec; (*feed)->is_filtering = 0; (*feed)->parent = demux; (*feed)->priv = NULL; @@ -1059,21 +1013,21 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, static int dvbdmx_release_section_feed(struct dmx_demux *demux, struct dmx_section_feed *feed) { - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) feed; - struct dvb_demux *dvbdmx = (struct dvb_demux *) demux; + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; + struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; - if (down_interruptible (&dvbdmx->mutex)) + if (down_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; - if (dvbdmxfeed->state==DMX_STATE_FREE) { + if (dvbdmxfeed->state == DMX_STATE_FREE) { up(&dvbdmx->mutex); return -EINVAL; } #ifndef NOBUFS vfree(dvbdmxfeed->buffer); - dvbdmxfeed->buffer=0; + dvbdmxfeed->buffer = NULL; #endif - dvbdmxfeed->state=DMX_STATE_FREE; + dvbdmxfeed->state = DMX_STATE_FREE; dvb_demux_feed_del(dvbdmxfeed); @@ -1083,14 +1037,13 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux, return 0; } - /****************************************************************************** * dvb_demux kernel data API calls ******************************************************************************/ static int dvbdmx_open(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (dvbdemux->users >= MAX_DVB_DEMUX_USERS) return -EUSERS; @@ -1099,10 +1052,9 @@ static int dvbdmx_open(struct dmx_demux *demux) return 0; } - static int dvbdmx_close(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (dvbdemux->users == 0) return -ENODEV; @@ -1112,15 +1064,14 @@ static int dvbdmx_close(struct dmx_demux *demux) return 0; } - static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) { - struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) return -EINVAL; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; dvb_dmx_swfilter(dvbdemux, buf, count); up(&dvbdemux->mutex); @@ -1130,10 +1081,10 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count) return count; } - -static int dvbdmx_add_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) +static int dvbdmx_add_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; struct list_head *head = &dvbdemux->frontend_list; list_add(&(frontend->connectivity_list), head); @@ -1141,13 +1092,13 @@ static int dvbdmx_add_frontend(struct dmx_demux *demux, struct dmx_frontend *fro return 0; } - -static int dvbdmx_remove_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) +static int dvbdmx_remove_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; struct list_head *pos, *n, *head = &dvbdemux->frontend_list; - list_for_each_safe (pos, n, head) { + list_for_each_safe(pos, n, head) { if (DMX_FE_ENTRY(pos) == frontend) { list_del(pos); return 0; @@ -1157,25 +1108,25 @@ static int dvbdmx_remove_frontend(struct dmx_demux *demux, struct dmx_frontend * return -ENODEV; } - -static struct list_head * dvbdmx_get_frontends(struct dmx_demux *demux) +static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (list_empty(&dvbdemux->frontend_list)) return NULL; + return &dvbdemux->frontend_list; } - -static int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend) +static int dvbdmx_connect_frontend(struct dmx_demux *demux, + struct dmx_frontend *frontend) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; if (demux->frontend) return -EINVAL; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; demux->frontend = frontend; @@ -1183,12 +1134,11 @@ static int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend return 0; } - static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - if (down_interruptible (&dvbdemux->mutex)) + if (down_interruptible(&dvbdemux->mutex)) return -ERESTARTSYS; demux->frontend = NULL; @@ -1196,44 +1146,42 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) return 0; } - -static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids) +static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) { - struct dvb_demux *dvbdemux = (struct dvb_demux *) demux; + struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - memcpy(pids, dvbdemux->pids, 5*sizeof(u16)); + memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); return 0; } - int dvb_dmx_init(struct dvb_demux *dvbdemux) { - int i, err; + int i; struct dmx_demux *dmx = &dvbdemux->dmx; dvbdemux->users = 0; - dvbdemux->filter = vmalloc(dvbdemux->filternum*sizeof(struct dvb_demux_filter)); + dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); if (!dvbdemux->filter) return -ENOMEM; - dvbdemux->feed = vmalloc(dvbdemux->feednum*sizeof(struct dvb_demux_feed)); + dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); if (!dvbdemux->feed) { vfree(dvbdemux->filter); return -ENOMEM; } - for (i=0; i<dvbdemux->filternum; i++) { + for (i = 0; i < dvbdemux->filternum; i++) { dvbdemux->filter[i].state = DMX_STATE_FREE; dvbdemux->filter[i].index = i; } - for (i=0; i<dvbdemux->feednum; i++) { + for (i = 0; i < dvbdemux->feednum; i++) { dvbdemux->feed[i].state = DMX_STATE_FREE; dvbdemux->feed[i].index = i; } - dvbdemux->frontend_list.next= - dvbdemux->frontend_list.prev= - &dvbdemux->frontend_list; - for (i=0; i<DMX_TS_PES_OTHER; i++) { + + INIT_LIST_HEAD(&dvbdemux->frontend_list); + + for (i = 0; i < DMX_TS_PES_OTHER; i++) { dvbdemux->pesfilter[i] = NULL; dvbdemux->pids[i] = 0xffff; } @@ -1247,12 +1195,11 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) if (!dvbdemux->check_crc32) dvbdemux->check_crc32 = dvb_dmx_crc32; - if (!dvbdemux->memcopy) - dvbdemux->memcopy = dvb_dmx_memcopy; + if (!dvbdemux->memcopy) + dvbdemux->memcopy = dvb_dmx_memcopy; dmx->frontend = NULL; - dmx->reg_list.prev = dmx->reg_list.next = &dmx->reg_list; - dmx->priv = (void *) dvbdemux; + dmx->priv = dvbdemux; dmx->open = dvbdmx_open; dmx->close = dvbdmx_close; dmx->write = dvbdmx_write; @@ -1261,9 +1208,6 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dmx->allocate_section_feed = dvbdmx_allocate_section_feed; dmx->release_section_feed = dvbdmx_release_section_feed; - dmx->descramble_mac_address = NULL; - dmx->descramble_section_payload = NULL; - dmx->add_frontend = dvbdmx_add_frontend; dmx->remove_frontend = dvbdmx_remove_frontend; dmx->get_frontends = dvbdmx_get_frontends; @@ -1274,21 +1218,15 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) sema_init(&dvbdemux->mutex, 1); spin_lock_init(&dvbdemux->lock); - if ((err = dmx_register_demux(dmx)) < 0) - return err; - return 0; } -EXPORT_SYMBOL(dvb_dmx_init); +EXPORT_SYMBOL(dvb_dmx_init); -int dvb_dmx_release(struct dvb_demux *dvbdemux) +void dvb_dmx_release(struct dvb_demux *dvbdemux) { - struct dmx_demux *dmx = &dvbdemux->dmx; - - dmx_unregister_demux(dmx); vfree(dvbdemux->filter); vfree(dvbdemux->feed); - return 0; } + EXPORT_SYMBOL(dvb_dmx_release); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index c09beb391622..0cc888339d52 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -20,7 +20,6 @@ * */ - #ifndef _DVB_DEMUX_H_ #define _DVB_DEMUX_H_ @@ -44,103 +43,98 @@ #define DVB_DEMUX_MASK_MAX 18 struct dvb_demux_filter { - struct dmx_section_filter filter; - u8 maskandmode [DMX_MAX_FILTER_SIZE]; - u8 maskandnotmode [DMX_MAX_FILTER_SIZE]; + struct dmx_section_filter filter; + u8 maskandmode[DMX_MAX_FILTER_SIZE]; + u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; int doneq; - struct dvb_demux_filter *next; - struct dvb_demux_feed *feed; - int index; - int state; - int type; - int pesto; - - u16 handle; - u16 hw_handle; - struct timer_list timer; - int ts_state; -}; + struct dvb_demux_filter *next; + struct dvb_demux_feed *feed; + int index; + int state; + int type; + u16 hw_handle; + struct timer_list timer; +}; #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) struct dvb_demux_feed { - union { - struct dmx_ts_feed ts; - struct dmx_section_feed sec; + union { + struct dmx_ts_feed ts; + struct dmx_section_feed sec; } feed; - union { - dmx_ts_cb ts; - dmx_section_cb sec; + union { + dmx_ts_cb ts; + dmx_section_cb sec; } cb; - struct dvb_demux *demux; + struct dvb_demux *demux; void *priv; - int type; - int state; - u16 pid; - u8 *buffer; - int buffer_size; - int descramble; + int type; + int state; + u16 pid; + u8 *buffer; + int buffer_size; - struct timespec timeout; - struct dvb_demux_filter *filter; - int cb_length; + struct timespec timeout; + struct dvb_demux_filter *filter; - int ts_type; - enum dmx_ts_pes pes_type; + int ts_type; + enum dmx_ts_pes pes_type; - int cc; - int pusi_seen; /* prevents feeding of garbage from previous section */ + int cc; + int pusi_seen; /* prevents feeding of garbage from previous section */ - u16 peslen; + u16 peslen; struct list_head list_head; - int index; /* a unique index for each feed (can be used as hardware pid filter index) */ + unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ }; struct dvb_demux { - struct dmx_demux dmx; - void *priv; - int filternum; - int feednum; - int (*start_feed) (struct dvb_demux_feed *feed); - int (*stop_feed) (struct dvb_demux_feed *feed); - int (*write_to_decoder) (struct dvb_demux_feed *feed, + struct dmx_demux dmx; + void *priv; + int filternum; + int feednum; + int (*start_feed)(struct dvb_demux_feed *feed); + int (*stop_feed)(struct dvb_demux_feed *feed); + int (*write_to_decoder)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); - u32 (*check_crc32) (struct dvb_demux_feed *feed, + u32 (*check_crc32)(struct dvb_demux_feed *feed, const u8 *buf, size_t len); - void (*memcopy) (struct dvb_demux_feed *feed, u8 *dst, + void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, const u8 *src, size_t len); - int users; + int users; #define MAX_DVB_DEMUX_USERS 10 - struct dvb_demux_filter *filter; - struct dvb_demux_feed *feed; + struct dvb_demux_filter *filter; + struct dvb_demux_feed *feed; - struct list_head frontend_list; + struct list_head frontend_list; - struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; - u16 pids[DMX_TS_PES_OTHER]; - int playing; - int recording; + struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; + u16 pids[DMX_TS_PES_OTHER]; + int playing; + int recording; #define DMX_MAX_PID 0x2000 struct list_head feed_list; - u8 tsbuf[204]; - int tsbufp; + u8 tsbuf[204]; + int tsbufp; struct semaphore mutex; spinlock_t lock; }; - int dvb_dmx_init(struct dvb_demux *dvbdemux); -int dvb_dmx_release(struct dvb_demux *dvbdemux); -void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count); +void dvb_dmx_release(struct dvb_demux *dvbdemux); +void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, + size_t count); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, + size_t count); #endif /* _DVB_DEMUX_H_ */ diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 6a968c346a36..87935490bfb2 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -62,7 +62,6 @@ #include <linux/uio.h> #include <asm/uaccess.h> #include <linux/crc32.h> -#include <linux/version.h> #include "dvb_demux.h" #include "dvb_net.h" @@ -171,11 +170,7 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8) - eth = skb->mac.ethernet; -#else eth = eth_hdr(skb); -#endif if (*eth->h_dest & 1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) @@ -908,7 +903,7 @@ static int dvb_net_feed_start(struct net_device *dev) return ret; } - ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 0, 1); + ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); if (ret<0) { printk("%s: could not set section feed\n", dev->name); @@ -960,9 +955,7 @@ static int dvb_net_feed_start(struct net_device *dev) priv->tsfeed->priv = (void *)dev; ret = priv->tsfeed->set(priv->tsfeed, priv->pid, TS_PACKET, DMX_TS_PES_OTHER, - 188 * 100, /* nr. of bytes delivered per callback */ 32768, /* circular buffer size */ - 0, /* descramble */ timeout); if (ret < 0) { diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 612e5b087b1c..54e2b29076b1 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -93,13 +93,30 @@ config DVB_USB_DIGITV Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. config DVB_USB_VP7045 - tristate "TwinhanDTV Alpha/MagicBoxII and DNTV tinyUSB2 DVB-T USB2.0 support" + tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support" depends on DVB_USB help Say Y here to support the + TwinhanDTV Alpha (stick) (VP-7045), - TwinhanDTV MagicBox II (VP-7046) and - DigitalNow TinyUSB 2 DVB-t DVB-T USB2.0 receivers. + TwinhanDTV MagicBox II (VP-7046), + DigitalNow TinyUSB 2 DVB-t, + DigitalRise USB 2.0 Ter (Beetle) and + TYPHOON DVB-T USB DRIVE + + DVB-T USB2.0 receivers. + +config DVB_USB_VP702X + tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support" + depends on DVB_USB + help + Say Y here to support the + + TwinhanDTV StarBox, + DigitalRise USB Starbox and + TYPHOON DVB-S USB 2.0 BOX + + DVB-S USB2.0 receivers. config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 746d87ed6f32..2dc9aad9681e 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_DVB_USB) += dvb-usb.o dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o +dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o +obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o + dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index f2fcc2f1f846..e55322ef76b3 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -90,7 +90,7 @@ static struct dvb_usb_properties a800_properties; static int a800_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE,NULL); } /* do not change the order of the ID table */ diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index c3e1b661aae6..3fe383f4bb4c 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -48,35 +48,26 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d, return 0; } -/* I2C */ -static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path) +/* GPIO */ +static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) { struct cxusb_state *st = d->priv; u8 o[2],i; - if (path == st->cur_i2c_path) + if (st->gpio_write_state[GPIO_TUNER] == onoff) return; - o[0] = IOCTL_SET_I2C_PATH; - switch (path) { - case PATH_CX22702: - o[1] = 0; - break; - case PATH_TUNER_OTHER: - o[1] = 1; - break; - default: - err("unkown i2c path"); - return; - } - cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1); + o[0] = GPIO_TUNER; + o[1] = onoff; + cxusb_ctrl_msg(d,CMD_GPIO_WRITE,o,2,&i,1); if (i != 0x01) - deb_info("i2c_path setting failed.\n"); + deb_info("gpio_write failed.\n"); - st->cur_i2c_path = path; + st->gpio_write_state[GPIO_TUNER] = onoff; } +/* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); @@ -92,10 +83,10 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) switch (msg[i].addr) { case 0x63: - cxusb_set_i2c_path(d,PATH_CX22702); + cxusb_gpio_tuner(d,0); break; default: - cxusb_set_i2c_path(d,PATH_TUNER_OTHER); + cxusb_gpio_tuner(d,1); break; } @@ -141,24 +132,26 @@ static u32 cxusb_i2c_func(struct i2c_adapter *adapter) } static struct i2c_algorithm cxusb_i2c_algo = { - .name = "Conexant USB I2C algorithm", - .id = I2C_ALGO_BIT, .master_xfer = cxusb_i2c_xfer, .functionality = cxusb_i2c_func, }; static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) { - return 0; + u8 b = 0; + if (onoff) + return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); + else + return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); } static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) { u8 buf[2] = { 0x03, 0x00 }; if (onoff) - cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); + cxusb_ctrl_msg(d,CMD_STREAMING_ON, buf, 2, NULL, 0); else - cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0); + cxusb_ctrl_msg(d,CMD_STREAMING_OFF, NULL, 0, NULL, 0); return 0; } @@ -184,22 +177,11 @@ static int cxusb_tuner_attach(struct dvb_usb_device *d) static int cxusb_frontend_attach(struct dvb_usb_device *d) { - u8 buf[2] = { 0x03, 0x00 }; - u8 b = 0; - - if (usb_set_interface(d->udev,0,0) < 0) - err("set interface to alts=0 failed"); - - cxusb_ctrl_msg(d,0xde,&b,0,NULL,0); - cxusb_set_i2c_path(d,PATH_TUNER_OTHER); - cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1); - + u8 b; if (usb_set_interface(d->udev,0,6) < 0) err("set interface failed"); - cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); - cxusb_set_i2c_path(d,PATH_CX22702); - cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1); + cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, &b, 1); if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL) return 0; @@ -213,7 +195,7 @@ static struct dvb_usb_properties cxusb_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE,NULL); } static struct usb_device_id cxusb_table [] = { @@ -239,14 +221,12 @@ static struct dvb_usb_properties cxusb_properties = { .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { - .type = DVB_USB_ISOC, + .type = DVB_USB_BULK, .count = 5, .endpoint = 0x02, .u = { - .isoc = { - .framesperurb = 32, - .framesize = 940, - .interval = 5, + .bulk = { + .buffersize = 8192, } } }, diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index 1d79016e3195..135c2a81f581 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -1,30 +1,31 @@ #ifndef _DVB_USB_CXUSB_H_ #define _DVB_USB_CXUSB_H_ -#define DVB_USB_LOG_PREFIX "digitv" +#define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" extern int dvb_usb_cxusb_debug; #define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) /* usb commands - some of it are guesses, don't have a reference yet */ -#define CMD_I2C_WRITE 0x08 -#define CMD_I2C_READ 0x09 +#define CMD_I2C_WRITE 0x08 +#define CMD_I2C_READ 0x09 -#define CMD_IOCTL 0x0e -#define IOCTL_SET_I2C_PATH 0x02 +#define CMD_GPIO_READ 0x0d +#define CMD_GPIO_WRITE 0x0e +#define GPIO_TUNER 0x02 -#define CMD_POWER_OFF 0x50 -#define CMD_POWER_ON 0x51 +#define CMD_POWER_OFF 0xdc +#define CMD_POWER_ON 0xde -enum cxusb_i2c_pathes { - PATH_UNDEF = 0x00, - PATH_CX22702 = 0x01, - PATH_TUNER_OTHER = 0x02, -}; +#define CMD_STREAMING_ON 0x36 +#define CMD_STREAMING_OFF 0x37 + +#define CMD_ANALOG 0x50 +#define CMD_DIGITAL 0x51 struct cxusb_state { - enum cxusb_i2c_pathes cur_i2c_path; + u8 gpio_write_state[3]; }; #endif diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 9b9d6f8ee74e..00b946419b40 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -156,8 +156,6 @@ static u32 dibusb_i2c_func(struct i2c_adapter *adapter) } struct i2c_algorithm dibusb_i2c_algo = { - .name = "DiBcom USB I2C algorithm", - .id = I2C_ALGO_BIT, .master_xfer = dibusb_i2c_xfer, .functionality = dibusb_i2c_func, }; diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 828b5182e16c..0058505634a0 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -86,9 +86,9 @@ static struct dvb_usb_properties dibusb2_0b_properties; static int dibusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE) == 0 || - dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE) == 0 || - dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE) == 0) + if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0) return 0; return -EINVAL; @@ -126,10 +126,12 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, /* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, +/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, + // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs -/* 27 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +/* 28 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, #endif { } /* Terminating entry */ }; @@ -262,7 +264,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { }, #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[27], NULL }, + { &dibusb_dib3000mb_table[28], NULL }, { NULL }, }, #endif @@ -306,12 +308,16 @@ static struct dvb_usb_properties dibusb2_0b_properties = { } }, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { - { "KWorld/ADSTech Instant DVB-T USB 2.0", + { "KWorld/ADSTech Instant DVB-T USB2.0", { &dibusb_dib3000mb_table[23], NULL }, { &dibusb_dib3000mb_table[24], NULL }, }, + { "KWorld Xpert DVB-T USB2.0", + { &dibusb_dib3000mb_table[27], NULL }, + { NULL } + }, } }; diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c index e9dac430f37d..6a0912eab396 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -20,7 +20,7 @@ static struct dvb_usb_properties dibusb_mc_properties; static int dibusb_mc_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE,NULL); } /* do not change the order of the ID table */ diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 9a676afc1d6e..74545f82eff1 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -77,8 +77,6 @@ static u32 digitv_i2c_func(struct i2c_adapter *adapter) } static struct i2c_algorithm digitv_i2c_algo = { - .name = "Nebula DigiTV USB I2C algorithm", - .id = I2C_ALGO_BIT, .master_xfer = digitv_i2c_xfer, .functionality = digitv_i2c_func, }; @@ -113,31 +111,28 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe) } static struct mt352_config digitv_mt352_config = { - .demod_address = 0x0, /* ignored by the digitv anyway */ .demod_init = digitv_mt352_demod_init, .pll_set = dvb_usb_pll_set, }; -static struct nxt6000_config digitv_nxt6000_config = { - .demod_address = 0x0, /* ignored by the digitv anyway */ - .clock_inversion = 0x0, +static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_device *d = fe->dvb->priv; + u8 b[5]; + dvb_usb_pll_set(fe,fep,b); + return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0); +} - .pll_init = NULL, - .pll_set = NULL, +static struct nxt6000_config digitv_nxt6000_config = { + .clock_inversion = 1, + .pll_set = digitv_nxt6000_pll_set, }; static int digitv_frontend_attach(struct dvb_usb_device *d) { - if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) + if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL || + (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) return 0; - if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) { - - warn("nxt6000 support is not done yet, in fact you are one of the first " - "person who wants to use this device in Linux. Please report to " - "linux-dvb@linuxtv.org"); - - return 0; - } return -EIO; } @@ -175,7 +170,18 @@ static struct dvb_usb_properties digitv_properties; static int digitv_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE); + struct dvb_usb_device *d; + int ret; + if ((ret = dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE,&d)) == 0) { + u8 b[4] = { 0 }; + + b[0] = 1; + digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); + + b[0] = 0; + digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + } + return ret; } static struct usb_device_id digitv_table [] = { diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index b032523b07bc..0a94ec22aeb8 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -18,6 +18,7 @@ struct dtt200u_fe_state { struct dvb_frontend_parameters fep; struct dvb_frontend frontend; + struct dvb_frontend_ops ops; }; static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) @@ -163,8 +164,9 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) deb_info("attaching frontend dtt200u\n"); state->d = d; + memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); - state->frontend.ops = &dtt200u_fe_ops; + state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; goto success; diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 47dba6e45968..5aa12ebab34f 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -98,20 +98,19 @@ static struct dvb_usb_properties wt220u_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE) == 0 || - dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE) == 0) + if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; } static struct usb_device_id dtt200u_usb_table [] = { -// { USB_DEVICE(0x04b4,0x8613) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, - { 0 }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, + { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -189,7 +188,7 @@ static struct dvb_usb_properties wt220u_properties = { .num_device_descs = 1, .devices = { - { .name = "WideView WT-220U PenType Receiver (and clones)", + { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", .cold_ids = { &dtt200u_usb_table[2], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL }, }, @@ -201,9 +200,9 @@ static struct dvb_usb_properties wt220u_properties = { static struct usb_driver dtt200u_usb_driver = { .owner = THIS_MODULE, .name = "dvb_usb_dtt200u", - .probe = dtt200u_usb_probe, + .probe = dtt200u_usb_probe, .disconnect = dvb_usb_device_exit, - .id_table = dtt200u_usb_table, + .id_table = dtt200u_usb_table, }; /* module stuff */ diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 9f0a8d90d146..da970947dfc7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -27,7 +27,6 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) #endif d->i2c_adap.algo = d->props.i2c_algo; d->i2c_adap.algo_data = NULL; - d->i2c_adap.id = I2C_ALGO_BIT; i2c_set_adapdata(&d->i2c_adap, d); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 794d513a8480..0818996bf150 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -24,8 +24,10 @@ #define USB_VID_HANFTEK 0x15f4 #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_KWORLD 0xeb2a #define USB_VID_KYE 0x0458 #define USB_VID_MEDION 0x1660 +#define USB_VID_PINNACLE 0x2304 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 @@ -52,12 +54,14 @@ #define USB_PID_KWORLD_VSTREAM_WARM 0x17df #define USB_PID_TWINHAN_VP7041_COLD 0x3201 #define USB_PID_TWINHAN_VP7041_WARM 0x3202 +#define USB_PID_TWINHAN_VP7020_COLD 0x3203 +#define USB_PID_TWINHAN_VP7020_WARM 0x3204 #define USB_PID_TWINHAN_VP7045_COLD 0x3205 #define USB_PID_TWINHAN_VP7045_WARM 0x3206 -#define USB_PID_DNTV_TINYUSB2_COLD 0x3223 -#define USB_PID_DNTV_TINYUSB2_WARM 0x3224 #define USB_PID_TWINHAN_VP7021_COLD 0x3207 #define USB_PID_TWINHAN_VP7021_WARM 0x3208 +#define USB_PID_DNTV_TINYUSB2_COLD 0x3223 +#define USB_PID_DNTV_TINYUSB2_WARM 0x3224 #define USB_PID_ULTIMA_TVBOX_COLD 0x8105 #define USB_PID_ULTIMA_TVBOX_WARM 0x8106 #define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107 @@ -85,5 +89,7 @@ #define USB_PID_MEDION_MD95700 0x0932 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f +#define USB_PID_PCTV_200E 0x020e +#define USB_PID_PCTV_400E 0x020f #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 65f0c095abc9..a902059812a2 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -128,7 +128,9 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device /* * USB */ -int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties *props, struct module *owner) + +int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties + *props, struct module *owner,struct dvb_usb_device **du) { struct usb_device *udev = interface_to_usbdev(intf); struct dvb_usb_device *d = NULL; @@ -170,6 +172,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties *p usb_set_intfdata(intf, d); + if (du != NULL) + *du = d; + ret = dvb_usb_init(d); } @@ -196,19 +201,6 @@ void dvb_usb_device_exit(struct usb_interface *intf) } EXPORT_SYMBOL(dvb_usb_device_exit); -/* module stuff */ -static int __init dvb_usb_module_init(void) -{ - return 0; -} - -static void __exit dvb_usb_module_exit(void) -{ -} - -module_init (dvb_usb_module_init); -module_exit (dvb_usb_module_exit); - MODULE_VERSION("0.3"); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index a80567caf508..0e4f1035b0dd 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -127,7 +127,7 @@ struct dvb_usb_device; * helper functions. * * @urb: describes the kind of USB transfer used for MPEG2-TS-streaming. - * Currently only BULK is implemented + * (BULK or ISOC) * * @num_device_descs: number of struct dvb_usb_device_description in @devices * @devices: array of struct dvb_usb_device_description compatibles with these @@ -310,7 +310,7 @@ struct dvb_usb_device { void *priv; }; -extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *); +extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *, struct dvb_usb_device **); extern void dvb_usb_device_exit(struct usb_interface *); /* the generic read/write method for device control */ diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index 258a92bfbcc7..1841a66427bf 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -144,7 +144,7 @@ static struct dvb_usb_properties nova_t_properties; static int nova_t_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE,NULL); } /* do not change the order of the ID table */ diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index 2112ac3cf5e2..6fd67657c269 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -77,7 +77,7 @@ static struct dvb_usb_properties umt_properties; static int umt_probe(struct usb_interface *intf, const struct usb_device_id *id) { - if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE) == 0) + if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE,NULL) == 0) return 0; return -EINVAL; } diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c new file mode 100644 index 000000000000..f20d8dbd0be8 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -0,0 +1,339 @@ +/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0 + * DVB-S receiver. + * + * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de> + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de> + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * This file can be removed soon, after the DST-driver is rewritten to provice + * the frontend-controlling separately. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + * + */ +#include "vp702x.h" + +struct vp702x_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; + + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone_mode; + + u8 lnb_buf[8]; + + u8 lock; + u8 sig; + u8 snr; + + unsigned long next_status_check; + unsigned long status_check_interval; +}; + +static int vp702x_fe_refresh_state(struct vp702x_fe_state *st) +{ + u8 buf[10]; + if (time_after(jiffies,st->next_status_check)) { + vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10); + + st->lock = buf[4]; + vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1); + vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1); + + st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; + } + return 0; +} + +static u8 vp702x_chksum(u8 *buf,int f, int count) +{ + u8 s = 0; + int i; + for (i = f; i < f+count; i++) + s += buf[i]; + return ~s+1; +} + +static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + deb_fe("%s\n",__FUNCTION__); + + if (st->lock == 0) + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + *status = 0; + + deb_fe("real state: %x\n",*status); + *status = 0x1f; + + if (*status & FE_HAS_LOCK) + st->status_check_interval = 1000; + else + st->status_check_interval = 250; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *ber = 0; + return 0; +} + +/* not supported by this Frontend */ +static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + *unc = 0; + return 0; +} + +static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + *strength = (st->sig << 8) | st->sig; + return 0; +} + +static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + u8 _snr; + struct vp702x_fe_state *st = fe->demodulator_priv; + vp702x_fe_refresh_state(st); + + _snr = (st->snr & 0x1f) * 0xff / 0x1f; + *snr = (_snr << 8) | _snr; + return 0; +} + +static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + deb_fe("%s\n",__FUNCTION__); + tune->min_delay_ms = 2000; + return 0; +} + +static int vp702x_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u32 freq = fep->frequency/1000; + /*CalFrequency*/ +/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ + u64 sr; + u8 cmd[8] = { 0 },ibuf[10]; + + cmd[0] = (freq >> 8) & 0x7f; + cmd[1] = freq & 0xff; + cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ + + sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20; + do_div(sr,88000); + cmd[3] = (sr >> 12) & 0xff; + cmd[4] = (sr >> 4) & 0xff; + cmd[5] = (sr << 4) & 0xf0; + + deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %Lu (%Lx)\n", + fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, sr, sr); + +/* if (fep->inversion == INVERSION_ON) + cmd[6] |= 0x80; */ + + if (st->voltage == SEC_VOLTAGE_18) + cmd[6] |= 0x40; + +/* if (fep->u.qpsk.symbol_rate > 8000000) + cmd[6] |= 0x20; + + if (fep->frequency < 1531000) + cmd[6] |= 0x04; + + if (st->tone_mode == SEC_TONE_ON) + cmd[6] |= 0x01;*/ + + cmd[7] = vp702x_chksum(cmd,0,7); + + st->status_check_interval = 250; + st->next_status_check = jiffies; + + vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); + msleep(30); + vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); + + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("tuning failed.\n"); + else + deb_fe("tuning succeeded.\n"); + + return 0; +} + +static int vp702x_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + deb_fe("%s\n",__FUNCTION__); + return 0; +} + +static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u8 cmd[8],ibuf[10]; + memset(cmd,0,8); + + deb_fe("%s\n",__FUNCTION__); + + if (m->msg_len > 4) + return -EINVAL; + + cmd[1] = SET_DISEQC_CMD; + cmd[2] = m->msg_len; + memcpy(&cmd[3], m->msg, m->msg_len); + cmd[7] = vp702x_chksum(cmd,0,7); + + vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100); + + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("diseqc cmd failed.\n"); + else + deb_fe("diseqc cmd succeeded.\n"); + + return 0; +} + +static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + deb_fe("%s\n",__FUNCTION__); + return 0; +} + +static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u8 ibuf[10]; + deb_fe("%s\n",__FUNCTION__); + + st->tone_mode = tone; + + if (tone == SEC_TONE_ON) + st->lnb_buf[2] = 0x02; + else + st->lnb_buf[2] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); + + vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("set_tone cmd failed.\n"); + else + deb_fe("set_tone cmd succeeded.\n"); + + return 0; +} + +static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t + voltage) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + u8 ibuf[10]; + deb_fe("%s\n",__FUNCTION__); + + st->voltage = voltage; + + if (voltage != SEC_VOLTAGE_OFF) + st->lnb_buf[4] = 0x01; + else + st->lnb_buf[4] = 0x00; + + st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7); + + vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100); + if (ibuf[2] == 0 && ibuf[3] == 0) + deb_fe("set_voltage cmd failed.\n"); + else + deb_fe("set_voltage cmd succeeded.\n"); + + return 0; +} + +static void vp702x_fe_release(struct dvb_frontend* fe) +{ + struct vp702x_fe_state *st = fe->demodulator_priv; + kfree(st); +} + +static struct dvb_frontend_ops vp702x_fe_ops; + +struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) +{ + struct vp702x_fe_state *s = kmalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + memset(s,0,sizeof(struct vp702x_fe_state)); + + s->d = d; + s->fe.ops = &vp702x_fe_ops; + s->fe.demodulator_priv = s; + + s->lnb_buf[1] = SET_LNB_POWER; + s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ + + goto success; +error: + return NULL; +success: + return &s->fe; +} + + +static struct dvb_frontend_ops vp702x_fe_ops = { + .info = { + .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + .release = vp702x_fe_release, + + .init = NULL, + .sleep = NULL, + + .set_frontend = vp702x_fe_set_frontend, + .get_frontend = vp702x_fe_get_frontend, + .get_tune_settings = vp702x_fe_get_tune_settings, + + .read_status = vp702x_fe_read_status, + .read_ber = vp702x_fe_read_ber, + .read_signal_strength = vp702x_fe_read_signal_strength, + .read_snr = vp702x_fe_read_snr, + .read_ucblocks = vp702x_fe_read_unc_blocks, + + .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, + .diseqc_send_burst = vp702x_fe_send_diseqc_burst, + .set_tone = vp702x_fe_set_tone, + .set_voltage = vp702x_fe_set_voltage, +}; diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c new file mode 100644 index 000000000000..de13c04e8e64 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -0,0 +1,290 @@ +/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S + * receiver. + * + * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de> + * Metzler Brothers Systementwicklung GbR + * + * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de> + * + * Thanks to Twinhan who kindly provided hardware and information. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "vp702x.h" + +/* debug */ +int dvb_usb_vp702x_debug; +module_param_named(debug,dvb_usb_vp702x_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +struct vp702x_state { + u8 pid_table[17]; /* [16] controls the pid_table state */ +}; + +/* check for mutex FIXME */ +int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + int ret = 0,try = 0; + + while (ret >= 0 && ret != blen && try < 3) { + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value,index,b,blen, + 2000); + deb_info("reading number %d (ret: %d)\n",try,ret); + try++; + } + + if (ret < 0 || ret != blen) { + warn("usb in operation failed."); + ret = -EIO; + } else + ret = 0; + + deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + return ret; +} + +int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + if (usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value,index,b,blen, + 2000) != blen) { + warn("usb out operation failed."); + return -EIO; + } else + return 0; +} + +int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec) +{ + int ret; + + if ((ret = down_interruptible(&d->usb_sem))) + return ret; + + if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0) + goto unlock; + msleep(msec); + ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen); + +unlock: + up(&d->usb_sem); + + return ret; +} + +int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, int olen, u8 *i, int ilen, int msec) +{ + u8 bout[olen+2]; + u8 bin[ilen+1]; + int ret = 0; + + bout[0] = 0x00; + bout[1] = cmd; + memcpy(&bout[2],o,olen); + + ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec); + + if (ret == 0) + memcpy(i,&bin[1],ilen); + + return ret; +} + +static int vp702x_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) +{ + struct vp702x_state *st = d->priv; + u8 buf[9]; + + if (onoff) { + st->pid_table[16] |= 1 << index; + st->pid_table[index*2] = (pid >> 8) & 0xff; + st->pid_table[index*2+1] = pid & 0xff; + } else { + st->pid_table[16] &= ~(1 << index); + st->pid_table[index*2] = st->pid_table[index*2+1] = 0; + } + + return vp702x_usb_inout_cmd(d,SET_PID_FILTER,st->pid_table,17,buf,9,10); +} + +static int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + vp702x_usb_in_op(d,RESET_TUNER,0,0,NULL,0); + + vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0); + return vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0); +} + +/* keys for the enclosed remote control */ +static struct dvb_usb_rc_key vp702x_rc_keys[] = { + { 0x00, 0x01, KEY_1 }, + { 0x00, 0x02, KEY_2 }, +}; + +/* remote control stuff (does not work with my box) */ +static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[10]; + int i; + +/* remove the following return to enabled remote querying */ + return 0; + + vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10); + + deb_rc("remote query key: %x %d\n",key[1],key[1]); + + if (key[1] == 0x44) { + *state = REMOTE_NO_KEY_PRESSED; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++) + if (vp702x_rc_keys[i].custom == key[1]) { + *state = REMOTE_KEY_PRESSED; + *event = vp702x_rc_keys[i].event; + break; + } + return 0; +} + +static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) +{ + u8 macb[9]; + if (vp702x_usb_inout_cmd(d, GET_MAC_ADDRESS, NULL, 0, macb, 9, 10)) + return -EIO; + memcpy(mac,&macb[3],6); + return 0; +} + +static int vp702x_frontend_attach(struct dvb_usb_device *d) +{ + u8 buf[9] = { 0 }; + + if (vp702x_usb_inout_cmd(d, GET_SYSTEM_STRING, NULL, 0, buf, 9, 10)) + return -EIO; + + buf[8] = '\0'; + info("system string: %s",&buf[1]); + + d->fe = vp702x_fe_attach(d); + return 0; +} + +static struct dvb_usb_properties vp702x_properties; + +static int vp702x_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + usb_clear_halt(udev,usb_sndctrlpipe(udev,0)); + usb_clear_halt(udev,usb_rcvctrlpipe(udev,0)); + + return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE,NULL); +} + +static struct usb_device_id vp702x_usb_table [] = { + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_WARM) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, + { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, vp702x_usb_table); + +static struct dvb_usb_properties vp702x_properties = { + .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, + .pid_filter_count = 8, /* !!! */ + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-vp702x-01.fw", + + .pid_filter = vp702x_pid_filter, + .power_ctrl = vp702x_power_ctrl, + .frontend_attach = vp702x_frontend_attach, + .read_mac_address = vp702x_read_mac_addr, + + .rc_key_map = vp702x_rc_keys, + .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys), + .rc_interval = 400, + .rc_query = vp702x_rc_query, + + .size_of_priv = sizeof(struct vp702x_state), + + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .num_device_descs = 2, + .devices = { + { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", + .cold_ids = { &vp702x_usb_table[0], NULL }, + .warm_ids = { &vp702x_usb_table[1], NULL }, + }, + { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", + .cold_ids = { &vp702x_usb_table[2], NULL }, + .warm_ids = { &vp702x_usb_table[3], NULL }, + }, + { 0 }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver vp702x_usb_driver = { + .owner = THIS_MODULE, + .name = "dvb-usb-vp702x", + .probe = vp702x_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = vp702x_usb_table, +}; + +/* module stuff */ +static int __init vp702x_usb_module_init(void) +{ + int result; + if ((result = usb_register(&vp702x_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit vp702x_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&vp702x_usb_driver); +} + +module_init(vp702x_usb_module_init); +module_exit(vp702x_usb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); +MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h new file mode 100644 index 000000000000..4a3e8c7eca2b --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp702x.h @@ -0,0 +1,109 @@ +#ifndef _DVB_USB_VP7021_H_ +#define _DVB_USB_VP7021_H_ + +#define DVB_USB_LOG_PREFIX "vp702x" +#include "dvb-usb.h" + +extern int dvb_usb_vp702x_debug; +#define deb_info(args...) dprintk(dvb_usb_vp702x_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp702x_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp702x_debug,0x04,args) +#define deb_fe(args...) dprintk(dvb_usb_vp702x_debug,0x08,args) + +/* commands are read and written with USB control messages */ + +/* consecutive read/write operation */ +#define REQUEST_OUT 0xB2 +#define REQUEST_IN 0xB3 + +/* the out-buffer of these consecutive operations contain sub-commands when b[0] = 0 + * request: 0xB2; i: 0; v: 0; b[0] = 0, b[1] = subcmd, additional buffer + * the returning buffer looks as follows + * request: 0xB3; i: 0; v: 0; b[0] = 0xB3, additional buffer */ + +#define GET_TUNER_STATUS 0x05 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x05 signal-quality N/A N/A signal-strength lock==0 N/A */ + +#define GET_SYSTEM_STRING 0x06 +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A 'U' 'S' 'B' '7' '0' '2' 'X' N/A */ + +#define SET_DISEQC_CMD 0x08 +/* additional out buffer: + * 0 1 2 3 4 + * len X1 X2 X3 X4 + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */ + +#define SET_LNB_POWER 0x09 +/* additional out buffer: + * 0 1 2 + * 0x00 0xff 1 = on, 0 = off + * additional in buffer: + * 0 1 2 + * N/A 0 0 b[1] == b[2] == 0 -> success otherwise not */ + +#define GET_MAC_ADDRESS 0x0A +/* #define GET_MAC_ADDRESS 0x0B */ +/* additional in buffer: + * 0 1 2 3 4 5 6 7 8 + * N/A N/A 0x0A or 0x0B MAC0 MAC1 MAC2 MAC3 MAC4 MAC5 */ + +#define SET_PID_FILTER 0x11 +/* additional in buffer: + * 0 1 ... 14 15 16 + * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */ + +/* request: 0xB2; i: 0; v: 0; + * b[0] != 0 -> tune and lock a channel + * 0 1 2 3 4 5 6 7 + * freq0 freq1 divstep srate0 srate1 srate2 flag chksum + */ + + +/* one direction requests */ +#define READ_REMOTE_REQ 0xB4 +/* IN i: 0; v: 0; b[0] == request, b[1] == key */ + +#define READ_PID_NUMBER_REQ 0xB5 +/* IN i: 0; v: 0; b[0] == request, b[1] == 0, b[2] = pid number */ + +#define WRITE_EEPROM_REQ 0xB6 +/* OUT i: offset; v: value to write; no extra buffer */ + +#define READ_EEPROM_REQ 0xB7 +/* IN i: bufferlen; v: offset; buffer with bufferlen bytes */ + +#define READ_STATUS 0xB8 +/* IN i: 0; v: 0; bufferlen 10 */ + +#define READ_TUNER_REG_REQ 0xB9 +/* IN i: 0; v: register; b[0] = value */ + +#define READ_FX2_REG_REQ 0xBA +/* IN i: offset; v: 0; b[0] = value */ + +#define WRITE_FX2_REG_REQ 0xBB +/* OUT i: offset; v: value to write; 1 byte extra buffer */ + +#define SET_TUNER_POWER_REQ 0xBC +/* IN i: 0 = power off, 1 = power on */ + +#define WRITE_TUNER_REG_REQ 0xBD +/* IN i: register, v: value to write, no extra buffer */ + +#define RESET_TUNER 0xBE +/* IN i: 0, v: 0, no extra buffer */ + +extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); + +extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); +extern int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o, int olen, u8 *i, int ilen, int msec); +extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); + +#endif diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 9ac95f54f9fc..0f57abeb6d6b 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -164,7 +164,6 @@ static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int off return 0; } - static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); @@ -199,7 +198,7 @@ static struct dvb_usb_properties vp7045_properties; static int vp7045_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE); + return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE,NULL); } static struct usb_device_id vp7045_usb_table [] = { @@ -256,9 +255,9 @@ static struct dvb_usb_properties vp7045_properties = { static struct usb_driver vp7045_usb_driver = { .owner = THIS_MODULE, .name = "dvb_usb_vp7045", - .probe = vp7045_usb_probe, + .probe = vp7045_usb_probe, .disconnect = dvb_usb_device_exit, - .id_table = vp7045_usb_table, + .id_table = vp7045_usb_table, }; /* module stuff */ diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 8222b88cb486..d4b97989e3ed 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -1,7 +1,7 @@ /* cx24110 - Single Chip Satellite Channel Receiver driver module - Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on + Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on work Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> @@ -387,8 +387,9 @@ static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { - int rv, bit, i; + int rv, bit; struct cx24110_state *state = fe->demodulator_priv; + unsigned long timeout; if (burst == SEC_MINI_A) bit = 0x00; @@ -398,12 +399,14 @@ static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t return -EINVAL; rv = cx24110_readreg(state, 0x77); - cx24110_writereg(state, 0x77, rv|0x04); + if (!(rv & 0x04)) + cx24110_writereg(state, 0x77, rv | 0x04); rv = cx24110_readreg(state, 0x76); cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit)); - for (i = 500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40) ; ) - ; /* wait for LNB ready */ + timeout = jiffies + msecs_to_jiffies(100); + while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) + ; /* wait for LNB ready */ return 0; } @@ -413,17 +416,22 @@ static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, { int i, rv; struct cx24110_state *state = fe->demodulator_priv; + unsigned long timeout; for (i = 0; i < cmd->msg_len; i++) cx24110_writereg(state, 0x79 + i, cmd->msg[i]); rv = cx24110_readreg(state, 0x77); - cx24110_writereg(state, 0x77, rv|0x04); + if (rv & 0x04) { + cx24110_writereg(state, 0x77, rv & ~0x04); + msleep(30); /* reportedly fixes switching problems */ + } rv = cx24110_readreg(state, 0x76); cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); - for (i=500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);) + timeout = jiffies + msecs_to_jiffies(100); + while (!time_after(jiffies, timeout) && !(cx24110_readreg(state, 0x76) & 0x40)) ; /* wait for LNB ready */ return 0; diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h index 6b663f4744e0..b63ecf26421a 100644 --- a/drivers/media/dvb/frontends/cx24110.h +++ b/drivers/media/dvb/frontends/cx24110.h @@ -1,7 +1,7 @@ /* cx24110 - Single Chip Satellite Channel Receiver driver module - Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on + Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on work Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index cd434b7cf9db..21433e1831e7 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -23,7 +23,6 @@ #include <linux/config.h> #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index cd33705a4320..441de665fec3 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -22,7 +22,6 @@ */ #include <linux/config.h> #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 1f1cd7a8d500..7142b9c51dd2 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -69,8 +69,8 @@ struct lgdt330x_state }; static int i2c_write_demod_bytes (struct lgdt330x_state* state, - u8 *buf, /* data bytes to send */ - int len /* number of bytes to send */ ) + u8 *buf, /* data bytes to send */ + int len /* number of bytes to send */ ) { struct i2c_msg msg = { .addr = state->config->demod_address, @@ -129,13 +129,13 @@ static int lgdt3302_SwReset(struct lgdt330x_state* state) }; ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); + reset, sizeof(reset)); if (ret == 0) { /* force reset high (inactive) and unmask interrupts */ reset[1] = 0x7f; ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); + reset, sizeof(reset)); } return ret; } @@ -149,13 +149,13 @@ static int lgdt3303_SwReset(struct lgdt330x_state* state) }; ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); + reset, sizeof(reset)); if (ret == 0) { /* force reset high (inactive) */ reset[1] = 0x01; ret = i2c_write_demod_bytes(state, - reset, sizeof(reset)); + reset, sizeof(reset)); } return ret; } @@ -172,7 +172,6 @@ static int lgdt330x_SwReset(struct lgdt330x_state* state) } } - static int lgdt330x_init(struct dvb_frontend* fe) { /* Hardware reset is done using gpio[0] of cx23880x chip. @@ -229,13 +228,13 @@ static int lgdt330x_init(struct dvb_frontend* fe) case LGDT3302: chip_name = "LGDT3302"; err = i2c_write_demod_bytes(state, lgdt3302_init_data, - sizeof(lgdt3302_init_data)); - break; + sizeof(lgdt3302_init_data)); + break; case LGDT3303: chip_name = "LGDT3303"; err = i2c_write_demod_bytes(state, lgdt3303_init_data, - sizeof(lgdt3303_init_data)); - break; + sizeof(lgdt3303_init_data)); + break; default: chip_name = "undefined"; printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n"); @@ -262,15 +261,15 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) switch (state->config->demod_chip) { case LGDT3302: err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, - buf, sizeof(buf)); - break; + buf, sizeof(buf)); + break; case LGDT3303: err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, - buf, sizeof(buf)); - break; + buf, sizeof(buf)); + break; default: printk(KERN_WARNING - "Only LGDT3302 and LGDT3303 are supported chips.\n"); + "Only LGDT3302 and LGDT3303 are supported chips.\n"); err = -ENODEV; } @@ -330,7 +329,7 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, if (state->config->demod_chip == LGDT3303) { err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data, - sizeof(lgdt3303_8vsb_44_data)); + sizeof(lgdt3303_8vsb_44_data)); } break; @@ -378,18 +377,19 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, /* Select the requested mode */ i2c_write_demod_bytes(state, top_ctrl_cfg, - sizeof(top_ctrl_cfg)); - state->config->set_ts_params(fe, 0); + sizeof(top_ctrl_cfg)); + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); state->current_modulation = param->u.vsb.modulation; } - /* Change only if we are actually changing the channel */ - if (state->current_frequency != param->frequency) { - /* Tune to the new frequency */ + /* Tune to the specified frequency */ + if (state->config->pll_set) state->config->pll_set(fe, param); - /* Keep track of the new frequency */ - state->current_frequency = param->frequency; - } + + /* Keep track of the new frequency */ + state->current_frequency = param->frequency; + lgdt330x_SwReset(state); return 0; } diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index d32dc4de9e7f..cc1bc0edd65e 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -462,9 +462,11 @@ static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength) { struct mt352_state* state = fe->demodulator_priv; - u16 signal = ((mt352_read_register(state, AGC_GAIN_1) << 8) & 0x0f) | - (mt352_read_register(state, AGC_GAIN_0)); + /* align the 12 bit AGC gain with the most significant bits */ + u16 signal = ((mt352_read_register(state, AGC_GAIN_1) & 0x0f) << 12) | + (mt352_read_register(state, AGC_GAIN_0) << 4); + /* inverse of gain is signal strength */ *strength = ~signal; return 0; } diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index 966de9853d18..88a57b791112 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -482,6 +482,7 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) return result; + msleep(500); return 0; } @@ -525,6 +526,12 @@ static int nxt6000_read_signal_strength(struct dvb_frontend* fe, u16* signal_str return 0; } +static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 500; + return 0; +} + static struct dvb_frontend_ops nxt6000_ops; struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, @@ -578,6 +585,8 @@ static struct dvb_frontend_ops nxt6000_ops = { .init = nxt6000_init, + .get_tune_settings = nxt6000_fe_get_tune_settings, + .set_frontend = nxt6000_set_frontend, .read_status = nxt6000_read_status, diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index cc0a77c790f1..b6d0eecc59eb 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -370,22 +370,19 @@ static int or51132_set_parameters(struct dvb_frontend* fe, or51132_setmode(fe); } - /* Change only if we are actually changing the channel */ - if (state->current_frequency != param->frequency) { - dvb_pll_configure(state->config->pll_desc, buf, - param->frequency, 0); - dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " - "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); - if (i2c_writebytes(state, state->config->pll_address ,buf, 4)) - printk(KERN_WARNING "or51132: set_parameters error " - "writing to tuner\n"); - - /* Set to current mode */ - or51132_setmode(fe); - - /* Update current frequency */ - state->current_frequency = param->frequency; - } + dvb_pll_configure(state->config->pll_desc, buf, + param->frequency, 0); + dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " + "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); + if (i2c_writebytes(state, state->config->pll_address ,buf, 4)) + printk(KERN_WARNING "or51132: set_parameters error " + "writing to tuner\n"); + + /* Set to current mode */ + or51132_setmode(fe); + + /* Update current frequency */ + state->current_frequency = param->frequency; return 0; } diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 4f396ac8de77..c7fe27fd530c 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -48,7 +48,8 @@ struct s5h1420_state { }; static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); -static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings); +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings); static int debug = 0; @@ -91,7 +92,8 @@ static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag switch(voltage) { case SEC_VOLTAGE_13: - s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); + s5h1420_writereg(state, 0x3c, + (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); break; case SEC_VOLTAGE_18: @@ -112,18 +114,21 @@ static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch(tone) { case SEC_TONE_ON: - s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); + s5h1420_writereg(state, 0x3b, + (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); break; case SEC_TONE_OFF: - s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); + s5h1420_writereg(state, 0x3b, + (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); break; } return 0; } -static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +static int s5h1420_send_master_cmd (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) { struct s5h1420_state* state = fe->demodulator_priv; u8 val; @@ -131,6 +136,9 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_m unsigned long timeout; int result = 0; + if (cmd->msg_len > 8) + return -EINVAL; + /* setup for DISEQC */ val = s5h1420_readreg(state, 0x3b); s5h1420_writereg(state, 0x3b, 0x02); @@ -138,16 +146,17 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_m /* write the DISEQC command bytes */ for(i=0; i< cmd->msg_len; i++) { - s5h1420_writereg(state, 0x3c + i, cmd->msg[i]); + s5h1420_writereg(state, 0x3d + i, cmd->msg[i]); } /* kick off transmission */ - s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08); + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | + ((cmd->msg_len-1) << 4) | 0x08); /* wait for transmission to complete */ timeout = jiffies + ((100*HZ) / 1000); while(time_before(jiffies, timeout)) { - if (s5h1420_readreg(state, 0x3b) & 0x08) + if (!(s5h1420_readreg(state, 0x3b) & 0x08)) break; msleep(5); @@ -161,7 +170,8 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_m return result; } -static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply) +static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, + struct dvb_diseqc_slave_reply* reply) { struct s5h1420_state* state = fe->demodulator_priv; u8 val; @@ -205,7 +215,7 @@ static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_ /* extract data */ for(i=0; i< length; i++) { - reply->msg[i] = s5h1420_readreg(state, 0x3c + i); + reply->msg[i] = s5h1420_readreg(state, 0x3d + i); } exit: @@ -236,7 +246,7 @@ static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicm s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08); /* wait for transmission to complete */ - timeout = jiffies + ((20*HZ) / 1000); + timeout = jiffies + ((100*HZ) / 1000); while(time_before(jiffies, timeout)) { if (!(s5h1420_readreg(state, 0x3b) & 0x08)) break; @@ -259,9 +269,9 @@ static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) val = s5h1420_readreg(state, 0x14); if (val & 0x02) - status |= FE_HAS_SIGNAL; // FIXME: not sure if this is right + status |= FE_HAS_SIGNAL; if (val & 0x01) - status |= FE_HAS_CARRIER; // FIXME: not sure if this is right + status |= FE_HAS_CARRIER; val = s5h1420_readreg(state, 0x36); if (val & 0x01) status |= FE_HAS_VITERBI; @@ -284,8 +294,8 @@ static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) /* determine lock state */ *status = s5h1420_get_status_bits(state); - /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert the inversion, - wait a bit and check again */ + /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert + the inversion, wait a bit and check again */ if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) { val = s5h1420_readreg(state, 0x32); if ((val & 0x07) == 0x03) { @@ -330,6 +340,10 @@ static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) tmp = (tmp * 2 * 7) / 8; break; } + if (tmp == 0) { + printk("s5h1420: avoided division by 0\n"); + tmp = 1; + } tmp = state->fclk / tmp; /* set the MPEG_CLK_INTL for the calculated data rate */ @@ -368,16 +382,21 @@ static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber) s5h1420_writereg(state, 0x46, 0x1d); mdelay(25); - return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + *ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + return 0; } static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength) { struct s5h1420_state* state = fe->demodulator_priv; - u8 val = 0xff - s5h1420_readreg(state, 0x15); + u8 val = s5h1420_readreg(state, 0x15); - return (int) ((val << 8) | val); + *strength = (u16) ((val << 8) | val); + + return 0; } static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) @@ -386,7 +405,10 @@ static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) s5h1420_writereg(state, 0x46, 0x1f); mdelay(25); - return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + *ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); + + return 0; } static void s5h1420_reset(struct s5h1420_state* state) @@ -396,11 +418,12 @@ static void s5h1420_reset(struct s5h1420_state* state) udelay(10); } -static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +static void s5h1420_setsymbolrate(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) { u64 val; - val = (p->u.qpsk.symbol_rate / 1000) * (1<<24); + val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); if (p->u.qpsk.symbol_rate <= 21000000) { val *= 2; } @@ -415,7 +438,7 @@ static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_fronte static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) { - u64 val; + u64 val = 0; int sampling = 2; if (s5h1420_readreg(state, 0x05) & 0x2) @@ -427,10 +450,10 @@ static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) val |= s5h1420_readreg(state, 0x13); s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); - val *= (state->fclk / 1000); + val *= (state->fclk / 1000ULL); do_div(val, ((1<<24) * sampling)); - return (u32) (val * 1000); + return (u32) (val * 1000ULL); } static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) @@ -463,46 +486,55 @@ static int s5h1420_getfreqoffset(struct s5h1420_state* state) /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so * divide fclk by 1000000 to get the correct value. */ - val = - ((val * (state->fclk/1000000)) / (1<<24)); + val = (((-val) * (state->fclk/1000000)) / (1<<24)); return val; } -static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +static void s5h1420_setfec_inversion(struct s5h1420_state* state, + struct dvb_frontend_parameters *p) { + u8 inversion = 0; + + if (p->inversion == INVERSION_OFF) { + inversion = state->config->invert ? 0x08 : 0; + } else if (p->inversion == INVERSION_ON) { + inversion = state->config->invert ? 0 : 0x08; + } + if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { - s5h1420_writereg(state, 0x31, 0x00); s5h1420_writereg(state, 0x30, 0x3f); + s5h1420_writereg(state, 0x31, 0x00 | inversion); } else { switch(p->u.qpsk.fec_inner) { case FEC_1_2: - s5h1420_writereg(state, 0x31, 0x10); s5h1420_writereg(state, 0x30, 0x01); + s5h1420_writereg(state, 0x31, 0x10 | inversion); break; case FEC_2_3: - s5h1420_writereg(state, 0x31, 0x11); s5h1420_writereg(state, 0x30, 0x02); + s5h1420_writereg(state, 0x31, 0x11 | inversion); break; case FEC_3_4: - s5h1420_writereg(state, 0x31, 0x12); s5h1420_writereg(state, 0x30, 0x04); - break; + s5h1420_writereg(state, 0x31, 0x12 | inversion); + break; case FEC_5_6: - s5h1420_writereg(state, 0x31, 0x13); s5h1420_writereg(state, 0x30, 0x08); + s5h1420_writereg(state, 0x31, 0x13 | inversion); break; case FEC_6_7: - s5h1420_writereg(state, 0x31, 0x14); s5h1420_writereg(state, 0x30, 0x10); + s5h1420_writereg(state, 0x31, 0x14 | inversion); break; case FEC_7_8: - s5h1420_writereg(state, 0x31, 0x15); s5h1420_writereg(state, 0x30, 0x20); + s5h1420_writereg(state, 0x31, 0x15 | inversion); break; default: @@ -536,22 +568,6 @@ static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) return FEC_NONE; } -static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p) -{ - if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { - s5h1420_writereg(state, 0x31, 0x00); - s5h1420_writereg(state, 0x30, 0x3f); - } else { - u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7; - tmp |= 0x10; - - if (p->inversion == INVERSION_ON) - tmp |= 0x80; - - s5h1420_writereg(state, 0x31, tmp); - } -} - static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) { if (s5h1420_readreg(state, 0x32) & 0x08) @@ -560,35 +576,35 @@ static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) return INVERSION_OFF; } -static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1420_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1420_state* state = fe->demodulator_priv; - u32 frequency_delta; + int frequency_delta; struct dvb_frontend_tune_settings fesettings; + u32 tmp; /* check if we should do a fast-tune */ memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); s5h1420_get_tune_settings(fe, &fesettings); frequency_delta = p->frequency - state->tunedfreq; - if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) && + if ((frequency_delta > -fesettings.max_drift) && + (frequency_delta < fesettings.max_drift) && (frequency_delta != 0) && (state->fec_inner == p->u.qpsk.fec_inner) && (state->symbol_rate == p->u.qpsk.symbol_rate)) { - s5h1420_setfreqoffset(state, frequency_delta); + if (state->config->pll_set) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_set(fe, p, &tmp); + s5h1420_setfreqoffset(state, p->frequency - tmp); + } return 0; } /* first of all, software reset */ s5h1420_reset(state); - /* set tuner PLL */ - if (state->config->pll_set) { - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); - state->config->pll_set(fe, p, &state->tunedfreq); - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); - } - /* set s5h1420 fclk PLL according to desired symbol rate */ if (p->u.qpsk.symbol_rate > 28000000) { state->fclk = 88000000; @@ -609,8 +625,9 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* set misc registers */ s5h1420_writereg(state, 0x02, 0x00); + s5h1420_writereg(state, 0x06, 0x00); s5h1420_writereg(state, 0x07, 0xb0); - s5h1420_writereg(state, 0x0a, 0x67); + s5h1420_writereg(state, 0x0a, 0xe7); s5h1420_writereg(state, 0x0b, 0x78); s5h1420_writereg(state, 0x0c, 0x48); s5h1420_writereg(state, 0x0d, 0x6b); @@ -626,21 +643,26 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* start QPSK */ s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); - /* set the frequency offset to adjust for PLL inaccuracy */ - s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq); + /* set tuner PLL */ + if (state->config->pll_set) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_set(fe, p, &tmp); + s5h1420_setfreqoffset(state, 0); + } /* set the reset of the parameters */ s5h1420_setsymbolrate(state, p); - s5h1420_setinversion(state, p); - s5h1420_setfec(state, p); + s5h1420_setfec_inversion(state, p); state->fec_inner = p->u.qpsk.fec_inner; state->symbol_rate = p->u.qpsk.symbol_rate; state->postlocked = 0; + state->tunedfreq = p->frequency; return 0; } -static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int s5h1420_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { struct s5h1420_state* state = fe->demodulator_priv; @@ -652,7 +674,8 @@ static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) { if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { fesettings->min_delay_ms = 50; @@ -717,7 +740,8 @@ static void s5h1420_release(struct dvb_frontend* fe) static struct dvb_frontend_ops s5h1420_ops; -struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c) +struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, + struct i2c_adapter* i2c) { struct s5h1420_state* state = NULL; u8 identity; diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h index b687fc77ceb3..872028ddf2a2 100644 --- a/drivers/media/dvb/frontends/s5h1420.h +++ b/drivers/media/dvb/frontends/s5h1420.h @@ -30,6 +30,9 @@ struct s5h1420_config /* the demodulator's i2c address */ u8 demod_address; + /* does the inversion require inversion? */ + u8 invert:1; + /* PLL maintenance */ int (*pll_init)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout); diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 928aca052afe..8d09afd7545d 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -35,7 +35,6 @@ struct stv0297_state { struct dvb_frontend frontend; unsigned long base_freq; - u8 pwm; }; #if 1 @@ -46,94 +45,6 @@ struct stv0297_state { #define STV0297_CLOCK_KHZ 28900 -static u8 init_tab[] = { - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x00, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0xff, - 0x4b, 0x7f, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x00, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x00, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x53, - 0xc1, 0x70, - 0xc2, 0x12, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x49, - 0x62, 0x0b, - 0x53, 0x08, - 0x59, 0x08, -}; - static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) { @@ -378,34 +289,9 @@ static int stv0297_init(struct dvb_frontend *fe) struct stv0297_state *state = fe->demodulator_priv; int i; - /* soft reset */ - stv0297_writereg_mask(state, 0x80, 1, 1); - stv0297_writereg_mask(state, 0x80, 1, 0); - - /* reset deinterleaver */ - stv0297_writereg_mask(state, 0x81, 1, 1); - stv0297_writereg_mask(state, 0x81, 1, 0); - /* load init table */ - for (i = 0; i < sizeof(init_tab); i += 2) { - stv0297_writereg(state, init_tab[i], init_tab[i + 1]); - } - - /* set a dummy symbol rate */ - stv0297_set_symbolrate(state, 6900); - - /* invert AGC1 polarity */ - stv0297_writereg_mask(state, 0x88, 0x10, 0x10); - - /* setup bit error counting */ - stv0297_writereg_mask(state, 0xA0, 0x80, 0x00); - stv0297_writereg_mask(state, 0xA0, 0x10, 0x00); - stv0297_writereg_mask(state, 0xA0, 0x08, 0x00); - stv0297_writereg_mask(state, 0xA0, 0x07, 0x04); - - /* min + max PWM */ - stv0297_writereg(state, 0x4a, 0x00); - stv0297_writereg(state, 0x4b, state->pwm); + for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) + stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]); msleep(200); if (state->config->pll_init) @@ -606,7 +492,13 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_set_inversion(state, inversion); /* kick off lock */ - stv0297_writereg_mask(state, 0x88, 0x08, 0x08); + /* Disable corner detection for higher QAMs */ + if (p->u.qam.modulation == QAM_128 || + p->u.qam.modulation == QAM_256) + stv0297_writereg_mask(state, 0x88, 0x08, 0x00); + else + stv0297_writereg_mask(state, 0x88, 0x08, 0x08); + stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); stv0297_writereg_mask(state, 0x43, 0x40, 0x40); @@ -732,7 +624,7 @@ static void stv0297_release(struct dvb_frontend *fe) static struct dvb_frontend_ops stv0297_ops; struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, - struct i2c_adapter *i2c, int pwm) + struct i2c_adapter *i2c) { struct stv0297_state *state = NULL; @@ -746,7 +638,6 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, state->i2c = i2c; memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); state->base_freq = 0; - state->pwm = pwm; /* check if the demod is there */ if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h index 3be535989302..9e53f019db71 100644 --- a/drivers/media/dvb/frontends/stv0297.h +++ b/drivers/media/dvb/frontends/stv0297.h @@ -29,6 +29,12 @@ struct stv0297_config /* the demodulator's i2c address */ u8 demod_address; + /* inittab - array of pairs of values. + * First of each pair is the register, second is the value. + * List should be terminated with an 0xff, 0xff pair. + */ + u8* inittab; + /* does the "inversion" need inverted? */ u8 invert:1; @@ -38,7 +44,7 @@ struct stv0297_config }; extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, - struct i2c_adapter* i2c, int pwm); + struct i2c_adapter* i2c); extern int stv0297_enable_plli2c(struct dvb_frontend* fe); #endif // STV0297_H diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index cfa3928bb487..2d62931f20b5 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -63,12 +63,8 @@ struct stv0299_state { u32 tuner_frequency; u32 symbol_rate; fe_code_rate_t fec_inner; - int errmode; }; -#define STATUS_BER 0 -#define STATUS_UCBLOCKS 1 - static int debug; static int debug_legacy_dish_switch; #define dprintk(args...) \ @@ -481,7 +477,7 @@ static int stv0299_init (struct dvb_frontend* fe) if (state->config->pll_init) { stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_init(fe); + state->config->pll_init(fe, state->i2c); stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ } @@ -520,7 +516,8 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) { struct stv0299_state* state = fe->demodulator_priv; - if (state->errmode != STATUS_BER) return 0; + stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x10); + msleep(100); *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); return 0; @@ -559,8 +556,9 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct stv0299_state* state = fe->demodulator_priv; - if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; - else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); + stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x30); + msleep(100); + *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); return 0; } @@ -603,7 +601,7 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par } else { /* A "normal" tune is requested */ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, p); + state->config->pll_set(fe, state->i2c, p); stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ stv0299_writeregI(state, 0x32, 0x80); @@ -615,7 +613,7 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par } } else { stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, p); + state->config->pll_set(fe, state->i2c, p); stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ stv0299_set_FEC (state, p->u.qpsk.fec_inner); @@ -709,7 +707,6 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, state->tuner_frequency = 0; state->symbol_rate = 0; state->fec_inner = 0; - state->errmode = STATUS_BER; /* check if the demod is there */ stv0299_writeregI(state, 0x02, 0x34); /* standby off */ diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 79457a80a11f..d0c4484861e1 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -92,8 +92,8 @@ struct stv0299_config int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c); + int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params); }; extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index ab0c032472cc..74cea9f8d721 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -1046,8 +1046,7 @@ static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr) tmp = tda1004x_read_byte(state, TDA1004X_SNR); if (tmp < 0) return -EIO; - if (tmp) - tmp = 255 - tmp; + tmp = 255 - tmp; *snr = ((tmp << 8) | tmp); dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr); diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 70fb44b391a7..c6d276618e86 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -194,19 +194,18 @@ static int ves1820_init(struct dvb_frontend* fe) { struct ves1820_state* state = fe->demodulator_priv; int i; - int val; ves1820_writereg(state, 0, 0); - for (i = 0; i < 53; i++) { - val = ves1820_inittab[i]; - if ((i == 2) && (state->config->selagc)) val |= 0x08; - ves1820_writereg(state, i, val); - } + for (i = 0; i < sizeof(ves1820_inittab); i++) + ves1820_writereg(state, i, ves1820_inittab[i]); + if (state->config->selagc) + ves1820_writereg(state, 2, ves1820_inittab[2] | 0x08); ves1820_writereg(state, 0x34, state->pwm); - if (state->config->pll_init) state->config->pll_init(fe); + if (state->config->pll_init) + state->config->pll_init(fe); return 0; } @@ -234,7 +233,7 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p ves1820_writereg(state, 0x09, reg0x09[real_qam]); ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion); - + ves1820_writereg(state, 2, ves1820_inittab[2] | (state->config->selagc ? 0x08 : 0)); return 0; } diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 706e0bcb5ede..85b437bbddcd 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -633,7 +633,6 @@ static int __devinit pluto2_probe(struct pci_dev *pdev, i2c_set_adapdata(&pluto->i2c_adap, pluto); strcpy(pluto->i2c_adap.name, DRIVER_NAME); pluto->i2c_adap.owner = THIS_MODULE; - pluto->i2c_adap.id = I2C_ALGO_BIT; pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL; pluto->i2c_adap.dev.parent = &pdev->dev; pluto->i2c_adap.algo_data = &pluto->i2c_bit; diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index e4c6e87f6c5d..22b203f8ff27 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -168,7 +168,9 @@ static void init_av7110_av(struct av7110 *av7110) if (ret < 0) printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); if (rgb_on && - (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { + ((av7110->dev->pci->subsystem_vendor == 0x110a) || + (av7110->dev->pci->subsystem_vendor == 0x13c2)) && + (av7110->dev->pci->subsystem_device == 0x0000)) { saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 //saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8 } @@ -177,9 +179,6 @@ static void init_av7110_av(struct av7110 *av7110) ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); if (ret < 0) printk("dvb-ttpci:cannot set volume :%d\n",ret); - ret = av7110_setup_irc_config(av7110, 0); - if (ret < 0) - printk("dvb-ttpci:cannot setup irc config :%d\n",ret); } static void recover_arm(struct av7110 *av7110) @@ -265,60 +264,6 @@ static int arm_thread(void *data) } -/** - * Hack! we save the last av7110 ptr. This should be ok, since - * you rarely will use more then one IR control. - * - * If we want to support multiple controls we would have to do much more... - */ -int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) -{ - int ret = 0; - static struct av7110 *last; - - dprintk(4, "%p\n", av7110); - - if (!av7110) - av7110 = last; - else - last = av7110; - - if (av7110) { - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); - av7110->ir_config = ir_config; - } - return ret; -} - -static void (*irc_handler)(u32); - -void av7110_register_irc_handler(void (*func)(u32)) -{ - dprintk(4, "registering %p\n", func); - irc_handler = func; -} - -void av7110_unregister_irc_handler(void (*func)(u32)) -{ - dprintk(4, "unregistering %p\n", func); - irc_handler = NULL; -} - -static void run_handlers(unsigned long ircom) -{ - if (irc_handler != NULL) - (*irc_handler)((u32) ircom); -} - -static DECLARE_TASKLET(irtask, run_handlers, 0); - -static void IR_handle(struct av7110 *av7110, u32 ircom) -{ - dprintk(4, "ircommand = %08x\n", ircom); - irtask.data = (unsigned long) ircom; - tasklet_schedule(&irtask); -} - /**************************************************************************** * IRQ handling ****************************************************************************/ @@ -711,8 +656,9 @@ static void gpioirq(unsigned long data) return; case DATA_IRCOMMAND: - IR_handle(av7110, - swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); + if (av7110->ir_handler) + av7110->ir_handler(av7110, + swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; @@ -1668,9 +1614,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct av7110* av7110 = (struct av7110*) fe->dvb->priv; int ret; u8 data[4]; u32 div; @@ -1687,7 +1632,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param if (params->frequency > 1530000) data[3] = 0xc0; - ret = i2c_transfer(&av7110->i2c_adap, &msg, 1); + ret = i2c_transfer(i2c, &msg, 1); if (ret != 1) return -EIO; return 0; @@ -1751,9 +1696,8 @@ static u8 alps_bsbe1_inittab[] = { 0xff, 0xff }; -static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct av7110* av7110 = (struct av7110*) fe->dvb->priv; int ret; u8 data[4]; u32 div; @@ -1768,7 +1712,7 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4; - ret = i2c_transfer(&av7110->i2c_adap, &msg, 1); + ret = i2c_transfer(i2c, &msg, 1); return (ret != 1) ? -EIO : 0; } @@ -1936,6 +1880,98 @@ static struct sp8870_config alps_tdlb7_config = { }; +static u8 nexusca_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, + 0xff, 0xff, +}; static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { @@ -1984,6 +2020,7 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ static struct stv0297_config nexusca_stv0297_config = { .demod_address = 0x1C, + .inittab = nexusca_stv0297_inittab, .invert = 1, .pll_set = nexusca_stv0297_pll_set, }; @@ -2261,7 +2298,7 @@ static int frontend_init(struct av7110 *av7110) case 0x000A: // Hauppauge/TT Nexus-CA rev1.X - av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b); + av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap); if (av7110->fe) { /* set TDA9819 into DVB mode */ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) @@ -2692,7 +2729,7 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d goto err_av7110_exit_v4l_12; #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_init(); + av7110_ir_init(av7110); #endif printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); av7110_num++; @@ -2734,6 +2771,9 @@ static int av7110_detach(struct saa7146_dev* saa) struct av7110 *av7110 = saa->ext_priv; dprintk(4, "%p\n", av7110); +#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) + av7110_ir_exit(av7110); +#endif if (budgetpatch) { /* Disable RPS1 */ saa7146_write(saa, MC1, MASK_29); @@ -2830,7 +2870,7 @@ static struct saa7146_pci_extension_data x_var = { \ .ext_priv = x_name, \ .ext = &av7110_extension } -MAKE_AV7110_INFO(tts_1_X, "Technotrend/Hauppauge WinTV DVB-S rev1.X"); +MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C"); MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); @@ -2842,16 +2882,16 @@ MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), - MAKE_EXTENSION_PCI(tts_1_X, 0x13c2, 0x0000), - MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), - MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), - MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), - MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), - MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), - MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), - MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), - MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), + MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), + MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), + MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), + MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), + MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), + MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), + MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), + MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), + MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte /* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 @@ -2889,9 +2929,6 @@ static int __init av7110_init(void) static void __exit av7110_exit(void) { -#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) - av7110_ir_exit(); -#endif saa7146_unregister_extension(&av7110_extension); } diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 508b7739c609..cce00ef293e9 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -228,7 +228,10 @@ struct av7110 { struct dvb_video_events video_events; video_size_t video_size; - u32 ir_config; + u32 ir_config; + u32 ir_command; + void (*ir_handler)(struct av7110 *av7110, u32 ircom); + struct tasklet_struct ir_tasklet; /* firmware stuff */ unsigned char *bin_fw; @@ -257,12 +260,10 @@ struct av7110 { extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid); -extern void av7110_register_irc_handler(void (*func)(u32)); -extern void av7110_unregister_irc_handler(void (*func)(u32)); extern int av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config); -extern int av7110_ir_init (void); -extern void av7110_ir_exit (void); +extern int av7110_ir_init(struct av7110 *av7110); +extern void av7110_ir_exit(struct av7110 *av7110); /* msp3400 i2c subaddresses */ #define MSP_WR_DEM 0x10 diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 1220826696c5..7442f56a72ec 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -41,6 +41,8 @@ #include "av7110.h" #include "av7110_hw.h" +#define _NOHANDSHAKE + /**************************************************************************** * DEBI functions ****************************************************************************/ @@ -364,7 +366,8 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) msleep(1); } - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); #ifndef _NOHANDSHAKE start = jiffies; @@ -437,7 +440,8 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); - wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); #ifdef COM_DEBUG start = jiffies; diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 665cdb8a3f71..357a3728ec68 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -7,16 +7,16 @@ #include <asm/bitops.h> #include "av7110.h" +#include "av7110_hw.h" -#define UP_TIMEOUT (HZ/4) +#define UP_TIMEOUT (HZ*7/25) /* enable ir debugging by or'ing debug with 16 */ -static int ir_initialized; +static int av_cnt; +static struct av7110 *av_list[4]; static struct input_dev input_dev; -static u32 ir_config; - static u16 key_map [256] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, @@ -53,8 +53,11 @@ static void av7110_emit_keyup(unsigned long data) static struct timer_list keyup_timer = { .function = av7110_emit_keyup }; -static void av7110_emit_key(u32 ircom) +static void av7110_emit_key(unsigned long parm) { + struct av7110 *av7110 = (struct av7110 *) parm; + u32 ir_config = av7110->ir_config; + u32 ircom = av7110->ir_command; u8 data; u8 addr; static u16 old_toggle = 0; @@ -62,19 +65,33 @@ static void av7110_emit_key(u32 ircom) u16 keycode; /* extract device address and data */ - if (ir_config & 0x0001) { - /* TODO RCMM: ? bits device address, 8 bits data */ + switch (ir_config & 0x0003) { + case 0: /* RC5: 5 bits device address, 6 bits data */ + data = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + break; + + case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */ data = ircom & 0xff; addr = (ircom >> 8) & 0xff; - } else { - /* RC5: 5 bits device address, 6 bits data */ + break; + + case 2: /* extended RC5: 5 bits device address, 7 bits data */ data = ircom & 0x3f; addr = (ircom >> 6) & 0x1f; + /* invert 7th data bit for backward compatibility with RC5 keymaps */ + if (!(ircom & 0x1000)) + data |= 0x40; + break; + + default: + printk("invalid ir_config %x\n", ir_config); + return; } keycode = key_map[data]; - dprintk(16, "#########%08x######### addr %i data 0x%02x (keycode %i)\n", + dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n", ircom, addr, data, keycode); /* check device address (if selected) */ @@ -87,10 +104,10 @@ static void av7110_emit_key(u32 ircom) return; } - if (ir_config & 0x0001) + if ((ir_config & 0x0003) == 1) new_toggle = 0; /* RCMM */ else - new_toggle = (ircom & 0x800); /* RC5 */ + new_toggle = (ircom & 0x800); /* RC5, extended RC5 */ if (timer_pending(&keyup_timer)) { del_timer(&keyup_timer); @@ -137,6 +154,8 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, { char *page; int size = 4 + 256 * sizeof(u16); + u32 ir_config; + int i; if (count < size) return -EINVAL; @@ -153,60 +172,95 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer, memcpy(&ir_config, page, 4); memcpy(&key_map, page + 4, 256 * sizeof(u16)); vfree(page); - av7110_setup_irc_config(NULL, ir_config); + if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001)) + ir_config |= 0x0002; /* enable extended RC5 */ + for (i = 0; i < av_cnt; i++) + av7110_setup_irc_config(av_list[i], ir_config); input_register_keys(); return count; } -int __init av7110_ir_init(void) +int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) { - static struct proc_dir_entry *e; + int ret = 0; - if (ir_initialized) - return 0; + dprintk(4, "%p\n", av7110); + if (av7110) { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); + av7110->ir_config = ir_config; + } + return ret; +} - init_timer(&keyup_timer); - keyup_timer.data = 0; - input_dev.name = "DVB on-card IR receiver"; +static void ir_handler(struct av7110 *av7110, u32 ircom) +{ + dprintk(4, "ircommand = %08x\n", ircom); + av7110->ir_command = ircom; + tasklet_schedule(&av7110->ir_tasklet); +} - /** - * enable keys - */ - set_bit(EV_KEY, input_dev.evbit); - set_bit(EV_REP, input_dev.evbit); - input_register_keys(); +int __init av7110_ir_init(struct av7110 *av7110) +{ + static struct proc_dir_entry *e; - input_register_device(&input_dev); - input_dev.timer.function = input_repeat_key; + if (av_cnt >= sizeof av_list/sizeof av_list[0]) + return -ENOSPC; - av7110_setup_irc_config(NULL, 0x0001); - av7110_register_irc_handler(av7110_emit_key); + av7110_setup_irc_config(av7110, 0x0001); + av_list[av_cnt++] = av7110; - e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); - if (e) { - e->write_proc = av7110_ir_write_proc; - e->size = 4 + 256 * sizeof(u16); + if (av_cnt == 1) { + init_timer(&keyup_timer); + keyup_timer.data = 0; + + input_dev.name = "DVB on-card IR receiver"; + set_bit(EV_KEY, input_dev.evbit); + set_bit(EV_REP, input_dev.evbit); + input_register_keys(); + input_register_device(&input_dev); + input_dev.timer.function = input_repeat_key; + + e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); + if (e) { + e->write_proc = av7110_ir_write_proc; + e->size = 4 + 256 * sizeof(u16); + } } - ir_initialized = 1; + tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110); + av7110->ir_handler = ir_handler; + return 0; } -void __exit av7110_ir_exit(void) +void __exit av7110_ir_exit(struct av7110 *av7110) { - if (ir_initialized == 0) + int i; + + if (av_cnt == 0) return; - del_timer_sync(&keyup_timer); - remove_proc_entry("av7110_ir", NULL); - av7110_unregister_irc_handler(av7110_emit_key); - input_unregister_device(&input_dev); - ir_initialized = 0; + + av7110->ir_handler = NULL; + tasklet_kill(&av7110->ir_tasklet); + for (i = 0; i < av_cnt; i++) + if (av_list[i] == av7110) { + av_list[i] = av_list[av_cnt-1]; + av_list[av_cnt-1] = NULL; + break; + } + + if (av_cnt == 1) { + del_timer_sync(&keyup_timer); + remove_proc_entry("av7110_ir", NULL); + input_unregister_device(&input_dev); + } + + av_cnt--; } //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>"); //MODULE_LICENSE("GPL"); - diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index e65fc36e2ce8..6af74f78b3e5 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -70,7 +70,7 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) return 0; } -static struct v4l2_input inputs[2] = { +static struct v4l2_input inputs[4] = { { .index = 0, .name = "DVB", @@ -87,6 +87,22 @@ static struct v4l2_input inputs[2] = { .tuner = 0, .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, .status = 0, + }, { + .index = 2, + .name = "Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + }, { + .index = 3, + .name = "Y/C", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, } }; @@ -212,24 +228,44 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) } if (0 != av7110->current_input) { + dprintk(1, "switching to analog TV:\n"); adswitch = 1; source = SAA7146_HPS_SOURCE_PORT_B; sync = SAA7146_HPS_SYNC_PORT_B; memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2); - dprintk(1, "switching to analog TV\n"); - msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source - msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source - msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source - msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono - msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone - msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume - if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { - if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) - dprintk(1, "setting band in demodulator failed.\n"); - } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF) + switch (av7110->current_input) { + case 1: + dprintk(1, "switching SAA7113 to Analog Tuner Input.\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) + dprintk(1, "setting band in demodulator failed.\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF) + } + if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 2: + dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 3: + dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + default: + dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n"); } } else { adswitch = 0; @@ -300,7 +336,6 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) // FIXME: standard / stereo detection is still broken msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); - msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); stereo = (s8)(stereo_det >> 8); @@ -310,7 +345,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) t->audmode = V4L2_TUNER_MODE_STEREO; } else if (stereo < -0x10) { - /* bilingual*/ + /* bilingual */ t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; t->audmode = V4L2_TUNER_MODE_LANG1; } @@ -344,7 +379,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) fm_matrix = 0x3000; // mono src = 0x0010; break; - default: /* case V4L2_TUNER_MODE_MONO: {*/ + default: /* case V4L2_TUNER_MODE_MONO: */ dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); fm_matrix = 0x3000; // mono src = 0x0030; @@ -406,7 +441,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); if (av7110->analog_tuner_flags) { - if (i->index < 0 || i->index >= 2) + if (i->index < 0 || i->index >= 4) return -EINVAL; } else { if (i->index != 0) @@ -433,10 +468,9 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) if (!av7110->analog_tuner_flags) return 0; - if (input < 0 || input >= 2) + if (input < 0 || input >= 4) return -EINVAL; - /* FIXME: switch inputs here */ av7110->current_input = input; return av7110_dvb_c_switch(fh); } diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9746d2bb916f..7692cd23f839 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -192,7 +192,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int timeout = 50; // 5 seconds (4.4.6 Ready) + int timeout = 500; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; @@ -217,7 +217,6 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ return -ETIMEDOUT; } @@ -276,7 +275,6 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open { printk(KERN_INFO "budget-av: cam ejected\n"); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ budget_av->slot_status = 0; } } @@ -453,9 +451,9 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra } static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { - struct budget_av *budget_av = (struct budget_av *) fe->dvb->priv; u32 div; u8 buf[4]; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -481,7 +479,7 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, else if (params->frequency < 2150000) buf[3] |= 0xC0; - if (i2c_transfer(&budget_av->budget.i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } @@ -745,6 +743,7 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBC_KNC1_PLUS: case SUBID_DVBT_KNC1_PLUS: // Enable / PowerON Frontend + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); break; } diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index a1267054bc01..2980db3ef22f 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -40,6 +40,7 @@ #include "dvb_ca_en50221.h" #include "stv0299.h" +#include "stv0297.h" #include "tda1004x.h" #define DEBIADDR_IR 0x1234 @@ -548,9 +549,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -567,7 +567,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_param if (params->frequency > 1530000) buf[3] = 0xc0; - if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } @@ -669,9 +669,9 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, } static int philips_su1278_tt_pll_set(struct dvb_frontend *fe, + struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u32 div; u8 buf[4]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -697,7 +697,7 @@ static int philips_su1278_tt_pll_set(struct dvb_frontend *fe, else if (params->frequency < 2150000) buf[3] |= 0xC0; - if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } @@ -848,6 +848,180 @@ static struct tda1004x_config philips_tdm1316l_config = { .request_firmware = philips_tdm1316l_request_firmware, }; +static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 tuner_buf[5]; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, + .flags = 0, + .buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36125000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) { + cp = 3; + band = 1; + } else if (tuner_frequency < 160000000) { + cp = 5; + band = 1; + } else if (tuner_frequency < 200000000) { + cp = 6; + band = 1; + } else if (tuner_frequency < 290000000) { + cp = 3; + band = 2; + } else if (tuner_frequency < 420000000) { + cp = 5; + band = 2; + } else if (tuner_frequency < 480000000) { + cp = 6; + band = 2; + } else if (tuner_frequency < 620000000) { + cp = 3; + band = 4; + } else if (tuner_frequency < 830000000) { + cp = 5; + band = 4; + } else if (tuner_frequency < 895000000) { + cp = 7; + band = 4; + } else + return -EINVAL; + + // assume PLL filter should always be 8MHz for the moment. + filter = 1; + + // calculate divisor + tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xc8; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + tuner_buf[4] = 0x80; + + stv0297_enable_plli2c(fe); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(50); + + stv0297_enable_plli2c(fe); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + + return 0; +} + +static u8 dvbc_philips_tdm1316l_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x20, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x38, + 0x62, 0x0a, + 0x53, 0x13, + 0x59, 0x08, + 0xff, 0xff, +}; + +static struct stv0297_config dvbc_philips_tdm1316l_config = { + .demod_address = 0x1c, + .inittab = dvbc_philips_tdm1316l_inittab, + .invert = 0, + .pll_set = dvbc_philips_tdm1316l_pll_set, +}; + + static void frontend_init(struct budget_ci *budget_ci) @@ -869,6 +1043,15 @@ static void frontend_init(struct budget_ci *budget_ci) } break; + case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) + budget_ci->tuner_pll_address = 0x61; + budget_ci->budget.dvb_frontend = + stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + break; + } + break; + case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) budget_ci->tuner_pll_address = 0x63; budget_ci->budget.dvb_frontend = @@ -878,7 +1061,7 @@ static void frontend_init(struct budget_ci *budget_ci) } break; - case 0x1012: // Hauppauge/TT Nova-T CI budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) budget_ci->tuner_pll_address = 0x60; budget_ci->budget.dvb_frontend = tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); @@ -966,10 +1149,12 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), + MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), { diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 8142e26b47f5..b1f21ef0e3b3 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -353,9 +353,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; @@ -370,7 +369,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param if (params->frequency > 1530000) data[3] = 0xc0; - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 9961917e8a7f..43d6c8268642 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -332,9 +332,8 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { - struct budget* budget = (struct budget*) fe->dvb->priv; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; @@ -349,7 +348,7 @@ static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param if (params->frequency > 1530000) data[3] = 0xc0; - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; } @@ -481,6 +480,7 @@ static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete static struct s5h1420_config s5h1420_config = { .demod_address = 0x53, + .invert = 1, .pll_set = s5h1420_pll_set, }; diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index aa43b5fcb8e7..d200ab0ad9e7 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/time.h> #include <linux/errno.h> +#include <linux/jiffies.h> #include <asm/semaphore.h> #include "dvb_frontend.h" @@ -570,7 +571,8 @@ static void ttusb_handle_sec_data(struct ttusb_channel *channel, const u8 * data, int len); #endif -static int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid; +static int numpkt = 0, numts, numstuff, numsec, numinvalid; +static unsigned long lastj; static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, int len) @@ -779,7 +781,7 @@ static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs) u8 *data; int len; numpkt++; - if ((jiffies - lastj) >= HZ) { + if (time_after_eq(jiffies, lastj + HZ)) { #if DEBUG > 2 printk ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n", @@ -1299,7 +1301,7 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 return 0; } -static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; @@ -1322,7 +1324,7 @@ static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ if (ttusb->revision == TTUSB_REV_2_2) buf[3] |= 0x20; - if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) + if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; @@ -1472,8 +1474,6 @@ static void frontend_init(struct ttusb* ttusb) static struct i2c_algorithm ttusb_dec_algo = { - .name = "ttusb dec i2c algorithm", - .id = I2C_ALGO_BIT, .master_xfer = master_xfer, .functionality = functionality, }; @@ -1525,7 +1525,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i #endif ttusb->i2c_adap.algo = &ttusb_dec_algo; ttusb->i2c_adap.algo_data = NULL; - ttusb->i2c_adap.id = I2C_ALGO_BIT; result = i2c_add_adapter(&ttusb->i2c_adap); if (result) { diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 45c9a9a08e4d..3d08fc83a754 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -28,7 +28,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/usb.h> -#include <linux/version.h> #include <linux/interrupt.h> #include <linux/firmware.h> #include <linux/crc32.h> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 3f5742396096..93570355819a 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -22,12 +22,21 @@ config VIDEO_BT848 the Miro, Hauppauge and STB boards. Please read the material in <file:Documentation/video4linux/bttv/> for more information. - If you say Y or M here, you need to say Y or M to "I2C support" and - "I2C bit-banging interfaces" in the device drivers section. - To compile this driver as a module, choose M here: the module will be called bttv. +config VIDEO_SAA6588 + tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards" + depends on VIDEO_DEV && I2C && VIDEO_BT848 + + help + Support for Radio Data System (RDS) decoder. This allows seeing + radio station identification transmitted using this standard. + Currentlly, it works only with bt8x8 chips. + + To compile this driver as a module, choose M here: the + module will be called saa6588. + config VIDEO_PMS tristate "Mediavision Pro Movie Studio Video For Linux" depends on VIDEO_DEV && ISA @@ -254,6 +263,7 @@ config VIDEO_SAA7134_DVB select VIDEO_BUF_DVB select DVB_MT352 select DVB_CX22702 + select DVB_TDA1004X ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 810e7aac0a53..046b82de9285 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -5,6 +5,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o +rds-objs := saa6588.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o @@ -15,6 +16,7 @@ obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o +obj-$(CONFIG_VIDEO_SAA6588) += rds.o obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o @@ -29,7 +31,7 @@ obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o obj-$(CONFIG_VIDEO_PMS) += pms.o obj-$(CONFIG_VIDEO_PLANB) += planb.o -obj-$(CONFIG_VIDEO_VINO) += vino.o +obj-$(CONFIG_VIDEO_VINO) += vino.o saa7191.o indycam.o obj-$(CONFIG_VIDEO_STRADIS) += stradis.o obj-$(CONFIG_VIDEO_CPIA) += cpia.o obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 48989eda2400..1ca2b67aedfb 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -43,7 +43,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/videodev.h> @@ -391,7 +390,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_adv7170; diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c index f898b6586374..173bca1e0295 100644 --- a/drivers/media/video/adv7175.c +++ b/drivers/media/video/adv7175.c @@ -39,7 +39,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/videodev.h> @@ -441,7 +440,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_adv7175; diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index 8733588f6db3..3ee0afca76a7 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -43,7 +43,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/videodev.h> @@ -507,7 +506,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_bt819; diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index a070417e65e6..76c1b63ebdf2 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c @@ -188,7 +188,7 @@ static int bt832_probe(struct i2c_adapter *adap) if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, bt832_attach); #else - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + if (adap->id == I2C_HW_B_BT848) return i2c_probe(adap, &addr_data, bt832_attach); #endif return 0; @@ -241,7 +241,7 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - I2C_DEVNAME("bt832"), + .name = "bt832", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, }; diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c index a5d529ccf3ad..8eb871d0e85b 100644 --- a/drivers/media/video/bt856.c +++ b/drivers/media/video/bt856.c @@ -43,7 +43,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/videodev.h> @@ -295,7 +294,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_bt856; diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c index 7f2d515d2873..a48de3c0e3f0 100644 --- a/drivers/media/video/btcx-risc.c +++ b/drivers/media/video/btcx-risc.c @@ -1,5 +1,4 @@ /* - $Id: btcx-risc.c,v 1.6 2005/02/21 13:57:59 kraxel Exp $ btcx-risc.c diff --git a/drivers/media/video/btcx-risc.h b/drivers/media/video/btcx-risc.h index 41f60395a520..503e6c6d7b69 100644 --- a/drivers/media/video/btcx-risc.h +++ b/drivers/media/video/btcx-risc.h @@ -1,5 +1,4 @@ /* - * $Id: btcx-risc.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $ */ struct btcx_riscmem { unsigned int size; diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index a97b9b958ed6..190977a1e549 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -1,5 +1,4 @@ /* - $Id: bttv-cards.c,v 1.54 2005/07/19 18:26:46 mkrufky Exp $ bttv-cards.c @@ -169,10 +168,10 @@ static struct CARD { { 0xd01810fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, - // some cards ship with byteswapped IDs ... + /* some cards ship with byteswapped IDs ... */ { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, { 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, - // this seems to happen as well ... + /* this seems to happen as well ... */ { 0xff1211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, @@ -200,12 +199,12 @@ static struct CARD { { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV Radio+" }, { 0x1127153b, BTTV_TERRATV, "Terratec TV+ (V1.05)" }, - // clashes with FlyVideo - //{ 0x18521852, BTTV_TERRATV, "Terratec TV+ (V1.10)" }, + /* clashes with FlyVideo + *{ 0x18521852, BTTV_TERRATV, "Terratec TV+ (V1.10)" }, */ { 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue (LR102)" }, - { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, // LR102 - { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, // ?? - { 0xff3b153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, // ?? + { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */ + { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, /* ?? */ + { 0xff3b153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */ { 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, @@ -287,10 +286,12 @@ static struct CARD { { 0x01071805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" }, { 0x01081805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" }, - // likely broken, vendor id doesn't match the other magic views ... - //{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, + { 0x15409511, BTTV_ACORP_Y878F, "Acorp Y878F" }, - // DVB cards (using pci function .1 for mpeg data xfer) + /* likely broken, vendor id doesn't match the other magic views ... + * { 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ + + /* DVB cards (using pci function .1 for mpeg data xfer) */ { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, { 0x07611461, BTTV_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, { 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" }, @@ -298,7 +299,8 @@ static struct CARD { { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB" }, { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, { 0x07711461, BTTV_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, - { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DVICO FusionHDTV DVB-T Lite" }, + { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, + { 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, { 0, -1, NULL } }; @@ -316,6 +318,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .muxsel = { 2, 3, 1, 0}, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "MIRO PCTV", .video_inputs = 4, @@ -327,6 +330,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 2, 0, 0, 0, 10}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Hauppauge (bt848)", .video_inputs = 4, @@ -338,6 +342,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 2, 3, 4}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "STB, Gateway P/N 6000699 (bt848)", .video_inputs = 3, @@ -350,6 +355,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .needs_tvaudio = 1, .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ @@ -365,6 +371,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 0, .tuner_type = 4, + .tuner_addr = ADDR_UNSET, },{ .name = "Diamond DTV2000", .video_inputs = 4, @@ -376,6 +383,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 0, 1, 3}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "AVerMedia TVPhone", .video_inputs = 3, @@ -388,6 +396,7 @@ struct tvcard bttv_tvcards[] = { /* 0x04 for some cards ?? */ .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .audio_hook = avermedia_tvphone_audio, .has_remote = 1, },{ @@ -401,6 +410,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {0 }, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x08 ---------------------------------- */ @@ -415,6 +425,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "IMS/IXmicro TurboTV", .video_inputs = 3, @@ -427,6 +438,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, },{ .name = "Hauppauge (bt878)", .video_inputs = 4, @@ -439,6 +451,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "MIRO PCTV pro", .video_inputs = 3, @@ -450,6 +463,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x20001,0x10001, 0, 0,10}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x0c ---------------------------------- */ @@ -463,6 +477,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 13, 14, 11, 7, 0, 0}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "AVerMedia TVCapture 98", .video_inputs = 3, @@ -476,6 +491,7 @@ struct tvcard bttv_tvcards[] = { .msp34xx_alt = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .audio_hook = avermedia_tv_stereo_audio, },{ .name = "Aimslab Video Highway Xtreme (VHX)", @@ -489,6 +505,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Zoltrix TV-Max", .video_inputs = 3, @@ -500,6 +517,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {0 , 0, 1 , 0, 10}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x10 ---------------------------------- */ @@ -510,7 +528,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .gpiomask = 0x01fe00, .muxsel = { 2, 3, 1, 1}, - // 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> + /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */ .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 }, .needs_tvaudio = 1, .pll = PLL_28, @@ -526,6 +544,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .audio_hook = winview_audio, .has_radio = 1, },{ @@ -539,6 +558,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {1, 0, 0, 0, 0}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)", .video_inputs = 4, @@ -550,6 +570,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .no_msp34xx = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x14 ---------------------------------- */ @@ -560,10 +581,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .muxsel = {2, 3, 1, 1}, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50", .video_inputs = 4, - .audio_inputs = 2, // tuner, line in + .audio_inputs = 2, /* tuner, line in */ .tuner = 0, .svhs = 2, .gpiomask = 0x1800, @@ -571,6 +593,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800}, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, },{ .name = "Askey CPH050/ Phoebe Tv Master + FM", .video_inputs = 3, @@ -583,6 +606,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878", .video_inputs = 3, @@ -591,11 +615,12 @@ struct tvcard bttv_tvcards[] = { .svhs = -1, .gpiomask = 7, .muxsel = { 2, 3, -1 }, - .digital_mode = DIGITAL_MODE_CAMERA, + .digital_mode = DIGITAL_MODE_CAMERA, .audiomux = { 0, 0, 0, 0, 0 }, .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_ALPS_TSBB5_PAL_I, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x18 ---------------------------------- */ @@ -610,6 +635,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_remote = 1, },{ .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", @@ -622,6 +648,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000}, .needs_tvaudio = 0, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .audio_hook = terratv_audio, },{ .name = "Hauppauge WinCam newer (bt878)", @@ -634,6 +661,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 2, 3, 4}, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50", .video_inputs = 4, @@ -645,6 +673,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800}, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_SECAM, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x1c ---------------------------------- */ @@ -658,37 +687,38 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000}, .needs_tvaudio = 0, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .audio_hook = terratv_audio, /* GPIO wiring: - External 20 pin connector (for Active Radio Upgrade board) - gpio00: i2c-sda - gpio01: i2c-scl - gpio02: om5610-data - gpio03: om5610-clk - gpio04: om5610-wre - gpio05: om5610-stereo - gpio06: rds6588-davn - gpio07: Pin 7 n.c. - gpio08: nIOW - gpio09+10: nIOR, nSEL ?? (bt878) - gpio09: nIOR (bt848) - gpio10: nSEL (bt848) - Sound Routing: - gpio16: u2-A0 (1st 4052bt) - gpio17: u2-A1 - gpio18: u2-nEN - gpio19: u4-A0 (2nd 4052) - gpio20: u4-A1 - u4-nEN - GND - Btspy: - 00000 : Cdrom (internal audio input) + External 20 pin connector (for Active Radio Upgrade board) + gpio00: i2c-sda + gpio01: i2c-scl + gpio02: om5610-data + gpio03: om5610-clk + gpio04: om5610-wre + gpio05: om5610-stereo + gpio06: rds6588-davn + gpio07: Pin 7 n.c. + gpio08: nIOW + gpio09+10: nIOR, nSEL ?? (bt878) + gpio09: nIOR (bt848) + gpio10: nSEL (bt848) + Sound Routing: + gpio16: u2-A0 (1st 4052bt) + gpio17: u2-A1 + gpio18: u2-nEN + gpio19: u4-A0 (2nd 4052) + gpio20: u4-A1 + u4-nEN - GND + Btspy: + 00000 : Cdrom (internal audio input) 10000 : ext. Video audio input 20000 : TV Mono a0000 : TV Mono/2 - 1a0000 : TV Stereo + 1a0000 : TV Stereo 30000 : Radio 40000 : Mute - */ +*/ },{ /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */ @@ -702,6 +732,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .muxsel_hook = PXC200_muxsel, },{ @@ -710,11 +741,12 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 1, .tuner = 0, .svhs = 2, - .gpiomask = 0x1800, //0x8dfe00 + .gpiomask = 0x1800, /* 0x8dfe00 */ .muxsel = { 2, 3, 1, 1}, .audiomux = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 }, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Formac iProTV, Formac ProTV I (bt848)", .video_inputs = 4, @@ -726,6 +758,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 1, 0, 0, 0, 0 }, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x20 ---------------------------------- */ @@ -739,6 +772,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 0, .tuner_type = 4, + .tuner_addr = ADDR_UNSET, },{ .name = "Terratec TerraTValue Version Bt878", .video_inputs = 3, @@ -751,31 +785,33 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, },{ .name = "Leadtek WinFast 2000/ WinFast 2000 XP", .video_inputs = 4, .audio_inputs = 1, .tuner = 0, .svhs = 2, - .muxsel = { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector + .muxsel = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */ /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */ .gpiomask = 0xb33000, .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 }, /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) gpio23 -- hef4052:nEnable (0x800000) gpio12 -- hef4052:A1 - gpio13 -- hef4052:A0 - 0x0000: external audio - 0x1000: FM - 0x2000: TV - 0x3000: n.c. - Note: There exists another variant "Winfast 2000" with tv stereo !? - Note: eeprom only contains FF and pci subsystem id 107d:6606 - */ + gpio13 -- hef4052:A0 + 0x0000: external audio + 0x1000: FM + 0x2000: TV + 0x3000: n.c. + Note: There exists another variant "Winfast 2000" with tv stereo !? + Note: eeprom only contains FF and pci subsystem id 107d:6606 + */ .needs_tvaudio = 0, .pll = PLL_28, .has_radio = 1, - .tuner_type = 5, // default for now, gpio reads BFFF06 for Pal bg+dk + .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */ + .tuner_addr = ADDR_UNSET, .audio_hook = winfast2000_audio, .has_remote = 1, },{ @@ -789,6 +825,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800}, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x24 ---------------------------------- */ @@ -802,6 +839,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 }, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ .name = "Prolink PixelView PlayTV pro", @@ -815,6 +853,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Askey CPH06X TView99", .video_inputs = 4, @@ -827,6 +866,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = 1, + .tuner_addr = ADDR_UNSET, .has_remote = 1, },{ .name = "Pinnacle PCTV Studio/Rave", @@ -840,6 +880,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x28 ---------------------------------- */ @@ -854,6 +895,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .needs_tvaudio = 1, .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ @@ -868,6 +910,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_radio = 1, .audio_hook = avermedia_tvphone_audio, },{ @@ -883,6 +926,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = 1, + .tuner_addr = ADDR_UNSET, },{ .name = "Little OnAir TV", .video_inputs = 3, @@ -894,6 +938,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc}, .no_msp34xx = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x2c ---------------------------------- */ @@ -908,6 +953,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_NONE, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "MATRIX-Vision MV-Delta 2", .video_inputs = 5, @@ -920,6 +966,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "Zoltrix Genie TV/FM", .video_inputs = 3, @@ -932,6 +979,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = 21, + .tuner_addr = ADDR_UNSET, },{ .name = "Terratec TV/Radio+", .video_inputs = 3, @@ -945,6 +993,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_35, .tuner_type = 1, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ @@ -960,6 +1009,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "IODATA GV-BCTV3/PCI", .video_inputs = 3, @@ -972,6 +1022,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_ALPS_TSHC6_NTSC, + .tuner_addr = ADDR_UNSET, .audio_hook = gvbctv3pci_audio, },{ .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", @@ -986,6 +1037,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, .has_remote = 1, /* GPIO wiring: (different from Rev.4C !) GPIO17: U4.A0 (first hef4052bt) @@ -994,8 +1046,8 @@ struct tvcard bttv_tvcards[] = { GPIO21: U4.nEN GPIO22: BT832 Reset Line GPIO23: A5,A0, U5,nEN - Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 - */ + Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 + */ },{ .name = "Eagle Wireless Capricorn2 (bt878A)", .video_inputs = 4, @@ -1007,6 +1059,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 1, 2, 3, 4}, .pll = PLL_28, .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x34 ---------------------------------- */ @@ -1020,20 +1073,21 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3, 1, 1}, .audiomux = { 1, 0xd0001, 0, 0, 10}, /* sound path (5 sources): - MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) + MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) 0= ext. Audio IN 1= from MUX2 2= Mono TV sound from Tuner 3= not connected - MUX2 (mask 0x30000): + MUX2 (mask 0x30000): 0,2,3= from MSP34xx 1= FM stereo Radio from Tuner */ .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Claas Langbehn <claas@bigfoot.com>, - Sven Grothklags <sven@upb.de> */ + Sven Grothklags <sven@upb.de> */ .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS", .video_inputs = 4, .audio_inputs = 3, @@ -1045,10 +1099,11 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ /* Tim Röstermundt <rosterm@uni-muenster.de> - in de.comp.os.unix.linux.hardware: + in de.comp.os.unix.linux.hardware: options bttv card=0 pll=1 radio=1 gpiomask=0x18e0 audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff options tuner type=5 */ @@ -1060,15 +1115,16 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x18e0, .muxsel = { 2, 3, 1, 1}, .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x18e0 }, - /* For cards with tda9820/tda9821: - 0x0000: Tuner normal stereo - 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) - 0x0880: Tuner A2 stereo */ + /* For cards with tda9820/tda9821: + 0x0000: Tuner normal stereo + 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) + 0x0880: Tuner A2 stereo */ .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Miguel Angel Alvarez <maacruz@navegalia.com> - old Easy TV BT848 version (model CPH031) */ + old Easy TV BT848 version (model CPH031) */ .name = "Askey CPH031/ BESTBUY Easy TV", .video_inputs = 4, .audio_inputs = 1, @@ -1080,6 +1136,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x38 ---------------------------------- */ @@ -1094,10 +1151,11 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 }, .pll = PLL_28, .tuner_type = 5, + .tuner_addr = ADDR_UNSET, },{ /* This is the ultimate cheapo capture card - * just a BT848A on a small PCB! - * Steve Hosgood <steve@equiinet.com> */ + * just a BT848A on a small PCB! + * Steve Hosgood <steve@equiinet.com> */ .name = "GrandTec 'Grand Video Capture' (Bt848)", .video_inputs = 2, .audio_inputs = 0, @@ -1110,19 +1168,21 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_35, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ - /* Daniel Herrington <daniel.herrington@home.com> */ - .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", - .video_inputs = 3, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .gpiomask = 0xe00, - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 }, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4036FY5_NTSC, + /* Daniel Herrington <daniel.herrington@home.com> */ + .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0xe00, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 }, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4036FY5_NTSC, + .tuner_addr = ADDR_UNSET, },{ /* Matti Mottus <mottus@physic.ut.ee> */ .name = "Askey CPH03x TV Capturer", @@ -1130,11 +1190,12 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 1, .tuner = 0, .svhs = 2, - .gpiomask = 0x03000F, + .gpiomask = 0x03000F, .muxsel = { 2, 3, 1, 0}, - .audiomux = { 2,0,0,0,1 }, + .audiomux = { 2,0,0,0,1 }, .pll = PLL_28, .tuner_type = 0, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x3c ---------------------------------- */ @@ -1149,7 +1210,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 2, 0, 0, 1, 8}, .pll = PLL_35, .tuner_type = TUNER_TEMIC_PAL, - + .tuner_addr = ADDR_UNSET, },{ /* Adrian Cox <adrian@humboldt.co.uk */ .name = "AG Electronics GMV1", @@ -1164,10 +1225,11 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Miguel Angel Alvarez <maacruz@navegalia.com> - new Easy TV BT878 version (model CPH061) - special thanks to Informatica Mieres for providing the card */ + new Easy TV BT878 version (model CPH061) + special thanks to Informatica Mieres for providing the card */ .name = "Askey CPH061/ BESTBUY Easy TV (bt878)", .video_inputs = 3, .audio_inputs = 2, @@ -1179,6 +1241,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, },{ /* Lukas Gebauer <geby@volny.cz> */ .name = "ATI TV-Wonder", @@ -1191,6 +1254,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0xbffe, 0, 0xbfff, 0, 0xbffe}, .pll = PLL_28, .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x40 ---------------------------------- */ @@ -1206,6 +1270,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, },{ /* DeeJay <deejay@westel900.net (2000S) */ .name = "Lifeview FlyVideo 2000S LR90", @@ -1216,7 +1281,7 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x18e0, .muxsel = { 2, 3, 0, 1}, /* Radio changed from 1e80 to 0x800 to make - FlyVideo2000S in .hu happy (gm)*/ + FlyVideo2000S in .hu happy (gm)*/ /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 }, .audio_hook = fv2000s_audio, @@ -1225,6 +1290,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = 5, + .tuner_addr = ADDR_UNSET, },{ .name = "Terratec TValueRadio", .video_inputs = 3, @@ -1237,6 +1303,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_radio = 1, },{ /* TANAKA Kei <peg00625@nifty.com> */ @@ -1251,25 +1318,27 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, + .tuner_addr = ADDR_UNSET, .audio_hook = gvbctv3pci_audio, },{ /* ---- card 0x44 ---------------------------------- */ - .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)", - // try "insmod msp3400 simple=0" if you have - // sound problems with this card. - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = -1, - .gpiomask = 0x4f8a00, - // 0x100000: 1=MSP enabled (0=disable again) - // 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) - .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff}, - // tvtuner, radio, external,internal, mute, stereo - /* tuner, Composit, SVid, Composit-on-Svid-adapter*/ - .muxsel = { 2, 3 ,0 ,1}, - .tuner_type = TUNER_MT2032, + .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)", + /* try "insmod msp3400 simple=0" if you have + * sound problems with this card. */ + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = -1, + .gpiomask = 0x4f8a00, + /* 0x100000: 1=MSP enabled (0=disable again) + * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ + .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff}, + /* tvtuner, radio, external,internal, mute, stereo + * tuner, Composit, SVid, Composit-on-Svid-adapter */ + .muxsel = { 2, 3 ,0 ,1}, + .tuner_type = TUNER_MT2032, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ @@ -1279,22 +1348,24 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .muxsel = { 2 }, .gpiomask = 0 },{ - /* Tomasz Pyra <hellfire@sedez.iq.pl> */ - .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", - .video_inputs = 3, - .audio_inputs = 4, - .tuner = 0, - .svhs = 2, - .gpiomask = 15, - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 0, 0, 11, 7, 13, 0}, // TV and Radio with same GPIO ! - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = 25, + /* Tomasz Pyra <hellfire@sedez.iq.pl> */ + .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", + .video_inputs = 3, + .audio_inputs = 4, + .tuner = 0, + .svhs = 2, + .gpiomask = 15, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */ + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = 25, + .tuner_addr = ADDR_UNSET, .has_remote = 1, /* GPIO wiring: GPIO0: U4.A0 (hef4052bt) @@ -1302,16 +1373,18 @@ struct tvcard bttv_tvcards[] = { GPIO2: U4.A1 (second hef4052bt) GPIO3: U4.nEN, U5.A0, A5.nEN GPIO8-15: vrd866b ? - */ + */ },{ .name = "Lifeview FlyVideo 98EZ (capture only) LR51", .video_inputs = 4, .audio_inputs = 0, .tuner = -1, .svhs = 2, - .muxsel = { 2, 3, 1, 1}, // AV1, AV2, SVHS, CVid adapter on SVHS + .muxsel = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */ .pll = PLL_28, .no_msp34xx = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x48 ---------------------------------- */ @@ -1329,8 +1402,9 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .pll = PLL_28, .tuner_type = 5, - .audio_hook = pvbt878p9b_audio, // Note: not all cards have stereo - .has_radio = 1, // Note: not all cards have radio + .tuner_addr = ADDR_UNSET, + .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */ + .has_radio = 1, /* Note: not all cards have radio */ .has_remote = 1, /* GPIO wiring: GPIO0: A0 hef4052 @@ -1338,7 +1412,7 @@ struct tvcard bttv_tvcards[] = { GPIO3: nEN hef4052 GPIO8-15: vrd866b GPIO20,22,23: R30,R29,R28 - */ + */ },{ /* Clay Kunz <ckunz@mail.arc.nasa.gov> */ /* you must jumper JP5 for the card to work */ @@ -1352,6 +1426,7 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 0 }, .needs_tvaudio = 0, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Miguel Freitas <miguel@cetuc.puc-rio.br> */ .name = "RemoteVision MX (RV605)", @@ -1362,71 +1437,78 @@ struct tvcard bttv_tvcards[] = { .gpiomask = 0x00, .gpiomask2 = 0x07ff, .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03, - 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 }, + 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 }, .no_msp34xx = 1, .no_tda9875 = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .muxsel_hook = rv605_muxsel, },{ - .name = "Powercolor MTV878/ MTV878R/ MTV878F", - .video_inputs = 3, - .audio_inputs = 2, + .name = "Powercolor MTV878/ MTV878R/ MTV878F", + .video_inputs = 3, + .audio_inputs = 2, .tuner = 0, - .svhs = 2, - .gpiomask = 0x1C800F, // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset - .muxsel = { 2, 1, 1, }, - .audiomux = { 0, 1, 2, 2, 4 }, - .needs_tvaudio = 0, - .tuner_type = TUNER_PHILIPS_PAL, + .svhs = 2, + .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */ + .muxsel = { 2, 1, 1, }, + .audiomux = { 0, 1, 2, 2, 4 }, + .needs_tvaudio = 0, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, .has_radio = 1, },{ /* ---- card 0x4c ---------------------------------- */ - /* Masaki Suzuki <masaki@btree.org> */ - .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", - .video_inputs = 3, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .gpiomask = 0x140007, - .muxsel = { 2, 3, 1, 1 }, - .audiomux = { 0, 1, 2, 3, 4, 0 }, - .tuner_type = TUNER_PHILIPS_NTSC, - .audio_hook = windvr_audio, -},{ - .name = "GrandTec Multi Capture Card (Bt878)", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .gpiomask = 0, - .muxsel = { 2, 3, 1, 0 }, - .audiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = -1, -},{ - .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", - .video_inputs = 4, - .audio_inputs = 3, - .tuner = 0, - .svhs = 2, - .gpiomask = 7, - .muxsel = { 2, 3, 1, 1 }, // Tuner, SVid, SVHS, SVid to SVHS connector - .audiomux = { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio! - // This card lacks external Audio In, so we mute it on Ext. & Int. - // The PCB can take a sbx1637/sbx1673, wiring unknown. - // This card lacks PCI subsystem ID, sigh. - // audiomux=1: lower volume, 2+3: mute - // btwincap uses 0x80000/0x80003 - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = 5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and - // radio signal strength indicators work fine. - .has_radio = 1, + /* Masaki Suzuki <masaki@btree.org> */ + .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x140007, + .muxsel = { 2, 3, 1, 1 }, + .audiomux = { 0, 1, 2, 3, 4, 0 }, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_hook = windvr_audio, +},{ + .name = "GrandTec Multi Capture Card (Bt878)", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0, + .muxsel = { 2, 3, 1, 0 }, + .audiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, +},{ + .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", + .video_inputs = 4, + .audio_inputs = 3, + .tuner = 0, + .svhs = 2, + .gpiomask = 7, + .muxsel = { 2, 3, 1, 1 }, /* Tuner, SVid, SVHS, SVid to SVHS connector */ + .audiomux = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio! + * This card lacks external Audio In, so we mute it on Ext. & Int. + * The PCB can take a sbx1637/sbx1673, wiring unknown. + * This card lacks PCI subsystem ID, sigh. + * audiomux=1: lower volume, 2+3: mute + * btwincap uses 0x80000/0x80003 + */ + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = 5, + .tuner_addr = ADDR_UNSET, + /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and + radio signal strength indicators work fine. */ + .has_radio = 1, /* GPIO Info: GPIO0,1: HEF4052 A0,A1 GPIO2: HEF4052 nENABLE @@ -1437,25 +1519,27 @@ struct tvcard bttv_tvcards[] = { GPIO22,23: ?? ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/ },{ - /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */ - .name = "DSP Design TCVIDEO", - .video_inputs = 4, - .svhs = -1, - .muxsel = { 2, 3, 1, 0}, - .pll = PLL_28, - .tuner_type = -1, + /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */ + .name = "DSP Design TCVIDEO", + .video_inputs = 4, + .svhs = -1, + .muxsel = { 2, 3, 1, 0}, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ - /* ---- card 0x50 ---------------------------------- */ + /* ---- card 0x50 ---------------------------------- */ .name = "Hauppauge WinTV PVR", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 0, 1, 1}, - .needs_tvaudio = 1, - .pll = PLL_28, - .tuner_type = -1, + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 0, 1, 1}, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .gpiomask = 7, .audiomux = {7}, @@ -1471,6 +1555,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, .audio_hook = gvbctv5pci_audio, .has_radio = 1, },{ @@ -1482,9 +1567,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 3, 2, 0, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ .video_inputs = 3, @@ -1494,9 +1580,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ /* ---- card 0x54 ---------------------------------- */ @@ -1508,9 +1595,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 3, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ .video_inputs = 1, @@ -1520,9 +1608,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 0 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ .video_inputs = 2, @@ -1532,9 +1621,10 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 0, 1 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ .video_inputs = 1, @@ -1543,10 +1633,11 @@ struct tvcard bttv_tvcards[] = { .svhs = -1, .muxsel = { 0 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ /* ---- card 0x58 ---------------------------------- */ @@ -1557,10 +1648,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .muxsel = { 0, 1 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */ .video_inputs = 2, @@ -1569,10 +1661,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .muxsel = { 2, 3 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ .name = "Osprey 500", /* 500 */ .video_inputs = 2, @@ -1582,19 +1675,21 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3 }, .pll = PLL_28, .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ - .name = "Osprey 540", /* 540 */ - .video_inputs = 4, - .audio_inputs = 1, - .tuner = -1, - .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, + .name = "Osprey 540", /* 540 */ + .video_inputs = 4, + .audio_inputs = 1, + .tuner = -1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, },{ /* ---- card 0x5C ---------------------------------- */ @@ -1605,10 +1700,11 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .muxsel = { 2, 3 }, .pll = PLL_28, - .tuner_type = -1, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ },{ /* M G Berberich <berberic@forwiss.uni-passau.de> */ .name = "IDS Eagle", @@ -1616,6 +1712,7 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, .gpiomask = 0, .muxsel = { 0, 1, 2, 3 }, @@ -1630,6 +1727,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 1, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, @@ -1641,38 +1739,40 @@ struct tvcard bttv_tvcards[] = { .no_gpioirq = 1, .has_dvb = 1, },{ - .name = "Formac ProTV II (bt878)", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 3, - .gpiomask = 2, - // TV, Comp1, Composite over SVID con, SVID - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 2, 2, 0, 0, 0 }, - .pll = PLL_28, + .name = "Formac ProTV II (bt878)", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 3, + .gpiomask = 2, + /* TV, Comp1, Composite over SVID con, SVID */ + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 2, 2, 0, 0, 0 }, + .pll = PLL_28, .has_radio = 1, - .tuner_type = TUNER_PHILIPS_PAL, - /* sound routing: - GPIO=0x00,0x01,0x03: mute (?) - 0x02: both TV and radio (tuner: FM1216/I) - The card has onboard audio connectors labeled "cdrom" and "board", - not soldered here, though unknown wiring. - Card lacks: external audio in, pci subsystem id. - */ + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, +/* sound routing: + GPIO=0x00,0x01,0x03: mute (?) + 0x02: both TV and radio (tuner: FM1216/I) + The card has onboard audio connectors labeled "cdrom" and "board", + not soldered here, though unknown wiring. + Card lacks: external audio in, pci subsystem id. +*/ },{ /* ---- card 0x60 ---------------------------------- */ .name = "MachTV", - .video_inputs = 3, - .audio_inputs = 1, - .tuner = 0, - .svhs = -1, - .gpiomask = 7, - .muxsel = { 2, 3, 1, 1}, - .audiomux = { 0, 1, 2, 3, 4}, - .needs_tvaudio = 1, - .tuner_type = 5, + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = -1, + .gpiomask = 7, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0, 1, 2, 3, 4}, + .needs_tvaudio = 1, + .tuner_type = 5, + .tuner_addr = ADDR_UNSET, .pll = 1, },{ .name = "Euresys Picolo", @@ -1686,6 +1786,8 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .muxsel = { 2, 0, 1}, .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, },{ /* Luc Van Hoeylandt <luc@e-magic.be> */ .name = "ProVideo PV150", /* 0x4f */ @@ -1699,7 +1801,8 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .no_msp34xx = 1, .pll = PLL_28, - .tuner_type = -1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, },{ /* Hiroshi Takekawa <sian@big.or.jp> */ /* This card lacks subsystem ID */ @@ -1716,78 +1819,85 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = 2, + .tuner_addr = ADDR_UNSET, .audio_hook = adtvk503_audio, },{ /* ---- card 0x64 ---------------------------------- */ - .name = "Hercules Smart TV Stereo", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .gpiomask = 0x00, - .muxsel = { 2, 3, 1, 1 }, - .needs_tvaudio = 1, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = 5, + .name = "Hercules Smart TV Stereo", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x00, + .muxsel = { 2, 3, 1, 1 }, + .needs_tvaudio = 1, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = 5, + .tuner_addr = ADDR_UNSET, /* Notes: - - card lacks subsystem ID - - stereo variant w/ daughter board with tda9874a @0xb0 - - Audio Routing: + - card lacks subsystem ID + - stereo variant w/ daughter board with tda9874a @0xb0 + - Audio Routing: always from tda9874 independent of GPIO (?) external line in: unknown - - Other chips: em78p156elp @ 0x96 (probably IR remote control) - hef4053 (instead 4052) for unknown function + - Other chips: em78p156elp @ 0x96 (probably IR remote control) + hef4053 (instead 4052) for unknown function + */ +},{ + .name = "Pace TV & Radio Card", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */ + .gpiomask = 0, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = 1, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + .pll = PLL_28, + /* Bt878, Bt832, FI1246 tuner; no pci subsystem id + only internal line out: (4pin header) RGGL + Radio must be decoded by msp3410d (not routed through)*/ + /* + .digital_mode = DIGITAL_MODE_CAMERA, todo! */ },{ - .name = "Pace TV & Radio Card", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 3, 1, 1}, // Tuner, CVid, SVid, CVid over SVid connector - .gpiomask = 0, - .no_tda9875 = 1, - .no_tda7432 = 1, - .tuner_type = 1, - .has_radio = 1, - .pll = PLL_28, - /* Bt878, Bt832, FI1246 tuner; no pci subsystem id - only internal line out: (4pin header) RGGL - Radio must be decoded by msp3410d (not routed through)*/ - // .digital_mode = DIGITAL_MODE_CAMERA, // todo! -},{ - /* Chris Willing <chris@vislab.usyd.edu.au> */ - .name = "IVC-200", - .video_inputs = 1, - .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, - .svhs = -1, - .gpiomask = 0xdf, - .muxsel = { 2 }, - .pll = PLL_28, + /* Chris Willing <chris@vislab.usyd.edu.au> */ + .name = "IVC-200", + .video_inputs = 1, + .audio_inputs = 0, + .tuner = -1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .svhs = -1, + .gpiomask = 0xdf, + .muxsel = { 2 }, + .pll = PLL_28, },{ .name = "Grand X-Guard / Trust 814PCI", .video_inputs = 16, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, .tuner_type = 4, - .gpiomask2 = 0xff, + .tuner_addr = ADDR_UNSET, + .gpiomask2 = 0xff, .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 }, .muxsel_hook = xguard_muxsel, .no_msp34xx = 1, .no_tda9875 = 1, - .no_tda7432 = 1, + .no_tda7432 = 1, .pll = PLL_28, },{ /* ---- card 0x68 ---------------------------------- */ .name = "Nebula Electronics DigiTV", .video_inputs = 1, - .tuner = -1, + .tuner = -1, .svhs = -1, .muxsel = { 2, 3, 1, 0}, .no_msp34xx = 1, @@ -1795,22 +1905,24 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_dvb = 1, .no_gpioirq = 1, },{ /* Jorge Boncompte - DTI2 <jorge@dti2.net> */ .name = "ProVideo PV143", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .gpiomask = 0, - .muxsel = { 2, 3, 1, 0 }, - .audiomux = { 0 }, - .needs_tvaudio = 0, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = -1, + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0, + .muxsel = { 2, 3, 1, 0 }, + .audiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* M.Klahr@phytec.de */ .name = "PHYTEC VD-009-X1 MiniDIN (bt878)", @@ -1824,6 +1936,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "PHYTEC VD-009-X1 Combi (bt878)", .video_inputs = 4, @@ -1836,6 +1949,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* ---- card 0x6c ---------------------------------- */ @@ -1846,13 +1960,14 @@ struct tvcard bttv_tvcards[] = { .svhs = 9, .gpiomask = 0x00, .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio - via the upper nibble of muxsel. here: used for - xternal video-mux */ + via the upper nibble of muxsel. here: used for + xternal video-mux */ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 }, .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ .name = "PHYTEC VD-009 Combi (bt878)", .video_inputs = 10, @@ -1861,23 +1976,25 @@ struct tvcard bttv_tvcards[] = { .svhs = 9, .gpiomask = 0x00, .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio - via the upper nibble of muxsel. here: used for - xternal video-mux */ + via the upper nibble of muxsel. here: used for + xternal video-mux */ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 }, .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */ .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ - .name = "IVC-100", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .tuner_type = -1, - .svhs = -1, - .gpiomask = 0xdf, - .muxsel = { 2, 3, 1, 0 }, - .pll = PLL_28, + .name = "IVC-100", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .svhs = -1, + .gpiomask = 0xdf, + .muxsel = { 2, 3, 1, 0 }, + .pll = PLL_28, },{ /* IVC-120G - Alan Garfield <alan@fromorbit.com> */ .name = "IVC-120G", @@ -1885,6 +2002,7 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 0, /* card has no audio */ .tuner = -1, /* card has no tuner */ .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, /* card has no svhs */ .needs_tvaudio = 0, .no_msp34xx = 1, @@ -1892,7 +2010,7 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .gpiomask = 0x00, .muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, .muxsel_hook = ivc120_muxsel, .pll = PLL_28, },{ @@ -1905,6 +2023,7 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .muxsel = { 2, 3, 1, 0}, .tuner_type = TUNER_PHILIPS_ATSC, + .tuner_addr = ADDR_UNSET, .has_dvb = 1, },{ .name = "Twinhan DST + clones", @@ -1912,19 +2031,21 @@ struct tvcard bttv_tvcards[] = { .no_tda9875 = 1, .no_tda7432 = 1, .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, .no_video = 1, .has_dvb = 1, },{ - .name = "Winfast VC100", + .name = "Winfast VC100", .video_inputs = 3, .audio_inputs = 0, .svhs = 1, - .tuner = -1, // no tuner - .muxsel = { 3, 1, 1, 3}, // Vid In, SVid In, Vid over SVid in connector - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, + .tuner = -1, + .muxsel = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */ + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, .pll = PLL_28, },{ .name = "Teppro TEV-560/InterVision IV-560", @@ -1937,44 +2058,49 @@ struct tvcard bttv_tvcards[] = { .audiomux = { 1, 1, 1, 1, 0}, .needs_tvaudio = 1, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .pll = PLL_35, },{ /* ---- card 0x74 ---------------------------------- */ - .name = "SIMUS GVC1100", - .video_inputs = 4, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .tuner_type = -1, - .pll = PLL_28, - .muxsel = { 2, 2, 2, 2}, - .gpiomask = 0x3F, + .name = "SIMUS GVC1100", + .video_inputs = 4, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .muxsel = { 2, 2, 2, 2}, + .gpiomask = 0x3F, .muxsel_hook = gvc1100_muxsel, },{ - /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ - .name = "NGS NGSTV+", - .video_inputs = 3, - .tuner = 0, - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = {2, 3, 0, 0}, - .audiomux = {0, 0, 0, 0, 0x000003, 0}, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .has_remote = 1, -},{ - /* http://linuxmedialabs.com */ - .name = "LMLBT4", - .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .muxsel = { 2, 3, 1, 0 }, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .needs_tvaudio = 0, + /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ + .name = "NGS NGSTV+", + .video_inputs = 3, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = {2, 3, 0, 0}, + .audiomux = {0, 0, 0, 0, 0x000003, 0}, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, +},{ + /* http://linuxmedialabs.com */ + .name = "LMLBT4", + .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .muxsel = { 2, 3, 1, 0 }, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .needs_tvaudio = 0, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Helmroos Harri <harri.helmroos@pp.inet.fi> */ .name = "Tekram M205 PRO", @@ -1982,6 +2108,7 @@ struct tvcard bttv_tvcards[] = { .audio_inputs = 1, .tuner = 0, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .svhs = 2, .needs_tvaudio = 0, .gpiomask = 0x68, @@ -2004,6 +2131,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_remote = 1, .has_radio = 1, },{ @@ -2026,6 +2154,8 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .needs_tvaudio = 0, .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/ + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Spirit TV Tuner from http://spiritmodems.com.au */ /* Stafford Goodsell <surge@goliath.homeunix.org> */ @@ -2038,23 +2168,25 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 1, 1 }, .audiomux = { 0x02, 0x00, 0x00, 0x00, 0x00}, .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, .no_msp34xx = 1, .no_tda9875 = 1, },{ /* Wolfram Joost <wojo@frokaschwei.de> */ - .name = "AVerMedia AVerTV DVB-T 771", - .video_inputs = 2, - .svhs = 1, - .tuner = -1, - .tuner_type = TUNER_ABSENT, - .muxsel = { 3 , 3 }, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .has_dvb = 1, - .no_gpioirq = 1, - .has_remote = 1, + .name = "AVerMedia AVerTV DVB-T 771", + .video_inputs = 2, + .svhs = 1, + .tuner = -1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel = { 3 , 3 }, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, },{ /* ---- card 0x7c ---------------------------------- */ /* Matt Jesson <dvb@jesson.eclipse.co.uk> */ @@ -2069,6 +2201,7 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .has_dvb = 1, .no_gpioirq = 1, .has_remote = 1, @@ -2081,12 +2214,13 @@ struct tvcard bttv_tvcards[] = { .svhs = -1, .gpiomask = 0x0, .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3 }, + 3, 3, 3, 3, 3, 3, 3, 3 }, .muxsel_hook = sigmaSQ_muxsel, .audiomux = { 0 }, .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* andre.schwarz@matrix-vision.de */ .name = "MATRIX Vision Sigma-SLC", @@ -2101,6 +2235,7 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* BTTV_APAC_VIEWCOMP */ /* Attila Kondoros <attila.kondoros@chello.hu> */ @@ -2116,13 +2251,14 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ .has_radio = 1, /* not every card has radio */ },{ /* ---- card 0x80 ---------------------------------- */ /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */ - .name = "DVICO FusionHDTV DVB-T Lite", + .name = "DViCO FusionHDTV DVB-T Lite", .tuner = -1, .no_msp34xx = 1, .no_tda9875 = 1, @@ -2131,6 +2267,7 @@ struct tvcard bttv_tvcards[] = { .no_video = 1, .has_dvb = 1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, },{ /* Steven <photon38@pchome.com.tw> */ .name = "V-Gear MyVCD", @@ -2144,62 +2281,65 @@ struct tvcard bttv_tvcards[] = { .no_msp34xx = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, .has_radio = 0, - // .has_remote = 1, },{ /* Rick C <cryptdragoon@gmail.com> */ - .name = "Super TV Tuner", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 3, 1, 0}, - .tuner_type = TUNER_PHILIPS_NTSC, - .gpiomask = 0x008007, - .audiomux = { 0, 0x000001,0,0, 0}, - .needs_tvaudio = 1, - .has_radio = 1, -},{ - /* Chris Fanning <video4linux@haydon.net> */ - .name = "Tibet Systems 'Progress DVR' CS16", - .video_inputs = 16, - .audio_inputs = 0, - .tuner = -1, - .svhs = -1, - .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda9875 = 1, - .no_tda7432 = 1, - .tuner_type = -1, - .muxsel_hook = tibetCS16_muxsel, + .name = "Super TV Tuner", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 0}, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .gpiomask = 0x008007, + .audiomux = { 0, 0x000001,0,0, 0}, + .needs_tvaudio = 1, + .has_radio = 1, +},{ + /* Chris Fanning <video4linux@haydon.net> */ + .name = "Tibet Systems 'Progress DVR' CS16", + .video_inputs = 16, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = tibetCS16_muxsel, }, { /* Bill Brack <wbrack@mmm.com.hk> */ /* - * Note that, because of the card's wiring, the "master" - * BT878A chip (i.e. the one which controls the analog switch - * and must use this card type) is the 2nd one detected. The - * other 3 chips should use card type 0x85, whose description - * follows this one. There is a EEPROM on the card (which is - * connected to the I2C of one of those other chips), but is - * not currently handled. There is also a facility for a - * "monitor", which is also not currently implemented. - */ - .name = "Kodicom 4400R (master)", + * Note that, because of the card's wiring, the "master" + * BT878A chip (i.e. the one which controls the analog switch + * and must use this card type) is the 2nd one detected. The + * other 3 chips should use card type 0x85, whose description + * follows this one. There is a EEPROM on the card (which is + * connected to the I2C of one of those other chips), but is + * not currently handled. There is also a facility for a + * "monitor", which is also not currently implemented. + */ + .name = "Kodicom 4400R (master)", .video_inputs = 16, .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, /* GPIO bits 0-9 used for analog switch: - * 00 - 03: camera selector - * 04 - 06: channel (controller) selector - * 07: data (1->on, 0->off) - * 08: strobe - * 09: reset - * bit 16 is input from sync separator for the channel - */ + * 00 - 03: camera selector + * 04 - 06: channel (controller) selector + * 07: data (1->on, 0->off) + * 08: strobe + * 09: reset + * bit 16 is input from sync separator for the channel + */ .gpiomask = 0x0003ff, .no_gpioirq = 1, .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, @@ -2212,15 +2352,16 @@ struct tvcard bttv_tvcards[] = { { /* Bill Brack <wbrack@mmm.com.hk> */ /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the - * one which controls the analog switch, and must use the card type) - * is the 2nd one detected. The other 3 chips should use this card - * type - */ + * one which controls the analog switch, and must use the card type) + * is the 2nd one detected. The other 3 chips should use this card + * type + */ .name = "Kodicom 4400R (slave)", .video_inputs = 16, .audio_inputs = 0, .tuner = -1, .tuner_type = -1, + .tuner_addr = ADDR_UNSET, .svhs = -1, .gpiomask = 0x010000, .no_gpioirq = 1, @@ -2232,18 +2373,51 @@ struct tvcard bttv_tvcards[] = { .muxsel_hook = kodicom4400r_muxsel, }, { - /* ---- card 0x85---------------------------------- */ - /* Michael Henson <mhenson@clarityvi.com> */ - /* Adlink RTV24 with special unlock codes */ - .name = "Adlink RTV24", - .video_inputs = 4, - .audio_inputs = 1, - .tuner = 0, - .svhs = 2, - .muxsel = { 2, 3, 1, 0}, - .tuner_type = -1, - .pll = PLL_28, - + /* ---- card 0x86---------------------------------- */ + /* Michael Henson <mhenson@clarityvi.com> */ + /* Adlink RTV24 with special unlock codes */ + .name = "Adlink RTV24", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 0}, + .tuner_type = -1, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, +}, +{ + /* ---- card 0x87---------------------------------- */ + /* Michael Krufky <mkrufky@m1k.net> */ + .name = "DViCO FusionHDTV 5 Lite", + .tuner = 0, + .tuner_type = TUNER_LG_TDVS_H062F, + .tuner_addr = ADDR_UNSET, + .video_inputs = 2, + .audio_inputs = 1, + .svhs = 2, + .muxsel = { 2, 3 }, + .gpiomask = 0x00e00007, + .audiomux = { 0x00400005, 0, 0, 0, 0, 0 }, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, +},{ + /* ---- card 0x88---------------------------------- */ + /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */ + .name = "Acorp Y878F", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x01fe00, + .muxsel = { 2, 3, 1, 1}, + .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 }, + .needs_tvaudio = 1, + .pll = PLL_28, + .tuner_type = TUNER_YMEC_TVF66T5_B_DFF, + .tuner_addr = 0xc1 >>1, + .has_radio = 1, }}; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -2355,32 +2529,32 @@ static void flyvideo_gpio(struct bttv *btv) int tuner=-1,ttype; gpio_inout(0xffffff, 0); - udelay(8); // without this we would see the 0x1800 mask + udelay(8); /* without this we would see the 0x1800 mask */ gpio = gpio_read(); /* FIXME: must restore OUR_EN ??? */ - // all cards provide GPIO info, some have an additional eeprom - // LR50: GPIO coding can be found lower right CP1 .. CP9 - // CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. - // GPIO14-12: n.c. - // LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) - - // lowest 3 bytes are remote control codes (no handshake needed) - // xxxFFF: No remote control chip soldered - // xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered - // Note: Some bits are Audio_Mask ! + /* all cards provide GPIO info, some have an additional eeprom + * LR50: GPIO coding can be found lower right CP1 .. CP9 + * CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. + * GPIO14-12: n.c. + * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) + * lowest 3 bytes are remote control codes (no handshake needed) + * xxxFFF: No remote control chip soldered + * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered + * Note: Some bits are Audio_Mask ! + */ ttype=(gpio&0x0f0000)>>16; switch(ttype) { - case 0x0: tuner=2; // NTSC, e.g. TPI8NSR11P + case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */ break; - case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P + case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */ break; - case 0x4: tuner=5; // Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 + case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ break; - case 0x6: tuner=37; // LG PAL (newer TAPC series) TAPC-G702P + case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */ break; - case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF + case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ break; default: printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); @@ -2388,15 +2562,16 @@ static void flyvideo_gpio(struct bttv *btv) has_remote = gpio & 0x800000; has_radio = gpio & 0x400000; - // unknown 0x200000; - // unknown2 0x100000; - is_capture_only = !(gpio & 0x008000); //GPIO15 + /* unknown 0x200000; + * unknown2 0x100000; */ + is_capture_only = !(gpio & 0x008000); /* GPIO15 */ has_tda9820_tda9821 = !(gpio & 0x004000); - is_lr90 = !(gpio & 0x002000); // else LR26/LR50 (LR38/LR51 f. capture only) - // gpio & 0x001000 // output bit for audio routing + is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */ + /* + * gpio & 0x001000 output bit for audio routing */ if(is_capture_only) - tuner=4; // No tuner present + tuner=4; /* No tuner present */ printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); @@ -2404,15 +2579,15 @@ static void flyvideo_gpio(struct bttv *btv) btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", is_capture_only?"yes":"no "); - if(tuner!= -1) // only set if known tuner autodetected, else let insmod option through + if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */ btv->tuner_type = tuner; btv->has_radio = has_radio; - // LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 - // LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 - // Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute + /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 + * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 + * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio; - //todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; + /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */ } static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, @@ -2633,6 +2808,8 @@ void __devinit bttv_init_card1(struct bttv *btv) void __devinit bttv_init_card2(struct bttv *btv) { int tda9887; + int addr=ADDR_UNSET; + btv->tuner_type = -1; if (BTTV_UNKNOWN == btv->c.type) { @@ -2773,9 +2950,12 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->pll.pll_current = -1; /* tuner configuration (from card list / autodetect / insmod option) */ - if (UNSET != bttv_tvcards[btv->c.type].tuner_type) + if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) + addr = bttv_tvcards[btv->c.type].tuner_addr; + + if (UNSET != bttv_tvcards[btv->c.type].tuner_type) if(UNSET == btv->tuner_type) - btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; + btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; if (UNSET != tuner[btv->c.nr]) btv->tuner_type = tuner[btv->c.nr]; printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type); @@ -2787,7 +2967,7 @@ void __devinit bttv_init_card2(struct bttv *btv) tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; tun_setup.type = btv->tuner_type; - tun_setup.addr = ADDR_UNSET; + tun_setup.addr = addr; bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup); } @@ -2880,7 +3060,7 @@ static void __devinit hauppauge_eeprom(struct bttv *btv) { struct tveeprom tv; - tveeprom_hauppauge_analog(&tv, eeprom_data); + tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); btv->tuner_type = tv.tuner_type; btv->has_radio = tv.has_radio; } @@ -2902,7 +3082,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv) btv->mbox_csel = 1 << 10; freq=88000/62.5; - tea5757_write(btv, 5 * freq + 0x358); // write 0x1ed8 + tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ if (0x1ed8 == tea5757_read(btv)) { printk("bttv%d: Terratec Active Radio Upgrade found.\n", btv->c.nr); @@ -3073,7 +3253,7 @@ static void __devinit osprey_eeprom(struct bttv *btv) case 0x0060: case 0x0070: btv->c.type = BTTV_OSPREY2x0; - //enable output on select control lines + /* enable output on select control lines */ gpio_inout(0xffffff,0x000303); break; default: @@ -3105,7 +3285,7 @@ static int tuner_1_table[] = { TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, - TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, //TUNER_TEMIC_SECAM + TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */ TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL}; static void __devinit avermedia_eeprom(struct bttv *btv) @@ -3126,7 +3306,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) if (tuner_make == 4) if(tuner_format == 0x09) - tuner = TUNER_LG_NTSC_NEW_TAPC; // TAPC-G702P + tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]); @@ -3143,7 +3323,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) /* used on Voodoo TV/FM (Voodoo 200), S0 wired to 0x10000 */ void bttv_tda9880_setnorm(struct bttv *btv, int norm) { - // fix up our card entry + /* fix up our card entry */ if(norm==VIDEO_MODE_NTSC) { bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff; bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff; @@ -3154,7 +3334,7 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm) bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff; dprintk("bttv_tda9880_setnorm to PAL\n"); } - // set GPIO according + /* set GPIO according */ gpio_bits(bttv_tvcards[btv->c.type].gpiomask, bttv_tvcards[btv->c.type].audiomux[btv->audio]); } @@ -3447,7 +3627,7 @@ static int tea5757_read(struct bttv *btv) udelay(10); timeout= jiffies + HZ; - // wait for DATA line to go low; error if it doesn't + /* wait for DATA line to go low; error if it doesn't */ while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) schedule(); if (bus_in(btv,btv->mbox_data)) { @@ -3574,8 +3754,8 @@ gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set) con = 0x300; if (v->mode & VIDEO_SOUND_STEREO) con = 0x200; -// if (v->mode & VIDEO_SOUND_MONO) -// con = 0x100; +/* if (v->mode & VIDEO_SOUND_MONO) + * con = 0x100; */ gpio_bits(0x300, con); } else { v->mode = VIDEO_SOUND_STEREO | @@ -3718,7 +3898,7 @@ lt9415_audio(struct bttv *btv, struct video_audio *v, int set) } } -// TDA9821 on TerraTV+ Bt848, Bt878 +/* TDA9821 on TerraTV+ Bt848, Bt878 */ static void terratv_audio(struct bttv *btv, struct video_audio *v, int set) { @@ -3818,7 +3998,7 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) } if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x1080; //-dk-???: 0x0880, 0x0080, 0x1800 ... + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ } if (val != 0xffff) { gpio_bits(0x1800, val); @@ -3869,10 +4049,10 @@ adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int con = 0xffffff; - //btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ if (set) { - //btor(***, BT848_GPIO_OUT_EN); + /* btor(***, BT848_GPIO_OUT_EN); */ if (v->mode & VIDEO_SOUND_LANG1) con = 0x00000000; if (v->mode & VIDEO_SOUND_LANG2) @@ -4079,14 +4259,14 @@ static void kodicom4400r_init(struct bttv *btv) master[btv->c.nr+2] = btv; } -// The Grandtec X-Guard framegrabber card uses two Dual 4-channel -// video multiplexers to provide up to 16 video inputs. These -// multiplexers are controlled by the lower 8 GPIO pins of the -// bt878. The multiplexers probably Pericom PI5V331Q or similar. - -// xxx0 is pin xxx of multiplexer U5, -// yyy1 is pin yyy of multiplexer U2 +/* The Grandtec X-Guard framegrabber card uses two Dual 4-channel + * video multiplexers to provide up to 16 video inputs. These + * multiplexers are controlled by the lower 8 GPIO pins of the + * bt878. The multiplexers probably Pericom PI5V331Q or similar. + * xxx0 is pin xxx of multiplexer U5, + * yyy1 is pin yyy of multiplexer U2 + */ #define ENA0 0x01 #define ENB0 0x02 #define ENA1 0x04 @@ -4157,14 +4337,14 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) static void ivc120_muxsel(struct bttv *btv, unsigned int input) { - // Simple maths + /* Simple maths */ int key = input % 4; int matrix = input / 4; dprintk("bttv%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", btv->c.nr, input, matrix, key); - // Handles the input selection on the TDA8540's + /* Handles the input selection on the TDA8540's */ bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00, ((matrix == 3) ? (key | key << 2) : 0x00), 1); bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00, @@ -4174,17 +4354,17 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input) bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00, ((matrix == 2) ? (key | key << 2) : 0x00), 1); - // Handles the output enables on the TDA8540's + /* Handles the output enables on the TDA8540's */ bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02, - ((matrix == 3) ? 0x03 : 0x00), 1); // 13 - 16 + ((matrix == 3) ? 0x03 : 0x00), 1); /* 13 - 16 */ bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02, - ((matrix == 0) ? 0x03 : 0x00), 1); // 1-4 + ((matrix == 0) ? 0x03 : 0x00), 1); /* 1-4 */ bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02, - ((matrix == 1) ? 0x03 : 0x00), 1); // 5-8 + ((matrix == 1) ? 0x03 : 0x00), 1); /* 5-8 */ bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02, - ((matrix == 2) ? 0x03 : 0x00), 1); // 9-12 + ((matrix == 2) ? 0x03 : 0x00), 1); /* 9-12 */ - // Selects MUX0 for input on the 878 + /* Selects MUX0 for input on the 878 */ btaor((0)<<5, ~(3<<5), BT848_IFORM); } diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index eee9322ce21b..a564321db2f0 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1,5 +1,4 @@ /* - $Id: bttv-driver.c,v 1.52 2005/08/04 00:55:16 mchehab Exp $ bttv - Bt848 frame grabber driver @@ -42,6 +41,9 @@ #include "bttvp.h" +#include "rds.h" + + unsigned int bttv_num; /* number of Bt848s in use */ struct bttv bttvs[BTTV_MAX]; @@ -3128,15 +3130,12 @@ static int radio_open(struct inode *inode, struct file *file) dprintk("bttv%d: open called (radio)\n",btv->c.nr); down(&btv->lock); - if (btv->radio_user) { - up(&btv->lock); - return -EBUSY; - } + btv->radio_user++; + file->private_data = btv; - i2c_vidiocschan(btv); - bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); + bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); audio_mux(btv,AUDIO_RADIO); up(&btv->lock); @@ -3145,9 +3144,13 @@ static int radio_open(struct inode *inode, struct file *file) static int radio_release(struct inode *inode, struct file *file) { - struct bttv *btv = file->private_data; + struct bttv *btv = file->private_data; + struct rds_command cmd; btv->radio_user--; + + bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd); + return 0; } @@ -3203,13 +3206,42 @@ static int radio_ioctl(struct inode *inode, struct file *file, return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); } +static ssize_t radio_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct bttv *btv = file->private_data; + struct rds_command cmd; + cmd.block_count = count/3; + cmd.buffer = data; + cmd.instance = file; + cmd.result = -ENODEV; + + bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd); + + return cmd.result; +} + +static unsigned int radio_poll(struct file *file, poll_table *wait) +{ + struct bttv *btv = file->private_data; + struct rds_command cmd; + cmd.instance = file; + cmd.event_list = wait; + cmd.result = -ENODEV; + bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd); + + return cmd.result; +} + static struct file_operations radio_fops = { .owner = THIS_MODULE, .open = radio_open, + .read = radio_read, .release = radio_release, .ioctl = radio_ioctl, .llseek = no_llseek, + .poll = radio_poll, }; static struct video_device radio_template = @@ -4047,7 +4079,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) struct bttv_buffer_set idle; unsigned long flags; - dprintk("bttv%d: suspend %d\n", btv->c.nr, state); + dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event); /* stop dma + irqs */ spin_lock_irqsave(&btv->s_lock,flags); @@ -4080,15 +4112,29 @@ static int bttv_resume(struct pci_dev *pci_dev) { struct bttv *btv = pci_get_drvdata(pci_dev); unsigned long flags; + int err; dprintk("bttv%d: resume\n", btv->c.nr); /* restore pci state */ if (btv->state.disabled) { - pci_enable_device(pci_dev); + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->c.nr); + return err; + } btv->state.disabled = 0; } - pci_set_power_state(pci_dev, PCI_D0); + err=pci_set_power_state(pci_dev, PCI_D0); + if (err) { + pci_disable_device(pci_dev); + printk(KERN_WARNING "bttv%d: Can't enable device.\n", + btv->c.nr); + btv->state.disabled = 1; + return err; + } + pci_restore_state(pci_dev); /* restore bt878 state */ diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c index 77320cdf205f..6b280c03e398 100644 --- a/drivers/media/video/bttv-gpio.c +++ b/drivers/media/video/bttv-gpio.c @@ -1,5 +1,4 @@ /* - $Id: bttv-gpio.c,v 1.7 2005/02/16 12:14:10 kraxel Exp $ bttv-gpio.c -- gpio sub drivers diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index 234a85563769..e684df37eb0e 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -1,5 +1,4 @@ /* - $Id: bttv-i2c.c,v 1.25 2005/07/05 17:37:35 nsh Exp $ bttv-i2c.c -- all the i2c code is here @@ -109,7 +108,7 @@ static struct i2c_adapter bttv_i2c_adap_sw_template = { #ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, #endif - I2C_DEVNAME("bt848"), + .name = "bt848", .id = I2C_HW_B_BT848, .client_register = attach_inform, }; @@ -270,8 +269,6 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int } static struct i2c_algorithm bttv_algo = { - .name = "bt878", - .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, .master_xfer = bttv_i2c_xfer, .algo_control = algo_control, .functionality = functionality, @@ -282,8 +279,8 @@ static struct i2c_adapter bttv_i2c_adap_hw_template = { #ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, #endif - I2C_DEVNAME("bt878"), - .id = I2C_ALGO_BIT | I2C_HW_B_BT848 /* FIXME */, + .name = "bt878", + .id = I2C_HW_B_BT848 /* FIXME */, .algo = &bttv_algo, .client_register = attach_inform, }; @@ -298,7 +295,7 @@ static int attach_inform(struct i2c_client *client) if (bttv_debug) printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n", btv->c.nr,client->driver->name,client->addr, - i2c_clientname(client)); + client->name); if (!client->driver->command) return 0; @@ -326,7 +323,7 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) } static struct i2c_client bttv_i2c_client_template = { - I2C_DEVNAME("bttv internal"), + .name = "bttv internal", }; @@ -383,6 +380,7 @@ void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) } static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt330x", [ 0x30 >> 1 ] = "IR (hauppauge)", [ 0x80 >> 1 ] = "msp34xx", [ 0x86 >> 1 ] = "tda9887", diff --git a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c index f7b5543a96a1..e8aada772b89 100644 --- a/drivers/media/video/bttv-if.c +++ b/drivers/media/video/bttv-if.c @@ -1,5 +1,4 @@ /* - $Id: bttv-if.c,v 1.4 2004/11/17 18:47:47 kraxel Exp $ bttv-if.c -- old gpio interface to other kernel modules don't use in new code, will go away in 2.7 diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c index 9ed21fd190c6..a5ed99b89445 100644 --- a/drivers/media/video/bttv-risc.c +++ b/drivers/media/video/bttv-risc.c @@ -1,5 +1,4 @@ /* - $Id: bttv-risc.c,v 1.10 2004/11/19 18:07:12 kraxel Exp $ bttv-risc.c -- interfaces to other kernel modules diff --git a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c index 06f3e62b3e8d..f4f58c60f152 100644 --- a/drivers/media/video/bttv-vbi.c +++ b/drivers/media/video/bttv-vbi.c @@ -1,5 +1,4 @@ /* - $Id: bttv-vbi.c,v 1.9 2005/01/13 17:22:33 kraxel Exp $ bttv - Bt848 frame grabber driver vbi interface diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index f2af9e1454f0..d254e90e3bb9 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h @@ -1,5 +1,4 @@ /* - * $Id: bttv.h,v 1.22 2005/07/28 18:41:21 mchehab Exp $ * * bttv - Bt848 frame grabber driver * @@ -218,6 +217,8 @@ struct tvcard #define PLL_35 2 unsigned int tuner_type; + unsigned int tuner_addr; + unsigned int has_radio; void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); void (*muxsel_hook)(struct bttv *btv, unsigned int input); diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index aab094bc243d..9b0b7ca035f8 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -1,5 +1,4 @@ /* - $Id: bttvp.h,v 1.21 2005/07/15 21:44:14 mchehab Exp $ bttv - Bt848 frame grabber driver diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 4f39688f780a..0c0c59e94774 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-blackbird.c,v 1.27 2005/06/03 13:31:50 mchehab Exp $ * * Support for a cx23416 mpeg encoder via cx2388x host port. * "blackbird" reference design. @@ -62,7 +61,6 @@ static LIST_HEAD(cx8802_devlist); #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF /* Firmware API commands */ -/* #define IVTV_API_STD_TIMEOUT 0x00010000 // 65536, units?? */ #define IVTV_API_STD_TIMEOUT 500 #define BLACKBIRD_API_PING 0x80 @@ -696,7 +694,6 @@ static void blackbird_codec_settings(struct cx8802_dev *dev) /* assign stream type */ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM); - /* blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_TRANSPORT); */ /* assign output port */ blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */ @@ -824,7 +821,8 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0); /* initialize the video input */ + /* initialize the video input */ + blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0); msleep(1); @@ -833,11 +831,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE); msleep(1); - /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); // start capturing to the host interface */ + /* start capturing to the host interface */ + /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); */ blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE - ); /* start capturing to the host interface */ + ); msleep(10); blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0); @@ -851,8 +850,8 @@ static int bb_buf_setup(struct videobuf_queue *q, { struct cx8802_fh *fh = q->priv_data; - fh->dev->ts_packet_size = 512; - fh->dev->ts_packet_count = 100; + fh->dev->ts_packet_size = 188 * 4; /* was: 512 */ + fh->dev->ts_packet_count = 32; /* was: 100 */ *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count; if (0 == *count) @@ -900,12 +899,36 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, { struct cx8802_fh *fh = file->private_data; struct cx8802_dev *dev = fh->dev; + struct cx88_core *core = dev->core; if (debug > 1) - cx88_print_ioctl(dev->core->name,cmd); + cx88_print_ioctl(core->name,cmd); switch (cmd) { + /* --- capabilities ------------------------------------------ */ + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "cx88_blackbird"); + strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = CX88_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + 0; + if (UNSET != core->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; + } + /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: { @@ -935,7 +958,11 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = 1024 * 512 /* FIXME: BUFFER_SIZE */; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = 188 * 4 * 1024; /* 1024 * 512 */ /* FIXME: BUFFER_SIZE */; + f->fmt.pix.colorspace = 0; + return 0; } /* --- streaming capture ------------------------------------- */ @@ -959,15 +986,25 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, return videobuf_streamoff(&fh->mpegq); default: - return -EINVAL; + return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook ); } return 0; } +int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + +static unsigned int mpeg_translate_ioctl(unsigned int cmd) +{ + return cmd; +} + static int mpeg_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); + cmd = cx88_ioctl_translator( cmd ); + return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); } static int mpeg_open(struct inode *inode, struct file *file) @@ -1135,7 +1172,7 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, dev->pci = pci_dev; dev->core = core; dev->width = 720; - dev->height = 480; + dev->height = 576; err = cx8802_init_common(dev); if (0 != err) @@ -1148,6 +1185,9 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, list_add_tail(&dev->devlist,&cx8802_devlist); blackbird_register_video(dev); + + /* initial device configuration: needed ? */ + return 0; fail_free: @@ -1202,6 +1242,8 @@ static int blackbird_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif + cx88_ioctl_hook = mpeg_do_ioctl; + cx88_ioctl_translator = mpeg_translate_ioctl; return pci_register_driver(&blackbird_pci_driver); } @@ -1213,6 +1255,9 @@ static void blackbird_fini(void) module_init(blackbird_init); module_exit(blackbird_fini); +EXPORT_SYMBOL(cx88_ioctl_hook); +EXPORT_SYMBOL(cx88_ioctl_translator); + /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index ebf02a7f81e8..4da91d535a5b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-cards.c,v 1.90 2005/07/28 02:47:42 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * card-specific stuff. @@ -499,9 +498,6 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_DVB, .vmux = 0, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, }}, .dvb = 1, }, @@ -614,12 +610,12 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0xed12, // internal decoder + .gpio0 = 0xed12, /* internal decoder */ .gpio2 = 0x00ff, },{ .type = CX88_VMUX_DEBUG, .vmux = 0, - .gpio0 = 0xff01, // mono from tuner chip + .gpio0 = 0xff01, /* mono from tuner chip */ },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, @@ -715,19 +711,18 @@ struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* See DViCO FusionHDTV 3 Gold-Q for GPIO documentation. */ .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0x0f0d, + .gpio0 = 0x97ed, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0x0f00, + .gpio0 = 0x97e9, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio0 = 0x0f00, + .gpio0 = 0x97e9, }}, .dvb = 1, }, @@ -765,20 +760,21 @@ struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* See DViCO FusionHDTV 3 Gold-Q for GPIO documentation. */ + .tda9887_conf = TDA9887_PRESENT, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0x0f0d, + .gpio0 = 0x87fd, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0x0f00, + .gpio0 = 0x87f9, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio0 = 0x0f00, + .gpio0 = 0x87f9, }}, + .dvb = 1, }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -949,7 +945,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) { struct tveeprom tv; - tveeprom_hauppauge_analog(&tv, eeprom_data); + tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); core->tuner_type = tv.tuner_type; core->has_radio = tv.has_radio; } diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 5e868f5cd0c0..dc5c5c1f3461 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-core.c,v 1.33 2005/07/07 14:17:47 mchehab Exp $ * * device driver for Conexant 2388x based TV cards * driver core @@ -876,7 +875,7 @@ static int set_tvaudio(struct cx88_core *core) cx_andor(MO_AFECFG_IO, 0x1f, 0x0); cx88_set_tvaudio(core); - // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); + /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */ cx_write(MO_AUDD_LNGTH, 128); /* fifo size */ cx_write(MO_AUDR_LNGTH, 128); /* fifo size */ @@ -1087,10 +1086,17 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); core->pci_irqmask = 0x00fc00; + init_MUTEX(&core->lock); core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); if (0 != get_ressources(core,pci)) { + printk(KERN_ERR "CORE %s No more PCI ressources for " + "subsystem: %04x:%04x, board: %s\n", + core->name,pci->subsystem_vendor, + pci->subsystem_device, + cx88_boards[core->board].name); + cx88_devcount--; goto fail_free; } @@ -1114,11 +1120,11 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->board = CX88_BOARD_UNKNOWN; cx88_card_list(core,pci); } - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - core->name,pci->subsystem_vendor, - pci->subsystem_device,cx88_boards[core->board].name, - core->board, card[core->nr] == core->board ? - "insmod option" : "autodetected"); + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + core->name,pci->subsystem_vendor, + pci->subsystem_device,cx88_boards[core->board].name, + core->board, card[core->nr] == core->board ? + "insmod option" : "autodetected"); core->tuner_type = tuner[core->nr]; core->radio_type = radio[core->nr]; @@ -1202,4 +1208,5 @@ EXPORT_SYMBOL(cx88_core_put); * Local variables: * c-basic-offset: 8 * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 78d223257a68..c9106b1d79df 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-dvb.c,v 1.58 2005/08/07 09:24:08 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -29,7 +28,7 @@ #include <linux/kthread.h> #include <linux/file.h> #include <linux/suspend.h> -#include <linux/config.h> + #include "cx88.h" #include "dvb-pll.h" @@ -210,16 +209,26 @@ static struct or51132_config pchdtv_hd3000 = { static int lgdt330x_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { + /* FIXME make this routine use the tuner-simple code. + * It could probably be shared with a number of ATSC + * frontends. Many share the same tuner with analog TV. */ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; u8 buf[4]; struct i2c_msg msg = { .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 }; int err; - dvb_pll_configure(dev->core->pll_desc, buf, params->frequency, 0); + /* Put the analog decoder in standby to keep it quiet */ + if (core->tda9887_conf) { + cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); + } + + dvb_pll_configure(core->pll_desc, buf, params->frequency, 0); dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); - if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { + if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) { printk(KERN_WARNING "cx88-dvb: %s error " "(addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err); @@ -228,6 +237,13 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe, else return -EREMOTEIO; } + if (core->tuner_type == TUNER_LG_TDVS_H062F) { + /* Set the Auxiliary Byte. */ + buf[2] &= ~0x20; + buf[2] |= 0x18; + buf[3] = 0x50; + i2c_transfer(&core->i2c_adap, &msg, 1); + } return 0; } @@ -261,6 +277,14 @@ static struct lgdt330x_config fusionhdtv_3_gold = { .pll_set = lgdt330x_pll_set, .set_ts_params = lgdt330x_set_ts_param, }; + +static struct lgdt330x_config fusionhdtv_5_gold = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ + .pll_set = lgdt330x_pll_set, + .set_ts_params = lgdt330x_set_ts_param, +}; #endif static int dvb_register(struct cx8802_dev *dev) @@ -346,6 +370,22 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); } break; + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: + dev->ts_gen_cntrl = 0x08; + { + /* Do a hardware reset of chip before using it. */ + struct cx88_core *core = dev->core; + + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 1); + mdelay(200); + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_tdvs_tua6034; + dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold, + &dev->core->i2c_adap); + } + break; #endif default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", @@ -362,11 +402,6 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max; } - /* Copy the board name into the DVB structure */ - strlcpy(dev->dvb.frontend->ops->info.name, - cx88_boards[dev->core->board].name, - sizeof(dev->dvb.frontend->ops->info.name)); - /* register everything */ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); } diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index a628a55299c6..761cebd40dbd 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -1,5 +1,4 @@ /* - $Id: cx88-i2c.c,v 1.30 2005/07/25 05:10:13 mkrufky Exp $ cx88-i2c.c -- all the i2c code is here @@ -95,7 +94,7 @@ static int attach_inform(struct i2c_client *client) struct cx88_core *core = i2c_get_adapdata(client->adapter); dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->name,client->addr,i2c_clientname(client)); + client->driver->name, client->addr, client->name); if (!client->driver->command) return 0; @@ -128,7 +127,7 @@ static int detach_inform(struct i2c_client *client) { struct cx88_core *core = i2c_get_adapdata(client->adapter); - dprintk(1, "i2c detach [client=%s]\n", i2c_clientname(client)); + dprintk(1, "i2c detach [client=%s]\n", client->name); return 0; } @@ -152,7 +151,7 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = { /* ----------------------------------------------------------------------- */ static struct i2c_adapter cx8800_i2c_adap_template = { - I2C_DEVNAME("cx2388x"), + .name = "cx2388x", .owner = THIS_MODULE, .id = I2C_HW_B_CX2388x, .client_register = attach_inform, @@ -160,7 +159,7 @@ static struct i2c_adapter cx8800_i2c_adap_template = { }; static struct i2c_client cx8800_i2c_client_template = { - I2C_DEVNAME("cx88xx internal"), + .name = "cx88xx internal", }; static char *i2c_devs[128] = { diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 214887798192..d81b21d6e05d 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-input.c,v 1.15 2005/07/07 13:58:38 mchehab Exp $ * * Device driver for GPIO attached remote control interfaces * on Conexant 2388x based TV/DVB cards. @@ -212,6 +211,53 @@ static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { /* ---------------------------------------------------------------------- */ +/* Cinergy 1400 DVB-T */ +static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = { + [0x01] = KEY_POWER, + [0x02] = KEY_1, + [0x03] = KEY_2, + [0x04] = KEY_3, + [0x05] = KEY_4, + [0x06] = KEY_5, + [0x07] = KEY_6, + [0x08] = KEY_7, + [0x09] = KEY_8, + [0x0a] = KEY_9, + [0x0c] = KEY_0, + + [0x0b] = KEY_VIDEO, + [0x0d] = KEY_REFRESH, + [0x0e] = KEY_SELECT, + [0x0f] = KEY_EPG, + [0x10] = KEY_UP, + [0x11] = KEY_LEFT, + [0x12] = KEY_OK, + [0x13] = KEY_RIGHT, + [0x14] = KEY_DOWN, + [0x15] = KEY_TEXT, + [0x16] = KEY_INFO, + + [0x17] = KEY_RED, + [0x18] = KEY_GREEN, + [0x19] = KEY_YELLOW, + [0x1a] = KEY_BLUE, + + [0x1b] = KEY_CHANNELUP, + [0x1c] = KEY_VOLUMEUP, + [0x1d] = KEY_MUTE, + [0x1e] = KEY_VOLUMEDOWN, + [0x1f] = KEY_CHANNELDOWN, + + [0x40] = KEY_PAUSE, + [0x4c] = KEY_PLAY, + [0x58] = KEY_RECORD, + [0x54] = KEY_PREVIOUS, + [0x48] = KEY_STOP, + [0x5c] = KEY_NEXT, +}; + +/* ---------------------------------------------------------------------- */ + struct cx88_IR { struct cx88_core *core; struct input_dev input; @@ -241,7 +287,7 @@ module_param(ir_debug, int, 0644); /* debug level [IR] */ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define ir_dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s IR: " fmt , ir->core->name, ## arg) + printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg) /* ---------------------------------------------------------------------- */ @@ -329,6 +375,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keyup = 0x60; ir->polling = 50; /* ms */ break; + case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: + ir_codes = ir_codes_cinergy_1400; + ir_type = IR_TYPE_PD; + ir->sampling = 1; + break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: ir_codes = ir_codes_hauppauge_new; @@ -394,6 +445,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->input.id.vendor = pci->vendor; ir->input.id.product = pci->device; } + ir->input.dev = &pci->dev; /* record handles to ourself */ ir->core = core; @@ -445,7 +497,7 @@ int cx88_ir_fini(struct cx88_core *core) void cx88_ir_irq(struct cx88_core *core) { struct cx88_IR *ir = core->ir; - u32 samples, rc5; + u32 samples, ircode; int i; if (NULL == ir) @@ -477,13 +529,44 @@ void cx88_ir_irq(struct cx88_core *core) /* decode it */ switch (core->board) { + case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: + ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4); + + if (ircode == 0xffffffff) { /* decoding error */ + ir_dprintk("pulse distance decoding error\n"); + break; + } + + ir_dprintk("pulse distance decoded: %x\n", ircode); + + if (ircode == 0) { /* key still pressed */ + ir_dprintk("pulse distance decoded repeat code\n"); + ir->release = jiffies + msecs_to_jiffies(120); + break; + } + + if ((ircode & 0xffff) != 0xeb04) { /* wrong address */ + ir_dprintk("pulse distance decoded wrong address\n"); + break; + } + + if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */ + ir_dprintk("pulse distance decoded wrong check sum\n"); + break; + } + + ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f); + + ir_input_keydown(&ir->input, &ir->ir, (ircode >> 16) & 0x7f, (ircode >> 16) & 0xff); + ir->release = jiffies + msecs_to_jiffies(120); + break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: - rc5 = ir_decode_biphase(ir->samples, ir->scount, 5, 7); - ir_dprintk("biphase decoded: %x\n", rc5); - if ((rc5 & 0xfffff000) != 0x3000) + ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); + ir_dprintk("biphase decoded: %x\n", ircode); + if ((ircode & 0xfffff000) != 0x3000) break; - ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5); + ir_input_keydown(&ir->input, &ir->ir, ircode & 0x3f, ircode); ir->release = jiffies + msecs_to_jiffies(120); break; } diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index fe2767c0ff94..ee2300e1ae0b 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-mpeg.c,v 1.31 2005/07/07 14:17:47 mchehab Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -73,11 +72,15 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); cx_write(MO_PINMUX_IO, 0x00); cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); - if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) || - (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) { + switch (core->board) { + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: + case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: cx_write(TS_SOP_STAT, 1<<13); - } else { + break; + default: cx_write(TS_SOP_STAT, 0x00); + break; } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); @@ -86,12 +89,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev, if (cx88_boards[core->board].blackbird) { cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ - // cx_write(TS_F2_CMD_STAT_MM, 0x2900106); /* F2_CMD_STAT_MM defaults + master + memory space */ cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ udelay(100); cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */ - //cx_write(TS_HW_SOP_CNTRL, 0x2F0BC0); /* mpeg start byte ts: 0x2F0BC0 ? */ cx_write(TS_VALERR_CNTRL, 0x2000); cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ @@ -106,7 +107,6 @@ static int cx8802_start_dma(struct cx8802_dev *dev, dprintk( 0, "setting the interrupt mask\n" ); cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04); cx_set(MO_TS_INTMSK, 0x1f0011); - //cx_write(MO_TS_INTMSK, 0x0f0011); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); @@ -206,7 +206,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(0,"[%p/%d] %s - first active\n", buf, buf->vb.i, __FUNCTION__); - //udelay(100); } else { dprintk( 1, "queue is not empty - append to active\n" ); @@ -217,7 +216,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", buf, buf->vb.i, __FUNCTION__); - //udelay(100); } } @@ -387,7 +385,6 @@ int cx8802_init_common(struct cx8802_dev *dev) dev->pci_lat,pci_resource_start(dev->pci,0)); /* initialize driver struct */ - init_MUTEX(&dev->lock); spin_lock_init(&dev->slock); /* init dma queue */ @@ -458,14 +455,28 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) int cx8802_resume_common(struct pci_dev *pci_dev) { - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); + struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + int err; if (dev->state.disabled) { - pci_enable_device(pci_dev); + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + dev->core->name); + return err; + } dev->state.disabled = 0; } - pci_set_power_state(pci_dev, PCI_D0); + err=pci_set_power_state(pci_dev, PCI_D0); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + dev->core->name); + pci_disable_device(pci_dev); + dev->state.disabled = 1; + + return err; + } pci_restore_state(pci_dev); /* FIXME: re-initialize hardware */ diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index 37f82662d265..0a3a62fc9bbb 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -1,5 +1,4 @@ /* - $Id: cx88-reg.h,v 1.8 2005/07/07 13:58:38 mchehab Exp $ cx88x-hw.h - CX2388x register offsets @@ -40,6 +39,29 @@ #define CX88X_EN_TBFX 0x02 #define CX88X_EN_VSFX 0x04 +/* ---------------------------------------------------------------------- */ +/* PCI controller registers */ + +/* Command and Status Register */ +#define F0_CMD_STAT_MM 0x2f0004 +#define F1_CMD_STAT_MM 0x2f0104 +#define F2_CMD_STAT_MM 0x2f0204 +#define F3_CMD_STAT_MM 0x2f0304 +#define F4_CMD_STAT_MM 0x2f0404 + +/* Device Control #1 */ +#define F0_DEV_CNTRL1_MM 0x2f0040 +#define F1_DEV_CNTRL1_MM 0x2f0140 +#define F2_DEV_CNTRL1_MM 0x2f0240 +#define F3_DEV_CNTRL1_MM 0x2f0340 +#define F4_DEV_CNTRL1_MM 0x2f0440 + +/* Device Control #1 */ +#define F0_BAR0_MM 0x2f0010 +#define F1_BAR0_MM 0x2f0110 +#define F2_BAR0_MM 0x2f0210 +#define F3_BAR0_MM 0x2f0310 +#define F4_BAR0_MM 0x2f0410 /* ---------------------------------------------------------------------- */ /* DMA Controller registers */ diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 91207f10bae7..2765acee0285 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -1,5 +1,4 @@ /* - $Id: cx88-tvaudio.c,v 1.37 2005/07/07 13:58:38 mchehab Exp $ cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver @@ -121,25 +120,19 @@ static void set_audio_registers(struct cx88_core *core, } static void set_audio_start(struct cx88_core *core, - u32 mode, u32 ctl) + u32 mode) { // mute cx_write(AUD_VOL_CTL, (1 << 6)); - // increase level of input by 12dB -// cx_write(AUD_AFE_12DB_EN, 0x0001); - cx_write(AUD_AFE_12DB_EN, 0x0000); - // start programming cx_write(AUD_CTL, 0x0000); cx_write(AUD_INIT, mode); cx_write(AUD_INIT_LD, 0x0001); cx_write(AUD_SOFT_RESET, 0x0001); - - cx_write(AUD_CTL, ctl); } -static void set_audio_finish(struct cx88_core *core) +static void set_audio_finish(struct cx88_core *core, u32 ctl) { u32 volume; @@ -154,25 +147,25 @@ static void set_audio_finish(struct cx88_core *core) cx_write(AUD_I2SOUTPUTCNTL, 1); cx_write(AUD_I2SCNTL, 0); //cx_write(AUD_APB_IN_RATE_ADJ, 0); + } else { + ctl |= EN_DAC_ENABLE; + cx_write(AUD_CTL, ctl); } - // finish programming + /* finish programming */ cx_write(AUD_SOFT_RESET, 0x0000); - // start audio processing - cx_set(AUD_CTL, EN_DAC_ENABLE); - - // unmute + /* unmute */ volume = cx_sread(SHADOW_AUD_VOL_CTL); cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); } /* ----------------------------------------------------------- */ -static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) +static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, u32 mode) { static const struct rlist btsc[] = { - /* from dscaler */ + { AUD_AFE_12DB_EN, 0x00000001 }, { AUD_OUT1_SEL, 0x00000013 }, { AUD_OUT1_SHIFT, 0x00000000 }, { AUD_POLY0_DDS_CONSTANT, 0x0012010c }, @@ -206,9 +199,10 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) { AUD_RDSI_SHIFT, 0x00000000 }, { AUD_RDSQ_SHIFT, 0x00000000 }, { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { /* end of list */ }, + { /* end of list */ }, }; static const struct rlist btsc_sap[] = { + { AUD_AFE_12DB_EN, 0x00000001 }, { AUD_DBX_IN_GAIN, 0x00007200 }, { AUD_DBX_WBE_GAIN, 0x00006200 }, { AUD_DBX_SE_GAIN, 0x00006200 }, @@ -259,371 +253,400 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) { AUD_RDSI_SHIFT, 0x00000000 }, { AUD_RDSQ_SHIFT, 0x00000000 }, { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { /* end of list */ }, + { /* end of list */ }, }; - // dscaler: exactly taken from driver, - // dscaler: don't know why to set EN_FMRADIO_EN_RDS + mode |= EN_FMRADIO_EN_RDS; + if (sap) { dprintk("%s SAP (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0001, - EN_FMRADIO_EN_RDS | EN_BTSC_FORCE_SAP); + set_audio_start(core, SEL_SAP); set_audio_registers(core, btsc_sap); + set_audio_finish(core, mode); } else { dprintk("%s (status: known-good)\n",__FUNCTION__); - set_audio_start(core, 0x0001, - EN_FMRADIO_EN_RDS | EN_BTSC_AUTO_STEREO); + set_audio_start(core, SEL_BTSC); set_audio_registers(core, btsc); + set_audio_finish(core, mode); } - set_audio_finish(core); } static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo) { - /* This is probably weird.. - * Let's operate and find out. */ - - static const struct rlist nicam_l_mono[] = { - { AUD_ERRLOGPERIOD_R, 0x00000064 }, - { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, - { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, - - { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x3D }, - { AUD_QAM_MODE, 0x00 }, - { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x4a }, - - { AUD_DEEMPHGAIN_R, 0x6680 }, - { AUD_DEEMPHNUMER1_R, 0x353DE }, - { AUD_DEEMPHNUMER2_R, 0x1B1 }, - { AUD_DEEMPHDENOM1_R, 0x0F3D0 }, - { AUD_DEEMPHDENOM2_R, 0x0 }, - { AUD_FM_MODE_ENABLE, 0x7 }, - { AUD_POLYPH80SCALEFAC, 0x3 }, - { AUD_AFE_12DB_EN, 0x1 }, - { AAGC_GAIN, 0x0 }, - { AAGC_HYST, 0x18 }, - { AAGC_DEF, 0x20 }, - { AUD_DN0_FREQ, 0x0 }, - { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 }, - { AUD_DCOC_0_SRC, 0x21 }, - { AUD_IIR1_0_SEL, 0x0 }, - { AUD_IIR1_0_SHIFT, 0x7 }, - { AUD_IIR1_1_SEL, 0x2 }, - { AUD_IIR1_1_SHIFT, 0x0 }, - { AUD_DCOC_1_SRC, 0x3 }, - { AUD_DCOC1_SHIFT, 0x0 }, - { AUD_DCOC_PASS_IN, 0x0 }, - { AUD_IIR1_2_SEL, 0x23 }, - { AUD_IIR1_2_SHIFT, 0x0 }, - { AUD_IIR1_3_SEL, 0x4 }, - { AUD_IIR1_3_SHIFT, 0x7 }, - { AUD_IIR1_4_SEL, 0x5 }, - { AUD_IIR1_4_SHIFT, 0x7 }, - { AUD_IIR3_0_SEL, 0x7 }, - { AUD_IIR3_0_SHIFT, 0x0 }, - { AUD_DEEMPH0_SRC_SEL, 0x11 }, - { AUD_DEEMPH0_SHIFT, 0x0 }, - { AUD_DEEMPH0_G0, 0x7000 }, - { AUD_DEEMPH0_A0, 0x0 }, - { AUD_DEEMPH0_B0, 0x0 }, - { AUD_DEEMPH0_A1, 0x0 }, - { AUD_DEEMPH0_B1, 0x0 }, - { AUD_DEEMPH1_SRC_SEL, 0x11 }, - { AUD_DEEMPH1_SHIFT, 0x0 }, - { AUD_DEEMPH1_G0, 0x7000 }, - { AUD_DEEMPH1_A0, 0x0 }, - { AUD_DEEMPH1_B0, 0x0 }, - { AUD_DEEMPH1_A1, 0x0 }, - { AUD_DEEMPH1_B1, 0x0 }, - { AUD_OUT0_SEL, 0x3F }, - { AUD_OUT1_SEL, 0x3F }, - { AUD_DMD_RA_DDS, 0x0F5C285 }, - { AUD_PLL_INT, 0x1E }, - { AUD_PLL_DDS, 0x0 }, - { AUD_PLL_FRAC, 0x0E542 }, - - // setup QAM registers - { AUD_RATE_ADJ1, 0x00000100 }, - { AUD_RATE_ADJ2, 0x00000200 }, - { AUD_RATE_ADJ3, 0x00000300 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00000500 }, - { AUD_RATE_THRES_DMD, 0x000000C0 }, - { /* end of list */ }, - }; - - static const struct rlist nicam_l[] = { - // setup QAM registers - { AUD_RATE_ADJ1, 0x00000060 }, - { AUD_RATE_ADJ2, 0x000000F9 }, - { AUD_RATE_ADJ3, 0x000001CC }, - { AUD_RATE_ADJ4, 0x000002B3 }, - { AUD_RATE_ADJ5, 0x00000726 }, - { AUD_DEEMPHDENOM1_R, 0x0000F3D0 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_ERRLOGPERIOD_R, 0x00000064 }, - { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, - { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, - { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { AUD_DMD_RA_DDS, 0x00C00000 }, - { AUD_PLL_INT, 0x0000001E }, - { AUD_PLL_DDS, 0x00000000 }, - { AUD_PLL_FRAC, 0x0000E542 }, - { AUD_START_TIMER, 0x00000000 }, - { AUD_DEEMPHNUMER1_R, 0x000353DE }, - { AUD_DEEMPHNUMER2_R, 0x000001B1 }, - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_QAM_MODE, 0x05 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_PHACC_FREQ_8MSB, 0x34 }, - { AUD_PHACC_FREQ_8LSB, 0x4C }, - { AUD_DEEMPHGAIN_R, 0x00006680 }, - { AUD_RATE_THRES_DMD, 0x000000C0 }, - { /* end of list */ }, - } ; - dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); - - if (!stereo) { - /* AM mono sound */ - set_audio_start(core, 0x0004, - 0x100c /* FIXME again */); - set_audio_registers(core, nicam_l_mono); - } else { - set_audio_start(core, 0x0010, - 0x1924 /* FIXME again */); - set_audio_registers(core, nicam_l); - } - set_audio_finish(core); + /* This is probably weird.. + * Let's operate and find out. */ + + static const struct rlist nicam_l_mono[] = { + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, + + { AUD_PDF_DDS_CNST_BYTE2, 0x48 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x3D }, + { AUD_QAM_MODE, 0x00 }, + { AUD_PDF_DDS_CNST_BYTE0, 0xf5 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x4a }, + + { AUD_DEEMPHGAIN_R, 0x6680 }, + { AUD_DEEMPHNUMER1_R, 0x353DE }, + { AUD_DEEMPHNUMER2_R, 0x1B1 }, + { AUD_DEEMPHDENOM1_R, 0x0F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x0 }, + { AUD_FM_MODE_ENABLE, 0x7 }, + { AUD_POLYPH80SCALEFAC, 0x3 }, + { AUD_AFE_12DB_EN, 0x1 }, + { AAGC_GAIN, 0x0 }, + { AAGC_HYST, 0x18 }, + { AAGC_DEF, 0x20 }, + { AUD_DN0_FREQ, 0x0 }, + { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 }, + { AUD_DCOC_0_SRC, 0x21 }, + { AUD_IIR1_0_SEL, 0x0 }, + { AUD_IIR1_0_SHIFT, 0x7 }, + { AUD_IIR1_1_SEL, 0x2 }, + { AUD_IIR1_1_SHIFT, 0x0 }, + { AUD_DCOC_1_SRC, 0x3 }, + { AUD_DCOC1_SHIFT, 0x0 }, + { AUD_DCOC_PASS_IN, 0x0 }, + { AUD_IIR1_2_SEL, 0x23 }, + { AUD_IIR1_2_SHIFT, 0x0 }, + { AUD_IIR1_3_SEL, 0x4 }, + { AUD_IIR1_3_SHIFT, 0x7 }, + { AUD_IIR1_4_SEL, 0x5 }, + { AUD_IIR1_4_SHIFT, 0x7 }, + { AUD_IIR3_0_SEL, 0x7 }, + { AUD_IIR3_0_SHIFT, 0x0 }, + { AUD_DEEMPH0_SRC_SEL, 0x11 }, + { AUD_DEEMPH0_SHIFT, 0x0 }, + { AUD_DEEMPH0_G0, 0x7000 }, + { AUD_DEEMPH0_A0, 0x0 }, + { AUD_DEEMPH0_B0, 0x0 }, + { AUD_DEEMPH0_A1, 0x0 }, + { AUD_DEEMPH0_B1, 0x0 }, + { AUD_DEEMPH1_SRC_SEL, 0x11 }, + { AUD_DEEMPH1_SHIFT, 0x0 }, + { AUD_DEEMPH1_G0, 0x7000 }, + { AUD_DEEMPH1_A0, 0x0 }, + { AUD_DEEMPH1_B0, 0x0 }, + { AUD_DEEMPH1_A1, 0x0 }, + { AUD_DEEMPH1_B1, 0x0 }, + { AUD_OUT0_SEL, 0x3F }, + { AUD_OUT1_SEL, 0x3F }, + { AUD_DMD_RA_DDS, 0x0F5C285 }, + { AUD_PLL_INT, 0x1E }, + { AUD_PLL_DDS, 0x0 }, + { AUD_PLL_FRAC, 0x0E542 }, + + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000100 }, + { AUD_RATE_ADJ2, 0x00000200 }, + { AUD_RATE_ADJ3, 0x00000300 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00000500 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + }; + static const struct rlist nicam_l[] = { + // setup QAM registers + { AUD_RATE_ADJ1, 0x00000060 }, + { AUD_RATE_ADJ2, 0x000000F9 }, + { AUD_RATE_ADJ3, 0x000001CC }, + { AUD_RATE_ADJ4, 0x000002B3 }, + { AUD_RATE_ADJ5, 0x00000726 }, + { AUD_DEEMPHDENOM1_R, 0x0000F3D0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000064 }, + { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF }, + { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_DMD_RA_DDS, 0x00C00000 }, + { AUD_PLL_INT, 0x0000001E }, + { AUD_PLL_DDS, 0x00000000 }, + { AUD_PLL_FRAC, 0x0000E542 }, + { AUD_START_TIMER, 0x00000000 }, + { AUD_DEEMPHNUMER1_R, 0x000353DE }, + { AUD_DEEMPHNUMER2_R, 0x000001B1 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x34 }, + { AUD_PHACC_FREQ_8LSB, 0x4C }, + { AUD_DEEMPHGAIN_R, 0x00006680 }, + { AUD_RATE_THRES_DMD, 0x000000C0 }, + { /* end of list */ }, + } ; + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); + + if (!stereo) { + /* AM Mono */ + set_audio_start(core, SEL_A2); + set_audio_registers(core, nicam_l_mono); + set_audio_finish(core, EN_A2_FORCE_MONO1); + } else { + /* Nicam Stereo */ + set_audio_start(core, SEL_NICAM); + set_audio_registers(core, nicam_l); + set_audio_finish(core, 0x1924); /* FIXME */ + } } static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo) { static const struct rlist pal_i_fm_mono[] = { - {AUD_ERRLOGPERIOD_R, 0x00000064}, - {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, - {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, - {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, - {AUD_PDF_DDS_CNST_BYTE2, 0x06}, - {AUD_PDF_DDS_CNST_BYTE1, 0x82}, - {AUD_PDF_DDS_CNST_BYTE0, 0x12}, - {AUD_QAM_MODE, 0x05}, - {AUD_PHACC_FREQ_8MSB, 0x3a}, - {AUD_PHACC_FREQ_8LSB, 0x93}, - {AUD_DMD_RA_DDS, 0x002a4f2f}, - {AUD_PLL_INT, 0x0000001e}, - {AUD_PLL_DDS, 0x00000004}, - {AUD_PLL_FRAC, 0x0000e542}, - {AUD_RATE_ADJ1, 0x00000100}, - {AUD_RATE_ADJ2, 0x00000200}, - {AUD_RATE_ADJ3, 0x00000300}, - {AUD_RATE_ADJ4, 0x00000400}, - {AUD_RATE_ADJ5, 0x00000500}, - {AUD_THR_FR, 0x00000000}, - {AUD_PILOT_BQD_1_K0, 0x0000755b}, - {AUD_PILOT_BQD_1_K1, 0x00551340}, - {AUD_PILOT_BQD_1_K2, 0x006d30be}, - {AUD_PILOT_BQD_1_K3, 0xffd394af}, - {AUD_PILOT_BQD_1_K4, 0x00400000}, - {AUD_PILOT_BQD_2_K0, 0x00040000}, - {AUD_PILOT_BQD_2_K1, 0x002a4841}, - {AUD_PILOT_BQD_2_K2, 0x00400000}, - {AUD_PILOT_BQD_2_K3, 0x00000000}, - {AUD_PILOT_BQD_2_K4, 0x00000000}, - {AUD_MODE_CHG_TIMER, 0x00000060}, - {AUD_AFE_12DB_EN, 0x00000001}, - {AAGC_HYST, 0x0000000a}, - {AUD_CORDIC_SHIFT_0, 0x00000007}, - {AUD_CORDIC_SHIFT_1, 0x00000007}, - {AUD_C1_UP_THR, 0x00007000}, - {AUD_C1_LO_THR, 0x00005400}, - {AUD_C2_UP_THR, 0x00005400}, - {AUD_C2_LO_THR, 0x00003000}, - {AUD_DCOC_0_SRC, 0x0000001a}, - {AUD_DCOC0_SHIFT, 0x00000000}, - {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, - {AUD_DCOC_PASS_IN, 0x00000003}, - {AUD_IIR3_0_SEL, 0x00000021}, - {AUD_DN2_AFC, 0x00000002}, - {AUD_DCOC_1_SRC, 0x0000001b}, - {AUD_DCOC1_SHIFT, 0x00000000}, - {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, - {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, - {AUD_IIR3_1_SEL, 0x00000023}, - {AUD_DN0_FREQ, 0x000035a3}, - {AUD_DN2_FREQ, 0x000029c7}, - {AUD_CRDC0_SRC_SEL, 0x00000511}, - {AUD_IIR1_0_SEL, 0x00000001}, - {AUD_IIR1_1_SEL, 0x00000000}, - {AUD_IIR3_2_SEL, 0x00000003}, - {AUD_IIR3_2_SHIFT, 0x00000000}, - {AUD_IIR3_0_SEL, 0x00000002}, - {AUD_IIR2_0_SEL, 0x00000021}, - {AUD_IIR2_0_SHIFT, 0x00000002}, - {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, - {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, - {AUD_POLYPH80SCALEFAC, 0x00000001}, - {AUD_START_TIMER, 0x00000000}, - { /* end of list */ }, + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x3a}, + {AUD_PHACC_FREQ_8LSB, 0x93}, + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000004}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000060}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AAGC_HYST, 0x0000000a}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_DN0_FREQ, 0x000035a3}, + {AUD_DN2_FREQ, 0x000029c7}, + {AUD_CRDC0_SRC_SEL, 0x00000511}, + {AUD_IIR1_0_SEL, 0x00000001}, + {AUD_IIR1_1_SEL, 0x00000000}, + {AUD_IIR3_2_SEL, 0x00000003}, + {AUD_IIR3_2_SHIFT, 0x00000000}, + {AUD_IIR3_0_SEL, 0x00000002}, + {AUD_IIR2_0_SEL, 0x00000021}, + {AUD_IIR2_0_SHIFT, 0x00000002}, + {AUD_DEEMPH0_SRC_SEL, 0x0000000b}, + {AUD_DEEMPH1_SRC_SEL, 0x0000000b}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, }; static const struct rlist pal_i_nicam[] = { - { AUD_RATE_ADJ1, 0x00000010 }, - { AUD_RATE_ADJ2, 0x00000040 }, - { AUD_RATE_ADJ3, 0x00000100 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00001000 }, - // { AUD_DMD_RA_DDS, 0x00c0d5ce }, - { AUD_DEEMPHGAIN_R, 0x000023c2 }, - { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, - { AUD_DEEMPHNUMER2_R, 0x0003023e }, - { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_ERRLOGPERIOD_R, 0x00000fff }, - { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, - { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, - { AUD_POLYPH80SCALEFAC, 0x00000003 }, - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, - { AUD_QAM_MODE, 0x05 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x93 }, - { /* end of list */ }, - }; - - dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); - - if (!stereo) { - // FM mono - set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1); + { AUD_RATE_ADJ1, 0x00000010 }, + { AUD_RATE_ADJ2, 0x00000040 }, + { AUD_RATE_ADJ3, 0x00000100 }, + { AUD_RATE_ADJ4, 0x00000400 }, + { AUD_RATE_ADJ5, 0x00001000 }, + // { AUD_DMD_RA_DDS, 0x00c0d5ce }, + { AUD_DEEMPHGAIN_R, 0x000023c2 }, + { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, + { AUD_DEEMPHNUMER2_R, 0x0003023e }, + { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_DEEMPHDENOM2_R, 0x00000000 }, + { AUD_ERRLOGPERIOD_R, 0x00000fff }, + { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, + { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, + { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, + { AUD_POLYPH80SCALEFAC, 0x00000003 }, + { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, + { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, + { AUD_QAM_MODE, 0x05 }, + { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, + { AUD_PHACC_FREQ_8MSB, 0x3a }, + { AUD_PHACC_FREQ_8LSB, 0x93 }, + { /* end of list */ }, + }; + + dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo); + + if (!stereo) { + /* FM Mono */ + set_audio_start(core, SEL_A2); set_audio_registers(core, pal_i_fm_mono); - } else { - // Nicam Stereo - set_audio_start(core, 0x0010, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); + set_audio_finish(core, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1); + } else { + /* Nicam Stereo */ + set_audio_start(core, SEL_NICAM); set_audio_registers(core, pal_i_nicam); - } - set_audio_finish(core); + set_audio_finish(core, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); + } } -static void set_audio_standard_A2(struct cx88_core *core) +static void set_audio_standard_A2(struct cx88_core *core, u32 mode) { - /* from dscaler cvs */ static const struct rlist a2_common[] = { - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_QAM_MODE, 0x05 }, - { AUD_PHACC_FREQ_8MSB, 0x34 }, - { AUD_PHACC_FREQ_8LSB, 0x4c }, - - { AUD_RATE_ADJ1, 0x00001000 }, - { AUD_RATE_ADJ2, 0x00002000 }, - { AUD_RATE_ADJ3, 0x00003000 }, - { AUD_RATE_ADJ4, 0x00004000 }, - { AUD_RATE_ADJ5, 0x00005000 }, - { AUD_THR_FR, 0x00000000 }, - { AAGC_HYST, 0x0000001a }, - { AUD_PILOT_BQD_1_K0, 0x0000755b }, - { AUD_PILOT_BQD_1_K1, 0x00551340 }, - { AUD_PILOT_BQD_1_K2, 0x006d30be }, - { AUD_PILOT_BQD_1_K3, 0xffd394af }, - { AUD_PILOT_BQD_1_K4, 0x00400000 }, - { AUD_PILOT_BQD_2_K0, 0x00040000 }, - { AUD_PILOT_BQD_2_K1, 0x002a4841 }, - { AUD_PILOT_BQD_2_K2, 0x00400000 }, - { AUD_PILOT_BQD_2_K3, 0x00000000 }, - { AUD_PILOT_BQD_2_K4, 0x00000000 }, - { AUD_MODE_CHG_TIMER, 0x00000040 }, - { AUD_START_TIMER, 0x00000200 }, - { AUD_AFE_12DB_EN, 0x00000000 }, - { AUD_CORDIC_SHIFT_0, 0x00000007 }, - { AUD_CORDIC_SHIFT_1, 0x00000007 }, - { AUD_DEEMPH0_G0, 0x00000380 }, - { AUD_DEEMPH1_G0, 0x00000380 }, - { AUD_DCOC_0_SRC, 0x0000001a }, - { AUD_DCOC0_SHIFT, 0x00000000 }, - { AUD_DCOC_0_SHIFT_IN0, 0x0000000a }, - { AUD_DCOC_0_SHIFT_IN1, 0x00000008 }, - { AUD_DCOC_PASS_IN, 0x00000003 }, - { AUD_IIR3_0_SEL, 0x00000021 }, - { AUD_DN2_AFC, 0x00000002 }, - { AUD_DCOC_1_SRC, 0x0000001b }, - { AUD_DCOC1_SHIFT, 0x00000000 }, - { AUD_DCOC_1_SHIFT_IN0, 0x0000000a }, - { AUD_DCOC_1_SHIFT_IN1, 0x00000008 }, - { AUD_IIR3_1_SEL, 0x00000023 }, - { AUD_RDSI_SEL, 0x00000017 }, - { AUD_RDSI_SHIFT, 0x00000000 }, - { AUD_RDSQ_SEL, 0x00000017 }, - { AUD_RDSQ_SHIFT, 0x00000000 }, - { AUD_POLYPH80SCALEFAC, 0x00000001 }, + {AUD_ERRLOGPERIOD_R, 0x00000064}, + {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff}, + {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f}, + {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f}, + {AUD_PDF_DDS_CNST_BYTE2, 0x06}, + {AUD_PDF_DDS_CNST_BYTE1, 0x82}, + {AUD_PDF_DDS_CNST_BYTE0, 0x12}, + {AUD_QAM_MODE, 0x05}, + {AUD_PHACC_FREQ_8MSB, 0x34}, + {AUD_PHACC_FREQ_8LSB, 0x4c}, + {AUD_RATE_ADJ1, 0x00000100}, + {AUD_RATE_ADJ2, 0x00000200}, + {AUD_RATE_ADJ3, 0x00000300}, + {AUD_RATE_ADJ4, 0x00000400}, + {AUD_RATE_ADJ5, 0x00000500}, + {AUD_THR_FR, 0x00000000}, + {AAGC_HYST, 0x0000001a}, + {AUD_PILOT_BQD_1_K0, 0x0000755b}, + {AUD_PILOT_BQD_1_K1, 0x00551340}, + {AUD_PILOT_BQD_1_K2, 0x006d30be}, + {AUD_PILOT_BQD_1_K3, 0xffd394af}, + {AUD_PILOT_BQD_1_K4, 0x00400000}, + {AUD_PILOT_BQD_2_K0, 0x00040000}, + {AUD_PILOT_BQD_2_K1, 0x002a4841}, + {AUD_PILOT_BQD_2_K2, 0x00400000}, + {AUD_PILOT_BQD_2_K3, 0x00000000}, + {AUD_PILOT_BQD_2_K4, 0x00000000}, + {AUD_MODE_CHG_TIMER, 0x00000040}, + {AUD_AFE_12DB_EN, 0x00000001}, + {AUD_CORDIC_SHIFT_0, 0x00000007}, + {AUD_CORDIC_SHIFT_1, 0x00000007}, + {AUD_DEEMPH0_G0, 0x00000380}, + {AUD_DEEMPH1_G0, 0x00000380}, + {AUD_DCOC_0_SRC, 0x0000001a}, + {AUD_DCOC0_SHIFT, 0x00000000}, + {AUD_DCOC_0_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_0_SHIFT_IN1, 0x00000008}, + {AUD_DCOC_PASS_IN, 0x00000003}, + {AUD_IIR3_0_SEL, 0x00000021}, + {AUD_DN2_AFC, 0x00000002}, + {AUD_DCOC_1_SRC, 0x0000001b}, + {AUD_DCOC1_SHIFT, 0x00000000}, + {AUD_DCOC_1_SHIFT_IN0, 0x0000000a}, + {AUD_DCOC_1_SHIFT_IN1, 0x00000008}, + {AUD_IIR3_1_SEL, 0x00000023}, + {AUD_RDSI_SEL, 0x00000017}, + {AUD_RDSI_SHIFT, 0x00000000}, + {AUD_RDSQ_SEL, 0x00000017}, + {AUD_RDSQ_SHIFT, 0x00000000}, + {AUD_PLL_INT, 0x0000001e}, + {AUD_PLL_DDS, 0x00000000}, + {AUD_PLL_FRAC, 0x0000e542}, + {AUD_POLYPH80SCALEFAC, 0x00000001}, + {AUD_START_TIMER, 0x00000000}, + { /* end of list */ }, + }; + static const struct rlist a2_bg[] = { + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, { /* end of list */ }, }; - static const struct rlist a2_table1[] = { - // PAL-BG - { AUD_DMD_RA_DDS, 0x002a73bd }, - { AUD_C1_UP_THR, 0x00007000 }, - { AUD_C1_LO_THR, 0x00005400 }, - { AUD_C2_UP_THR, 0x00005400 }, - { AUD_C2_LO_THR, 0x00003000 }, + static const struct rlist a2_dk[] = { + {AUD_DMD_RA_DDS, 0x002a4f2f}, + {AUD_C1_UP_THR, 0x00007000}, + {AUD_C1_LO_THR, 0x00005400}, + {AUD_C2_UP_THR, 0x00005400}, + {AUD_C2_LO_THR, 0x00003000}, + {AUD_DN0_FREQ, 0x00003a1c}, + {AUD_DN2_FREQ, 0x0000d2e0}, { /* end of list */ }, }; - static const struct rlist a2_table2[] = { - // PAL-DK - { AUD_DMD_RA_DDS, 0x002a73bd }, - { AUD_C1_UP_THR, 0x00007000 }, - { AUD_C1_LO_THR, 0x00005400 }, - { AUD_C2_UP_THR, 0x00005400 }, - { AUD_C2_LO_THR, 0x00003000 }, - { AUD_DN0_FREQ, 0x00003a1c }, - { AUD_DN2_FREQ, 0x0000d2e0 }, +/* unknown, probably NTSC-M */ + static const struct rlist a2_m[] = { + {AUD_DMD_RA_DDS, 0x002a0425}, + {AUD_C1_UP_THR, 0x00003c00}, + {AUD_C1_LO_THR, 0x00003000}, + {AUD_C2_UP_THR, 0x00006000}, + {AUD_C2_LO_THR, 0x00003c00}, + {AUD_DEEMPH0_A0, 0x00007a80}, + {AUD_DEEMPH1_A0, 0x00007a80}, + {AUD_DEEMPH0_G0, 0x00001200}, + {AUD_DEEMPH1_G0, 0x00001200}, + {AUD_DN0_FREQ, 0x0000283b}, + {AUD_DN1_FREQ, 0x00003418}, + {AUD_DN2_FREQ, 0x000029c7}, + {AUD_POLY0_DDS_CONSTANT, 0x000a7540}, { /* end of list */ }, }; - static const struct rlist a2_table3[] = { - // unknown, probably NTSC-M - { AUD_DMD_RA_DDS, 0x002a2873 }, - { AUD_C1_UP_THR, 0x00003c00 }, - { AUD_C1_LO_THR, 0x00003000 }, - { AUD_C2_UP_THR, 0x00006000 }, - { AUD_C2_LO_THR, 0x00003c00 }, - { AUD_DN0_FREQ, 0x00002836 }, - { AUD_DN1_FREQ, 0x00003418 }, - { AUD_DN2_FREQ, 0x000029c7 }, - { AUD_POLY0_DDS_CONSTANT, 0x000a7540 }, + + static const struct rlist a2_deemph50[] = { + {AUD_DEEMPH0_G0, 0x00000380}, + {AUD_DEEMPH1_G0, 0x00000380}, + {AUD_DEEMPHGAIN_R, 0x000011e1}, + {AUD_DEEMPHNUMER1_R, 0x0002a7bc}, + {AUD_DEEMPHNUMER2_R, 0x0003023c}, + { /* end of list */ }, + }; + + static const struct rlist a2_deemph75[] = { + {AUD_DEEMPH0_G0, 0x00000480}, + {AUD_DEEMPH1_G0, 0x00000480}, + {AUD_DEEMPHGAIN_R, 0x00009000}, + {AUD_DEEMPHNUMER1_R, 0x000353de}, + {AUD_DEEMPHNUMER2_R, 0x000001b1}, { /* end of list */ }, }; - set_audio_start(core, 0x0004, EN_DMTRX_SUMDIFF | EN_A2_AUTO_STEREO); + set_audio_start(core, SEL_A2); set_audio_registers(core, a2_common); switch (core->tvaudio) { case WW_A2_BG: dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__); - set_audio_registers(core, a2_table1); + set_audio_registers(core, a2_bg); + set_audio_registers(core, a2_deemph50); break; case WW_A2_DK: dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__); - set_audio_registers(core, a2_table2); + set_audio_registers(core, a2_dk); + set_audio_registers(core, a2_deemph50); break; case WW_A2_M: dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, a2_table3); + set_audio_registers(core, a2_m); + set_audio_registers(core, a2_deemph75); break; }; - set_audio_finish(core); + + mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; + set_audio_finish(core, mode); } static void set_audio_standard_EIAJ(struct cx88_core *core) @@ -635,9 +658,9 @@ static void set_audio_standard_EIAJ(struct cx88_core *core) }; dprintk("%s (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0002, EN_EIAJ_AUTO_STEREO); + set_audio_start(core, SEL_EIAJ); set_audio_registers(core, eiaj); - set_audio_finish(core); + set_audio_finish(core, EN_EIAJ_AUTO_STEREO); } static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph) @@ -683,7 +706,7 @@ static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type }; dprintk("%s (status: unknown)\n",__FUNCTION__); - set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO); + set_audio_start(core, SEL_FMRADIO); switch (deemph) { @@ -700,7 +723,7 @@ static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type break; } - set_audio_finish(core); + set_audio_finish(core, EN_FMRADIO_AUTO_STEREO); } /* ----------------------------------------------------------- */ @@ -709,7 +732,7 @@ void cx88_set_tvaudio(struct cx88_core *core) { switch (core->tvaudio) { case WW_BTSC: - set_audio_standard_BTSC(core,0); + set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); break; case WW_NICAM_BGDKL: set_audio_standard_NICAM_L(core,0); @@ -720,7 +743,7 @@ void cx88_set_tvaudio(struct cx88_core *core) case WW_A2_BG: case WW_A2_DK: case WW_A2_M: - set_audio_standard_A2(core); + set_audio_standard_A2(core, EN_A2_FORCE_MONO1); break; case WW_EIAJ: set_audio_standard_EIAJ(core); @@ -734,7 +757,7 @@ void cx88_set_tvaudio(struct cx88_core *core) case WW_NONE: default: printk("%s/0: unknown tv audio mode [%d]\n", - core->name, core->tvaudio); + core->name, core->tvaudio); break; } return; @@ -769,6 +792,13 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) aud_ctl_names[cx_read(AUD_CTL) & 63]); core->astat = reg; +/* TODO + Reading from AUD_STATUS is not enough + for auto-detecting sap/dual-fm/nicam. + Add some code here later. +*/ + +# if 0 t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; t->rxsubchans = V4L2_TUNER_SUB_MONO; @@ -779,7 +809,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP; t->rxsubchans = V4L2_TUNER_SUB_STEREO; - if (1 == pilot) { + if (1 == pilot) { /* SAP */ t->rxsubchans |= V4L2_TUNER_SUB_SAP; } @@ -787,13 +817,13 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) case WW_A2_BG: case WW_A2_DK: case WW_A2_M: - if (1 == pilot) { + if (1 == pilot) { /* stereo */ t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (0 == mode) t->audmode = V4L2_TUNER_MODE_STEREO; } - if (2 == pilot) { + if (2 == pilot) { /* dual language -- FIXME */ t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; t->audmode = V4L2_TUNER_MODE_LANG1; @@ -805,16 +835,17 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) t->rxsubchans |= V4L2_TUNER_SUB_STEREO; } break; - case WW_SYSTEM_L_AM: - if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) { - t->audmode = V4L2_TUNER_MODE_STEREO; + case WW_SYSTEM_L_AM: + if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) { + t->audmode = V4L2_TUNER_MODE_STEREO; t->rxsubchans |= V4L2_TUNER_SUB_STEREO; } - break ; + break ; default: /* nothing */ break; } +# endif return; } @@ -835,16 +866,16 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) case WW_BTSC: switch (mode) { case V4L2_TUNER_MODE_MONO: - ctl = EN_BTSC_FORCE_MONO; - mask = 0x3f; + set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_MONO); break; - case V4L2_TUNER_MODE_SAP: - ctl = EN_BTSC_FORCE_SAP; - mask = 0x3f; + case V4L2_TUNER_MODE_LANG1: + set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO); + break; + case V4L2_TUNER_MODE_LANG2: + set_audio_standard_BTSC(core, 1, EN_BTSC_FORCE_SAP); break; case V4L2_TUNER_MODE_STEREO: - ctl = EN_BTSC_AUTO_STEREO; - mask = 0x3f; + set_audio_standard_BTSC(core, 0, EN_BTSC_FORCE_STEREO); break; } break; @@ -854,16 +885,13 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) switch (mode) { case V4L2_TUNER_MODE_MONO: case V4L2_TUNER_MODE_LANG1: - ctl = EN_A2_FORCE_MONO1; - mask = 0x3f; + set_audio_standard_A2(core, EN_A2_FORCE_MONO1); break; case V4L2_TUNER_MODE_LANG2: - ctl = EN_A2_AUTO_MONO2; - mask = 0x3f; + set_audio_standard_A2(core, EN_A2_FORCE_MONO2); break; case V4L2_TUNER_MODE_STEREO: - ctl = EN_A2_AUTO_STEREO | EN_DMTRX_SUMR; - mask = 0x8bf; + set_audio_standard_A2(core, EN_A2_FORCE_STEREO); break; } break; diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index 320d57888bbd..9bc6c8995581 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-vbi.c,v 1.17 2005/06/12 04:19:19 mchehab Exp $ */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 5f58c103198a..3dbc074fb515 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1,5 +1,4 @@ /* - * $Id: cx88-video.c,v 1.82 2005/07/22 05:13:34 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * video4linux video interface @@ -66,7 +65,7 @@ module_param(vid_limit,int,0644); MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); #define dprintk(level,fmt, arg...) if (video_debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->core->name , ## arg) + printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) /* ------------------------------------------------------------------ */ @@ -326,22 +325,23 @@ static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls); static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit) { + struct cx88_core *core = dev->core; if (fh->resources & bit) /* have it already allocated */ return 1; /* is it free? */ - down(&dev->lock); + down(&core->lock); if (dev->resources & bit) { /* no, someone else uses it */ - up(&dev->lock); + up(&core->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk(1,"res: get %d\n",bit); - up(&dev->lock); + up(&core->lock); return 1; } @@ -360,27 +360,29 @@ int res_locked(struct cx8800_dev *dev, unsigned int bit) static void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) { + struct cx88_core *core = dev->core; if ((fh->resources & bits) != bits) BUG(); - down(&dev->lock); + down(&core->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk(1,"res: put %d\n",bits); - up(&dev->lock); + up(&core->lock); } /* ------------------------------------------------------------------ */ -static int video_mux(struct cx8800_dev *dev, unsigned int input) +/* static int video_mux(struct cx8800_dev *dev, unsigned int input) */ +static int video_mux(struct cx88_core *core, unsigned int input) { - struct cx88_core *core = dev->core; + /* struct cx88_core *core = dev->core; */ dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", input, INPUT(input)->vmux, INPUT(input)->gpio0,INPUT(input)->gpio1, INPUT(input)->gpio2,INPUT(input)->gpio3); - dev->core->input = input; + core->input = input; cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14); cx_write(MO_GP3_IO, INPUT(input)->gpio3); cx_write(MO_GP0_IO, INPUT(input)->gpio0); @@ -413,9 +415,9 @@ static int start_video_dma(struct cx8800_dev *dev, struct cx88_core *core = dev->core; /* setup fifo + format */ - cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH21], + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], buf->bpl, buf->risc.dma); - cx88_set_scale(dev->core, buf->vb.width, buf->vb.height, buf->vb.field); + cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field); cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma); /* reset counter */ @@ -424,6 +426,14 @@ static int start_video_dma(struct cx8800_dev *dev, /* enable irqs */ cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01); + + /* Enables corresponding bits at PCI_INT_STAT: + bits 0 to 4: video, audio, transport stream, VIP, Host + bit 7: timer + bits 8 and 9: DMA complete for: SRC, DST + bits 10 and 11: BERR signal asserted for RISC: RD, WR + bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB + */ cx_set(MO_VID_INTMSK, 0x0f0011); /* enable capture */ @@ -431,7 +441,7 @@ static int start_video_dma(struct cx8800_dev *dev, /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); - cx_set(MO_VID_DMACNTRL, 0x11); + cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ return 0; } @@ -455,6 +465,7 @@ static int stop_video_dma(struct cx8800_dev *dev) static int restart_video_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) { + struct cx88_core *core = dev->core; struct cx88_buffer *buf, *prev; struct list_head *item; @@ -524,12 +535,13 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, { struct cx8800_fh *fh = q->priv_data; struct cx8800_dev *dev = fh->dev; + struct cx88_core *core = dev->core; struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb); int rc, init_buffer = 0; BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(dev->core->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(dev->core->tvnorm)) + if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || + fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) return -EINVAL; buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) @@ -609,6 +621,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) struct cx88_buffer *prev; struct cx8800_fh *fh = vq->priv_data; struct cx8800_dev *dev = fh->dev; + struct cx88_core *core = dev->core; struct cx88_dmaqueue *q = &dev->vidq; /* add jump to stopper */ @@ -701,6 +714,7 @@ static int video_open(struct inode *inode, struct file *file) { int minor = iminor(inode); struct cx8800_dev *h,*dev = NULL; + struct cx88_core *core; struct cx8800_fh *fh; struct list_head *list; enum v4l2_buf_type type = 0; @@ -725,6 +739,8 @@ static int video_open(struct inode *inode, struct file *file) if (NULL == dev) return -ENODEV; + core = dev->core; + dprintk(1,"open minor=%d radio=%d type=%s\n", minor,radio,v4l2_type_names[type]); @@ -755,17 +771,16 @@ static int video_open(struct inode *inode, struct file *file) fh); if (fh->radio) { - struct cx88_core *core = dev->core; int board = core->board; dprintk(1,"video_open: setting radio device\n"); cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3); cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0); cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1); cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2); - dev->core->tvaudio = WW_FM; + core->tvaudio = WW_FM; cx88_set_tvaudio(core); cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); - cx88_call_i2c_clients(dev->core,AUDC_SET_RADIO,NULL); + cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); } return 0; @@ -857,6 +872,9 @@ static int video_release(struct inode *inode, struct file *file) videobuf_mmap_free(&fh->vbiq); file->private_data = NULL; kfree(fh); + + cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); + return 0; } @@ -870,9 +888,10 @@ video_mmap(struct file *file, struct vm_area_struct * vma) /* ------------------------------------------------------------------ */ -static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) +/* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ +static int get_control(struct cx88_core *core, struct v4l2_control *ctl) { - struct cx88_core *core = dev->core; + /* struct cx88_core *core = dev->core; */ struct cx88_ctrl *c = NULL; u32 value; int i; @@ -898,9 +917,10 @@ static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) return 0; } -static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) +/* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ +static int set_control(struct cx88_core *core, struct v4l2_control *ctl) { - struct cx88_core *core = dev->core; + /* struct cx88_core *core = dev->core; */ struct cx88_ctrl *c = NULL; u32 v_sat_value; u32 value; @@ -913,9 +933,9 @@ static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) return -EINVAL; if (ctl->value < c->v.minimum) - return -ERANGE; + ctl->value = c->v.minimum; if (ctl->value > c->v.maximum) - return -ERANGE; + ctl->value = c->v.maximum; switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value; @@ -946,7 +966,8 @@ static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) return 0; } -static void init_controls(struct cx8800_dev *dev) +/* static void init_controls(struct cx8800_dev *dev) */ +static void init_controls(struct cx88_core *core) { static struct v4l2_control mute = { .id = V4L2_CID_AUDIO_MUTE, @@ -969,11 +990,11 @@ static void init_controls(struct cx8800_dev *dev) .value = 0x80, }; - set_control(dev,&mute); - set_control(dev,&volume); - set_control(dev,&hue); - set_control(dev,&contrast); - set_control(dev,&brightness); + set_control(core,&mute); + set_control(core,&volume); + set_control(core,&hue); + set_control(core,&contrast); + set_control(core,&brightness); } /* ------------------------------------------------------------------ */ @@ -1004,6 +1025,8 @@ static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, struct v4l2_format *f) { + struct cx88_core *core = dev->core; + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { @@ -1016,8 +1039,8 @@ static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, return -EINVAL; field = f->fmt.pix.field; - maxw = norm_maxw(dev->core->tvnorm); - maxh = norm_maxh(dev->core->tvnorm); + maxw = norm_maxw(core->tvnorm); + maxh = norm_maxh(core->tvnorm); if (V4L2_FIELD_ANY == field) { field = (f->fmt.pix.height > maxh/2) @@ -1101,12 +1124,14 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (video_debug > 1) cx88_print_ioctl(core->name,cmd); switch (cmd) { + + /* --- capabilities ------------------------------------------ */ case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "cx8800"); + strcpy(cap->driver, "cx8800"); strlcpy(cap->card, cx88_boards[core->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); @@ -1116,12 +1141,128 @@ static int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } + /* --- capture ioctls ---------------------------------------- */ + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type; + unsigned int index; + + index = f->index; + type = f->type; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= ARRAY_SIZE(formats)) + return -EINVAL; + memset(f,0,sizeof(*f)); + f->index = index; + f->type = type; + strlcpy(f->description,formats[index].name,sizeof(f->description)); + f->pixelformat = formats[index].fourcc; + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + return cx8800_g_fmt(dev,fh,f); + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + return cx8800_s_fmt(dev,fh,f); + } + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = arg; + return cx8800_try_fmt(dev,fh,f); + } + + /* --- streaming capture ------------------------------------- */ + case VIDIOCGMBUF: + { + struct video_mbuf *mbuf = arg; + struct videobuf_queue *q; + struct v4l2_requestbuffers req; + unsigned int i; + + q = get_queue(fh); + memset(&req,0,sizeof(req)); + req.type = q->type; + req.count = 8; + req.memory = V4L2_MEMORY_MMAP; + err = videobuf_reqbufs(q,&req); + if (err < 0) + return err; + memset(mbuf,0,sizeof(*mbuf)); + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + return 0; + } + case VIDIOC_REQBUFS: + return videobuf_reqbufs(get_queue(fh), arg); + + case VIDIOC_QUERYBUF: + return videobuf_querybuf(get_queue(fh), arg); + + case VIDIOC_QBUF: + return videobuf_qbuf(get_queue(fh), arg); + + case VIDIOC_DQBUF: + return videobuf_dqbuf(get_queue(fh), arg, + file->f_flags & O_NONBLOCK); + + case VIDIOC_STREAMON: + { + int res = get_ressource(fh); + + if (!res_get(dev,fh,res)) + return -EBUSY; + return videobuf_streamon(get_queue(fh)); + } + case VIDIOC_STREAMOFF: + { + int res = get_ressource(fh); + + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + res_free(dev,fh,res); + return 0; + } + + default: + return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl ); + } + return 0; +} + +int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, + struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl) +{ + int err; + + if (video_debug > 1) + cx88_print_ioctl(core->name,cmd); + printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd ); + cx88_print_ioctl(core->name,cmd); + dprintk( 1, "CORE IOCTL: 0x%x\n", cmd ); + + switch (cmd) { /* ---------- tv norms ---------- */ case VIDIOC_ENUMSTD: { @@ -1156,9 +1297,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (i == ARRAY_SIZE(tvnorms)) return -EINVAL; - down(&dev->lock); - cx88_set_tvnorm(dev->core,&tvnorms[i]); - up(&dev->lock); + down(&core->lock); + cx88_set_tvnorm(core,&tvnorms[i]); + up(&core->lock); return 0; } @@ -1199,7 +1340,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - *i = dev->core->input; + *i = core->input; return 0; } case VIDIOC_S_INPUT: @@ -1208,55 +1349,15 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (*i >= 4) return -EINVAL; - down(&dev->lock); + down(&core->lock); cx88_newstation(core); - video_mux(dev,*i); - up(&dev->lock); + video_mux(core,*i); + up(&core->lock); return 0; } - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int index; - - index = f->index; - type = f->type; - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (index >= ARRAY_SIZE(formats)) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - strlcpy(f->description,formats[index].name,sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - break; - default: - return -EINVAL; - } - return 0; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - return cx8800_g_fmt(dev,fh,f); - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - return cx8800_s_fmt(dev,fh,f); - } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - return cx8800_try_fmt(dev,fh,f); - } - /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: { @@ -1277,9 +1378,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, return 0; } case VIDIOC_G_CTRL: - return get_control(dev,arg); + return get_control(core,arg); case VIDIOC_S_CTRL: - return set_control(dev,arg); + return set_control(core,arg); /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: @@ -1323,10 +1424,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (UNSET == core->tuner_type) return -EINVAL; - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; + /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ + f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = core->freq; - cx88_call_i2c_clients(dev->core,VIDIOC_G_FREQUENCY,f); + cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); return 0; } @@ -1338,83 +1440,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (f->tuner != 0) return -EINVAL; - if (0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV) + if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV) return -EINVAL; - if (1 == fh->radio && f->type != V4L2_TUNER_RADIO) + if (1 == radio && f->type != V4L2_TUNER_RADIO) return -EINVAL; - down(&dev->lock); - dev->freq = f->frequency; + down(&core->lock); + core->freq = f->frequency; cx88_newstation(core); - cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f); + cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); /* When changing channels it is required to reset TVAUDIO */ msleep (10); cx88_set_tvaudio(core); - up(&dev->lock); - return 0; - } - - /* --- streaming capture ------------------------------------- */ - case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - - q = get_queue(fh); - memset(&req,0,sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q,&req); - if (err < 0) - return err; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; - } - case VIDIOC_REQBUFS: - return videobuf_reqbufs(get_queue(fh), arg); - - case VIDIOC_QUERYBUF: - return videobuf_querybuf(get_queue(fh), arg); - - case VIDIOC_QBUF: - return videobuf_qbuf(get_queue(fh), arg); - - case VIDIOC_DQBUF: - return videobuf_dqbuf(get_queue(fh), arg, - file->f_flags & O_NONBLOCK); - - case VIDIOC_STREAMON: - { - int res = get_ressource(fh); - - if (!res_get(dev,fh,res)) - return -EBUSY; - return videobuf_streamon(get_queue(fh)); - } - case VIDIOC_STREAMOFF: - { - int res = get_ressource(fh); - - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - res_free(dev,fh,res); + up(&core->lock); return 0; } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, - video_do_ioctl); + driver_ioctl); } return 0; } @@ -1461,7 +1506,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); - cx88_call_i2c_clients(dev->core,VIDIOC_G_TUNER,t); + cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); return 0; } case VIDIOC_ENUMINPUT: @@ -1501,8 +1546,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, if (v->tuner) /* Only tuner 0 */ return -EINVAL; - cx88_call_i2c_clients(dev->core,VIDIOCSTUNER,v); - return 0; + cx88_call_i2c_clients(core,VIDIOCSTUNER,v); + return 0; } case VIDIOC_S_TUNER: { @@ -1511,7 +1556,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, if (0 != t->index) return -EINVAL; - cx88_call_i2c_clients(dev->core,VIDIOC_S_TUNER,t); + cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); return 0; } @@ -1569,7 +1614,7 @@ static void cx8800_vid_timeout(unsigned long data) struct cx88_buffer *buf; unsigned long flags; - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH21]); + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); @@ -1614,14 +1659,14 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH21]); + cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); } /* risc1 y */ if (status & 0x01) { spin_lock(&dev->slock); count = cx_read(MO_VIDY_GPCNT); - cx88_wakeup(dev->core, &dev->vidq, count); + cx88_wakeup(core, &dev->vidq, count); spin_unlock(&dev->slock); } @@ -1629,7 +1674,7 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) if (status & 0x08) { spin_lock(&dev->slock); count = cx_read(MO_VBI_GPCNT); - cx88_wakeup(dev->core, &dev->vbiq, count); + cx88_wakeup(core, &dev->vbiq, count); spin_unlock(&dev->slock); } @@ -1798,7 +1843,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, } /* initialize driver struct */ - init_MUTEX(&dev->lock); spin_lock_init(&dev->slock); core->tvnorm = tvnorms; @@ -1835,6 +1879,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, request_module("tuner"); if (core->tda9887_conf) request_module("tda9887"); + /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); @@ -1878,11 +1923,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, pci_set_drvdata(pci_dev,dev); /* initial device configuration */ - down(&dev->lock); - init_controls(dev); - cx88_set_tvnorm(dev->core,tvnorms); - video_mux(dev,0); - up(&dev->lock); + down(&core->lock); + init_controls(core); + cx88_set_tvnorm(core,tvnorms); + video_mux(core,0); + up(&core->lock); /* start tvaudio thread */ if (core->tuner_type != TUNER_ABSENT) @@ -1902,14 +1947,15 @@ fail_free: static void __devexit cx8800_finidev(struct pci_dev *pci_dev) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); + struct cx88_core *core = dev->core; /* stop thread */ - if (dev->core->kthread) { - kthread_stop(dev->core->kthread); - dev->core->kthread = NULL; + if (core->kthread) { + kthread_stop(core->kthread); + core->kthread = NULL; } - cx88_shutdown(dev->core); /* FIXME */ + cx88_shutdown(core); /* FIXME */ pci_disable_device(pci_dev); /* unregister stuff */ @@ -1921,7 +1967,7 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev) /* free memory */ btcx_riscmem_free(dev->pci,&dev->vidq.stopper); list_del(&dev->devlist); - cx88_core_put(dev->core,dev->pci); + cx88_core_put(core,dev->pci); kfree(dev); } @@ -1945,7 +1991,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) spin_unlock(&dev->slock); /* FIXME -- shutdown device */ - cx88_shutdown(dev->core); + cx88_shutdown(core); pci_save_state(pci_dev); if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { @@ -1959,16 +2005,32 @@ static int cx8800_resume(struct pci_dev *pci_dev) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + int err; if (dev->state.disabled) { - pci_enable_device(pci_dev); + err=pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + core->name); + return err; + } + dev->state.disabled = 0; } - pci_set_power_state(pci_dev, PCI_D0); + err= pci_set_power_state(pci_dev, PCI_D0); + if (err) { + printk(KERN_ERR "%s: can't enable device\n", + core->name); + + pci_disable_device(pci_dev); + dev->state.disabled = 1; + + return err; + } pci_restore_state(pci_dev); /* FIXME: re-initialize hardware */ - cx88_reset(dev->core); + cx88_reset(core); /* restart video+vbi capture */ spin_lock(&dev->slock); @@ -2030,6 +2092,8 @@ static void cx8800_fini(void) module_init(cx8800_init); module_exit(cx8800_fini); +EXPORT_SYMBOL(cx88_do_ioctl); + /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index da65dc92787c..f48dd4353568 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -1,5 +1,4 @@ /* - * $Id: cx88.h,v 1.70 2005/07/24 17:44:09 mkrufky Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -35,7 +34,7 @@ #include "btcx-risc.h" #include "cx88-reg.h" -#include <linux/utsname.h> +#include <linux/version.h> #define CX88_VERSION_CODE KERNEL_VERSION(0,0,5) #ifndef TRUE @@ -48,6 +47,9 @@ #define CX88_MAXBOARDS 8 +/* Max number of inputs by card */ +#define MAX_CX88_INPUT 8 + /* ----------------------------------------------------------- */ /* defines and enums */ @@ -199,7 +201,7 @@ struct cx88_board { unsigned char tuner_addr; unsigned char radio_addr; int tda9887_conf; - struct cx88_input input[8]; + struct cx88_input input[MAX_CX88_INPUT]; struct cx88_input radio; int blackbird:1; int dvb:1; @@ -288,6 +290,11 @@ struct cx88_core { /* IR remote control state */ struct cx88_IR *ir; + + struct semaphore lock; + + /* various v4l controls */ + u32 freq; }; struct cx8800_dev; @@ -323,8 +330,7 @@ struct cx8800_suspend_state { struct cx8800_dev { struct cx88_core *core; struct list_head devlist; - struct semaphore lock; - spinlock_t slock; + spinlock_t slock; /* various device info */ unsigned int resources; @@ -342,7 +348,6 @@ struct cx8800_dev { struct cx88_dmaqueue vbiq; /* various v4l controls */ - u32 freq; /* other global state info */ struct cx8800_suspend_state state; @@ -350,14 +355,8 @@ struct cx8800_dev { /* ----------------------------------------------------------- */ /* function 1: audio/alsa stuff */ +/* =============> moved to cx88-alsa.c <====================== */ -struct cx8801_dev { - struct cx88_core *core; - - /* pci i/o */ - struct pci_dev *pci; - unsigned char pci_rev,pci_lat; -}; /* ----------------------------------------------------------- */ /* function 2: mpeg stuff */ @@ -373,8 +372,7 @@ struct cx8802_suspend_state { struct cx8802_dev { struct cx88_core *core; - struct semaphore lock; - spinlock_t slock; + spinlock_t slock; /* pci i/o */ struct pci_dev *pci; @@ -553,8 +551,21 @@ void cx8802_fini_common(struct cx8802_dev *dev); int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); int cx8802_resume_common(struct pci_dev *pci_dev); +/* ----------------------------------------------------------- */ +/* cx88-video.c */ +extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, + struct cx88_core *core, unsigned int cmd, + void *arg, v4l2_kioctl driver_ioctl); + +/* ----------------------------------------------------------- */ +/* cx88-blackbird.c */ +extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + /* * Local variables: * c-basic-offset: 8 * End: + * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off */ diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c new file mode 100644 index 000000000000..b2b0384cd4b9 --- /dev/null +++ b/drivers/media/video/indycam.c @@ -0,0 +1,412 @@ +/* + * indycam.c - Silicon Graphics IndyCam digital camera driver + * + * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> + * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/sched.h> + +#include <linux/videodev.h> +/* IndyCam decodes stream of photons into digital image representation ;-) */ +#include <linux/video_decoder.h> +#include <linux/i2c.h> + +#include "indycam.h" + +//#define INDYCAM_DEBUG + +#define INDYCAM_MODULE_VERSION "0.0.3" + +MODULE_DESCRIPTION("SGI IndyCam driver"); +MODULE_VERSION(INDYCAM_MODULE_VERSION); +MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); +MODULE_LICENSE("GPL"); + +#ifdef INDYCAM_DEBUG +#define dprintk(x...) printk("IndyCam: " x); +#define indycam_regdump(client) indycam_regdump_debug(client) +#else +#define dprintk(x...) +#define indycam_regdump(client) +#endif + +#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO) + +struct indycam { + struct i2c_client *client; + int version; +}; + +static struct i2c_driver i2c_driver_indycam; + +static const unsigned char initseq[] = { + INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ + INDYCAM_SHUTTER_DEFAULT, /* INDYCAM_SHUTTER */ + INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */ + 0x00, /* INDYCAM_BRIGHTNESS (read-only) */ + INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */ + INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */ + INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */ + INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */ +}; + +/* IndyCam register handling */ + +static int indycam_read_reg(struct i2c_client *client, unsigned char reg, + unsigned char *value) +{ + int ret; + + if (reg == INDYCAM_RESET) { + dprintk("indycam_read_reg(): " + "skipping write-only register %d\n", reg); + *value = 0; + return 0; + } + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, " + "register = 0x%02x\n", reg); + return ret; + } + + *value = (unsigned char)ret; + + return 0; +} + +static int indycam_write_reg(struct i2c_client *client, unsigned char reg, + unsigned char value) +{ + int err; + + if ((reg == INDYCAM_BRIGHTNESS) + || (reg == INDYCAM_VERSION)) { + dprintk("indycam_write_reg(): " + "skipping read-only register %d\n", reg); + return 0; + } + + dprintk("Writing Reg %d = 0x%02x\n", reg, value); + err = i2c_smbus_write_byte_data(client, reg, value); + if (err) { + printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, " + "register = 0x%02x, value = 0x%02x\n", reg, value); + } + return err; +} + +static int indycam_write_block(struct i2c_client *client, unsigned char reg, + unsigned char length, unsigned char *data) +{ + unsigned char i; + int err; + + for (i = reg; i < length; i++) { + err = indycam_write_reg(client, reg + i, data[i]); + if (err) + return err; + } + + return 0; +} + +/* Helper functions */ + +#ifdef INDYCAM_DEBUG +static void indycam_regdump_debug(struct i2c_client *client) +{ + int i; + unsigned char val; + + for (i = 0; i < 9; i++) { + indycam_read_reg(client, i, &val); + dprintk("Reg %d = 0x%02x\n", i, val); + } +} +#endif + +static int indycam_get_controls(struct i2c_client *client, + struct indycam_control *ctrl) +{ + unsigned char ctrl_reg; + + indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg); + ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA) + ? INDYCAM_VALUE_ENABLED + : INDYCAM_VALUE_DISABLED; + ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL) + ? INDYCAM_VALUE_ENABLED + : INDYCAM_VALUE_DISABLED; + indycam_read_reg(client, INDYCAM_SHUTTER, + (unsigned char *)&ctrl->shutter); + indycam_read_reg(client, INDYCAM_GAIN, + (unsigned char *)&ctrl->gain); + indycam_read_reg(client, INDYCAM_RED_BALANCE, + (unsigned char *)&ctrl->red_balance); + indycam_read_reg(client, INDYCAM_BLUE_BALANCE, + (unsigned char *)&ctrl->blue_balance); + indycam_read_reg(client, INDYCAM_RED_SATURATION, + (unsigned char *)&ctrl->red_saturation); + indycam_read_reg(client, INDYCAM_BLUE_SATURATION, + (unsigned char *)&ctrl->blue_saturation); + indycam_read_reg(client, INDYCAM_GAMMA, + (unsigned char *)&ctrl->gamma); + + return 0; +} + +static int indycam_set_controls(struct i2c_client *client, + struct indycam_control *ctrl) +{ + unsigned char ctrl_reg; + + indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg); + if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) { + if (ctrl->agc) + ctrl_reg |= INDYCAM_CONTROL_AGCENA; + else + ctrl_reg &= ~INDYCAM_CONTROL_AGCENA; + } + if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) { + if (ctrl->awb) + ctrl_reg |= INDYCAM_CONTROL_AWBCTL; + else + ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL; + } + indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg); + + if (ctrl->shutter >= 0) + indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter); + if (ctrl->gain >= 0) + indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain); + if (ctrl->red_balance >= 0) + indycam_write_reg(client, INDYCAM_RED_BALANCE, + ctrl->red_balance); + if (ctrl->blue_balance >= 0) + indycam_write_reg(client, INDYCAM_BLUE_BALANCE, + ctrl->blue_balance); + if (ctrl->red_saturation >= 0) + indycam_write_reg(client, INDYCAM_RED_SATURATION, + ctrl->red_saturation); + if (ctrl->blue_saturation >= 0) + indycam_write_reg(client, INDYCAM_BLUE_SATURATION, + ctrl->blue_saturation); + if (ctrl->gamma >= 0) + indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma); + + return 0; +} + +/* I2C-interface */ + +static int indycam_attach(struct i2c_adapter *adap, int addr, int kind) +{ + int err = 0; + struct indycam *camera; + struct i2c_client *client; + + printk(KERN_INFO "SGI IndyCam driver version %s\n", + INDYCAM_MODULE_VERSION); + + client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!client) + return -ENOMEM; + camera = kmalloc(sizeof(struct indycam), GFP_KERNEL); + if (!camera) { + err = -ENOMEM; + goto out_free_client; + } + + memset(client, 0, sizeof(struct i2c_client)); + memset(camera, 0, sizeof(struct indycam)); + + client->addr = addr; + client->adapter = adap; + client->driver = &i2c_driver_indycam; + client->flags = 0; + strcpy(client->name, "IndyCam client"); + i2c_set_clientdata(client, camera); + + camera->client = client; + + err = i2c_attach_client(client); + if (err) + goto out_free_camera; + + camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION); + if (camera->version != CAMERA_VERSION_INDY && + camera->version != CAMERA_VERSION_MOOSE) { + err = -ENODEV; + goto out_detach_client; + } + printk(KERN_INFO "IndyCam v%d.%d detected\n", + INDYCAM_VERSION_MAJOR(camera->version), + INDYCAM_VERSION_MINOR(camera->version)); + + indycam_regdump(client); + + // initialize + err = indycam_write_block(client, 0, sizeof(initseq), + (unsigned char *)&initseq); + if (err) { + printk(KERN_ERR "IndyCam initalization failed\n"); + err = -EIO; + goto out_detach_client; + } + + indycam_regdump(client); + + // white balance + err = indycam_write_reg(client, INDYCAM_CONTROL, + INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); + if (err) { + printk(KERN_ERR "IndyCam white balance " + "initialization failed\n"); + err = -EIO; + goto out_detach_client; + } + + indycam_regdump(client); + + printk(KERN_INFO "IndyCam initialized\n"); + + return 0; + +out_detach_client: + i2c_detach_client(client); +out_free_camera: + kfree(camera); +out_free_client: + kfree(client); + return err; +} + +static int indycam_probe(struct i2c_adapter *adap) +{ + /* Indy specific crap */ + if (adap->id == VINO_ADAPTER) + return indycam_attach(adap, INDYCAM_ADDR, 0); + /* Feel free to add probe here :-) */ + return -ENODEV; +} + +static int indycam_detach(struct i2c_client *client) +{ + struct indycam *camera = i2c_get_clientdata(client); + + i2c_detach_client(client); + kfree(camera); + kfree(client); + return 0; +} + +static int indycam_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + // struct indycam *camera = i2c_get_clientdata(client); + + /* The old video_decoder interface just isn't enough, + * so we'll use some custom commands. */ + switch (cmd) { + case DECODER_GET_CAPABILITIES: { + struct video_decoder_capability *cap = arg; + + cap->flags = VIDEO_DECODER_NTSC; + cap->inputs = 1; + cap->outputs = 1; + break; + } + case DECODER_GET_STATUS: { + int *iarg = arg; + + *iarg = DECODER_STATUS_GOOD | DECODER_STATUS_NTSC | + DECODER_STATUS_COLOR; + break; + } + case DECODER_SET_NORM: { + int *iarg = arg; + + switch (*iarg) { + case VIDEO_MODE_NTSC: + break; + default: + return -EINVAL; + } + break; + } + case DECODER_SET_INPUT: { + int *iarg = arg; + + if (*iarg != 0) + return -EINVAL; + break; + } + case DECODER_SET_OUTPUT: { + int *iarg = arg; + + if (*iarg != 0) + return -EINVAL; + break; + } + case DECODER_ENABLE_OUTPUT: { + /* Always enabled */ + break; + } + case DECODER_SET_PICTURE: { + // struct video_picture *pic = arg; + /* TODO: convert values for indycam_set_controls() */ + break; + } + case DECODER_INDYCAM_GET_CONTROLS: { + struct indycam_control *ctrl = arg; + indycam_get_controls(client, ctrl); + } + case DECODER_INDYCAM_SET_CONTROLS: { + struct indycam_control *ctrl = arg; + indycam_set_controls(client, ctrl); + } + default: + return -EINVAL; + } + + return 0; +} + +static struct i2c_driver i2c_driver_indycam = { + .owner = THIS_MODULE, + .name = "indycam", + .id = I2C_DRIVERID_INDYCAM, + .flags = I2C_DF_NOTIFY, + .attach_adapter = indycam_probe, + .detach_client = indycam_detach, + .command = indycam_command, +}; + +static int __init indycam_init(void) +{ + return i2c_add_driver(&i2c_driver_indycam); +} + +static void __exit indycam_exit(void) +{ + i2c_del_driver(&i2c_driver_indycam); +} + +module_init(indycam_init); +module_exit(indycam_exit); diff --git a/drivers/media/video/indycam.h b/drivers/media/video/indycam.h new file mode 100644 index 000000000000..d9ddb6b79a03 --- /dev/null +++ b/drivers/media/video/indycam.h @@ -0,0 +1,112 @@ +/* + * indycam.h - Silicon Graphics IndyCam digital camera driver + * + * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> + * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _INDYCAM_H_ +#define _INDYCAM_H_ + +/* I2C address for the Guinness Camera */ +#define INDYCAM_ADDR 0x56 + +/* Camera version */ +#define CAMERA_VERSION_INDY 0x10 /* v1.0 */ +#define CAMERA_VERSION_MOOSE 0x12 /* v1.2 */ +#define INDYCAM_VERSION_MAJOR(x) (((x) & 0xf0) >> 4) +#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f) + +/* Register bus addresses */ +#define INDYCAM_CONTROL 0x00 +#define INDYCAM_SHUTTER 0x01 +#define INDYCAM_GAIN 0x02 +#define INDYCAM_BRIGHTNESS 0x03 /* read-only */ +#define INDYCAM_RED_BALANCE 0x04 +#define INDYCAM_BLUE_BALANCE 0x05 +#define INDYCAM_RED_SATURATION 0x06 +#define INDYCAM_BLUE_SATURATION 0x07 +#define INDYCAM_GAMMA 0x08 +#define INDYCAM_VERSION 0x0e /* read-only */ +#define INDYCAM_RESET 0x0f /* write-only */ + +#define INDYCAM_LED 0x46 +#define INDYCAM_ORIENTATION 0x47 +#define INDYCAM_BUTTON 0x48 + +/* Field definitions of registers */ +#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */ +#define INDYCAM_CONTROL_AWBCTL (1<<1) /* automatic white balance */ + /* 2-3 are reserved */ +#define INDYCAM_CONTROL_EVNFLD (1<<4) /* read-only */ + +#define INDYCAM_SHUTTER_10000 0x02 /* 1/10000 second */ +#define INDYCAM_SHUTTER_4000 0x04 /* 1/4000 second */ +#define INDYCAM_SHUTTER_2000 0x08 /* 1/2000 second */ +#define INDYCAM_SHUTTER_1000 0x10 /* 1/1000 second */ +#define INDYCAM_SHUTTER_500 0x20 /* 1/500 second */ +#define INDYCAM_SHUTTER_250 0x3f /* 1/250 second */ +#define INDYCAM_SHUTTER_125 0x7e /* 1/125 second */ +#define INDYCAM_SHUTTER_100 0x9e /* 1/100 second */ +#define INDYCAM_SHUTTER_60 0x00 /* 1/60 second */ + +#define INDYCAM_LED_ACTIVE 0x10 +#define INDYCAM_LED_INACTIVE 0x30 +#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40 +#define INDYCAM_BUTTON_RELEASED 0x10 + +#define INDYCAM_SHUTTER_MIN 0x00 +#define INDYCAM_SHUTTER_MAX 0xff +#define INDYCAM_GAIN_MIN 0x00 +#define INDYCAM_GAIN_MAX 0xff +#define INDYCAM_RED_BALANCE_MIN 0x00 /* the effect is the opposite? */ +#define INDYCAM_RED_BALANCE_MAX 0xff +#define INDYCAM_BLUE_BALANCE_MIN 0x00 /* the effect is the opposite? */ +#define INDYCAM_BLUE_BALANCE_MAX 0xff +#define INDYCAM_RED_SATURATION_MIN 0x00 +#define INDYCAM_RED_SATURATION_MAX 0xff +#define INDYCAM_BLUE_SATURATION_MIN 0x00 +#define INDYCAM_BLUE_SATURATION_MAX 0xff +#define INDYCAM_GAMMA_MIN 0x00 +#define INDYCAM_GAMMA_MAX 0xff + +/* Driver interface definitions */ + +#define INDYCAM_VALUE_ENABLED 1 +#define INDYCAM_VALUE_DISABLED 0 +#define INDYCAM_VALUE_UNCHANGED -1 + +/* When setting controls, a value of -1 leaves the control unchanged. */ +struct indycam_control { + int agc; /* boolean */ + int awb; /* boolean */ + int shutter; + int gain; + int red_balance; + int blue_balance; + int red_saturation; + int blue_saturation; + int gamma; +}; + +#define DECODER_INDYCAM_GET_CONTROLS _IOR('d', 193, struct indycam_control) +#define DECODER_INDYCAM_SET_CONTROLS _IOW('d', 194, struct indycam_control) + +/* Default values for controls */ + +#define INDYCAM_AGC_DEFAULT INDYCAM_VALUE_ENABLED +#define INDYCAM_AWB_DEFAULT INDYCAM_VALUE_ENABLED + +#define INDYCAM_SHUTTER_DEFAULT INDYCAM_SHUTTER_60 +#define INDYCAM_GAIN_DEFAULT 0x80 +#define INDYCAM_RED_BALANCE_DEFAULT 0x18 +#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4 +#define INDYCAM_RED_SATURATION_DEFAULT 0x80 +#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0 +#define INDYCAM_GAMMA_DEFAULT 0x80 + +#endif diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c index a565823330aa..cf292da8fdd5 100644 --- a/drivers/media/video/ir-kbd-gpio.c +++ b/drivers/media/video/ir-kbd-gpio.c @@ -1,5 +1,4 @@ /* - * $Id: ir-kbd-gpio.c,v 1.13 2005/05/15 19:01:26 mchehab Exp $ * * Copyright (c) 2003 Gerd Knorr * Copyright (c) 2003 Pavel Machek @@ -354,6 +353,7 @@ static int ir_probe(struct device *dev) ir->input.id.vendor = sub->core->pci->vendor; ir->input.id.product = sub->core->pci->device; } + ir->input.dev = &sub->core->pci->dev; if (ir->polling) { INIT_WORK(&ir->work, ir_work, ir); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 9fc5055e001c..67105b9804a2 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -1,5 +1,4 @@ /* - * $Id: ir-kbd-i2c.c,v 1.11 2005/07/07 16:42:11 mchehab Exp $ * * keyboard input driver for i2c IR remote controls * @@ -308,7 +307,7 @@ static struct i2c_driver driver = { static struct i2c_client client_template = { - I2C_DEVNAME("unset"), + .name = "unset", .driver = &driver }; @@ -429,10 +428,10 @@ static int ir_probe(struct i2c_adapter *adap) struct i2c_client c; char buf; int i,rc; switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_HW_B_BT848: probe = probe_bttv; break; - case I2C_ALGO_SAA7134: + case I2C_HW_SAA7134: probe = probe_saa7134; break; } diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index fe194012bccf..3f2a882bc20a 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -37,6 +37,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/vmalloc.h> +#include <linux/dma-mapping.h> #include "meye.h" #include <linux/meye.h> @@ -121,7 +122,7 @@ static int ptable_alloc(void) memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); /* give only 32 bit DMA addresses */ - if (dma_set_mask(&meye.mchip_dev->dev, 0xffffffff)) + if (dma_set_mask(&meye.mchip_dev->dev, DMA_32BIT_MASK)) return -1; meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev, diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 62f1b8ddb98b..f0d43fc2632f 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -124,10 +124,14 @@ module_param(standard, int, 0644); module_param(amsound, int, 0644); module_param(dolby, int, 0644); +MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Simple, 2=Simpler"); MODULE_PARM_DESC(once, "No continuous stereo monitoring"); MODULE_PARM_DESC(debug, "Enable debug messages"); +MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); +MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); + MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); MODULE_AUTHOR("Gerd Knorr"); @@ -1416,7 +1420,7 @@ static int msp_detach(struct i2c_client *client); static int msp_probe(struct i2c_adapter *adap); static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); -static int msp_suspend(struct device * dev, u32 state, u32 level); +static int msp_suspend(struct device * dev, pm_message_t state, u32 level); static int msp_resume(struct device * dev, u32 level); static void msp_wake_thread(struct i2c_client *client); @@ -1437,7 +1441,7 @@ static struct i2c_driver driver = { static struct i2c_client client_template = { - I2C_DEVNAME("(unset)"), + .name = "(unset)", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, }; @@ -1452,7 +1456,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) client_template.addr = addr; if (-1 == msp3400c_reset(&client_template)) { - dprintk("msp3400: no chip found\n"); + dprintk("msp34xx: no chip found\n"); return -1; } @@ -1478,7 +1482,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) if (-1 == msp3400c_reset(c)) { kfree(msp); kfree(c); - dprintk("msp3400: no chip found\n"); + dprintk("msp34xx: no chip found\n"); return -1; } @@ -1488,7 +1492,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) { kfree(msp); kfree(c); - printk("msp3400: error while reading chip version\n"); + dprintk("msp34xx: error while reading chip version\n"); return -1; } @@ -1509,7 +1513,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) } /* hello world :-) */ - printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c)); + printk(KERN_INFO "msp34xx: init: chip=%s", c->name); if (HAVE_NICAM(msp)) printk(" +nicam"); if (HAVE_SIMPLE(msp)) @@ -1817,7 +1821,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int msp_suspend(struct device * dev, u32 state, u32 level) +static int msp_suspend(struct device * dev, pm_message_t state, u32 level) { struct i2c_client *c = container_of(dev, struct i2c_client, dev); diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index 023f33056a4f..2d9ff40f0b09 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h @@ -1,5 +1,4 @@ /* - * $Id: msp3400.h,v 1.3 2005/06/12 04:19:19 mchehab Exp $ */ #ifndef MSP3400_H diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 2fb7c2d1787a..972aa5e0aeef 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -1,5 +1,4 @@ /* - * $Id: mt20xx.c,v 1.5 2005/06/16 08:29:49 nsh Exp $ * * i2c tv tuner chip device driver * controls microtune tuners, mt2032 + mt2050 at the moment. @@ -494,6 +493,7 @@ int microtune_init(struct i2c_client *c) memset(buf,0,sizeof(buf)); t->tv_freq = NULL; t->radio_freq = NULL; + t->standby = NULL; name = "unknown"; i2c_master_send(c,buf,1); diff --git a/drivers/media/video/ovcamchip/ov6x20.c b/drivers/media/video/ovcamchip/ov6x20.c index 3433619ad93f..b3f4d266cede 100644 --- a/drivers/media/video/ovcamchip/ov6x20.c +++ b/drivers/media/video/ovcamchip/ov6x20.c @@ -164,10 +164,10 @@ static int ov6x20_init(struct i2c_client *c) DDEBUG(4, &c->dev, "entered"); switch (c->adapter->id) { - case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511: + case I2C_HW_SMBUS_OV511: rc = ov_write_regvals(c, regvals_init_6x20_511); break; - case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518: + case I2C_HW_SMBUS_OV518: rc = ov_write_regvals(c, regvals_init_6x20_518); break; default: @@ -338,7 +338,7 @@ static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win) /******** Palette-specific regs ********/ /* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */ - if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) { + if (c->adapter->id == I2C_HW_SMBUS_OV518) { if (win->format == VIDEO_PALETTE_GREY) ov_write_mask(c, 0x13, 0x00, 0x20); else diff --git a/drivers/media/video/ovcamchip/ov6x30.c b/drivers/media/video/ovcamchip/ov6x30.c index 44a842379b45..6eab458ab792 100644 --- a/drivers/media/video/ovcamchip/ov6x30.c +++ b/drivers/media/video/ovcamchip/ov6x30.c @@ -301,7 +301,7 @@ static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win) /******** Palette-specific regs ********/ if (win->format == VIDEO_PALETTE_GREY) { - if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) { + if (c->adapter->id == I2C_HW_SMBUS_OV518) { /* Do nothing - we're already in 8-bit mode */ } else { ov_write_mask(c, 0x13, 0x20, 0x20); @@ -313,7 +313,7 @@ static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win) * Therefore, the OV6630 needs to be in 8-bit multiplexed * output mode */ - if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) { + if (c->adapter->id == I2C_HW_SMBUS_OV518) { /* Do nothing - we want to stay in 8-bit mode */ /* Warning: Messing with reg 0x13 breaks OV518 color */ } else { diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c index 54dd5612d3b8..2de34ebf0673 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_core.c +++ b/drivers/media/video/ovcamchip/ovcamchip_core.c @@ -296,10 +296,10 @@ static int ovcamchip_attach(struct i2c_adapter *adap) * attach to adapters that are known to contain OV camera chips. */ switch (adap->id) { - case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511): - case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518): - case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OVFX2): - case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF): + case I2C_HW_SMBUS_OV511: + case I2C_HW_SMBUS_OV518: + case I2C_HW_SMBUS_OVFX2: + case I2C_HW_SMBUS_W9968CF: PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id); break; default: @@ -314,7 +314,7 @@ static int ovcamchip_attach(struct i2c_adapter *adap) } memcpy(c, &client_template, sizeof *c); c->adapter = adap; - strcpy(i2c_clientname(c), "OV????"); + strcpy(c->name, "OV????"); ov = kmalloc(sizeof *ov, GFP_KERNEL); if (!ov) { @@ -328,7 +328,7 @@ static int ovcamchip_attach(struct i2c_adapter *adap) if (rc < 0) goto error; - strcpy(i2c_clientname(c), chip_names[ov->subtype]); + strcpy(c->name, chip_names[ov->subtype]); PDEBUG(1, "Camera chip detection complete"); @@ -421,7 +421,7 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - I2C_DEVNAME("(unset)"), + .name = "(unset)", .driver = &driver, }; diff --git a/drivers/media/video/rds.h b/drivers/media/video/rds.h new file mode 100644 index 000000000000..30337d0f1a87 --- /dev/null +++ b/drivers/media/video/rds.h @@ -0,0 +1,48 @@ +/* + + Types and defines needed for RDS. This is included by + saa6588.c and every driver (e.g. bttv-driver.c) that wants + to use the saa6588 module. + + Instead of having a seperate rds.h, I'd prefer to include + this stuff in one of the already existing files like tuner.h + + (c) 2005 by Hans J. Koch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef _RDS_H +#define _RDS_H + +struct rds_command { + unsigned int block_count; + int result; + unsigned char *buffer; + struct file *instance; + poll_table *event_list; +}; + +#define RDS_CMD_OPEN _IOW('R',1,int) +#define RDS_CMD_CLOSE _IOW('R',2,int) +#define RDS_CMD_READ _IOR('R',3,int) +#define RDS_CMD_POLL _IOR('R',4,int) + +#endif + + + + diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c new file mode 100644 index 000000000000..1a657a70ff43 --- /dev/null +++ b/drivers/media/video/saa6588.c @@ -0,0 +1,534 @@ +/* + Driver for SAA6588 RDS decoder + + (c) 2005 Hans J. Koch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/types.h> +#include <linux/videodev.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/wait.h> +#include <asm/uaccess.h> + +#include <media/id.h> + +#include "rds.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { + 0x20 >> 1, + 0x22 >> 1, + I2C_CLIENT_END, +}; + +I2C_CLIENT_INSMOD; + +/* insmod options */ +static unsigned int debug = 0; +static unsigned int xtal = 0; +static unsigned int rbds = 0; +static unsigned int plvl = 0; +static unsigned int bufblocks = 100; + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "enable debug messages"); +MODULE_PARM(xtal, "i"); +MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0"); +MODULE_PARM(rbds, "i"); +MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0"); +MODULE_PARM(plvl, "i"); +MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0"); +MODULE_PARM(bufblocks, "i"); +MODULE_PARM_DESC(bufblocks, "number of buffered blocks, default 100"); + +MODULE_DESCRIPTION("v4l2 driver module for SAA6588 RDS decoder"); +MODULE_AUTHOR("Hans J. Koch <koch@hjk-az.de>"); + +MODULE_LICENSE("GPL"); + +/* ---------------------------------------------------------------------- */ + +#define UNSET (-1U) +#define PREFIX "saa6588: " +#define dprintk if (debug) printk + +struct saa6588 { + struct i2c_client client; + struct work_struct work; + struct timer_list timer; + spinlock_t lock; + unsigned char *buffer; + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; + unsigned int block_count; + unsigned char last_blocknum; + wait_queue_head_t read_queue; + int data_available_for_read; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +/* ---------------------------------------------------------------------- */ + +/* + * SAA6588 defines + */ + +/* Initialization and mode control byte (0w) */ + +/* bit 0+1 (DAC0/DAC1) */ +#define cModeStandard 0x00 +#define cModeFastPI 0x01 +#define cModeReducedRequest 0x02 +#define cModeInvalid 0x03 + +/* bit 2 (RBDS) */ +#define cProcessingModeRDS 0x00 +#define cProcessingModeRBDS 0x04 + +/* bit 3+4 (SYM0/SYM1) */ +#define cErrCorrectionNone 0x00 +#define cErrCorrection2Bits 0x08 +#define cErrCorrection5Bits 0x10 +#define cErrCorrectionNoneRBDS 0x18 + +/* bit 5 (NWSY) */ +#define cSyncNormal 0x00 +#define cSyncRestart 0x20 + +/* bit 6 (TSQD) */ +#define cSigQualityDetectOFF 0x00 +#define cSigQualityDetectON 0x40 + +/* bit 7 (SQCM) */ +#define cSigQualityTriggered 0x00 +#define cSigQualityContinous 0x80 + +/* Pause level and flywheel control byte (1w) */ + +/* bits 0..5 (FEB0..FEB5) */ +#define cFlywheelMaxBlocksMask 0x3F +#define cFlywheelDefault 0x20 + +/* bits 6+7 (PL0/PL1) */ +#define cPauseLevel_11mV 0x00 +#define cPauseLevel_17mV 0x40 +#define cPauseLevel_27mV 0x80 +#define cPauseLevel_43mV 0xC0 + +/* Pause time/oscillator frequency/quality detector control byte (1w) */ + +/* bits 0..4 (SQS0..SQS4) */ +#define cQualityDetectSensMask 0x1F +#define cQualityDetectDefault 0x0F + +/* bit 5 (SOSC) */ +#define cSelectOscFreqOFF 0x00 +#define cSelectOscFreqON 0x20 + +/* bit 6+7 (PTF0/PTF1) */ +#define cOscFreq_4332kHz 0x00 +#define cOscFreq_8664kHz 0x40 +#define cOscFreq_12996kHz 0x80 +#define cOscFreq_17328kHz 0xC0 + +/* ---------------------------------------------------------------------- */ + +static int block_to_user_buf(struct saa6588 *s, unsigned char *user_buf) +{ + int i; + + if (s->rd_index == s->wr_index) { + if (debug > 2) + dprintk(PREFIX "Read: buffer empty.\n"); + return 0; + } + + if (debug > 2) { + dprintk(PREFIX "Read: "); + for (i = s->rd_index; i < s->rd_index + 3; i++) + dprintk("0x%02x ", s->buffer[i]); + } + + if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3)) + return -EFAULT; + + s->rd_index += 3; + if (s->rd_index >= s->buf_size) + s->rd_index = 0; + s->block_count--; + + if (debug > 2) + dprintk("%d blocks total.\n", s->block_count); + + return 1; +} + +static void read_from_buf(struct saa6588 *s, struct rds_command *a) +{ + unsigned long flags; + + unsigned char *buf_ptr = a->buffer; /* This is a user space buffer! */ + unsigned int i; + unsigned int rd_blocks; + + a->result = 0; + if (!a->buffer) + return; + + while (!s->data_available_for_read) { + int ret = wait_event_interruptible(s->read_queue, + s->data_available_for_read); + if (ret == -ERESTARTSYS) { + a->result = -EINTR; + return; + } + } + + spin_lock_irqsave(&s->lock, flags); + rd_blocks = a->block_count; + if (rd_blocks > s->block_count) + rd_blocks = s->block_count; + + if (!rd_blocks) + return; + + for (i = 0; i < rd_blocks; i++) { + if (block_to_user_buf(s, buf_ptr)) { + buf_ptr += 3; + a->result++; + } else + break; + } + a->result *= 3; + s->data_available_for_read = (s->block_count > 0); + spin_unlock_irqrestore(&s->lock, flags); +} + +static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf) +{ + unsigned int i; + + if (debug > 3) + dprintk(PREFIX "New block: "); + + for (i = 0; i < 3; ++i) { + if (debug > 3) + dprintk("0x%02x ", blockbuf[i]); + s->buffer[s->wr_index] = blockbuf[i]; + s->wr_index++; + } + + if (s->wr_index >= s->buf_size) + s->wr_index = 0; + + if (s->wr_index == s->rd_index) { + s->rd_index++; + if (s->rd_index >= s->buf_size) + s->rd_index = 0; + } else + s->block_count++; + + if (debug > 3) + dprintk("%d blocks total.\n", s->block_count); +} + +static void saa6588_i2c_poll(struct saa6588 *s) +{ + unsigned long flags; + unsigned char tmpbuf[6]; + unsigned char blocknum; + unsigned char tmp; + + /* Although we only need 3 bytes, we have to read at least 6. + SAA6588 returns garbage otherwise */ + if (6 != i2c_master_recv(&s->client, &tmpbuf[0], 6)) { + if (debug > 1) + dprintk(PREFIX "read error!\n"); + return; + } + + blocknum = tmpbuf[0] >> 5; + if (blocknum == s->last_blocknum) { + if (debug > 3) + dprintk("Saw block %d again.\n", blocknum); + return; + } + + s->last_blocknum = blocknum; + + /* + Byte order according to v4l2 specification: + + Byte 0: Least Significant Byte of RDS Block + Byte 1: Most Significant Byte of RDS Block + Byte 2 Bit 7: Error bit. Indicates that an uncorrectable error + occurred during reception of this block. + Bit 6: Corrected bit. Indicates that an error was + corrected for this data block. + Bits 5-3: Received Offset. Indicates the offset received + by the sync system. + Bits 2-0: Offset Name. Indicates the offset applied to this data. + + SAA6588 byte order is Status-MSB-LSB, so we have to swap the + first and the last of the 3 bytes block. + */ + + tmp = tmpbuf[2]; + tmpbuf[2] = tmpbuf[0]; + tmpbuf[0] = tmp; + + tmp = blocknum; + tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */ + if ((tmpbuf[2] & 0x03) == 0x03) + tmp |= 0x80; /* uncorrectable error */ + else if ((tmpbuf[2] & 0x03) != 0x00) + tmp |= 0x40; /* corrected error */ + tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */ + + spin_lock_irqsave(&s->lock, flags); + block_to_buf(s, tmpbuf); + spin_unlock_irqrestore(&s->lock, flags); + s->data_available_for_read = 1; + wake_up_interruptible(&s->read_queue); +} + +static void saa6588_timer(unsigned long data) +{ + struct saa6588 *s = (struct saa6588 *)data; + + schedule_work(&s->work); +} + +static void saa6588_work(void *data) +{ + struct saa6588 *s = (struct saa6588 *)data; + + saa6588_i2c_poll(s); + mod_timer(&s->timer, jiffies + HZ / 50); /* 20 msec */ +} + +static int saa6588_configure(struct saa6588 *s) +{ + unsigned char buf[3]; + int rc; + + buf[0] = cSyncRestart; + if (rbds) + buf[0] |= cProcessingModeRBDS; + + buf[1] = cFlywheelDefault; + switch (plvl) { + case 0: + buf[1] |= cPauseLevel_11mV; + break; + case 1: + buf[1] |= cPauseLevel_17mV; + break; + case 2: + buf[1] |= cPauseLevel_27mV; + break; + case 3: + buf[1] |= cPauseLevel_43mV; + break; + default: /* nothing */ + break; + } + + buf[2] = cQualityDetectDefault | cSelectOscFreqON; + + switch (xtal) { + case 0: + buf[2] |= cOscFreq_4332kHz; + break; + case 1: + buf[2] |= cOscFreq_8664kHz; + break; + case 2: + buf[2] |= cOscFreq_12996kHz; + break; + case 3: + buf[2] |= cOscFreq_17328kHz; + break; + default: /* nothing */ + break; + } + + dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n", + buf[0], buf[1], buf[2]); + + if (3 != (rc = i2c_master_send(&s->client, buf, 3))) + printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc); + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) +{ + struct saa6588 *s; + client_template.adapter = adap; + client_template.addr = addr; + + printk(PREFIX "chip found @ 0x%x\n", addr << 1); + + if (NULL == (s = kmalloc(sizeof(*s), GFP_KERNEL))) + return -ENOMEM; + + s->buf_size = bufblocks * 3; + + if (NULL == (s->buffer = kmalloc(s->buf_size, GFP_KERNEL))) { + kfree(s); + return -ENOMEM; + } + s->client = client_template; + s->block_count = 0; + s->wr_index = 0; + s->rd_index = 0; + s->last_blocknum = 0xff; + init_waitqueue_head(&s->read_queue); + s->data_available_for_read = 0; + i2c_set_clientdata(&s->client, s); + i2c_attach_client(&s->client); + + saa6588_configure(s); + + /* start polling via eventd */ + INIT_WORK(&s->work, saa6588_work, s); + init_timer(&s->timer); + s->timer.function = saa6588_timer; + s->timer.data = (unsigned long)s; + schedule_work(&s->work); + + return 0; +} + +static int saa6588_probe(struct i2c_adapter *adap) +{ +#ifdef I2C_CLASS_TV_ANALOG + if (adap->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, saa6588_attach); +#else + switch (adap->id) { + case I2C_ALGO_BIT | I2C_HW_B_BT848: + case I2C_ALGO_BIT | I2C_HW_B_RIVA: + case I2C_ALGO_SAA7134: + return i2c_probe(adap, &addr_data, saa6588_attach); + break; + } +#endif + return 0; +} + +static int saa6588_detach(struct i2c_client *client) +{ + struct saa6588 *s = i2c_get_clientdata(client); + + del_timer_sync(&s->timer); + flush_scheduled_work(); + + i2c_detach_client(client); + kfree(s->buffer); + kfree(s); + return 0; +} + +static int saa6588_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct saa6588 *s = i2c_get_clientdata(client); + struct rds_command *a = (struct rds_command *)arg; + + switch (cmd) { + /* --- open() for /dev/radio --- */ + case RDS_CMD_OPEN: + a->result = 0; /* return error if chip doesn't work ??? */ + break; + /* --- close() for /dev/radio --- */ + case RDS_CMD_CLOSE: + s->data_available_for_read = 1; + wake_up_interruptible(&s->read_queue); + a->result = 0; + break; + /* --- read() for /dev/radio --- */ + case RDS_CMD_READ: + read_from_buf(s, a); + break; + /* --- poll() for /dev/radio --- */ + case RDS_CMD_POLL: + a->result = 0; + if (s->data_available_for_read) { + a->result |= POLLIN | POLLRDNORM; + } + poll_wait(a->instance, &s->read_queue, a->event_list); + break; + + default: + /* nothing */ + break; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver driver = { + .owner = THIS_MODULE, + .name = "i2c saa6588 driver", + .id = -1, /* FIXME */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = saa6588_probe, + .detach_client = saa6588_detach, + .command = saa6588_command, +}; + +static struct i2c_client client_template = { + .name = "saa6588", + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, +}; + +static int __init saa6588_init_module(void) +{ + return i2c_add_driver(&driver); +} + +static void __exit saa6588_cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +module_init(saa6588_init_module); +module_exit(saa6588_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 22d055d8a695..e116bdbed310 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c @@ -470,7 +470,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_saa7110; diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c index fcd897382fcf..fe8a5e453969 100644 --- a/drivers/media/video/saa7111.c +++ b/drivers/media/video/saa7111.c @@ -42,7 +42,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/videodev.h> @@ -489,7 +488,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_saa7111; diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c index 2ba997f5ef1d..d9f50e2f7b92 100644 --- a/drivers/media/video/saa7114.c +++ b/drivers/media/video/saa7114.c @@ -45,7 +45,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/videodev.h> @@ -827,7 +826,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_saa7114; diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 79d05ea1b69b..382911c6ef22 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -598,7 +598,7 @@ static struct i2c_driver driver = { static struct i2c_client client_template = { - I2C_DEVNAME("saa6752hs"), + .name = "saa6752hs", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, }; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 88b71a20b602..acc7a4335e23 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-cards.c,v 1.80 2005/07/07 01:49:30 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * card-specific stuff. @@ -1373,7 +1372,7 @@ struct saa7134_board saa7134_boards[] = { .inputs = {{ .name = name_comp1, .vmux = 1, - .amux = LINE2, + .amux = LINE1, },{ .name = name_tv, .vmux = 3, @@ -1382,7 +1381,7 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_svideo, .vmux = 8, - .amux = LINE2, + .amux = LINE1, }}, .radio = { .name = name_radio, @@ -2001,6 +2000,115 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x000, }, }, + [SAA7134_BOARD_FLYTV_DIGIMATRIX] = { + .name = "FlyTV mini Asus Digimatrix", + .audio_clock = 0x00200000, + .tuner_type = TUNER_LG_NTSC_TALN_MINI, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, /* radio unconfirmed */ + .amux = LINE2, + }, + }, + [SAA7134_BOARD_KWORLD_TERMINATOR] = { + /* Kworld V-Stream Studio TV Terminator */ + /* "James Webb <jrwebb@qwest.net> */ + .name = "V-Stream Studio TV Terminator", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 1 << 21, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .gpio = 0x0000000, + .tv = 1, + },{ + .name = name_comp1, /* Composite input */ + .vmux = 3, + .amux = LINE2, + .gpio = 0x0000000, + },{ + .name = name_svideo, /* S-Video input */ + .vmux = 8, + .amux = LINE2, + .gpio = 0x0000000, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, + }, + [SAA7134_BOARD_YUAN_TUN900] = { + /* FIXME: + * S-Video and composite sources untested. + * Radio not working. + * Remote control not yet implemented. + * From : codemaster@webgeeks.be */ + .name = "Yuan TUN-900 (saa7135)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr= ADDR_UNSET, + .radio_addr= ADDR_UNSET, + .gpiomask = 0x00010003, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x01, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + .gpio = 0x02, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE2, + .gpio = 0x02, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x00010003, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x01, + }, + }, }; @@ -2272,12 +2380,6 @@ struct pci_device_id saa7134_pci_tbl[] = { .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0, - .driver_data = SAA7134_BOARD_SABRENT_SBTTVFM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0x9715, @@ -2346,6 +2448,18 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x4e42, .subdevice = 0x0502, .driver_data = SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1043, + .subdevice = 0x0210, /* mini pci NTSC version */ + .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1043, + .subdevice = 0x0210, /* mini pci PAL/SECAM version */ + .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, },{ /* --- boards without eeprom + subsystem ID --- */ diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 1dbe61755e9f..e5e36f3c6250 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-core.c,v 1.39 2005/07/05 17:37:35 nsh Exp $ * * device driver for philips saa7134 based TV cards * driver core diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 8be6a90358c8..639ae51a052d 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-dvb.c,v 1.23 2005/07/24 22:12:47 mkrufky Exp $ * * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * @@ -29,7 +28,6 @@ #include <linux/delay.h> #include <linux/kthread.h> #include <linux/suspend.h> -#include <linux/config.h> #include "saa7134-reg.h" diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index c85348d0239f..77b627eb6483 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-empress.c,v 1.11 2005/05/22 19:23:39 nsh Exp $ * * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 1203b93a572c..711aa8e85fac 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-i2c.c,v 1.22 2005/07/22 04:09:41 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * i2c interface support @@ -334,7 +333,7 @@ static int attach_inform(struct i2c_client *client) struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->name,client->addr,i2c_clientname(client)); + client->driver->name, client->addr, client->name); if (!client->driver->command) return 0; @@ -370,8 +369,6 @@ static int attach_inform(struct i2c_client *client) } static struct i2c_algorithm saa7134_algo = { - .name = "saa7134", - .id = I2C_ALGO_SAA7134, .master_xfer = saa7134_i2c_xfer, .algo_control = algo_control, .functionality = functionality, @@ -382,14 +379,14 @@ static struct i2c_adapter saa7134_adap_template = { #ifdef I2C_CLASS_TV_ANALOG .class = I2C_CLASS_TV_ANALOG, #endif - I2C_DEVNAME("saa7134"), - .id = I2C_ALGO_SAA7134, + .name = "saa7134", + .id = I2C_HW_SAA7134, .algo = &saa7134_algo, .client_register = attach_inform, }; static struct i2c_client saa7134_client_template = { - I2C_DEVNAME("saa7134 internal"), + .name = "saa7134 internal", }; /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 213740122fe6..1f456c4d76f2 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-input.c,v 1.21 2005/06/22 23:37:34 nsh Exp $ * * handle saa7134 IR remotes via linux kernel input layer. * @@ -565,6 +564,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) ir->dev.id.vendor = dev->pci->vendor; ir->dev.id.product = dev->pci->device; } + ir->dev.dev = &dev->pci->dev; /* all done */ dev->remote = ir; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index b5bede95dbf5..c20630c82f1c 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-oss.c,v 1.17 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * oss dsp interface diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h index 87734f22af7d..ae0c7a165390 100644 --- a/drivers/media/video/saa7134/saa7134-reg.h +++ b/drivers/media/video/saa7134/saa7134-reg.h @@ -1,5 +1,4 @@ /* - * $Id: saa7134-reg.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $ * * philips saa7134 registers */ diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 4dd9f1b23928..463885601ab4 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-ts.c,v 1.15 2005/06/14 22:48:18 hhackmann Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index eeafa5a71d2b..badf2f9e3072 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-tvaudio.c,v 1.30 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * tv audio decoder (fm stereo, nicam, ...) diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 29e51cad2aaf..f4aee0af80e1 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-vbi.c,v 1.7 2005/05/24 23:13:06 nsh Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index a4c2f751d097..35e5e85f669a 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1,5 +1,4 @@ /* - * $Id: saa7134-video.c,v 1.36 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -1368,29 +1367,7 @@ static int video_release(struct inode *inode, struct file *file) saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); - if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { - u8 data[2]; - int ret; - struct i2c_msg msg = {.addr=I2C_ADDR_TDA8290, .flags=0, .buf=data, .len = 2}; - data[0] = 0x21; - data[1] = 0xc0; - ret = i2c_transfer(&dev->i2c_adap, &msg, 1); - if (ret != 1) - printk(KERN_ERR "TDA8290 access failure\n"); - msg.addr = I2C_ADDR_TDA8275; - data[0] = 0x30; - data[1] = 0xd0; - ret = i2c_transfer(&dev->i2c_adap, &msg, 1); - if (ret != 1) - printk(KERN_ERR "TDA8275 access failure\n"); - msg.addr = I2C_ADDR_TDA8290; - data[0] = 0x21; - data[1] = 0x80; - i2c_transfer(&dev->i2c_adap, &msg, 1); - data[0] = 0x00; - data[1] = 0x02; - i2c_transfer(&dev->i2c_adap, &msg, 1); - } + saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); /* free stuff */ videobuf_mmap_free(&fh->cap); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 2af0cb2a731b..3ea09142ec9c 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -1,5 +1,4 @@ /* - * $Id: saa7134.h,v 1.49 2005/07/13 17:25:25 mchehab Exp $ * * v4l2 device driver for philips saa7134 based TV cards * @@ -185,6 +184,9 @@ struct saa7134_format { #define SAA7134_BOARD_PHILIPS_TOUGH 61 #define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62 #define SAA7134_BOARD_KWORLD_XPERT 63 +#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64 +#define SAA7134_BOARD_KWORLD_TERMINATOR 65 +#define SAA7134_BOARD_YUAN_TUN900 66 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c index 108e7a4a0273..132aa7943c16 100644 --- a/drivers/media/video/saa7185.c +++ b/drivers/media/video/saa7185.c @@ -39,7 +39,6 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> -#include <asm/segment.h> #include <linux/types.h> #include <linux/videodev.h> @@ -387,7 +386,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver i2c_driver_saa7185; diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c new file mode 100644 index 000000000000..454f5c1199b4 --- /dev/null +++ b/drivers/media/video/saa7191.c @@ -0,0 +1,512 @@ +/* + * saa7191.c - Philips SAA7191 video decoder driver + * + * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> + * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/sched.h> + +#include <linux/videodev.h> +#include <linux/video_decoder.h> +#include <linux/i2c.h> + +#include "saa7191.h" + +#define SAA7191_MODULE_VERSION "0.0.3" + +MODULE_DESCRIPTION("Philips SAA7191 video decoder driver"); +MODULE_VERSION(SAA7191_MODULE_VERSION); +MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); +MODULE_LICENSE("GPL"); + +#define VINO_ADAPTER (I2C_ALGO_SGI | I2C_HW_SGI_VINO) + +struct saa7191 { + struct i2c_client *client; + + /* the register values are stored here as the actual + * I2C-registers are write-only */ + unsigned char reg[25]; + + unsigned char norm; + unsigned char input; +}; + +static struct i2c_driver i2c_driver_saa7191; + +static const unsigned char initseq[] = { + 0, /* Subaddress */ + 0x50, /* SAA7191_REG_IDEL */ + 0x30, /* SAA7191_REG_HSYB */ + 0x00, /* SAA7191_REG_HSYS */ + 0xe8, /* SAA7191_REG_HCLB */ + 0xb6, /* SAA7191_REG_HCLS */ + 0xf4, /* SAA7191_REG_HPHI */ + 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */ + 0x00, /* SAA7191_REG_HUEC */ + 0xf8, /* SAA7191_REG_CKTQ */ + 0xf8, /* SAA7191_REG_CKTS */ + 0x90, /* SAA7191_REG_PLSE */ + 0x90, /* SAA7191_REG_SESE */ + 0x00, /* SAA7191_REG_GAIN */ + 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */ + 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */ + 0x99, /* SAA7191_REG_CTL3 - automatic field detection */ + 0x00, /* SAA7191_REG_CTL4 */ + 0x2c, /* SAA7191_REG_CHCV */ + 0x00, /* unused */ + 0x00, /* unused */ + 0x34, /* SAA7191_REG_HS6B */ + 0x0a, /* SAA7191_REG_HS6S */ + 0xf4, /* SAA7191_REG_HC6B */ + 0xce, /* SAA7191_REG_HC6S */ + 0xf4, /* SAA7191_REG_HP6I */ +}; + +/* SAA7191 register handling */ + +static unsigned char saa7191_read_reg(struct i2c_client *client, + unsigned char reg) +{ + return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg]; +} + +static int saa7191_read_status(struct i2c_client *client, + unsigned char *value) +{ + int ret; + + ret = i2c_master_recv(client, value, 1); + if (ret < 0) { + printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed"); + return ret; + } + + return 0; +} + + +static int saa7191_write_reg(struct i2c_client *client, unsigned char reg, + unsigned char value) +{ + + ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value; + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* the first byte of data must be the first subaddress number (register) */ +static int saa7191_write_block(struct i2c_client *client, + unsigned char length, unsigned char *data) +{ + int i; + int ret; + + struct saa7191 *decoder = (struct saa7191 *)i2c_get_clientdata(client); + for (i = 0; i < (length - 1); i++) { + decoder->reg[data[0] + i] = data[i + 1]; + } + + ret = i2c_master_send(client, data, length); + if (ret < 0) { + printk(KERN_ERR "SAA7191: saa7191_write_block(): " + "write failed"); + return ret; + } + + return 0; +} + +/* Helper functions */ + +static int saa7191_set_input(struct i2c_client *client, int input) +{ + unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA); + unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK); + int err; + + switch (input) { + case SAA7191_INPUT_COMPOSITE: /* Set Composite input */ + iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1 + | SAA7191_IOCK_GPSW2); + /* Chrominance trap active */ + luma &= ~SAA7191_LUMA_BYPS; + break; + case SAA7191_INPUT_SVIDEO: /* Set S-Video input */ + iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2; + /* Chrominance trap bypassed */ + luma |= SAA7191_LUMA_BYPS; + break; + default: + return -EINVAL; + } + + err = saa7191_write_reg(client, SAA7191_REG_LUMA, luma); + if (err) + return -EIO; + err = saa7191_write_reg(client, SAA7191_REG_IOCK, iock); + if (err) + return -EIO; + + return 0; +} + +static int saa7191_set_norm(struct i2c_client *client, int norm) +{ + struct saa7191 *decoder = i2c_get_clientdata(client); + unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); + unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); + unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV); + int err; + + switch(norm) { + case SAA7191_NORM_AUTO: { + unsigned char status; + + // does status depend on current norm ? + if (saa7191_read_status(client, &status)) + return -EIO; + + stdc &= ~SAA7191_STDC_SECS; + ctl3 &= ~SAA7191_CTL3_FSEL; + ctl3 |= SAA7191_CTL3_AUFD; + chcv = (status & SAA7191_STATUS_FIDT) + ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL; + break; + } + case SAA7191_NORM_PAL: + stdc &= ~SAA7191_STDC_SECS; + ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); + chcv = SAA7191_CHCV_PAL; + break; + case SAA7191_NORM_NTSC: + stdc &= ~SAA7191_STDC_SECS; + ctl3 &= ~SAA7191_CTL3_AUFD; + ctl3 |= SAA7191_CTL3_FSEL; + chcv = SAA7191_CHCV_NTSC; + break; + case SAA7191_NORM_SECAM: + stdc |= SAA7191_STDC_SECS; + ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); + chcv = SAA7191_CHCV_PAL; + break; + default: + return -EINVAL; + } + + err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); + if (err) + return -EIO; + err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); + if (err) + return -EIO; + err = saa7191_write_reg(client, SAA7191_REG_CHCV, chcv); + if (err) + return -EIO; + + decoder->norm = norm; + + return 0; +} + +static int saa7191_get_controls(struct i2c_client *client, + struct saa7191_control *ctrl) +{ + unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC); + unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); + + if (hue < 0x80) { + hue += 0x80; + } else { + hue -= 0x80; + } + ctrl->hue = hue; + + ctrl->vtrc = (stdc & SAA7191_STDC_VTRC) + ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; + + return 0; +} + +static int saa7191_set_controls(struct i2c_client *client, + struct saa7191_control *ctrl) +{ + int err; + + if (ctrl->hue >= 0) { + unsigned char hue = ctrl->hue & 0xff; + if (hue < 0x80) { + hue += 0x80; + } else { + hue -= 0x80; + } + err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue); + if (err) + return -EIO; + } + if (ctrl->vtrc >= 0) { + unsigned char stdc = + saa7191_read_reg(client, SAA7191_REG_STDC); + + if (ctrl->vtrc) { + stdc |= SAA7191_STDC_VTRC; + } else { + stdc &= ~SAA7191_STDC_VTRC; + } + + err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); + if (err) + return -EIO; + } + + return 0; +} + +/* I2C-interface */ + +static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) +{ + int err = 0; + struct saa7191 *decoder; + struct i2c_client *client; + + printk(KERN_INFO "Philips SAA7191 driver version %s\n", + SAA7191_MODULE_VERSION); + + client = kmalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + decoder = kmalloc(sizeof(*decoder), GFP_KERNEL); + if (!decoder) { + err = -ENOMEM; + goto out_free_client; + } + + memset(client, 0, sizeof(struct i2c_client)); + memset(decoder, 0, sizeof(struct saa7191)); + + client->addr = addr; + client->adapter = adap; + client->driver = &i2c_driver_saa7191; + client->flags = 0; + strcpy(client->name, "saa7191 client"); + i2c_set_clientdata(client, decoder); + + decoder->client = client; + + err = i2c_attach_client(client); + if (err) + goto out_free_decoder; + + decoder->input = SAA7191_INPUT_COMPOSITE; + decoder->norm = SAA7191_NORM_AUTO; + + err = saa7191_write_block(client, sizeof(initseq), + (unsigned char *)initseq); + if (err) { + printk(KERN_ERR "SAA7191 initialization failed\n"); + goto out_detach_client; + } + + printk(KERN_INFO "SAA7191 initialized\n"); + + return 0; + +out_detach_client: + i2c_detach_client(client); +out_free_decoder: + kfree(decoder); +out_free_client: + kfree(client); + return err; +} + +static int saa7191_probe(struct i2c_adapter *adap) +{ + /* Always connected to VINO */ + if (adap->id == VINO_ADAPTER) + return saa7191_attach(adap, SAA7191_ADDR, 0); + /* Feel free to add probe here :-) */ + return -ENODEV; +} + +static int saa7191_detach(struct i2c_client *client) +{ + struct saa7191 *decoder = i2c_get_clientdata(client); + + i2c_detach_client(client); + kfree(decoder); + kfree(client); + return 0; +} + +static int saa7191_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct saa7191 *decoder = i2c_get_clientdata(client); + + switch (cmd) { + case DECODER_GET_CAPABILITIES: { + struct video_decoder_capability *cap = arg; + + cap->flags = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC | + VIDEO_DECODER_SECAM | VIDEO_DECODER_AUTO; + cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1; + cap->outputs = 1; + break; + } + case DECODER_GET_STATUS: { + int *iarg = arg; + unsigned char status; + int res = 0; + + if (saa7191_read_status(client, &status)) { + return -EIO; + } + if ((status & SAA7191_STATUS_HLCK) == 0) + res |= DECODER_STATUS_GOOD; + if (status & SAA7191_STATUS_CODE) + res |= DECODER_STATUS_COLOR; + switch (decoder->norm) { + case SAA7191_NORM_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case SAA7191_NORM_PAL: + res |= DECODER_STATUS_PAL; + break; + case SAA7191_NORM_SECAM: + res |= DECODER_STATUS_SECAM; + break; + case SAA7191_NORM_AUTO: + default: + if (status & SAA7191_STATUS_FIDT) + res |= DECODER_STATUS_NTSC; + else + res |= DECODER_STATUS_PAL; + break; + } + *iarg = res; + break; + } + case DECODER_SET_NORM: { + int *iarg = arg; + + switch (*iarg) { + case VIDEO_MODE_AUTO: + return saa7191_set_norm(client, SAA7191_NORM_AUTO); + case VIDEO_MODE_PAL: + return saa7191_set_norm(client, SAA7191_NORM_PAL); + case VIDEO_MODE_NTSC: + return saa7191_set_norm(client, SAA7191_NORM_NTSC); + case VIDEO_MODE_SECAM: + return saa7191_set_norm(client, SAA7191_NORM_SECAM); + default: + return -EINVAL; + } + break; + } + case DECODER_SET_INPUT: { + int *iarg = arg; + + switch (client->adapter->id) { + case VINO_ADAPTER: + return saa7191_set_input(client, *iarg); + default: + if (*iarg != 0) + return -EINVAL; + } + break; + } + case DECODER_SET_OUTPUT: { + int *iarg = arg; + + /* not much choice of outputs */ + if (*iarg != 0) + return -EINVAL; + break; + } + case DECODER_ENABLE_OUTPUT: { + /* Always enabled */ + break; + } + case DECODER_SET_PICTURE: { + struct video_picture *pic = arg; + unsigned val; + int err; + + val = (pic->hue >> 8) - 0x80; + err = saa7191_write_reg(client, SAA7191_REG_HUEC, val); + if (err) + return -EIO; + break; + } + case DECODER_SAA7191_GET_STATUS: { + struct saa7191_status *status = arg; + unsigned char status_reg; + + if (saa7191_read_status(client, &status_reg)) + return -EIO; + status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0) + ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; + status->ntsc = (status_reg & SAA7191_STATUS_FIDT) + ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; + status->color = (status_reg & SAA7191_STATUS_CODE) + ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; + + status->input = decoder->input; + status->norm = decoder->norm; + } + case DECODER_SAA7191_SET_NORM: { + int *norm = arg; + return saa7191_set_norm(client, *norm); + } + case DECODER_SAA7191_GET_CONTROLS: { + struct saa7191_control *ctrl = arg; + return saa7191_get_controls(client, ctrl); + } + case DECODER_SAA7191_SET_CONTROLS: { + struct saa7191_control *ctrl = arg; + return saa7191_set_controls(client, ctrl); + } + default: + return -EINVAL; + } + + return 0; +} + +static struct i2c_driver i2c_driver_saa7191 = { + .owner = THIS_MODULE, + .name = "saa7191", + .id = I2C_DRIVERID_SAA7191, + .flags = I2C_DF_NOTIFY, + .attach_adapter = saa7191_probe, + .detach_client = saa7191_detach, + .command = saa7191_command +}; + +static int saa7191_init(void) +{ + return i2c_add_driver(&i2c_driver_saa7191); +} + +static void saa7191_exit(void) +{ + i2c_del_driver(&i2c_driver_saa7191); +} + +module_init(saa7191_init); +module_exit(saa7191_exit); diff --git a/drivers/media/video/saa7191.h b/drivers/media/video/saa7191.h new file mode 100644 index 000000000000..272045031435 --- /dev/null +++ b/drivers/media/video/saa7191.h @@ -0,0 +1,139 @@ +/* + * saa7191.h - Philips SAA7191 video decoder driver + * + * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> + * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _SAA7191_H_ +#define _SAA7191_H_ + +/* Philips SAA7191 DMSD I2C bus address */ +#define SAA7191_ADDR 0x8a + +/* Register subaddresses. */ +#define SAA7191_REG_IDEL 0x00 +#define SAA7191_REG_HSYB 0x01 +#define SAA7191_REG_HSYS 0x02 +#define SAA7191_REG_HCLB 0x03 +#define SAA7191_REG_HCLS 0x04 +#define SAA7191_REG_HPHI 0x05 +#define SAA7191_REG_LUMA 0x06 +#define SAA7191_REG_HUEC 0x07 +#define SAA7191_REG_CKTQ 0x08 +#define SAA7191_REG_CKTS 0x09 +#define SAA7191_REG_PLSE 0x0a +#define SAA7191_REG_SESE 0x0b +#define SAA7191_REG_GAIN 0x0c +#define SAA7191_REG_STDC 0x0d +#define SAA7191_REG_IOCK 0x0e +#define SAA7191_REG_CTL3 0x0f +#define SAA7191_REG_CTL4 0x10 +#define SAA7191_REG_CHCV 0x11 +#define SAA7191_REG_HS6B 0x14 +#define SAA7191_REG_HS6S 0x15 +#define SAA7191_REG_HC6B 0x16 +#define SAA7191_REG_HC6S 0x17 +#define SAA7191_REG_HP6I 0x18 +#define SAA7191_REG_STATUS 0xff /* not really a subaddress */ + +/* Status Register definitions */ +#define SAA7191_STATUS_CODE 0x01 /* color detected flag */ +#define SAA7191_STATUS_FIDT 0x20 /* format type NTSC/PAL */ +#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked/locked */ +#define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */ + +/* Luminance Control Register definitions */ +#define SAA7191_LUMA_BYPS 0x80 + +/* Chroma Gain Control Settings Register definitions */ +/* 0=automatic colour-killer enabled, 1=forced colour on */ +#define SAA7191_GAIN_COLO 0x80 + +/* Standard/Mode Control Register definitions */ +/* tv/vtr mode bit: 0=TV mode (slow time constant), + * 1=VTR mode (fast time constant) */ +#define SAA7191_STDC_VTRC 0x80 +/* SECAM mode bit: 0=other standards, 1=SECAM */ +#define SAA7191_STDC_SECS 0x01 +/* the bit fields above must be or'd with this value */ +#define SAA7191_STDC_VALUE 0x0c + +/* I/O and Clock Control Register definitions */ +/* horizontal clock PLL: 0=PLL closed, + * 1=PLL circuit open and horizontal freq fixed */ +#define SAA7191_IOCK_HPLL 0x80 +/* S-VHS bit (chrominance from CVBS or from chrominance input): + * 0=controlled by BYPS-bit, 1=from chrominance input */ +#define SAA7191_IOCK_CHRS 0x04 +/* general purpose switch 2 + * VINO-specific: 0=used with CVBS, 1=used with S-Video */ +#define SAA7191_IOCK_GPSW2 0x02 +/* general purpose switch 1 */ +/* VINO-specific: 0=always, 1=not used!*/ +#define SAA7191_IOCK_GPSW1 0x01 + +/* Miscellaneous Control #1 Register definitions */ +/* automatic field detection (50/60Hz standard) */ +#define SAA7191_CTL3_AUFD 0x80 +/* field select: (if AUFD=0) + * 0=50Hz (625 lines), 1=60Hz (525 lines) */ +#define SAA7191_CTL3_FSEL 0x40 +/* the bit fields above must be or'd with this value */ +#define SAA7191_CTL3_VALUE 0x19 + +/* Chrominance Gain Control Register definitions + * (nominal value for UV CCIR level) */ +#define SAA7191_CHCV_NTSC 0x2c +#define SAA7191_CHCV_PAL 0x59 + +/* Driver interface definitions */ +#define SAA7191_INPUT_COMPOSITE 0 +#define SAA7191_INPUT_SVIDEO 1 + +#define SAA7191_NORM_AUTO 0 +#define SAA7191_NORM_PAL 1 +#define SAA7191_NORM_NTSC 2 +#define SAA7191_NORM_SECAM 3 + +#define SAA7191_VALUE_ENABLED 1 +#define SAA7191_VALUE_DISABLED 0 +#define SAA7191_VALUE_UNCHANGED -1 + +struct saa7191_status { + /* 0=no signal, 1=signal active*/ + int signal; + /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */ + int ntsc; + /* 0=no color detected, 1=color detected */ + int color; + + /* current SAA7191_INPUT_ */ + int input; + /* current SAA7191_NORM_ */ + int norm; +}; + +#define SAA7191_HUE_MIN 0x00 +#define SAA7191_HUE_MAX 0xff +#define SAA7191_HUE_DEFAULT 0x80 + +#define SAA7191_VTRC_MIN 0x00 +#define SAA7191_VTRC_MAX 0x01 +#define SAA7191_VTRC_DEFAULT 0x00 + +struct saa7191_control { + int hue; + int vtrc; +}; + +#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status) +#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int) +#define DECODER_SAA7191_GET_CONTROLS _IOR('d', 197, struct saa7191_control) +#define DECODER_SAA7191_SET_CONTROLS _IOW('d', 198, struct saa7191_control) + +#endif diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 7cb1fb3e66f9..255b6088ebf9 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -328,7 +328,7 @@ static int tda7432_probe(struct i2c_adapter *adap) if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda7432_attach); #else - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + if (adap->id == I2C_HW_B_BT848) return i2c_probe(adap, &addr_data, tda7432_attach); #endif return 0; @@ -513,7 +513,7 @@ static struct i2c_driver driver = { static struct i2c_client client_template = { - I2C_DEVNAME("tda7432"), + .name = "tda7432", .driver = &driver, }; diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index a8b6a8df5109..c65f0c7680a2 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -1,5 +1,4 @@ /* - * $Id: tda8290.c,v 1.15 2005/07/08 20:21:33 mchehab Exp $ * * i2c tv tuner chip device driver * controls the philips tda8290+75 tuner chip combo. @@ -9,6 +8,9 @@ #include <linux/delay.h> #include <media/tuner.h> +#define I2C_ADDR_TDA8290 0x4b +#define I2C_ADDR_TDA8275 0x61 + /* ---------------------------------------------------------------------- */ struct freq_entry { @@ -75,10 +77,12 @@ static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00, static unsigned char i2c_set_VS[2] = { 0x30, 0x6F }; static unsigned char i2c_set_GP01_CF[2] = { 0x20, 0x0B }; static unsigned char i2c_tda8290_reset[2] = { 0x00, 0x00 }; +static unsigned char i2c_tda8290_standby[2] = { 0x00, 0x02 }; static unsigned char i2c_gainset_off[2] = { 0x28, 0x14 }; static unsigned char i2c_gainset_on[2] = { 0x28, 0x54 }; static unsigned char i2c_agc3_00[2] = { 0x80, 0x00 }; static unsigned char i2c_agc2_BF[2] = { 0x60, 0xBF }; +static unsigned char i2c_cb1_D0[2] = { 0x30, 0xD0 }; static unsigned char i2c_cb1_D2[2] = { 0x30, 0xD2 }; static unsigned char i2c_cb1_56[2] = { 0x30, 0x56 }; static unsigned char i2c_cb1_52[2] = { 0x30, 0x52 }; @@ -117,6 +121,13 @@ static struct i2c_msg i2c_msg_epilog[] = { { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on }, }; +static struct i2c_msg i2c_msg_standby[] = { + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge }, + { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D0), i2c_cb1_D0 }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge }, + { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_standby), i2c_tda8290_standby }, +}; + static int tda8290_tune(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -205,6 +216,11 @@ static int has_signal(struct i2c_client *c) return (afc & 0x80)? 65535:0; } +static void standby(struct i2c_client *c) +{ + i2c_transfer(c->adapter, i2c_msg_standby, ARRAY_SIZE(i2c_msg_standby)); +} + int tda8290_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); @@ -214,6 +230,7 @@ int tda8290_init(struct i2c_client *c) t->tv_freq = set_tv_freq; t->radio_freq = set_radio_freq; t->has_signal = has_signal; + t->standby = standby; i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge)); i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init)); diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index c29bdfc3244e..1794686612c6 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -205,7 +205,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind) static int attach(struct i2c_adapter *adapter) { /* let's see whether this is a know adapter we can attach to */ - if (adapter->id != I2C_ALGO_SAA7146) { + if (adapter->id != I2C_HW_SAA7146) { dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); return -ENODEV; } @@ -231,7 +231,7 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - I2C_DEVNAME("tda9840"), + .name = "tda9840", .driver = &driver, }; diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 566e1a5ca135..7e3dcdb262b0 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -262,7 +262,7 @@ static int tda9875_probe(struct i2c_adapter *adap) if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9875_attach); #else - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + if (adap->id == I2C_HW_B_BT848) return i2c_probe(adap, &addr_data, tda9875_attach); #endif return 0; @@ -384,7 +384,7 @@ static struct i2c_driver driver = { static struct i2c_client client_template = { - I2C_DEVNAME("tda9875"), + .name = "tda9875", .driver = &driver, }; diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 108c3ad7d622..0456dda2624d 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -23,6 +23,7 @@ TDA9887 (world), TDA9885 (USA) Note: OP2 of tda988x must be set to 1, else MT2032 is disabled! - KNC One TV-Station RDS (saa7134) + - Hauppauge PVR-150/500 (possibly more) */ @@ -49,7 +50,7 @@ MODULE_LICENSE("GPL"); struct tda9887 { struct i2c_client client; v4l2_std_id std; - unsigned int radio; + enum tuner_mode mode; unsigned int config; unsigned int pinnacle_id; unsigned int using_v4l2; @@ -196,7 +197,7 @@ static struct tvnorm tvnorms[] = { .b = ( cNegativeFmTV | cQSS ), .c = ( cDeemphasisON | - cDeemphasis50 ), + cDeemphasis75 ), .e = ( cGating_36 | cAudioIF_4_5 | cVideoIF_45_75 ), @@ -364,7 +365,7 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) struct tvnorm *norm = NULL; int i; - if (t->radio) { + if (t->mode == T_RADIO) { if (t->radio_mode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else @@ -378,7 +379,7 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) } } if (NULL == norm) { - dprintk(PREFIX "Oops: no tvnorm entry found\n"); + dprintk(PREFIX "Unsupported tvnorm entry - audio muted\n"); return -1; } @@ -519,6 +520,12 @@ static int tda9887_fixup_std(struct tda9887 *t) dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; + case '-': + /* default parameter, do nothing */ + break; + default: + printk(PREFIX "pal= argument not recognised\n"); + break; } } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { @@ -535,6 +542,12 @@ static int tda9887_fixup_std(struct tda9887 *t) dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n"); t->std = V4L2_STD_SECAM_L; break; + case '-': + /* default parameter, do nothing */ + break; + default: + printk(PREFIX "secam= argument not recognised\n"); + break; } } return 0; @@ -569,6 +582,10 @@ static int tda9887_configure(struct tda9887 *t) tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); + if (t->mode == T_STANDBY) { + buf[1] |= cForcedMuteAudioON; + } + dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", buf[1],buf[2],buf[3]); @@ -618,9 +635,9 @@ static int tda9887_probe(struct i2c_adapter *adap) return i2c_probe(adap, &addr_data, tda9887_attach); #else switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - case I2C_ALGO_SAA7134: + case I2C_HW_B_BT848: + case I2C_HW_B_RIVA: + case I2C_HW_SAA7134: return i2c_probe(adap, &addr_data, tda9887_attach); break; } @@ -653,10 +670,17 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) /* --- configuration --- */ case AUDC_SET_RADIO: - t->radio = 1; + { + t->mode = T_RADIO; tda9887_configure(t); break; - + } + case TUNER_SET_STANDBY: + { + t->mode = T_STANDBY; + tda9887_configure(t); + break; + } case AUDC_CONFIG_PINNACLE: { int *i = arg; @@ -689,7 +713,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) struct video_channel *vc = arg; CHECK_V4L2; - t->radio = 0; + t->mode = T_ANALOG_TV; if (vc->norm < ARRAY_SIZE(map)) t->std = map[vc->norm]; tda9887_fixup_std(t); @@ -701,7 +725,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) v4l2_std_id *id = arg; SWITCH_V4L2; - t->radio = 0; + t->mode = T_ANALOG_TV; t->std = *id; tda9887_fixup_std(t); tda9887_configure(t); @@ -713,14 +737,14 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) SWITCH_V4L2; if (V4L2_TUNER_ANALOG_TV == f->type) { - if (t->radio == 0) + if (t->mode == T_ANALOG_TV) return 0; - t->radio = 0; + t->mode = T_ANALOG_TV; } if (V4L2_TUNER_RADIO == f->type) { - if (t->radio == 1) + if (t->mode == T_RADIO) return 0; - t->radio = 1; + t->mode = T_RADIO; } tda9887_configure(t); break; @@ -735,7 +759,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) }; struct v4l2_tuner* tuner = arg; - if (t->radio) { + if (t->mode == T_RADIO) { __u8 reg = 0; tuner->afc=0; if (1 == i2c_master_recv(&t->client,®,1)) @@ -747,7 +771,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_tuner* tuner = arg; - if (t->radio) { + if (t->mode == T_RADIO) { t->radio_mode = tuner->audmode; tda9887_configure (t); } @@ -760,7 +784,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int tda9887_suspend(struct device * dev, u32 state, u32 level) +static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level) { dprintk("tda9887: suspend\n"); return 0; @@ -793,7 +817,7 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - I2C_DEVNAME("tda9887"), + .name = "tda9887", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, }; diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index cebcc1fa68d1..38bf50943798 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -2,7 +2,6 @@ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview * I2C address is allways 0xC0. * - * $Id: tea5767.c,v 1.27 2005/07/31 12:10:56 mchehab Exp $ * * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) * This code is placed under the terms of the GNU General Public License @@ -205,11 +204,6 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq) TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; buffer[4] = 0; - if (t->mode == T_STANDBY) { - tuner_dbg("TEA5767 set to standby mode\n"); - buffer[3] |= TEA5767_STDBY; - } - if (t->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); buffer[2] |= TEA5767_MONO; @@ -290,13 +284,31 @@ static int tea5767_stereo(struct i2c_client *c) return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } +static void tea5767_standby(struct i2c_client *c) +{ + unsigned char buffer[5]; + struct tuner *t = i2c_get_clientdata(c); + unsigned div, rc; + + div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; + buffer[2] = TEA5767_PORT1_HIGH; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | + TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; + buffer[4] = 0; + + if (5 != (rc = i2c_master_send(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); +} + int tea5767_autodetection(struct i2c_client *c) { unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; struct tuner *t = i2c_get_clientdata(c); - if (7 != (rc = i2c_master_recv(c, buffer, 7))) { + if ((rc = i2c_master_recv(c, buffer, 7))< 5) { tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc); return EINVAL; } @@ -313,15 +325,10 @@ int tea5767_autodetection(struct i2c_client *c) * bit 0 : internally set to 0 * Byte 5: bit 7:0 : == 0 */ - if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { + if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); return EINVAL; } - /* It seems that tea5767 returns 0xff after the 5th byte */ - if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) { - tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n"); - return EINVAL; - } /* It seems that tea5767 returns 0xff after the 5th byte */ if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) { @@ -337,14 +344,14 @@ int tea5767_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); - tuner_info("type set to %d (%s)\n", t->type, - "Philips TEA5767HN FM Radio"); + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); strlcpy(c->name, "tea5767", sizeof(c->name)); t->tv_freq = set_tv_freq; t->radio_freq = set_radio_freq; t->has_signal = tea5767_signal; t->is_stereo = tea5767_stereo; + t->standby = tea5767_standby; return (0); } diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index b44db8a7b94d..ee3688348b66 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -86,7 +86,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind) static int attach(struct i2c_adapter *adapter) { /* let's see whether this is a know adapter we can attach to */ - if (adapter->id != I2C_ALGO_SAA7146) { + if (adapter->id != I2C_HW_SAA7146) { dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); return -ENODEV; } @@ -200,7 +200,7 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - I2C_DEVNAME("tea6415c"), + .name = "tea6415c", .driver = &driver, }; diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index 48d4db7d507b..17975c19da5e 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -135,7 +135,7 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind) static int attach(struct i2c_adapter *adapter) { /* let's see whether this is a know adapter we can attach to */ - if (adapter->id != I2C_ALGO_SAA7146) { + if (adapter->id != I2C_HW_SAA7146) { dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); return -ENODEV; } @@ -177,7 +177,7 @@ static struct i2c_driver driver = { }; static struct i2c_client client_template = { - I2C_DEVNAME("tea6420"), + .name = "tea6420", .driver = &driver, }; diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c index 7d825e510ffd..79203595b9c1 100644 --- a/drivers/media/video/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c @@ -41,7 +41,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; /* ---------------------------------------------------------------------- */ @@ -166,7 +165,7 @@ static int tuner_probe(struct i2c_adapter *adap) { this_adap = 0; - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_LP)) + if (adap->id == I2C_HW_B_LP) return i2c_probe(adap, &addr_data, tuner_attach); return 0; } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f0a579827a24..05572020af4d 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1,5 +1,4 @@ /* - * $Id: tuner-core.c,v 1.63 2005/07/28 18:19:55 mchehab Exp $ * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on @@ -182,6 +181,14 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c, buffer, 4); default_tuner_init(c); break; + case TUNER_LG_TDVS_H062F: + /* Set the Auxiliary Byte. */ + buffer[2] &= ~0x20; + buffer[2] |= 0x18; + buffer[3] = 0x20; + i2c_master_send(c, buffer, 4); + default_tuner_init(c); + break; default: default_tuner_init(c); break; @@ -208,31 +215,31 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) { struct tuner *t = i2c_get_clientdata(c); - if (tun_setup->addr == ADDR_UNSET) { - if (t->mode_mask & tun_setup->mode_mask) + if ((tun_setup->addr == ADDR_UNSET && + (t->mode_mask & tun_setup->mode_mask)) || + tun_setup->addr == c->addr) { set_type(c, tun_setup->type, tun_setup->mode_mask); - } else if (tun_setup->addr == c->addr) { - set_type(c, tun_setup->type, tun_setup->mode_mask); } } static inline int check_mode(struct tuner *t, char *cmd) { - if (1 << t->mode & t->mode_mask) { - switch (t->mode) { - case V4L2_TUNER_RADIO: - tuner_dbg("Cmd %s accepted for radio\n", cmd); - break; - case V4L2_TUNER_ANALOG_TV: - tuner_dbg("Cmd %s accepted for analog TV\n", cmd); - break; - case V4L2_TUNER_DIGITAL_TV: - tuner_dbg("Cmd %s accepted for digital TV\n", cmd); - break; - } - return 0; + if ((1 << t->mode & t->mode_mask) == 0) { + return EINVAL; + } + + switch (t->mode) { + case V4L2_TUNER_RADIO: + tuner_dbg("Cmd %s accepted for radio\n", cmd); + break; + case V4L2_TUNER_ANALOG_TV: + tuner_dbg("Cmd %s accepted for analog TV\n", cmd); + break; + case V4L2_TUNER_DIGITAL_TV: + tuner_dbg("Cmd %s accepted for digital TV\n", cmd); + break; } - return EINVAL; + return 0; } static char pal[] = "-"; @@ -274,6 +281,12 @@ static int tuner_fixup_std(struct tuner *t) tuner_dbg ("insmod fixup: PAL => PAL-N\n"); t->std = V4L2_STD_PAL_N; break; + case '-': + /* default parameter, do nothing */ + break; + default: + tuner_warn ("pal= argument not recognised\n"); + break; } } if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { @@ -290,6 +303,12 @@ static int tuner_fixup_std(struct tuner *t) tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); t->std = V4L2_STD_SECAM_L; break; + case '-': + /* default parameter, do nothing */ + break; + default: + tuner_warn ("secam= argument not recognised\n"); + break; } } @@ -406,20 +425,18 @@ static int tuner_detach(struct i2c_client *client) static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { - if (mode != t->mode) { - - t->mode = mode; - if (check_mode(t, cmd) == EINVAL) { - t->mode = T_STANDBY; - if (V4L2_TUNER_RADIO == mode) { - set_tv_freq(client, 400 * 16); - } else { - set_radio_freq(client, 87.5 * 16000); - } - return EINVAL; - } - } - return 0; + if (mode == t->mode) + return 0; + + t->mode = mode; + + if (check_mode(t, cmd) == EINVAL) { + t->mode = T_STANDBY; + if (t->standby) + t->standby (client); + return EINVAL; + } + return 0; } #define switch_v4l2() if (!t->using_v4l2) \ @@ -453,6 +470,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) case AUDC_SET_RADIO: set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO"); break; + case TUNER_SET_STANDBY: + { + if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) + return 0; + if (t->standby) + t->standby (client); + break; + } case AUDC_CONFIG_PINNACLE: if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL) return 0; @@ -672,7 +697,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int tuner_suspend(struct device *dev, u32 state, u32 level) +static int tuner_suspend(struct device *dev, pm_message_t state, u32 level) { struct i2c_client *c = container_of (dev, struct i2c_client, dev); struct tuner *t = i2c_get_clientdata (c); @@ -709,7 +734,7 @@ static struct i2c_driver driver = { }, }; static struct i2c_client client_template = { - I2C_DEVNAME("(tuner unset)"), + .name = "(tuner unset)", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, }; diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index de0c93aeb75d..8edd73abe1d8 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,5 +1,4 @@ /* - * $Id: tuner-simple.c,v 1.43 2005/07/28 18:41:21 mchehab Exp $ * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. @@ -102,6 +101,7 @@ struct tunertype * "no float in kernel" rule. */ static struct tunertype tuners[] = { + /* 0-9 */ { "Temic PAL (4002 FH5)", TEMIC, PAL, 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, @@ -110,7 +110,6 @@ static struct tunertype tuners[] = { 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, - { "NoTuner", NoTuner, NOTUNER, 0,0,0x00,0x00,0x00,0x00,0x00}, { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, @@ -119,34 +118,34 @@ static struct tunertype tuners[] = { 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I, 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, - { "Temic NTSC (4036 FY5)", TEMIC, NTSC, 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, { "Alps HSBH1", TEMIC, NTSC, 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, - { "Alps TSBE1",TEMIC,PAL, + + /* 10-19 */ + { "Alps TSBE1", TEMIC, PAL, 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, - { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, { "Temic PAL_BG (4006FH5)", TEMIC, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Alps TSCH6",Alps,NTSC, + { "Alps TSCH6", Alps, NTSC, 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732}, - - { "Temic PAL_DK (4016 FY5)",TEMIC,PAL, + { "Temic PAL_DK (4016 FY5)", TEMIC, PAL, 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC_M (MK2)",Philips,NTSC, + { "Philips NTSC_M (MK2)", Philips, NTSC, 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I, 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic PAL* auto (4006 FN5)", TEMIC, PAL, 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, + /* 20-29 */ { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic NTSC (4039 FR5)", TEMIC, NTSC, @@ -155,7 +154,6 @@ static struct tunertype tuners[] = { 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, - { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I, @@ -164,25 +162,24 @@ static struct tunertype tuners[] = { 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC, 16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732}, - { "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + + /* 30-39 */ { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 }, - - { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ + { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, - { "MT20xx universal", Microtune,PAL|NTSC, + { "MT20xx universal", Microtune, PAL|NTSC, /* see mt20xx.c for details */ }, { "Temic PAL_BG (4106 FH5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL, 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623}, - { "Temic NTSC (4136 FY5)", TEMIC, NTSC, 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, { "LG PAL (newer TAPC series)", LGINNOTEK, PAL, @@ -192,42 +189,41 @@ static struct tunertype tuners[] = { { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, + /* 40-49 */ { "HITACHI V7-J180AT", HITACHI, NTSC, 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,940 }, { "Philips PAL_MK (FI1216 MK)", Philips, PAL, 16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623}, - { "Philips 1236D ATSC/NTSC daul in",Philips,ATSC, + { "Philips 1236D ATSC/NTSC daul in", Philips, ATSC, 16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732}, - { "Microtune 4049 FM5",Microtune,PAL, + { "Microtune 4049 FM5", Microtune, PAL, 16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623}, { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC, 16*160.00,16*454.00,0x01,0x02,0x08,0xce,940}, { "LG NTSC (TAPE series)", LGINNOTEK, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, - { "Tenna TNF 8831 BGFF)", Philips, PAL, 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC, 16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732}, + + /* 50-59 */ { "TCL 2002N", TCL, NTSC, 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732}, { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, - { "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, { "Philips FQ1286", Philips, NTSC, - 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, // UHF band untested - { "tda8290+75", Philips,PAL|NTSC, + 16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */ + { "tda8290+75", Philips, PAL|NTSC, /* see tda8290.c for details */ }, { "LG PAL (TAPE series)", LGINNOTEK, PAL, 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623}, - { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, { "Philips FQ1236A MK4", Philips, NTSC, @@ -237,6 +233,7 @@ static struct tunertype tuners[] = { { "Ymec TVision TVF-5533MF", Philips, NTSC, 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, + /* 60-66 */ { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, @@ -245,12 +242,12 @@ static struct tunertype tuners[] = { /* see tea5767.c for details */}, { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, - - { "LG TDVS-H062F/TUA6034", LGINNOTEK, NTSC, + { "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC, 16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732}, - { "Ymec TVF66T5-B/DFF", Philips, PAL, 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623}, + { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC, + 16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); @@ -471,6 +468,10 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) case TUNER_LG_PAL_FM: buffer[3] = 0xa5; break; + case TUNER_MICROTUNE_4049FM5: + div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ + buffer[3] = 0xa4; + break; default: buffer[3] = 0xa4; break; @@ -497,6 +498,7 @@ int default_tuner_init(struct i2c_client *c) t->radio_freq = default_set_radio_freq; t->has_signal = tuner_signal; t->is_stereo = tuner_stereo; + t->standby = NULL; return 0; } diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index f42a1efa8fcf..1c31ef52f863 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -46,7 +46,17 @@ MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr"); MODULE_LICENSE("GPL"); #define UNSET (-1U) -#define dprintk if (debug) printk + +#define tvaudio_info(fmt, arg...) do {\ + printk(KERN_INFO "tvaudio %d-%04x: " fmt, \ + chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) +#define tvaudio_warn(fmt, arg...) do {\ + printk(KERN_WARNING "tvaudio %d-%04x: " fmt, \ + chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) +#define tvaudio_dbg(fmt, arg...) do {\ + if (debug) \ + printk(KERN_INFO "tvaudio %d-%04x: " fmt, \ + chip->c.adapter->nr, chip->c.addr , ##arg); } while (0) /* ---------------------------------------------------------------------- */ /* our structs */ @@ -162,24 +172,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) unsigned char buffer[2]; if (-1 == subaddr) { - dprintk("%s: chip_write: 0x%x\n", - i2c_clientname(&chip->c), val); + tvaudio_dbg("%s: chip_write: 0x%x\n", + chip->c.name, val); chip->shadow.bytes[1] = val; buffer[0] = val; if (1 != i2c_master_send(&chip->c,buffer,1)) { - printk(KERN_WARNING "%s: I/O error (write 0x%x)\n", - i2c_clientname(&chip->c), val); + tvaudio_warn("%s: I/O error (write 0x%x)\n", + chip->c.name, val); return -1; } } else { - dprintk("%s: chip_write: reg%d=0x%x\n", - i2c_clientname(&chip->c), subaddr, val); + tvaudio_dbg("%s: chip_write: reg%d=0x%x\n", + chip->c.name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; if (2 != i2c_master_send(&chip->c,buffer,2)) { - printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n", - i2c_clientname(&chip->c), subaddr, val); + tvaudio_warn("%s: I/O error (write reg%d=0x%x)\n", + chip->c.name, subaddr, val); return -1; } } @@ -203,31 +213,30 @@ static int chip_read(struct CHIPSTATE *chip) unsigned char buffer; if (1 != i2c_master_recv(&chip->c,&buffer,1)) { - printk(KERN_WARNING "%s: I/O error (read)\n", - i2c_clientname(&chip->c)); + tvaudio_warn("%s: I/O error (read)\n", + chip->c.name); return -1; } - dprintk("%s: chip_read: 0x%x\n",i2c_clientname(&chip->c),buffer); + tvaudio_dbg("%s: chip_read: 0x%x\n",chip->c.name,buffer); return buffer; } static int chip_read2(struct CHIPSTATE *chip, int subaddr) { - unsigned char write[1]; - unsigned char read[1]; - struct i2c_msg msgs[2] = { - { chip->c.addr, 0, 1, write }, - { chip->c.addr, I2C_M_RD, 1, read } - }; - write[0] = subaddr; + unsigned char write[1]; + unsigned char read[1]; + struct i2c_msg msgs[2] = { + { chip->c.addr, 0, 1, write }, + { chip->c.addr, I2C_M_RD, 1, read } + }; + write[0] = subaddr; if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { - printk(KERN_WARNING "%s: I/O error (read2)\n", - i2c_clientname(&chip->c)); + tvaudio_warn("%s: I/O error (read2)\n", chip->c.name); return -1; } - dprintk("%s: chip_read2: reg%d=0x%x\n", - i2c_clientname(&chip->c),subaddr,read[0]); + tvaudio_dbg("%s: chip_read2: reg%d=0x%x\n", + chip->c.name,subaddr,read[0]); return read[0]; } @@ -239,17 +248,19 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return 0; /* update our shadow register set; print bytes if (debug > 0) */ - dprintk("%s: chip_cmd(%s): reg=%d, data:", - i2c_clientname(&chip->c),name,cmd->bytes[0]); + tvaudio_dbg("%s: chip_cmd(%s): reg=%d, data:", + chip->c.name,name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { - dprintk(" 0x%x",cmd->bytes[i]); + if (debug) + printk(" 0x%x",cmd->bytes[i]); chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i]; } - dprintk("\n"); + if (debug) + printk("\n"); /* send data to the chip */ if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { - printk(KERN_WARNING "%s: I/O error (%s)\n", i2c_clientname(&chip->c), name); + tvaudio_warn("%s: I/O error (%s)\n", chip->c.name, name); return -1; } return 0; @@ -264,19 +275,19 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) static void chip_thread_wake(unsigned long data) { - struct CHIPSTATE *chip = (struct CHIPSTATE*)data; + struct CHIPSTATE *chip = (struct CHIPSTATE*)data; wake_up_interruptible(&chip->wq); } static int chip_thread(void *data) { DECLARE_WAITQUEUE(wait, current); - struct CHIPSTATE *chip = data; + struct CHIPSTATE *chip = data; struct CHIPDESC *desc = chiplist + chip->type; - daemonize("%s",i2c_clientname(&chip->c)); + daemonize("%s", chip->c.name); allow_signal(SIGTERM); - dprintk("%s: thread started\n", i2c_clientname(&chip->c)); + tvaudio_dbg("%s: thread started\n", chip->c.name); for (;;) { add_wait_queue(&chip->wq, &wait); @@ -288,7 +299,7 @@ static int chip_thread(void *data) try_to_freeze(); if (chip->done || signal_pending(current)) break; - dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c)); + tvaudio_dbg("%s: thread wakeup\n", chip->c.name); /* don't do anything for radio or if mode != auto */ if (chip->norm == VIDEO_MODE_RADIO || chip->mode != 0) @@ -301,8 +312,8 @@ static int chip_thread(void *data) mod_timer(&chip->wt, jiffies+2*HZ); } - dprintk("%s: thread exiting\n", i2c_clientname(&chip->c)); - complete_and_exit(&chip->texit, 0); + tvaudio_dbg("%s: thread exiting\n", chip->c.name); + complete_and_exit(&chip->texit, 0); return 0; } @@ -312,9 +323,9 @@ static void generic_checkmode(struct CHIPSTATE *chip) int mode = desc->getmode(chip); if (mode == chip->prevmode) - return; + return; - dprintk("%s: thread checkmode\n", i2c_clientname(&chip->c)); + tvaudio_dbg("%s: thread checkmode\n", chip->c.name); chip->prevmode = mode; if (mode & VIDEO_SOUND_STEREO) @@ -361,8 +372,8 @@ static int tda9840_getmode(struct CHIPSTATE *chip) if (val & TDA9840_ST_STEREO) mode |= VIDEO_SOUND_STEREO; - dprintk ("tda9840_getmode(): raw chip read: %d, return: %d\n", - val, mode); + tvaudio_dbg ("tda9840_getmode(): raw chip read: %d, return: %d\n", + val, mode); return mode; } @@ -657,8 +668,8 @@ static int tda9873_getmode(struct CHIPSTATE *chip) mode |= VIDEO_SOUND_STEREO; if (val & TDA9873_DUAL) mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - dprintk ("tda9873_getmode(): raw chip read: %d, return: %d\n", - val, mode); + tvaudio_dbg ("tda9873_getmode(): raw chip read: %d, return: %d\n", + val, mode); return mode; } @@ -668,12 +679,12 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - dprintk("tda9873_setmode(): external input\n"); + tvaudio_dbg("tda9873_setmode(): external input\n"); return; } - dprintk("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - dprintk("tda9873_setmode(): sw_data = %d\n", sw_data); + tvaudio_dbg("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + tvaudio_dbg("tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { case VIDEO_SOUND_MONO: @@ -694,7 +705,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) } chip_write(chip, TDA9873_SW, sw_data); - dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", + tvaudio_dbg("tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -831,9 +842,9 @@ static int tda9874a_setup(struct CHIPSTATE *chip) } else { /* dic == 0x07 */ chip_write(chip, TDA9874A_AMCONR, 0xfb); chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); - chip_write(chip, TDA9874A_AOSR, 0x00); // or 0x10 + chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ } - dprintk("tda9874a_setup(): %s [0x%02X].\n", + tvaudio_dbg("tda9874a_setup(): %s [0x%02X].\n", tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } @@ -876,7 +887,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } - dprintk("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + tvaudio_dbg("tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } @@ -922,7 +933,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - dprintk("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + tvaudio_dbg("tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ @@ -957,7 +968,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - dprintk("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + tvaudio_dbg("tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -971,10 +982,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) return 0; - dprintk("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); + tvaudio_dbg("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); if((dic == 0x11)||(dic == 0x07)) { - printk("tvaudio: found tda9874%s.\n", (dic == 0x11) ? "a":"h"); + tvaudio_info("found tda9874%s.\n", (dic == 0x11) ? "a":"h"); tda9874a_dic = dic; /* remember device id. */ return 1; } @@ -1098,7 +1109,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip) /* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF, /* off */ TDA8425_S1_OFF, /* on */ TDA8425_S1_CH2}; - if (chip->c.adapter->id == (I2C_ALGO_BIT | I2C_HW_B_RIVA)) { + if (chip->c.adapter->id == I2C_HW_B_RIVA) { memcpy (desc->inputmap, inputmap, sizeof (inputmap)); } return 0; @@ -1149,7 +1160,7 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) /* ---------------------------------------------------------------------- */ /* audio chip descriptions - defines+functions for TA8874Z */ -// write 1st byte +/* write 1st byte */ #define TA8874Z_LED_STE 0x80 #define TA8874Z_LED_BIL 0x40 #define TA8874Z_LED_EXT 0x20 @@ -1159,21 +1170,22 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) #define TA8874Z_MODE_SUB 0x02 #define TA8874Z_MODE_MAIN 0x01 -// write 2nd byte -//#define TA8874Z_TI 0x80 // test mode +/* write 2nd byte */ +/*#define TA8874Z_TI 0x80 */ /* test mode */ #define TA8874Z_SEPARATION 0x3f #define TA8874Z_SEPARATION_DEFAULT 0x10 -// read +/* read */ #define TA8874Z_B1 0x80 #define TA8874Z_B0 0x40 #define TA8874Z_CHAG_FLAG 0x20 -// B1 B0 -// mono L H -// stereo L L -// BIL H L - +/* + * B1 B0 + * mono L H + * stereo L L + * BIL H L + */ static int ta8874z_getmode(struct CHIPSTATE *chip) { int val, mode; @@ -1185,7 +1197,7 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) }else if (!(val & TA8874Z_B0)){ mode |= VIDEO_SOUND_STEREO; } - //dprintk ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); + /* tvaudio_dbg ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; } @@ -1198,7 +1210,7 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; audiocmd *t = NULL; - dprintk("ta8874z_setmode(): mode: 0x%02x\n", mode); + tvaudio_dbg("ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ case VIDEO_SOUND_MONO: @@ -1238,11 +1250,11 @@ static int tda9850 = 1; static int tda9855 = 1; static int tda9873 = 1; static int tda9874a = 1; -static int tea6300 = 0; // address clash with msp34xx -static int tea6320 = 0; // address clash with msp34xx +static int tea6300 = 0; /* address clash with msp34xx */ +static int tea6320 = 0; /* address clash with msp34xx */ static int tea6420 = 1; static int pic16c54 = 1; -static int ta8874z = 0; // address clash with tda9840 +static int ta8874z = 0; /* address clash with tda9840 */ module_param(tda8425, int, 0444); module_param(tda9840, int, 0444); @@ -1444,7 +1456,7 @@ static struct CHIPDESC chiplist[] = { { .name = "ta8874z", .id = -1, - //.id = I2C_DRIVERID_TA8874Z, + /*.id = I2C_DRIVERID_TA8874Z, */ .checkit = ta8874z_checkit, .insmodopt = &ta8874z, .addr_lo = I2C_TDA9840 >> 1, @@ -1479,7 +1491,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(&chip->c, chip); /* find description for the chip */ - dprintk("tvaudio: chip found @ i2c-addr=0x%x\n", addr<<1); + tvaudio_dbg("chip found @ 0x%x\n", addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; @@ -1491,17 +1503,19 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) break; } if (desc->name == NULL) { - dprintk("tvaudio: no matching chip description found\n"); + tvaudio_dbg("no matching chip description found\n"); return -EIO; } - printk("tvaudio: found %s @ 0x%x\n", desc->name, addr<<1); - dprintk("tvaudio: matches:%s%s%s.\n", - (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", - (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", - (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); + tvaudio_info("%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); + if (desc->flags) { + tvaudio_dbg("matches:%s%s%s.\n", + (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", + (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", + (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); + } /* fill required data structures */ - strcpy(i2c_clientname(&chip->c),desc->name); + strcpy(chip->c.name,desc->name); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; @@ -1537,8 +1551,8 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) init_completion(&chip->texit); chip->tpid = kernel_thread(chip_thread,(void *)chip,0); if (chip->tpid < 0) - printk(KERN_WARNING "%s: kernel_thread() failed\n", - i2c_clientname(&chip->c)); + tvaudio_warn("%s: kernel_thread() failed\n", + chip->c.name); wake_up_interruptible(&chip->wq); } return 0; @@ -1548,16 +1562,16 @@ static int chip_probe(struct i2c_adapter *adap) { /* don't attach on saa7146 based cards, because dedicated drivers are used */ - if ((adap->id & I2C_ALGO_SAA7146)) + if ((adap->id == I2C_HW_SAA7146)) return 0; #ifdef I2C_CLASS_TV_ANALOG if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, chip_attach); #else switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - case I2C_ALGO_SAA7134: + case I2C_HW_B_BT848: + case I2C_HW_B_RIVA: + case I2C_HW_SAA7134: return i2c_probe(adap, &addr_data, chip_attach); } #endif @@ -1587,11 +1601,11 @@ static int chip_detach(struct i2c_client *client) static int chip_command(struct i2c_client *client, unsigned int cmd, void *arg) { - __u16 *sarg = arg; + __u16 *sarg = arg; struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - dprintk("%s: chip_command 0x%x\n",i2c_clientname(&chip->c),cmd); + tvaudio_dbg("%s: chip_command 0x%x\n",chip->c.name,cmd); switch (cmd) { case AUDC_SET_INPUT: @@ -1604,7 +1618,6 @@ static int chip_command(struct i2c_client *client, break; case AUDC_SET_RADIO: - dprintk(KERN_DEBUG "tvaudio: AUDC_SET_RADIO\n"); chip->norm = VIDEO_MODE_RADIO; chip->watch_stereo = 0; /* del_timer(&chip->wt); */ @@ -1612,7 +1625,7 @@ static int chip_command(struct i2c_client *client, /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ + kernel pointer here... */ case VIDIOCGAUDIO: { struct video_audio *va = arg; @@ -1646,9 +1659,9 @@ static int chip_command(struct i2c_client *client, if (desc->flags & CHIP_HAS_VOLUME) { chip->left = (min(65536 - va->balance,32768) * - va->volume) / 32768; + va->volume) / 32768; chip->right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; + va->volume) / 32768; chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); } @@ -1670,17 +1683,16 @@ static int chip_command(struct i2c_client *client, { struct video_channel *vc = arg; - dprintk(KERN_DEBUG "tvaudio: VIDIOCSCHAN\n"); chip->norm = vc->norm; break; } case VIDIOCSFREQ: { - chip->mode = 0; /* automatic */ + chip->mode = 0; /* automatic */ if (desc->checkmode) { desc->setmode(chip,VIDEO_SOUND_MONO); - if (chip->prevmode != VIDEO_SOUND_MONO) - chip->prevmode = -1; /* reset previous mode */ + if (chip->prevmode != VIDEO_SOUND_MONO) + chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+2*HZ); /* the thread will call checkmode() later */ } @@ -1692,29 +1704,32 @@ static int chip_command(struct i2c_client *client, static struct i2c_driver driver = { .owner = THIS_MODULE, - .name = "generic i2c audio driver", - .id = I2C_DRIVERID_TVAUDIO, - .flags = I2C_DF_NOTIFY, - .attach_adapter = chip_probe, - .detach_client = chip_detach, - .command = chip_command, + .name = "generic i2c audio driver", + .id = I2C_DRIVERID_TVAUDIO, + .flags = I2C_DF_NOTIFY, + .attach_adapter = chip_probe, + .detach_client = chip_detach, + .command = chip_command, }; static struct i2c_client client_template = { - I2C_DEVNAME("(unset)"), + .name = "(unset)", .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + .driver = &driver, }; static int __init audiochip_init_module(void) { struct CHIPDESC *desc; - printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); - printk(KERN_INFO "tvaudio: known chips: "); - for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ",",desc->name); - printk("\n"); + + if (debug) { + printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); + printk(KERN_INFO "tvaudio: known chips: "); + for (desc = chiplist; desc->name != NULL; desc++) + printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); + printk("\n"); + } return i2c_add_driver(&driver); } diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 127ec38ebd60..5344d5592199 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -47,18 +47,21 @@ MODULE_LICENSE("GPL"); static int debug = 0; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-2)"); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown") -#define dprintk(num, args...) \ - do { \ - if (debug >= num) \ - printk(KERN_INFO "tveeprom: " args); \ - } while (0) +#define tveeprom_info(fmt, arg...) do {\ + printk(KERN_INFO "tveeprom %d-%04x: " fmt, \ + c->adapter->nr, c->addr , ##arg); } while (0) +#define tveeprom_warn(fmt, arg...) do {\ + printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \ + c->adapter->nr, c->addr , ##arg); } while (0) +#define tveeprom_dbg(fmt, arg...) do {\ + if (debug) \ + printk(KERN_INFO "tveeprom %d-%04x: " fmt, \ + c->adapter->nr, c->addr , ##arg); } while (0) -#define TVEEPROM_KERN_ERR(args...) printk(KERN_ERR "tveeprom: " args); -#define TVEEPROM_KERN_INFO(args...) printk(KERN_INFO "tveeprom: " args); /* ----------------------------------------------------------------------- */ /* some hauppauge specific stuff */ @@ -70,14 +73,14 @@ static struct HAUPPAUGE_TUNER_FMT } hauppauge_tuner_fmt[] = { - { 0x00000000, "unknown1" }, - { 0x00000000, "unknown2" }, - { 0x00000007, "PAL(B/G)" }, - { 0x00001000, "NTSC(M)" }, - { 0x00000010, "PAL(I)" }, - { 0x00400000, "SECAM(L/L´)" }, - { 0x00000e00, "PAL(D/K)" }, - { 0x03000000, "ATSC Digital" }, + { 0x00000000, " unknown1" }, + { 0x00000000, " unknown2" }, + { 0x00000007, " PAL(B/G)" }, + { 0x00001000, " NTSC(M)" }, + { 0x00000010, " PAL(I)" }, + { 0x00400000, " SECAM(L/L')" }, + { 0x00000e00, " PAL(D/K)" }, + { 0x03000000, " ATSC Digital" }, }; /* This is the full list of possible tuners. Many thanks to Hauppauge for @@ -152,13 +155,13 @@ hauppauge_tuner[] = { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, { TUNER_ABSENT, "LG TPI8NSR11F"}, { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, - { TUNER_ABSENT, "Philips FQ1216ME MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, { TUNER_ABSENT, "Philips FI1236 MK3"}, { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, - { TUNER_ABSENT, "Philips FM1236 MK3"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, { TUNER_ABSENT, "Philips FM1216MP MK3"}, /* 60-69 */ - { TUNER_ABSENT, "LG S001D MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, { TUNER_ABSENT, "LG M001D MK3"}, { TUNER_ABSENT, "LG S701D MK3"}, { TUNER_ABSENT, "LG M701D MK3"}, @@ -167,7 +170,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Temic 4106FH5"}, { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, - { TUNER_ABSENT, "LG TAPE H701F MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, /* 70-79 */ { TUNER_ABSENT, "LG TALN H200T"}, { TUNER_ABSENT, "LG TALN H250T"}, @@ -183,8 +186,8 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Philips FQ1216LME MK3"}, { TUNER_ABSENT, "LG TAPC G701D"}, { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, - { TUNER_ABSENT, "TCL 2002MB 3"}, - { TUNER_ABSENT, "TCL 2002MI 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, { TUNER_TCL_2002N, "TCL 2002N 6A"}, { TUNER_ABSENT, "Philips FQ1236 MK3"}, { TUNER_ABSENT, "Samsung TCPN 2121P30A"}, @@ -199,17 +202,51 @@ hauppauge_tuner[] = { TUNER_ABSENT, "Philips FQ1236 MK5"}, { TUNER_ABSENT, "Unspecified"}, { TUNER_LG_PAL_TAPE, "LG PAL (TAPE Series)"}, + { TUNER_ABSENT, "Unspecified"}, + { TUNER_TCL_2002N, "TCL 2002N 5H"}, + /* 100-103 */ + { TUNER_ABSENT, "Unspecified"}, + { TUNER_TEA5767, "Philips TEA5767HN FM Radio"}, + { TUNER_ABSENT, "Unspecified"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05 4"}, }; -static char *sndtype[] = { - "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C", "MSP3410D", - "MSP3415", "MSP3430", "MSP3438", "CS5331", "MSP3435", "MSP3440", - "MSP3445", "MSP3411", "MSP3416", "MSP3425", +/* This list is supplied by Hauppauge. Thanks! */ +static const char *audioIC[] = { + /* 0-4 */ + "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C", + /* 5-9 */ + "MSP3410D", "MSP3415", "MSP3430", "MSP3438", "CS5331", + /* 10-14 */ + "MSP3435", "MSP3440", "MSP3445", "MSP3411", "MSP3416", + /* 15-19 */ + "MSP3425", "MSP3451", "MSP3418", "Type 0x12", "OKI7716", + /* 20-24 */ + "MSP4410", "MSP4420", "MSP4440", "MSP4450", "MSP4408", + /* 25-29 */ + "MSP4418", "MSP4428", "MSP4448", "MSP4458", "Type 0x1d", + /* 30-34 */ + "CX880", "CX881", "CX883", "CX882", "CX25840", + /* 35-38 */ + "CX25841", "CX25842", "CX25843", "CX23418", +}; - "Type 0x10","Type 0x11","Type 0x12","Type 0x13", - "Type 0x14","Type 0x15","Type 0x16","Type 0x17", - "Type 0x18","MSP4418","Type 0x1a","MSP4448", - "Type 0x1c","Type 0x1d","Type 0x1e","Type 0x1f", +/* This list is supplied by Hauppauge. Thanks! */ +static const char *decoderIC[] = { + /* 0-4 */ + "None", "BT815", "BT817", "BT819", "BT815A", + /* 5-9 */ + "BT817A", "BT819A", "BT827", "BT829", "BT848", + /* 10-14 */ + "BT848A", "BT849A", "BT829A", "BT827A", "BT878", + /* 15-19 */ + "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115", + /* 20-24 */ + "CX880", "CX881", "CX883", "SAA7111", "SAA7113", + /* 25-29 */ + "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", + /* 30-31 */ + "CX25843", "CX23418", }; static int hasRadioTuner(int tunerType) @@ -250,7 +287,8 @@ static int hasRadioTuner(int tunerType) return 0; } -void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data) +void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, + unsigned char *eeprom_data) { /* ---------------------------------------------- ** The hauppauge eeprom format is tagged @@ -260,10 +298,11 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum ** ** In our (ivtv) case we're interested in the following: - ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) - ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) - ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) - ** audio proc: tag [02].01 or [05].00 (lower nibble indexes lut?) + ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) + ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) + ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) + ** decoder proc: tag [09].01) ** Fun info: ** model: tag [00].07-08 or [06].00-01 @@ -273,20 +312,24 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data ** # of inputs/outputs ??? */ - int i, j, len, done, beenhere, tag, tuner = 0, t_format = 0; - char *t_name = NULL, *t_fmt_name = NULL; + int i, j, len, done, beenhere, tag; - dprintk(1, "%s\n",__FUNCTION__); - tvee->revision = done = len = beenhere = 0; - for (i = 0; !done && i < 256; i += len) { - dprintk(2, "processing pos = %02x (%02x, %02x)\n", - i, eeprom_data[i], eeprom_data[i + 1]); + int tuner1 = 0, t_format1 = 0; + char *t_name1 = NULL; + const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; + int tuner2 = 0, t_format2 = 0; + char *t_name2 = NULL; + const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" }; + + memset(tvee, 0, sizeof(*tvee)); + done = len = beenhere = 0; + for (i = 0; !done && i < 256; i += len) { if (eeprom_data[i] == 0x84) { len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8); - i+=3; + i += 3; } else if ((eeprom_data[i] & 0xf0) == 0x70) { - if ((eeprom_data[i] & 0x08)) { + if (eeprom_data[i] & 0x08) { /* verify checksum! */ done = 1; break; @@ -294,24 +337,30 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data len = eeprom_data[i] & 0x07; ++i; } else { - TVEEPROM_KERN_ERR("Encountered bad packet header [%02x]. " + tveeprom_warn("Encountered bad packet header [%02x]. " "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); return; } - dprintk(1, "%3d [%02x] ", len, eeprom_data[i]); - for(j = 1; j < len; j++) { - dprintk(1, "%02x ", eeprom_data[i + j]); - } - dprintk(1, "\n"); + if (debug) { + tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1); + for(j = 1; j < len; j++) { + printk(" %02x", eeprom_data[i + j]); + } + printk("\n"); + } /* process by tag */ tag = eeprom_data[i]; switch (tag) { case 0x00: - tuner = eeprom_data[i+6]; - t_format = eeprom_data[i+5]; + /* tag: 'Comprehensive' */ + tuner1 = eeprom_data[i+6]; + t_format1 = eeprom_data[i+5]; tvee->has_radio = eeprom_data[i+len-1]; + /* old style tag, don't know how to detect + IR presence, mark as unknown. */ + tvee->has_ir = 2; tvee->model = eeprom_data[i+8] + (eeprom_data[i+9] << 8); @@ -319,25 +368,43 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data (eeprom_data[i+11] << 8) + (eeprom_data[i+12] << 16); break; + case 0x01: + /* tag: 'SerialID' */ tvee->serial_number = eeprom_data[i+6] + (eeprom_data[i+7] << 8) + (eeprom_data[i+8] << 16); break; + case 0x02: - tvee->audio_processor = eeprom_data[i+2] & 0x0f; + /* tag 'AudioInfo' + Note mask with 0x7F, high bit used on some older models + to indicate 4052 mux was removed in favor of using MSP + inputs directly. */ + tvee->audio_processor = eeprom_data[i+2] & 0x7f; break; + + /* case 0x03: tag 'EEInfo' */ + case 0x04: + /* tag 'SerialID2' */ tvee->serial_number = eeprom_data[i+5] + (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); break; + case 0x05: - tvee->audio_processor = eeprom_data[i+1] & 0x0f; + /* tag 'Audio2' + Note mask with 0x7F, high bit used on some older models + to indicate 4052 mux was removed in favor of using MSP + inputs directly. */ + tvee->audio_processor = eeprom_data[i+1] & 0x7f; break; + case 0x06: + /* tag 'ModelRev' */ tvee->model = eeprom_data[i+1] + (eeprom_data[i+2] << 8); @@ -345,27 +412,66 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); break; + + case 0x07: + /* tag 'Details': according to Hauppauge not interesting + on any PCI-era or later boards. */ + break; + + /* there is no tag 0x08 defined */ + + case 0x09: + /* tag 'Video' */ + tvee->decoder_processor = eeprom_data[i + 1]; + break; + case 0x0a: - if(beenhere == 0) { - tuner = eeprom_data[i+2]; - t_format = eeprom_data[i+1]; + /* tag 'Tuner' */ + if (beenhere == 0) { + tuner1 = eeprom_data[i+2]; + t_format1 = eeprom_data[i+1]; beenhere = 1; - break; } else { - break; - } + /* a second (radio) tuner may be present */ + tuner2 = eeprom_data[i+2]; + t_format2 = eeprom_data[i+1]; + if (t_format2 == 0) { /* not a TV tuner? */ + tvee->has_radio = 1; /* must be radio */ + } + } + break; + + case 0x0b: + /* tag 'Inputs': according to Hauppauge this is specific + to each driver family, so no good assumptions can be + made. */ + break; + + /* case 0x0c: tag 'Balun' */ + /* case 0x0d: tag 'Teletext' */ + case 0x0e: + /* tag: 'Radio' */ tvee->has_radio = eeprom_data[i+1]; break; + + case 0x0f: + /* tag 'IRInfo' */ + tvee->has_ir = eeprom_data[i+1]; + break; + + /* case 0x10: tag 'VBIInfo' */ + /* case 0x11: tag 'QCInfo' */ + /* case 0x12: tag 'InfoBits' */ + default: - dprintk(1, "Not sure what to do with tag [%02x]\n", tag); + tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag); /* dump the rest of the packet? */ } - } if (!done) { - TVEEPROM_KERN_ERR("Ran out of data!\n"); + tveeprom_warn("Ran out of data!\n"); return; } @@ -377,47 +483,72 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data tvee->rev_str[4] = 0; } - if (hasRadioTuner(tuner) && !tvee->has_radio) { - TVEEPROM_KERN_INFO("The eeprom says no radio is present, but the tuner type\n"); - TVEEPROM_KERN_INFO("indicates otherwise. I will assume that radio is present.\n"); + if (hasRadioTuner(tuner1) && !tvee->has_radio) { + tveeprom_info("The eeprom says no radio is present, but the tuner type\n"); + tveeprom_info("indicates otherwise. I will assume that radio is present.\n"); tvee->has_radio = 1; } - if (tuner < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { - tvee->tuner_type = hauppauge_tuner[tuner].id; - t_name = hauppauge_tuner[tuner].name; + if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { + tvee->tuner_type = hauppauge_tuner[tuner1].id; + t_name1 = hauppauge_tuner[tuner1].name; } else { - t_name = "<unknown>"; + t_name1 = "unknown"; + } + + if (tuner2 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { + tvee->tuner2_type = hauppauge_tuner[tuner2].id; + t_name2 = hauppauge_tuner[tuner2].name; + } else { + t_name2 = "unknown"; } tvee->tuner_formats = 0; - t_fmt_name = "<none>"; - for (i = 0; i < 8; i++) { - if (t_format & (1<<i)) { + tvee->tuner2_formats = 0; + for (i = j = 0; i < 8; i++) { + if (t_format1 & (1 << i)) { tvee->tuner_formats |= hauppauge_tuner_fmt[i].id; - /* yuck */ - t_fmt_name = hauppauge_tuner_fmt[i].name; + t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name; } + if (t_format2 & (1 << i)) { + tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id; + t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name; + } } - - TVEEPROM_KERN_INFO("Hauppauge: model = %d, rev = %s, serial# = %d\n", - tvee->model, - tvee->rev_str, - tvee->serial_number); - TVEEPROM_KERN_INFO("tuner = %s (idx = %d, type = %d)\n", - t_name, - tuner, - tvee->tuner_type); - TVEEPROM_KERN_INFO("tuner fmt = %s (eeprom = 0x%02x, v4l2 = 0x%08x)\n", - t_fmt_name, - t_format, - tvee->tuner_formats); - - TVEEPROM_KERN_INFO("audio_processor = %s (type = %d)\n", - STRM(sndtype,tvee->audio_processor), + tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", + tvee->model, tvee->rev_str, tvee->serial_number); + tveeprom_info("tuner model is %s (idx %d, type %d)\n", + t_name1, tuner1, tvee->tuner_type); + tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], + t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], + t_format1); + if (tuner2) { + tveeprom_info("second tuner model is %s (idx %d, type %d)\n", + t_name2, tuner2, tvee->tuner2_type); + } + if (t_format2) { + tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], + t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], + t_format2); + } + tveeprom_info("audio processor is %s (idx %d)\n", + STRM(audioIC, tvee->audio_processor), tvee->audio_processor); - + if (tvee->decoder_processor) { + tveeprom_info("decoder processor is %s (idx %d)\n", + STRM(decoderIC, tvee->decoder_processor), + tvee->decoder_processor); + } + if (tvee->has_ir == 2) + tveeprom_info("has %sradio\n", + tvee->has_radio ? "" : "no "); + else + tveeprom_info("has %sradio, has %sIR remote\n", + tvee->has_radio ? "" : "no ", + tvee->has_ir ? "" : "no "); } EXPORT_SYMBOL(tveeprom_hauppauge_analog); @@ -429,40 +560,31 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) unsigned char buf; int err; - dprintk(1, "%s\n",__FUNCTION__); buf = 0; - if (1 != (err = i2c_master_send(c,&buf,1))) { - printk(KERN_INFO "tveeprom(%s): Huh, no eeprom present (err=%d)?\n", - c->name,err); + if (1 != (err = i2c_master_send(c, &buf, 1))) { + tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); return -1; } - if (len != (err = i2c_master_recv(c,eedata,len))) { - printk(KERN_WARNING "tveeprom(%s): i2c eeprom read error (err=%d)\n", - c->name,err); + if (len != (err = i2c_master_recv(c, eedata, len))) { + tveeprom_warn("i2c eeprom read error (err=%d)\n", err); return -1; } + if (debug) { + int i; + + tveeprom_info("full 256-byte eeprom dump:\n"); + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + tveeprom_info("%02x:", i); + printk(" %02x", eedata[i]); + if (15 == (i % 16)) + printk("\n"); + } + } return 0; } EXPORT_SYMBOL(tveeprom_read); -#if 0 -int tveeprom_dump(unsigned char *eedata, int len) -{ - int i; - - dprintk(1, "%s\n",__FUNCTION__); - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "tveeprom: %02x:",i); - printk(" %02x",eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } - return 0; -} -EXPORT_SYMBOL(tveeprom_dump); -#endif /* 0 */ - /* ----------------------------------------------------------------------- */ /* needed for ivtv.sf.net at the moment. Should go away in the long */ /* run, just call the exported tveeprom_* directly, there is no point in */ @@ -495,12 +617,13 @@ tveeprom_command(struct i2c_client *client, buf = kmalloc(256,GFP_KERNEL); memset(buf,0,256); tveeprom_read(client,buf,256); - tveeprom_hauppauge_analog(&eeprom,buf); + tveeprom_hauppauge_analog(client, &eeprom,buf); kfree(buf); eeprom_props[0] = eeprom.tuner_type; eeprom_props[1] = eeprom.tuner_formats; eeprom_props[2] = eeprom.model; eeprom_props[3] = eeprom.revision; + eeprom_props[4] = eeprom.has_radio; break; default: return -EINVAL; @@ -515,8 +638,6 @@ tveeprom_detect_client(struct i2c_adapter *adapter, { struct i2c_client *client; - dprintk(1,"%s: id 0x%x @ 0x%x\n",__FUNCTION__, - adapter->id, address << 1); client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (NULL == client) return -ENOMEM; @@ -533,8 +654,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter, static int tveeprom_attach_adapter (struct i2c_adapter *adapter) { - dprintk(1,"%s: id 0x%x\n",__FUNCTION__,adapter->id); - if (adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) + if (adapter->id != I2C_HW_B_BT848) return 0; return i2c_probe(adapter, &addr_data, tveeprom_detect_client); } diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c index 51b99cdbf29e..d86e08ebddfc 100644 --- a/drivers/media/video/tvmixer.c +++ b/drivers/media/video/tvmixer.c @@ -1,5 +1,4 @@ /* - * $Id: tvmixer.c,v 1.8 2005/06/12 04:19:19 mchehab Exp $ */ #include <linux/module.h> @@ -91,7 +90,7 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm if (cmd == SOUND_MIXER_INFO) { mixer_info info; strlcpy(info.id, "tv card", sizeof(info.id)); - strlcpy(info.name, i2c_clientname(client), sizeof(info.name)); + strlcpy(info.name, client->name, sizeof(info.name)); info.modify_counter = 42 /* FIXME */; if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; @@ -100,7 +99,7 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; strlcpy(info.id, "tv card", sizeof(info.id)); - strlcpy(info.name, i2c_clientname(client), sizeof(info.name)); + strlcpy(info.name, client->name, sizeof(info.name)); if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; return 0; @@ -276,9 +275,9 @@ static int tvmixer_clients(struct i2c_client *client) #else /* TV card ??? */ switch (client->adapter->id) { - case I2C_ALGO_BIT | I2C_HW_SMBUS_VOODOO3: - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: + case I2C_HW_SMBUS_VOODOO3: + case I2C_HW_B_BT848: + case I2C_HW_B_RIVA: /* ok, have a look ... */ break; default: @@ -295,7 +294,7 @@ static int tvmixer_clients(struct i2c_client *client) devices[i].dev = NULL; devices[i].minor = -1; printk("tvmixer: %s unregistered (#1)\n", - i2c_clientname(client)); + client->name); return 0; } } @@ -354,7 +353,7 @@ static void __exit tvmixer_cleanup_module(void) if (devices[i].minor != -1) { unregister_sound_mixer(devices[i].minor); printk("tvmixer: %s unregistered (#2)\n", - i2c_clientname(devices[i].dev)); + devices[i].dev->name); } } } diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 70ecbdb80277..59bb71381a1b 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -1,5 +1,4 @@ /* - * $Id: v4l1-compat.c,v 1.9 2005/06/12 04:19:19 mchehab Exp $ * * Video for Linux Two * Backward Compatibility Layer @@ -604,9 +603,6 @@ v4l_compat_translate_ioctl(struct inode *inode, dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err); break; } -#if 0 /* FIXME */ - pict->depth = fmt2->fmt.pix.depth; -#endif pict->palette = pixelformat_to_palette( fmt2->fmt.pix.pixelformat); break; @@ -707,13 +703,7 @@ v4l_compat_translate_ioctl(struct inode *inode, } case VIDIOCSTUNER: /* select a tuner input */ { -#if 0 /* FIXME */ - err = drv(inode, file, VIDIOC_S_INPUT, &i); - if (err < 0) - dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err); -#else err = 0; -#endif break; } case VIDIOCGFREQ: /* get frequency */ @@ -852,12 +842,6 @@ v4l_compat_translate_ioctl(struct inode *inode, err = 0; break; } -#if 0 - case VIDIOCGMBUF: - /* v4l2 drivers must implement that themself. The - mmap() differences can't be translated fully - transparent, thus there is no point to try that */ -#endif case VIDIOCMCAPTURE: /* capture a frame */ { struct video_mmap *mm = arg; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index b5e0cf3448f4..597b8db35a13 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -84,20 +84,6 @@ MODULE_LICENSE("GPL"); * Video Standard Operations (contributed by Michael Schimek) */ -#if 0 /* seems to have no users */ -/* This is the recommended method to deal with the framerate fields. More - sophisticated drivers will access the fields directly. */ -unsigned int -v4l2_video_std_fps(struct v4l2_standard *vs) -{ - if (vs->frameperiod.numerator > 0) - return (((vs->frameperiod.denominator << 8) / - vs->frameperiod.numerator) + - (1 << 7)) / (1 << 8); - return 0; -} -EXPORT_SYMBOL(v4l2_video_std_fps); -#endif /* Fill in the fields of a v4l2_standard structure according to the 'id' and 'transmission' parameters. Returns negative on error. */ @@ -213,10 +199,6 @@ char *v4l2_ioctl_names[256] = { [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", -#if 0 - [_IOC_NR(VIDIOC_G_COMP)] = "VIDIOC_G_COMP", - [_IOC_NR(VIDIOC_S_COMP)] = "VIDIOC_S_COMP", -#endif [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index 15f5bb486963..55f129e964eb 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -1,5 +1,4 @@ /* - * $Id: video-buf-dvb.c,v 1.7 2004/12/09 12:51:35 kraxel Exp $ * * some helper function for simple DVB cards which simply DMA the * complete transport stream and let the computer sort everything else diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index 5afdc7852610..97354f253a80 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -1,5 +1,4 @@ /* - * $Id: video-buf.c,v 1.18 2005/02/24 13:32:30 kraxel Exp $ * * generic helper functions for video4linux capture buffers, to handle * memory management and PCI DMA. Right now bttv + saa7134 use it. diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 76e8681d65c6..d8a0f763ca10 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -1,80 +1,606 @@ /* - * (incomplete) Driver for the VINO (Video In No Out) system found in SGI Indys. + * Driver for the VINO (Video In No Out) system found in SGI Indys. * * This file is subject to the terms and conditions of the GNU General Public * License version 2 as published by the Free Software Foundation. * + * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi> + * + * Based on the previous version of the driver for 2.4 kernels by: * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> */ -#include <linux/module.h> +/* + * TODO: + * - remove "hacks" from memory allocation code and implement nopage() + * - check decimation, calculating and reporting image size when + * using decimation + * - check vino_acquire_input(), vino_set_input() and channel + * ownership handling + * - report VINO error-interrupts via ioctls ? + * - implement picture controls (all implemented?) + * - use macros for boolean values (?) + * - implement user mode buffers and overlay (?) + */ + #include <linux/init.h> -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/wrapper.h> -#include <linux/errno.h> -#include <linux/irq.h> +#include <linux/module.h> #include <linux/delay.h> -#include <linux/videodev.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/time.h> +#include <linux/moduleparam.h> + +#ifdef CONFIG_KMOD +#include <linux/kmod.h> +#endif + #include <linux/i2c.h> #include <linux/i2c-algo-sgi.h> -#include <asm/addrspace.h> -#include <asm/system.h> -#include <asm/bootinfo.h> -#include <asm/pgtable.h> +#include <linux/videodev.h> +#include <linux/videodev2.h> +#include <linux/video_decoder.h> + #include <asm/paccess.h> #include <asm/io.h> #include <asm/sgi/ip22.h> -#include <asm/sgi/hpc3.h> #include <asm/sgi/mc.h> #include "vino.h" +#include "saa7191.h" +#include "indycam.h" + +/* Uncomment the following line to get lots and lots of (mostly useless) + * debug info. + * Note that the debug output also slows down the driver significantly */ +// #define VINO_DEBUG + +#define VINO_MODULE_VERSION "0.0.3" +#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 3) + +MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver"); +MODULE_VERSION(VINO_MODULE_VERSION); +MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>"); +MODULE_LICENSE("GPL"); -/* debugging? */ -#if 1 -#define DEBUG(x...) printk(x); +#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags)) +#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags)) + +#ifdef VINO_DEBUG +#define dprintk(x...) printk("VINO: " x); #else -#define DEBUG(x...) +#define dprintk(x...) #endif +#define VINO_NO_CHANNEL 0 +#define VINO_CHANNEL_A 1 +#define VINO_CHANNEL_B 2 + +#define VINO_PAL_WIDTH 768 +#define VINO_PAL_HEIGHT 576 +#define VINO_NTSC_WIDTH 640 +#define VINO_NTSC_HEIGHT 480 + +#define VINO_MIN_WIDTH 32 +#define VINO_MIN_HEIGHT 32 + +#define VINO_CLIPPING_START_ODD_D1 1 +#define VINO_CLIPPING_START_ODD_PAL 1 +#define VINO_CLIPPING_START_ODD_NTSC 1 + +#define VINO_CLIPPING_START_EVEN_D1 2 +#define VINO_CLIPPING_START_EVEN_PAL 2 +#define VINO_CLIPPING_START_EVEN_NTSC 2 + +#define VINO_INPUT_CHANNEL_COUNT 3 + +#define VINO_INPUT_NONE -1 +#define VINO_INPUT_COMPOSITE 0 +#define VINO_INPUT_SVIDEO 1 +#define VINO_INPUT_D1 2 + +#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE) + +#define VINO_FIFO_THRESHOLD_DEFAULT 512 + +/*#define VINO_FRAMEBUFFER_SIZE (VINO_PAL_WIDTH * VINO_PAL_HEIGHT * 4 \ + + 2 * PAGE_SIZE)*/ +#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \ + * VINO_PAL_HEIGHT * 4 \ + + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1)) + +#define VINO_FRAMEBUFFER_MAX_COUNT 8 + +#define VINO_FRAMEBUFFER_UNUSED 0 +#define VINO_FRAMEBUFFER_IN_USE 1 +#define VINO_FRAMEBUFFER_READY 2 + +#define VINO_QUEUE_ERROR -1 +#define VINO_QUEUE_MAGIC 0x20050125 + +#define VINO_MEMORY_NONE 0 +#define VINO_MEMORY_MMAP 1 +#define VINO_MEMORY_USERPTR 2 + +#define VINO_DUMMY_DESC_COUNT 4 +#define VINO_DESC_FETCH_DELAY 5 /* microseconds */ + +/* the number is the index for vino_data_formats */ +#define VINO_DATA_FMT_NONE -1 +#define VINO_DATA_FMT_GREY 0 +#define VINO_DATA_FMT_RGB332 1 +#define VINO_DATA_FMT_RGB32 2 +#define VINO_DATA_FMT_YUV 3 +//#define VINO_DATA_FMT_RGB24 4 + +#define VINO_DATA_FMT_COUNT 4 + +#define VINO_DATA_NORM_NONE -1 +#define VINO_DATA_NORM_NTSC 0 +#define VINO_DATA_NORM_PAL 1 +#define VINO_DATA_NORM_SECAM 2 +#define VINO_DATA_NORM_D1 3 +/* The following is a special entry that can be used to + * autodetect the norm. */ +#define VINO_DATA_NORM_AUTO 0xff + +#define VINO_DATA_NORM_COUNT 4 -/* VINO ASIC registers */ -struct sgi_vino *vino; +/* Internal data structure definitions */ -static const char *vinostr = "VINO IndyCam/TV"; -static int threshold_a = 512; -static int threshold_b = 512; +struct vino_input { + char *name; + v4l2_std_id std; +}; + +struct vino_clipping { + unsigned int left, right, top, bottom; +}; + +struct vino_data_format { + /* the description */ + char *description; + /* bytes per pixel */ + unsigned int bpp; + /* V4L2 fourcc code */ + __u32 pixelformat; + /* V4L2 colorspace (duh!) */ + enum v4l2_colorspace colorspace; +}; + +struct vino_data_norm { + char *description; + unsigned int width, height; + struct vino_clipping odd; + struct vino_clipping even; + + v4l2_std_id std; + unsigned int fps_min, fps_max; + __u32 framelines; +}; + +struct vino_descriptor_table { + /* the number of PAGE_SIZE sized pages in the buffer */ + unsigned int page_count; + /* virtual (kmalloc'd) pointers to the actual data + * (in PAGE_SIZE chunks, used with mmap streaming) */ + unsigned long *virtual; + + /* cpu address for the VINO descriptor table + * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ + unsigned long *dma_cpu; + /* dma address for the VINO descriptor table + * (contains DMA addresses, VINO_PAGE_SIZE chunks) */ + dma_addr_t dma; +}; + +struct vino_framebuffer { + /* identifier nubmer */ + unsigned int id; + /* the length of the whole buffer */ + unsigned int size; + /* the length of actual data in buffer */ + unsigned int data_size; + /* the data format */ + unsigned int data_format; + /* the state of buffer data */ + unsigned int state; + /* is the buffer mapped in user space? */ + unsigned int map_count; + /* memory offset for mmap() */ + unsigned int offset; + /* frame counter */ + unsigned int frame_counter; + /* timestamp (written when image capture finishes) */ + struct timeval timestamp; + + struct vino_descriptor_table desc_table; + + spinlock_t state_lock; +}; -struct vino_device { - struct video_device vdev; -#define VINO_CHAN_A 1 -#define VINO_CHAN_B 2 - int chan; +struct vino_framebuffer_fifo { + unsigned int length; + + unsigned int used; + unsigned int head; + unsigned int tail; + + unsigned int data[VINO_FRAMEBUFFER_MAX_COUNT]; +}; + +struct vino_framebuffer_queue { + unsigned int magic; + + /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */ + unsigned int type; + unsigned int length; + + /* data field of in and out contain index numbers for buffer */ + struct vino_framebuffer_fifo in; + struct vino_framebuffer_fifo out; + + struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_MAX_COUNT]; + + spinlock_t queue_lock; + struct semaphore queue_sem; + wait_queue_head_t frame_wait_queue; +}; + +struct vino_channel_settings { + unsigned int channel; + + int input; + unsigned int data_format; + unsigned int data_norm; + struct vino_clipping clipping; + unsigned int decimation; + unsigned int line_size; + unsigned int alpha; + unsigned int fps; + unsigned int framert_reg; + + unsigned int fifo_threshold; + + struct vino_framebuffer_queue fb_queue; + + /* number of the current field */ + unsigned int field; + + /* read in progress */ + int reading; + /* streaming is active */ + int streaming; + /* the driver is currently processing the queue */ + int capturing; + + struct semaphore sem; + spinlock_t capture_lock; + + unsigned int users; + + /* V4L support */ + struct video_device *v4l_device; }; struct vino_client { + /* the channel which owns this client: + * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */ + unsigned int owner; struct i2c_client *driver; - int owner; }; -struct vino_video { - struct vino_device chA; - struct vino_device chB; +struct vino_settings { + struct vino_channel_settings a; + struct vino_channel_settings b; struct vino_client decoder; struct vino_client camera; - struct semaphore input_lock; + /* a lock for vino register access */ + spinlock_t vino_lock; + /* a lock for channel input changes */ + spinlock_t input_lock; - /* Loaded into VINO descriptors to clear End Of Descriptors table - * interupt condition */ unsigned long dummy_page; - unsigned int dummy_buf[4] __attribute__((aligned(8))); + struct vino_descriptor_table dummy_desc_table; }; -static struct vino_video *Vino; +/* Module parameters */ + +/* + * Using vino_pixel_conversion the ARGB32-format pixels supplied + * by the VINO chip can be converted to more common formats + * like RGBA32 (or probably RGB24 in the future). This way we + * can give out data that can be specified correctly with + * the V4L2-definitions. + * + * The pixel format is specified as RGBA32 when no conversion + * is used. + * + * Note that this only affects the 32-bit bit depth. + * + * Use non-zero value to enable conversion. + */ +static int vino_pixel_conversion = 0; +module_param_named(pixelconv, vino_pixel_conversion, int, 0); +MODULE_PARM_DESC(pixelconv, + "enable pixel conversion (non-zero value enables)"); + +/* Internal data structures */ + +static struct sgi_vino *vino; + +static struct vino_settings *vino_drvdata; + +static const char *vino_driver_name = "vino"; +static const char *vino_driver_description = "SGI VINO"; +static const char *vino_bus_name = "GIO64 bus"; +static const char *vino_v4l_device_name_a = "SGI VINO Channel A"; +static const char *vino_v4l_device_name_b = "SGI VINO Channel B"; + +static const struct vino_input vino_inputs[] = { + { + .name = "Composite", + .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + },{ + .name = "S-Video", + .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + },{ + .name = "D1 (IndyCam)", + .std = V4L2_STD_NTSC, + } +}; + +static const struct vino_data_format vino_data_formats[] = { + { + .description = "8-bit greyscale", + .bpp = 1, + .pixelformat = V4L2_PIX_FMT_GREY, + .colorspace = V4L2_COLORSPACE_SMPTE170M, + },{ + .description = "8-bit dithered RGB 3-3-2", + .bpp = 1, + .pixelformat = V4L2_PIX_FMT_RGB332, + .colorspace = V4L2_COLORSPACE_SRGB, + },{ + .description = "32-bit RGB", + .bpp = 4, + .pixelformat = V4L2_PIX_FMT_RGB32, + .colorspace = V4L2_COLORSPACE_SRGB, + },{ + .description = "YUV 4:2:2", + .bpp = 4, + .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped? + .colorspace = V4L2_COLORSPACE_SMPTE170M, + }/*,{ + .description = "24-bit RGB", + .bpp = 3, + .pixelformat = V4L2_PIX_FMT_RGB24, + .colorspace = V4L2_COLORSPACE_SRGB, + }*/ +}; + +static const struct vino_data_norm vino_data_norms[] = { + { + .description = "NTSC", + .std = V4L2_STD_NTSC, + .fps_min = 6, + .fps_max = 30, + .framelines = 525, + .width = VINO_NTSC_WIDTH, + .height = VINO_NTSC_HEIGHT, + .odd = { + .top = VINO_CLIPPING_START_ODD_NTSC, + .left = 0, + .bottom = VINO_CLIPPING_START_ODD_NTSC + + VINO_NTSC_HEIGHT / 2 - 1, + .right = VINO_NTSC_WIDTH, + }, + .even = { + .top = VINO_CLIPPING_START_EVEN_NTSC, + .left = 0, + .bottom = VINO_CLIPPING_START_EVEN_NTSC + + VINO_NTSC_HEIGHT / 2 - 1, + .right = VINO_NTSC_WIDTH, + }, + },{ + .description = "PAL", + .std = V4L2_STD_PAL, + .fps_min = 5, + .fps_max = 25, + .framelines = 625, + .width = VINO_PAL_WIDTH, + .height = VINO_PAL_HEIGHT, + .odd = { + .top = VINO_CLIPPING_START_ODD_PAL, + .left = 0, + .bottom = VINO_CLIPPING_START_ODD_PAL + + VINO_PAL_HEIGHT / 2 - 1, + .right = VINO_PAL_WIDTH, + }, + .even = { + .top = VINO_CLIPPING_START_EVEN_PAL, + .left = 0, + .bottom = VINO_CLIPPING_START_EVEN_PAL + + VINO_PAL_HEIGHT / 2 - 1, + .right = VINO_PAL_WIDTH, + }, + },{ + .description = "SECAM", + .std = V4L2_STD_SECAM, + .fps_min = 5, + .fps_max = 25, + .framelines = 625, + .width = VINO_PAL_WIDTH, + .height = VINO_PAL_HEIGHT, + .odd = { + .top = VINO_CLIPPING_START_ODD_PAL, + .left = 0, + .bottom = VINO_CLIPPING_START_ODD_PAL + + VINO_PAL_HEIGHT / 2 - 1, + .right = VINO_PAL_WIDTH, + }, + .even = { + .top = VINO_CLIPPING_START_EVEN_PAL, + .left = 0, + .bottom = VINO_CLIPPING_START_EVEN_PAL + + VINO_PAL_HEIGHT / 2 - 1, + .right = VINO_PAL_WIDTH, + }, + },{ + .description = "NTSC (D1 input)", + .std = V4L2_STD_NTSC, + .fps_min = 6, + .fps_max = 30, + .framelines = 525, + .width = VINO_NTSC_WIDTH, + .height = VINO_NTSC_HEIGHT, + .odd = { + .top = VINO_CLIPPING_START_ODD_D1, + .left = 0, + .bottom = VINO_CLIPPING_START_ODD_D1 + + VINO_NTSC_HEIGHT / 2 - 1, + .right = VINO_NTSC_WIDTH, + }, + .even = { + .top = VINO_CLIPPING_START_EVEN_D1, + .left = 0, + .bottom = VINO_CLIPPING_START_EVEN_D1 + + VINO_NTSC_HEIGHT / 2 - 1, + .right = VINO_NTSC_WIDTH, + }, + } +}; + +#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9 + +struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Gain Control", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = INDYCAM_AGC_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic White Balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = INDYCAM_AWB_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = INDYCAM_GAIN_MIN, + .maximum = INDYCAM_GAIN_MAX, + .step = 1, + .default_value = INDYCAM_GAIN_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Saturation", + .minimum = INDYCAM_RED_SATURATION_MIN, + .maximum = INDYCAM_RED_SATURATION_MAX, + .step = 1, + .default_value = INDYCAM_RED_SATURATION_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 1, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Saturation", + .minimum = INDYCAM_BLUE_SATURATION_MIN, + .maximum = INDYCAM_BLUE_SATURATION_MAX, + .step = 1, + .default_value = INDYCAM_BLUE_SATURATION_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = INDYCAM_RED_BALANCE_MIN, + .maximum = INDYCAM_RED_BALANCE_MAX, + .step = 1, + .default_value = INDYCAM_RED_BALANCE_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = INDYCAM_BLUE_BALANCE_MIN, + .maximum = INDYCAM_BLUE_BALANCE_MAX, + .step = 1, + .default_value = INDYCAM_BLUE_BALANCE_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Shutter Control", + .minimum = INDYCAM_SHUTTER_MIN, + .maximum = INDYCAM_SHUTTER_MAX, + .step = 1, + .default_value = INDYCAM_SHUTTER_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gamma", + .minimum = INDYCAM_GAMMA_MIN, + .maximum = INDYCAM_GAMMA_MAX, + .step = 1, + .default_value = INDYCAM_GAMMA_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + } +}; + +#define VINO_SAA7191_V4L2_CONTROL_COUNT 2 + +struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = SAA7191_HUE_MIN, + .maximum = SAA7191_HUE_MAX, + .step = 1, + .default_value = SAA7191_HUE_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "VTR Time Constant", + .minimum = SAA7191_VTRC_MIN, + .maximum = SAA7191_VTRC_MAX, + .step = 1, + .default_value = SAA7191_VTRC_DEFAULT, + .flags = 0, + .reserved = { 0, 0 }, + } +}; + +/* VINO I2C bus functions */ unsigned i2c_vino_getctrl(void *data) { @@ -112,49 +638,49 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data = */ static int i2c_vino_client_reg(struct i2c_client *client) { - int res = 0; + int ret = 0; - down(&Vino->input_lock); + spin_lock(&vino_drvdata->input_lock); switch (client->driver->id) { case I2C_DRIVERID_SAA7191: - if (Vino->decoder.driver) - res = -EBUSY; + if (vino_drvdata->decoder.driver) + ret = -EBUSY; else - Vino->decoder.driver = client; + vino_drvdata->decoder.driver = client; break; case I2C_DRIVERID_INDYCAM: - if (Vino->camera.driver) - res = -EBUSY; + if (vino_drvdata->camera.driver) + ret = -EBUSY; else - Vino->camera.driver = client; + vino_drvdata->camera.driver = client; break; default: - res = -ENODEV; + ret = -ENODEV; } - up(&Vino->input_lock); + spin_unlock(&vino_drvdata->input_lock); - return res; + return ret; } static int i2c_vino_client_unreg(struct i2c_client *client) { - int res = 0; + int ret = 0; - down(&Vino->input_lock); - if (client == Vino->decoder.driver) { - if (Vino->decoder.owner) - res = -EBUSY; + spin_lock(&vino_drvdata->input_lock); + if (client == vino_drvdata->decoder.driver) { + if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL) + ret = -EBUSY; else - Vino->decoder.driver = NULL; - } else if (client == Vino->camera.driver) { - if (Vino->camera.owner) - res = -EBUSY; + vino_drvdata->decoder.driver = NULL; + } else if (client == vino_drvdata->camera.driver) { + if (vino_drvdata->camera.owner != VINO_NO_CHANNEL) + ret = -EBUSY; else - Vino->camera.driver = NULL; + vino_drvdata->camera.driver = NULL; } - up(&Vino->input_lock); + spin_unlock(&vino_drvdata->input_lock); - return res; + return ret; } static struct i2c_adapter vino_i2c_adapter = @@ -176,172 +702,3591 @@ static int vino_i2c_del_bus(void) return i2c_sgi_del_bus(&vino_i2c_adapter); } +static int i2c_camera_command(unsigned int cmd, void *arg) +{ + return vino_drvdata->camera.driver-> + driver->command(vino_drvdata->camera.driver, + cmd, arg); +} + +static int i2c_decoder_command(unsigned int cmd, void *arg) +{ + return vino_drvdata->decoder.driver-> + driver->command(vino_drvdata->decoder.driver, + cmd, arg); +} + +/* VINO framebuffer/DMA descriptor management */ + +static void vino_free_buffer_with_count(struct vino_framebuffer *fb, + unsigned int count) +{ + unsigned int i; + + dprintk("vino_free_buffer_with_count(): count = %d\n", count); + + for (i = 0; i < count; i++) { + mem_map_unreserve(virt_to_page(fb->desc_table.virtual[i])); + dma_unmap_single(NULL, + fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], + PAGE_SIZE, DMA_FROM_DEVICE); + free_page(fb->desc_table.virtual[i]); + } + + dma_free_coherent(NULL, + VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) * + sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu, + fb->desc_table.dma); + kfree(fb->desc_table.virtual); + + memset(fb, 0, sizeof(struct vino_framebuffer)); +} + +static void vino_free_buffer(struct vino_framebuffer *fb) +{ + vino_free_buffer_with_count(fb, fb->desc_table.page_count); +} + +static int vino_allocate_buffer(struct vino_framebuffer *fb, + unsigned int size) +{ + unsigned int count, i, j; + int ret = 0; + + dprintk("vino_allocate_buffer():\n"); + + if (size < 1) + return -EINVAL; + + memset(fb, 0, sizeof(struct vino_framebuffer)); + + count = ((size / PAGE_SIZE) + 4) & ~3; + + dprintk("vino_allocate_buffer(): size = %d, count = %d\n", + size, count); + + /* allocate memory for table with virtual (page) addresses */ + fb->desc_table.virtual = (unsigned long *) + kmalloc(count * sizeof(unsigned long), GFP_KERNEL); + if (!fb->desc_table.virtual) + return -ENOMEM; + + /* allocate memory for table with dma addresses + * (has space for four extra descriptors) */ + fb->desc_table.dma_cpu = + dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * + sizeof(dma_addr_t), &fb->desc_table.dma, + GFP_KERNEL | GFP_DMA); + if (!fb->desc_table.dma_cpu) { + ret = -ENOMEM; + goto out_free_virtual; + } + + /* allocate pages for the buffer and acquire the according + * dma addresses */ + for (i = 0; i < count; i++) { + dma_addr_t dma_data_addr; + + fb->desc_table.virtual[i] = + get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!fb->desc_table.virtual[i]) { + ret = -ENOBUFS; + break; + } + + dma_data_addr = + dma_map_single(NULL, + (void *)fb->desc_table.virtual[i], + PAGE_SIZE, DMA_FROM_DEVICE); + + for (j = 0; j < VINO_PAGE_RATIO; j++) { + fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = + dma_data_addr + VINO_PAGE_SIZE * j; + } + + mem_map_reserve(virt_to_page(fb->desc_table.virtual[i])); + } + + /* page_count needs to be set anyway, because the descriptor table has + * been allocated according to this number */ + fb->desc_table.page_count = count; + + if (ret) { + /* the descriptor with index i doesn't contain + * a valid address yet */ + vino_free_buffer_with_count(fb, i); + return ret; + } + + //fb->size = size; + fb->size = count * PAGE_SIZE; + fb->data_format = VINO_DATA_FMT_NONE; + + /* set the dma stop-bit for the last (count+1)th descriptor */ + fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; + return 0; + + out_free_virtual: + kfree(fb->desc_table.virtual); + return ret; +} + +#if 0 +/* user buffers not fully implemented yet */ +static int vino_prepare_user_buffer(struct vino_framebuffer *fb, + void *user, + unsigned int size) +{ + unsigned int count, i, j; + int ret = 0; + + dprintk("vino_prepare_user_buffer():\n"); + + if (size < 1) + return -EINVAL; + + memset(fb, 0, sizeof(struct vino_framebuffer)); + + count = ((size / PAGE_SIZE)) & ~3; + + dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n", + size, count); + + /* allocate memory for table with virtual (page) addresses */ + fb->desc_table.virtual = (unsigned long *) + kmalloc(count * sizeof(unsigned long), GFP_KERNEL); + if (!fb->desc_table.virtual) + return -ENOMEM; + + /* allocate memory for table with dma addresses + * (has space for four extra descriptors) */ + fb->desc_table.dma_cpu = + dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) * + sizeof(dma_addr_t), &fb->desc_table.dma, + GFP_KERNEL | GFP_DMA); + if (!fb->desc_table.dma_cpu) { + ret = -ENOMEM; + goto out_free_virtual; + } + + /* allocate pages for the buffer and acquire the according + * dma addresses */ + for (i = 0; i < count; i++) { + dma_addr_t dma_data_addr; + + fb->desc_table.virtual[i] = + get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!fb->desc_table.virtual[i]) { + ret = -ENOBUFS; + break; + } + + dma_data_addr = + dma_map_single(NULL, + (void *)fb->desc_table.virtual[i], + PAGE_SIZE, DMA_FROM_DEVICE); + + for (j = 0; j < VINO_PAGE_RATIO; j++) { + fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] = + dma_data_addr + VINO_PAGE_SIZE * j; + } + + mem_map_reserve(virt_to_page(fb->desc_table.virtual[i])); + } + + /* page_count needs to be set anyway, because the descriptor table has + * been allocated according to this number */ + fb->desc_table.page_count = count; + + if (ret) { + /* the descriptor with index i doesn't contain + * a valid address yet */ + vino_free_buffer_with_count(fb, i); + return ret; + } + + //fb->size = size; + fb->size = count * PAGE_SIZE; + + /* set the dma stop-bit for the last (count+1)th descriptor */ + fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP; + return 0; + + out_free_virtual: + kfree(fb->desc_table.virtual); + return ret; +} +#endif + +static void vino_sync_buffer(struct vino_framebuffer *fb) +{ + int i; + + dprintk("vino_sync_buffer():\n"); + + for (i = 0; i < fb->desc_table.page_count; i++) + dma_sync_single(NULL, + fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], + PAGE_SIZE, DMA_FROM_DEVICE); +} + +/* Framebuffer fifo functions (need to be locked externally) */ + +static void vino_fifo_init(struct vino_framebuffer_fifo *f, + unsigned int length) +{ + f->length = 0; + f->used = 0; + f->head = 0; + f->tail = 0; + + if (length > VINO_FRAMEBUFFER_MAX_COUNT) + length = VINO_FRAMEBUFFER_MAX_COUNT; + + f->length = length; +} + +/* returns true/false */ +static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id) +{ + unsigned int i; + for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) { + if (f->data[i] == id) + return 1; + } + + return 0; +} + +/* returns true/false */ +static int vino_fifo_full(struct vino_framebuffer_fifo *f) +{ + return (f->used == f->length); +} + +static unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f) +{ + return f->used; +} -static void vino_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id) { + if (id >= f->length) { + return VINO_QUEUE_ERROR; + } + + if (vino_fifo_has_id(f, id)) { + return VINO_QUEUE_ERROR; + } + + if (f->used < f->length) { + f->data[f->tail] = id; + f->tail = (f->tail + 1) % f->length; + f->used++; + } else { + return VINO_QUEUE_ERROR; + } + + return 0; } -static int vino_open(struct video_device *dev, int flags) +static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id) { - struct vino_device *videv = (struct vino_device *)dev; + if (f->used > 0) { + *id = f->data[f->head]; + } else { + return VINO_QUEUE_ERROR; + } return 0; } -static void vino_close(struct video_device *dev) +static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id) { - struct vino_device *videv = (struct vino_device *)dev; + if (f->used > 0) { + *id = f->data[f->head]; + f->head = (f->head + 1) % f->length; + f->used--; + } else { + return VINO_QUEUE_ERROR; + } + + return 0; } -static int vino_mmap(struct video_device *dev, const char *adr, - unsigned long size) +/* Framebuffer queue functions */ + +/* execute with queue_lock locked */ +static void vino_queue_free_with_count(struct vino_framebuffer_queue *q, + unsigned int length) { - struct vino_device *videv = (struct vino_device *)dev; + unsigned int i; - return -EINVAL; + q->length = 0; + memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo)); + memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo)); + for (i = 0; i < length; i++) { + dprintk("vino_queue_free_with_count(): freeing buffer %d\n", + i); + vino_free_buffer(q->buffer[i]); + kfree(q->buffer[i]); + } + + q->type = VINO_MEMORY_NONE; + q->magic = 0; } -static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +static void vino_queue_free(struct vino_framebuffer_queue *q) { - struct vino_device *videv = (struct vino_device *)dev; + dprintk("vino_queue_free():\n"); + + if (q->magic != VINO_QUEUE_MAGIC) + return; + if (q->type != VINO_MEMORY_MMAP) + return; + + down(&q->queue_sem); + + vino_queue_free_with_count(q, q->length); + + up(&q->queue_sem); +} + +static int vino_queue_init(struct vino_framebuffer_queue *q, + unsigned int *length) +{ + unsigned int i; + int ret = 0; + + dprintk("vino_queue_init(): length = %d\n", *length); + + if (q->magic == VINO_QUEUE_MAGIC) { + dprintk("vino_queue_init(): queue already initialized!\n"); + return -EINVAL; + } + + if (q->type != VINO_MEMORY_NONE) { + dprintk("vino_queue_init(): queue already initialized!\n"); + return -EINVAL; + } + + if (*length < 1) + return -EINVAL; + + down(&q->queue_sem); + + if (*length > VINO_FRAMEBUFFER_MAX_COUNT) + *length = VINO_FRAMEBUFFER_MAX_COUNT; + + q->length = 0; + + for (i = 0; i < *length; i++) { + dprintk("vino_queue_init(): allocating buffer %d\n", i); + q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer), + GFP_KERNEL); + if (!q->buffer[i]) { + dprintk("vino_queue_init(): kmalloc() failed\n"); + ret = -ENOMEM; + break; + } + + ret = vino_allocate_buffer(q->buffer[i], + VINO_FRAMEBUFFER_SIZE); + if (ret) { + kfree(q->buffer[i]); + dprintk("vino_queue_init(): " + "vino_allocate_buffer() failed\n"); + break; + } + + q->buffer[i]->id = i; + if (i > 0) { + q->buffer[i]->offset = q->buffer[i - 1]->offset + + q->buffer[i - 1]->size; + } else { + q->buffer[i]->offset = 0; + } + + spin_lock_init(&q->buffer[i]->state_lock); + + dprintk("vino_queue_init(): buffer = %d, offset = %d, " + "size = %d\n", i, q->buffer[i]->offset, + q->buffer[i]->size); + } + + if (ret) { + vino_queue_free_with_count(q, i); + *length = 0; + } else { + q->length = *length; + vino_fifo_init(&q->in, q->length); + vino_fifo_init(&q->out, q->length); + q->type = VINO_MEMORY_MMAP; + q->magic = VINO_QUEUE_MAGIC; + } + + up(&q->queue_sem); + + return ret; +} + +static struct vino_framebuffer *vino_queue_add(struct + vino_framebuffer_queue *q, + unsigned int id) +{ + struct vino_framebuffer *ret = NULL; + unsigned int total; + unsigned long flags; + + dprintk("vino_queue_add(): id = %d\n", id); + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) + goto out; + + if (id >= q->length) + goto out; + + /* not needed?: if (vino_fifo_full(&q->out)) { + goto out; + }*/ + /* check that outgoing queue isn't already full + * (or that it won't become full) */ + total = vino_fifo_get_used(&q->in) + + vino_fifo_get_used(&q->out); + if (total >= q->length) + goto out; + + if (vino_fifo_enqueue(&q->in, id)) + goto out; + + ret = q->buffer[id]; + +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static struct vino_framebuffer *vino_queue_transfer(struct + vino_framebuffer_queue *q) +{ + struct vino_framebuffer *ret = NULL; + struct vino_framebuffer *fb; + int id; + unsigned long flags; + + dprintk("vino_queue_transfer():\n"); + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) + goto out; + + // now this actually removes an entry from the incoming queue + if (vino_fifo_dequeue(&q->in, &id)) { + goto out; + } + + dprintk("vino_queue_transfer(): id = %d\n", id); + fb = q->buffer[id]; + + // we have already checked that the outgoing queue is not full, but... + if (vino_fifo_enqueue(&q->out, id)) { + printk(KERN_ERR "vino_queue_transfer(): " + "outgoing queue is full, this shouldn't happen!\n"); + goto out; + } + + ret = fb; +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +/* returns true/false */ +static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q, + unsigned int id) +{ + int ret = 0; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) + goto out; + + ret = vino_fifo_has_id(&q->in, id); + +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +/* returns true/false */ +static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q, + unsigned int id) +{ + int ret = 0; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) + goto out; + + ret = vino_fifo_has_id(&q->out, id); + +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static int vino_queue_get_incoming(struct vino_framebuffer_queue *q, + unsigned int *used) +{ + int ret = 0; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return VINO_QUEUE_ERROR; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) { + ret = VINO_QUEUE_ERROR; + goto out; + } + + *used = vino_fifo_get_used(&q->in); + +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q, + unsigned int *used) +{ + int ret = 0; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return VINO_QUEUE_ERROR; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) { + ret = VINO_QUEUE_ERROR; + goto out; + } + + *used = vino_fifo_get_used(&q->out); + +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static int vino_queue_get_total(struct vino_framebuffer_queue *q, + unsigned int *total) +{ + int ret = 0; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return VINO_QUEUE_ERROR; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) { + ret = VINO_QUEUE_ERROR; + goto out; + } + + *total = vino_fifo_get_used(&q->in) + + vino_fifo_get_used(&q->out); + +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static struct vino_framebuffer *vino_queue_peek(struct + vino_framebuffer_queue *q, + unsigned int *id) +{ + struct vino_framebuffer *ret = NULL; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) + goto out; + + if (vino_fifo_peek(&q->in, id)) { + goto out; + } + + ret = q->buffer[*id]; +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static struct vino_framebuffer *vino_queue_remove(struct + vino_framebuffer_queue *q, + unsigned int *id) +{ + struct vino_framebuffer *ret = NULL; + unsigned long flags; + dprintk("vino_queue_remove():\n"); + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) + goto out; + + if (vino_fifo_dequeue(&q->out, id)) { + goto out; + } + + dprintk("vino_queue_remove(): id = %d\n", *id); + ret = q->buffer[*id]; +out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static struct +vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q, + unsigned int id) +{ + struct vino_framebuffer *ret = NULL; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + + if (q->length == 0) + goto out; + + if (id >= q->length) + goto out; + + ret = q->buffer[id]; + out: + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q) +{ + unsigned int length = 0; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return length; + } + + spin_lock_irqsave(&q->queue_lock, flags); + length = q->length; + spin_unlock_irqrestore(&q->queue_lock, flags); + + return length; +} + +static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q) +{ + unsigned int i; + int ret = 0; + unsigned long flags; + + if (q->magic != VINO_QUEUE_MAGIC) { + return ret; + } + + spin_lock_irqsave(&q->queue_lock, flags); + for (i = 0; i < q->length; i++) { + if (q->buffer[i]->map_count > 0) { + ret = 1; + break; + } + } + spin_unlock_irqrestore(&q->queue_lock, flags); + + return ret; +} + +/* VINO functions */ + +/* execute with input_lock locked */ +static void vino_update_line_size(struct vino_channel_settings *vcs) +{ + unsigned int w = vcs->clipping.right - vcs->clipping.left; + unsigned int d = vcs->decimation; + unsigned int bpp = vino_data_formats[vcs->data_format].bpp; + unsigned int lsize; + + dprintk("update_line_size(): before: w = %d, d = %d, " + "line_size = %d\n", w, d, vcs->line_size); + /* line size must be multiple of 8 bytes */ + lsize = (bpp * (w / d)) & ~7; + w = (lsize / bpp) * d; + + vcs->clipping.right = vcs->clipping.left + w; + vcs->line_size = lsize; + dprintk("update_line_size(): after: w = %d, d = %d, " + "line_size = %d\n", w, d, vcs->line_size); +} + +/* execute with input_lock locked */ +static void vino_set_clipping(struct vino_channel_settings *vcs, + unsigned int x, unsigned int y, + unsigned int w, unsigned int h) +{ + unsigned int maxwidth, maxheight; + unsigned int d; + + maxwidth = vino_data_norms[vcs->data_norm].width; + maxheight = vino_data_norms[vcs->data_norm].height; + d = vcs->decimation; + + y &= ~1; /* odd/even fields */ + + if (x > maxwidth) { + x = 0; + } + if (y > maxheight) { + y = 0; + } + + if (((w / d) < VINO_MIN_WIDTH) + || ((h / d) < VINO_MIN_HEIGHT)) { + w = VINO_MIN_WIDTH * d; + h = VINO_MIN_HEIGHT * d; + } + + if ((x + w) > maxwidth) { + w = maxwidth - x; + if ((w / d) < VINO_MIN_WIDTH) + x = maxwidth - VINO_MIN_WIDTH * d; + } + if ((y + h) > maxheight) { + h = maxheight - y; + if ((h / d) < VINO_MIN_HEIGHT) + y = maxheight - VINO_MIN_HEIGHT * d; + } + + vcs->clipping.left = x; + vcs->clipping.top = y; + vcs->clipping.right = x + w; + vcs->clipping.bottom = y + h; + + vino_update_line_size(vcs); + + dprintk("clipping %d, %d, %d, %d / %d - %d\n", + vcs->clipping.left, vcs->clipping.top, vcs->clipping.right, + vcs->clipping.bottom, vcs->decimation, vcs->line_size); +} + +/* execute with input_lock locked */ +static void vino_set_default_clipping(struct vino_channel_settings *vcs) +{ + vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width, + vino_data_norms[vcs->data_norm].height); +} + +/* execute with input_lock locked */ +static void vino_set_scaling(struct vino_channel_settings *vcs, + unsigned int w, unsigned int h) +{ + unsigned int x, y, curw, curh, d; + + x = vcs->clipping.left; + y = vcs->clipping.top; + curw = vcs->clipping.right - vcs->clipping.left; + curh = vcs->clipping.bottom - vcs->clipping.top; + + d = max(curw / w, curh / h); + + dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n", + w, h, curw, curh, d); + + if (d < 1) { + d = 1; + } + if (d > 8) { + d = 8; + } + + vcs->decimation = d; + vino_set_clipping(vcs, x, y, w * d, h * d); + + dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left, + vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom, + vcs->decimation, vcs->line_size); +} + +/* execute with input_lock locked */ +static void vino_reset_scaling(struct vino_channel_settings *vcs) +{ + vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left, + vcs->clipping.bottom - vcs->clipping.top); +} + +/* execute with input_lock locked */ +static void vino_set_framerate(struct vino_channel_settings *vcs, + unsigned int fps) +{ + unsigned int mask; + + switch (vcs->data_norm) { + case VINO_DATA_NORM_NTSC: + case VINO_DATA_NORM_D1: + fps = (unsigned int)(fps / 6) * 6; // FIXME: round! + + if (fps < vino_data_norms[vcs->data_norm].fps_min) + fps = vino_data_norms[vcs->data_norm].fps_min; + if (fps > vino_data_norms[vcs->data_norm].fps_max) + fps = vino_data_norms[vcs->data_norm].fps_max; + + switch (fps) { + case 6: + mask = 0x003; + break; + case 12: + mask = 0x0c3; + break; + case 18: + mask = 0x333; + break; + case 24: + mask = 0x3ff; + break; + case 30: + mask = 0xfff; + break; + default: + mask = VINO_FRAMERT_FULL; + } + vcs->framert_reg = VINO_FRAMERT_RT(mask); + break; + case VINO_DATA_NORM_PAL: + case VINO_DATA_NORM_SECAM: + fps = (unsigned int)(fps / 5) * 5; // FIXME: round! + + if (fps < vino_data_norms[vcs->data_norm].fps_min) + fps = vino_data_norms[vcs->data_norm].fps_min; + if (fps > vino_data_norms[vcs->data_norm].fps_max) + fps = vino_data_norms[vcs->data_norm].fps_max; + + switch (fps) { + case 5: + mask = 0x003; + break; + case 10: + mask = 0x0c3; + break; + case 15: + mask = 0x333; + break; + case 20: + mask = 0x0ff; + break; + case 25: + mask = 0x3ff; + break; + default: + mask = VINO_FRAMERT_FULL; + } + vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL; + break; + } + + vcs->fps = fps; +} + +/* execute with input_lock locked */ +static void vino_set_default_framerate(struct vino_channel_settings *vcs) +{ + vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max); +} + +/* + * Prepare VINO for DMA transfer... + * (execute only with vino_lock and input_lock locked) + */ +static int vino_dma_setup(struct vino_channel_settings *vcs, + struct vino_framebuffer *fb) +{ + u32 ctrl, intr; + struct sgi_vino_channel *ch; + const struct vino_data_norm *norm; + + dprintk("vino_dma_setup():\n"); + + vcs->field = 0; + fb->frame_counter = 0; + + ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; + norm = &vino_data_norms[vcs->data_norm]; + + ch->page_index = 0; + ch->line_count = 0; + + /* VINO line size register is set 8 bytes less than actual */ + ch->line_size = vcs->line_size - 8; + + /* let VINO know where to transfer data */ + ch->start_desc_tbl = fb->desc_table.dma; + ch->next_4_desc = fb->desc_table.dma; + + /* give vino time to fetch the first four descriptors, 5 usec + * should be more than enough time */ + udelay(VINO_DESC_FETCH_DELAY); + + /* set the alpha register */ + ch->alpha = vcs->alpha; + + /* set clipping registers */ + ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) | + VINO_CLIP_EVEN(norm->even.top + + vcs->clipping.top / 2) | + VINO_CLIP_X(vcs->clipping.left); + ch->clip_end = VINO_CLIP_ODD(norm->odd.top + + vcs->clipping.bottom / 2 - 1) | + VINO_CLIP_EVEN(norm->even.top + + vcs->clipping.bottom / 2 - 1) | + VINO_CLIP_X(vcs->clipping.right); + /* FIXME: end-of-field bug workaround + VINO_CLIP_X(VINO_PAL_WIDTH); + */ + + /* set the size of actual content in the buffer (DECIMATION !) */ + fb->data_size = ((vcs->clipping.right - vcs->clipping.left) / + vcs->decimation) * + ((vcs->clipping.bottom - vcs->clipping.top) / + vcs->decimation) * + vino_data_formats[vcs->data_format].bpp; + + ch->frame_rate = vcs->framert_reg; + + ctrl = vino->control; + intr = vino->intr_status; + + if (vcs->channel == VINO_CHANNEL_A) { + /* All interrupt conditions for this channel was cleared + * so clear the interrupt status register and enable + * interrupts */ + intr &= ~VINO_INTSTAT_A; + ctrl |= VINO_CTRL_A_INT; + + /* enable synchronization */ + ctrl |= VINO_CTRL_A_SYNC_ENBL; + + /* enable frame assembly */ + ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL; + + /* set decimation used */ + if (vcs->decimation < 2) + ctrl &= ~VINO_CTRL_A_DEC_ENBL; + else { + ctrl |= VINO_CTRL_A_DEC_ENBL; + ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK; + ctrl |= (vcs->decimation - 1) << + VINO_CTRL_A_DEC_SCALE_SHIFT; + } + + /* select input interface */ + if (vcs->input == VINO_INPUT_D1) + ctrl |= VINO_CTRL_A_SELECT; + else + ctrl &= ~VINO_CTRL_A_SELECT; + + /* palette */ + ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB | + VINO_CTRL_A_DITHER); + } else { + intr &= ~VINO_INTSTAT_B; + ctrl |= VINO_CTRL_B_INT; + + ctrl |= VINO_CTRL_B_SYNC_ENBL; + ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL; + + if (vcs->decimation < 2) + ctrl &= ~VINO_CTRL_B_DEC_ENBL; + else { + ctrl |= VINO_CTRL_B_DEC_ENBL; + ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK; + ctrl |= (vcs->decimation - 1) << + VINO_CTRL_B_DEC_SCALE_SHIFT; + + } + if (vcs->input == VINO_INPUT_D1) + ctrl |= VINO_CTRL_B_SELECT; + else + ctrl &= ~VINO_CTRL_B_SELECT; + + ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB | + VINO_CTRL_B_DITHER); + } + + /* set palette */ + fb->data_format = vcs->data_format; + + switch (vcs->data_format) { + case VINO_DATA_FMT_GREY: + ctrl |= (vcs->channel == VINO_CHANNEL_A) ? + VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY; + break; + case VINO_DATA_FMT_RGB32: + ctrl |= (vcs->channel == VINO_CHANNEL_A) ? + VINO_CTRL_A_RGB : VINO_CTRL_B_RGB; + break; + case VINO_DATA_FMT_YUV: + /* nothing needs to be done */ + break; + case VINO_DATA_FMT_RGB332: + ctrl |= (vcs->channel == VINO_CHANNEL_A) ? + VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER : + VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER; + break; + } + + vino->intr_status = intr; + vino->control = ctrl; + + return 0; +} + +/* (execute only with vino_lock locked) */ +static void vino_dma_start(struct vino_channel_settings *vcs) +{ + u32 ctrl = vino->control; + + dprintk("vino_dma_start():\n"); + ctrl |= (vcs->channel == VINO_CHANNEL_A) ? + VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL; + vino->control = ctrl; +} + +/* (execute only with vino_lock locked) */ +static void vino_dma_stop(struct vino_channel_settings *vcs) +{ + u32 ctrl = vino->control; + + ctrl &= (vcs->channel == VINO_CHANNEL_A) ? + ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL; + vino->control = ctrl; + dprintk("vino_dma_stop():\n"); +} + +/* + * Load dummy page to descriptor registers. This prevents generating of + * spurious interrupts. (execute only with vino_lock locked) + */ +static void vino_clear_interrupt(struct vino_channel_settings *vcs) +{ + struct sgi_vino_channel *ch; + + ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b; + + ch->page_index = 0; + ch->line_count = 0; + + ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma; + ch->next_4_desc = vino_drvdata->dummy_desc_table.dma; + + udelay(VINO_DESC_FETCH_DELAY); + dprintk("channel %c clear interrupt condition\n", + (vcs->channel == VINO_CHANNEL_A) ? 'A':'B'); +} + +static int vino_capture(struct vino_channel_settings *vcs, + struct vino_framebuffer *fb) +{ + int err = 0; + unsigned long flags, flags2; + + spin_lock_irqsave(&fb->state_lock, flags); + + if (fb->state == VINO_FRAMEBUFFER_IN_USE) + err = -EBUSY; + fb->state = VINO_FRAMEBUFFER_IN_USE; + + spin_unlock_irqrestore(&fb->state_lock, flags); + + if (err) + return err; + + spin_lock_irqsave(&vino_drvdata->vino_lock, flags); + spin_lock_irqsave(&vino_drvdata->input_lock, flags2); + + vino_dma_setup(vcs, fb); + vino_dma_start(vcs); + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2); + spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); + + return err; +} + +static +struct vino_framebuffer *vino_capture_enqueue(struct + vino_channel_settings *vcs, + unsigned int index) +{ + struct vino_framebuffer *fb; + unsigned long flags; + + dprintk("vino_capture_enqueue():\n"); + + spin_lock_irqsave(&vcs->capture_lock, flags); + + fb = vino_queue_add(&vcs->fb_queue, index); + if (fb == NULL) { + dprintk("vino_capture_enqueue(): vino_queue_add() failed, " + "queue full?\n"); + goto out; + } +out: + spin_unlock_irqrestore(&vcs->capture_lock, flags); + + return fb; +} + +static int vino_capture_next(struct vino_channel_settings *vcs, int start) +{ + struct vino_framebuffer *fb; + unsigned int incoming, id; + int err = 0; + unsigned long flags, flags2; + + dprintk("vino_capture_next():\n"); + + spin_lock_irqsave(&vcs->capture_lock, flags); + + if (start) { + /* start capture only if capture isn't in progress already */ + if (vcs->capturing) { + spin_unlock_irqrestore(&vcs->capture_lock, flags); + return 0; + } + + } else { + /* capture next frame: + * stop capture if capturing is not set */ + if (!vcs->capturing) { + spin_unlock_irqrestore(&vcs->capture_lock, flags); + return 0; + } + } + + err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); + if (err) { + dprintk("vino_capture_next(): vino_queue_get_incoming() " + "failed\n"); + err = -EINVAL; + goto out; + } + if (incoming == 0) { + dprintk("vino_capture_next(): no buffers available\n"); + goto out; + } + + fb = vino_queue_peek(&vcs->fb_queue, &id); + if (fb == NULL) { + dprintk("vino_capture_next(): vino_queue_peek() failed\n"); + err = -EINVAL; + goto out; + } + + spin_lock_irqsave(&fb->state_lock, flags2); + fb->state = VINO_FRAMEBUFFER_UNUSED; + spin_unlock_irqrestore(&fb->state_lock, flags2); + + if (start) { + vcs->capturing = 1; + } + + spin_unlock_irqrestore(&vcs->capture_lock, flags); + + err = vino_capture(vcs, fb); + + return err; + +out: + vcs->capturing = 0; + spin_unlock_irqrestore(&vcs->capture_lock, flags); + + return err; +} + +static int vino_is_capturing(struct vino_channel_settings *vcs) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&vcs->capture_lock, flags); + + ret = vcs->capturing; + + spin_unlock_irqrestore(&vcs->capture_lock, flags); + + return ret; +} + +/* waits until a frame is captured */ +static int vino_wait_for_frame(struct vino_channel_settings *vcs) +{ + wait_queue_t wait; + int err = 0; + + dprintk("vino_wait_for_frame():\n"); + + init_waitqueue_entry(&wait, current); + /* add ourselves into wait queue */ + add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); + /* and set current state */ + set_current_state(TASK_INTERRUPTIBLE); + + /* to ensure that schedule_timeout will return immediately + * if VINO interrupt was triggred meanwhile */ + schedule_timeout(HZ / 10); + + if (signal_pending(current)) + err = -EINTR; + + remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait); + + dprintk("vino_wait_for_frame(): waiting for frame %s\n", + err ? "failed" : "ok"); + + return err; +} + +/* the function assumes that PAGE_SIZE % 4 == 0 */ +static void vino_convert_to_rgba(struct vino_framebuffer *fb) { + unsigned char *pageptr; + unsigned int page, i; + unsigned char a; + + for (page = 0; page < fb->desc_table.page_count; page++) { + pageptr = (unsigned char *)fb->desc_table.virtual[page]; + + for (i = 0; i < PAGE_SIZE; i += 4) { + a = pageptr[0]; + pageptr[0] = pageptr[3]; + pageptr[1] = pageptr[2]; + pageptr[2] = pageptr[1]; + pageptr[3] = a; + pageptr += 4; + } + } +} + +/* checks if the buffer is in correct state and syncs data */ +static int vino_check_buffer(struct vino_channel_settings *vcs, + struct vino_framebuffer *fb) +{ + int err = 0; + unsigned long flags; + + dprintk("vino_check_buffer():\n"); + + spin_lock_irqsave(&fb->state_lock, flags); + switch (fb->state) { + case VINO_FRAMEBUFFER_IN_USE: + err = -EIO; + break; + case VINO_FRAMEBUFFER_READY: + vino_sync_buffer(fb); + fb->state = VINO_FRAMEBUFFER_UNUSED; + break; + default: + err = -EINVAL; + } + spin_unlock_irqrestore(&fb->state_lock, flags); + + if (!err) { + if (vino_pixel_conversion + && (fb->data_format == VINO_DATA_FMT_RGB32)) { + vino_convert_to_rgba(fb); + } + } else if (err && (err != -EINVAL)) { + dprintk("vino_check_buffer(): buffer not ready\n"); + + spin_lock_irqsave(&vino_drvdata->vino_lock, flags); + vino_dma_stop(vcs); + vino_clear_interrupt(vcs); + spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); + } + + return err; +} + +/* forcefully terminates capture */ +static void vino_capture_stop(struct vino_channel_settings *vcs) +{ + unsigned int incoming = 0, outgoing = 0, id; + unsigned long flags, flags2; + + dprintk("vino_capture_stop():\n"); + + spin_lock_irqsave(&vcs->capture_lock, flags); + /* unset capturing to stop queue processing */ + vcs->capturing = 0; + + spin_lock_irqsave(&vino_drvdata->vino_lock, flags2); + + vino_dma_stop(vcs); + vino_clear_interrupt(vcs); + + spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2); + + /* remove all items from the queue */ + if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { + dprintk("vino_capture_stop(): " + "vino_queue_get_incoming() failed\n"); + goto out; + } + while (incoming > 0) { + vino_queue_transfer(&vcs->fb_queue); + + if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) { + dprintk("vino_capture_stop(): " + "vino_queue_get_incoming() failed\n"); + goto out; + } + } + + if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { + dprintk("vino_capture_stop(): " + "vino_queue_get_outgoing() failed\n"); + goto out; + } + while (outgoing > 0) { + vino_queue_remove(&vcs->fb_queue, &id); + + if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { + dprintk("vino_capture_stop(): " + "vino_queue_get_outgoing() failed\n"); + goto out; + } + } + +out: + spin_unlock_irqrestore(&vcs->capture_lock, flags); +} + +static int vino_capture_failed(struct vino_channel_settings *vcs) +{ + struct vino_framebuffer *fb; + unsigned long flags; + unsigned int i; + int ret; + + dprintk("vino_capture_failed():\n"); + + spin_lock_irqsave(&vino_drvdata->vino_lock, flags); + + vino_dma_stop(vcs); + vino_clear_interrupt(vcs); + + spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags); + + ret = vino_queue_get_incoming(&vcs->fb_queue, &i); + if (ret == VINO_QUEUE_ERROR) { + dprintk("vino_queue_get_incoming() failed\n"); + return -EINVAL; + } + if (i == 0) { + /* no buffers to process */ + return 0; + } + + fb = vino_queue_peek(&vcs->fb_queue, &i); + if (fb == NULL) { + dprintk("vino_queue_peek() failed\n"); + return -EINVAL; + } + + spin_lock_irqsave(&fb->state_lock, flags); + if (fb->state == VINO_FRAMEBUFFER_IN_USE) { + fb->state = VINO_FRAMEBUFFER_UNUSED; + vino_queue_transfer(&vcs->fb_queue); + vino_queue_remove(&vcs->fb_queue, &i); + /* we should actually discard the newest frame, + * but who cares ... */ + } + spin_unlock_irqrestore(&fb->state_lock, flags); + + return 0; +} + +static void vino_frame_done(struct vino_channel_settings *vcs, + unsigned int fc) +{ + struct vino_framebuffer *fb; + unsigned long flags; + + spin_lock_irqsave(&vcs->capture_lock, flags); + fb = vino_queue_transfer(&vcs->fb_queue); + if (!fb) { + spin_unlock_irqrestore(&vcs->capture_lock, flags); + dprintk("vino_frame_done(): vino_queue_transfer() failed!\n"); + return; + } + spin_unlock_irqrestore(&vcs->capture_lock, flags); + + fb->frame_counter = fc; + do_gettimeofday(&fb->timestamp); + + spin_lock_irqsave(&fb->state_lock, flags); + if (fb->state == VINO_FRAMEBUFFER_IN_USE) + fb->state = VINO_FRAMEBUFFER_READY; + spin_unlock_irqrestore(&fb->state_lock, flags); + + wake_up(&vcs->fb_queue.frame_wait_queue); + + vino_capture_next(vcs, 0); +} + +static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 intr; + unsigned int fc_a, fc_b; + int done_a = 0; + int done_b = 0; + + spin_lock(&vino_drvdata->vino_lock); + + intr = vino->intr_status; + fc_a = vino->a.field_counter / 2; + fc_b = vino->b.field_counter / 2; + + // TODO: handle error-interrupts in some special way ? + + if (intr & VINO_INTSTAT_A) { + if (intr & VINO_INTSTAT_A_EOF) { + vino_drvdata->a.field++; + if (vino_drvdata->a.field > 1) { + vino_dma_stop(&vino_drvdata->a); + vino_clear_interrupt(&vino_drvdata->a); + vino_drvdata->a.field = 0; + done_a = 1; + } + dprintk("intr: channel A end-of-field interrupt: " + "%04x\n", intr); + } else { + vino_dma_stop(&vino_drvdata->a); + vino_clear_interrupt(&vino_drvdata->a); + done_a = 1; + dprintk("channel A error interrupt: %04x\n", intr); + } + } + if (intr & VINO_INTSTAT_B) { + if (intr & VINO_INTSTAT_B_EOF) { + vino_drvdata->b.field++; + if (vino_drvdata->b.field > 1) { + vino_dma_stop(&vino_drvdata->b); + vino_clear_interrupt(&vino_drvdata->b); + vino_drvdata->b.field = 0; + done_b = 1; + } + dprintk("intr: channel B end-of-field interrupt: " + "%04x\n", intr); + } else { + vino_dma_stop(&vino_drvdata->b); + vino_clear_interrupt(&vino_drvdata->b); + done_b = 1; + dprintk("channel B error interrupt: %04x\n", intr); + } + } + + /* always remember to clear interrupt status */ + vino->intr_status = ~intr; + + spin_unlock(&vino_drvdata->vino_lock); + + if (done_a) { + vino_frame_done(&vino_drvdata->a, fc_a); + dprintk("channel A frame done, interrupt: %d\n", intr); + } + if (done_b) { + vino_frame_done(&vino_drvdata->b, fc_b); + dprintk("channel B frame done, interrupt: %d\n", intr); + } - return -EINVAL; + return IRQ_HANDLED; } -static const struct video_device vino_device = { +/* VINO video input management */ + +static int vino_get_saa7191_input(int input) +{ + switch (input) { + case VINO_INPUT_COMPOSITE: + return SAA7191_INPUT_COMPOSITE; + case VINO_INPUT_SVIDEO: + return SAA7191_INPUT_SVIDEO; + default: + printk(KERN_ERR "VINO: vino_get_saa7191_input(): " + "invalid input!\n"); + return -1; + } +} + +static int vino_get_saa7191_norm(int norm) +{ + switch (norm) { + case VINO_DATA_NORM_AUTO: + return SAA7191_NORM_AUTO; + case VINO_DATA_NORM_PAL: + return SAA7191_NORM_PAL; + case VINO_DATA_NORM_NTSC: + return SAA7191_NORM_NTSC; + case VINO_DATA_NORM_SECAM: + return SAA7191_NORM_SECAM; + default: + printk(KERN_ERR "VINO: vino_get_saa7191_norm(): " + "invalid norm!\n"); + return -1; + } +} + +/* execute with input_lock locked */ +static int vino_is_input_owner(struct vino_channel_settings *vcs) +{ + switch(vcs->input) { + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: + return (vino_drvdata->decoder.owner == vcs->channel); + case VINO_INPUT_D1: + return (vino_drvdata->camera.owner == vcs->channel); + default: + return 0; + } +} + +static int vino_acquire_input(struct vino_channel_settings *vcs) +{ + int ret = 0; + + dprintk("vino_acquire_input():\n"); + + spin_lock(&vino_drvdata->input_lock); + + /* First try D1 and then SAA7191 */ + if (vino_drvdata->camera.driver + && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) { + if (i2c_use_client(vino_drvdata->camera.driver)) { + ret = -ENODEV; + goto out; + } + + vino_drvdata->camera.owner = vcs->channel; + vcs->input = VINO_INPUT_D1; + vcs->data_norm = VINO_DATA_NORM_D1; + } else if (vino_drvdata->decoder.driver + && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) { + int saa7191_input; + int saa7191_norm; + + if (i2c_use_client(vino_drvdata->decoder.driver)) { + ret = -ENODEV; + goto out; + } + + vino_drvdata->decoder.owner = vcs->channel; + vcs->input = VINO_INPUT_COMPOSITE; + vcs->data_norm = VINO_DATA_NORM_PAL; + + saa7191_input = vino_get_saa7191_input(vcs->input); + i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input); + + saa7191_norm = vino_get_saa7191_norm(vcs->data_norm); + i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm); + } else { + vcs->input = (vcs->channel == VINO_CHANNEL_A) ? + vino_drvdata->b.input : vino_drvdata->a.input; + vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ? + vino_drvdata->b.data_norm : vino_drvdata->a.data_norm; + } + + if (vcs->input == VINO_INPUT_NONE) { + ret = -ENODEV; + goto out; + } + + if (vino_is_input_owner(vcs)) { + vino_set_default_clipping(vcs); + vino_set_default_framerate(vcs); + } + + dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name); + +out: + spin_unlock(&vino_drvdata->input_lock); + + return ret; +} + +static int vino_set_input(struct vino_channel_settings *vcs, int input) +{ + struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? + &vino_drvdata->b : &vino_drvdata->a; + int ret = 0; + + dprintk("vino_set_input():\n"); + + spin_lock(&vino_drvdata->input_lock); + + if (vcs->input == input) + goto out; + + switch(input) { + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: + if (!vino_drvdata->decoder.driver) { + ret = -EINVAL; + goto out; + } + + if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) { + if (i2c_use_client(vino_drvdata->decoder.driver)) { + ret = -ENODEV; + goto out; + } + vino_drvdata->decoder.owner = vcs->channel; + } + + if (vino_drvdata->decoder.owner == vcs->channel) { + int saa7191_input; + int saa7191_norm; + + vcs->input = input; + vcs->data_norm = VINO_DATA_NORM_PAL; + + saa7191_input = vino_get_saa7191_input(vcs->input); + i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input); + saa7191_norm = vino_get_saa7191_norm(vcs->data_norm); + i2c_decoder_command(DECODER_SAA7191_SET_NORM, + &saa7191_norm); + } else { + if (vcs2->input != input) { + ret = -EBUSY; + goto out; + } + + vcs->input = input; + vcs->data_norm = vcs2->data_norm; + } + + if (vino_drvdata->camera.owner == vcs->channel) { + /* Transfer the ownership or release the input */ + if (vcs2->input == VINO_INPUT_D1) { + vino_drvdata->camera.owner = vcs2->channel; + } else { + i2c_release_client(vino_drvdata-> + camera.driver); + vino_drvdata->camera.owner = VINO_NO_CHANNEL; + } + } + break; + case VINO_INPUT_D1: + if (!vino_drvdata->camera.driver) { + ret = -EINVAL; + goto out; + } + + if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) { + if (i2c_use_client(vino_drvdata->camera.driver)) { + ret = -ENODEV; + goto out; + } + vino_drvdata->camera.owner = vcs->channel; + } + + if (vino_drvdata->decoder.owner == vcs->channel) { + /* Transfer the ownership or release the input */ + if ((vcs2->input == VINO_INPUT_COMPOSITE) || + (vcs2->input == VINO_INPUT_SVIDEO)) { + vino_drvdata->decoder.owner = vcs2->channel; + } else { + i2c_release_client(vino_drvdata-> + decoder.driver); + vino_drvdata->decoder.owner = VINO_NO_CHANNEL; + } + } + + vcs->input = input; + vcs->data_norm = VINO_DATA_NORM_D1; + break; + default: + ret = -EINVAL; + goto out; + } + + vino_set_default_clipping(vcs); + vino_set_default_framerate(vcs); + + dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name); + +out: + spin_unlock(&vino_drvdata->input_lock); + + return ret; +} + +static void vino_release_input(struct vino_channel_settings *vcs) +{ + struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? + &vino_drvdata->b : &vino_drvdata->a; + + dprintk("vino_release_input():\n"); + + spin_lock(&vino_drvdata->input_lock); + + /* Release ownership of the channel + * and if the other channel takes input from + * the same source, transfer the ownership */ + if (vino_drvdata->camera.owner == vcs->channel) { + if (vcs2->input == VINO_INPUT_D1) { + vino_drvdata->camera.owner = vcs2->channel; + } else { + i2c_release_client(vino_drvdata->camera.driver); + vino_drvdata->camera.owner = VINO_NO_CHANNEL; + } + } else if (vino_drvdata->decoder.owner == vcs->channel) { + if ((vcs2->input == VINO_INPUT_COMPOSITE) || + (vcs2->input == VINO_INPUT_SVIDEO)) { + vino_drvdata->decoder.owner = vcs2->channel; + } else { + i2c_release_client(vino_drvdata->decoder.driver); + vino_drvdata->decoder.owner = VINO_NO_CHANNEL; + } + } + vcs->input = VINO_INPUT_NONE; + + spin_unlock(&vino_drvdata->input_lock); +} + +/* execute with input_lock locked */ +static int vino_set_data_norm(struct vino_channel_settings *vcs, + unsigned int data_norm) +{ + int saa7191_norm; + + switch (vcs->input) { + case VINO_INPUT_D1: + /* only one "norm" supported */ + if (data_norm != VINO_DATA_NORM_D1) + return -EINVAL; + break; + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: + + saa7191_norm = vino_get_saa7191_norm(data_norm); + + i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm); + vcs->data_norm = data_norm; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* V4L2 helper functions */ + +static int vino_find_data_format(__u32 pixelformat) +{ + int i; + + for (i = 0; i < VINO_DATA_FMT_COUNT; i++) { + if (vino_data_formats[i].pixelformat == pixelformat) + return i; + } + + return VINO_DATA_FMT_NONE; +} + +static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index) +{ + int data_norm = VINO_DATA_NORM_NONE; + + spin_lock(&vino_drvdata->input_lock); + switch(vcs->input) { + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: + if (index == 0) { + data_norm = VINO_DATA_NORM_PAL; + } else if (index == 1) { + data_norm = VINO_DATA_NORM_NTSC; + } else if (index == 2) { + data_norm = VINO_DATA_NORM_SECAM; + } + break; + case VINO_INPUT_D1: + if (index == 0) { + data_norm = VINO_DATA_NORM_D1; + } + break; + } + spin_unlock(&vino_drvdata->input_lock); + + return data_norm; +} + +static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index) +{ + int input = VINO_INPUT_NONE; + + spin_lock(&vino_drvdata->input_lock); + if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) { + switch (index) { + case 0: + input = VINO_INPUT_COMPOSITE; + break; + case 1: + input = VINO_INPUT_SVIDEO; + break; + case 2: + input = VINO_INPUT_D1; + break; + } + } else if (vino_drvdata->decoder.driver) { + switch (index) { + case 0: + input = VINO_INPUT_COMPOSITE; + break; + case 1: + input = VINO_INPUT_SVIDEO; + break; + } + } else if (vino_drvdata->camera.driver) { + switch (index) { + case 0: + input = VINO_INPUT_D1; + break; + } + } + spin_unlock(&vino_drvdata->input_lock); + + return input; +} + +/* execute with input_lock locked */ +static __u32 vino_find_input_index(struct vino_channel_settings *vcs) +{ + __u32 index = 0; + // FIXME: detect when no inputs available + + if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) { + switch (vcs->input) { + case VINO_INPUT_COMPOSITE: + index = 0; + break; + case VINO_INPUT_SVIDEO: + index = 1; + break; + case VINO_INPUT_D1: + index = 2; + break; + } + } else if (vino_drvdata->decoder.driver) { + switch (vcs->input) { + case VINO_INPUT_COMPOSITE: + index = 0; + break; + case VINO_INPUT_SVIDEO: + index = 1; + break; + } + } else if (vino_drvdata->camera.driver) { + switch (vcs->input) { + case VINO_INPUT_D1: + index = 0; + break; + } + } + + return index; +} + +/* V4L2 ioctls */ + +static void vino_v4l2_querycap(struct v4l2_capability *cap) +{ + memset(cap, 0, sizeof(struct v4l2_capability)); + + strcpy(cap->driver, vino_driver_name); + strcpy(cap->card, vino_driver_description); + strcpy(cap->bus_info, vino_bus_name); + cap->version = VINO_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING; + // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE +} + +static int vino_v4l2_enuminput(struct vino_channel_settings *vcs, + struct v4l2_input *i) +{ + __u32 index = i->index; + int input; + dprintk("requested index = %d\n", index); + + input = vino_enum_input(vcs, index); + if (input == VINO_INPUT_NONE) + return -EINVAL; + + memset(i, 0, sizeof(struct v4l2_input)); + + i->index = index; + i->type = V4L2_INPUT_TYPE_CAMERA; + i->std = vino_inputs[input].std; + strcpy(i->name, vino_inputs[input].name); + + if ((input == VINO_INPUT_COMPOSITE) + || (input == VINO_INPUT_SVIDEO)) { + struct saa7191_status status; + i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status); + i->status |= status.signal ? 0 : V4L2_IN_ST_NO_SIGNAL; + i->status |= status.color ? 0 : V4L2_IN_ST_NO_COLOR; + } + + return 0; +} + +static int vino_v4l2_g_input(struct vino_channel_settings *vcs, + struct v4l2_input *i) +{ + __u32 index; + int input; + + spin_lock(&vino_drvdata->input_lock); + input = vcs->input; + index = vino_find_input_index(vcs); + spin_unlock(&vino_drvdata->input_lock); + + dprintk("input = %d\n", input); + + if (input == VINO_INPUT_NONE) { + return -EINVAL; + } + + memset(i, 0, sizeof(struct v4l2_input)); + + i->index = index; + i->type = V4L2_INPUT_TYPE_CAMERA; + i->std = vino_inputs[input].std; + strcpy(i->name, vino_inputs[input].name); + + return 0; +} + +static int vino_v4l2_s_input(struct vino_channel_settings *vcs, + struct v4l2_input *i) +{ + int input; + dprintk("requested input = %d\n", i->index); + + input = vino_enum_input(vcs, i->index); + if (input == VINO_INPUT_NONE) + return -EINVAL; + + return vino_set_input(vcs, input); +} + +static int vino_v4l2_enumstd(struct vino_channel_settings *vcs, + struct v4l2_standard *s) +{ + int index = s->index; + int data_norm = vino_enum_data_norm(vcs, index); + dprintk("standard index = %d\n", index); + + if (data_norm == VINO_DATA_NORM_NONE) + return -EINVAL; + + dprintk("standard name = %s\n", + vino_data_norms[data_norm].description); + + memset(s, 0, sizeof(struct v4l2_standard)); + s->index = index; + + s->id = vino_data_norms[data_norm].std; + s->frameperiod.numerator = 1; + s->frameperiod.denominator = + vino_data_norms[data_norm].fps_max; + s->framelines = + vino_data_norms[data_norm].framelines; + strcpy(s->name, + vino_data_norms[data_norm].description); + + return 0; +} + +static int vino_v4l2_g_std(struct vino_channel_settings *vcs, + v4l2_std_id *std) +{ + spin_lock(&vino_drvdata->input_lock); + dprintk("current standard = %d\n", vcs->data_norm); + *std = vino_data_norms[vcs->data_norm].std; + spin_unlock(&vino_drvdata->input_lock); + + return 0; +} + +static int vino_v4l2_s_std(struct vino_channel_settings *vcs, + v4l2_std_id *std) +{ + int ret = 0; + + spin_lock(&vino_drvdata->input_lock); + + /* check if the standard is valid for the current input */ + if (vino_is_input_owner(vcs) + && (vino_inputs[vcs->input].std & (*std))) { + dprintk("standard accepted\n"); + + /* change the video norm for SAA7191 + * and accept NTSC for D1 (do nothing) */ + + if (vcs->input == VINO_INPUT_D1) + goto out; + + if ((*std) & V4L2_STD_PAL) { + vino_set_data_norm(vcs, VINO_DATA_NORM_PAL); + vcs->data_norm = VINO_DATA_NORM_PAL; + } else if ((*std) & V4L2_STD_NTSC) { + vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC); + vcs->data_norm = VINO_DATA_NORM_NTSC; + } else if ((*std) & V4L2_STD_SECAM) { + vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM); + vcs->data_norm = VINO_DATA_NORM_SECAM; + } else { + ret = -EINVAL; + } + } else { + ret = -EINVAL; + } + +out: + spin_unlock(&vino_drvdata->input_lock); + + return ret; +} + +static int vino_v4l2_enum_fmt(struct vino_channel_settings *vcs, + struct v4l2_fmtdesc *fd) +{ + enum v4l2_buf_type type = fd->type; + int index = fd->index; + dprintk("format index = %d\n", index); + + switch (fd->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if ((fd->index < 0) || + (fd->index >= VINO_DATA_FMT_COUNT)) + return -EINVAL; + dprintk("format name = %s\n", + vino_data_formats[index].description); + + memset(fd, 0, sizeof(struct v4l2_fmtdesc)); + fd->index = index; + fd->type = type; + fd->pixelformat = vino_data_formats[index].pixelformat; + strcpy(fd->description, vino_data_formats[index].description); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs, + struct v4l2_format *f) +{ + struct vino_channel_settings tempvcs; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct v4l2_pix_format *pf = &f->fmt.pix; + + dprintk("requested: w = %d, h = %d\n", + pf->width, pf->height); + + spin_lock(&vino_drvdata->input_lock); + memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings)); + spin_unlock(&vino_drvdata->input_lock); + + tempvcs.data_format = vino_find_data_format(pf->pixelformat); + if (tempvcs.data_format == VINO_DATA_FMT_NONE) { + tempvcs.data_format = VINO_DATA_FMT_RGB32; + pf->pixelformat = + vino_data_formats[tempvcs.data_format]. + pixelformat; + } + + /* data format must be set before clipping/scaling */ + vino_set_scaling(&tempvcs, pf->width, pf->height); + + dprintk("data format = %s\n", + vino_data_formats[tempvcs.data_format].description); + + pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) / + tempvcs.decimation; + pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) / + tempvcs.decimation; + + pf->field = V4L2_FIELD_INTERLACED; + pf->bytesperline = tempvcs.line_size; + pf->sizeimage = tempvcs.line_size * + (tempvcs.clipping.bottom - tempvcs.clipping.top) / + tempvcs.decimation; + pf->colorspace = + vino_data_formats[tempvcs.data_format].colorspace; + + pf->priv = 0; + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs, + struct v4l2_format *f) +{ + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct v4l2_pix_format *pf = &f->fmt.pix; + spin_lock(&vino_drvdata->input_lock); + + pf->width = (vcs->clipping.right - vcs->clipping.left) / + vcs->decimation; + pf->height = (vcs->clipping.bottom - vcs->clipping.top) / + vcs->decimation; + pf->pixelformat = + vino_data_formats[vcs->data_format].pixelformat; + + pf->field = V4L2_FIELD_INTERLACED; + pf->bytesperline = vcs->line_size; + pf->sizeimage = vcs->line_size * + (vcs->clipping.bottom - vcs->clipping.top) / + vcs->decimation; + pf->colorspace = + vino_data_formats[vcs->data_format].colorspace; + + pf->priv = 0; + + spin_unlock(&vino_drvdata->input_lock); + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs, + struct v4l2_format *f) +{ + int data_format; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct v4l2_pix_format *pf = &f->fmt.pix; + spin_lock(&vino_drvdata->input_lock); + + if (!vino_is_input_owner(vcs)) { + spin_unlock(&vino_drvdata->input_lock); + return -EINVAL; + } + + data_format = vino_find_data_format(pf->pixelformat); + if (data_format == VINO_DATA_FMT_NONE) { + vcs->data_format = VINO_DATA_FMT_RGB32; + pf->pixelformat = + vino_data_formats[vcs->data_format]. + pixelformat; + } else { + vcs->data_format = data_format; + } + + /* data format must be set before clipping/scaling */ + vino_set_scaling(vcs, pf->width, pf->height); + + dprintk("data format = %s\n", + vino_data_formats[vcs->data_format].description); + + pf->width = vcs->clipping.right - vcs->clipping.left; + pf->height = vcs->clipping.bottom - vcs->clipping.top; + + pf->field = V4L2_FIELD_INTERLACED; + pf->bytesperline = vcs->line_size; + pf->sizeimage = vcs->line_size * + (vcs->clipping.bottom - vcs->clipping.top) / + vcs->decimation; + pf->colorspace = + vino_data_formats[vcs->data_format].colorspace; + + pf->priv = 0; + + spin_unlock(&vino_drvdata->input_lock); + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_cropcap(struct vino_channel_settings *vcs, + struct v4l2_cropcap *ccap) +{ + const struct vino_data_norm *norm; + + switch (ccap->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + spin_lock(&vino_drvdata->input_lock); + norm = &vino_data_norms[vcs->data_norm]; + spin_unlock(&vino_drvdata->input_lock); + + ccap->bounds.left = 0; + ccap->bounds.top = 0; + ccap->bounds.width = norm->width; + ccap->bounds.height = norm->height; + memcpy(&ccap->defrect, &ccap->bounds, + sizeof(struct v4l2_rect)); + + ccap->pixelaspect.numerator = 1; + ccap->pixelaspect.denominator = 1; + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_g_crop(struct vino_channel_settings *vcs, + struct v4l2_crop *c) +{ + switch (c->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + spin_lock(&vino_drvdata->input_lock); + + c->c.left = vcs->clipping.left; + c->c.top = vcs->clipping.top; + c->c.width = vcs->clipping.right - vcs->clipping.left; + c->c.height = vcs->clipping.bottom - vcs->clipping.top; + + spin_unlock(&vino_drvdata->input_lock); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_s_crop(struct vino_channel_settings *vcs, + struct v4l2_crop *c) +{ + switch (c->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + spin_lock(&vino_drvdata->input_lock); + + if (!vino_is_input_owner(vcs)) { + spin_unlock(&vino_drvdata->input_lock); + return -EINVAL; + } + vino_set_clipping(vcs, c->c.left, c->c.top, + c->c.width, c->c.height); + + spin_unlock(&vino_drvdata->input_lock); + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_g_parm(struct vino_channel_settings *vcs, + struct v4l2_streamparm *sp) +{ + switch (sp->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct v4l2_captureparm *cp = &sp->parm.capture; + memset(cp, 0, sizeof(struct v4l2_captureparm)); + + cp->capability = V4L2_CAP_TIMEPERFRAME; + cp->timeperframe.numerator = 1; + + spin_lock(&vino_drvdata->input_lock); + cp->timeperframe.denominator = vcs->fps; + spin_unlock(&vino_drvdata->input_lock); + + // TODO: cp->readbuffers = xxx; + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_s_parm(struct vino_channel_settings *vcs, + struct v4l2_streamparm *sp) +{ + switch (sp->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct v4l2_captureparm *cp = &sp->parm.capture; + + spin_lock(&vino_drvdata->input_lock); + if (!vino_is_input_owner(vcs)) { + spin_unlock(&vino_drvdata->input_lock); + return -EINVAL; + } + + if ((cp->timeperframe.numerator == 0) || + (cp->timeperframe.denominator == 0)) { + /* reset framerate */ + vino_set_default_framerate(vcs); + } else { + vino_set_framerate(vcs, cp->timeperframe.denominator / + cp->timeperframe.numerator); + } + spin_unlock(&vino_drvdata->input_lock); + + // TODO: set buffers according to cp->readbuffers + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs, + struct v4l2_requestbuffers *rb) +{ + if (vcs->reading) + return -EBUSY; + + switch (rb->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + // TODO: check queue type + if (rb->memory != V4L2_MEMORY_MMAP) { + dprintk("type not mmap\n"); + return -EINVAL; + } + + if (vino_is_capturing(vcs)) { + dprintk("busy, capturing\n"); + return -EBUSY; + } + + dprintk("count = %d\n", rb->count); + if (rb->count > 0) { + if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) { + dprintk("busy, buffers still mapped\n"); + return -EBUSY; + } else { + vino_queue_free(&vcs->fb_queue); + vino_queue_init(&vcs->fb_queue, &rb->count); + } + } else { + vino_capture_stop(vcs); + vino_queue_free(&vcs->fb_queue); + } + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs, + struct vino_framebuffer *fb, + struct v4l2_buffer *b) +{ + if (vino_queue_outgoing_contains(&vcs->fb_queue, + fb->id)) { + b->flags &= ~V4L2_BUF_FLAG_QUEUED; + b->flags |= V4L2_BUF_FLAG_DONE; + } else if (vino_queue_incoming_contains(&vcs->fb_queue, + fb->id)) { + b->flags &= ~V4L2_BUF_FLAG_DONE; + b->flags |= V4L2_BUF_FLAG_QUEUED; + } else { + b->flags &= ~(V4L2_BUF_FLAG_DONE | + V4L2_BUF_FLAG_QUEUED); + } + + b->flags &= ~(V4L2_BUF_FLAG_TIMECODE); + + if (fb->map_count > 0) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + b->index = fb->id; + b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ? + V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR; + b->m.offset = fb->offset; + b->bytesused = fb->data_size; + b->length = fb->size; + b->field = V4L2_FIELD_INTERLACED; + b->sequence = fb->frame_counter; + memcpy(&b->timestamp, &fb->timestamp, + sizeof(struct timeval)); + // b->input ? + + dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n", + fb->id, fb->size, fb->data_size, fb->offset); +} + +static int vino_v4l2_querybuf(struct vino_channel_settings *vcs, + struct v4l2_buffer *b) +{ + if (vcs->reading) + return -EBUSY; + + switch (b->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct vino_framebuffer *fb; + + // TODO: check queue type + if (b->index >= vino_queue_get_length(&vcs->fb_queue)) { + dprintk("invalid index = %d\n", + b->index); + return -EINVAL; + } + + fb = vino_queue_get_buffer(&vcs->fb_queue, + b->index); + if (fb == NULL) { + dprintk("vino_queue_get_buffer() failed"); + return -EINVAL; + } + + vino_v4l2_get_buffer_status(vcs, fb, b); + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_qbuf(struct vino_channel_settings *vcs, + struct v4l2_buffer *b) +{ + if (vcs->reading) + return -EBUSY; + + switch (b->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct vino_framebuffer *fb; + int ret; + + // TODO: check queue type + if (b->memory != V4L2_MEMORY_MMAP) { + dprintk("type not mmap\n"); + return -EINVAL; + } + + fb = vino_capture_enqueue(vcs, b->index); + if (fb == NULL) + return -EINVAL; + + vino_v4l2_get_buffer_status(vcs, fb, b); + + if (vcs->streaming) { + ret = vino_capture_next(vcs, 1); + if (ret) + return ret; + } + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs, + struct v4l2_buffer *b, + unsigned int nonblocking) +{ + if (vcs->reading) + return -EBUSY; + + switch (b->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: { + struct vino_framebuffer *fb; + unsigned int incoming, outgoing; + int err; + + // TODO: check queue type + + err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); + if (err) { + dprintk("vino_queue_get_incoming() failed\n"); + return -EIO; + } + err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing); + if (err) { + dprintk("vino_queue_get_outgoing() failed\n"); + return -EIO; + } + + dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing); + + if (outgoing == 0) { + if (incoming == 0) { + dprintk("no incoming or outgoing buffers\n"); + return -EINVAL; + } + if (nonblocking) { + dprintk("non-blocking I/O was selected and " + "there are no buffers to dequeue\n"); + return -EAGAIN; + } + + err = vino_wait_for_frame(vcs); + if (err) { + err = vino_wait_for_frame(vcs); + if (err) { + /* interrupted */ + vino_capture_failed(vcs); + return -EIO; + } + } + } + + fb = vino_queue_remove(&vcs->fb_queue, &b->index); + if (fb == NULL) { + dprintk("vino_queue_remove() failed\n"); + return -EINVAL; + } + + err = vino_check_buffer(vcs, fb); + if (err) + return -EIO; + + vino_v4l2_get_buffer_status(vcs, fb, b); + break; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + default: + return -EINVAL; + } + + return 0; +} + +static int vino_v4l2_streamon(struct vino_channel_settings *vcs) +{ + unsigned int incoming; + int ret; + if (vcs->reading) + return -EBUSY; + + if (vcs->streaming) + return 0; + + // TODO: check queue type + + if (vino_queue_get_length(&vcs->fb_queue) < 1) { + dprintk("no buffers allocated\n"); + return -EINVAL; + } + + ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming); + if (ret) { + dprintk("vino_queue_get_incoming() failed\n"); + return -EINVAL; + } + + vcs->streaming = 1; + + if (incoming > 0) { + ret = vino_capture_next(vcs, 1); + if (ret) { + vcs->streaming = 0; + + dprintk("couldn't start capture\n"); + return -EINVAL; + } + } + + return 0; +} + +static int vino_v4l2_streamoff(struct vino_channel_settings *vcs) +{ + if (vcs->reading) + return -EBUSY; + + if (!vcs->streaming) + return 0; + + vino_capture_stop(vcs); + vcs->streaming = 0; + + return 0; +} + +static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs, + struct v4l2_queryctrl *queryctrl) +{ + int i; + int err = 0; + + spin_lock(&vino_drvdata->input_lock); + + switch (vcs->input) { + case VINO_INPUT_D1: + for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { + if (vino_indycam_v4l2_controls[i].id == + queryctrl->id) { + memcpy(queryctrl, + &vino_indycam_v4l2_controls[i], + sizeof(struct v4l2_queryctrl)); + goto found; + } + } + + err = -EINVAL; + break; + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: + for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { + if (vino_saa7191_v4l2_controls[i].id == + queryctrl->id) { + memcpy(queryctrl, + &vino_saa7191_v4l2_controls[i], + sizeof(struct v4l2_queryctrl)); + goto found; + } + } + + err = -EINVAL; + break; + default: + err = -EINVAL; + } + + found: + spin_unlock(&vino_drvdata->input_lock); + + return err; +} + +static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs, + struct v4l2_control *control) +{ + struct indycam_control indycam_ctrl; + struct saa7191_control saa7191_ctrl; + int err = 0; + + spin_lock(&vino_drvdata->input_lock); + + switch (vcs->input) { + case VINO_INPUT_D1: + i2c_camera_command(DECODER_INDYCAM_GET_CONTROLS, + &indycam_ctrl); + + switch(control->id) { + case V4L2_CID_AUTOGAIN: + control->value = indycam_ctrl.agc; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + control->value = indycam_ctrl.awb; + break; + case V4L2_CID_GAIN: + control->value = indycam_ctrl.gain; + break; + case V4L2_CID_PRIVATE_BASE: + control->value = indycam_ctrl.red_saturation; + break; + case V4L2_CID_PRIVATE_BASE + 1: + control->value = indycam_ctrl.blue_saturation; + break; + case V4L2_CID_RED_BALANCE: + control->value = indycam_ctrl.red_balance; + break; + case V4L2_CID_BLUE_BALANCE: + control->value = indycam_ctrl.blue_balance; + break; + case V4L2_CID_EXPOSURE: + control->value = indycam_ctrl.shutter; + break; + case V4L2_CID_GAMMA: + control->value = indycam_ctrl.gamma; + break; + default: + err = -EINVAL; + } + break; + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: + i2c_decoder_command(DECODER_SAA7191_GET_CONTROLS, + &saa7191_ctrl); + + switch(control->id) { + case V4L2_CID_HUE: + control->value = saa7191_ctrl.hue; + break; + case V4L2_CID_PRIVATE_BASE: + control->value = saa7191_ctrl.vtrc; + break; + default: + err = -EINVAL; + } + break; + default: + err = -EINVAL; + } + + spin_unlock(&vino_drvdata->input_lock); + + return err; +} + +static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs, + struct v4l2_control *control) +{ + struct indycam_control indycam_ctrl; + struct saa7191_control saa7191_ctrl; + int i; + int err = 0; + + spin_lock(&vino_drvdata->input_lock); + + switch (vcs->input) { + case VINO_INPUT_D1: + for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { + if (vino_indycam_v4l2_controls[i].id == + control->id) { + if ((control->value >= + vino_indycam_v4l2_controls[i].minimum) + && (control->value <= + vino_indycam_v4l2_controls[i]. + maximum)) { + goto ok1; + } else { + err = -ERANGE; + goto error; + } + } + } + err = -EINVAL; + goto error; + +ok1: + indycam_ctrl.agc = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.awb = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.shutter = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.gain = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.red_balance = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.blue_balance = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.red_saturation = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.blue_saturation = INDYCAM_VALUE_UNCHANGED; + indycam_ctrl.gamma = INDYCAM_VALUE_UNCHANGED; + + switch(control->id) { + case V4L2_CID_AUTOGAIN: + indycam_ctrl.agc = control->value; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + indycam_ctrl.awb = control->value; + break; + case V4L2_CID_GAIN: + indycam_ctrl.gain = control->value; + break; + case V4L2_CID_PRIVATE_BASE: + indycam_ctrl.red_saturation = control->value; + break; + case V4L2_CID_PRIVATE_BASE + 1: + indycam_ctrl.blue_saturation = control->value; + break; + case V4L2_CID_RED_BALANCE: + indycam_ctrl.red_balance = control->value; + break; + case V4L2_CID_BLUE_BALANCE: + indycam_ctrl.blue_balance = control->value; + break; + case V4L2_CID_EXPOSURE: + indycam_ctrl.shutter = control->value; + break; + case V4L2_CID_GAMMA: + indycam_ctrl.gamma = control->value; + break; + default: + err = -EINVAL; + } + + if (!err) + i2c_camera_command(DECODER_INDYCAM_SET_CONTROLS, + &indycam_ctrl); + break; + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: + for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { + if (vino_saa7191_v4l2_controls[i].id == + control->id) { + if ((control->value >= + vino_saa7191_v4l2_controls[i].minimum) + && (control->value <= + vino_saa7191_v4l2_controls[i]. + maximum)) { + goto ok2; + } else { + err = -ERANGE; + goto error; + } + } + } + err = -EINVAL; + goto error; + +ok2: + saa7191_ctrl.hue = SAA7191_VALUE_UNCHANGED; + saa7191_ctrl.vtrc = SAA7191_VALUE_UNCHANGED; + + switch(control->id) { + case V4L2_CID_HUE: + saa7191_ctrl.hue = control->value; + break; + case V4L2_CID_PRIVATE_BASE: + saa7191_ctrl.vtrc = control->value; + break; + default: + err = -EINVAL; + } + + if (!err) + i2c_decoder_command(DECODER_SAA7191_SET_CONTROLS, + &saa7191_ctrl); + break; + default: + err = -EINVAL; + } + +error: + spin_unlock(&vino_drvdata->input_lock); + + return err; +} + +/* File operations */ + +static int vino_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct vino_channel_settings *vcs = video_get_drvdata(dev); + int ret = 0; + dprintk("open(): channel = %c\n", + (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B'); + + down(&vcs->sem); + + if (vcs->users) { + dprintk("open(): driver busy\n"); + ret = -EBUSY; + goto out; + } + + ret = vino_acquire_input(vcs); + if (ret) { + dprintk("open(): vino_acquire_input() failed\n"); + goto out; + } + + vcs->users++; + + out: + up(&vcs->sem); + + dprintk("open(): %s!\n", ret ? "failed" : "complete"); + + return ret; +} + +static int vino_close(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct vino_channel_settings *vcs = video_get_drvdata(dev); + dprintk("close():\n"); + + down(&vcs->sem); + + vcs->users--; + + if (!vcs->users) { + vino_release_input(vcs); + + /* stop DMA and free buffers */ + vino_capture_stop(vcs); + vino_queue_free(&vcs->fb_queue); + } + + up(&vcs->sem); + + return 0; +} + +static void vino_vm_open(struct vm_area_struct *vma) +{ + struct vino_framebuffer *fb = vma->vm_private_data; + + fb->map_count++; + dprintk("vino_vm_open(): count = %d\n", fb->map_count); +} + +static void vino_vm_close(struct vm_area_struct *vma) +{ + struct vino_framebuffer *fb = vma->vm_private_data; + + fb->map_count--; + dprintk("vino_vm_close(): count = %d\n", fb->map_count); +} + +static struct vm_operations_struct vino_vm_ops = { + .open = vino_vm_open, + .close = vino_vm_close, +}; + +static int vino_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *dev = video_devdata(file); + struct vino_channel_settings *vcs = video_get_drvdata(dev); + + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + struct vino_framebuffer *fb = NULL; + unsigned int i, length; + int ret = 0; + + dprintk("mmap():\n"); + + // TODO: reject mmap if already mapped + + if (down_interruptible(&vcs->sem)) + return -EINTR; + + if (vcs->reading) { + ret = -EBUSY; + goto out; + } + + // TODO: check queue type + + if (!(vma->vm_flags & VM_WRITE)) { + dprintk("mmap(): app bug: PROT_WRITE please\n"); + ret = -EINVAL; + goto out; + } + if (!(vma->vm_flags & VM_SHARED)) { + dprintk("mmap(): app bug: MAP_SHARED please\n"); + ret = -EINVAL; + goto out; + } + + /* find the correct buffer using offset */ + length = vino_queue_get_length(&vcs->fb_queue); + if (length == 0) { + dprintk("mmap(): queue not initialized\n"); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < length; i++) { + fb = vino_queue_get_buffer(&vcs->fb_queue, i); + if (fb == NULL) { + dprintk("mmap(): vino_queue_get_buffer() failed\n"); + ret = -EINVAL; + goto out; + } + + if (fb->offset == offset) + goto found; + } + + dprintk("mmap(): invalid offset = %lu\n", offset); + ret = -EINVAL; + goto out; + +found: + dprintk("mmap(): buffer = %d\n", i); + + if (size > (fb->desc_table.page_count * PAGE_SIZE)) { + dprintk("mmap(): failed: size = %lu > %lu\n", + size, fb->desc_table.page_count * PAGE_SIZE); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < fb->desc_table.page_count; i++) { + unsigned long pfn = + virt_to_phys((void *)fb->desc_table.virtual[i]) >> + PAGE_SHIFT; + + if (size < PAGE_SIZE) + break; + + // protection was: PAGE_READONLY + if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, + vma->vm_page_prot)) { + dprintk("mmap(): remap_pfn_range() failed\n"); + ret = -EAGAIN; + goto out; + } + + start += PAGE_SIZE; + size -= PAGE_SIZE; + } + + fb->map_count = 1; + + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_flags &= ~VM_IO; + vma->vm_private_data = fb; + vma->vm_file = file; + vma->vm_ops = &vino_vm_ops; + +out: + up(&vcs->sem); + + return ret; +} + +static unsigned int vino_poll(struct file *file, poll_table *pt) +{ + struct video_device *dev = video_devdata(file); + struct vino_channel_settings *vcs = video_get_drvdata(dev); + unsigned int outgoing; + unsigned int ret = 0; + + // lock mutex (?) + // TODO: this has to be corrected for different read modes + + dprintk("poll():\n"); + + if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { + dprintk("poll(): vino_queue_get_outgoing() failed\n"); + ret = POLLERR; + goto error; + } + if (outgoing > 0) + goto over; + + poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt); + + if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) { + dprintk("poll(): vino_queue_get_outgoing() failed\n"); + ret = POLLERR; + goto error; + } + +over: + dprintk("poll(): data %savailable\n", + (outgoing > 0) ? "" : "not "); + if (outgoing > 0) { + ret = POLLIN | POLLRDNORM; + } + +error: + + return ret; +} + +static int vino_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *dev = video_devdata(file); + struct vino_channel_settings *vcs = video_get_drvdata(dev); + + switch (_IOC_TYPE(cmd)) { + case 'v': + dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd); + break; + case 'V': + dprintk("ioctl(): V4L2 %s (0x%08x)\n", + v4l2_ioctl_names[_IOC_NR(cmd)], cmd); + break; + default: + dprintk("ioctl(): unsupported command 0x%08x\n", cmd); + } + + switch (cmd) { + /* TODO: V4L1 interface (use compatibility layer?) */ + /* V4L2 interface */ + case VIDIOC_QUERYCAP: { + vino_v4l2_querycap(arg); + break; + } + case VIDIOC_ENUMINPUT: { + return vino_v4l2_enuminput(vcs, arg); + } + case VIDIOC_G_INPUT: { + return vino_v4l2_g_input(vcs, arg); + } + case VIDIOC_S_INPUT: { + return vino_v4l2_s_input(vcs, arg); + } + case VIDIOC_ENUMSTD: { + return vino_v4l2_enumstd(vcs, arg); + } + case VIDIOC_G_STD: { + return vino_v4l2_g_std(vcs, arg); + } + case VIDIOC_S_STD: { + return vino_v4l2_s_std(vcs, arg); + } + case VIDIOC_ENUM_FMT: { + return vino_v4l2_enum_fmt(vcs, arg); + } + case VIDIOC_TRY_FMT: { + return vino_v4l2_try_fmt(vcs, arg); + } + case VIDIOC_G_FMT: { + return vino_v4l2_g_fmt(vcs, arg); + } + case VIDIOC_S_FMT: { + return vino_v4l2_s_fmt(vcs, arg); + } + case VIDIOC_CROPCAP: { + return vino_v4l2_cropcap(vcs, arg); + } + case VIDIOC_G_CROP: { + return vino_v4l2_g_crop(vcs, arg); + } + case VIDIOC_S_CROP: { + return vino_v4l2_s_crop(vcs, arg); + } + case VIDIOC_G_PARM: { + return vino_v4l2_g_parm(vcs, arg); + } + case VIDIOC_S_PARM: { + return vino_v4l2_s_parm(vcs, arg); + } + case VIDIOC_REQBUFS: { + return vino_v4l2_reqbufs(vcs, arg); + } + case VIDIOC_QUERYBUF: { + return vino_v4l2_querybuf(vcs, arg); + } + case VIDIOC_QBUF: { + return vino_v4l2_qbuf(vcs, arg); + } + case VIDIOC_DQBUF: { + return vino_v4l2_dqbuf(vcs, arg, file->f_flags & O_NONBLOCK); + } + case VIDIOC_STREAMON: { + return vino_v4l2_streamon(vcs); + } + case VIDIOC_STREAMOFF: { + return vino_v4l2_streamoff(vcs); + } + case VIDIOC_QUERYCTRL: { + return vino_v4l2_queryctrl(vcs, arg); + } + case VIDIOC_G_CTRL: { + return vino_v4l2_g_ctrl(vcs, arg); + } + case VIDIOC_S_CTRL: { + return vino_v4l2_s_ctrl(vcs, arg); + } + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static int vino_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *dev = video_devdata(file); + struct vino_channel_settings *vcs = video_get_drvdata(dev); + int ret; + + if (down_interruptible(&vcs->sem)) + return -EINTR; + + ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl); + + up(&vcs->sem); + + return ret; +} + +/* Initialization and cleanup */ + +// __initdata +static int vino_init_stage = 0; + +static struct file_operations vino_fops = { .owner = THIS_MODULE, - .type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE, - .hardware = VID_HARDWARE_VINO, - .name = "VINO", .open = vino_open, - .close = vino_close, + .release = vino_close, .ioctl = vino_ioctl, .mmap = vino_mmap, + .poll = vino_poll, + .llseek = no_llseek, }; -static int __init vino_init(void) +static struct video_device v4l_device_template = { + .name = "NOT SET", + //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | + // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY + .hardware = VID_HARDWARE_VINO, + .fops = &vino_fops, + .minor = -1, +}; + +static void vino_module_cleanup(int stage) +{ + switch(stage) { + case 10: + video_unregister_device(vino_drvdata->b.v4l_device); + vino_drvdata->b.v4l_device = NULL; + case 9: + video_unregister_device(vino_drvdata->a.v4l_device); + vino_drvdata->a.v4l_device = NULL; + case 8: + vino_i2c_del_bus(); + case 7: + free_irq(SGI_VINO_IRQ, NULL); + case 6: + if (vino_drvdata->b.v4l_device) { + video_device_release(vino_drvdata->b.v4l_device); + vino_drvdata->b.v4l_device = NULL; + } + case 5: + if (vino_drvdata->a.v4l_device) { + video_device_release(vino_drvdata->a.v4l_device); + vino_drvdata->a.v4l_device = NULL; + } + case 4: + /* all entries in dma_cpu dummy table have the same address */ + dma_unmap_single(NULL, + vino_drvdata->dummy_desc_table.dma_cpu[0], + PAGE_SIZE, DMA_FROM_DEVICE); + dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT + * sizeof(dma_addr_t), + (void *)vino_drvdata-> + dummy_desc_table.dma_cpu, + vino_drvdata->dummy_desc_table.dma); + case 3: + free_page(vino_drvdata->dummy_page); + case 2: + kfree(vino_drvdata); + case 1: + iounmap(vino); + case 0: + break; + default: + dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n", + stage); + } +} + +static int vino_probe(void) { - unsigned long rev; - int i, ret = 0; + unsigned long rev_id; - /* VINO is Indy specific beast */ - if (ip22_is_fullhouse()) + if (ip22_is_fullhouse()) { + printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n"); return -ENODEV; + } - /* - * VINO is in the EISA address space, so the sysid register will tell - * us if the EISA_PRESENT pin on MC has been pulled low. - * - * If EISA_PRESENT is not set we definitely don't have a VINO equiped - * system. - */ if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) { - printk(KERN_ERR "VINO not found\n"); + printk(KERN_ERR "VINO is not found (EISA BUS not present)\n"); return -ENODEV; } vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino)); - if (!vino) + if (!vino) { + printk(KERN_ERR "VINO: ioremap() failed\n"); return -EIO; + } + vino_init_stage++; - /* Okay, once we know that VINO is present we'll read its revision - * safe way. One never knows... */ - if (get_dbe(rev, &(vino->rev_id))) { - printk(KERN_ERR "VINO: failed to read revision register\n"); - ret = -ENODEV; - goto out_unmap; + if (get_dbe(rev_id, &(vino->rev_id))) { + printk(KERN_ERR "Failed to read VINO revision register\n"); + vino_module_cleanup(vino_init_stage); + return -ENODEV; } - if (VINO_ID_VALUE(rev) != VINO_CHIP_ID) { - printk(KERN_ERR "VINO is not VINO (Rev/ID: 0x%04lx)\n", rev); - ret = -ENODEV; - goto out_unmap; + + if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) { + printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n", + rev_id); + vino_module_cleanup(vino_init_stage); + return -ENODEV; } - printk(KERN_INFO "VINO Rev: 0x%02lx\n", VINO_REV_NUM(rev)); - Vino = (struct vino_video *) - kmalloc(sizeof(struct vino_video), GFP_KERNEL); - if (!Vino) { - ret = -ENOMEM; - goto out_unmap; + printk(KERN_INFO "VINO with chip ID %ld, revision %ld found\n", + VINO_ID_VALUE(rev_id), VINO_REV_NUM(rev_id)); + + return 0; +} + +static int vino_init(void) +{ + dma_addr_t dma_dummy_address; + int i; + + vino_drvdata = (struct vino_settings *) + kmalloc(sizeof(struct vino_settings), GFP_KERNEL); + if (!vino_drvdata) { + vino_module_cleanup(vino_init_stage); + return -ENOMEM; } + memset(vino_drvdata, 0, sizeof(struct vino_settings)); + vino_init_stage++; - Vino->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!Vino->dummy_page) { - ret = -ENOMEM; - goto out_free_vino; + /* create a dummy dma descriptor */ + vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!vino_drvdata->dummy_page) { + vino_module_cleanup(vino_init_stage); + return -ENOMEM; } - for (i = 0; i < 4; i++) - Vino->dummy_buf[i] = PHYSADDR(Vino->dummy_page); + vino_init_stage++; + + // TODO: use page_count in dummy_desc_table + + vino_drvdata->dummy_desc_table.dma_cpu = + dma_alloc_coherent(NULL, + VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t), + &vino_drvdata->dummy_desc_table.dma, + GFP_KERNEL | GFP_DMA); + if (!vino_drvdata->dummy_desc_table.dma_cpu) { + vino_module_cleanup(vino_init_stage); + return -ENOMEM; + } + vino_init_stage++; + + dma_dummy_address = dma_map_single(NULL, + (void *)vino_drvdata->dummy_page, + PAGE_SIZE, DMA_FROM_DEVICE); + for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) { + vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address; + } + + /* initialize VINO */ vino->control = 0; - /* prevent VINO from throwing spurious interrupts */ - vino->a.next_4_desc = PHYSADDR(Vino->dummy_buf); - vino->b.next_4_desc = PHYSADDR(Vino->dummy_buf); - udelay(5); + vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma; + vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma; + udelay(VINO_DESC_FETCH_DELAY); + vino->intr_status = 0; - /* set threshold level */ - vino->a.fifo_thres = threshold_a; - vino->b.fifo_thres = threshold_b; - init_MUTEX(&Vino->input_lock); + vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT; + vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT; + + return 0; +} + +static int vino_init_channel_settings(struct vino_channel_settings *vcs, + unsigned int channel, const char *name) +{ + vcs->channel = channel; + vcs->input = VINO_INPUT_NONE; + vcs->alpha = 0; + vcs->users = 0; + vcs->data_format = VINO_DATA_FMT_GREY; + vcs->data_norm = VINO_DATA_NORM_NTSC; + vcs->decimation = 1; + vino_set_default_clipping(vcs); + vino_set_default_framerate(vcs); + + vcs->capturing = 0; + + init_MUTEX(&vcs->sem); + spin_lock_init(&vcs->capture_lock); + + init_MUTEX(&vcs->fb_queue.queue_sem); + spin_lock_init(&vcs->fb_queue.queue_lock); + init_waitqueue_head(&vcs->fb_queue.frame_wait_queue); + + vcs->v4l_device = video_device_alloc(); + if (!vcs->v4l_device) { + vino_module_cleanup(vino_init_stage); + return -ENOMEM; + } + vino_init_stage++; + + memcpy(vcs->v4l_device, &v4l_device_template, + sizeof(struct video_device)); + strcpy(vcs->v4l_device->name, name); + vcs->v4l_device->release = video_device_release; + + video_set_drvdata(vcs->v4l_device, vcs); + + return 0; +} + +static int __init vino_module_init(void) +{ + int ret; + + printk(KERN_INFO "SGI VINO driver version %s\n", + VINO_MODULE_VERSION); + + ret = vino_probe(); + if (ret) + return ret; + + ret = vino_init(); + if (ret) + return ret; + + /* initialize data structures */ - if (request_irq(SGI_VINO_IRQ, vino_interrupt, 0, vinostr, NULL)) { - printk(KERN_ERR "VINO: irq%02d registration failed\n", + spin_lock_init(&vino_drvdata->vino_lock); + spin_lock_init(&vino_drvdata->input_lock); + + ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A, + vino_v4l_device_name_a); + if (ret) + return ret; + + ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B, + vino_v4l_device_name_b); + if (ret) + return ret; + + /* initialize hardware and register V4L devices */ + + ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0, + vino_driver_description, NULL); + if (ret) { + printk(KERN_ERR "VINO: requesting IRQ %02d failed\n", SGI_VINO_IRQ); - ret = -EAGAIN; - goto out_free_page; + vino_module_cleanup(vino_init_stage); + return -EAGAIN; } + vino_init_stage++; ret = vino_i2c_add_bus(); if (ret) { - printk(KERN_ERR "VINO: I2C bus registration failed\n"); - goto out_free_irq; + printk(KERN_ERR "VINO I2C bus registration failed\n"); + vino_module_cleanup(vino_init_stage); + return ret; } + vino_init_stage++; - if (video_register_device(&Vino->chA.vdev, VFL_TYPE_GRABBER, -1) < 0) { - printk("%s, chnl %d: device registration failed.\n", - Vino->chA.vdev.name, Vino->chA.chan); - ret = -EINVAL; - goto out_i2c_del_bus; + ret = video_register_device(vino_drvdata->a.v4l_device, + VFL_TYPE_GRABBER, -1); + if (ret < 0) { + printk(KERN_ERR "VINO channel A Video4Linux-device " + "registration failed\n"); + vino_module_cleanup(vino_init_stage); + return -EINVAL; } - if (video_register_device(&Vino->chB.vdev, VFL_TYPE_GRABBER, -1) < 0) { - printk("%s, chnl %d: device registration failed.\n", - Vino->chB.vdev.name, Vino->chB.chan); - ret = -EINVAL; - goto out_unregister_vdev; + vino_init_stage++; + + ret = video_register_device(vino_drvdata->b.v4l_device, + VFL_TYPE_GRABBER, -1); + if (ret < 0) { + printk(KERN_ERR "VINO channel B Video4Linux-device " + "registration failed\n"); + vino_module_cleanup(vino_init_stage); + return -EINVAL; } + vino_init_stage++; - return 0; +#if defined(CONFIG_KMOD) && defined(MODULE) + request_module("saa7191"); + request_module("indycam"); +#endif -out_unregister_vdev: - video_unregister_device(&Vino->chA.vdev); -out_i2c_del_bus: - vino_i2c_del_bus(); -out_free_irq: - free_irq(SGI_VINO_IRQ, NULL); -out_free_page: - free_page(Vino->dummy_page); -out_free_vino: - kfree(Vino); -out_unmap: - iounmap(vino); + dprintk("init complete!\n"); - return ret; + return 0; } -static void __exit vino_exit(void) +static void __exit vino_module_exit(void) { - video_unregister_device(&Vino->chA.vdev); - video_unregister_device(&Vino->chB.vdev); - vino_i2c_del_bus(); - free_irq(SGI_VINO_IRQ, NULL); - free_page(Vino->dummy_page); - kfree(Vino); - iounmap(vino); + dprintk("exiting, stage = %d ...\n", vino_init_stage); + vino_module_cleanup(vino_init_stage); + dprintk("cleanup complete, exit!\n"); } -module_init(vino_init); -module_exit(vino_exit); - -MODULE_DESCRIPTION("Video4Linux driver for SGI Indy VINO (IndyCam)"); -MODULE_LICENSE("GPL"); +module_init(vino_module_init); +module_exit(vino_module_exit); diff --git a/drivers/media/video/vino.h b/drivers/media/video/vino.h index d2fce472f35a..de2d615ae7c9 100644 --- a/drivers/media/video/vino.h +++ b/drivers/media/video/vino.h @@ -1,13 +1,19 @@ /* + * Driver for the VINO (Video In No Out) system found in SGI Indys. + * + * This file is subject to the terms and conditions of the GNU General Public + * License version 2 as published by the Free Software Foundation. + * * Copyright (C) 1999 Ulf Karlsson <ulfc@bun.falkenberg.se> * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> */ -#ifndef VINO_H -#define VINO_H +#ifndef _VINO_H_ +#define _VINO_H_ #define VINO_BASE 0x00080000 /* Vino is in the EISA address space, * but it is not an EISA bus card */ +#define VINO_PAGE_SIZE 4096 struct sgi_vino_channel { u32 _pad_alpha; @@ -21,8 +27,9 @@ struct sgi_vino_channel { u32 _pad_clip_end; volatile u32 clip_end; +#define VINO_FRAMERT_FULL 0xfff #define VINO_FRAMERT_PAL (1<<0) /* 0=NTSC 1=PAL */ -#define VINO_FRAMERT_RT(x) (((x) & 0x1fff) << 1) /* bits 1:12 */ +#define VINO_FRAMERT_RT(x) (((x) & 0xfff) << 1) /* bits 1:12 */ u32 _pad_frame_rate; volatile u32 frame_rate; @@ -67,18 +74,18 @@ struct sgi_vino { volatile u32 rev_id; #define VINO_CTRL_LITTLE_ENDIAN (1<<0) -#define VINO_CTRL_A_FIELD_TRANS_INT (1<<1) /* Field transferred int */ -#define VINO_CTRL_A_FIFO_OF_INT (1<<2) /* FIFO overflow int */ -#define VINO_CTRL_A_END_DESC_TBL_INT (1<<3) /* End of desc table int */ -#define VINO_CTRL_A_INT (VINO_CTRL_A_FIELD_TRANS_INT | \ - VINO_CTRL_A_FIFO_OF_INT | \ - VINO_CTRL_A_END_DESC_TBL_INT) -#define VINO_CTRL_B_FIELD_TRANS_INT (1<<4) /* Field transferred int */ -#define VINO_CTRL_B_FIFO_OF_INT (1<<5) /* FIFO overflow int */ -#define VINO_CTRL_B_END_DESC_TBL_INT (1<<6) /* End of desc table int */ -#define VINO_CTRL_B_INT (VINO_CTRL_B_FIELD_TRANS_INT | \ - VINO_CTRL_B_FIFO_OF_INT | \ - VINO_CTRL_B_END_DESC_TBL_INT) +#define VINO_CTRL_A_EOF_INT (1<<1) /* Field transferred int */ +#define VINO_CTRL_A_FIFO_INT (1<<2) /* FIFO overflow int */ +#define VINO_CTRL_A_EOD_INT (1<<3) /* End of desc table int */ +#define VINO_CTRL_A_INT (VINO_CTRL_A_EOF_INT | \ + VINO_CTRL_A_FIFO_INT | \ + VINO_CTRL_A_EOD_INT) +#define VINO_CTRL_B_EOF_INT (1<<4) /* Field transferred int */ +#define VINO_CTRL_B_FIFO_INT (1<<5) /* FIFO overflow int */ +#define VINO_CTRL_B_EOD_INT (1<<6) /* End of desc table int */ +#define VINO_CTRL_B_INT (VINO_CTRL_B_EOF_INT | \ + VINO_CTRL_B_FIFO_INT | \ + VINO_CTRL_B_EOD_INT) #define VINO_CTRL_A_DMA_ENBL (1<<7) #define VINO_CTRL_A_INTERLEAVE_ENBL (1<<8) #define VINO_CTRL_A_SYNC_ENBL (1<<9) @@ -104,18 +111,18 @@ struct sgi_vino { u32 _pad_control; volatile u32 control; -#define VINO_INTSTAT_A_FIELD_TRANS (1<<0) /* Field transferred int */ -#define VINO_INTSTAT_A_FIFO_OF (1<<1) /* FIFO overflow int */ -#define VINO_INTSTAT_A_END_DESC_TBL (1<<2) /* End of desc table int */ -#define VINO_INTSTAT_A (VINO_INTSTAT_A_FIELD_TRANS | \ - VINO_INTSTAT_A_FIFO_OF | \ - VINO_INTSTAT_A_END_DESC_TBL) -#define VINO_INTSTAT_B_FIELD_TRANS (1<<3) /* Field transferred int */ -#define VINO_INTSTAT_B_FIFO_OF (1<<4) /* FIFO overflow int */ -#define VINO_INTSTAT_B_END_DESC_TBL (1<<5) /* End of desc table int */ -#define VINO_INTSTAT_B (VINO_INTSTAT_B_FIELD_TRANS | \ - VINO_INTSTAT_B_FIFO_OF | \ - VINO_INTSTAT_B_END_DESC_TBL) +#define VINO_INTSTAT_A_EOF (1<<0) /* Field transferred int */ +#define VINO_INTSTAT_A_FIFO (1<<1) /* FIFO overflow int */ +#define VINO_INTSTAT_A_EOD (1<<2) /* End of desc table int */ +#define VINO_INTSTAT_A (VINO_INTSTAT_A_EOF | \ + VINO_INTSTAT_A_FIFO | \ + VINO_INTSTAT_A_EOD) +#define VINO_INTSTAT_B_EOF (1<<3) /* Field transferred int */ +#define VINO_INTSTAT_B_FIFO (1<<4) /* FIFO overflow int */ +#define VINO_INTSTAT_B_EOD (1<<5) /* End of desc table int */ +#define VINO_INTSTAT_B (VINO_INTSTAT_B_EOF | \ + VINO_INTSTAT_B_FIFO | \ + VINO_INTSTAT_B_EOD) u32 _pad_intr_status; volatile u32 intr_status; diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 5dbd9f6bf353..4437bdebe24f 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -576,7 +576,6 @@ static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore, - .force = &ignore, }; static struct i2c_driver vpx3220_i2c_driver; diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 25743085b2d5..eed2acea1779 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -737,7 +737,7 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = { }; static struct i2c_adapter zoran_i2c_adapter_template = { - I2C_DEVNAME("zr36057"), + .name = "zr36057", .id = I2C_HW_B_ZR36067, .algo = NULL, .client_register = zoran_i2c_client_register, |