diff options
Diffstat (limited to 'linux/drivers/media/dvb')
31 files changed, 1254 insertions, 332 deletions
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index f56ffc0e2..301bf1688 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -378,7 +378,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc, if (!fc->fe) return 0; - i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);; + i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); if (!i2c_tuner) return 0; diff --git a/linux/drivers/media/dvb/bt8xx/bt878.c b/linux/drivers/media/dvb/bt8xx/bt878.c index 57f0f84b6..456cd8756 100644 --- a/linux/drivers/media/dvb/bt8xx/bt878.c +++ b/linux/drivers/media/dvb/bt8xx/bt878.c @@ -512,12 +512,6 @@ static int __devinit bt878_probe(struct pci_dev *dev, pci_set_master(dev); pci_set_drvdata(dev, bt); -/* if(init_bt878(btv) < 0) { - bt878_remove(dev); - return -EIO; - } -*/ - if ((result = bt878_mem_alloc(bt))) { printk(KERN_ERR "bt878: failed to allocate memory!\n"); goto fail2; @@ -583,7 +577,7 @@ static struct pci_driver bt878_pci_driver = { .name = "bt878", .id_table = bt878_pci_tbl, .probe = bt878_probe, - .remove = bt878_remove, + .remove = __devexit_p(bt878_remove), }; static int bt878_pci_driver_registered; diff --git a/linux/drivers/media/dvb/dm1105/dm1105.c b/linux/drivers/media/dvb/dm1105/dm1105.c index ca1048fd4..17edeb66b 100644 --- a/linux/drivers/media/dvb/dm1105/dm1105.c +++ b/linux/drivers/media/dvb/dm1105/dm1105.c @@ -51,6 +51,9 @@ #ifndef PCI_VENDOR_ID_TRIGEM #define PCI_VENDOR_ID_TRIGEM 0x109f #endif +#ifndef PCI_VENDOR_ID_AXESS +#define PCI_VENDOR_ID_AXESS 0x195d +#endif #ifndef PCI_DEVICE_ID_DM1105 #define PCI_DEVICE_ID_DM1105 0x036f #endif @@ -60,6 +63,9 @@ #ifndef PCI_DEVICE_ID_DW2004 #define PCI_DEVICE_ID_DW2004 0x2004 #endif +#ifndef PCI_DEVICE_ID_DM05 +#define PCI_DEVICE_ID_DM05 0x1105 +#endif /* ----------------------------------------------- */ /* sdmc dm1105 registers */ @@ -150,6 +156,11 @@ #define DM1105_LNB_13V 0x00010100 #define DM1105_LNB_18V 0x00000100 +/* GPIO's for LNB power control for Axess DM05 */ +#define DM05_LNB_MASK 0x00000000 +#define DM05_LNB_13V 0x00020000 +#define DM05_LNB_18V 0x00030000 + static int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); @@ -188,6 +199,8 @@ struct dm1105dvb { /* irq */ struct work_struct work; + struct workqueue_struct *wq; + char wqn[16]; /* dma */ dma_addr_t dma_addr; @@ -316,15 +329,25 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe) static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe); + u32 lnb_mask, lnb_13v, lnb_18v; - if (voltage == SEC_VOLTAGE_18) { - outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); - outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL)); - } else { - /*LNB ON-13V by default!*/ - outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR)); - outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL)); - } + switch (dm1105dvb->pdev->subsystem_device) { + case PCI_DEVICE_ID_DM05: + lnb_mask = DM05_LNB_MASK; + lnb_13v = DM05_LNB_13V; + lnb_18v = DM05_LNB_18V; + break; + default: + lnb_mask = DM1105_LNB_MASK; + lnb_13v = DM1105_LNB_13V; + lnb_18v = DM1105_LNB_18V; + } + + outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR)); + if (voltage == SEC_VOLTAGE_18) + outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL)); + else + outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL)); return 0; } @@ -463,7 +486,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id) case (INTSTS_TSIRQ | INTSTS_IR): dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) - inl(dm_io_mem(DM1105_STADR)); - schedule_work(&dm1105dvb->work); + queue_work(dm1105dvb->wq, &dm1105dvb->work); break; case INTSTS_IR: dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE)); @@ -599,46 +622,44 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) int ret; switch (dm1105dvb->pdev->subsystem_device) { - case PCI_DEVICE_ID_DW2002: + case PCI_DEVICE_ID_DW2004: dm1105dvb->fe = dvb_attach( - stv0299_attach, &sharp_z0194a_config, + cx24116_attach, &serit_sp2633_config, &dm1105dvb->i2c_adap); + if (dm1105dvb->fe) + dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; + break; + default: + dm1105dvb->fe = dvb_attach( + stv0299_attach, &sharp_z0194a_config, + &dm1105dvb->i2c_adap); if (dm1105dvb->fe) { dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60, &dm1105dvb->i2c_adap, DVB_PLL_OPERA1); + break; } - if (!dm1105dvb->fe) { - dm1105dvb->fe = dvb_attach( - stv0288_attach, &earda_config, - &dm1105dvb->i2c_adap); - if (dm1105dvb->fe) { - dm1105dvb->fe->ops.set_voltage = - dm1105dvb_set_voltage; - dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61, - &dm1105dvb->i2c_adap); - } + dm1105dvb->fe = dvb_attach( + stv0288_attach, &earda_config, + &dm1105dvb->i2c_adap); + if (dm1105dvb->fe) { + dm1105dvb->fe->ops.set_voltage = + dm1105dvb_set_voltage; + dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61, + &dm1105dvb->i2c_adap); + break; } - if (!dm1105dvb->fe) { - dm1105dvb->fe = dvb_attach( - si21xx_attach, &serit_config, - &dm1105dvb->i2c_adap); - if (dm1105dvb->fe) - dm1105dvb->fe->ops.set_voltage = - dm1105dvb_set_voltage; - } - break; - case PCI_DEVICE_ID_DW2004: dm1105dvb->fe = dvb_attach( - cx24116_attach, &serit_sp2633_config, + si21xx_attach, &serit_config, &dm1105dvb->i2c_adap); if (dm1105dvb->fe) - dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; - break; + dm1105dvb->fe->ops.set_voltage = + dm1105dvb_set_voltage; + } if (!dm1105dvb->fe) { @@ -662,10 +683,17 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac) static u8 command[1] = { 0x28 }; struct i2c_msg msg[] = { - { .addr = IIC_24C01_addr >> 1, .flags = 0, - .buf = command, .len = 1 }, - { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD, - .buf = mac, .len = 6 }, + { + .addr = IIC_24C01_addr >> 1, + .flags = 0, + .buf = command, + .len = 1 + }, { + .addr = IIC_24C01_addr >> 1, + .flags = I2C_M_RD, + .buf = mac, + .len = 6 + }, }; dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2); @@ -788,14 +816,22 @@ static int __devinit dm1105_probe(struct pci_dev *pdev, #else INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer); #endif + sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num); + dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn); + if (!dm1105dvb->wq) + goto err_dvb_net; ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb); if (ret < 0) - goto err_free_irq; + goto err_workqueue; return 0; +err_workqueue: + destroy_workqueue(dm1105dvb->wq); +err_dvb_net: + dvb_net_release(&dm1105dvb->dvbnet); err_disconnect_frontend: dmx->disconnect_frontend(dmx); err_remove_mem_frontend: @@ -812,8 +848,6 @@ err_i2c_del_adapter: i2c_del_adapter(&dm1105dvb->i2c_adap); err_dm1105dvb_hw_exit: dm1105dvb_hw_exit(dm1105dvb); -err_free_irq: - free_irq(pdev->irq, dm1105dvb); err_pci_iounmap: pci_iounmap(pdev, dm1105dvb->io_mem); err_pci_release_regions: @@ -870,6 +904,11 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_DEVICE_ID_DW2004, }, { + .vendor = PCI_VENDOR_ID_AXESS, + .device = PCI_DEVICE_ID_DM05, + .subvendor = PCI_VENDOR_ID_AXESS, + .subdevice = PCI_DEVICE_ID_DM05, + }, { /* empty */ }, }; diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c index 6d6121eb5..3750ff48c 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.c +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c @@ -430,6 +430,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, /* stop feed but only mark the specified filter as stopped (state set) */ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) { + struct dmxdev_feed *feed; + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); switch (dmxdevfilter->type) { @@ -438,7 +440,8 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); break; case DMXDEV_TYPE_PES: - dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts); + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) + feed->ts->stop_filtering(feed->ts); break; default: return -EINVAL; @@ -449,13 +452,23 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) /* start feed associated with the specified filter */ static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) { + struct dmxdev_feed *feed; + int ret; + dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); switch (filter->type) { case DMXDEV_TYPE_SEC: return filter->feed.sec->start_filtering(filter->feed.sec); case DMXDEV_TYPE_PES: - return filter->feed.ts->start_filtering(filter->feed.ts); + list_for_each_entry(feed, &filter->feed.ts, next) { + ret = feed->ts->start_filtering(feed->ts); + if (ret < 0) { + dvb_dmxdev_feed_stop(filter); + return ret; + } + } + break; default: return -EINVAL; } @@ -487,6 +500,9 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) { + struct dmxdev_feed *feed; + struct dmx_demux *demux; + if (dmxdevfilter->state < DMXDEV_STATE_GO) return 0; @@ -503,13 +519,12 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) dmxdevfilter->feed.sec = NULL; break; case DMXDEV_TYPE_PES: - if (!dmxdevfilter->feed.ts) - break; dvb_dmxdev_feed_stop(dmxdevfilter); - dmxdevfilter->dev->demux-> - release_ts_feed(dmxdevfilter->dev->demux, - dmxdevfilter->feed.ts); - dmxdevfilter->feed.ts = NULL; + demux = dmxdevfilter->dev->demux; + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { + demux->release_ts_feed(demux, feed->ts); + feed->ts = NULL; + } break; default: if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) @@ -521,19 +536,88 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) return 0; } +static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter) +{ + struct dmxdev_feed *feed, *tmp; + + /* delete all PIDs */ + list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) { + list_del(&feed->next); + kfree(feed); + } + + BUG_ON(!list_empty(&dmxdevfilter->feed.ts)); +} + static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) { if (dmxdevfilter->state < DMXDEV_STATE_SET) return 0; + if (dmxdevfilter->type == DMXDEV_TYPE_PES) + dvb_dmxdev_delete_pids(dmxdevfilter); + dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); return 0; } +static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmxdev_feed *feed) +{ + struct timespec timeout = { 0 }; + struct dmx_pes_filter_params *para = &filter->params.pes; + dmx_output_t otype; + int ret; + int ts_type; + enum dmx_ts_pes ts_pes; + struct dmx_ts_feed *tsfeed; + + feed->ts = NULL; + otype = para->output; + + ts_pes = (enum dmx_ts_pes)para->pes_type; + + if (ts_pes < DMX_PES_OTHER) + ts_type = TS_DECODER; + else + ts_type = 0; + + if (otype == DMX_OUT_TS_TAP) + ts_type |= TS_PACKET; + else if (otype == DMX_OUT_TSDEMUX_TAP) + ts_type |= TS_PACKET | TS_DEMUX; + else if (otype == DMX_OUT_TAP) + ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; + + ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts, + dvb_dmxdev_ts_callback); + if (ret < 0) + return ret; + + tsfeed = feed->ts; + tsfeed->priv = filter; + + ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout); + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + + ret = tsfeed->start_filtering(tsfeed); + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + + return 0; +} + static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) { struct dmxdev *dmxdev = filter->dev; + struct dmxdev_feed *feed; void *mem; int ret, i; @@ -631,56 +715,14 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) break; } case DMXDEV_TYPE_PES: - { - struct timespec timeout = { 0 }; - struct dmx_pes_filter_params *para = &filter->params.pes; - dmx_output_t otype; - int ts_type; - enum dmx_ts_pes ts_pes; - struct dmx_ts_feed **tsfeed = &filter->feed.ts; - - filter->feed.ts = NULL; - otype = para->output; - - ts_pes = (enum dmx_ts_pes)para->pes_type; - - if (ts_pes < DMX_PES_OTHER) - ts_type = TS_DECODER; - else - ts_type = 0; - - if (otype == DMX_OUT_TS_TAP) - ts_type |= TS_PACKET; - else if (otype == DMX_OUT_TSDEMUX_TAP) - ts_type |= TS_PACKET | TS_DEMUX; - else if (otype == DMX_OUT_TAP) - ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; - - ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, - tsfeed, - dvb_dmxdev_ts_callback); - if (ret < 0) - return ret; - - (*tsfeed)->priv = filter; - - ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, - 32768, timeout); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, - *tsfeed); - return ret; - } - - ret = filter->feed.ts->start_filtering(filter->feed.ts); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, - *tsfeed); - return ret; + list_for_each_entry(feed, &filter->feed.ts, next) { + ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); + if (ret < 0) { + dvb_dmxdev_filter_stop(filter); + return ret; + } } - break; - } default: return -EINVAL; } @@ -718,7 +760,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file) dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - dmxdevfilter->feed.ts = NULL; + INIT_LIST_HEAD(&dmxdevfilter->feed.ts); init_timer(&dmxdevfilter->timer); dvbdev->users++; @@ -760,6 +802,55 @@ static inline void invert_mode(dmx_filter_t *filter) filter->mode[i] ^= 0xff; } +static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, u16 pid) +{ + struct dmxdev_feed *feed; + + if ((filter->type != DMXDEV_TYPE_PES) || + (filter->state < DMXDEV_STATE_SET)) + return -EINVAL; + + /* only TS packet filters may have multiple PIDs */ + if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) && + (!list_empty(&filter->feed.ts))) + return -EINVAL; + + feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL); + if (feed == NULL) + return -ENOMEM; + + feed->pid = pid; + list_add(&feed->next, &filter->feed.ts); + + if (filter->state >= DMXDEV_STATE_GO) + return dvb_dmxdev_start_feed(dmxdev, filter, feed); + + return 0; +} + +static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, u16 pid) +{ + struct dmxdev_feed *feed, *tmp; + + if ((filter->type != DMXDEV_TYPE_PES) || + (filter->state < DMXDEV_STATE_SET)) + return -EINVAL; + + list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { + if ((feed->pid == pid) && (feed->ts != NULL)) { + feed->ts->stop_filtering(feed->ts); + filter->dev->demux->release_ts_feed(filter->dev->demux, + feed->ts); + list_del(&feed->next); + kfree(feed); + } + } + + return 0; +} + static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_sct_filter_params *params) @@ -784,7 +875,10 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_pes_filter_params *params) { + int ret; + dvb_dmxdev_filter_stop(dmxdevfilter); + dvb_dmxdev_filter_reset(dmxdevfilter); if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) return -EINVAL; @@ -795,6 +889,11 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); + ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, + dmxdevfilter->params.pes.pid); + if (ret < 0) + return ret; + if (params->flags & DMX_IMMEDIATE_START) return dvb_dmxdev_filter_start(dmxdevfilter); @@ -958,6 +1057,24 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, &((struct dmx_stc *)parg)->base); break; + case DMX_ADD_PID: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_REMOVE_PID: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + default: ret = -EINVAL; break; diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.h b/linux/drivers/media/dvb/dvb-core/dmxdev.h index 7e8137d0b..be63783ad 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.h +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.h @@ -54,13 +54,20 @@ enum dmxdev_state { DMXDEV_STATE_TIMEDOUT }; +struct dmxdev_feed { + u16 pid; + struct dmx_ts_feed *ts; + struct list_head next; +}; + struct dmxdev_filter { union { struct dmx_section_filter *sec; } filter; union { - struct dmx_ts_feed *ts; + /* list of TS and PES feeds (struct dmxdev_feed) */ + struct list_head ts; struct dmx_section_feed *sec; } feed; diff --git a/linux/drivers/media/dvb/dvb-core/dvb_demux.c b/linux/drivers/media/dvb/dvb-core/dvb_demux.c index cfe2768d2..eef6d3616 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.c @@ -425,13 +425,9 @@ no_dvb_demux_tscheck: if ((DVR_FEED(feed)) && (dvr_done++)) continue; - if (feed->pid == pid) { + if (feed->pid == pid) dvb_dmx_swfilter_packet_type(feed, buf); - if (DVR_FEED(feed)) - continue; - } - - if (feed->pid == 0x2000) + else if (feed->pid == 0x2000) feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); } } diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c index 5f4856c6d..1eede48a9 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_net.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c @@ -126,7 +126,9 @@ static void hexdump( const unsigned char *buf, unsigned short len ) struct dvb_net_priv { int in_use; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) struct net_device_stats stats; +#endif u16 pid; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) struct net_device *net; @@ -391,8 +393,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_frame_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; +#endif } reset_ule(priv); priv->need_pusi = 1; @@ -445,8 +452,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ // reset_ule(priv); moved to below. +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_frame_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; +#endif } reset_ule(priv); /* skip to next PUSI. */ @@ -467,8 +479,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_frame_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; +#endif } reset_ule(priv); priv->need_pusi = 1; @@ -484,8 +501,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_remain > 183) { /* Current SNDU lacks more data than there could be available in the * current TS cell. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_length_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; +#endif printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); @@ -527,8 +549,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_len < 5) { printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_length_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; +#endif priv->ule_sndu_len = 0; priv->need_pusi = 1; new_ts = 1; @@ -580,7 +607,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_dropped++; +#else + dev->stats.rx_dropped++; +#endif return; } @@ -653,8 +684,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) ule_dump = 1; #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_crc_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_crc_errors++; +#endif dev_kfree_skb(priv->ule_skb); } else { /* CRC32 verified OK. */ @@ -764,8 +800,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * receive the packet anyhow. */ /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) priv->ule_skb->pkt_type = PACKET_HOST; */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_packets++; priv->stats.rx_bytes += priv->ule_skb->len; +#else + dev->stats.rx_packets++; + dev->stats.rx_bytes += priv->ule_skb->len; +#endif netif_rx(priv->ule_skb); } sndu_done: @@ -820,8 +861,12 @@ static void dvb_net_sec(struct net_device *dev, { u8 *eth; struct sk_buff *skb; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) struct net_device_stats *stats = &((struct dvb_net_priv *) netdev_priv(dev))->stats; +#else + struct net_device_stats *stats = &dev->stats; +#endif int snap = 0; /* note: pkt_len includes a 32bit checksum */ @@ -1269,11 +1314,12 @@ static int dvb_net_stop(struct net_device *dev) return dvb_net_feed_stop(dev); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) { return &((struct dvb_net_priv *) netdev_priv(dev))->stats; } - +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) static const struct header_ops dvb_header_ops = { .create = eth_header, @@ -1282,6 +1328,19 @@ static const struct header_ops dvb_header_ops = { }; #endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +static const struct net_device_ops dvb_netdev_ops = { + .ndo_open = dvb_net_open, + .ndo_stop = dvb_net_stop, + .ndo_start_xmit = dvb_net_tx, + .ndo_set_multicast_list = dvb_net_set_multicast_list, + .ndo_set_mac_address = dvb_net_set_mac, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; +#endif + static void dvb_net_setup(struct net_device *dev) { ether_setup(dev); @@ -1291,12 +1350,16 @@ static void dvb_net_setup(struct net_device *dev) #else dev->hard_header_cache = NULL; #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) dev->open = dvb_net_open; dev->stop = dvb_net_stop; dev->hard_start_xmit = dvb_net_tx; dev->get_stats = dvb_net_get_stats; dev->set_multicast_list = dvb_net_set_multicast_list; dev->set_mac_address = dvb_net_set_mac; +#else + dev->netdev_ops = &dvb_netdev_ops; +#endif dev->mtu = 4096; dev->mc_count = 0; diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index 60955a70d..496c1a370 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -216,7 +216,7 @@ config DVB_USB_TTUSB2 help Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver. The firmware protocol used by this module is similar to the one used by the - old ttusb-driver - that's why the module is called dvb-usb-ttusb2.ko. + old ttusb-driver - that's why the module is called dvb-usb-ttusb2. config DVB_USB_DTT200U tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" @@ -261,6 +261,7 @@ config DVB_USB_DW2102 select DVB_STB6000 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_SI21XX if !DVB_FE_CUSTOMISE + select DVB_TDA10021 if !DVB_FE_CUSTOMISE help Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers and the TeVii S650. diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c index a50bf34af..b6fc8ddf3 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9015.c +++ b/linux/drivers/media/dvb/dvb-usb/af9015.c @@ -541,7 +541,7 @@ exit: /* dump eeprom */ static int af9015_eeprom_dump(struct dvb_usb_device *d) { - char buf[52], buf2[4]; + char buf[4+3*16+1], buf2[4]; u8 reg, val; for (reg = 0; ; reg++) { diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index eda025714..8ec98f6e0 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -310,7 +310,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *tun_i2c; tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); return dvb_attach(mt2266_attach, adap->fe, tun_i2c, - &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;; + &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; } /* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */ diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb.h index 8874221c1..f4819c32f 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -197,7 +197,7 @@ struct dvb_usb_device_properties { #define CYPRESS_FX2 3 int usb_ctrl; int (*download_firmware) (struct usb_device *, const struct firmware *); - const char firmware[FIRMWARE_NAME_MAX]; + const char *firmware; int no_reconnect; int size_of_priv; diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.c b/linux/drivers/media/dvb/dvb-usb/dw2102.c index 2b8ee587b..0fc9be43a 100644 --- a/linux/drivers/media/dvb/dvb-usb/dw2102.c +++ b/linux/drivers/media/dvb/dvb-usb/dw2102.c @@ -1,7 +1,7 @@ /* DVB USB framework compliant Linux driver for the -* DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card -* -* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) +* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, +* TeVii S600, S650 Cards +* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by) * * 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 @@ -17,6 +17,7 @@ #include "stb6000.h" #include "eds1547.h" #include "cx24116.h" +#include "tda1002x.h" #ifndef USB_PID_DW2102 #define USB_PID_DW2102 0x2102 @@ -26,10 +27,18 @@ #define USB_PID_DW2104 0x2104 #endif +#ifndef USB_PID_DW3101 +#define USB_PID_DW3101 0x3101 +#endif + #ifndef USB_PID_CINERGY_S #define USB_PID_CINERGY_S 0x0064 #endif +#ifndef USB_PID_TEVII_S650 +#define USB_PID_TEVII_S650 0xd650 +#endif + #define DW210X_READ_MSG 0 #define DW210X_WRITE_MSG 1 @@ -40,18 +49,21 @@ #define DW2102_VOLTAGE_CTRL (0x1800) #define DW2102_RC_QUERY (0x1a00) -struct dw210x_state { - u32 last_key_pressed; -}; -struct dw210x_rc_keys { - u32 keycode; - u32 event; +struct dvb_usb_rc_keys_table { + struct dvb_usb_rc_key *rc_keys; + int rc_keys_size; }; /* debug */ static int dvb_usb_dw2102_debug; module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS); +MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." + DVB_USB_DEBUG_STATUS); + +/* keymaps */ +static int ir_keymap; +module_param_named(keymap, ir_keymap, int, 0644); +MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -79,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { -struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dvb_usb_device *d = i2c_get_adapdata(adap); int i = 0, ret = 0; u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; u16 value; @@ -205,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, mutex_unlock(&d->i2c_mutex); return num; } + static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); @@ -219,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms case 2: { /* read */ /* first write first register number */ - u8 ibuf [msg[1].len + 2], obuf[3]; + u8 ibuf[msg[1].len + 2], obuf[3]; obuf[0] = 0xd0; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; @@ -293,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i case 2: { /* read */ /* first write first register number */ - u8 ibuf [msg[1].len + 2], obuf[3]; + u8 ibuf[msg[1].len + 2], obuf[3]; obuf[0] = 0xaa; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; @@ -360,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i return num; } +static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: { + /* read */ + /* first write first register number */ + u8 ibuf[msg[1].len + 2], obuf[3]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + obuf[2] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + /* second read registers */ + ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, ibuf + 2, msg[1].len); + + break; + } + case 1: + switch (msg[0].addr) { + case 0x60: + case 0x0c: { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = msg[0].addr << 1; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); + break; + } + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); + memcpy(msg[0].buf, ibuf , 2); + break; + } + } + + break; + } + + for (i = 0; i < num; i++) { + deb_xfer("%02x:%02x: %s ", i, msg[i].addr, + msg[i].flags == 0 ? ">>>" : "<<<"); + debug_dump(msg[i].buf, msg[i].len, deb_xfer); + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + static u32 dw210x_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; @@ -397,6 +473,14 @@ static struct i2c_algorithm dw2104_i2c_algo = { #endif }; +static struct i2c_algorithm dw3101_i2c_algo = { + .master_xfer = dw3101_i2c_transfer, + .functionality = dw210x_i2c_func, +#ifdef NEED_ALGO_CONTROL + .algo_control = dummy_algo_control, +#endif +}; + static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) { int i; @@ -416,6 +500,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) debug_dump(eepromline, 16, deb_xfer); } } + memcpy(mac, eeprom + 8, 6); return 0; }; @@ -460,6 +545,11 @@ static struct si21xx_config serit_sp1511lhb_config = { }; +static struct tda10023_config dw3101_tda10023_config = { + .demod_address = 0x0c, + .invert = 1, +}; + static int dw2104_frontend_attach(struct dvb_usb_adapter *d) { if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, @@ -472,6 +562,7 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } static struct dvb_usb_device_properties dw2102_properties; +static struct dvb_usb_device_properties dw2104_properties; static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { @@ -509,6 +600,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) return -EIO; } +static int dw3101_frontend_attach(struct dvb_usb_adapter *d) +{ + d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + &d->dev->i2c_adap, 0x48); + if (d->fe != NULL) { + info("Attached tda10023!\n"); + return 0; + } + return -EIO; +} + static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x60, @@ -524,6 +626,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(dvb_pll_attach, adap->fe, 0x60, + &adap->dev->i2c_adap, DVB_PLL_TUA6034); + + return 0; +} + static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf8, 0x0a, KEY_Q }, /*power*/ { 0xf8, 0x0c, KEY_M }, /*mute*/ @@ -556,44 +666,147 @@ static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf8, 0x40, KEY_F }, /*full*/ { 0xf8, 0x1e, KEY_W }, /*tvmode*/ { 0xf8, 0x1b, KEY_B }, /*recall*/ +}; +static struct dvb_usb_rc_key tevii_rc_keys[] = { + { 0xf8, 0x0a, KEY_POWER }, + { 0xf8, 0x0c, KEY_MUTE }, + { 0xf8, 0x11, KEY_1 }, + { 0xf8, 0x12, KEY_2 }, + { 0xf8, 0x13, KEY_3 }, + { 0xf8, 0x14, KEY_4 }, + { 0xf8, 0x15, KEY_5 }, + { 0xf8, 0x16, KEY_6 }, + { 0xf8, 0x17, KEY_7 }, + { 0xf8, 0x18, KEY_8 }, + { 0xf8, 0x19, KEY_9 }, + { 0xf8, 0x10, KEY_0 }, + { 0xf8, 0x1c, KEY_MENU }, + { 0xf8, 0x0f, KEY_VOLUMEDOWN }, + { 0xf8, 0x1a, KEY_LAST }, + { 0xf8, 0x0e, KEY_OPEN }, + { 0xf8, 0x04, KEY_RECORD }, + { 0xf8, 0x09, KEY_VOLUMEUP }, + { 0xf8, 0x08, KEY_CHANNELUP }, + { 0xf8, 0x07, KEY_PVR }, + { 0xf8, 0x0b, KEY_TIME }, + { 0xf8, 0x02, KEY_RIGHT }, + { 0xf8, 0x03, KEY_LEFT }, + { 0xf8, 0x00, KEY_UP }, + { 0xf8, 0x1f, KEY_OK }, + { 0xf8, 0x01, KEY_DOWN }, + { 0xf8, 0x05, KEY_TUNER }, + { 0xf8, 0x06, KEY_CHANNELDOWN }, + { 0xf8, 0x40, KEY_PLAYPAUSE }, + { 0xf8, 0x1e, KEY_REWIND }, + { 0xf8, 0x1b, KEY_FAVORITES }, + { 0xf8, 0x1d, KEY_BACK }, + { 0xf8, 0x4d, KEY_FASTFORWARD }, + { 0xf8, 0x44, KEY_EPG }, + { 0xf8, 0x4c, KEY_INFO }, + { 0xf8, 0x41, KEY_AB }, + { 0xf8, 0x43, KEY_AUDIO }, + { 0xf8, 0x45, KEY_SUBTITLE }, + { 0xf8, 0x4a, KEY_LIST }, + { 0xf8, 0x46, KEY_F1 }, + { 0xf8, 0x47, KEY_F2 }, + { 0xf8, 0x5e, KEY_F3 }, + { 0xf8, 0x5c, KEY_F4 }, + { 0xf8, 0x52, KEY_F5 }, + { 0xf8, 0x5a, KEY_F6 }, + { 0xf8, 0x56, KEY_MODE }, + { 0xf8, 0x58, KEY_SWITCHVIDEOMODE }, }; +static struct dvb_usb_rc_key tbs_rc_keys[] = { + { 0xf8, 0x84, KEY_POWER }, + { 0xf8, 0x94, KEY_MUTE }, + { 0xf8, 0x87, KEY_1 }, + { 0xf8, 0x86, KEY_2 }, + { 0xf8, 0x85, KEY_3 }, + { 0xf8, 0x8b, KEY_4 }, + { 0xf8, 0x8a, KEY_5 }, + { 0xf8, 0x89, KEY_6 }, + { 0xf8, 0x8f, KEY_7 }, + { 0xf8, 0x8e, KEY_8 }, + { 0xf8, 0x8d, KEY_9 }, + { 0xf8, 0x92, KEY_0 }, + { 0xf8, 0x96, KEY_CHANNELUP }, + { 0xf8, 0x91, KEY_CHANNELDOWN }, + { 0xf8, 0x93, KEY_VOLUMEUP }, + { 0xf8, 0x8c, KEY_VOLUMEDOWN }, + { 0xf8, 0x83, KEY_RECORD }, + { 0xf8, 0x98, KEY_PAUSE }, + { 0xf8, 0x99, KEY_OK }, + { 0xf8, 0x9a, KEY_SHUFFLE }, + { 0xf8, 0x81, KEY_UP }, + { 0xf8, 0x90, KEY_LEFT }, + { 0xf8, 0x82, KEY_RIGHT }, + { 0xf8, 0x88, KEY_DOWN }, + { 0xf8, 0x95, KEY_FAVORITES }, + { 0xf8, 0x97, KEY_SUBTITLE }, + { 0xf8, 0x9d, KEY_ZOOM }, + { 0xf8, 0x9f, KEY_EXIT }, + { 0xf8, 0x9e, KEY_MENU }, + { 0xf8, 0x9c, KEY_EPG }, + { 0xf8, 0x80, KEY_PREVIOUS }, + { 0xf8, 0x9b, KEY_MODE } +}; +static struct dvb_usb_rc_keys_table keys_tables[] = { + { dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) }, + { tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) }, + { tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) }, +}; static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { - struct dw210x_state *st = d->priv; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + int keymap_size = d->props.rc_key_map_size; u8 key[2]; - struct i2c_msg msg[] = { - {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key, - .len = 2}, + struct i2c_msg msg = { + .addr = DW2102_RC_QUERY, + .flags = I2C_M_RD, + .buf = key, + .len = 2 }; int i; + /* override keymap */ + if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { + keymap = keys_tables[ir_keymap - 1].rc_keys ; + keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; + } *state = REMOTE_NO_KEY_PRESSED; - if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { - for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) { - if (dw210x_rc_keys[i].data == msg[0].buf[0]) { + if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) { + for (i = 0; i < keymap_size ; i++) { + if (keymap[i].data == msg.buf[0]) { *state = REMOTE_KEY_PRESSED; - *event = dw210x_rc_keys[i].event; - st->last_key_pressed = - dw210x_rc_keys[i].event; + *event = keymap[i].event; break; } - st->last_key_pressed = 0; + } + + if ((*state) == REMOTE_KEY_PRESSED) + deb_rc("%s: found rc key: %x, %x, event: %x\n", + __func__, key[0], key[1], (*event)); + else if (key[0] != 0xff) + deb_rc("%s: unknown rc key: %x, %x\n", + __func__, key[0], key[1]); + } - /* info("key: %x %x\n",key[0],key[1]); */ + return 0; } static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, - {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, - {USB_DEVICE(0x9022, 0xd650)}, + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, + {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, { } }; @@ -654,11 +867,16 @@ static int dw2102_load_firmware(struct usb_device *dev, } /* init registers */ switch (dev->descriptor.idProduct) { + case USB_PID_TEVII_S650: + dw2104_properties.rc_key_map = tevii_rc_keys; + dw2104_properties.rc_key_map_size = + ARRAY_SIZE(tevii_rc_keys); case USB_PID_DW2104: - case 0xd650: reset = 1; dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, DW210X_WRITE_MSG); + /* break omitted intentionally */ + case USB_PID_DW3101: reset = 0; dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); @@ -702,6 +920,7 @@ static int dw2102_load_firmware(struct usb_device *dev, DW210X_READ_MSG); break; } + msleep(100); kfree(p); } @@ -712,7 +931,6 @@ static struct dvb_usb_device_properties dw2102_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-dw2102.fw", - .size_of_priv = sizeof(struct dw210x_state), .no_reconnect = 1, .i2c_algo = &dw2102_serit_i2c_algo, @@ -726,7 +944,7 @@ static struct dvb_usb_device_properties dw2102_properties = { .num_adapters = 1, .download_firmware = dw2102_load_firmware, .read_mac_address = dw210x_read_mac_address, - .adapter = { + .adapter = { { .frontend_attach = dw2102_frontend_attach, .streaming_ctrl = NULL, @@ -764,7 +982,6 @@ static struct dvb_usb_device_properties dw2104_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-dw2104.fw", - .size_of_priv = sizeof(struct dw210x_state), .no_reconnect = 1, .i2c_algo = &dw2104_i2c_algo, @@ -808,12 +1025,57 @@ static struct dvb_usb_device_properties dw2104_properties = { } }; +static struct dvb_usb_device_properties dw3101_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-dw3101.fw", + .no_reconnect = 1, + + .i2c_algo = &dw3101_i2c_algo, + .rc_key_map = dw210x_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + + .generic_bulk_ctrl_endpoint = 0x81, + /* parameter for the MPEG2-data transfer */ + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = dw210x_read_mac_address, + .adapter = { + { + .frontend_attach = dw3101_frontend_attach, + .streaming_ctrl = NULL, + .tuner_attach = dw3101_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 1, + .devices = { + { "DVBWorld DVB-C 3101 USB2.0", + {&dw2102_table[5], NULL}, + {NULL}, + }, + } +}; + static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { if (0 == dvb_usb_device_init(intf, &dw2102_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &dw2104_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &dw3101_properties, THIS_MODULE, NULL, adapter_nr)) { return 0; } @@ -845,6 +1107,8 @@ module_init(dw2102_module_init); module_exit(dw2102_module_exit); MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); -MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device"); +MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," + " DVB-C 3101 USB2.0," + " TeVii S600, S650 USB2.0 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.h b/linux/drivers/media/dvb/dvb-usb/dw2102.h index e3370734e..5cd0b0eb6 100644 --- a/linux/drivers/media/dvb/dvb-usb/dw2102.h +++ b/linux/drivers/media/dvb/dvb-usb/dw2102.h @@ -5,4 +5,5 @@ #include "dvb-usb.h" #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) +#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args) #endif diff --git a/linux/drivers/media/dvb/frontends/af9013.c b/linux/drivers/media/dvb/frontends/af9013.c index d12d99802..62d3185ee 100644 --- a/linux/drivers/media/dvb/frontends/af9013.c +++ b/linux/drivers/media/dvb/frontends/af9013.c @@ -528,6 +528,10 @@ static int af9013_set_ofdm_params(struct af9013_state *state, u8 i, buf[3] = {0, 0, 0}; *auto_mode = 0; /* set if parameters are requested to auto set */ + /* Try auto-detect transmission parameters in case of AUTO requested or + garbage parameters given by application for compatibility. + MPlayer seems to provide garbage parameters currently. */ + switch (params->transmission_mode) { case TRANSMISSION_MODE_AUTO: *auto_mode = 1; @@ -537,7 +541,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (1 << 0); break; default: - return -EINVAL; + deb_info("%s: invalid transmission_mode\n", __func__); + *auto_mode = 1; } switch (params->guard_interval) { @@ -555,7 +560,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 2); break; default: - return -EINVAL; + deb_info("%s: invalid guard_interval\n", __func__); + *auto_mode = 1; } switch (params->hierarchy_information) { @@ -573,7 +579,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 4); break; default: - return -EINVAL; + deb_info("%s: invalid hierarchy_information\n", __func__); + *auto_mode = 1; }; switch (params->constellation) { @@ -588,7 +595,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[1] |= (2 << 6); break; default: - return -EINVAL; + deb_info("%s: invalid constellation\n", __func__); + *auto_mode = 1; } /* Use HP. How and which case we can switch to LP? */ @@ -612,7 +620,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[2] |= (4 << 0); break; default: - return -EINVAL; + deb_info("%s: invalid code_rate_HP\n", __func__); + *auto_mode = 1; } switch (params->code_rate_LP) { @@ -639,7 +648,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, if (params->hierarchy_information == HIERARCHY_AUTO) break; default: - return -EINVAL; + deb_info("%s: invalid code_rate_LP\n", __func__); + *auto_mode = 1; } switch (params->bandwidth) { @@ -652,7 +662,8 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[1] |= (2 << 2); break; default: - return -EINVAL; + deb_info("%s: invalid bandwidth\n", __func__); + buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */ } /* program */ diff --git a/linux/drivers/media/dvb/frontends/au8522_dig.c b/linux/drivers/media/dvb/frontends/au8522_dig.c index 41aedcc99..9375905ee 100644 --- a/linux/drivers/media/dvb/frontends/au8522_dig.c +++ b/linux/drivers/media/dvb/frontends/au8522_dig.c @@ -367,11 +367,90 @@ static struct { { 0x8231, 0x13 }, }; -/* QAM Modulation table */ +/* QAM64 Modulation table */ static struct { u16 reg; u16 data; -} QAM_mod_tab[] = { +} QAM64_mod_tab[] = { + { 0x00a3, 0x09 }, + { 0x00a4, 0x00 }, + { 0x0081, 0xc4 }, + { 0x00a5, 0x40 }, + { 0x00aa, 0x77 }, + { 0x00ad, 0x77 }, + { 0x00a6, 0x67 }, + { 0x0262, 0x20 }, + { 0x021c, 0x30 }, + { 0x00b8, 0x3e }, + { 0x00b9, 0xf0 }, + { 0x00ba, 0x01 }, + { 0x00bb, 0x18 }, + { 0x00bc, 0x50 }, + { 0x00bd, 0x00 }, + { 0x00be, 0xea }, + { 0x00bf, 0xef }, + { 0x00c0, 0xfc }, + { 0x00c1, 0xbd }, + { 0x00c2, 0x1f }, + { 0x00c3, 0xfc }, + { 0x00c4, 0xdd }, + { 0x00c5, 0xaf }, + { 0x00c6, 0x00 }, + { 0x00c7, 0x38 }, + { 0x00c8, 0x30 }, + { 0x00c9, 0x05 }, + { 0x00ca, 0x4a }, + { 0x00cb, 0xd0 }, + { 0x00cc, 0x01 }, + { 0x00cd, 0xd9 }, + { 0x00ce, 0x6f }, + { 0x00cf, 0xf9 }, + { 0x00d0, 0x70 }, + { 0x00d1, 0xdf }, + { 0x00d2, 0xf7 }, + { 0x00d3, 0xc2 }, + { 0x00d4, 0xdf }, + { 0x00d5, 0x02 }, + { 0x00d6, 0x9a }, + { 0x00d7, 0xd0 }, + { 0x0250, 0x0d }, + { 0x0251, 0xcd }, + { 0x0252, 0xe0 }, + { 0x0253, 0x05 }, + { 0x0254, 0xa7 }, + { 0x0255, 0xff }, + { 0x0256, 0xed }, + { 0x0257, 0x5b }, + { 0x0258, 0xae }, + { 0x0259, 0xe6 }, + { 0x025a, 0x3d }, + { 0x025b, 0x0f }, + { 0x025c, 0x0d }, + { 0x025d, 0xea }, + { 0x025e, 0xf2 }, + { 0x025f, 0x51 }, + { 0x0260, 0xf5 }, + { 0x0261, 0x06 }, + { 0x021a, 0x00 }, + { 0x0546, 0x40 }, + { 0x0210, 0xc7 }, + { 0x0211, 0xaa }, + { 0x0212, 0xab }, + { 0x0213, 0x02 }, + { 0x0502, 0x00 }, + { 0x0121, 0x04 }, + { 0x0122, 0x04 }, + { 0x052e, 0x10 }, + { 0x00a4, 0xca }, + { 0x00a7, 0x40 }, + { 0x0526, 0x01 }, +}; + +/* QAM256 Modulation table */ +static struct { + u16 reg; + u16 data; +} QAM256_mod_tab[] = { { 0x80a3, 0x09 }, { 0x80a4, 0x00 }, { 0x8081, 0xc4 }, @@ -464,12 +543,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_set_if(fe, state->config->vsb_if); break; case QAM_64: + dprintk("%s() QAM 64\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++) + au8522_writereg(state, + QAM64_mod_tab[i].reg, + QAM64_mod_tab[i].data); + au8522_set_if(fe, state->config->qam_if); + break; case QAM_256: - dprintk("%s() QAM 64/256\n", __func__); - for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++) + dprintk("%s() QAM 256\n", __func__); + for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++) au8522_writereg(state, - QAM_mod_tab[i].reg, - QAM_mod_tab[i].data); + QAM256_mod_tab[i].reg, + QAM256_mod_tab[i].data); au8522_set_if(fe, state->config->qam_if); break; default: diff --git a/linux/drivers/media/dvb/frontends/cx24123.c b/linux/drivers/media/dvb/frontends/cx24123.c index f431f0c56..5fdc81b53 100644 --- a/linux/drivers/media/dvb/frontends/cx24123.c +++ b/linux/drivers/media/dvb/frontends/cx24123.c @@ -470,7 +470,7 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) /* check if symbol rate is within limits */ if ((srate > state->frontend.ops.info.symbol_rate_max) || (srate < state->frontend.ops.info.symbol_rate_min)) - return -EOPNOTSUPP;; + return -EOPNOTSUPP; /* choose the sampling rate high enough for the required operation, while optimizing the power consumed by the demodulator */ diff --git a/linux/drivers/media/dvb/frontends/dib0070.c b/linux/drivers/media/dvb/frontends/dib0070.c index e9fab2d3e..7dd131fb3 100644 --- a/linux/drivers/media/dvb/frontends/dib0070.c +++ b/linux/drivers/media/dvb/frontends/dib0070.c @@ -168,7 +168,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par break; case BAND_SBAND: LO4_SET_VCO_HFDIV(lo4, 0, 0); - LO4_SET_CTRIM(lo4, 1);; + LO4_SET_CTRIM(lo4, 1); c = 1; break; case BAND_UHF: diff --git a/linux/drivers/media/dvb/frontends/lgs8gxx.c b/linux/drivers/media/dvb/frontends/lgs8gxx.c index 1395f3b5b..226536ae0 100644 --- a/linux/drivers/media/dvb/frontends/lgs8gxx.c +++ b/linux/drivers/media/dvb/frontends/lgs8gxx.c @@ -1,9 +1,9 @@ /* - * Support for Legend Silicon DMB-TH demodulator - * LGS8913, LGS8GL5 + * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator + * LGS8913, LGS8GL5, LGS8G75 * experimental support LGS8G42, LGS8G52 * - * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com> + * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com> * Copyright (C) 2008 Sirius International (Hong Kong) Limited * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5) * @@ -37,14 +37,50 @@ } while (0) static int debug; -static int fake_signal_str; +static int fake_signal_str = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); module_param(fake_signal_str, int, 0644); MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913." -"Signal strength calculation is slow.(default:off)."); +"Signal strength calculation is slow.(default:on)."); + +static const u8 lgs8g75_initdat[] = { + 0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5, + 0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50, + 0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5, + 0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01, + 0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90, + 0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23, + 0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90, + 0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D, + 0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60, + 0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12, + 0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD, + 0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60, + 0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12, + 0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B, + 0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60, + 0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74, + 0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74, + 0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2, + 0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09, + 0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00, + 0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90, + 0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08, + 0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, + 0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80, + 0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80, + 0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22 +}; /* LGS8GXX internal helper functions */ @@ -55,7 +91,7 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data) struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; msg.addr = priv->config->demod_address; - if (reg >= 0xC0) + if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0) msg.addr += 0x02; if (debug >= 2) @@ -84,7 +120,7 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data) }; dev_addr = priv->config->demod_address; - if (reg >= 0xC0) + if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0) dev_addr += 0x02; msg[1].addr = msg[0].addr = dev_addr; @@ -112,19 +148,36 @@ static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv) return 0; } +static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask, + u8 val, u8 delay, u8 tries) +{ + u8 t; + int i; + + for (i = 0; i < tries; i++) { + lgs8gxx_read_reg(priv, reg, &t); + + if ((t & mask) == val) + return 0; + msleep(delay); + } + + return 1; +} + static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv) { const struct lgs8gxx_config *config = priv->config; u8 if_conf; - if_conf = 0x10; /* AGC output on; */ + if_conf = 0x10; /* AGC output on, RF_AGC output off; */ if_conf |= ((config->ext_adc) ? 0x80 : 0x00) | ((config->if_neg_center) ? 0x04 : 0x00) | ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */ - ((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) | - ((config->ext_adc && config->if_neg_edge) ? 0x01 : 0x00); + ((config->adc_signed) ? 0x02 : 0x00) | + ((config->if_neg_edge) ? 0x01 : 0x00); if (config->ext_adc && (config->prod == LGS8GXX_PROD_LGS8G52)) { @@ -157,39 +210,82 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/) } dprintk("AFC_INIT_FREQ = 0x%08X\n", v32); - lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32)); - lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8)); - lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16)); - lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24)); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32)); + lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8)); + lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16)); + lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24)); + } else { + lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32)); + lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8)); + lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16)); + lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24)); + } return 0; } +static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv) +{ + u64 val; + u32 v32 = 0; + u8 reg_addr, t; + int i; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + reg_addr = 0x23; + else + reg_addr = 0x48; + + for (i = 0; i < 4; i++) { + lgs8gxx_read_reg(priv, reg_addr, &t); + v32 <<= 8; + v32 |= t; + reg_addr--; + } + + val = v32; + val *= priv->config->if_clk_freq; + val /= (u64)1 << 32; + dprintk("AFC = %u kHz\n", (u32)val); + return 0; +} + static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv) { u8 t; + u8 prod = priv->config->prod; - if (priv->config->prod == LGS8GXX_PROD_LGS8913) + if (prod == LGS8GXX_PROD_LGS8913) lgs8gxx_write_reg(priv, 0xC6, 0x01); - lgs8gxx_read_reg(priv, 0x7E, &t); - lgs8gxx_write_reg(priv, 0x7E, t | 0x01); - - /* clear FEC self reset */ - lgs8gxx_read_reg(priv, 0xC5, &t); - lgs8gxx_write_reg(priv, 0xC5, t & 0xE0); + if (prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x0C, &t); + t &= (~0x04); + lgs8gxx_write_reg(priv, 0x0C, t | 0x80); + lgs8gxx_write_reg(priv, 0x39, 0x00); + lgs8gxx_write_reg(priv, 0x3D, 0x04); + } else if (prod == LGS8GXX_PROD_LGS8913 || + prod == LGS8GXX_PROD_LGS8GL5 || + prod == LGS8GXX_PROD_LGS8G42 || + prod == LGS8GXX_PROD_LGS8G52 || + prod == LGS8GXX_PROD_LGS8G54) { + lgs8gxx_read_reg(priv, 0x7E, &t); + lgs8gxx_write_reg(priv, 0x7E, t | 0x01); + + /* clear FEC self reset */ + lgs8gxx_read_reg(priv, 0xC5, &t); + lgs8gxx_write_reg(priv, 0xC5, t & 0xE0); + } - if (priv->config->prod == LGS8GXX_PROD_LGS8913) { + if (prod == LGS8GXX_PROD_LGS8913) { /* FEC auto detect */ lgs8gxx_write_reg(priv, 0xC1, 0x03); lgs8gxx_read_reg(priv, 0x7C, &t); t = (t & 0x8C) | 0x03; lgs8gxx_write_reg(priv, 0x7C, t); - } - - if (priv->config->prod == LGS8GXX_PROD_LGS8913) { /* BER test mode */ lgs8gxx_read_reg(priv, 0xC3, &t); t = (t & 0xEF) | 0x10; @@ -207,6 +303,32 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv) int ret = 0; u8 t; + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + u8 t2; + lgs8gxx_read_reg(priv, 0x0C, &t); + t &= (~0x80); + lgs8gxx_write_reg(priv, 0x0C, t); + + lgs8gxx_read_reg(priv, 0x0C, &t); + lgs8gxx_read_reg(priv, 0x19, &t2); + + if (((t&0x03) == 0x01) && (t2&0x01)) { + lgs8gxx_write_reg(priv, 0x6E, 0x05); + lgs8gxx_write_reg(priv, 0x39, 0x02); + lgs8gxx_write_reg(priv, 0x39, 0x03); + lgs8gxx_write_reg(priv, 0x3D, 0x05); + lgs8gxx_write_reg(priv, 0x3E, 0x28); + lgs8gxx_write_reg(priv, 0x53, 0x80); + } else { + lgs8gxx_write_reg(priv, 0x6E, 0x3F); + lgs8gxx_write_reg(priv, 0x39, 0x00); + lgs8gxx_write_reg(priv, 0x3D, 0x04); + } + + lgs8gxx_soft_reset(priv); + return 0; + } + /* turn off auto-detect; manual settings */ lgs8gxx_write_reg(priv, 0x7E, 0); if (priv->config->prod == LGS8GXX_PROD_LGS8913) @@ -226,11 +348,39 @@ static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked) int ret = 0; u8 t; - ret = lgs8gxx_read_reg(priv, 0x4B, &t); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + ret = lgs8gxx_read_reg(priv, 0x13, &t); + else + ret = lgs8gxx_read_reg(priv, 0x4B, &t); if (ret != 0) return ret; - *locked = ((t & 0xC0) == 0xC0) ? 1 : 0; + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + *locked = ((t & 0x80) == 0x80) ? 1 : 0; + else + *locked = ((t & 0xC0) == 0xC0) ? 1 : 0; + return 0; +} + +/* Wait for Code Acquisition Lock */ +static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked) +{ + int ret = 0; + u8 reg, mask, val; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + reg = 0x13; + mask = 0x80; + val = 0x80; + } else { + reg = 0x4B; + mask = 0xC0; + val = 0xC0; + } + + ret = wait_reg_mask(priv, reg, mask, val, 50, 40); + *locked = (ret == 0) ? 1 : 0; + return 0; } @@ -238,21 +388,30 @@ static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv, u8 *finished) { int ret = 0; - u8 t; + u8 reg, mask, val; - ret = lgs8gxx_read_reg(priv, 0xA4, &t); - if (ret != 0) - return ret; + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + reg = 0x1f; + mask = 0xC0; + val = 0x80; + } else { + reg = 0xA4; + mask = 0x03; + val = 0x01; + } - *finished = ((t & 0x3) == 0x1) ? 1 : 0; + ret = wait_reg_mask(priv, reg, mask, val, 10, 20); + *finished = (ret == 0) ? 1 : 0; return 0; } -static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked) +static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn, + u8 *locked) { - int err; + int err = 0; u8 ad_fini = 0; + u8 t1, t2; if (gi == GI_945) dprintk("try GI 945\n"); @@ -260,17 +419,29 @@ static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked) dprintk("try GI 595\n"); else if (gi == GI_420) dprintk("try GI 420\n"); - lgs8gxx_write_reg(priv, 0x04, gi); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x0C, &t1); + lgs8gxx_read_reg(priv, 0x18, &t2); + t1 &= ~(GI_MASK); + t1 |= gi; + t2 &= 0xFE; + t2 |= cpn ? 0x01 : 0x00; + lgs8gxx_write_reg(priv, 0x0C, t1); + lgs8gxx_write_reg(priv, 0x18, t2); + } else { + lgs8gxx_write_reg(priv, 0x04, gi); + } lgs8gxx_soft_reset(priv); - msleep(50); + err = lgs8gxx_wait_ca_lock(priv, locked); + if (err || !(*locked)) + return err; err = lgs8gxx_is_autodetect_finished(priv, &ad_fini); if (err != 0) return err; if (ad_fini) { - err = lgs8gxx_is_locked(priv, locked); - if (err != 0) - return err; - } + dprintk("auto detect finished\n"); + } else + *locked = 0; return 0; } @@ -285,13 +456,18 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv, dprintk("%s\n", __func__); lgs8gxx_set_mode_auto(priv); - /* Guard Interval */ - lgs8gxx_write_reg(priv, 0x03, 00); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_write_reg(priv, 0x67, 0xAA); + lgs8gxx_write_reg(priv, 0x6E, 0x3F); + } else { + /* Guard Interval */ + lgs8gxx_write_reg(priv, 0x03, 00); + } for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { tmp_gi = GI_945; - err = lgs8gxx_autolock_gi(priv, GI_945, &locked); + err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked); if (err) goto out; if (locked) @@ -299,14 +475,14 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv, } for (j = 0; j < 2; j++) { tmp_gi = GI_420; - err = lgs8gxx_autolock_gi(priv, GI_420, &locked); + err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked); if (err) goto out; if (locked) goto locked; } tmp_gi = GI_595; - err = lgs8gxx_autolock_gi(priv, GI_595, &locked); + err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked); if (err) goto out; if (locked) @@ -317,8 +493,13 @@ locked: if ((err == 0) && (locked == 1)) { u8 t; - lgs8gxx_read_reg(priv, 0xA2, &t); - *detected_param = t; + if (priv->config->prod != LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0xA2, &t); + *detected_param = t; + } else { + lgs8gxx_read_reg(priv, 0x1F, &t); + *detected_param = t & 0x3F; + } if (tmp_gi == GI_945) dprintk("GI 945 locked\n"); @@ -349,18 +530,28 @@ static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv) lgs8gxx_write_reg(priv, 0x03, 0x01); #endif dprintk("lgs8gxx_auto_detect failed\n"); - } + } else + dprintk("detected param = 0x%02X\n", detected_param); /* Apply detected parameters */ if (priv->config->prod == LGS8GXX_PROD_LGS8913) { u8 inter_leave_len = detected_param & TIM_MASK ; - inter_leave_len = (inter_leave_len == TIM_LONG) ? 0x60 : 0x40; + /* Fix 8913 time interleaver detection bug */ + inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40; detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK; detected_param |= inter_leave_len; } - lgs8gxx_write_reg(priv, 0x7D, detected_param); - if (priv->config->prod == LGS8GXX_PROD_LGS8913) - lgs8gxx_write_reg(priv, 0xC0, detected_param); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + u8 t; + lgs8gxx_read_reg(priv, 0x19, &t); + t &= 0x81; + t |= detected_param << 1; + lgs8gxx_write_reg(priv, 0x19, t); + } else { + lgs8gxx_write_reg(priv, 0x7D, detected_param); + if (priv->config->prod == LGS8GXX_PROD_LGS8913) + lgs8gxx_write_reg(priv, 0xC0, detected_param); + } /* lgs8gxx_soft_reset(priv); */ /* Enter manual mode */ @@ -382,9 +573,10 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv, u8 serial, u8 clk_pol, u8 clk_gated) { int ret = 0; - u8 t; + u8 t, reg_addr; - ret = lgs8gxx_read_reg(priv, 0xC2, &t); + reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2; + ret = lgs8gxx_read_reg(priv, reg_addr, &t); if (ret != 0) return ret; @@ -393,13 +585,29 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv, t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL; t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN; - ret = lgs8gxx_write_reg(priv, 0xC2, t); + ret = lgs8gxx_write_reg(priv, reg_addr, t); if (ret != 0) return ret; return 0; } +/* A/D input peak-to-peak voltage range */ +static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv, + u8 sel) +{ + u8 r26 = 0x73, r27 = 0x90; + + if (priv->config->prod != LGS8GXX_PROD_LGS8G75) + return 0; + + r26 |= (sel & 0x01) << 7; + r27 |= (sel & 0x02) >> 1; + lgs8gxx_write_reg(priv, 0x26, r26); + lgs8gxx_write_reg(priv, 0x27, r27); + + return 0; +} /* LGS8913 demod frontend functions */ @@ -428,6 +636,34 @@ static int lgs8913_init(struct lgs8gxx_state *priv) return 0; } +static int lgs8g75_init_data(struct lgs8gxx_state *priv) +{ + const u8 *p = lgs8g75_initdat; + int i; + + lgs8gxx_write_reg(priv, 0xC6, 0x40); + + lgs8gxx_write_reg(priv, 0x3D, 0x04); + lgs8gxx_write_reg(priv, 0x39, 0x00); + + lgs8gxx_write_reg(priv, 0x3A, 0x00); + lgs8gxx_write_reg(priv, 0x38, 0x00); + lgs8gxx_write_reg(priv, 0x3B, 0x00); + lgs8gxx_write_reg(priv, 0x38, 0x00); + + for (i = 0; i < sizeof(lgs8g75_initdat); i++) { + lgs8gxx_write_reg(priv, 0x38, 0x00); + lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff)); + lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8)); + lgs8gxx_write_reg(priv, 0x3C, *p); + p++; + } + + lgs8gxx_write_reg(priv, 0x38, 0x00); + + return 0; +} + static int lgs8gxx_init(struct dvb_frontend *fe) { struct lgs8gxx_state *priv = @@ -440,6 +676,9 @@ static int lgs8gxx_init(struct dvb_frontend *fe) lgs8gxx_read_reg(priv, 0, &data); dprintk("reg 0 = 0x%02X\n", data); + if (config->prod == LGS8GXX_PROD_LGS8G75) + lgs8g75_set_adc_vpp(priv, config->adc_vpp); + /* Setup MPEG output format */ err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts, config->ts_clk_pol, @@ -450,8 +689,7 @@ static int lgs8gxx_init(struct dvb_frontend *fe) if (config->prod == LGS8GXX_PROD_LGS8913) lgs8913_init(priv); lgs8gxx_set_if_freq(priv, priv->config->if_freq); - if (config->prod != LGS8GXX_PROD_LGS8913) - lgs8gxx_set_ad_mode(priv); + lgs8gxx_set_ad_mode(priv); return 0; } @@ -508,12 +746,6 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe, static int lgs8gxx_get_fe(struct dvb_frontend *fe, struct dvb_frontend_parameters *fe_params) { - struct lgs8gxx_state *priv = fe->demodulator_priv; - u8 t; -#if 0 - int translated_fec = FEC_1_2; -#endif - dprintk("%s\n", __func__); /* TODO: get real readings from device */ @@ -523,47 +755,10 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe, /* bandwidth */ fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - - lgs8gxx_read_reg(priv, 0x7D, &t); -#if 0 - /* FEC. No exact match for DMB-TH, pick approx. value */ - switch (t & LGS_FEC_MASK) { - case LGS_FEC_0_4: /* FEC 0.4 */ - translated_fec = FEC_1_2; - break; - case LGS_FEC_0_6: /* FEC 0.6 */ - translated_fec = FEC_2_3; - break; - case LGS_FEC_0_8: /* FEC 0.8 */ - translated_fec = FEC_5_6; - break; - default: - translated_fec = FEC_1_2; - } - fe_params->u.ofdm.code_rate_HP = translated_fec; - fe_params->u.ofdm.code_rate_LP = translated_fec; -#endif fe_params->u.ofdm.code_rate_HP = FEC_AUTO; fe_params->u.ofdm.code_rate_LP = FEC_AUTO; - /* constellation */ - switch (t & SC_MASK) { - case SC_QAM64: - fe_params->u.ofdm.constellation = QAM_64; - break; - case SC_QAM32: - fe_params->u.ofdm.constellation = QAM_32; - break; - case SC_QAM16: - fe_params->u.ofdm.constellation = QAM_16; - break; - case SC_QAM4: - case SC_QAM4NR: - fe_params->u.ofdm.constellation = QPSK; - break; - default: - fe_params->u.ofdm.constellation = QAM_64; - } + fe_params->u.ofdm.constellation = QAM_AUTO; /* transmission mode */ fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; @@ -592,9 +787,19 @@ static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status) { struct lgs8gxx_state *priv = fe->demodulator_priv; s8 ret; - u8 t; + u8 t, locked = 0; dprintk("%s\n", __func__); + *fe_status = 0; + + lgs8gxx_get_afc_phase(priv); + lgs8gxx_is_locked(priv, &locked); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + if (locked) + *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + return 0; + } ret = lgs8gxx_read_reg(priv, 0x4B, &t); if (ret != 0) @@ -650,7 +855,7 @@ static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal) else cat = 0; - *signal = cat; + *signal = cat * 65535 / 5; return 0; } @@ -670,8 +875,8 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) if (fake_signal_str) { if ((t & 0xC0) == 0xC0) { - dprintk("Fake signal strength as 50\n"); - *signal = 0x32; + dprintk("Fake signal strength\n"); + *signal = 0x7FFF; } else *signal = 0; return 0; @@ -698,12 +903,33 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) return 0; } +static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal) +{ + u8 t; + s16 v = 0; + + dprintk("%s\n", __func__); + + lgs8gxx_read_reg(priv, 0xB1, &t); + v |= t; + v <<= 8; + lgs8gxx_read_reg(priv, 0xB0, &t); + v |= t; + + *signal = v; + dprintk("%s: signal=0x%02X\n", __func__, *signal); + + return 0; +} + static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal) { struct lgs8gxx_state *priv = fe->demodulator_priv; if (priv->config->prod == LGS8GXX_PROD_LGS8913) return lgs8913_read_signal_strength(priv, signal); + else if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + return lgs8g75_read_signal_strength(priv, signal); else return lgs8gxx_read_signal_agc(priv, signal); } @@ -714,7 +940,10 @@ static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr) u8 t; *snr = 0; - lgs8gxx_read_reg(priv, 0x95, &t); + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) + lgs8gxx_read_reg(priv, 0x34, &t); + else + lgs8gxx_read_reg(priv, 0x95, &t); dprintk("AVG Noise=0x%02X\n", t); *snr = 256 - t; *snr <<= 8; @@ -730,31 +959,68 @@ static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } +static void packet_counter_start(struct lgs8gxx_state *priv) +{ + u8 orig, t; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x30, &orig); + orig &= 0xE7; + t = orig | 0x10; + lgs8gxx_write_reg(priv, 0x30, t); + t = orig | 0x18; + lgs8gxx_write_reg(priv, 0x30, t); + t = orig | 0x10; + lgs8gxx_write_reg(priv, 0x30, t); + } else { + lgs8gxx_write_reg(priv, 0xC6, 0x01); + lgs8gxx_write_reg(priv, 0xC6, 0x41); + lgs8gxx_write_reg(priv, 0xC6, 0x01); + } +} + +static void packet_counter_stop(struct lgs8gxx_state *priv) +{ + u8 t; + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + lgs8gxx_read_reg(priv, 0x30, &t); + t &= 0xE7; + lgs8gxx_write_reg(priv, 0x30, t); + } else { + lgs8gxx_write_reg(priv, 0xC6, 0x81); + } +} + static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber) { struct lgs8gxx_state *priv = fe->demodulator_priv; - u8 r0, r1, r2, r3; - u32 total_cnt, err_cnt; + u8 reg_err, reg_total, t; + u32 total_cnt = 0, err_cnt = 0; + int i; dprintk("%s\n", __func__); - lgs8gxx_write_reg(priv, 0xc6, 0x01); - lgs8gxx_write_reg(priv, 0xc6, 0x41); - lgs8gxx_write_reg(priv, 0xc6, 0x01); - + packet_counter_start(priv); msleep(200); + packet_counter_stop(priv); + + if (priv->config->prod == LGS8GXX_PROD_LGS8G75) { + reg_total = 0x28; reg_err = 0x2C; + } else { + reg_total = 0xD0; reg_err = 0xD4; + } - lgs8gxx_write_reg(priv, 0xc6, 0x81); - lgs8gxx_read_reg(priv, 0xd0, &r0); - lgs8gxx_read_reg(priv, 0xd1, &r1); - lgs8gxx_read_reg(priv, 0xd2, &r2); - lgs8gxx_read_reg(priv, 0xd3, &r3); - total_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0); - lgs8gxx_read_reg(priv, 0xd4, &r0); - lgs8gxx_read_reg(priv, 0xd5, &r1); - lgs8gxx_read_reg(priv, 0xd6, &r2); - lgs8gxx_read_reg(priv, 0xd7, &r3); - err_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0); + for (i = 0; i < 4; i++) { + total_cnt <<= 8; + lgs8gxx_read_reg(priv, reg_total+3-i, &t); + total_cnt |= t; + } + for (i = 0; i < 4; i++) { + err_cnt <<= 8; + lgs8gxx_read_reg(priv, reg_err+3-i, &t); + err_cnt |= t; + } dprintk("error=%d total=%d\n", err_cnt, total_cnt); if (total_cnt == 0) @@ -844,6 +1110,9 @@ struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, sizeof(struct dvb_frontend_ops)); priv->frontend.demodulator_priv = priv; + if (config->prod == LGS8GXX_PROD_LGS8G75) + lgs8g75_init_data(priv); + return &priv->frontend; error_out: diff --git a/linux/drivers/media/dvb/frontends/lgs8gxx.h b/linux/drivers/media/dvb/frontends/lgs8gxx.h index 321d366a8..33c3c5e16 100644 --- a/linux/drivers/media/dvb/frontends/lgs8gxx.h +++ b/linux/drivers/media/dvb/frontends/lgs8gxx.h @@ -1,9 +1,9 @@ /* - * Support for Legend Silicon DMB-TH demodulator - * LGS8913, LGS8GL5 + * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator + * LGS8913, LGS8GL5, LGS8G75 * experimental support LGS8G42, LGS8G52 * - * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com> + * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com> * Copyright (C) 2008 Sirius International (Hong Kong) Limited * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5) * @@ -34,6 +34,7 @@ #define LGS8GXX_PROD_LGS8G42 3 #define LGS8GXX_PROD_LGS8G52 4 #define LGS8GXX_PROD_LGS8G54 5 +#define LGS8GXX_PROD_LGS8G75 6 struct lgs8gxx_config { @@ -70,6 +71,10 @@ struct lgs8gxx_config { /*IF use Negative center frequency*/ u8 if_neg_center; + /*8G75 internal ADC input range selection*/ + /*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/ + u8 adc_vpp; + /* slave address and configuration of the tuner */ u8 tuner_address; }; diff --git a/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h b/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h index 9776d3068..8ef376f14 100644 --- a/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h +++ b/linux/drivers/media/dvb/frontends/lgs8gxx_priv.h @@ -1,9 +1,9 @@ /* - * Support for Legend Silicon DMB-TH demodulator - * LGS8913, LGS8GL5 + * Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator + * LGS8913, LGS8GL5, LGS8G75 * experimental support LGS8G42, LGS8G52 * - * Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com> + * Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com> * Copyright (C) 2008 Sirius International (Hong Kong) Limited * Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5) * @@ -38,7 +38,7 @@ struct lgs8gxx_state { #define SC_QAM64 0x10 /* 64QAM modulation */ #define SC_QAM32 0x0C /* 32QAM modulation */ #define SC_QAM16 0x08 /* 16QAM modulation */ -#define SC_QAM4NR 0x04 /* 4QAM modulation */ +#define SC_QAM4NR 0x04 /* 4QAM-NR modulation */ #define SC_QAM4 0x00 /* 4QAM modulation */ #define LGS_FEC_MASK 0x03 /* FEC Rate Mask */ @@ -47,8 +47,8 @@ struct lgs8gxx_state { #define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */ #define TIM_MASK 0x20 /* Time Interleave Length Mask */ -#define TIM_LONG 0x00 /* Time Interleave Length = 720 */ -#define TIM_MIDDLE 0x20 /* Time Interleave Length = 240 */ +#define TIM_LONG 0x20 /* Time Interleave Length = 720 */ +#define TIM_MIDDLE 0x00 /* Time Interleave Length = 240 */ #define CF_MASK 0x80 /* Control Frame Mask */ #define CF_EN 0x80 /* Control Frame On */ diff --git a/linux/drivers/media/dvb/frontends/mt312.c b/linux/drivers/media/dvb/frontends/mt312.c index a621f7279..071328d7b 100644 --- a/linux/drivers/media/dvb/frontends/mt312.c +++ b/linux/drivers/media/dvb/frontends/mt312.c @@ -85,7 +85,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, int i; dprintk("R(%d):", reg & 0x7f); for (i = 0; i < count; i++) - printk(" %02x", buf[i]); + printk(KERN_CONT " %02x", buf[i]); printk("\n"); } @@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, int i; dprintk("W(%d):", reg & 0x7f); for (i = 0; i < count; i++) - printk(" %02x", src[i]); + printk(KERN_CONT " %02x", src[i]); printk("\n"); } @@ -744,7 +744,8 @@ static struct dvb_frontend_ops mt312_ops = { .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, - .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */ + /* FIXME: adjust freq to real used xtal */ + .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, .symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */ .symbol_rate_max = MT312_SYS_CLK / 2, .caps = diff --git a/linux/drivers/media/dvb/frontends/stv0900.h b/linux/drivers/media/dvb/frontends/stv0900.h index 8a1332c20..bf4e9b633 100644 --- a/linux/drivers/media/dvb/frontends/stv0900.h +++ b/linux/drivers/media/dvb/frontends/stv0900.h @@ -29,6 +29,11 @@ #include <linux/dvb/frontend.h> #include "dvb_frontend.h" +struct stv0900_reg { + u16 addr; + u8 val; +}; + struct stv0900_config { u8 demod_address; u32 xtal; @@ -38,7 +43,7 @@ struct stv0900_config { u8 path1_mode; u8 path2_mode; - + struct stv0900_reg *ts_config_regs; u8 tun1_maddress;/* 0, 1, 2, 3 for 0xc0, 0xc2, 0xc4, 0xc6 */ u8 tun2_maddress; u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */ diff --git a/linux/drivers/media/dvb/frontends/stv0900_core.c b/linux/drivers/media/dvb/frontends/stv0900_core.c index 899b1e7ed..84bf35edb 100644 --- a/linux/drivers/media/dvb/frontends/stv0900_core.c +++ b/linux/drivers/media/dvb/frontends/stv0900_core.c @@ -149,31 +149,31 @@ void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr, dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret); } -u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg_addr) +u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg) { - u8 data[2]; int ret; - struct i2c_msg i2cmsg = { - .addr = i_params->i2c_addr, - .flags = 0, - .len = 2, - .buf = data, + u8 b0[] = { MSB(reg), LSB(reg) }; + u8 buf = 0; + struct i2c_msg msg[] = { + { + .addr = i_params->i2c_addr, + .flags = 0, + .buf = b0, + .len = 2, + }, { + .addr = i_params->i2c_addr, + .flags = I2C_M_RD, + .buf = &buf, + .len = 1, + }, }; - data[0] = MSB(reg_addr); - data[1] = LSB(reg_addr); - - ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1); - if (ret != 1) - dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret); - - i2cmsg.flags = I2C_M_RD; - i2cmsg.len = 1; - ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1); - if (ret != 1) - dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret); + ret = i2c_transfer(i_params->i2c_adap, msg, 2); + if (ret != 2) + dprintk(KERN_ERR "%s: i2c error %d, reg[0x%02x]\n", + __func__, ret, reg); - return data[0]; + return buf; } void extract_mask_pos(u32 label, u8 *mask, u8 *pos) @@ -716,6 +716,44 @@ static s32 stv0900_carr_get_quality(struct dvb_frontend *fe, return c_n; } +static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) +{ + struct stv0900_state *state = fe->demodulator_priv; + struct stv0900_internal *i_params = state->internal; + enum fe_stv0900_demod_num demod = state->demod; + u8 err_val1, err_val0; + s32 err_field1, err_field0; + u32 header_err_val = 0; + + *ucblocks = 0x0; + if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) { + /* DVB-S2 delineator errors count */ + + /* retreiving number for errnous headers */ + dmd_reg(err_field0, R0900_P1_BBFCRCKO0, + R0900_P2_BBFCRCKO0); + dmd_reg(err_field1, R0900_P1_BBFCRCKO1, + R0900_P2_BBFCRCKO1); + + err_val1 = stv0900_read_reg(i_params, err_field1); + err_val0 = stv0900_read_reg(i_params, err_field0); + header_err_val = (err_val1<<8) | err_val0; + + /* retreiving number for errnous packets */ + dmd_reg(err_field0, R0900_P1_UPCRCKO0, + R0900_P2_UPCRCKO0); + dmd_reg(err_field1, R0900_P1_UPCRCKO1, + R0900_P2_UPCRCKO1); + + err_val1 = stv0900_read_reg(i_params, err_field1); + err_val0 = stv0900_read_reg(i_params, err_field0); + *ucblocks = (err_val1<<8) | err_val0; + *ucblocks += header_err_val; + } + + return 0; +} + static int stv0900_read_snr(struct dvb_frontend *fe, u16 *snr) { *snr = stv0900_carr_get_quality(fe, @@ -1359,7 +1397,7 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, struct stv0900_state *state = fe->demodulator_priv; enum fe_stv0900_error error = STV0900_NO_ERROR; enum fe_stv0900_error demodError = STV0900_NO_ERROR; - int selosci; + int selosci, i; struct stv0900_inode *temp_int = find_inode(state->i2c_adap, state->config->demod_address); @@ -1406,7 +1444,23 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, stv0900_write_bits(state->internal, F0900_P1_ROLLOFF_CONTROL, p_init->rolloff); stv0900_write_bits(state->internal, F0900_P2_ROLLOFF_CONTROL, p_init->rolloff); - stv0900_set_ts_parallel_serial(state->internal, p_init->path1_ts_clock, p_init->path2_ts_clock); + state->internal->ts_config = p_init->ts_config; + if (state->internal->ts_config == NULL) + stv0900_set_ts_parallel_serial(state->internal, + p_init->path1_ts_clock, + p_init->path2_ts_clock); + else { + for (i = 0; state->internal->ts_config[i].addr != 0xffff; i++) + stv0900_write_reg(state->internal, + state->internal->ts_config[i].addr, + state->internal->ts_config[i].val); + + stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 1); + stv0900_write_bits(state->internal, F0900_P2_RST_HWARE, 0); + stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 1); + stv0900_write_bits(state->internal, F0900_P1_RST_HWARE, 0); + } + stv0900_write_bits(state->internal, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress); switch (p_init->tuner1_adc) { case 1: @@ -1897,6 +1951,7 @@ static struct dvb_frontend_ops stv0900_ops = { .read_ber = stv0900_read_ber, .read_signal_strength = stv0900_read_signal_strength, .read_snr = stv0900_read_snr, + .read_ucblocks = stv0900_read_ucblocks, }; struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, @@ -1930,6 +1985,7 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, init_params.tun1_iq_inversion = STV0900_IQ_NORMAL; init_params.tuner1_adc = config->tun1_adc; init_params.path2_ts_clock = config->path2_mode; + init_params.ts_config = config->ts_config_regs; init_params.tun2_maddress = config->tun2_maddress; init_params.tuner2_adc = config->tun2_adc; init_params.tun2_iq_inversion = STV0900_IQ_SWAPPED; diff --git a/linux/drivers/media/dvb/frontends/stv0900_priv.h b/linux/drivers/media/dvb/frontends/stv0900_priv.h index 67dc8ec63..5ed7a145c 100644 --- a/linux/drivers/media/dvb/frontends/stv0900_priv.h +++ b/linux/drivers/media/dvb/frontends/stv0900_priv.h @@ -271,6 +271,7 @@ struct stv0900_init_params{ /* IQ from the tuner2 to the demod */ enum stv0900_iq_inversion tun2_iq_inversion; + struct stv0900_reg *ts_config; }; struct stv0900_search_params { @@ -363,6 +364,7 @@ struct stv0900_internal{ u8 i2c_addr; u8 clkmode;/* 0 for CLKI, 2 for XTALI */ u8 chip_id; + struct stv0900_reg *ts_config; enum fe_stv0900_error errs; int dmds_used; }; diff --git a/linux/drivers/media/dvb/frontends/stv0900_sw.c b/linux/drivers/media/dvb/frontends/stv0900_sw.c index a5a31536c..962fde143 100644 --- a/linux/drivers/media/dvb/frontends/stv0900_sw.c +++ b/linux/drivers/media/dvb/frontends/stv0900_sw.c @@ -1721,7 +1721,7 @@ static enum fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_front s32 srate, demod_timeout, fec_timeout, freq1, freq0; - enum fe_stv0900_signal_type signal_type = STV0900_NODATA;; + enum fe_stv0900_signal_type signal_type = STV0900_NODATA; switch (demod) { case STV0900_DEMOD_1: diff --git a/linux/drivers/media/dvb/frontends/stv090x.c b/linux/drivers/media/dvb/frontends/stv090x.c index 62078400f..8b152bea3 100644 --- a/linux/drivers/media/dvb/frontends/stv090x.c +++ b/linux/drivers/media/dvb/frontends/stv090x.c @@ -3405,7 +3405,7 @@ static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_mod static u8 stv090x_optimize_carloop_short(struct stv090x_state *state) { - struct stv090x_short_frame_crloop *short_crl; + struct stv090x_short_frame_crloop *short_crl = NULL; s32 index = 0; u8 aclc = 0x0b; @@ -3425,10 +3425,13 @@ static u8 stv090x_optimize_carloop_short(struct stv090x_state *state) break; } - if (state->dev_ver >= 0x30) - short_crl = stv090x_s2_short_crl_cut20; - else if (state->dev_ver >= 0x20) + if (state->dev_ver >= 0x30) { + /* Cut 3.0 and up */ short_crl = stv090x_s2_short_crl_cut30; + } else { + /* Cut 2.0 and up: we don't support cuts older than 2.0 */ + short_crl = stv090x_s2_short_crl_cut20; + } if (state->srate <= 3000000) aclc = short_crl[index].crl_2; diff --git a/linux/drivers/media/dvb/frontends/tda10048.c b/linux/drivers/media/dvb/frontends/tda10048.c index 04596baa9..edf5a19a3 100644 --- a/linux/drivers/media/dvb/frontends/tda10048.c +++ b/linux/drivers/media/dvb/frontends/tda10048.c @@ -210,6 +210,7 @@ static struct pll_tab { { TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 }, { TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 }, { TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 }, + { TDA10048_CLK_16000, TDA10048_IF_3800, 10, 3, 0 }, { TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 }, { TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 }, { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 }, diff --git a/linux/drivers/media/dvb/frontends/zl10036.c b/linux/drivers/media/dvb/frontends/zl10036.c index 67cdb056f..ce2a2703b 100644 --- a/linux/drivers/media/dvb/frontends/zl10036.c +++ b/linux/drivers/media/dvb/frontends/zl10036.c @@ -29,7 +29,7 @@ #include <linux/module.h> #include <linux/dvb/frontend.h> -#include <asm/types.h> +#include <linux/types.h> #include "compat.h" #include "zl10036.h" diff --git a/linux/drivers/media/dvb/siano/smscoreapi.c b/linux/drivers/media/dvb/siano/smscoreapi.c index e513408fc..54f59f24e 100644 --- a/linux/drivers/media/dvb/siano/smscoreapi.c +++ b/linux/drivers/media/dvb/siano/smscoreapi.c @@ -1477,8 +1477,8 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, struct smscore_gpio_config *pGpioConfig) { u32 totalLen; - u32 TranslatedPinNum; - u32 GroupNum; + u32 TranslatedPinNum = 0; + u32 GroupNum = 0; u32 ElectricChar; u32 groupCfg; void *buffer; diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig index 68eb4493f..d8d4214fd 100644 --- a/linux/drivers/media/dvb/ttpci/Kconfig +++ b/linux/drivers/media/dvb/ttpci/Kconfig @@ -1,5 +1,6 @@ config TTPCI_EEPROM tristate + depends on I2C default n config DVB_AV7110 diff --git a/linux/drivers/media/dvb/ttpci/av7110_v4l.c b/linux/drivers/media/dvb/ttpci/av7110_v4l.c index ce64c6214..8986d967d 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/linux/drivers/media/dvb/ttpci/av7110_v4l.c @@ -490,7 +490,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) if (!av7110->analog_tuner_flags) return 0; - if (input < 0 || input >= 4) + if (input >= 4) return -EINVAL; av7110->current_input = input; |