diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2006-01-19 16:39:33 +0000 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2006-01-19 16:39:33 +0000 |
commit | 944d79559d154c12becde0dab327016cf438f46c (patch) | |
tree | 50c101806f4d3b6585222dda060559eb4f3e005a /drivers/media/dvb | |
parent | d087e4bdd24ebe3ae3d0b265b6573ec901af4b4b (diff) | |
parent | 0f36b018b2e314d45af86449f1a97facb1fbe300 (diff) |
Merge branch 'master' of /usr/src/ntfs-2.6/
Diffstat (limited to 'drivers/media/dvb')
91 files changed, 2921 insertions, 784 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 21a9045b3ef..0b940e152b7 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -298,7 +298,7 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir } static int lgdt3303_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) + struct dvb_frontend_parameters* params) { struct flexcop_device *fc = fe->dvb->priv; u8 buf[4]; @@ -485,12 +485,16 @@ static struct stv0297_config alps_tdee4_stv0297_config = { /* try to figure out the frontend, each card/box can have on of the following list */ int flexcop_frontend_init(struct flexcop_device *fc) { + struct dvb_frontend_ops *ops; + /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { - fc->fe->ops->set_voltage = flexcop_set_voltage; + ops = fc->fe->ops; + + ops->set_voltage = flexcop_set_voltage; - fc->fe_sleep = fc->fe->ops->sleep; - fc->fe->ops->sleep = flexcop_sleep; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; fc->dev_type = FC_SKY; info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address); @@ -522,15 +526,17 @@ int flexcop_frontend_init(struct flexcop_device *fc) } else /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { - fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; - fc->fe->ops->set_tone = flexcop_set_tone; - fc->fe->ops->set_voltage = flexcop_set_voltage; + ops = fc->fe->ops; + + ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + ops->diseqc_send_burst = flexcop_diseqc_send_burst; + ops->set_tone = flexcop_set_tone; + ops->set_voltage = flexcop_set_voltage; - fc->fe_sleep = fc->fe->ops->sleep; - fc->fe->ops->sleep = flexcop_sleep; + fc->fe_sleep = ops->sleep; + ops->sleep = flexcop_sleep; - fc->dev_type = FC_SKY_OLD; + fc->dev_type = FC_SKY_OLD; info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address); } @@ -540,8 +546,9 @@ int flexcop_frontend_init(struct flexcop_device *fc) } else { if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { err("frontend registration failed!"); - if (fc->fe->ops->release != NULL) - fc->fe->ops->release(fc->fe); + ops = fc->fe->ops; + if (ops->release != NULL) + ops->release(fc->fe); fc->fe = NULL; return -EINVAL; } diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h index 23cc6431e2b..3153f9513c6 100644 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -39,11 +39,13 @@ extern const char *flexcop_device_names[]; /* FlexCop IBI Registers */ #if defined(__LITTLE_ENDIAN) #include "flexcop_ibi_value_le.h" -#elif defined(__BIG_ENDIAN) +#else +#if defined(__BIG_ENDIAN) #include "flexcop_ibi_value_be.h" #else #error no endian defined #endif +#endif #define fc_data_Tag_ID_DVB 0x3e #define fc_data_Tag_ID_ATSC 0x3f diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 0a78ba3737a..a6c91db40ad 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -544,7 +544,6 @@ static struct usb_device_id flexcop_usb_table [] = { /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver flexcop_usb_driver = { - .owner = THIS_MODULE, .name = "b2c2_flexcop_usb", .probe = flexcop_usb_probe, .disconnect = flexcop_usb_disconnect, diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 123ed96f6fa..56ba5247067 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -220,20 +220,18 @@ EXPORT_SYMBOL(flexcop_reset_block_300); struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) { void *bus; - struct flexcop_device *fc = kmalloc(sizeof(struct flexcop_device), GFP_KERNEL); + struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), GFP_KERNEL); if (!fc) { err("no memory"); return NULL; } - memset(fc, 0, sizeof(struct flexcop_device)); - bus = kmalloc(bus_specific_len, GFP_KERNEL); + bus = kzalloc(bus_specific_len, GFP_KERNEL); if (!bus) { err("no memory"); kfree(fc); return NULL; } - memset(bus, 0, bus_specific_len); fc->bus_specific = bus; diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index f2957145003..a04bb61f21f 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -542,7 +542,7 @@ static struct pci_driver bt878_pci_driver = { .remove = bt878_remove, }; -static int bt878_pci_driver_registered = 0; +static int bt878_pci_driver_registered; /*******************************/ /* Module management functions */ diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 8977c7a313d..3a2ff1cc24b 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1341,30 +1341,40 @@ 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, + unsigned int mode_flags, + int *delay, + fe_status_t *status) { struct dst_state *state = fe->demodulator_priv; - dst_set_freq(state, p->frequency); - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + if (p != NULL) { + dst_set_freq(state, p->frequency); + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); - 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); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); - - } 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) { - 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); + 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); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + + } 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) { + 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); + } + dst_write_tuna(fe); } - dst_write_tuna(fe); + if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) + dst_read_status(fe, status); + + *delay = HZ/10; return 0; } @@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = { .release = dst_release, .init = dst_init, - .set_frontend = dst_set_frontend, + .tune = dst_set_frontend, .get_frontend = dst_get_frontend, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, @@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = { .release = dst_release, .init = dst_init, - .set_frontend = dst_set_frontend, + .tune = dst_set_frontend, .get_frontend = dst_get_frontend, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, @@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = { .release = dst_release, .init = dst_init, - .set_frontend = dst_set_frontend, + .tune = dst_set_frontend, .get_frontend = dst_get_frontend, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 2239651969c..c650b4bf7f5 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -283,16 +283,17 @@ 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; } - 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) { diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 77977e9c013..ea27b15007e 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -600,7 +600,6 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) struct dst_state* state = NULL; switch(type) { -#ifdef BTTV_BOARD_DVICO_DVBT_LITE case BTTV_BOARD_DVICO_DVBT_LITE: card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); if (card->fe != NULL) { @@ -608,22 +607,15 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) card->fe->ops->info.frequency_max = 862000000; } break; -#endif -#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: lgdt330x_reset(card); card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter); if (card->fe != NULL) dprintk ("dvb_bt8xx: lgdt330x detected\n"); break; -#endif -#ifdef BTTV_BOARD_TWINHAN_VP3021 - case BTTV_BOARD_TWINHAN_VP3021: -#else case BTTV_BOARD_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. @@ -787,17 +779,15 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) return 0; } -static int dvb_bt8xx_probe(struct device *dev) +static int dvb_bt8xx_probe(struct bttv_sub_device *sub) { - struct bttv_sub_device *sub = to_bttv_sub_dev(dev); struct dvb_bt8xx_card *card; struct pci_dev* bttv_pci_dev; int ret; - if (!(card = kmalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) + if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) return -ENOMEM; - memset(card, 0, sizeof(*card)); init_MUTEX(&card->lock); card->bttv_nr = sub->core->nr; strncpy(card->card_name, sub->core->name, sizeof(sub->core->name)); @@ -812,9 +802,7 @@ static int dvb_bt8xx_probe(struct device *dev) card->irq_err_ignore = 0; break; -#ifdef BTTV_BOARD_DVICO_DVBT_LITE case BTTV_BOARD_DVICO_DVBT_LITE: -#endif card->gpio_mode = 0x0400C060; card->op_sync_orin = 0; card->irq_err_ignore = 0; @@ -823,19 +811,13 @@ static int dvb_bt8xx_probe(struct device *dev) * DA_APP(parallel) */ break; -#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: -#endif card->gpio_mode = 0x0400c060; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; break; -#ifdef BTTV_BOARD_TWINHAN_VP3021 - case BTTV_BOARD_TWINHAN_VP3021: -#else case BTTV_BOARD_NEBULA_DIGITV: -#endif case BTTV_BOARD_AVDVBT_761: card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->op_sync_orin = 0; @@ -907,13 +889,13 @@ static int dvb_bt8xx_probe(struct device *dev) return ret; } - dev_set_drvdata(dev, card); + dev_set_drvdata(&sub->dev, card); return 0; } -static int dvb_bt8xx_remove(struct device *dev) +static void dvb_bt8xx_remove(struct bttv_sub_device *sub) { - struct dvb_bt8xx_card *card = dev_get_drvdata(dev); + struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); @@ -929,21 +911,19 @@ static int dvb_bt8xx_remove(struct device *dev) dvb_unregister_adapter(&card->dvb_adapter); kfree(card); - - return 0; } static struct bttv_sub_driver driver = { .drv = { .name = "dvb-bt8xx", - .probe = dvb_bt8xx_probe, - .remove = dvb_bt8xx_remove, - /* FIXME: - * .shutdown = dvb_bt8xx_shutdown, - * .suspend = dvb_bt8xx_suspend, - * .resume = dvb_bt8xx_resume, - */ }, + .probe = dvb_bt8xx_probe, + .remove = dvb_bt8xx_remove, + /* FIXME: + * .shutdown = dvb_bt8xx_shutdown, + * .suspend = dvb_bt8xx_suspend, + * .resume = dvb_bt8xx_resume, + */ }; static int __init dvb_bt8xx_init(void) diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig index 7cf4c4a888e..6018fcdba1e 100644 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ b/drivers/media/dvb/cinergyT2/Kconfig @@ -21,35 +21,35 @@ config DVB_CINERGYT2_TUNING config DVB_CINERGYT2_STREAM_URB_COUNT int "Number of queued USB Request Blocks for Highspeed Stream Transfers" depends on DVB_CINERGYT2_TUNING - default "32" + default "32" help USB Request Blocks for Highspeed Stream transfers are scheduled in a queue for the Host Controller. Usually the default value is a safe choice. - You may increase this number if you are using this device in a - Server Environment with many high-traffic USB Highspeed devices + You may increase this number if you are using this device in a + Server Environment with many high-traffic USB Highspeed devices sharing the same USB bus. config DVB_CINERGYT2_STREAM_BUF_SIZE int "Size of URB Stream Buffers for Highspeed Transfers" depends on DVB_CINERGYT2_TUNING - default "512" + default "512" help Should be a multiple of native buffer size of 512 bytes. Default value is a safe choice. - You may increase this number if you are using this device in a - Server Environment with many high-traffic USB Highspeed devices + You may increase this number if you are using this device in a + Server Environment with many high-traffic USB Highspeed devices sharing the same USB bus. config DVB_CINERGYT2_QUERY_INTERVAL int "Status update interval [milliseconds]" depends on DVB_CINERGYT2_TUNING - default "250" + default "250" help This is the interval for status readouts from the demodulator. You may try lower values if you need more responsive signal quality @@ -64,9 +64,9 @@ config DVB_CINERGYT2_QUERY_INTERVAL config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE bool "Register the onboard IR Remote Control Receiver as Input Device" depends on DVB_CINERGYT2_TUNING - default "yes" + default "yes" help - Enable this option if you want to use the onboard Infrared Remote + Enable this option if you want to use the onboard Infrared Remote Control Receiver as Linux-Input device. Right now only the keycode table for the default Remote Control @@ -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 "50" + 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 336fc284fa5..c4b4c5b6b7c 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define dprintk(level, args...) \ do { \ if ((debug & level)) { \ - printk("%s: %s(): ", __stringify(KBUILD_MODNAME), \ + printk("%s: %s(): ", KBUILD_MODNAME, \ __FUNCTION__); \ printk(args); } \ } while (0) @@ -131,6 +131,8 @@ struct cinergyt2 { wait_queue_head_t poll_wq; int pending_fe_events; + int disconnect_pending; + atomic_t inuse; void *streambuf; dma_addr_t streambuf_dmahandle; @@ -343,7 +345,7 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed) struct dvb_demux *demux = dvbdmxfeed->demux; struct cinergyt2 *cinergyt2 = demux->priv; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (cinergyt2->streaming == 0) @@ -359,7 +361,7 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed) struct dvb_demux *demux = dvbdmxfeed->demux; struct cinergyt2 *cinergyt2 = demux->priv; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (--cinergyt2->streaming == 0) @@ -479,23 +481,37 @@ static int cinergyt2_open (struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - int err; + int err = -ERESTARTSYS; - if ((err = dvb_generic_open(inode, file))) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + + if ((err = dvb_generic_open(inode, file))) { + up(&cinergyt2->sem); return err; + } - if (down_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { cinergyt2_sleep(cinergyt2, 0); schedule_delayed_work(&cinergyt2->query_work, HZ/2); } + atomic_inc(&cinergyt2->inuse); + up(&cinergyt2->sem); return 0; } +static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) +{ + dvb_unregister_device(cinergyt2->fedev); + dvb_unregister_adapter(&cinergyt2->adapter); + + cinergyt2_free_stream_urbs(cinergyt2); + kfree(cinergyt2); +} + static int cinergyt2_release (struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; @@ -504,7 +520,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file) if (down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) { cancel_delayed_work(&cinergyt2->query_work); flush_scheduled_work(); cinergyt2_sleep(cinergyt2, 1); @@ -512,6 +528,11 @@ static int cinergyt2_release (struct inode *inode, struct file *file) up(&cinergyt2->sem); + if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) { + warn("delayed unregister in release"); + cinergyt2_unregister(cinergyt2); + } + return dvb_generic_release(inode, file); } @@ -519,7 +540,14 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; + + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + poll_wait(file, &cinergyt2->poll_wq, wait); + + up(&cinergyt2->sem); + return (POLLIN | POLLRDNORM | POLLPRI); } @@ -564,10 +592,15 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file, (__u16 __user *) arg); case FE_READ_UNCORRECTED_BLOCKS: - /* UNC are already converted to host byte order... */ - return put_user(stat->uncorrected_block_count, - (__u32 __user *) arg); + { + uint32_t unc_count; + + unc_count = stat->uncorrected_block_count; + stat->uncorrected_block_count = 0; + /* UNC are already converted to host byte order... */ + return put_user(unc_count,(__u32 __user *) arg); + } case FE_SET_FRONTEND: { struct dvbt_set_parameters_msg *param = &cinergyt2->param; @@ -580,7 +613,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file, if (copy_from_user(&p, (void __user*) arg, sizeof(p))) return -EFAULT; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; @@ -691,7 +724,7 @@ static void cinergyt2_query_rc (void *data) struct cinergyt2_rc_event rc_events[12]; int n, len, i; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return; len = cinergyt2_command(cinergyt2, buf, sizeof(buf), @@ -786,7 +819,6 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { cancel_delayed_work(&cinergyt2->rc_query_work); - flush_scheduled_work(); input_unregister_device(cinergyt2->rc_input_dev); } @@ -817,7 +849,7 @@ static void cinergyt2_query (void *data) uint8_t lock_bits; uint32_t unc; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return; unc = s->uncorrected_block_count; @@ -917,28 +949,25 @@ static void cinergyt2_disconnect (struct usb_interface *intf) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); - if (down_interruptible(&cinergyt2->sem)) - return; + flush_scheduled_work(); cinergyt2_unregister_rc(cinergyt2); + cancel_delayed_work(&cinergyt2->query_work); + wake_up_interruptible(&cinergyt2->poll_wq); + cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); - dvb_net_release(&cinergyt2->dvbnet); - dvb_dmxdev_release(&cinergyt2->dmxdev); - dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_device(cinergyt2->fedev); - dvb_unregister_adapter(&cinergyt2->adapter); + cinergyt2->disconnect_pending = 1; - cinergyt2_free_stream_urbs(cinergyt2); - up(&cinergyt2->sem); - kfree(cinergyt2); + if (!atomic_read(&cinergyt2->inuse)) + cinergyt2_unregister(cinergyt2); } static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (state.event > PM_EVENT_ON) { @@ -961,7 +990,7 @@ static int cinergyt2_resume (struct usb_interface *intf) struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); struct dvbt_set_parameters_msg *param = &cinergyt2->param; - if (down_interruptible(&cinergyt2->sem)) + if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; if (!cinergyt2->sleeping) { @@ -986,7 +1015,6 @@ static const struct usb_device_id cinergyt2_table [] __devinitdata = { MODULE_DEVICE_TABLE(usb, cinergyt2_table); static struct usb_driver cinergyt2_driver = { - .owner = THIS_MODULE, .name = "cinergyT2", .probe = cinergyt2_probe, .disconnect = cinergyt2_disconnect, @@ -1015,4 +1043,3 @@ module_exit (cinergyt2_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); - diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig index a9a7b342104..12ee912a570 100644 --- a/drivers/media/dvb/dvb-core/Kconfig +++ b/drivers/media/dvb/dvb-core/Kconfig @@ -5,7 +5,7 @@ config DVB_CORE help DVB core utility functions for device handling, software fallbacks etc. Say Y when you have a DVB card and want to use it. Say Y if your want - to build your drivers outside the kernel, but need the DVB core. All + to build your drivers outside the kernel, but need the DVB core. All in-kernel drivers will select this automatically if needed. If unsure say N. diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile index c6baac20f52..7adb50c1e8e 100644 --- a/drivers/media/dvb/dvb-core/Makefile +++ b/drivers/media/dvb/dvb-core/Makefile @@ -3,7 +3,7 @@ # dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ - dvb_ca_en50221.o dvb_frontend.o \ + dvb_ca_en50221.o dvb_frontend.o \ dvb_net.o dvb_ringbuffer.o obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 5956c35d34a..00347a75068 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1649,21 +1649,17 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, return -EINVAL; /* initialise the system data */ - if ((ca = - (struct dvb_ca_private *) kmalloc(sizeof(struct dvb_ca_private), - GFP_KERNEL)) == NULL) { + if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { ret = -ENOMEM; goto error; } - memset(ca, 0, sizeof(struct dvb_ca_private)); ca->pub = pubca; ca->flags = flags; ca->slot_count = slot_count; - if ((ca->slot_info = kmalloc(sizeof(struct dvb_ca_slot) * slot_count, GFP_KERNEL)) == NULL) { + if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { ret = -ENOMEM; goto error; } - memset(ca->slot_info, 0, sizeof(struct dvb_ca_slot) * slot_count); init_waitqueue_head(&ca->wait_queue); ca->thread_pid = 0; init_waitqueue_head(&ca->thread_queue); @@ -1745,9 +1741,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); - if (ca->slot_info[i].rx_buffer.data != NULL) { - vfree(ca->slot_info[i].rx_buffer.data); - } + vfree(ca->slot_info[i].rx_buffer.data); } kfree(ca->slot_info); dvb_unregister_device(ca->dvbdev); diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c index c49fd0bd718..772003fb182 100644 --- a/drivers/media/dvb/dvb-core/dvb_filter.c +++ b/drivers/media/dvb/dvb-core/dvb_filter.c @@ -409,16 +409,16 @@ static u8 *skip_pes_header(u8 **bufp) if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ if (buf[7] & PTS_ONLY) - pts = buf+9; + pts = buf+9; else pts = NULL; buf = inbuf + 9 + inbuf[8]; } else { /* mpeg1 */ for (buf = inbuf + 6; *buf == 0xff; buf++) - if (buf == inbuf + 6 + 16) { - break; - } + if (buf == inbuf + 6 + 16) { + break; + } if ((*buf & 0xc0) == 0x40) - buf += 2; + buf += 2; skip = mpeg1_skip_table [*buf >> 4]; if (skip == 5 || skip == 10) pts = buf; else pts = NULL; @@ -529,9 +529,9 @@ static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_t pic->picture_header = 0; pic->sequence_header_data = ( INIT_HORIZONTAL_SIZE << 20 ) - | ( INIT_VERTICAL_SIZE << 8 ) - | ( INIT_ASPECT_RATIO << 4 ) - | ( INIT_FRAME_RATE ); + | ( INIT_VERTICAL_SIZE << 8 ) + | ( INIT_ASPECT_RATIO << 4 ) + | ( INIT_FRAME_RATE ); pic->mpeg1_flag = 0; pic->vinfo.horizontal_size = INIT_DISP_HORIZONTAL_SIZE; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 95ea5095e07..771f32d889e 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex); struct dvb_frontend_private { + /* thread/frontend values */ struct dvb_device *dvbdev; struct dvb_frontend_parameters parameters; struct dvb_fe_events events; @@ -100,20 +101,25 @@ struct dvb_frontend_private { wait_queue_head_t wait_queue; pid_t thread_pid; unsigned long release_jiffies; - int state; - int bending; - int lnb_drift; - int inversion; - int auto_step; - int auto_sub_step; - int started_auto_step; - int min_delay; - int max_drift; - int step_size; - int exit; - int wakeup; + unsigned int exit; + unsigned int wakeup; fe_status_t status; - fe_sec_tone_mode_t tone; + unsigned long tune_mode_flags; + unsigned int delay; + + /* swzigzag values */ + unsigned int state; + unsigned int bending; + int lnb_drift; + unsigned int inversion; + unsigned int auto_step; + unsigned int auto_sub_step; + unsigned int started_auto_step; + unsigned int min_delay; + unsigned int max_drift; + unsigned int step_size; + int quality; + unsigned int check_wrapped; }; @@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe) fe->ops->init(fe); } -static void update_delay(int *quality, int *delay, int min_delay, int locked) +static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked) { - int q2; + int q2; - dprintk ("%s\n", __FUNCTION__); + dprintk ("%s\n", __FUNCTION__); - if (locked) - (*quality) = (*quality * 220 + 36*256) / 256; - else - (*quality) = (*quality * 220 + 0) / 256; + if (locked) + (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; + else + (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; - q2 = *quality - 128; - q2 *= q2; + q2 = fepriv->quality - 128; + q2 *= q2; - *delay = min_delay + q2 * HZ / (128*128); + fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); } /** @@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked) * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT * @returns Number of complete iterations that have been performed. */ -static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) +static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped) { int autoinversion; int ready = 0; @@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) return 0; } +static void dvb_frontend_swzigzag(struct dvb_frontend *fe) +{ + fe_status_t s; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + /* if we've got no parameters, just keep idling */ + if (fepriv->state & FESTATE_IDLE) { + fepriv->delay = 3*HZ; + fepriv->quality = 0; + return; + } + + /* in SCAN mode, we just set the frontend when asked and leave it alone */ + if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { + if (fepriv->state & FESTATE_RETUNE) { + if (fe->ops->set_frontend) + fe->ops->set_frontend(fe, &fepriv->parameters); + fepriv->state = FESTATE_TUNED; + } + fepriv->delay = 3*HZ; + fepriv->quality = 0; + return; + } + + /* get the frontend status */ + if (fepriv->state & FESTATE_RETUNE) { + s = 0; + } else { + if (fe->ops->read_status) + fe->ops->read_status(fe, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); + fepriv->status = s; + } + } + + /* if we're not tuned, and we have a lock, move to the TUNED state */ + if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + fepriv->state = FESTATE_TUNED; + + /* if we're tuned, then we have determined the correct inversion */ + if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && + (fepriv->parameters.inversion == INVERSION_AUTO)) { + fepriv->parameters.inversion = fepriv->inversion; + } + return; + } + + /* if we are tuned already, check we're still locked */ + if (fepriv->state & FESTATE_TUNED) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + + /* we're tuned, and the lock is still good... */ + if (s & FE_HAS_LOCK) { + return; + } else { /* if we _WERE_ tuned, but now don't have a lock */ + fepriv->state = FESTATE_ZIGZAG_FAST; + fepriv->started_auto_step = fepriv->auto_step; + fepriv->check_wrapped = 0; + } + } + + /* don't actually do anything if we're in the LOSTLOCK state, + * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ + if ((fepriv->state & FESTATE_LOSTLOCK) && + (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + return; + } + + /* don't do anything if we're in the DISEQC state, since this + * might be someone with a motorized dish controlled by DISEQC. + * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ + if (fepriv->state & FESTATE_DISEQC) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + return; + } + + /* if we're in the RETUNE state, set everything up for a brand + * new scan, keeping the current inversion setting, as the next + * tune is _very_ likely to require the same */ + if (fepriv->state & FESTATE_RETUNE) { + fepriv->lnb_drift = 0; + fepriv->auto_step = 0; + fepriv->auto_sub_step = 0; + fepriv->started_auto_step = 0; + fepriv->check_wrapped = 0; + } + + /* fast zigzag. */ + if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { + fepriv->delay = fepriv->min_delay; + + /* peform a tune */ + if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) { + /* OK, if we've run out of trials at the fast speed. + * Drop back to slow for the _next_ attempt */ + fepriv->state = FESTATE_SEARCHING_SLOW; + fepriv->started_auto_step = fepriv->auto_step; + return; + } + fepriv->check_wrapped = 1; + + /* if we've just retuned, enter the ZIGZAG_FAST state. + * This ensures we cannot return from an + * FE_SET_FRONTEND ioctl before the first frontend tune + * occurs */ + if (fepriv->state & FESTATE_RETUNE) { + fepriv->state = FESTATE_TUNING_FAST; + } + } + + /* slow zigzag */ + if (fepriv->state & FESTATE_SEARCHING_SLOW) { + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + + /* Note: don't bother checking for wrapping; we stay in this + * state until we get a lock */ + dvb_frontend_swzigzag_autotune(fe, 0); + } +} + static int dvb_frontend_is_exiting(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -330,7 +459,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe) if (fepriv->dvbdev->writers == 1) if (time_after(jiffies, fepriv->release_jiffies + - dvb_shutdown_timeout * HZ)) + dvb_shutdown_timeout * HZ)) return 1; return 0; @@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe) wake_up_interruptible(&fepriv->wait_queue); } -/* - * FIXME: use linux/kthread.h - */ static int dvb_frontend_thread(void *data) { struct dvb_frontend *fe = data; struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; char name [15]; - int quality = 0, delay = 3*HZ; fe_status_t s; - int check_wrapped = 0; + struct dvb_frontend_parameters *params; dprintk("%s\n", __FUNCTION__); @@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data) sigfillset(¤t->blocked); unlock_kernel(); + fepriv->check_wrapped = 0; + fepriv->quality = 0; + fepriv->delay = 3*HZ; fepriv->status = 0; dvb_frontend_init(fe); fepriv->wakeup = 0; @@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data) timeout = wait_event_interruptible_timeout(fepriv->wait_queue, dvb_frontend_should_wakeup(fe), - delay); + fepriv->delay); if (0 != dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ break; @@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data) if (down_interruptible(&fepriv->sem)) break; - /* if we've got no parameters, just keep idling */ - if (fepriv->state & FESTATE_IDLE) { - delay = 3*HZ; - quality = 0; - continue; - } + /* do an iteration of the tuning loop */ + if (fe->ops->tune) { + /* have we been asked to retune? */ + params = NULL; + if (fepriv->state & FESTATE_RETUNE) { + params = &fepriv->parameters; + fepriv->state = FESTATE_TUNED; + } - /* get the frontend status */ - if (fepriv->state & FESTATE_RETUNE) { - s = 0; - } else { - if (fe->ops->read_status) - fe->ops->read_status(fe, &s); + fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); fepriv->status = s; } - } - /* if we're not tuned, and we have a lock, move to the TUNED state */ - if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - fepriv->state = FESTATE_TUNED; - - /* if we're tuned, then we have determined the correct inversion */ - if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters.inversion == INVERSION_AUTO)) { - fepriv->parameters.inversion = fepriv->inversion; - } - continue; - } - - /* if we are tuned already, check we're still locked */ - if (fepriv->state & FESTATE_TUNED) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - - /* we're tuned, and the lock is still good... */ - if (s & FE_HAS_LOCK) - continue; - else { /* if we _WERE_ tuned, but now don't have a lock */ - fepriv->state = FESTATE_ZIGZAG_FAST; - fepriv->started_auto_step = fepriv->auto_step; - check_wrapped = 0; - } - } - - /* don't actually do anything if we're in the LOSTLOCK state, - * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ - if ((fepriv->state & FESTATE_LOSTLOCK) && - (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - continue; - } - - /* don't do anything if we're in the DISEQC state, since this - * might be someone with a motorized dish controlled by DISEQC. - * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ - if (fepriv->state & FESTATE_DISEQC) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - continue; - } - - /* if we're in the RETUNE state, set everything up for a brand - * new scan, keeping the current inversion setting, as the next - * tune is _very_ likely to require the same */ - if (fepriv->state & FESTATE_RETUNE) { - fepriv->lnb_drift = 0; - fepriv->auto_step = 0; - fepriv->auto_sub_step = 0; - fepriv->started_auto_step = 0; - check_wrapped = 0; - } - - /* fast zigzag. */ - if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { - delay = fepriv->min_delay; - - /* peform a tune */ - if (dvb_frontend_autotune(fe, check_wrapped)) { - /* OK, if we've run out of trials at the fast speed. - * Drop back to slow for the _next_ attempt */ - fepriv->state = FESTATE_SEARCHING_SLOW; - fepriv->started_auto_step = fepriv->auto_step; - continue; - } - check_wrapped = 1; - - /* if we've just retuned, enter the ZIGZAG_FAST state. - * This ensures we cannot return from an - * FE_SET_FRONTEND ioctl before the first frontend tune - * occurs */ - if (fepriv->state & FESTATE_RETUNE) { - fepriv->state = FESTATE_TUNING_FAST; - } - } - - /* slow zigzag */ - if (fepriv->state & FESTATE_SEARCHING_SLOW) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - - /* Note: don't bother checking for wrapping; we stay in this - * state until we get a lock */ - dvb_frontend_autotune(fe, 0); + } else { + dvb_frontend_swzigzag(fe); } } @@ -733,7 +775,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; - fepriv->tone = (fe_sec_tone_mode_t) parg; } break; @@ -747,7 +788,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops->dishnetwork_send_legacy_command) { - err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg); + err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } else if (fe->ops->set_voltage) { @@ -767,13 +808,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, * initialization, so parg is 8 bits and does not * include the initialization or start bit */ - unsigned int cmd = ((unsigned int) parg) << 1; + unsigned long cmd = ((unsigned long) parg) << 1; struct timeval nexttime; struct timeval tv[10]; int i; u8 last = 1; if (dvb_frontend_debug) - printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd); + printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd); do_gettimeofday(&nexttime); if (dvb_frontend_debug) memcpy(&tv[0], &nexttime, sizeof(struct timeval)); @@ -814,7 +855,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_ENABLE_HIGH_LNB_VOLTAGE: if (fe->ops->enable_high_lnb_voltage) - err = fe->ops->enable_high_lnb_voltage(fe, (int) parg); + err = fe->ops->enable_high_lnb_voltage(fe, (long) parg); break; case FE_SET_FRONTEND: { @@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg); } break; + + case FE_SET_FRONTEND_TUNE_MODE: + fepriv->tune_mode_flags = (unsigned long) parg; + break; }; up (&fepriv->sem); @@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) /* empty event queue */ fepriv->events.eventr = fepriv->events.eventw = 0; + + /* normal tune mode when opened R/W */ + fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; } return ret; @@ -976,13 +1024,12 @@ int dvb_register_frontend(struct dvb_adapter* dvb, if (down_interruptible (&frontend_mutex)) return -ERESTARTSYS; - fe->frontend_priv = kmalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); + fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); if (fe->frontend_priv == NULL) { up(&frontend_mutex); return -ENOMEM; } fepriv = fe->frontend_priv; - memset(fe->frontend_priv, 0, sizeof(struct dvb_frontend_private)); init_MUTEX (&fepriv->sem); init_waitqueue_head (&fepriv->wait_queue); @@ -990,7 +1037,6 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->events.sem); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; - fepriv->tone = SEC_TONE_OFF; printk ("DVB: registering frontend %i (%s)...\n", fe->dvb->num, diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 1e0840d02f1..70a6d14efda 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -58,10 +58,19 @@ struct dvb_frontend_ops { int (*init)(struct dvb_frontend* fe); int (*sleep)(struct dvb_frontend* fe); + /* if this is set, it overrides the default swzigzag */ + int (*tune)(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params, + unsigned int mode_flags, + int *delay, + fe_status_t *status); + + /* these two are only used for the swzigzag code */ int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); + int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*read_ber)(struct dvb_frontend* fe, u32* ber); int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); @@ -74,8 +83,9 @@ struct dvb_frontend_ops { int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg); - int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); + int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); + int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); + int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); }; #define MAX_EVENT 8 diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 86bba81e851..6711eb6a058 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1222,7 +1222,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) return if_num; } -static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned int num) +static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) { struct net_device *net = dvbnet->device[num]; struct dvb_net_priv *priv; @@ -1296,9 +1296,9 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if ((unsigned int) parg >= DVB_NET_DEVICES_MAX) + if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) return -EINVAL; - ret = dvb_net_remove_if(dvbnet, (unsigned int) parg); + ret = dvb_net_remove_if(dvbnet, (unsigned long) parg); if (!ret) module_put(dvbdev->adapter->module); return ret; diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index 283c6e9339a..77ad2410f4d 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -112,10 +112,10 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; if (split > 0) { if (!usermem) - memcpy(buf, rbuf->data+rbuf->pread, split); + memcpy(buf, rbuf->data+rbuf->pread, split); else - if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) + return -EFAULT; buf += split; todo -= split; rbuf->pread = 0; @@ -124,7 +124,7 @@ ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, in memcpy(buf, rbuf->data+rbuf->pread, todo); else if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) - return -EFAULT; + return -EFAULT; rbuf->pread = (rbuf->pread + todo) % rbuf->size; @@ -167,7 +167,7 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le } ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem) + int offset, u8* buf, size_t len, int usermem) { size_t todo; size_t split; @@ -183,10 +183,10 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; if (split > 0) { if (!usermem) - memcpy(buf, rbuf->data+idx, split); + memcpy(buf, rbuf->data+idx, split); else - if (copy_to_user(buf, rbuf->data+idx, split)) - return -EFAULT; + if (copy_to_user(buf, rbuf->data+idx, split)) + return -EFAULT; buf += split; todo -= split; idx = 0; @@ -195,7 +195,7 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, memcpy(buf, rbuf->data+idx, todo); else if (copy_to_user(buf, rbuf->data+idx, todo)) - return -EFAULT; + return -EFAULT; return len; } @@ -209,12 +209,12 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) // clean up disposed packets while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) { - pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; - pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); - DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); + pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; + pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); + DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); } else { - // first packet is not disposed, so we stop cleaning now - break; + // first packet is not disposed, so we stop cleaning now + break; } } } @@ -242,8 +242,8 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* curpktstatus = rbuf->data[(idx + 2) % rbuf->size]; if (curpktstatus == PKT_READY) { - *pktlen = curpktlen; - return idx; + *pktlen = curpktlen; + return idx; } consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h index fa476f662f8..6d256097277 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h @@ -106,7 +106,7 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); ** returns number of bytes transferred or -EFAULT */ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, - size_t len, int usermem); + size_t len, int usermem); /* write routines & macros */ @@ -121,7 +121,7 @@ extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, ** returns number of bytes transferred or -EFAULT */ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, - size_t len); + size_t len); /** @@ -133,7 +133,7 @@ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. */ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, - size_t len); + size_t len); /** * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this @@ -149,7 +149,7 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, * returns Number of bytes read, or -EFAULT. */ extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem); + int offset, u8* buf, size_t len, int usermem); /** * Dispose of a packet in the ring buffer. diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index a4aee866585..54f8b95717b 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -33,7 +33,7 @@ #include <linux/device.h> #include <linux/fs.h> #include <linux/cdev.h> - +#include <linux/mutex.h> #include "dvbdev.h" static int dvbdev_debug; @@ -44,7 +44,7 @@ MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); #define dprintk if (dvbdev_debug) printk static LIST_HEAD(dvb_adapter_list); -static DECLARE_MUTEX(dvbdev_register_lock); +static DEFINE_MUTEX(dvbdev_register_lock); static const char * const dnames[] = { "video", "audio", "sec", "frontend", "demux", "dvr", "ca", @@ -92,10 +92,10 @@ static int dvb_device_open(struct inode *inode, struct file *file) old_fops = file->f_op; file->f_op = fops_get(dvbdev->fops); if(file->f_op->open) - err = file->f_op->open(inode,file); + err = file->f_op->open(inode,file); if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); + fops_put(file->f_op); + file->f_op = fops_get(old_fops); } fops_put(old_fops); return err; @@ -202,11 +202,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, struct dvb_device *dvbdev; int id; - if (down_interruptible (&dvbdev_register_lock)) + if (mutex_lock_interruptible(&dvbdev_register_lock)) return -ERESTARTSYS; if ((id = dvbdev_get_free_id (adap, type)) < 0) { - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); *pdvbdev = NULL; printk ("%s: could get find free device id...\n", __FUNCTION__); return -ENFILE; @@ -215,11 +215,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); if (!dvbdev) { - up(&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); return -ENOMEM; } - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); memcpy(dvbdev, template, sizeof(struct dvb_device)); dvbdev->type = type; @@ -289,11 +289,11 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu { int num; - if (down_interruptible (&dvbdev_register_lock)) + if (mutex_lock_interruptible(&dvbdev_register_lock)) return -ERESTARTSYS; if ((num = dvbdev_get_free_adapter_num ()) < 0) { - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); return -ENFILE; } @@ -309,7 +309,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu list_add_tail (&adap->list_head, &dvb_adapter_list); - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); return num; } @@ -320,10 +320,10 @@ int dvb_unregister_adapter(struct dvb_adapter *adap) { devfs_remove("dvb/adapter%d", adap->num); - if (down_interruptible (&dvbdev_register_lock)) + if (mutex_lock_interruptible(&dvbdev_register_lock)) return -ERESTARTSYS; list_del (&adap->list_head); - up (&dvbdev_register_lock); + mutex_unlock(&dvbdev_register_lock); return 0; } EXPORT_SYMBOL(dvb_unregister_adapter); @@ -356,18 +356,18 @@ int dvb_usercopy(struct inode *inode, struct file *file, case _IOC_WRITE: case (_IOC_WRITE | _IOC_READ): if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; + parg = sbuf; } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; } err = -EFAULT; if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) - goto out; + goto out; break; } @@ -384,7 +384,7 @@ int dvb_usercopy(struct inode *inode, struct file *file, case _IOC_READ: case (_IOC_WRITE | _IOC_READ): if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; + err = -EFAULT; break; } diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 0cc6e4a0e27..74ed5853f0f 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -97,7 +97,7 @@ we simply define out own dvb_usercopy(), which will hopefully become generic_usercopy() someday... */ extern int dvb_usercopy(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, + unsigned int cmd, unsigned long arg, int (*func)(struct inode *inode, struct file *file, unsigned int cmd, void *arg)); diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 54e2b29076b..90a69d343b7 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -37,16 +37,16 @@ config DVB_USB_DIBUSB_MB DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator. Devices supported by this driver: - TwinhanDTV USB-Ter (VP7041) - TwinhanDTV Magic Box (VP7041e) - KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0 - Hama DVB-T USB1.1-Box - DiBcom USB1.1 reference devices (non-public) - Ultima Electronic/Artec T1 USB TVBOX + Artec T1 USB1.1 boxes + Avermedia AverTV DVBT USB1.1 Compro Videomate DVB-U2000 - DVB-T USB + DiBcom USB1.1 reference devices (non-public) Grandtec DVB-T USB - Avermedia AverTV DVBT USB1.1 - Artec T1 USB1.1 boxes + Hama DVB-T USB1.1-Box + KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0 + TwinhanDTV Magic Box (VP7041e) + TwinhanDTV USB-Ter (VP7041) + Ultima Electronic/Artec T1 USB TVBOX The VP7041 seems to be identical to "CTS Portable" (Chinese Television System). @@ -54,6 +54,12 @@ config DVB_USB_DIBUSB_MB Say Y if you own such a device and want to use it. You should build it as a module. +config DVB_USB_DIBUSB_MB_FAULTY + bool "Support faulty USB IDs" + depends on DVB_USB_DIBUSB_MB + help + Support for faulty USB IDs due to an invalid EEPROM on some Artec devices. + config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB @@ -63,8 +69,8 @@ config DVB_USB_DIBUSB_MC DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator. Devices supported by this driver: - DiBcom USB2.0 reference devices (non-public) Artec T1 USB2.0 boxes + DiBcom USB2.0 reference devices (non-public) Say Y if you own such a device and want to use it. You should build it as a module. diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index 8c7beffb045..ce44aa6bbb8 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -144,7 +144,6 @@ static struct dvb_usb_properties a800_properties = { }; static struct usb_driver a800_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_a800", .probe = a800_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 3fe383f4bb4..a7fb06f4cd3 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -11,10 +11,11 @@ * design, so it can be reused for the "analogue-only" device (if it will * appear at all). * - * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue - * part + * TODO: Use the cx25840-driver for the analogue part * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2005 Michael Krufky (mkrufky@m1k.net) + * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au) * * 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 @@ -25,6 +26,9 @@ #include "cxusb.h" #include "cx22702.h" +#include "lgdt330x.h" +#include "mt352.h" +#include "mt352_priv.h" /* debug */ int dvb_usb_cxusb_debug; @@ -156,6 +160,119 @@ static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) return 0; } +static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + u8 ircode[4]; + int i; + + cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == ircode[2] && + keymap[i].data == ircode[3]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + +struct dvb_usb_rc_key dvico_mce_rc_keys[] = { + { 0xfe, 0x02, KEY_TV }, + { 0xfe, 0x0e, KEY_MP3 }, + { 0xfe, 0x1a, KEY_DVD }, + { 0xfe, 0x1e, KEY_FAVORITES }, + { 0xfe, 0x16, KEY_SETUP }, + { 0xfe, 0x46, KEY_POWER2 }, + { 0xfe, 0x0a, KEY_EPG }, + { 0xfe, 0x49, KEY_BACK }, + { 0xfe, 0x4d, KEY_MENU }, + { 0xfe, 0x51, KEY_UP }, + { 0xfe, 0x5b, KEY_LEFT }, + { 0xfe, 0x5f, KEY_RIGHT }, + { 0xfe, 0x53, KEY_DOWN }, + { 0xfe, 0x5e, KEY_OK }, + { 0xfe, 0x59, KEY_INFO }, + { 0xfe, 0x55, KEY_TAB }, + { 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */ + { 0xfe, 0x12, KEY_NEXTSONG }, /* Skip */ + { 0xfe, 0x42, KEY_ENTER }, /* Windows/Start */ + { 0xfe, 0x15, KEY_VOLUMEUP }, + { 0xfe, 0x05, KEY_VOLUMEDOWN }, + { 0xfe, 0x11, KEY_CHANNELUP }, + { 0xfe, 0x09, KEY_CHANNELDOWN }, + { 0xfe, 0x52, KEY_CAMERA }, + { 0xfe, 0x5a, KEY_TUNER }, /* Live */ + { 0xfe, 0x19, KEY_OPEN }, + { 0xfe, 0x0b, KEY_1 }, + { 0xfe, 0x17, KEY_2 }, + { 0xfe, 0x1b, KEY_3 }, + { 0xfe, 0x07, KEY_4 }, + { 0xfe, 0x50, KEY_5 }, + { 0xfe, 0x54, KEY_6 }, + { 0xfe, 0x48, KEY_7 }, + { 0xfe, 0x4c, KEY_8 }, + { 0xfe, 0x58, KEY_9 }, + { 0xfe, 0x13, KEY_ANGLE }, /* Aspect */ + { 0xfe, 0x03, KEY_0 }, + { 0xfe, 0x1f, KEY_ZOOM }, + { 0xfe, 0x43, KEY_REWIND }, + { 0xfe, 0x47, KEY_PLAYPAUSE }, + { 0xfe, 0x4f, KEY_FASTFORWARD }, + { 0xfe, 0x57, KEY_MUTE }, + { 0xfe, 0x0d, KEY_STOP }, + { 0xfe, 0x01, KEY_RECORD }, + { 0xfe, 0x4e, KEY_POWER }, +}; + +static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) +{ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + +static int cxusb_mt352_demod_init(struct dvb_frontend* fe) +{ /* used in both lgz201 and th7579 */ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; + static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + return 0; +} + struct cx22702_config cxusb_cx22702_config = { .demod_address = 0x63, @@ -165,17 +282,68 @@ struct cx22702_config cxusb_cx22702_config = { .pll_set = dvb_usb_pll_set_i2c, }; +struct lgdt330x_config cxusb_lgdt330x_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .pll_set = dvb_usb_pll_set_i2c, +}; + +struct mt352_config cxusb_dee1601_config = { + .demod_address = 0x0f, + .demod_init = cxusb_dee1601_demod_init, + .pll_set = dvb_usb_pll_set, +}; + +struct mt352_config cxusb_mt352_config = { + /* used in both lgz201 and th7579 */ + .demod_address = 0x0f, + .demod_init = cxusb_mt352_demod_init, + .pll_set = dvb_usb_pll_set, +}; + /* Callbacks for DVB USB */ -static int cxusb_tuner_attach(struct dvb_usb_device *d) +static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d) { u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; d->pll_addr = 0x61; - memcpy(d->pll_init,bpll,4); + memcpy(d->pll_init, bpll, 4); d->pll_desc = &dvb_pll_fmd1216me; return 0; } -static int cxusb_frontend_attach(struct dvb_usb_device *d) +static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d) +{ + u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 }; + /* bpll[2] : unset bit 3, set bits 4&5 + bpll[3] : 0x50 - digital, 0x20 - analog */ + d->pll_addr = 0x61; + memcpy(d->pll_init, bpll, 4); + d->pll_desc = &dvb_pll_tdvs_tua6034; + return 0; +} + +static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d) +{ + d->pll_addr = 0x61; + d->pll_desc = &dvb_pll_thomson_dtt7579; + return 0; +} + +static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d) +{ + d->pll_addr = 0x61; + d->pll_desc = &dvb_pll_lg_z201; + return 0; +} + +static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d) +{ + d->pll_addr = 0x60; + d->pll_desc = &dvb_pll_thomson_dtt7579; + return 0; +} + +static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d) { u8 b; if (usb_set_interface(d->udev,0,6) < 0) @@ -189,22 +357,107 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d) return -EIO; } +static int cxusb_lgdt330x_frontend_attach(struct dvb_usb_device *d) +{ + if (usb_set_interface(d->udev,0,7) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); + + if ((d->fe = lgdt330x_attach(&cxusb_lgdt330x_config, &d->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_mt352_frontend_attach(struct dvb_usb_device *d) +{ /* used in both lgz201 and th7579 */ + if (usb_set_interface(d->udev,0,0) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); + + if ((d->fe = mt352_attach(&cxusb_mt352_config, &d->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d) +{ + if (usb_set_interface(d->udev,0,0) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); + + if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +/* + * DViCO bluebird firmware needs the "warm" product ID to be patched into the + * firmware file before download. + */ + +#define BLUEBIRD_01_ID_OFFSET 6638 +static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw) +{ + if (fw->size < BLUEBIRD_01_ID_OFFSET + 4) + return -EINVAL; + + if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) && + fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) { + + /* FIXME: are we allowed to change the fw-data ? */ + fw->data[BLUEBIRD_01_ID_OFFSET + 2] = udev->descriptor.idProduct + 1; + fw->data[BLUEBIRD_01_ID_OFFSET + 3] = udev->descriptor.idProduct >> 8; + + return usb_cypress_load_firmware(udev,fw,CYPRESS_FX2); + } + + return -EINVAL; +} + /* DVB USB Driver stuff */ -static struct dvb_usb_properties cxusb_properties; +static struct dvb_usb_properties cxusb_medion_properties; +static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties; +static struct dvb_usb_properties cxusb_bluebird_dee1601_properties; +static struct dvb_usb_properties cxusb_bluebird_lgz201_properties; +static struct dvb_usb_properties cxusb_bluebird_dtt7579_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,NULL); + if (dvb_usb_device_init(intf,&cxusb_medion_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) { + return 0; + } + + return -EINVAL; } static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); -static struct dvb_usb_properties cxusb_properties = { +static struct dvb_usb_properties cxusb_medion_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, @@ -213,8 +466,8 @@ static struct dvb_usb_properties cxusb_properties = { .streaming_ctrl = cxusb_streaming_ctrl, .power_ctrl = cxusb_power_ctrl, - .frontend_attach = cxusb_frontend_attach, - .tuner_attach = cxusb_tuner_attach, + .frontend_attach = cxusb_cx22702_frontend_attach, + .tuner_attach = cxusb_fmd1216me_tuner_attach, .i2c_algo = &cxusb_i2c_algo, @@ -240,8 +493,176 @@ static struct dvb_usb_properties cxusb_properties = { } }; +static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, + .power_ctrl = cxusb_power_ctrl, + .frontend_attach = cxusb_lgdt330x_frontend_attach, + .tuner_attach = cxusb_lgh064f_tuner_attach, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV5 USB Gold", + { &cxusb_table[1], NULL }, + { &cxusb_table[2], NULL }, + }, + } +}; + +static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, + .power_ctrl = cxusb_power_ctrl, + .frontend_attach = cxusb_dee1601_frontend_attach, + .tuner_attach = cxusb_dee1601_tuner_attach, + + .i2c_algo = &cxusb_i2c_algo, + + .rc_interval = 150, + .rc_key_map = dvico_mce_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), + .rc_query = cxusb_rc_query, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + .num_device_descs = 2, + .devices = { + { "DViCO FusionHDTV DVB-T Dual USB", + { &cxusb_table[3], NULL }, + { &cxusb_table[4], NULL }, + }, + { "DigitalNow DVB-T Dual USB", + { &cxusb_table[9], NULL }, + { &cxusb_table[10], NULL }, + }, + } +}; + +static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, + .power_ctrl = cxusb_power_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_lgz201_tuner_attach, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T USB (LGZ201)", + { &cxusb_table[5], NULL }, + { &cxusb_table[6], NULL }, + }, + } +}; + +static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-01.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + /* use usb alt setting 0 for EP4 transfer (dvb-t), + use usb alt setting 7 for EP2 transfer (atsc) */ + + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, + .power_ctrl = cxusb_power_ctrl, + .frontend_attach = cxusb_mt352_frontend_attach, + .tuner_attach = cxusb_dtt7579_tuner_attach, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 5, + .endpoint = 0x04, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T USB (TH7579)", + { &cxusb_table[7], NULL }, + { &cxusb_table[8], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_cxusb", .probe = cxusb_probe, .disconnect = dvb_usb_device_exit, @@ -270,6 +691,8 @@ module_init (cxusb_module_init); module_exit (cxusb_module_exit); MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); +MODULE_AUTHOR("Michael Krufky <mkrufky@m1k.net>"); +MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>"); MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); MODULE_VERSION("1.0-alpha"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index 135c2a81f58..087c9942785 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -21,6 +21,8 @@ extern int dvb_usb_cxusb_debug; #define CMD_STREAMING_ON 0x36 #define CMD_STREAMING_OFF 0x37 +#define CMD_GET_IR_CODE 0x47 + #define CMD_ANALOG 0x50 #define CMD_DIGITAL 0x51 diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index aa271a2496d..dd5a1319588 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -65,11 +65,11 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d) d->tuner_pass_ctrl(d->fe,0,msg[0].addr); if (b2[0] == 0xfe) { - info("this device has the Thomson Cable onboard. Which is default."); + info("This device has the Thomson Cable onboard. Which is default."); dibusb_thomson_tuner_attach(d); } else { u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab }; - info("this device has the Panasonic ENV77H11D5 onboard."); + info("This device has the Panasonic ENV77H11D5 onboard."); d->pll_addr = 0x60; memcpy(d->pll_init,bpll,4); d->pll_desc = &dvb_pll_tda665x; @@ -98,15 +98,15 @@ static int dibusb_probe(struct usb_interface *intf, /* do not change the order of the ID table */ static struct usb_device_id dibusb_dib3000mb_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD)}, -/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM)}, +/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) }, +/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) }, /* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, /* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, /* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, /* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, /* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, -/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, +/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, +/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, /* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, /* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, /* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, @@ -117,27 +117,34 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) }, /* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, /* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, -/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, -/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, -/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, -/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, +/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, +/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, +/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, +/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, /* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, /* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ /* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, -/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, -/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, +/* 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) }, -/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, +/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, -// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs +/* + * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices + * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that + * have been left on the device. If you don't have such a device but an Artec + * device that's supposed to work with this driver but is not detected by it, + * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config. + */ -#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY /* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, #endif + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); @@ -257,7 +264,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { } }, -#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY .num_device_descs = 2, #else .num_device_descs = 1, @@ -267,11 +274,12 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { { &dibusb_dib3000mb_table[20], NULL }, { &dibusb_dib3000mb_table[21], NULL }, }, -#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs +#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", { &dibusb_dib3000mb_table[30], NULL }, { NULL }, }, + { NULL }, #endif } }; @@ -323,6 +331,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = { { &dibusb_dib3000mb_table[27], NULL }, { NULL } }, + { NULL }, } }; @@ -369,11 +378,11 @@ static struct dvb_usb_properties artec_t1_usb2_properties = { { &dibusb_dib3000mb_table[28], NULL }, { &dibusb_dib3000mb_table[29], NULL }, }, + { NULL }, } }; static struct usb_driver dibusb_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_dibusb_mb", .probe = dibusb_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c index 6a0912eab39..55802fba3c2 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -82,7 +82,6 @@ static struct dvb_usb_properties dibusb_mc_properties = { }; static struct usb_driver dibusb_mc_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_dibusb_mc", .probe = dibusb_mc_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index f98e306a575..e6c55c9c941 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -32,7 +32,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d, sndbuf[1] = vv; sndbuf[2] = wo ? wlen : rlen; - if (!wo) { + if (wo) { memcpy(&sndbuf[3],wbuf,wlen); dvb_usb_generic_write(d,sndbuf,7); } else { @@ -233,7 +233,6 @@ static struct dvb_usb_properties digitv_properties = { }; static struct usb_driver digitv_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_digitv", .probe = digitv_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index 0a94ec22aeb..cd21ddbfd05 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -156,10 +156,9 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) struct dtt200u_fe_state* state = NULL; /* allocate memory for the internal state */ - state = (struct dtt200u_fe_state*) kmalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL); if (state == NULL) goto error; - memset(state,0,sizeof(struct dtt200u_fe_state)); deb_info("attaching frontend dtt200u\n"); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index b595476332c..130ea7f21f5 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = { .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, - { NULL }, + { 0 }, } }; @@ -160,7 +160,7 @@ static struct dvb_usb_properties wt220u_properties = { .pid_filter_count = 15, .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-wt220u-01.fw", + .firmware = "dvb-usb-wt220u-02.fw", .power_ctrl = dtt200u_power_ctrl, .streaming_ctrl = dtt200u_streaming_ctrl, @@ -192,13 +192,12 @@ static struct dvb_usb_properties wt220u_properties = { .cold_ids = { &dtt200u_usb_table[2], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL }, }, - { NULL }, + { 0 }, } }; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_dtt200u", .probe = dtt200u_usb_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h index 6f1f3042e21..005b0a7df35 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.h +++ b/drivers/media/dvb/dvb-usb/dtt200u.h @@ -13,6 +13,7 @@ #define _DVB_USB_DTT200U_H_ #define DVB_USB_LOG_PREFIX "dtt200u" + #include "dvb-usb.h" extern int dvb_usb_dtt200u_debug; @@ -25,15 +26,15 @@ extern int dvb_usb_dtt200u_debug; * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal) */ -#define GET_SPEED 0x00 -#define GET_TUNE_STATUS 0x81 -#define GET_RC_CODE 0x84 -#define GET_CONFIGURATION 0x88 -#define GET_AGC 0x89 -#define GET_SNR 0x8a -#define GET_VIT_ERR_CNT 0x8c -#define GET_RS_ERR_CNT 0x8d -#define GET_RS_UNCOR_BLK_CNT 0x8e +#define GET_SPEED 0x00 +#define GET_TUNE_STATUS 0x81 +#define GET_RC_CODE 0x84 +#define GET_CONFIGURATION 0x88 +#define GET_AGC 0x89 +#define GET_SNR 0x8a +#define GET_VIT_ERR_CNT 0x8c +#define GET_RS_ERR_CNT 0x8d +#define GET_RS_UNCOR_BLK_CNT 0x8e /* write * 01 - init @@ -44,12 +45,12 @@ extern int dvb_usb_dtt200u_debug; * 08 - transfer switch */ -#define SET_INIT 0x01 -#define SET_RF_FREQ 0x02 -#define SET_BANDWIDTH 0x03 -#define SET_PID_FILTER 0x04 -#define RESET_PID_FILTER 0x05 -#define SET_STREAMING 0x08 +#define SET_INIT 0x01 +#define SET_RF_FREQ 0x02 +#define SET_BANDWIDTH 0x03 +#define SET_PID_FILTER 0x04 +#define RESET_PID_FILTER 0x05 +#define SET_STREAMING 0x08 extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h index 7300489d3e2..a3460bf2d9f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -24,7 +24,7 @@ extern int dvb_usb_disable_rc_polling; #define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args) /* commonly used methods */ -extern int usb_cypress_load_firmware(struct usb_device *, const char *, int); +extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *); extern int dvb_usb_urb_submit(struct dvb_usb_device *); extern int dvb_usb_urb_kill(struct dvb_usb_device *); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c index 5244e39770a..8535895819f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c @@ -9,7 +9,6 @@ */ #include "dvb-usb-common.h" -#include <linux/firmware.h> #include <linux/usb.h> struct usb_cypress_controller { @@ -19,9 +18,10 @@ struct usb_cypress_controller { }; static struct usb_cypress_controller cypress[] = { - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, + { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, }; /* @@ -30,71 +30,117 @@ static struct usb_cypress_controller cypress[] = { static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) { return usb_control_msg(udev, usb_sndctrlpipe(udev,0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ); + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); } -int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type) +int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) { - const struct firmware *fw = NULL; - u16 addr; - u8 *b,*p; - int ret = 0,i; + struct hexline hx; + u8 reset; + int ret,pos=0; - if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems.", - filename); + /* stop the CPU */ + reset = 1; + if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) + err("could not stop the USB controller CPU."); + + while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) { + deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); + ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); + + if (ret != hx.len) { + err("error while transferring firmware " + "(transferred size: %d, block size: %d)", + ret,hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); return ret; } - info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name); - - p = kmalloc(fw->size,GFP_KERNEL); - if (p != NULL) { - u8 reset; - /* - * you cannot use the fw->data as buffer for - * usb_control_msg, a new buffer has to be - * created - */ - memcpy(p,fw->data,fw->size); - - /* stop the CPU */ - reset = 1; - if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) - err("could not stop the USB controller CPU."); - for(i = 0; p[i+3] == 0 && i < fw->size; ) { - b = (u8 *) &p[i]; - addr = cpu_to_le16( *((u16 *) &b[1]) ); - - deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]); - - ret = usb_cypress_writemem(udev,addr,&b[4],b[0]); - - if (ret != b[0]) { - err("error while transferring firmware " - "(transferred size: %d, block size: %d)", - ret,b[0]); - ret = -EINVAL; - break; - } - i += 5 + b[0]; - } - /* length in ret */ - if (ret > 0) - ret = 0; + if (ret == 0) { /* restart the CPU */ reset = 0; if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } + } else + ret = -EIO; - kfree(p); - } else { - ret = -ENOMEM; + return ret; +} +EXPORT_SYMBOL(usb_cypress_load_firmware); + +int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props) +{ + int ret; + const struct firmware *fw = NULL; + + if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + props->firmware,ret); + return ret; } - release_firmware(fw); + info("downloading firmware from file '%s'",props->firmware); + + switch (props->usb_ctrl) { + case CYPRESS_AN2135: + case CYPRESS_AN2235: + case CYPRESS_FX2: + ret = usb_cypress_load_firmware(udev, fw, props->usb_ctrl); + break; + case DEVICE_SPECIFIC: + if (props->download_firmware) + ret = props->download_firmware(udev,fw); + else { + err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + break; + } + + release_firmware(fw); return ret; } + +int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + if (*pos >= fw->size) + return 0; + + memset(hx,0,sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = le16_to_cpu( *((u16 *) &b[1]) ); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); +/* hx->len -= 2; + data_offs += 2; */ + } + memcpy(hx->data,&b[data_offs],hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usb_get_hexline); + diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index da970947dfc..9b254532af4 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -52,9 +52,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe) struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 }; int ret = 0; - /* if there is nothing to initialize */ - if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 && - d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00) + /* if pll_desc is not used */ + if (d->pll_desc == NULL) return 0; if (d->tuner_pass_ctrl) @@ -80,6 +79,9 @@ int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep { struct dvb_usb_device *d = fe->dvb->priv; + if (d->pll_desc == NULL) + return 0; + deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc); b[0] = d->pll_addr << 1; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 6be99e537e1..4a1b9e77e33 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -86,11 +86,17 @@ #define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_NEBULA_DIGITV 0x0201 -#define USB_PID_DVICO_BLUEBIRD_LGZ201 0xdb00 -#define USB_PID_DVICO_BLUEBIRD_TH7579 0xdb10 #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 -#define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01 -#define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11 +#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500 +#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd501 +#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD 0xdb00 +#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01 +#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10 +#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11 +#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD 0xdb50 +#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM 0xdb51 +#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD 0xdb54 +#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM 0xdb55 #define USB_PID_MEDION_MD95700 0x0932 #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index dd8e0b94edb..716f8bf528c 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -138,6 +138,9 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties int ret = -ENOMEM,cold=0; + if (du != NULL) + *du = NULL; + if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) { deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); return -ENODEV; @@ -145,38 +148,38 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties if (cold) { info("found a '%s' in cold state, will try to load a firmware",desc->name); - ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl); - } else { - info("found a '%s' in warm state.",desc->name); - d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL); - if (d == NULL) { - err("no memory for 'struct dvb_usb_device'"); + ret = dvb_usb_download_firmware(udev,props); + if (!props->no_reconnect) return ret; + } + + info("found a '%s' in warm state.",desc->name); + d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL); + if (d == NULL) { + err("no memory for 'struct dvb_usb_device'"); + return ret; + } + + d->udev = udev; + memcpy(&d->props,props,sizeof(struct dvb_usb_properties)); + d->desc = desc; + d->owner = owner; + + if (d->props.size_of_priv > 0) { + d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL); + if (d->priv == NULL) { + err("no memory for priv in 'struct dvb_usb_device'"); + kfree(d); + return -ENOMEM; } - memset(d,0,sizeof(struct dvb_usb_device)); - - d->udev = udev; - memcpy(&d->props,props,sizeof(struct dvb_usb_properties)); - d->desc = desc; - d->owner = owner; - - if (d->props.size_of_priv > 0) { - d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL); - if (d->priv == NULL) { - err("no memory for priv in 'struct dvb_usb_device'"); - kfree(d); - return -ENOMEM; - } - memset(d->priv,0,d->props.size_of_priv); - } + } - usb_set_intfdata(intf, d); + usb_set_intfdata(intf, d); - if (du != NULL) - *du = d; + if (du != NULL) + *du = d; - ret = dvb_usb_init(d); - } + ret = dvb_usb_init(d); if (ret == 0) info("%s successfully initialized and connected.",desc->name); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index 36b7048c02d..ee821974dc6 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -175,15 +175,13 @@ static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, un deb_mem("all in all I will use %lu bytes for streaming\n",num*size); - if ((d->buf_list = kmalloc(num*sizeof(u8 *), GFP_ATOMIC)) == NULL) + if ((d->buf_list = kcalloc(num, sizeof(u8 *), GFP_ATOMIC)) == NULL) return -ENOMEM; - if ((d->dma_addr = kmalloc(num*sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) { + if ((d->dma_addr = kcalloc(num, sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) { kfree(d->buf_list); return -ENOMEM; } - memset(d->buf_list,0,num*sizeof(u8 *)); - memset(d->dma_addr,0,num*sizeof(dma_addr_t)); d->state |= DVB_USB_STATE_URB_BUF; @@ -285,10 +283,9 @@ int dvb_usb_urb_init(struct dvb_usb_device *d) usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.urb.endpoint)); /* allocate the array for the data transfer URBs */ - d->urb_list = kmalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL); + d->urb_list = kzalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL); if (d->urb_list == NULL) return -ENOMEM; - memset(d->urb_list,0,d->props.urb.count * sizeof(struct urb *)); d->state |= DVB_USB_STATE_URB_LIST; switch (d->props.urb.type) { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index b4a1a98006c..dd568396e59 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -10,8 +10,8 @@ #include <linux/config.h> #include <linux/input.h> -#include <linux/module.h> #include <linux/usb.h> +#include <linux/firmware.h> #include "dvb_frontend.h" #include "dvb_demux.h" @@ -94,7 +94,11 @@ struct dvb_usb_device; * @usb_ctrl: which USB device-side controller is in use. Needed for firmware * download. * @firmware: name of the firmware file. - * + * @download_firmware: called to download the firmware when the usb_ctrl is + * DEVICE_SPECIFIC. + * @no_reconnect: device doesn't do a reconnect after downloading the firmware, + so do the warm initialization right after it + * @size_of_priv: how many bytes shall be allocated for the private field * of struct dvb_usb_device. * @@ -142,11 +146,14 @@ struct dvb_usb_properties { int caps; int pid_filter_count; -#define CYPRESS_AN2135 0 -#define CYPRESS_AN2235 1 -#define CYPRESS_FX2 2 +#define DEVICE_SPECIFIC 0 +#define CYPRESS_AN2135 1 +#define CYPRESS_AN2235 2 +#define CYPRESS_FX2 3 int usb_ctrl; - const char *firmware; + const char firmware[FIRMWARE_NAME_MAX]; + int (*download_firmware) (struct usb_device *, const struct firmware *); + int no_reconnect; int size_of_priv; @@ -326,5 +333,15 @@ extern int dvb_usb_pll_init_i2c(struct dvb_frontend *); extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]); extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *); +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int dvb_usb_get_hexline(const struct firmware *, struct hexline *, int *); +extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); #endif diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index 1841a66427b..412039d8dba 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -129,10 +129,6 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) dibusb_read_eeprom_byte(d,i, &b); mac[5 - (i - 136)] = b; - -/* deb_ee("%02x ",b); - if ((i+1) % 16 == 0) - deb_ee("\n");*/ } return 0; @@ -153,7 +149,7 @@ static struct usb_device_id nova_t_table [] = { /* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, nova_t_table); +MODULE_DEVICE_TABLE(usb, nova_t_table); static struct dvb_usb_properties nova_t_properties = { .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, @@ -198,11 +194,11 @@ static struct dvb_usb_properties nova_t_properties = { { &nova_t_table[0], NULL }, { &nova_t_table[1], NULL }, }, + { NULL }, } }; static struct usb_driver nova_t_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_nova_t_usb2", .probe = nova_t_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index 6fd67657c26..14f1911c79b 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -128,7 +128,6 @@ static struct dvb_usb_properties umt_properties = { }; static struct usb_driver umt_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_umt_010", .probe = umt_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index 104b5d016c7..b6d95e1c9c5 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -190,7 +190,7 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe, } static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, - struct dvb_diseqc_master_cmd *m) + struct dvb_diseqc_master_cmd *m) { struct vp702x_fe_state *st = fe->demodulator_priv; u8 cmd[8],ibuf[10]; @@ -281,10 +281,9 @@ 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); + struct vp702x_fe_state *s = kzalloc(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; diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index de13c04e8e6..afa00fdb5ec 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -256,7 +256,6 @@ static struct dvb_usb_properties vp702x_properties = { /* 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, diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h index 4a3e8c7eca2..a808d48e7bf 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.h +++ b/drivers/media/dvb/dvb-usb/vp702x.h @@ -13,47 +13,47 @@ extern int dvb_usb_vp702x_debug; /* commands are read and written with USB control messages */ /* consecutive read/write operation */ -#define REQUEST_OUT 0xB2 -#define REQUEST_IN 0xB3 +#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 +#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 +#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 +#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 */ + * N/A 0 0 b[1] == b[2] == 0 -> success, failure otherwise */ -#define SET_LNB_POWER 0x09 +#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 */ + * N/A 0 0 b[1] == b[2] == 0 -> success failure otherwise */ -#define GET_MAC_ADDRESS 0x0A +#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 +#define SET_PID_FILTER 0x11 /* additional in buffer: * 0 1 ... 14 15 16 * PID0_MSB PID0_LSB ... PID7_MSB PID7_LSB PID_active (bits) */ @@ -64,39 +64,38 @@ extern int dvb_usb_vp702x_debug; * freq0 freq1 divstep srate0 srate1 srate2 flag chksum */ - /* one direction requests */ -#define READ_REMOTE_REQ 0xB4 +#define READ_REMOTE_REQ 0xB4 /* IN i: 0; v: 0; b[0] == request, b[1] == key */ -#define READ_PID_NUMBER_REQ 0xB5 +#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 +#define WRITE_EEPROM_REQ 0xB6 /* OUT i: offset; v: value to write; no extra buffer */ -#define READ_EEPROM_REQ 0xB7 +#define READ_EEPROM_REQ 0xB7 /* IN i: bufferlen; v: offset; buffer with bufferlen bytes */ -#define READ_STATUS 0xB8 +#define READ_STATUS 0xB8 /* IN i: 0; v: 0; bufferlen 10 */ -#define READ_TUNER_REG_REQ 0xB9 +#define READ_TUNER_REG_REQ 0xB9 /* IN i: 0; v: register; b[0] = value */ -#define READ_FX2_REG_REQ 0xBA +#define READ_FX2_REG_REQ 0xBA /* IN i: offset; v: 0; b[0] = value */ -#define WRITE_FX2_REG_REQ 0xBB +#define WRITE_FX2_REG_REQ 0xBB /* OUT i: offset; v: value to write; 1 byte extra buffer */ -#define SET_TUNER_POWER_REQ 0xBC +#define SET_TUNER_POWER_REQ 0xBC /* IN i: 0 = power off, 1 = power on */ -#define WRITE_TUNER_REG_REQ 0xBD +#define WRITE_TUNER_REG_REQ 0xBD /* IN i: register, v: value to write, no extra buffer */ -#define RESET_TUNER 0xBE +#define RESET_TUNER 0xBE /* IN i: 0, v: 0, no extra buffer */ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c index 83f1de1e7e5..5242cca5db4 100644 --- a/drivers/media/dvb/dvb-usb/vp7045-fe.c +++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c @@ -145,10 +145,9 @@ static struct dvb_frontend_ops vp7045_fe_ops; struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d) { - struct vp7045_fe_state *s = kmalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL); + struct vp7045_fe_state *s = kzalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL); if (s == NULL) goto error; - memset(s,0,sizeof(struct vp7045_fe_state)); s->d = d; s->fe.ops = &vp7045_fe_ops; diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 75765e3a569..028204956bb 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -247,13 +247,12 @@ static struct dvb_usb_properties vp7045_properties = { .cold_ids = { &vp7045_usb_table[2], NULL }, .warm_ids = { &vp7045_usb_table[3], NULL }, }, - { NULL }, + { 0 }, } }; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver vp7045_usb_driver = { - .owner = THIS_MODULE, .name = "dvb_usb_vp7045", .probe = vp7045_usb_probe, .disconnect = dvb_usb_device_exit, diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 8e269e1c1f9..db3a8b40031 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -16,6 +16,12 @@ config DVB_CX24110 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_CX24123 + tristate "Conexant CX24123 based" + depends on DVB_CORE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + config DVB_TDA8083 tristate "Philips TDA8083 based" depends on DVB_CORE @@ -50,18 +56,19 @@ comment "DVB-T (terrestrial) frontends" depends on DVB_CORE config DVB_SP8870 - tristate "Spase sp8870 based" + tristate "Spase sp8870 based" depends on DVB_CORE select FW_LOADER help - A DVB-T tuner module. Say Y when you want to support this frontend. + A DVB-T tuner module. Say Y when you want to support this frontend. This driver needs external firmware. Please use the command "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). config DVB_SP887X - tristate "Spase sp887x based" + tristate "Spase sp887x based" depends on DVB_CORE select FW_LOADER help @@ -69,7 +76,8 @@ config DVB_SP887X This driver needs external firmware. Please use the command "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). config DVB_CX22700 tristate "Conexant CX22700 based" @@ -78,10 +86,10 @@ config DVB_CX22700 A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_CX22702 - tristate "Conexant cx22702 demodulator (OFDM)" - depends on DVB_CORE - help - A DVB-T tuner module. Say Y when you want to support this frontend. + tristate "Conexant cx22702 demodulator (OFDM)" + depends on DVB_CORE + help + A DVB-T tuner module. Say Y when you want to support this frontend. config DVB_L64781 tristate "LSI L64781" @@ -98,8 +106,9 @@ config DVB_TDA1004X This driver needs external firmware. Please use the commands "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045", - "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to - download/extract them, and then copy them to /usr/lib/hotplug/firmware. + "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). config DVB_NXT6000 tristate "NxtWave Communications NXT6000 based" @@ -140,13 +149,13 @@ config DVB_VES1820 tristate "VLSI VES1820 based" depends on DVB_CORE help - A DVB-C tuner module. Say Y when you want to support this frontend. + A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_TDA10021 tristate "Philips TDA10021 based" depends on DVB_CORE help - A DVB-C tuner module. Say Y when you want to support this frontend. + A DVB-C tuner module. Say Y when you want to support this frontend. config DVB_STV0297 tristate "ST STV0297 based" @@ -164,6 +173,11 @@ config DVB_NXT2002 help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. + This driver needs external firmware. Please use the command + "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_NXT200X tristate "Nextwave NXT2002/NXT2004 based" depends on DVB_CORE @@ -172,6 +186,12 @@ config DVB_NXT200X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. + This driver needs external firmware. Please use the commands + "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" and + "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_OR51211 tristate "or51211 based (pcHDTV HD2000 card)" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index a98760fe08a..615ec830e1c 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o +obj-$(CONFIG_DVB_CX24123) += cx24123.o diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index 8ceb9a33c7a..caaee893ca7 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -255,7 +255,7 @@ static int bcm3510_bert_reset(struct bcm3510_state *st) bcm3510_register_value b; int ret; - if ((ret < bcm3510_readB(st,0xfa,&b)) < 0) + if ((ret = bcm3510_readB(st,0xfa,&b)) < 0) return ret; b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b); @@ -623,13 +623,13 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe) err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); return ret; } - deb_info("got firmware: %d\n",fw->size); + deb_info("got firmware: %zd\n",fw->size); b = fw->data; for (i = 0; i < fw->size;) { addr = le16_to_cpu( *( (u16 *)&b[i] ) ); len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); - deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size); + deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size); if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { err("firmware download failed: %d\n",ret); return ret; @@ -782,10 +782,9 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, bcm3510_register_value v; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct bcm3510_state), GFP_KERNEL); + state = kzalloc(sizeof(struct bcm3510_state), GFP_KERNEL); if (state == NULL) goto error; - memset(state,0,sizeof(struct bcm3510_state)); /* setup the state */ diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 5de0e6d350b..0fc899f81c5 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -195,6 +195,16 @@ static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_paramet return 0; } +static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct cx22702_state* state = fe->demodulator_priv; + dprintk ("%s(%d)\n", __FUNCTION__, enable); + if (enable) + return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe); + else + return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1); +} + /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { @@ -202,7 +212,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet struct cx22702_state* state = fe->demodulator_priv; /* set PLL */ - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + cx22702_i2c_gate_ctrl(fe, 1); if (state->config->pll_set) { state->config->pll_set(fe, p); } else if (state->config->pll_desc) { @@ -216,7 +226,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet } else { BUG(); } - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); + cx22702_i2c_gate_ctrl(fe, 0); /* set inversion */ cx22702_set_inversion (state, p->inversion); @@ -349,11 +359,10 @@ static int cx22702_init (struct dvb_frontend* fe) cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02); /* init PLL */ - if (state->config->pll_init) { - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe); + if (state->config->pll_init) state->config->pll_init(fe); - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); - } + + cx22702_i2c_gate_ctrl(fe, 0); return 0; } @@ -531,6 +540,7 @@ static struct dvb_frontend_ops cx22702_ops = { .read_signal_strength = cx22702_read_signal_strength, .read_snr = cx22702_read_snr, .read_ucblocks = cx22702_read_ucblocks, + .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, }; module_param(debug, int, 0644); diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 0c4db80ec33..d15d32c51dc 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -27,7 +27,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> -#include <linux/jiffies.h> #include "dvb_frontend.h" #include "cx24110.h" @@ -56,7 +55,7 @@ static int debug; static struct {u8 reg; u8 data;} cx24110_regdata[]= /* Comments beginning with @ denote this value should - be the default */ + be the default */ {{0x09,0x01}, /* SoftResetAll */ {0x09,0x00}, /* release reset */ {0x01,0xe8}, /* MSB of code rate 27.5MS/s */ @@ -67,26 +66,26 @@ static struct {u8 reg; u8 data;} cx24110_regdata[]= {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */ {0x0a,0x00}, /* @ partial chip disables, do not set */ {0x0b,0x01}, /* set output clock in gapped mode, start signal low - active for first byte */ + active for first byte */ {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */ {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */ {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1 - to avoid starting the BER counter. Reset the - CRC test bit. Finite counting selected */ + to avoid starting the BER counter. Reset the + CRC test bit. Finite counting selected */ {0x15,0xff}, /* @ size of the limited time window for RS BER - estimation. It is <value>*256 RS blocks, this - gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */ + estimation. It is <value>*256 RS blocks, this + gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */ {0x16,0x00}, /* @ enable all RS output ports */ {0x17,0x04}, /* @ time window allowed for the RS to sync */ {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned - for automatically */ + for automatically */ /* leave the current code rate and normalization - registers as they are after reset... */ + registers as they are after reset... */ {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting - only once */ + only once */ {0x23,0x18}, /* @ size of the limited time window for Viterbi BER - estimation. It is <value>*65536 channel bits, i.e. - approx. 38ms at 27.5MS/s, rate 3/4 */ + estimation. It is <value>*65536 channel bits, i.e. + approx. 38ms at 27.5MS/s, rate 3/4 */ {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */ /* leave front-end AGC parameters at default values */ /* leave decimation AGC parameters at default values */ diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c new file mode 100644 index 00000000000..d661c6f9cbe --- /dev/null +++ b/drivers/media/dvb/frontends/cx24123.c @@ -0,0 +1,889 @@ +/* + Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver + + Copyright (C) 2005 Steven Toth <stoth@hauppauge.com> + + Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc> + + 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/slab.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> + +#include "dvb_frontend.h" +#include "cx24123.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk (KERN_DEBUG "cx24123: " args); \ + } while (0) + +struct cx24123_state +{ + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + const struct cx24123_config* config; + + struct dvb_frontend frontend; + + u32 lastber; + u16 snr; + u8 lnbreg; + + /* Some PLL specifics for tuning */ + u32 VCAarg; + u32 VGAarg; + u32 bandselectarg; + u32 pllarg; + + /* The Demod/Tuner can't easily provide these, we cache them */ + u32 currentfreq; + u32 currentsymbolrate; +}; + +/* Various tuner defaults need to be established for a given symbol rate Sps */ +static struct +{ + u32 symbolrate_low; + u32 symbolrate_high; + u32 VCAslope; + u32 VCAoffset; + u32 VGA1offset; + u32 VGA2offset; + u32 VCAprogdata; + u32 VGAprogdata; +} cx24123_AGC_vals[] = +{ + { + .symbolrate_low = 1000000, + .symbolrate_high = 4999999, + .VCAslope = 0x07, + .VCAoffset = 0x0f, + .VGA1offset = 0x1f8, + .VGA2offset = 0x1f8, + .VGAprogdata = (2 << 18) | (0x1f8 << 9) | 0x1f8, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07, + }, + { + .symbolrate_low = 5000000, + .symbolrate_high = 14999999, + .VCAslope = 0x1f, + .VCAoffset = 0x1f, + .VGA1offset = 0x1e0, + .VGA2offset = 0x180, + .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f, + }, + { + .symbolrate_low = 15000000, + .symbolrate_high = 45000000, + .VCAslope = 0x3f, + .VCAoffset = 0x3f, + .VGA1offset = 0x180, + .VGA2offset = 0x100, + .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180, + .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f, + }, +}; + +/* + * Various tuner defaults need to be established for a given frequency kHz. + * fixme: The bounds on the bands do not match the doc in real life. + * fixme: Some of them have been moved, other might need adjustment. + */ +static struct +{ + u32 freq_low; + u32 freq_high; + u32 bandselect; + u32 VCOdivider; + u32 VCOnumber; + u32 progdata; +} cx24123_bandselect_vals[] = +{ + { + .freq_low = 950000, + .freq_high = 1018999, + .bandselect = 0x40, + .VCOdivider = 4, + .VCOnumber = 7, + .progdata = (0 << 18) | (0 << 9) | 0x40, + }, + { + .freq_low = 1019000, + .freq_high = 1074999, + .bandselect = 0x80, + .VCOdivider = 4, + .VCOnumber = 8, + .progdata = (0 << 18) | (0 << 9) | 0x80, + }, + { + .freq_low = 1075000, + .freq_high = 1227999, + .bandselect = 0x01, + .VCOdivider = 2, + .VCOnumber = 1, + .progdata = (0 << 18) | (1 << 9) | 0x01, + }, + { + .freq_low = 1228000, + .freq_high = 1349999, + .bandselect = 0x02, + .VCOdivider = 2, + .VCOnumber = 2, + .progdata = (0 << 18) | (1 << 9) | 0x02, + }, + { + .freq_low = 1350000, + .freq_high = 1481999, + .bandselect = 0x04, + .VCOdivider = 2, + .VCOnumber = 3, + .progdata = (0 << 18) | (1 << 9) | 0x04, + }, + { + .freq_low = 1482000, + .freq_high = 1595999, + .bandselect = 0x08, + .VCOdivider = 2, + .VCOnumber = 4, + .progdata = (0 << 18) | (1 << 9) | 0x08, + }, + { + .freq_low = 1596000, + .freq_high = 1717999, + .bandselect = 0x10, + .VCOdivider = 2, + .VCOnumber = 5, + .progdata = (0 << 18) | (1 << 9) | 0x10, + }, + { + .freq_low = 1718000, + .freq_high = 1855999, + .bandselect = 0x20, + .VCOdivider = 2, + .VCOnumber = 6, + .progdata = (0 << 18) | (1 << 9) | 0x20, + }, + { + .freq_low = 1856000, + .freq_high = 2035999, + .bandselect = 0x40, + .VCOdivider = 2, + .VCOnumber = 7, + .progdata = (0 << 18) | (1 << 9) | 0x40, + }, + { + .freq_low = 2036000, + .freq_high = 2149999, + .bandselect = 0x80, + .VCOdivider = 2, + .VCOnumber = 8, + .progdata = (0 << 18) | (1 << 9) | 0x80, + }, +}; + +static struct { + u8 reg; + u8 data; +} cx24123_regdata[] = +{ + {0x00, 0x03}, /* Reset system */ + {0x00, 0x00}, /* Clear reset */ + {0x01, 0x3b}, /* Apply sensible defaults, from an i2c sniffer */ + {0x03, 0x07}, + {0x04, 0x10}, + {0x05, 0x04}, + {0x06, 0x31}, + {0x0d, 0x02}, + {0x0e, 0x03}, + {0x0f, 0xfe}, + {0x10, 0x01}, + {0x14, 0x01}, + {0x15, 0x98}, + {0x16, 0x00}, + {0x17, 0x01}, + {0x1b, 0x05}, + {0x1c, 0x80}, + {0x1d, 0x00}, + {0x1e, 0x00}, + {0x20, 0x41}, + {0x21, 0x15}, + {0x27, 0x14}, + {0x28, 0x46}, + {0x29, 0x00}, + {0x2a, 0xb0}, + {0x2b, 0x73}, + {0x2c, 0x00}, + {0x2d, 0x00}, + {0x2e, 0x00}, + {0x2f, 0x00}, + {0x30, 0x00}, + {0x31, 0x00}, + {0x32, 0x8c}, + {0x33, 0x00}, + {0x34, 0x00}, + {0x35, 0x03}, + {0x36, 0x02}, + {0x37, 0x3a}, + {0x3a, 0x00}, /* Enable AGC accumulator */ + {0x44, 0x00}, + {0x45, 0x00}, + {0x46, 0x05}, + {0x56, 0x41}, + {0x57, 0xff}, + {0x67, 0x83}, +}; + +static int cx24123_writereg(struct cx24123_state* state, int reg, int data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk("%s: writereg error(err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data) +{ + u8 buf[] = { reg, data }; + /* fixme: put the intersil addr int the config */ + struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk("%s: writelnbreg error (err == %i, reg == 0x%02x," + " data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + /* cache the write, no way to read back */ + state->lnbreg = data; + + return 0; +} + +static int cx24123_readreg(struct cx24123_state* state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) { + printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret); + return ret; + } + + return b1[0]; +} + +static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg) +{ + return state->lnbreg; +} + +static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion) +{ + switch (inversion) { + case INVERSION_OFF: + cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f); + cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); + break; + case INVERSION_ON: + cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80); + cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); + break; + case INVERSION_AUTO: + cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_inversion_t *inversion) +{ + u8 val; + + val = cx24123_readreg(state, 0x1b) >> 7; + + if (val == 0) + *inversion = INVERSION_OFF; + else + *inversion = INVERSION_ON; + + return 0; +} + +static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) +{ + if ( (fec < FEC_NONE) || (fec > FEC_AUTO) ) + fec = FEC_AUTO; + + /* Hardware has 5/11 and 3/5 but are never unused */ + switch (fec) { + case FEC_NONE: + return cx24123_writereg(state, 0x0f, 0x01); + case FEC_1_2: + return cx24123_writereg(state, 0x0f, 0x02); + case FEC_2_3: + return cx24123_writereg(state, 0x0f, 0x04); + case FEC_3_4: + return cx24123_writereg(state, 0x0f, 0x08); + case FEC_5_6: + return cx24123_writereg(state, 0x0f, 0x20); + case FEC_7_8: + return cx24123_writereg(state, 0x0f, 0x80); + case FEC_AUTO: + return cx24123_writereg(state, 0x0f, 0xae); + default: + return -EOPNOTSUPP; + } +} + +static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) +{ + int ret; + u8 val; + + ret = cx24123_readreg (state, 0x1b); + if (ret < 0) + return ret; + val = ret & 0x07; + switch (val) { + case 1: + *fec = FEC_1_2; + break; + case 3: + *fec = FEC_2_3; + break; + case 4: + *fec = FEC_3_4; + break; + case 5: + *fec = FEC_4_5; + break; + case 6: + *fec = FEC_5_6; + break; + case 7: + *fec = FEC_7_8; + break; + case 2: /* *fec = FEC_3_5; break; */ + case 0: /* *fec = FEC_5_11; break; */ + *fec = FEC_AUTO; + break; + default: + *fec = FEC_NONE; // can't happen + } + + return 0; +} + +/* fixme: Symbol rates < 3MSps may not work because of precision loss */ +static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) +{ + u32 val; + + val = (srate / 1185) * 100; + + /* Compensate for scaling up, by removing 17 symbols per 1Msps */ + val = val - (17 * (srate / 1000000)); + + cx24123_writereg(state, 0x08, (val >> 16) & 0xff ); + cx24123_writereg(state, 0x09, (val >> 8) & 0xff ); + cx24123_writereg(state, 0x0a, (val ) & 0xff ); + + return 0; +} + +/* + * Based on the required frequency and symbolrate, the tuner AGC has to be configured + * and the correct band selected. Calculate those values + */ +static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + u32 ndiv = 0, adiv = 0, vco_div = 0; + int i = 0; + + /* Defaults for low freq, low rate */ + state->VCAarg = cx24123_AGC_vals[0].VCAprogdata; + state->VGAarg = cx24123_AGC_vals[0].VGAprogdata; + state->bandselectarg = cx24123_bandselect_vals[0].progdata; + vco_div = cx24123_bandselect_vals[0].VCOdivider; + + /* For the given symbolerate, determine the VCA and VGA programming bits */ + for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++) + { + if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) && + (cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) { + state->VCAarg = cx24123_AGC_vals[i].VCAprogdata; + state->VGAarg = cx24123_AGC_vals[i].VGAprogdata; + } + } + + /* For the given frequency, determine the bandselect programming bits */ + for (i = 0; i < sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]); i++) + { + if ((cx24123_bandselect_vals[i].freq_low <= p->frequency) && + (cx24123_bandselect_vals[i].freq_high >= p->frequency) ) { + state->bandselectarg = cx24123_bandselect_vals[i].progdata; + vco_div = cx24123_bandselect_vals[i].VCOdivider; + } + } + + /* Determine the N/A dividers for the requested lband freq (in kHz). */ + /* Note: 10111 (kHz) is the Crystal Freq and divider of 10. */ + ndiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) / 32) & 0x1ff; + adiv = ( ((p->frequency * vco_div) / (10111 / 10) / 2) % 32) & 0x1f; + + if (adiv == 0) + adiv++; + + /* determine the correct pll frequency values. */ + /* Command 11, refdiv 11, cpump polarity 1, cpump current 3mA 10. */ + state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (2 << 14); + state->pllarg |= (ndiv << 5) | adiv; + + return 0; +} + +/* + * Tuner data is 21 bits long, must be left-aligned in data. + * Tuner cx24109 is written through a dedicated 3wire interface on the demod chip. + */ +static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_parameters *p, u32 data) +{ + struct cx24123_state *state = fe->demodulator_priv; + unsigned long timeout; + + /* align the 21 bytes into to bit23 boundary */ + data = data << 3; + + /* Reset the demod pll word length to 0x15 bits */ + cx24123_writereg(state, 0x21, 0x15); + + /* write the msb 8 bits, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); + cx24123_writereg(state, 0x22, (data >> 16) & 0xff); + while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { + if (time_after(jiffies, timeout)) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__); + return -EREMOTEIO; + } + msleep(10); + } + + /* send another 8 bytes, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); + cx24123_writereg(state, 0x22, (data>>8) & 0xff ); + while ((cx24123_readreg(state, 0x20) & 0x40) == 0) { + if (time_after(jiffies, timeout)) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__); + return -EREMOTEIO; + } + msleep(10); + } + + /* send the lower 5 bits of this byte, padded with 3 LBB, wait for the send to be completed */ + timeout = jiffies + msecs_to_jiffies(40); + cx24123_writereg(state, 0x22, (data) & 0xff ); + while ((cx24123_readreg(state, 0x20) & 0x80)) { + if (time_after(jiffies, timeout)) { + printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__); + return -EREMOTEIO; + } + msleep(10); + } + + /* Trigger the demod to configure the tuner */ + cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) | 2); + cx24123_writereg(state, 0x20, cx24123_readreg(state, 0x20) & 0xfd); + + return 0; +} + +static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + if (cx24123_pll_calculate(fe, p) != 0) { + printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__); + return -EINVAL; + } + + /* Write the new VCO/VGA */ + cx24123_pll_writereg(fe, p, state->VCAarg); + cx24123_pll_writereg(fe, p, state->VGAarg); + + /* Write the new bandselect and pll args */ + cx24123_pll_writereg(fe, p, state->bandselectarg); + cx24123_pll_writereg(fe, p, state->pllarg); + + return 0; +} + +static int cx24123_initfe(struct dvb_frontend* fe) +{ + struct cx24123_state *state = fe->demodulator_priv; + int i; + + /* Configure the demod to a good set of defaults */ + for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++) + cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data); + + if (state->config->pll_init) + state->config->pll_init(fe); + + /* Configure the LNB for 14V */ + if (state->config->use_isl6421) + cx24123_writelnbreg(state, 0x0, 0x2a); + + return 0; +} + +static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + switch (state->config->use_isl6421) { + + case 1: + + val = cx24123_readlnbreg(state, 0x0); + + switch (voltage) { + case SEC_VOLTAGE_13: + return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */ + case SEC_VOLTAGE_18: + return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */ + case SEC_VOLTAGE_OFF: + return cx24123_writelnbreg(state, 0x0, val & 0x30); + default: + return -EINVAL; + }; + + case 0: + + val = cx24123_readreg(state, 0x29); + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk("%s: setting voltage 13V\n", __FUNCTION__); + if (state->config->enable_lnb_voltage) + state->config->enable_lnb_voltage(fe, 1); + return cx24123_writereg(state, 0x29, val | 0x80); + case SEC_VOLTAGE_18: + dprintk("%s: setting voltage 18V\n", __FUNCTION__); + if (state->config->enable_lnb_voltage) + state->config->enable_lnb_voltage(fe, 1); + return cx24123_writereg(state, 0x29, val & 0x7f); + case SEC_VOLTAGE_OFF: + dprintk("%s: setting voltage off\n", __FUNCTION__); + if (state->config->enable_lnb_voltage) + state->config->enable_lnb_voltage(fe, 0); + return 0; + default: + return -EINVAL; + }; + } + + return 0; +} + +static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *cmd) +{ + /* fixme: Implement diseqc */ + printk("%s: No support yet\n",__FUNCTION__); + + return -ENOTSUPP; +} + +static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct cx24123_state *state = fe->demodulator_priv; + + int sync = cx24123_readreg(state, 0x14); + int lock = cx24123_readreg(state, 0x20); + + *status = 0; + if (lock & 0x01) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + if (sync & 0x04) + *status |= FE_HAS_VITERBI; + if (sync & 0x08) + *status |= FE_HAS_CARRIER; + if (sync & 0x80) + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + + return 0; +} + +/* + * Configured to return the measurement of errors in blocks, because no UCBLOCKS value + * is available, so this value doubles up to satisfy both measurements + */ +static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct cx24123_state *state = fe->demodulator_priv; + + state->lastber = + ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) | + (cx24123_readreg(state, 0x1d) << 8 | + cx24123_readreg(state, 0x1e)); + + /* Do the signal quality processing here, it's derived from the BER. */ + /* Scale the BER from a 24bit to a SNR 16 bit where higher = better */ + if (state->lastber < 5000) + state->snr = 655*100; + else if ( (state->lastber >= 5000) && (state->lastber < 55000) ) + state->snr = 655*90; + else if ( (state->lastber >= 55000) && (state->lastber < 150000) ) + state->snr = 655*80; + else if ( (state->lastber >= 150000) && (state->lastber < 250000) ) + state->snr = 655*70; + else if ( (state->lastber >= 250000) && (state->lastber < 450000) ) + state->snr = 655*65; + else + state->snr = 0; + + *ber = state->lastber; + + return 0; +} + +static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct cx24123_state *state = fe->demodulator_priv; + *signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */ + + return 0; +} + +static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct cx24123_state *state = fe->demodulator_priv; + *snr = state->snr; + + return 0; +} + +static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct cx24123_state *state = fe->demodulator_priv; + *ucblocks = state->lastber; + + return 0; +} + +static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + state->currentfreq=p->frequency; + state->currentsymbolrate = p->u.qpsk.symbol_rate; + + cx24123_set_inversion(state, p->inversion); + cx24123_set_fec(state, p->u.qpsk.fec_inner); + cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate); + cx24123_pll_tune(fe, p); + + /* Enable automatic aquisition and reset cycle */ + cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07)); + cx24123_writereg(state, 0x00, 0x10); + cx24123_writereg(state, 0x00, 0); + + return 0; +} + +static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24123_state *state = fe->demodulator_priv; + + if (cx24123_get_inversion(state, &p->inversion) != 0) { + printk("%s: Failed to get inversion status\n",__FUNCTION__); + return -EREMOTEIO; + } + if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) { + printk("%s: Failed to get fec status\n",__FUNCTION__); + return -EREMOTEIO; + } + p->frequency = state->currentfreq; + p->u.qpsk.symbol_rate = state->currentsymbolrate; + + return 0; +} + +static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct cx24123_state *state = fe->demodulator_priv; + u8 val; + + switch (state->config->use_isl6421) { + case 1: + + val = cx24123_readlnbreg(state, 0x0); + + switch (tone) { + case SEC_TONE_ON: + return cx24123_writelnbreg(state, 0x0, val | 0x10); + case SEC_TONE_OFF: + return cx24123_writelnbreg(state, 0x0, val & 0x2f); + default: + printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); + return -EINVAL; + } + + case 0: + + val = cx24123_readreg(state, 0x29); + + switch (tone) { + case SEC_TONE_ON: + dprintk("%s: setting tone on\n", __FUNCTION__); + return cx24123_writereg(state, 0x29, val | 0x10); + case SEC_TONE_OFF: + dprintk("%s: setting tone off\n",__FUNCTION__); + return cx24123_writereg(state, 0x29, val & 0xef); + default: + printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); + return -EINVAL; + } + } + + return 0; +} + +static void cx24123_release(struct dvb_frontend* fe) +{ + struct cx24123_state* state = fe->demodulator_priv; + dprintk("%s\n",__FUNCTION__); + kfree(state); +} + +static struct dvb_frontend_ops cx24123_ops; + +struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, + struct i2c_adapter* i2c) +{ + struct cx24123_state* state = NULL; + int ret; + + dprintk("%s\n",__FUNCTION__); + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL); + if (state == NULL) { + printk("Unable to kmalloc\n"); + goto error; + } + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops)); + state->lastber = 0; + state->snr = 0; + state->lnbreg = 0; + state->VCAarg = 0; + state->VGAarg = 0; + state->bandselectarg = 0; + state->pllarg = 0; + state->currentfreq = 0; + state->currentsymbolrate = 0; + + /* check if the demod is there */ + ret = cx24123_readreg(state, 0x00); + if ((ret != 0xd1) && (ret != 0xe1)) { + printk("Version != d1 or e1\n"); + goto error; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + + return NULL; +} + +static struct dvb_frontend_ops cx24123_ops = { + + .info = { + .name = "Conexant CX24123/CX24109", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + 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_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = cx24123_release, + + .init = cx24123_initfe, + .set_frontend = cx24123_set_frontend, + .get_frontend = cx24123_get_frontend, + .read_status = cx24123_read_status, + .read_ber = cx24123_read_ber, + .read_signal_strength = cx24123_read_signal_strength, + .read_snr = cx24123_read_snr, + .read_ucblocks = cx24123_read_ucblocks, + .diseqc_send_master_cmd = cx24123_send_diseqc_msg, + .set_tone = cx24123_set_tone, + .set_voltage = cx24123_set_voltage, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cx24123_attach); diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h new file mode 100644 index 00000000000..0c922b5e926 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24123.h @@ -0,0 +1,51 @@ +/* + Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver + + Copyright (C) 2005 Steven Toth <stoth@hauppauge.com> + + 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 CX24123_H +#define CX24123_H + +#include <linux/dvb/frontend.h> + +struct cx24123_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* + cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip + for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits + from register 0x29 of the CX24123 demodulator + */ + int use_isl6421; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); + + void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on); +}; + +extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, + struct i2c_adapter* i2c); + +#endif /* CX24123_H */ diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index 6b055360861..ae589adb1c0 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -700,10 +700,9 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, struct dib3000_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); + state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL); if (state == NULL) goto error; - memset(state,0,sizeof(struct dib3000_state)); /* setup the state */ state->i2c = i2c; diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index c024fad1733..3b303dbb615 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -832,10 +832,9 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, u16 devid; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); + state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL); if (state == NULL) goto error; - memset(state,0,sizeof(struct dib3000_state)); /* setup the state */ state->i2c = i2c; diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index f857b869616..1b9934ea5b0 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -107,18 +107,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { }; EXPORT_SYMBOL(dvb_pll_microtune_4042); -struct dvb_pll_desc dvb_pll_thomson_dtt7611 = { - .name = "Thomson dtt7611", - .min = 44000000, - .max = 958000000, +struct dvb_pll_desc dvb_pll_thomson_dtt761x = { + /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ + .name = "Thomson dtt761x", + .min = 57000000, + .max = 863000000, .count = 3, .entries = { - { 157250000, 44000000, 62500, 0x8e, 0x39 }, - { 454000000, 44000000, 62500, 0x8e, 0x3a }, + { 147000000, 44000000, 62500, 0x8e, 0x39 }, + { 417000000, 44000000, 62500, 0x8e, 0x3a }, { 999999999, 44000000, 62500, 0x8e, 0x3c }, }, }; -EXPORT_SYMBOL(dvb_pll_thomson_dtt7611); +EXPORT_SYMBOL(dvb_pll_thomson_dtt761x); struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ @@ -332,7 +333,7 @@ struct dvb_pll_desc dvb_pll_tbmv30111in = { .name = "Samsung TBMV30111IN", .min = 54000000, .max = 860000000, - .count = 4, + .count = 6, .entries = { { 172000000, 44000000, 166666, 0xb4, 0x01 }, { 214000000, 44000000, 166666, 0xb4, 0x02 }, @@ -344,6 +345,23 @@ struct dvb_pll_desc dvb_pll_tbmv30111in = { }; EXPORT_SYMBOL(dvb_pll_tbmv30111in); +/* + * Philips SD1878 Tuner. + */ +struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { + .name = "Philips SD1878", + .min = 950000, + .max = 2150000, + .count = 4, + .entries = { + { 1250000, 499, 500, 0xc4, 0x00}, + { 1550000, 499, 500, 0xc4, 0x40}, + { 2050000, 499, 500, 0xc4, 0x80}, + { 2150000, 499, 500, 0xc4, 0xc0}, + }, +}; +EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261); + /* ----------------------------------------------------------- */ /* code */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 497d31dcf41..f682c09189b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -25,7 +25,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; extern struct dvb_pll_desc dvb_pll_lg_z201; extern struct dvb_pll_desc dvb_pll_microtune_4042; -extern struct dvb_pll_desc dvb_pll_thomson_dtt7611; +extern struct dvb_pll_desc dvb_pll_thomson_dtt761x; extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_tua6010xs; @@ -39,6 +39,7 @@ extern struct dvb_pll_desc dvb_pll_tded4; extern struct dvb_pll_desc dvb_pll_tuv1236d; extern struct dvb_pll_desc dvb_pll_tdhu2; extern struct dvb_pll_desc dvb_pll_tbmv30111in; +extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261; int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index cb5301865d0..4691ac54bc1 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -27,6 +27,7 @@ * DViCO FusionHDTV 3 Gold-T * DViCO FusionHDTV 5 Gold * DViCO FusionHDTV 5 Lite + * DViCO FusionHDTV 5 USB Gold * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) * * TODO: @@ -402,6 +403,8 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, state->config->pll_set(fe, param); /* Keep track of the new frequency */ + /* FIXME this is the wrong way to do this... */ + /* The tuner is shared with the video4linux analog API */ state->current_frequency = param->frequency; lgdt330x_SwReset(state); @@ -711,10 +714,9 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, u8 buf[1]; /* Allocate memory for the internal state */ - state = (struct lgdt330x_state*) kmalloc(sizeof(struct lgdt330x_state), GFP_KERNEL); + state = kzalloc(sizeof(struct lgdt330x_state), GFP_KERNEL); if (state == NULL) goto error; - memset(state,0,sizeof(*state)); /* Setup the state */ state->config = config; diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 8d672283c93..ec4e641acc6 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -501,7 +501,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe, case ID_VP310: // For now we will do this only for the VP310. // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03 - if ((ret = mt312_readreg(state, CONFIG, &config_val) < 0)) + ret = mt312_readreg(state, CONFIG, &config_val); + if (ret < 0) return ret; if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz { diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index f0c610f2c2d..aaaec909ddf 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -535,9 +535,8 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config, struct mt352_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct mt352_state), GFP_KERNEL); + state = kzalloc(sizeof(struct mt352_state), GFP_KERNEL); if (state == NULL) goto error; - memset(state,0,sizeof(*state)); /* setup the state */ state->i2c = i2c; diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c index 52c416043a6..4f263e65ba1 100644 --- a/drivers/media/dvb/frontends/nxt2002.c +++ b/drivers/media/dvb/frontends/nxt2002.c @@ -22,7 +22,8 @@ /* * This driver needs external firmware. Please use the command * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" #define CRC_CCIT_MASK 0x1021 diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index aeafef46e3e..78d2b93d35b 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -1110,10 +1110,9 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, u8 buf [] = {0,0,0,0,0}; /* allocate memory for the internal state */ - state = (struct nxt200x_state*) kmalloc(sizeof(struct nxt200x_state), GFP_KERNEL); + state = kzalloc(sizeof(struct nxt200x_state), GFP_KERNEL); if (state == NULL) goto error; - memset(state,0,sizeof(*state)); /* setup the state */ state->config = config; diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index a458a3bfff7..a16eeba0020 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -574,11 +574,11 @@ static struct dvb_frontend_ops nxt6000_ops = { .symbol_rate_max = 9360000, /* FIXME */ .symbol_rate_tolerance = 4000, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, }, .release = nxt6000_release, diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 531f76246e5..7c3aed1f546 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -25,7 +25,8 @@ /* * This driver needs external firmware. Please use the command * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw" @@ -112,7 +113,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe, u8 tudata[585]; int i; - dprintk("Firmware is %d bytes\n",fw->size); + dprintk("Firmware is %zd bytes\n",fw->size); /* Get eprom data */ tudata[0] = 17; diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 18715091aed..d6947759692 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -521,8 +521,8 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state, case FEC_3_4: s5h1420_writereg(state, 0x30, 0x04); - s5h1420_writereg(state, 0x31, 0x12 | inversion); - break; + s5h1420_writereg(state, 0x31, 0x12 | inversion); + break; case FEC_5_6: s5h1420_writereg(state, 0x30, 0x08); diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index fc06cd6b46c..73829e647e5 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -22,7 +22,8 @@ /* * This driver needs external firmware. Please use the command * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index e3b66578224..eb8a602198c 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -5,7 +5,8 @@ /* * This driver needs external firmware. Please use the command * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw" @@ -581,7 +582,7 @@ static struct dvb_frontend_ops sp887x_ops = { .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_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_RECOVER + FE_CAN_RECOVER }, .release = sp887x_release, diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 177d71d56b6..5bcd00f792e 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -131,6 +131,13 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len return ret == 2 ? 0 : ret; } +int stv0299_enable_plli2c (struct dvb_frontend* fe) +{ + struct stv0299_state* state = fe->demodulator_priv; + + return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ +} + static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) { dprintk ("%s\n", __FUNCTION__); @@ -387,7 +394,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag }; } -static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) +static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long cmd) { struct stv0299_state* state = fe->demodulator_priv; u8 reg0x08; @@ -407,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) cmd = cmd << 1; if (debug_legacy_dish_switch) - printk ("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + printk ("%s switch command: 0x%04lx\n",__FUNCTION__, cmd); do_gettimeofday (&nexttime); if (debug_legacy_dish_switch) @@ -717,5 +724,6 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(stv0299_enable_plli2c); EXPORT_SYMBOL(stv0299_writereg); EXPORT_SYMBOL(stv0299_attach); diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 9af3d71c89d..32c87b4c2f1 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -94,6 +94,7 @@ struct stv0299_config }; extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); +extern int stv0299_enable_plli2c (struct dvb_frontend* fe); extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, struct i2c_adapter* i2c); diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 425cd19136f..21255cac979 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -95,7 +95,7 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) u8 b0 [] = { reg }; u8 b1 [] = { 0 }; struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; int ret; ret = i2c_transfer (state->i2c, msg, 2); @@ -434,7 +434,7 @@ static struct dvb_frontend_ops tda10021_ops = { .frequency_max = 858000000, .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ - #if 0 +#if 0 .frequency_tolerance = ???, .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ #endif diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index dd02aff467f..c63e9a5084e 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -23,7 +23,8 @@ * This driver needs external firmware. Please use the commands * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045", * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to - * download/extract them, and then copy them to /usr/lib/hotplug/firmware. + * download/extract them, and then copy them to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). */ #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw" #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw" @@ -271,32 +272,57 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state, static int tda10046h_set_bandwidth(struct tda1004x_state *state, fe_bandwidth_t bandwidth) { - static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e }; - static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 }; - static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd }; - + static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; + static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; + static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d }; + + static u8 bandwidth_6mhz_48M[] = { 0x70, 0x02, 0x49, 0x24, 0x92 }; + static u8 bandwidth_7mhz_48M[] = { 0x60, 0x02, 0xaa, 0xaa, 0xab }; + static u8 bandwidth_8mhz_48M[] = { 0x54, 0x03, 0x0c, 0x30, 0xc3 }; + int tda10046_clk53m; + + if ((state->config->if_freq == TDA10046_FREQ_045) || + (state->config->if_freq == TDA10046_FREQ_052)) + tda10046_clk53m = 0; + else + tda10046_clk53m = 1; switch (bandwidth) { case BANDWIDTH_6_MHZ: - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, + sizeof(bandwidth_6mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_48M, + sizeof(bandwidth_6mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xab); } break; case BANDWIDTH_7_MHZ: - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, + sizeof(bandwidth_7mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_48M, + sizeof(bandwidth_7mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); } break; case BANDWIDTH_8_MHZ: - tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + if (tda10046_clk53m) + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, + sizeof(bandwidth_8mhz_53M)); + else + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_48M, + sizeof(bandwidth_8mhz_48M)); if (state->config->if_freq == TDA10046_FREQ_045) { - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x55); } break; @@ -418,9 +444,22 @@ static int tda10045_fwupload(struct dvb_frontend* fe) static void tda10046_init_plls(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; + int tda10046_clk53m; + + if ((state->config->if_freq == TDA10046_FREQ_045) || + (state->config->if_freq == TDA10046_FREQ_052)) + tda10046_clk53m = 0; + else + tda10046_clk53m = 1; tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10 + if(tda10046_clk53m) { + printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n"); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8 + } else { + printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n"); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3 + } if (state->config->xtal_freq == TDA10046_XTAL_4M ) { dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 @@ -428,26 +467,32 @@ static void tda10046_init_plls(struct dvb_frontend* fe) dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 } - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); + if(tda10046_clk53m) + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x67); + else + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 0x72); + /* Note clock frequency is handled implicitly */ switch (state->config->if_freq) { - case TDA10046_FREQ_3617: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); - break; - case TDA10046_FREQ_3613: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13); - break; case TDA10046_FREQ_045: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x00); break; case TDA10046_FREQ_052: - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0d); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xc7); + break; + case TDA10046_FREQ_3617: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x59); + break; + case TDA10046_FREQ_3613: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd7); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); break; } tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + /* let the PLLs settle */ + msleep(120); } static int tda10046_fwupload(struct dvb_frontend* fe) @@ -462,13 +507,13 @@ static int tda10046_fwupload(struct dvb_frontend* fe) /* let the clocks recover from sleep */ msleep(5); + /* The PLLs need to be reprogrammed after sleep */ + tda10046_init_plls(fe); + /* don't re-upload unless necessary */ if (tda1004x_check_upload_ok(state) == 0) return 0; - /* set parameters */ - tda10046_init_plls(fe); - if (state->config->request_firmware != NULL) { /* request the firmware, this will block until someone uploads it */ printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); @@ -484,7 +529,6 @@ static int tda10046_fwupload(struct dvb_frontend* fe) return ret; } else { /* boot from firmware eeprom */ - /* Hac Note: we might need to do some GPIO Magic here */ printk(KERN_INFO "tda1004x: booting from eeprom\n"); tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); msleep(300); @@ -606,10 +650,9 @@ static int tda10046_init(struct dvb_frontend* fe) // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream - tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer + tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream + tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer - tda10046_init_plls(fe); switch (state->config->agc_config) { case TDA10046_AGC_DEFAULT: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup @@ -626,25 +669,22 @@ static int tda10046_init(struct dvb_frontend* fe) case TDA10046_AGC_TDA827X: tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold - tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize - tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities break; } + tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } - tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 + tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 0x12); // IF gain 2, TUN gain 1 tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); - tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup - tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config - tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select - state->initialised = 1; return 0; } @@ -686,9 +726,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // Set standard params.. or put them to auto if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || - (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || - (fe_params->u.ofdm.constellation == QAM_AUTO) || - (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { + (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || + (fe_params->u.ofdm.constellation == QAM_AUTO) || + (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits @@ -851,6 +891,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) { struct tda1004x_state* state = fe->demodulator_priv; + dprintk("%s\n", __FUNCTION__); // inversion status @@ -875,16 +916,18 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete break; } break; - case TDA1004X_DEMOD_TDA10046: switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { - case 0x60: + case 0x5c: + case 0x54: fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break; - case 0x6e: + case 0x6a: + case 0x60: fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break; - case 0x80: + case 0x7b: + case 0x70: fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break; } diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig index f02842be0d6..84f8f9f5286 100644 --- a/drivers/media/dvb/pluto2/Kconfig +++ b/drivers/media/dvb/pluto2/Kconfig @@ -8,7 +8,7 @@ config DVB_PLUTO2 Support for PCI cards based on the Pluto2 FPGA like the Satelco Easywatch Mobile Terrestrial DVB-T Receiver. - Since these cards have no MPEG decoder onboard, they transmit + Since these cards have no MPEG decoder onboard, they transmit only compressed MPEG data over the PCI bus, so you need an external software decoder to watch TV on your computer. diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index bbebd1c4cac..1c5316e209e 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -584,11 +584,10 @@ static int __devinit pluto2_probe(struct pci_dev *pdev, struct dmx_demux *dmx; int ret = -ENOMEM; - pluto = kmalloc(sizeof(struct pluto), GFP_KERNEL); + pluto = kzalloc(sizeof(struct pluto), GFP_KERNEL); if (!pluto) goto out; - memset(pluto, 0, sizeof(struct pluto)); pluto->pdev = pdev; ret = pci_enable_device(pdev); diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index fa5034a9ecf..5b2aadb8385 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -18,9 +18,10 @@ config DVB_AV7110 This driver only supports the fullfeatured cards with onboard MPEG2 decoder. - This driver needs an external firmware. Please use the script - "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. + This driver needs an external firmware. Please use the script + "<kerneldir>/Documentation/dvb/get_dvb_firmware av7110" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). Say Y if you own such a card and want to use it. diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index 825ab1c38a4..a690730ac39 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -16,7 +16,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ hostprogs-y := fdump ifdef CONFIG_DVB_AV7110_FIRMWARE -$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h +$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h $(obj)/av7110_firm.h: $(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@ diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 7dae91e5863..27494901975 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -81,7 +81,7 @@ static int adac = DVB_ADAC_TI; static int hw_sections; static int rgb_on; static int volume = 255; -static int budgetpatch = 0; +static int budgetpatch; module_param_named(debug, av7110_debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); @@ -103,7 +103,7 @@ MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 static void restart_feeds(struct av7110 *av7110); -static int av7110_num = 0; +static int av7110_num; #define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \ {\ @@ -133,7 +133,13 @@ static void init_av7110_av(struct av7110 *av7110) /* remaining inits according to card and frontend type */ av7110->analog_tuner_flags = 0; av7110->current_input = 0; - if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) { + printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x5; + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on + } + else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_CRYSTAL; @@ -156,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110) else { av7110->adac_type = adac; printk("dvb-ttpci: adac type set to %d @ card %d\n", - av7110->dvb_adapter.num, av7110->adac_type); + av7110->adac_type, av7110->dvb_adapter.num); } - if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { + if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) { // switch DVB SCART on ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); if (ret < 0) @@ -190,17 +196,15 @@ static void recover_arm(struct av7110 *av7110) av7110_bootarm(av7110); msleep(100); - restart_feeds(av7110); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); -} -static void arm_error(struct av7110 *av7110) -{ - dprintk(4, "%p\n",av7110); + init_av7110_av(av7110); + + /* card-specific recovery */ + if (av7110->recover) + av7110->recover(av7110); - av7110->arm_errors++; - av7110->arm_ready = 0; - recover_arm(av7110); + restart_feeds(av7110); + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config); } static void av7110_arm_sync(struct av7110 *av7110) @@ -240,26 +244,22 @@ static int arm_thread(void *data) if (down_interruptible(&av7110->dcomlock)) break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); up(&av7110->dcomlock); - if (newloops == av7110->arm_loops) { + if (newloops == av7110->arm_loops || av7110->arm_errors > 3) { printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", av7110->dvb_adapter.num); - arm_error(av7110); - av7710_set_video_mode(av7110, vidmode); - - init_av7110_av(av7110); + recover_arm(av7110); if (down_interruptible(&av7110->dcomlock)) break; - newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; up(&av7110->dcomlock); } av7110->arm_loops = newloops; + av7110->arm_errors = 0; } av7110->arm_thread = NULL; @@ -510,10 +510,6 @@ static void gpioirq(unsigned long data) iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); av7110->video_size.h = h_ar & 0xfff; - dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", - av7110->video_size.w, - av7110->video_size.h, - av7110->video_size.aspect_ratio); event.type = VIDEO_EVENT_SIZE_CHANGED; event.u.size.w = av7110->video_size.w; @@ -535,6 +531,11 @@ static void gpioirq(unsigned long data) event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; av7110->videostate.video_format = VIDEO_FORMAT_4_3; } + + dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", + av7110->video_size.w, av7110->video_size.h, + av7110->video_size.aspect_ratio); + dvb_video_add_event(av7110, &event); break; } @@ -714,6 +715,8 @@ static struct dvb_device dvbdev_osd = { static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid) { + u16 aflags = 0; + dprintk(4, "%p\n", av7110); if (vpid == 0x1fff || apid == 0x1fff || @@ -725,8 +728,11 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, av7110->pids[DMX_PES_PCR] = 0; } - return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 5, - pcrpid, vpid, apid, ttpid, subpid); + if (av7110->audiostate.bypass_mode) + aflags |= 0x8000; + + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6, + pcrpid, vpid, apid, ttpid, subpid, aflags); } int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, @@ -1043,7 +1049,7 @@ static void restart_feeds(struct av7110 *av7110) struct dvb_demux *dvbdmx = &av7110->demux; struct dvb_demux_feed *feed; int mode; - int i; + int i, j; dprintk(4, "%p\n", av7110); @@ -1051,10 +1057,21 @@ static void restart_feeds(struct av7110 *av7110) av7110->playing = 0; av7110->rec_mode = 0; - for (i = 0; i < dvbdmx->filternum; i++) { + for (i = 0; i < dvbdmx->feednum; i++) { feed = &dvbdmx->feed[i]; - if (feed->state == DMX_STATE_GO) + if (feed->state == DMX_STATE_GO) { + if (feed->type == DMX_TYPE_SEC) { + for (j = 0; j < dvbdmx->filternum; j++) { + if (dvbdmx->filter[j].type != DMX_TYPE_SEC) + continue; + if (dvbdmx->filter[j].filter.parent != &feed->feed.sec) + continue; + if (dvbdmx->filter[j].state == DMX_STATE_GO) + dvbdmx->filter[j].state = DMX_STATE_READY; + } + } av7110_start_feed(feed); + } } if (mode) @@ -1483,9 +1500,9 @@ static int get_firmware(struct av7110* av7110) if (ret == -ENOENT) { printk(KERN_ERR "dvb-ttpci: could not load firmware," " file not found: dvb-ttpci-01.fw\n"); - printk(KERN_ERR "dvb-ttpci: usually this should be in" - " /usr/lib/hotplug/firmware\n"); - printk(KERN_ERR "dvb-ttpci: and can be downloaded here" + printk(KERN_ERR "dvb-ttpci: usually this should be in " + "/usr/lib/hotplug/firmware or /lib/firmware\n"); + printk(KERN_ERR "dvb-ttpci: and can be downloaded from" " http://www.linuxtv.org/download/dvb/firmware/\n"); } else printk(KERN_ERR "dvb-ttpci: cannot request firmware" @@ -2110,8 +2127,10 @@ static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_p struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_fe_params = *params; ret = av7110->fe_set_frontend(fe, params); + } return ret; } @@ -2153,8 +2172,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_master_cmd = *cmd; ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); + } return ret; } @@ -2163,8 +2184,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_minicmd = minicmd; ret = av7110->fe_diseqc_send_burst(fe, minicmd); + } return ret; } @@ -2173,8 +2196,10 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_tone = tone; ret = av7110->fe_set_tone(fe, tone); + } return ret; } @@ -2183,12 +2208,14 @@ static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t volta struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) + if (!ret) { + av7110->saved_voltage = voltage; ret = av7110->fe_set_voltage(fe, voltage); + } return ret; } -static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd) +static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd) { struct av7110* av7110 = fe->dvb->priv; @@ -2198,6 +2225,23 @@ static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, un return ret; } +static void dvb_s_recover(struct av7110* av7110) +{ + av7110_fe_init(av7110->fe); + + av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); + if (av7110->saved_master_cmd.msg_len) { + msleep(20); + av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); + } + msleep(20); + av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); + msleep(20); + av7110_fe_set_tone(av7110->fe, av7110->saved_tone); + + av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params); +} + static u8 read_pwm(struct av7110* av7110) { u8 b = 0xff; @@ -2235,6 +2279,7 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; break; } @@ -2244,15 +2289,17 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; break; } // Try the grundig 29504-451 - av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap); + av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; break; } @@ -2274,12 +2321,12 @@ static int frontend_init(struct av7110 *av7110) case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X // ALPS TDLB7 - av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap); + av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap); break; case 0x0002: // Hauppauge/TT DVB-C premium rev2.X - av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); break; case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ @@ -2289,6 +2336,7 @@ static int frontend_init(struct av7110 *av7110) av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops->set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; } break; @@ -2314,8 +2362,11 @@ static int frontend_init(struct av7110 *av7110) case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ /* ALPS BSBE1 */ av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap); - if (av7110->fe) + if (av7110->fe) { av7110->fe->ops->set_voltage = lnbp21_set_voltage; + av7110->fe->ops->dishnetwork_send_legacy_command = NULL; + av7110->recover = dvb_s_recover; + } break; } } @@ -2514,14 +2565,12 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d } /* prepare the av7110 device struct */ - av7110 = kmalloc(sizeof(struct av7110), GFP_KERNEL); + av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL); if (!av7110) { dprintk(1, "out of memory\n"); return -ENOMEM; } - memset(av7110, 0, sizeof(struct av7110)); - av7110->card_name = (char*) pci_ext->ext_priv; av7110->dev = dev; dev->ext_priv = av7110; diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index cce00ef293e..6ea30df2e82 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -98,7 +98,8 @@ struct av7110 { int adac_type; /* audio DAC type */ #define DVB_ADAC_TI 0 #define DVB_ADAC_CRYSTAL 1 -#define DVB_ADAC_MSP 2 +#define DVB_ADAC_MSP34x0 2 +#define DVB_ADAC_MSP34x5 3 #define DVB_ADAC_NONE -1 @@ -228,6 +229,9 @@ struct av7110 { struct dvb_video_events video_events; video_size_t video_size; + u16 wssMode; + u16 wssData; + u32 ir_config; u32 ir_command; void (*ir_handler)(struct av7110 *av7110, u32 ircom); @@ -245,6 +249,15 @@ struct av7110 { struct dvb_frontend* fe; fe_status_t fe_status; + + /* crash recovery */ + void (*recover)(struct av7110* av7110); + struct dvb_frontend_parameters saved_fe_params; + fe_sec_voltage_t saved_voltage; + fe_sec_tone_mode_t saved_tone; + struct dvb_diseqc_master_cmd saved_master_cmd; + fe_sec_mini_cmd_t saved_minicmd; + int (*fe_init)(struct dvb_frontend* fe); int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); @@ -252,7 +265,7 @@ struct av7110 { int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 0696a5a4f85..400facec740 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -309,7 +309,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) i2c_writereg(av7110, 0x20, 0x04, volright); return 0; - case DVB_ADAC_MSP: + case DVB_ADAC_MSP34x0: vol = (volleft > volright) ? volleft : volright; val = (vol * 0x73 / 255) << 8; if (vol > 0) @@ -1256,7 +1256,9 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, break; case AUDIO_SET_BYPASS_MODE: - ret = -EINVAL; + if (FW_VERSION(av7110->arm_app) < 0x2621) + ret = -EINVAL; + av7110->audiostate.bypass_mode = (int)arg; break; case AUDIO_CHANNEL_SELECT: @@ -1295,7 +1297,11 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, break; case AUDIO_GET_CAPABILITIES: - *(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + if (FW_VERSION(av7110->arm_app) < 0x2621) + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + else + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 | + AUDIO_CAP_MP1 | AUDIO_CAP_MP2; break; case AUDIO_CLEAR_BUFFER: diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 87106e8bf35..b2e63e9fc05 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -146,52 +146,52 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) { int i; int blocks, rest; - u32 base, bootblock = BOOT_BLOCK; + u32 base, bootblock = AV7110_BOOT_BLOCK; dprintk(4, "%p\n", av7110); - blocks = len / BOOT_MAX_SIZE; - rest = len % BOOT_MAX_SIZE; + blocks = len / AV7110_BOOT_MAX_SIZE; + rest = len % AV7110_BOOT_MAX_SIZE; base = DRAM_START_CODE; for (i = 0; i < blocks; i++) { - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); return -ETIMEDOUT; } dprintk(4, "writing DRAM block %d\n", i); mwdebi(av7110, DEBISWAB, bootblock, - ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE); + ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); bootblock ^= 0x1400; - iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4); - iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, BOOT_MAX_SIZE, 2); - iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - base += BOOT_MAX_SIZE; + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + base += AV7110_BOOT_MAX_SIZE; } if (rest > 0) { - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); return -ETIMEDOUT; } if (rest > 4) mwdebi(av7110, DEBISWAB, bootblock, - ((char*)data) + i * BOOT_MAX_SIZE, rest); + ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest); else mwdebi(av7110, DEBISWAB, bootblock, - ((char*)data) + i * BOOT_MAX_SIZE - 4, rest + 4); + ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); - iwdebi(av7110, DEBISWAB, BOOT_BASE, swab32(base), 4); - iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, rest, 2); - iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); } - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); return -ETIMEDOUT; } - iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2); - iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) { + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); return -ETIMEDOUT; } @@ -230,6 +230,8 @@ int av7110_bootarm(struct av7110 *av7110) dprintk(4, "%p\n", av7110); + av7110->arm_ready = 0; + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); /* Disable DEBI and GPIO irq */ @@ -260,7 +262,7 @@ int av7110_bootarm(struct av7110 *av7110) //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT); mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode)); - iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); if (saa7146_wait_for_debi_done(av7110->dev, 1)) { printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " @@ -361,6 +363,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) break; if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); + av7110->arm_errors++; return -ETIMEDOUT; } msleep(1); @@ -1206,9 +1209,9 @@ int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) switch (cap->cmd) { case OSD_CAP_MEMSIZE: if (FW_4M_SDRAM(av7110->arm_app)) - cap->val = 1000000; + cap->val = 1000000; else - cap->val = 92000; + cap->val = 92000; return 0; default: return -EINVAL; diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index 2a5e87ba105..4e173c67fbb 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h @@ -18,7 +18,7 @@ enum av7110_bootstate { BOOTSTATE_BUFFER_EMPTY = 0, BOOTSTATE_BUFFER_FULL = 1, - BOOTSTATE_BOOT_COMPLETE = 2 + BOOTSTATE_AV7110_BOOT_COMPLETE = 2 }; enum av7110_type_rec_play_format @@ -167,7 +167,8 @@ enum av7110_encoder_command { LoadVidCode, SetMonitorType, SetPanScanType, - SetFreezeMode + SetFreezeMode, + SetWSSConfig }; enum av7110_rec_play_state { @@ -294,11 +295,11 @@ enum av7110_command_type { #define DPRAM_BASE 0x4000 /* boot protocol area */ -#define BOOT_STATE (DPRAM_BASE + 0x3F8) -#define BOOT_SIZE (DPRAM_BASE + 0x3FA) -#define BOOT_BASE (DPRAM_BASE + 0x3FC) -#define BOOT_BLOCK (DPRAM_BASE + 0x400) -#define BOOT_MAX_SIZE 0xc00 +#define AV7110_BOOT_STATE (DPRAM_BASE + 0x3F8) +#define AV7110_BOOT_SIZE (DPRAM_BASE + 0x3FA) +#define AV7110_BOOT_BASE (DPRAM_BASE + 0x3FC) +#define AV7110_BOOT_BLOCK (DPRAM_BASE + 0x400) +#define AV7110_BOOT_MAX_SIZE 0xc00 /* firmware command protocol area */ #define IRQ_STATE (DPRAM_BASE + 0x0F4) diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index f5e59fc924a..9138132ad25 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -17,6 +17,8 @@ static int av_cnt; static struct av7110 *av_list[4]; static struct input_dev *input_dev; +static u8 delay_timer_finished; + 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, @@ -112,13 +114,16 @@ static void av7110_emit_key(unsigned long parm) if (timer_pending(&keyup_timer)) { del_timer(&keyup_timer); if (keyup_timer.data != keycode || new_toggle != old_toggle) { + delay_timer_finished = 0; input_event(input_dev, EV_KEY, keyup_timer.data, !!0); input_event(input_dev, EV_KEY, keycode, !0); } else - input_event(input_dev, EV_KEY, keycode, 2); - - } else + if (delay_timer_finished) + input_event(input_dev, EV_KEY, keycode, 2); + } else { + delay_timer_finished = 0; input_event(input_dev, EV_KEY, keycode, !0); + } keyup_timer.expires = jiffies + UP_TIMEOUT; keyup_timer.data = keycode; @@ -145,7 +150,8 @@ static void input_register_keys(void) static void input_repeat_key(unsigned long data) { - /* dummy routine to disable autorepeat in the input driver */ + /* called by the input driver after rep[REP_DELAY] ms */ + delay_timer_finished = 1; } diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index b5aea4129fa..94cf38c7e8a 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -490,6 +490,58 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); break; } + case VIDIOC_G_SLICED_VBI_CAP: + { + struct v4l2_sliced_vbi_cap *cap = arg; + dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); + memset(cap, 0, sizeof *cap); + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + cap->service_set = V4L2_SLICED_WSS_625; + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + } + break; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + dprintk(2, "VIDIOC_G_FMT:\n"); + if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT || + FW_VERSION(av7110->arm_app) < 0x2623) + return -EAGAIN; /* handled by core driver */ + memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); + if (av7110->wssMode) { + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data); + } + break; + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + dprintk(2, "VIDIOC_S_FMT\n"); + if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT || + FW_VERSION(av7110->arm_app) < 0x2623) + return -EAGAIN; /* handled by core driver */ + if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && + f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { + memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); + /* WSS controlled by firmware */ + av7110->wssMode = 0; + av7110->wssData = 0; + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, + SetWSSConfig, 1, 0); + } else { + memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data); + /* WSS controlled by userspace */ + av7110->wssMode = 1; + av7110->wssData = 0; + } + break; + } default: printk("no such ioctl\n"); return -ENOIOCTLCMD; @@ -497,6 +549,46 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) return 0; } +static int av7110_vbi_reset(struct inode *inode, struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + + dprintk(2, "%s\n", __FUNCTION__); + av7110->wssMode = 0; + av7110->wssData = 0; + if (FW_VERSION(av7110->arm_app) < 0x2623) + return 0; + else + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0); +} + +static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + struct v4l2_sliced_vbi_data d; + int rc; + + dprintk(2, "%s\n", __FUNCTION__); + if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d) + return -EINVAL; + if (copy_from_user(&d, data, count)) + return -EFAULT; + if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23) + return -EINVAL; + if (d.id) { + av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0]; + rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, + 2, 1, av7110->wssData); + } else { + av7110->wssData = 0; + rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0); + } + return (rc < 0) ? rc : count; +} /**************************************************************************** * INITIALIZATION @@ -512,6 +604,9 @@ static struct saa7146_extension_ioctls ioctls[] = { { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, + { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE }, + { VIDIOC_G_FMT, SAA7146_BEFORE }, + { VIDIOC_S_FMT, SAA7146_BEFORE }, { 0, 0 } }; @@ -587,7 +682,7 @@ int av7110_init_analog_module(struct av7110 *av7110) printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP; + av7110->adac_type = DVB_ADAC_MSP34x0; msleep(100); // the probing above resets the msp... msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); @@ -692,12 +787,11 @@ int av7110_init_v4l(struct av7110 *av7110) saa7146_vv_release(dev); return -ENODEV; } - if (av7110->analog_tuner_flags) { - if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) { - ERR(("cannot register vbi v4l2 device. skipping.\n")); - } else { + if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) { + ERR(("cannot register vbi v4l2 device. skipping.\n")); + } else { + if (av7110->analog_tuner_flags) av7110->analog_tuner_flags |= ANALOG_TUNER_VBI; - } } return 0; } @@ -778,7 +872,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) static struct saa7146_ext_vv av7110_vv_data_st = { .inputs = 1, .audios = 1, - .capabilities = 0, + .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT, .flags = 0, .stds = &standard[0], @@ -787,12 +881,16 @@ static struct saa7146_ext_vv av7110_vv_data_st = { .ioctls = &ioctls[0], .ioctl = av7110_ioctl, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, }; static struct saa7146_ext_vv av7110_vv_data_c = { .inputs = 1, .audios = 1, - .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, + .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT, .flags = SAA7146_USE_PORT_B_FOR_VBI, .stds = &standard[0], @@ -801,5 +899,9 @@ static struct saa7146_ext_vv av7110_vv_data_c = { .ioctls = &ioctls[0], .ioctl = av7110_ioctl, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, }; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9f51bae7194..1465c04e49a 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -37,6 +37,7 @@ #include "stv0299.h" #include "tda10021.h" #include "tda1004x.h" +#include "dvb-pll.h" #include <media/saa7146_vv.h> #include <linux/module.h> #include <linux/errno.h> @@ -127,7 +128,7 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0); + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); if (result == -ETIMEDOUT) budget_av->slot_status = 0; @@ -145,7 +146,7 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0); + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); if (result == -ETIMEDOUT) budget_av->slot_status = 0; @@ -192,7 +193,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 = 500; // 5 seconds (4.4.6 Ready) + int timeout = 50; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; @@ -256,19 +257,37 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; + int cam_present = 0; if (slot != 0) return -EINVAL; - if (!budget_av->slot_status) { + if (!budget_av->slot_status) + { + // first of all test the card detect line saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); udelay(1); if (saa7146_read(saa, PSR) & MASK_06) { + cam_present = 1; + } + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + + // that is unreliable however, so try and read from IO memory + if (!cam_present) + { + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) + { + cam_present = 1; + } + } + + // did we find something? + if (cam_present) { printk(KERN_INFO "budget-av: cam inserted\n"); budget_av->slot_status = 1; } - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); } else if (!open) { saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) @@ -484,6 +503,140 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, return 0; } +#define MIN2(a,b) ((a) < (b) ? (a) : (b)) +#define MIN3(a,b,c) MIN2(MIN2(a,b),c) + +static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct dvb_frontend_parameters *params) +{ + u8 reg0 [2] = { 0x00, 0x00 }; + u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 }; + u8 reg2 [3] = { 0x02, 0x00, 0x00 }; + int _fband; + int first_ZF; + int R, A, N, P, M; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 }; + int freq = params->frequency; + + first_ZF = (freq) / 1000; + + if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) < + abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890)))) + _fband = 2; + else + _fband = 3; + + if (_fband == 2) { + if (((first_ZF >= 950) && (first_ZF < 1350)) || + ((first_ZF >= 1430) && (first_ZF < 1950))) + reg0[1] = 0x07; + else if (((first_ZF >= 1350) && (first_ZF < 1430)) || + ((first_ZF >= 1950) && (first_ZF < 2150))) + reg0[1] = 0x0B; + } + + if(_fband == 3) { + if (((first_ZF >= 950) && (first_ZF < 1350)) || + ((first_ZF >= 1455) && (first_ZF < 1950))) + reg0[1] = 0x07; + else if (((first_ZF >= 1350) && (first_ZF < 1420)) || + ((first_ZF >= 1950) && (first_ZF < 2150))) + reg0[1] = 0x0B; + else if ((first_ZF >= 1420) && (first_ZF < 1455)) + reg0[1] = 0x0F; + } + + if (first_ZF > 1525) + reg1[1] |= 0x80; + else + reg1[1] &= 0x7F; + + if (_fband == 2) { + if (first_ZF > 1430) { /* 1430MHZ */ + reg1[1] &= 0xCF; /* N2 */ + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } else { + reg1[1] &= 0xCF; /* N2 */ + reg1[1] |= 0x20; + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } + } + + if (_fband == 3) { + if ((first_ZF >= 1455) && + (first_ZF < 1630)) { + reg1[1] &= 0xCF; /* N2 */ + reg1[1] |= 0x20; + reg2[1] &= 0xCF; /* R2 */ + } else { + if (first_ZF < 1455) { + reg1[1] &= 0xCF; /* N2 */ + reg1[1] |= 0x20; + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } else { + if (first_ZF >= 1630) { + reg1[1] &= 0xCF; /* N2 */ + reg2[1] &= 0xCF; /* R2 */ + reg2[1] |= 0x10; + } + } + } + } + + /* set ports, enable P0 for symbol rates > 4Ms/s */ + if (params->u.qpsk.symbol_rate >= 4000000) + reg1[1] |= 0x0c; + else + reg1[1] |= 0x04; + + reg2[1] |= 0x0c; + + R = 64; + A = 64; + P = 64; //32 + + M = (freq * R) / 4; /* in Mhz */ + N = (M - A * 1000) / (P * 1000); + + reg1[1] |= (N >> 9) & 0x03; + reg1[2] = (N >> 1) & 0xff; + reg1[3] = (N << 7) & 0x80; + + reg2[1] |= (R >> 8) & 0x03; + reg2[2] = R & 0xFF; /* R */ + + reg1[3] |= A & 0x7f; /* A */ + + if (P == 64) + reg1[1] |= 0x40; /* Prescaler 64/65 */ + + reg0[1] |= 0x03; + + /* already enabled - do not reenable i2c repeater or TX fails */ + msg.buf = reg0; + msg.len = sizeof(reg0); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + stv0299_enable_plli2c(fe); + msg.buf = reg1; + msg.len = sizeof(reg1); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + stv0299_enable_plli2c(fe); + msg.buf = reg2; + msg.len = sizeof(reg2); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + return 0; +} + static u8 typhoon_cinergy1200s_inittab[] = { 0x01, 0x15, 0x02, 0x30, @@ -553,6 +706,18 @@ static struct stv0299_config cinergy_1200s_config = { .pll_set = philips_su1278_ty_ci_pll_set, }; +static struct stv0299_config cinergy_1200s_1894_0010_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, + .pll_set = philips_su1278sh2_tua6100_pll_set, +}; static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { @@ -700,8 +865,117 @@ static struct tda1004x_config philips_tu1216_config = { .request_firmware = philips_tu1216_request_firmware, }; +static u8 philips_sd1878_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, + 0x05, 0x35, + 0x06, 0x40, + 0x07, 0x00, + 0x08, 0x43, + 0x09, 0x02, + 0x0C, 0x51, + 0x0D, 0x82, + 0x0E, 0x23, + 0x10, 0x3f, + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, + 0x16, 0x19, + 0x17, 0x8c, + 0x18, 0x59, + 0x19, 0xf8, + 0x1a, 0xfe, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x09, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x93, + 0xff, 0xff +}; + +static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct dvb_frontend_parameters *params) +{ + u8 buf[4]; + int rc; + struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)}; + + if((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf, + params->frequency, 0); + if(rc < 0) return rc; + + if(i2c_transfer(i2c, &tuner_msg, 1) != 1) + return -EIO; + + return 0; +} +static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + u8 m1; + aclk = 0xb5; + if (srate < 2000000) + bclk = 0x86; + else if (srate < 5000000) + bclk = 0x89; + else if (srate < 15000000) + bclk = 0x8f; + else if (srate < 45000000) + bclk = 0x95; + + m1 = 0x14; + if (srate < 4000000) + m1 = 0x10; + + stv0299_writereg(fe, 0x0e, 0x23); + stv0299_writereg(fe, 0x0f, 0x94); + stv0299_writereg(fe, 0x10, 0x39); + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x15, 0xc9); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + stv0299_writereg(fe, 0x0f, 0x80 | m1); + + return 0; +} + +static struct stv0299_config philips_sd1878_config = { + .demod_address = 0x68, + .inittab = philips_sd1878_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, + .pll_set = philips_sd1878_tda8261_pll_set, +}; static u8 read_pwm(struct budget_av *budget_av) { @@ -722,7 +996,10 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBS_KNC1_PLUS 0x0011 #define SUBID_DVBS_TYPHOON 0x4f56 #define SUBID_DVBS_CINERGY1200 0x1154 +#define SUBID_DVBS_CYNERGY1200N 0x1155 +#define SUBID_DVBS_TV_STAR 0x0014 +#define SUBID_DVBS_TV_STAR_CI 0x0016 #define SUBID_DVBC_KNC1 0x0020 #define SUBID_DVBC_KNC1_PLUS 0x0021 #define SUBID_DVBC_CINERGY1200 0x1156 @@ -749,6 +1026,22 @@ static void frontend_init(struct budget_av *budget_av) switch (saa->pci->subsystem_device) { case SUBID_DVBS_KNC1: + if (saa->pci->subsystem_vendor == 0x1894) { + fe = stv0299_attach(&cinergy_1200s_1894_0010_config, + &budget_av->budget.i2c_adap); + } else { + fe = stv0299_attach(&typhoon_config, + &budget_av->budget.i2c_adap); + } + break; + + case SUBID_DVBS_TV_STAR: + case SUBID_DVBS_TV_STAR_CI: + case SUBID_DVBS_CYNERGY1200N: + fe = stv0299_attach(&philips_sd1878_config, + &budget_av->budget.i2c_adap); + break; + case SUBID_DVBS_KNC1_PLUS: case SUBID_DVBS_TYPHOON: fe = stv0299_attach(&typhoon_config, @@ -854,11 +1147,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio dprintk(2, "dev: %p\n", dev); - if (!(budget_av = kmalloc(sizeof(struct budget_av), GFP_KERNEL))) + if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL))) return -ENOMEM; - memset(budget_av, 0, sizeof(struct budget_av)); - budget_av->has_saa7113 = 0; budget_av->budget.ci_present = 0; @@ -993,22 +1284,28 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); +MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); +MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), + MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), + MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), + MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), + MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), { diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 017fcbccb8c..633e68c341c 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -404,9 +404,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget); /* frontend power on */ - if (bi->type == BUDGET_FS_ACTIVY) - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - else + if (bi->type != BUDGET_FS_ACTIVY) saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); if (budget_register(budget) == 0) { diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index fafe6407b3d..238c77b52f8 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -112,6 +112,7 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long * Routines for the Fujitsu Siemens Activy budget card * 22 kHz tone and DiSEqC are handled by the frontend. * Voltage must be set here. + * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL */ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) { @@ -121,11 +122,16 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) switch (voltage) { case SEC_VOLTAGE_13: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); break; case SEC_VOLTAGE_18: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); break; + case SEC_VOLTAGE_OFF: + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); + break; default: return -EINVAL; } @@ -206,7 +212,7 @@ static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) return 0; } -static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg) +static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, long arg) { struct budget* budget = (struct budget*) fe->dvb->priv; u8 buf; @@ -580,6 +586,7 @@ static void frontend_init(struct budget *budget) if (budget->dvb_frontend) { budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage; budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; if (lnbp21_init(budget)) { printk("%s: No LNBP21 found!\n", __FUNCTION__); goto error_out; @@ -624,7 +631,7 @@ static void frontend_init(struct budget *budget) budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); if (budget->dvb_frontend) { budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; - break; + budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; } break; @@ -632,7 +639,7 @@ static void frontend_init(struct budget *budget) budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap); if (budget->dvb_frontend) { budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; - break; + budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; } break; diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index fdaa3318ad3..c7bb63c4d98 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -19,7 +19,7 @@ extern int budget_debug; #endif #define dprintk(level,args...) \ - do { if ((budget_debug & level)) { printk("%s: %s(): ",__stringify(KBUILD_MODNAME), __FUNCTION__); printk(args); } } while (0) + do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __FUNCTION__); printk(args); } } while (0) struct budget_info { char *name; @@ -95,6 +95,7 @@ static struct saa7146_pci_extension_data x_var = { \ #define BUDGET_KNC1SP 11 #define BUDGET_KNC1CP 12 #define BUDGET_KNC1TP 13 +#define BUDGET_TVSTAR 14 #define BUDGET_VIDEO_PORTA 0 #define BUDGET_VIDEO_PORTB 1 diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c index 18aa22b5478..1f31e91195b 100644 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c @@ -13,7 +13,7 @@ Holger Waechtler Convergence Copyright (C) 2002-2003 Ralph Metzler <rjkm@metzlerbros.de> - Metzler Brothers Systementwicklung GbR + Metzler Brothers Systementwicklung GbR 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/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig index c6c1d41a2ef..914587d52b5 100644 --- a/drivers/media/dvb/ttusb-budget/Kconfig +++ b/drivers/media/dvb/ttusb-budget/Kconfig @@ -10,7 +10,7 @@ config DVB_TTUSB_BUDGET Support for external USB adapters designed by Technotrend and produced by Hauppauge, shipped under the brand name 'Nova-USB'. - These devices don't have a MPEG decoder built in, so you need + These devices don't have a MPEG decoder built in, so you need an external software decoder to watch TV. Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 104df610dbe..5a13c4744f6 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1489,11 +1489,9 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i if (intf->altsetting->desc.bInterfaceNumber != 1) return -ENODEV; - if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL))) + if (!(ttusb = kzalloc(sizeof(struct ttusb), GFP_KERNEL))) return -ENOMEM; - memset(ttusb, 0, sizeof(struct ttusb)); - ttusb->dev = udev; ttusb->c = 0; ttusb->mux_state = 0; diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig index c334526af66..83611012ef3 100644 --- a/drivers/media/dvb/ttusb-dec/Kconfig +++ b/drivers/media/dvb/ttusb-dec/Kconfig @@ -8,14 +8,15 @@ config DVB_TTUSB_DEC produced by Hauppauge, shipped under the brand name 'DEC2000-t' and 'DEC3000-s'. - Even if these devices have a MPEG decoder built in, they transmit + Even if these devices have a MPEG decoder built in, they transmit only compressed MPEG data over the USB bus, so you need an external software decoder to watch TV on your computer. - This driver needs external firmware. Please use the commands - "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t", - "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t", - "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s", - download/extract them, and then copy them to /usr/lib/hotplug/firmware. + This driver needs external firmware. Please use the commands + "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2000t", + "<kerneldir>/Documentation/dvb/get_dvb_firmware dec2540t", + "<kerneldir>/Documentation/dvb/get_dvb_firmware dec3000s", + download/extract them, and then copy them to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 8abc2189012..df831171e03 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -369,7 +369,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) { - struct ttusb_dec *dec = (struct ttusb_dec *)priv; + struct ttusb_dec *dec = priv; dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, &dec->audio_filter->feed->feed.ts, @@ -380,7 +380,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) { - struct ttusb_dec *dec = (struct ttusb_dec *)priv; + struct ttusb_dec *dec = priv; dec->video_filter->feed->cb.ts(data, 188, NULL, 0, &dec->video_filter->feed->feed.ts, @@ -965,8 +965,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TS_PES_TELETEXT: dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; - dprintk(" pes_type: DMX_TS_PES_TELETEXT\n"); - break; + dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); + return -ENOSYS; case DMX_TS_PES_PCR: dprintk(" pes_type: DMX_TS_PES_PCR\n"); @@ -975,8 +975,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) break; case DMX_TS_PES_OTHER: - dprintk(" pes_type: DMX_TS_PES_OTHER\n"); - break; + dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); + return -ENOSYS; default: dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); @@ -1182,7 +1182,7 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) (unsigned long)dec); } -static int ttusb_init_rc(struct ttusb_dec *dec) +static int ttusb_init_rc( struct ttusb_dec *dec) { struct input_dev *input_dev; u8 b[] = { 0x00, 0x01 }; @@ -1203,13 +1203,12 @@ static int ttusb_init_rc(struct ttusb_dec *dec) input_dev->keycode = rc_keys; for (i = 0; i < ARRAY_SIZE(rc_keys); i++) - set_bit(rc_keys[i], input_dev->keybit); + set_bit(rc_keys[i], input_dev->keybit); input_register_device(input_dev); if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) printk("%s: usb_submit_urb failed\n",__FUNCTION__); - /* enable irq pipe */ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); @@ -1395,6 +1394,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) /* We can't trust the USB IDs that some firmwares give the box */ switch (model) { + case 0x00070001: case 0x00070008: case 0x0007000c: ttusb_dec_set_model(dec, TTUSB_DEC3000S); @@ -1588,7 +1588,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command, int param_length, const u8 params[], int *result_length, u8 cmd_result[]) { - struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv; + struct ttusb_dec* dec = fe->dvb->priv; return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); } @@ -1606,15 +1606,13 @@ static int ttusb_dec_probe(struct usb_interface *intf, udev = interface_to_usbdev(intf); - if (!(dec = kmalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { + if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { printk("%s: couldn't allocate memory.\n", __FUNCTION__); return -ENOMEM; } usb_set_intfdata(intf, (void *)dec); - memset(dec, 0, sizeof(struct ttusb_dec)); - switch (le16_to_cpu(id->idProduct)) { case 0x1006: ttusb_dec_set_model(dec, TTUSB_DEC3000S); diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 725af3af5b2..a5a46175fa0 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -42,8 +42,39 @@ struct ttusbdecfe_state { static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) { - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + struct ttusbdecfe_state* state = fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + u8 result[4]; + int len, ret; + + *status=0; + + ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result); + if(ret) + return ret; + + if(len != 4) { + printk(KERN_ERR "%s: unexpected reply\n", __FUNCTION__); + return -EIO; + } + + switch(result[3]) { + case 1: /* not tuned yet */ + case 2: /* no signal/no lock*/ + break; + case 3: /* signal found and locked*/ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + break; + case 4: + *status = FE_TIMEDOUT; + break; + default: + pr_info("%s: returned unknown value: %d\n", + __FUNCTION__, result[3]); + return -EIO; + } return 0; } @@ -64,6 +95,16 @@ static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_fron return 0; } +static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 1500; + /* Drift compensation makes no sense for DVB-T */ + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; @@ -212,6 +253,8 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { .set_frontend = ttusbdecfe_dvbt_set_frontend, + .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, + .read_status = ttusbdecfe_read_status, }; @@ -223,11 +266,11 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, + .symbol_rate_min = 1000000, /* guessed */ + .symbol_rate_max = 45000000, /* guessed */ .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_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, + FE_CAN_QPSK }, .release = ttusbdecfe_release, |