From 7a9b5fc5fd9e30b58be767722e270f3df651f27c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 11 Sep 2008 23:02:12 -0300 Subject: V4L/DVB (8978): sms1xxx: fix product name for Hauppauge WinTV MiniStick Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/siano/sms-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index cc5efb643f33..06297665c9f9 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -87,7 +87,7 @@ static struct sms_board sms_boards[] = { .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", }, [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { - .name = "Hauppauge WinTV-Nova-T-MiniStick", + .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw", }, -- cgit v1.2.1 From 3d843c92da5a1f1ab2cbc2b2e04f84d5ecedf5aa Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 16 Sep 2008 16:46:42 -0300 Subject: V4L/DVB (8979): sms1xxx: Add new USB product ID for Hauppauge WinTV MiniStick 2040:5510 is the same hardware as 2040:5500 Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/siano/sms-cards.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index 06297665c9f9..9da260fe3fd1 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -40,6 +40,8 @@ struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B }, { USB_DEVICE(0x2040, 0x5500), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0x5510), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5580), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5590), -- cgit v1.2.1 From dda06a8e4610757def753ee3a541a0b1a1feb36b Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Wed, 24 Sep 2008 05:00:37 -0300 Subject: V4L/DVB (9029): Fix deadlock in demux code The functions dvb_dmxdev_section_callback, dvb_dmxdev_ts_callback, dvb_dmx_swfilter_packet, dvb_dmx_swfilter_packets, dvb_dmx_swfilter and dvb_dmx_swfilter_204 may be called from both interrupt and process context. Therefore they need to be protected by spin_lock_irqsave() instead of spin_lock(). This fixes a deadlock discovered by lockdep. Signed-off-by: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dmxdev.c | 16 +++++++++------- drivers/media/dvb/dvb-core/dvb_demux.c | 16 ++++++++++------ 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 069d847ba887..0c733c66a441 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -364,15 +364,16 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, enum dmx_success success) { struct dmxdev_filter *dmxdevfilter = filter->priv; + unsigned long flags; int ret; if (dmxdevfilter->buffer.error) { wake_up(&dmxdevfilter->buffer.queue); return 0; } - spin_lock(&dmxdevfilter->dev->lock); + spin_lock_irqsave(&dmxdevfilter->dev->lock, flags); if (dmxdevfilter->state != DMXDEV_STATE_GO) { - spin_unlock(&dmxdevfilter->dev->lock); + spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); return 0; } del_timer(&dmxdevfilter->timer); @@ -391,7 +392,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, } if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) dmxdevfilter->state = DMXDEV_STATE_DONE; - spin_unlock(&dmxdevfilter->dev->lock); + spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); wake_up(&dmxdevfilter->buffer.queue); return 0; } @@ -403,11 +404,12 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, { struct dmxdev_filter *dmxdevfilter = feed->priv; struct dvb_ringbuffer *buffer; + unsigned long flags; int ret; - spin_lock(&dmxdevfilter->dev->lock); + spin_lock_irqsave(&dmxdevfilter->dev->lock, flags); if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { - spin_unlock(&dmxdevfilter->dev->lock); + spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); return 0; } @@ -417,7 +419,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, else buffer = &dmxdevfilter->dev->dvr_buffer; if (buffer->error) { - spin_unlock(&dmxdevfilter->dev->lock); + spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); wake_up(&buffer->queue); return 0; } @@ -428,7 +430,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, dvb_ringbuffer_flush(buffer); buffer->error = ret; } - spin_unlock(&dmxdevfilter->dev->lock); + spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); wake_up(&buffer->queue); return 0; } diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index e2eca0b1fe7c..a2c1fd5d2f67 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -399,7 +399,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count) { - spin_lock(&demux->lock); + unsigned long flags; + + spin_lock_irqsave(&demux->lock, flags); while (count--) { if (buf[0] == 0x47) @@ -407,16 +409,17 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, buf += 188; } - spin_unlock(&demux->lock); + spin_unlock_irqrestore(&demux->lock, flags); } EXPORT_SYMBOL(dvb_dmx_swfilter_packets); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) { + unsigned long flags; int p = 0, i, j; - spin_lock(&demux->lock); + spin_lock_irqsave(&demux->lock, flags); if (demux->tsbufp) { i = demux->tsbufp; @@ -449,17 +452,18 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) } bailout: - spin_unlock(&demux->lock); + spin_unlock_irqrestore(&demux->lock, flags); } EXPORT_SYMBOL(dvb_dmx_swfilter); void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) { + unsigned long flags; int p = 0, i, j; u8 tmppack[188]; - spin_lock(&demux->lock); + spin_lock_irqsave(&demux->lock, flags); if (demux->tsbufp) { i = demux->tsbufp; @@ -500,7 +504,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) } bailout: - spin_unlock(&demux->lock); + spin_unlock_irqrestore(&demux->lock, flags); } EXPORT_SYMBOL(dvb_dmx_swfilter_204); -- cgit v1.2.1 From c18c5ffe13e553cf670da521fe09150c36edeb61 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 6 Sep 2008 13:31:58 -0300 Subject: V4L/DVB (9037): Fix support for Hauppauge Nova-S SE Different backends have different input busses (saa7146, flexcop). To reflect that a config-option to the s5h1420-driver was added which makes the output mode selectable. Furthermore the s5h1420-driver is now doing the same i2c-method as it was done before adding support for other i2c-users. This patch needs to go into the current release of the kernel, as this driver is currently broken. (Thanks to Eberhard Kaltenhaeuser for helping out to debug this issue.) Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop-fe-tuner.c | 1 + drivers/media/dvb/frontends/s5h1420.c | 9 ++++++--- drivers/media/dvb/frontends/s5h1420.h | 8 +++++--- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 4eed783f4bce..a127a4175c40 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -491,6 +491,7 @@ static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { .demod_address = 0x53, .invert = 1, .repeated_start_workaround = 1, + .serial_mpeg = 1, }; static struct itd1000_config skystar2_rev2_7_itd1000_config = { diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 747d3fa2e5e5..7d6cb39da1d9 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -94,8 +94,11 @@ static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg) if (ret != 3) return ret; } else { - ret = i2c_transfer(state->i2c, &msg[1], 2); - if (ret != 2) + ret = i2c_transfer(state->i2c, &msg[1], 1); + if (ret != 1) + return ret; + ret = i2c_transfer(state->i2c, &msg[2], 1); + if (ret != 1) return ret; } @@ -823,7 +826,7 @@ static int s5h1420_init (struct dvb_frontend* fe) struct s5h1420_state* state = fe->demodulator_priv; /* disable power down and do reset */ - state->CON_1_val = 0x10; + state->CON_1_val = state->config->serial_mpeg << 4; s5h1420_writereg(state, 0x02, state->CON_1_val); msleep(10); s5h1420_reset(state); diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h index 4c913f142bc4..ff308136d865 100644 --- a/drivers/media/dvb/frontends/s5h1420.h +++ b/drivers/media/dvb/frontends/s5h1420.h @@ -32,10 +32,12 @@ struct s5h1420_config u8 demod_address; /* does the inversion require inversion? */ - u8 invert : 1; + u8 invert:1; - u8 repeated_start_workaround : 1; - u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */ + u8 repeated_start_workaround:1; + u8 cdclk_polarity:1; /* 1 == falling edge, 0 == raising edge */ + + u8 serial_mpeg:1; }; #if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) -- cgit v1.2.1 From bda1cda54b7e1654e9416fec76e6342847b25216 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 7 Sep 2008 16:04:38 -0300 Subject: V4L/DVB (9043): S5H1420: Fix size of shadow-array to avoid overflow The array size of 'shadow' still needs to be fixed in order to not overflow when reading register 0x00. Thanks to Oliver Endriss for pointing that out. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1420.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 7d6cb39da1d9..2e9fd2893ede 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -59,7 +59,7 @@ struct s5h1420_state { * it does not support repeated-start, workaround: write addr-1 * and then read */ - u8 shadow[255]; + u8 shadow[256]; }; static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); -- cgit v1.2.1 From 29e66a6ce84abe04bc809ddb35634752881dec79 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 4 Sep 2008 17:24:51 -0300 Subject: V4L/DVB: follow lspci device/vendor style Use "[%04x:%04x]" for PCI vendor/device IDs to follow the format used by lspci(8). Signed-off-by: Bjorn Helgaas Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 2 +- drivers/media/dvb/ttpci/av7110.c | 2 +- drivers/media/dvb/ttpci/budget-av.c | 2 +- drivers/media/dvb/ttpci/budget-ci.c | 2 +- drivers/media/dvb/ttpci/budget-patch.c | 2 +- drivers/media/dvb/ttpci/budget.c | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 2 +- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 6afbfbbef0ce..48762a2b9e42 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -702,7 +702,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) } if (card->fe == NULL) - printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", card->bt->dev->vendor, card->bt->dev->device, card->bt->dev->subsystem_vendor, diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 0777e8f9544b..3b641804f6cb 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2256,7 +2256,7 @@ static int frontend_init(struct av7110 *av7110) if (!av7110->fe) { /* FIXME: propagate the failure code from the lower layers */ ret = -ENOMEM; - printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", av7110->dev->pci->vendor, av7110->dev->pci->device, av7110->dev->pci->subsystem_vendor, diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index b7d1f2f18d3a..839c94101b4e 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1049,7 +1049,7 @@ static void frontend_init(struct budget_av *budget_av) if (fe == NULL) { printk(KERN_ERR "budget-av: A frontend driver was not found " - "for device %04x/%04x subsystem %04x/%04x\n", + "for device [%04x:%04x] subsystem [%04x:%04x]\n", saa->pci->vendor, saa->pci->device, saa->pci->subsystem_vendor, diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 060e7c785326..38dd5cf1aed2 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -1153,7 +1153,7 @@ static void frontend_init(struct budget_ci *budget_ci) } if (budget_ci->budget.dvb_frontend == NULL) { - printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", budget_ci->budget.dev->pci->vendor, budget_ci->budget.dev->pci->device, budget_ci->budget.dev->pci->subsystem_vendor, diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index aa5ed4ef19f2..bbd234fe11c1 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -360,7 +360,7 @@ static void frontend_init(struct budget_patch* budget) } if (budget->dvb_frontend == NULL) { - printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", budget->dev->pci->vendor, budget->dev->pci->device, budget->dev->pci->subsystem_vendor, diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index f0068996ac07..851e523fbffc 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -550,7 +550,7 @@ static void frontend_init(struct budget *budget) } if (budget->dvb_frontend == NULL) { - printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", budget->dev->pci->vendor, budget->dev->pci->device, budget->dev->pci->subsystem_vendor, diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index e6c9cd2e3b94..66ab0c6e9783 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1614,7 +1614,7 @@ static void frontend_init(struct ttusb* ttusb) } if (ttusb->fe == NULL) { - printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n", + printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n", le16_to_cpu(ttusb->dev->descriptor.idVendor), le16_to_cpu(ttusb->dev->descriptor.idProduct)); } else { diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index de5829b863fd..ab33fec8a19f 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1665,7 +1665,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, } if (dec->fe == NULL) { - printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n", + printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", le16_to_cpu(dec->udev->descriptor.idVendor), le16_to_cpu(dec->udev->descriptor.idProduct)); } else { -- cgit v1.2.1 From 95fc2ead8406a6d0aa6d8ccf30125f4a50ae323f Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Mon, 21 Jul 2008 16:21:58 -0300 Subject: V4L/DVB (8560): replace __FUNCTION__ with __func__ v4l/drx397xD: replace __FUNCTION__ with __func__ Signed-off-by: Alexander Beregalov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/drx397xD.c | 34 +++++++++++++++++----------------- drivers/media/dvb/frontends/drx397xD.h | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index 3cbed874a6f8..e19147bad178 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -96,7 +96,7 @@ static void drx_release_fw(struct drx397xD_state *s) { fw_ix_t ix = s->chip_rev; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); write_lock(&fw[ix].lock); if (fw[ix].refcnt) { @@ -113,7 +113,7 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) size_t size, len; int i = 0, j, rc = -EINVAL; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (ix < 0 || ix >= ARRAY_SIZE(fw)) return -EINVAL; @@ -197,10 +197,10 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix) int len, rc = 0, i = 0; if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { - pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__); + pr_debug("%s drx_fw_ix_t out of range\n", __func__); return -EINVAL; } - pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]); + pr_debug("%s %s\n", __func__, blob_name[ix]); read_lock(&fw[s->chip_rev].lock); data = fw[s->chip_rev].data[ix]; @@ -305,7 +305,7 @@ static int PLL_Set(struct drx397xD_state *s, u32 f_tuner, f = fep->frequency; int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || (f < s->frontend.ops.tuner_ops.info.frequency_min)) @@ -325,7 +325,7 @@ static int PLL_Set(struct drx397xD_state *s, return rc; *df_tuner = f_tuner - f; - pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f, + pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f, f_tuner); return 0; @@ -340,7 +340,7 @@ static int SC_WaitForReady(struct drx397xD_state *s) int cnt = 1000; int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); while (cnt--) { rc = RD16(s, 0x820043); @@ -354,7 +354,7 @@ static int SC_SendCommand(struct drx397xD_state *s, int cmd) { int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); WR16(s, 0x820043, cmd); SC_WaitForReady(s); @@ -368,7 +368,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) { int rc, cnt = 1000; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); rc = WR16(s, 0x420032, cmd); if (rc < 0) @@ -389,7 +389,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) static int HI_CfgCommand(struct drx397xD_state *s) { - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); WR16(s, 0x420033, 0x3973); WR16(s, 0x420034, s->config.w50); // code 4, log 4 @@ -419,7 +419,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) u16 w0C = agc->w0C; int quot, rem, i, rc = -EINVAL; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (agc->w04 > 0x3ff) goto exit_rc; @@ -478,7 +478,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) u16 w06 = agc->w06; int rc = -1; - pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06); + pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06); if (w04 > 0x3ff) goto exit_rc; @@ -554,7 +554,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) int lockstat; u32 clk, clk_limit; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (s->config.d5C == 0) { EXIT_RC(WR16(s, 0x08200e8, 0x010)); @@ -598,7 +598,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { s->f_osc = clk; - pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__, + pr_debug("%s: osc %d %d [Hz]\n", __func__, s->config.f_osc * 1000, clk - s->config.f_osc * 1000); } rc = WR16(s, 0x08200e8, 0); @@ -610,7 +610,7 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) { int rc, si, bp; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); si = s->config.wA0; if (s->config.w98 == 0) { @@ -646,7 +646,7 @@ static int drx_tune(struct drx397xD_state *s, int rc, df_tuner; int a, b, c, d; - pr_debug("%s %d\n", __FUNCTION__, s->config.d60); + pr_debug("%s %d\n", __func__, s->config.d60); if (s->config.d60 != 2) goto set_tuner; @@ -1082,7 +1082,7 @@ static int drx397x_init(struct dvb_frontend *fe) struct drx397xD_state *s = fe->demodulator_priv; int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); s->config.rfagc.d00 = 2; /* 0x7c */ s->config.rfagc.w04 = 0; diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h index ddc7a07971b7..2ad1ea0ccfb0 100644 --- a/drivers/media/dvb/frontends/drx397xD.h +++ b/drivers/media/dvb/frontends/drx397xD.h @@ -122,7 +122,7 @@ extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, struct i2c_adapter *i2c) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } #endif /* CONFIG_DVB_DRX397XD */ -- cgit v1.2.1 From 8d79898897f8afee182febef18b96f559d32ebc4 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sat, 9 Aug 2008 12:23:15 -0300 Subject: V4L/DVB (8654): cxusb: add support for DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2) Add support for revision 2 of the DViCO FusionHDTV DVB-T Dual Digital 4 which has new tuners and demodulators (2 x DIB7070p). With this patch both DVB reception and IR works. The dib7000p driver currently hardwires the output mode to OUTMODE_MPEG2_SERIAL regardless of what we ask for. Modify it to allow OUTMODE_MPEG2_PAR_GATED_CLK to be set. Longer term we should remove the check completely and set the output mode correctly in all the callers. Add Kconfig bits to ensure the dib7000p and dib0070 modules are enabled. It would be nice to only do this for the !DVB_FE_CUSTOMISE case, but this is what the other DIB7070 module does (there are a number of module dependencies in the attach code). Signed-off-by: Anton Blanchard Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 + drivers/media/dvb/dvb-usb/cxusb.c | 206 ++++++++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/frontends/dib7000p.c | 3 +- 4 files changed, 211 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index e84152b7576d..df9932368bba 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -108,6 +108,8 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + select DVB_DIB7000P + select DVB_TUNER_DIB0070 help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 563400277a42..1de3678a294b 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -36,6 +36,8 @@ #include "tuner-xc2028.h" #include "tuner-simple.h" #include "mxl5005s.h" +#include "dib7000p.h" +#include "dib0070.h" /* debug */ static int dvb_usb_cxusb_debug; @@ -726,6 +728,157 @@ no_IR: return 0; } +static struct dibx000_agc_config dib7070_agc_config = { + .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + + /* + * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 + */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + .inv_gain = 600, + .time_stabiliz = 10, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, + .agc1_max = 65535, + .agc1_min = 0, + .agc2_max = 65535, + .agc2_min = 0, + .agc1_pt1 = 0, + .agc1_pt2 = 40, + .agc1_pt3 = 183, + .agc1_slope1 = 206, + .agc1_slope2 = 255, + .agc2_pt1 = 72, + .agc2_pt2 = 152, + .agc2_slope1 = 88, + .agc2_slope2 = 90, + .alpha_mant = 17, + .alpha_exp = 27, + .beta_mant = 23, + .beta_exp = 51, + .perform_agc_softsplit = 0, +}; + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 20, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + /* refsel, sel, freq_15k */ + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20452225, + .xtal_hz = 12000000, +}; + +static struct dib7000p_config cxusb_dualdig4_rev2_config = { + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = 0xfcef, + .gpio_val = 0x0110, + + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &cxusb_dualdig4_rev2_config); + + if ((adap->fe = dvb_attach(dib7000p_attach, + &adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config)) == NULL) + return -EIO; + + return 0; +} + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return 0; +} + +static struct dib0070_config dib7070p_dib0070_config = { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, +}; + +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, + struct dvb_frontend_parameters *); +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + + return state->set_param_save(fe, fep); +} + +static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + &dib7070p_dib0070_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev, 0, 1) < 0) @@ -826,6 +979,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static struct dvb_usb_device_properties cxusb_aver_a868r_properties; @@ -852,6 +1006,9 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_rev2_properties, + THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -876,6 +1033,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1321,6 +1479,54 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } }; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, + .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, + .size_of_priv = sizeof(struct dib0700_adapter_state), + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_mce_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), + .rc_query = cxusb_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", + { NULL }, + { &cxusb_table[17], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 03dfb9f2fe30..f327a154b6c6 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -171,6 +171,7 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 +#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 1a0142e0d741..8217e5b38f47 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1333,7 +1333,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, /* Ensure the output mode remains at the previous default if it's * not specifically set by the caller. */ - if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) + if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && + (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) st->cfg.output_mode = OUTMODE_MPEG2_FIFO; demod = &st->demod; -- cgit v1.2.1 From a2dc86b69dcbcbeb498c5f5169f09f4bd207de5f Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 13:06:26 -0300 Subject: V4L/DVB (8655): cxusb: fix checkpatch warnings & errors Fix the following checkpatch.pl errors and warnings: ERROR: do not use assignment in if condition 117: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:819: + if ((adap->fe = dvb_attach(dib7000p_attach, ERROR: switch and case should be at the same indent 155: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:857: + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; WARNING: line over 80 characters 169: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:871: + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); WARNING: line over 80 characters 213: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:1342: +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { WARNING: line over 80 characters 226: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:1355: + .size_of_priv = sizeof(struct dib0700_adapter_state), total: 2 errors, 3 warnings, 266 lines checked Signed-off-by: Michael Krufky Cc: Anton Blanchard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 1de3678a294b..338c819ca739 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -816,9 +816,9 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &cxusb_dualdig4_rev2_config); - if ((adap->fe = dvb_attach(dib7000p_attach, - &adap->dev->i2c_adap, 0x80, - &cxusb_dualdig4_rev2_config)) == NULL) + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config); + if (adap->fe == NULL) return -EIO; return 0; @@ -855,9 +855,9 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, u16 offset; u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); switch (band) { - case BAND_VHF: offset = 950; break; - case BAND_UHF: - default: offset = 550; break; + case BAND_VHF: offset = 950; break; + default: + case BAND_UHF: offset = 550; break; } dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); @@ -868,7 +868,9 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = + dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config) == NULL) @@ -1479,7 +1481,8 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } }; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { +static +struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, @@ -1489,10 +1492,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties .num_adapters = 1, .adapter = { { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, - .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, - .size_of_priv = sizeof(struct dib0700_adapter_state), + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, + .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, + .size_of_priv = sizeof(struct dib0700_adapter_state), /* parameter for the MPEG2-data transfer */ .stream = { .type = USB_BULK, -- cgit v1.2.1 From 2e06d2ff548fc6333f5b34d188646ded327187c3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 14:21:58 -0300 Subject: V4L/DVB (8656): fix DVB_FE_CUSTOMISE for DVB_DIB7000P and DVB_TUNER_DIB0070 with dvb-usb-cxusb Allow dvb-usb-cxusb to be built without dib7000p or dib0070 selected Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 4 ++-- drivers/media/dvb/frontends/dib0070.h | 8 ++++++- drivers/media/dvb/frontends/dib7000p.h | 41 +++++++++++++++++++++++++++++----- 3 files changed, 45 insertions(+), 8 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index df9932368bba..8a54cb48322f 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -108,8 +108,8 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE - select DVB_DIB7000P - select DVB_TUNER_DIB0070 + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h index 3eedfdf505bc..21f2c5161af4 100644 --- a/drivers/media/dvb/frontends/dib0070.h +++ b/drivers/media/dvb/frontends/dib0070.h @@ -41,6 +41,7 @@ struct dib0070_config { extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); #else static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, @@ -49,9 +50,14 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } + +static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); -extern u16 dib0070_wbd_offset(struct dvb_frontend *); #endif diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 07c4d12ed5b7..3e8126857127 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -41,6 +41,14 @@ struct dib7000p_config { extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, + enum dibx000_i2c_interface, + int); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib7000p_config cfg[]); +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #else static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, @@ -49,13 +57,36 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); +static inline +struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, + enum dibx000_i2c_interface i, int x) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib7000p_config cfg[]) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif -extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); -extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #endif -- cgit v1.2.1 From dfbdce04905d3196c828ca36f01ef06e6fdb2428 Mon Sep 17 00:00:00 2001 From: Timothy Lee Date: Sat, 9 Aug 2008 13:36:51 -0300 Subject: V4L/DVB (8657): cxusb: add lgs8gl5 and support for Magic-Pro DMB-TH usb stick Add support for Magic-Pro DMB-TH usb stick. DMB-TH is the HDTV broadcast standard used in Hong Kong and China. [...] I've also attached a second patch against the dvb-apps repository which adds a DMB-TH scan file for Hong Kong. Since the ProHDTV stick contains a DMB-TH decoder (lgs8gl5) onboard, it outputs MPEG-TS to the PC. Signed-off-by: Timothy Lee Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 286 +++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/lgs8gl5.c | 480 ++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/lgs8gl5.h | 45 +++ 6 files changed, 821 insertions(+) create mode 100644 drivers/media/dvb/frontends/lgs8gl5.c create mode 100644 drivers/media/dvb/frontends/lgs8gl5.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 338c819ca739..bffb44380389 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -38,6 +38,7 @@ #include "mxl5005s.h" #include "dib7000p.h" #include "dib0070.h" +#include "lgs8gl5.h" /* debug */ static int dvb_usb_cxusb_debug; @@ -111,6 +112,25 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); } +static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, + u8 addr, int onoff) +{ + u8 o[2] = {addr, onoff}; + u8 i; + int rc; + + rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (rc < 0) + return rc; + if (i == 0x01) + return 0; + else { + deb_info("gpio_write failed.\n"); + return -EIO; + } +} + /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -264,6 +284,20 @@ static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) return rc; } +static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 b; + ret = cxusb_power_ctrl(d, onoff); + if (!onoff) + return ret; + + msleep(128); + cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); + msleep(100); + return ret; +} + static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[2] = { 0x03, 0x00 }; @@ -285,6 +319,67 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return 0; } +static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) +{ + int ep = d->props.generic_bulk_ctrl_endpoint; + const int timeout = 100; + const int junk_len = 32; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, ep), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) +{ + struct usb_data_stream_properties *p = &d->props.adapter[0].stream; + const int timeout = 100; + const int junk_len = p->u.bulk.buffersize; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, p->endpoint), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static int cxusb_d680_dmb_streaming_ctrl( + struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) { + u8 buf[2] = { 0x03, 0x00 }; + cxusb_d680_dmb_drain_video(adap->dev); + return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, + buf, sizeof(buf), NULL, 0); + } else { + int ret = cxusb_ctrl_msg(adap->dev, + CMD_STREAMING_OFF, NULL, 0, NULL, 0); + return ret; + } +} + 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; @@ -337,6 +432,32 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, return 0; } +static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + u8 ircode[2]; + int i; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) + return 0; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == ircode[0] && + keymap[i].data == ircode[1]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x02, KEY_TV }, { 0xfe, 0x0e, KEY_MP3 }, @@ -424,6 +545,44 @@ static struct dvb_usb_rc_key dvico_portable_rc_keys[] = { { 0xfc, 0x00, KEY_UNKNOWN }, /* HD */ }; +static struct dvb_usb_rc_key d680_dmb_rc_keys[] = { + { 0x00, 0x38, KEY_UNKNOWN }, /* TV/AV */ + { 0x08, 0x0c, KEY_ZOOM }, + { 0x08, 0x00, KEY_0 }, + { 0x00, 0x01, KEY_1 }, + { 0x08, 0x02, KEY_2 }, + { 0x00, 0x03, KEY_3 }, + { 0x08, 0x04, KEY_4 }, + { 0x00, 0x05, KEY_5 }, + { 0x08, 0x06, KEY_6 }, + { 0x00, 0x07, KEY_7 }, + { 0x08, 0x08, KEY_8 }, + { 0x00, 0x09, KEY_9 }, + { 0x00, 0x0a, KEY_MUTE }, + { 0x08, 0x29, KEY_BACK }, + { 0x00, 0x12, KEY_CHANNELUP }, + { 0x08, 0x13, KEY_CHANNELDOWN }, + { 0x00, 0x2b, KEY_VOLUMEUP }, + { 0x08, 0x2c, KEY_VOLUMEDOWN }, + { 0x00, 0x20, KEY_UP }, + { 0x08, 0x21, KEY_DOWN }, + { 0x00, 0x11, KEY_LEFT }, + { 0x08, 0x10, KEY_RIGHT }, + { 0x00, 0x0d, KEY_OK }, + { 0x08, 0x1f, KEY_RECORD }, + { 0x00, 0x17, KEY_PLAYPAUSE }, + { 0x08, 0x16, KEY_PLAYPAUSE }, + { 0x00, 0x0b, KEY_STOP }, + { 0x08, 0x27, KEY_FASTFORWARD }, + { 0x00, 0x26, KEY_REWIND }, + { 0x08, 0x1e, KEY_UNKNOWN }, /* Time Shift */ + { 0x00, 0x0e, KEY_UNKNOWN }, /* Snapshot */ + { 0x08, 0x2d, KEY_UNKNOWN }, /* Mouse Cursor */ + { 0x00, 0x0f, KEY_UNKNOWN }, /* Minimize/Maximize */ + { 0x08, 0x14, KEY_UNKNOWN }, /* Shuffle */ + { 0x00, 0x25, KEY_POWER }, +}; + static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; @@ -529,6 +688,24 @@ static struct mxl5005s_config aver_a868r_tuner = { .AgcMasterByte = 0x00, }; +/* FIXME: needs tweaking */ +static struct mxl5005s_config d680_dmb_tuner = { + .i2c_address = 0x63, + .if_freq = 36125000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -617,6 +794,14 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + fe = dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &d680_dmb_tuner); + return (fe == NULL) ? -EIO : 0; +} + static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; @@ -906,6 +1091,54 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) return -EIO; } +static struct lgs8gl5_config lgs8gl5_cfg = { + .demod_address = 0x19, +}; + +static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + int n; + + /* Select required USB configuration */ + if (usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + + /* Unblock all USB pipes */ + usb_clear_halt(d->udev, + usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); + + /* Drain USB pipes to avoid hang after reboot */ + for (n = 0; n < 5; n++) { + cxusb_d680_dmb_drain_message(d); + cxusb_d680_dmb_drain_video(d); + msleep(200); + } + + /* Reset the tuner */ + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* Attach frontend */ + adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + /* * DViCO has shipped two devices with the same USB ID, but only one of them * needs a firmware download. Check the device class details to see if they @@ -985,6 +1218,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static struct dvb_usb_device_properties cxusb_aver_a868r_properties; +static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -1011,6 +1245,8 @@ static int cxusb_probe(struct usb_interface *intf, 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_rev2_properties, THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, + THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -1036,6 +1272,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, + { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1530,6 +1767,55 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { } }; +static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, + .frontend_attach = cxusb_d680_dmb_frontend_attach, + .tuner_attach = cxusb_d680_dmb_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_d680_dmb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = d680_dmb_rc_keys, + .rc_key_map_size = ARRAY_SIZE(d680_dmb_rc_keys), + .rc_query = cxusb_d680_dmb_rc_query, + + .num_device_descs = 1, + .devices = { + { + "Conexant DMB-TH Stick", + { NULL }, + { &cxusb_table[18], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index f327a154b6c6..81369b79e75a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -22,6 +22,7 @@ #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f +#define USB_VID_CONEXANT 0x0572 #define USB_VID_CYPRESS 0x04b4 #define USB_VID_DIBCOM 0x10b8 #define USB_VID_DPOSH 0x1498 @@ -69,6 +70,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 #define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 +#define USB_PID_CONEXANT_D680_DMB 0x86d6 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 7dbb4a223c99..774f5c2a71e8 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -385,4 +385,11 @@ config DVB_ISL6421 help An SEC control chip. +config DVB_LGS8GL5 + tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DMB-TH tuner module. Say Y when you want to support this frontend. + endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 028da55611c0..262eaa429f5d 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o +obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c new file mode 100644 index 000000000000..c0a223d28b0f --- /dev/null +++ b/drivers/media/dvb/frontends/lgs8gl5.c @@ -0,0 +1,480 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee + + 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 +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "lgs8gl5.h" + + +#define REG_RESET 0x02 +#define REG_RESET_OFF 0x01 +#define REG_03 0x03 +#define REG_04 0x04 +#define REG_07 0x07 +#define REG_09 0x09 +#define REG_0A 0x0a +#define REG_0B 0x0b +#define REG_0C 0x0c +#define REG_37 0x37 +#define REG_STRENGTH 0x4b +#define REG_STRENGTH_MASK 0x7f +#define REG_STRENGTH_CARRIER 0x80 +#define REG_INVERSION 0x7c +#define REG_INVERSION_ON 0x80 +#define REG_7D 0x7d +#define REG_7E 0x7e +#define REG_A2 0xa2 +#define REG_STATUS 0xa4 +#define REG_STATUS_SYNC 0x04 +#define REG_STATUS_LOCK 0x01 + + +struct lgs8gl5_state { + struct i2c_adapter *i2c; + const struct lgs8gl5_config *config; + struct dvb_frontend frontend; +}; + + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "lgs8gl5: " args); \ + } while (0) + + +/* Writes into demod's register */ +static int +lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = {reg, data}; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", + __func__, reg, data, ret); + return (ret != 1) ? -1 : 0; +} + + +/* Reads from demod's register */ +static int +lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) +{ + int ret, j; + u8 b0[] = {reg}; + u8 b1[] = {0}; + struct i2c_msg msg[2] = { + { + .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) + return -EIO; + + return b1[0]; +} + + +static int +lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + lgs8gl5_read_reg(state, reg); + lgs8gl5_write_reg(state, reg, data); + return 0; +} + + +/* Writes into alternate device's register */ +/* TODO: Find out what that device is for! */ +static int +lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret, j; + u8 b0[] = {reg}; + u8 b1[] = {0}; + u8 b2[] = {reg, data}; + struct i2c_msg msg[3] = { + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b0, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b2, + .len = 2 + }, + }; + + ret = i2c_transfer(state->i2c, msg, 3); + return (ret != 3) ? -1 : 0; +} + + +static void +lgs8gl5_soft_reset(struct lgs8gl5_state *state) +{ + u8 val; + + dprintk("%s\n", __func__); + + val = lgs8gl5_read_reg(state, REG_RESET); + lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); + lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); + msleep(5); +} + + +static int +lgs8gl5_set_inversion(struct lgs8gl5_state *state, int inversion) +{ + u8 val; + + dprintk("%s\n", __func__); + + switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_ON: + val = lgs8gl5_read_reg(state, REG_INVERSION); + return lgs8gl5_write_reg(state, REG_INVERSION, + val | REG_INVERSION_ON); + case INVERSION_OFF: + val = lgs8gl5_read_reg(state, REG_INVERSION); + return lgs8gl5_write_reg(state, REG_INVERSION, + val & ~REG_INVERSION_ON); + default: + return -EINVAL; + } +} + + +/* Starts demodulation */ +static void +lgs8gl5_start_demod(struct lgs8gl5_state *state) +{ + u8 val; + int n; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + lgs8gl5_update_reg(state, REG_03, 0x00); + lgs8gl5_update_reg(state, REG_7E, 0x01); + lgs8gl5_update_alt_reg(state, 0xc5, 0x00); + lgs8gl5_update_reg(state, REG_04, 0x02); + lgs8gl5_update_reg(state, REG_37, 0x01); + lgs8gl5_soft_reset(state); + + /* Wait for carrier */ + for (n = 0; n < 10; n++) { + val = lgs8gl5_read_reg(state, REG_STRENGTH); + dprintk("Wait for carrier[%d] 0x%02X\n", n, val); + if (val & REG_STRENGTH_CARRIER) + break; + msleep(4); + } + if (!(val & REG_STRENGTH_CARRIER)) + return; + + /* Wait for lock */ + for (n = 0; n < 20; n++) { + val = lgs8gl5_read_reg(state, REG_STATUS); + dprintk("Wait for lock[%d] 0x%02X\n", n, val); + if (val & REG_STATUS_LOCK) + break; + msleep(12); + } + if (!(val & REG_STATUS_LOCK)) + return; + + lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); + lgs8gl5_soft_reset(state); +} + + +static int +lgs8gl5_init(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + return 0; +} + + +static int +lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + u8 flags = lgs8gl5_read_reg(state, REG_STATUS); + + *status = 0; + + if ((level & REG_STRENGTH_MASK) > 0) + *status |= FE_HAS_SIGNAL; + if (level & REG_STRENGTH_CARRIER) + *status |= FE_HAS_CARRIER; + if (flags & REG_STATUS_SYNC) + *status |= FE_HAS_SYNC; + if (flags & REG_STATUS_LOCK) + *status |= FE_HAS_LOCK; + + return 0; +} + + +static int +lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + *ber = 0; + + return 0; +} + + +static int +lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *signal_strength = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *snr = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + *ucblocks = 0; + + return 0; +} + + +static int +lgs8gl5_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) + return -EINVAL; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* lgs8gl5_set_inversion(state, p->inversion); */ + + lgs8gl5_start_demod(state); + + return 0; +} + + +static int +lgs8gl5_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); + struct dvb_ofdm_parameters *o = &p->u.ofdm; + + p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; + + o->code_rate_HP = FEC_1_2; + o->code_rate_LP = FEC_7_8; + o->guard_interval = GUARD_INTERVAL_1_32; + o->transmission_mode = TRANSMISSION_MODE_2K; + o->constellation = QAM_64; + o->hierarchy_information = HIERARCHY_NONE; + o->bandwidth = BANDWIDTH_8_MHZ; + + return 0; +} + + +static int +lgs8gl5_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 240; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + + +static void +lgs8gl5_release(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + kfree(state); +} + + +static struct dvb_frontend_ops lgs8gl5_ops; + + +struct dvb_frontend* +lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) +{ + struct lgs8gl5_state *state = NULL; + + dprintk("%s\n", __func__); + + /* Allocate memory for the internal state */ + state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + + /* Check if the demod is there */ + if (lgs8gl5_read_reg(state, REG_RESET) < 0) + goto error; + + /* Create dvb_frontend */ + memcpy(&state->frontend.ops, &lgs8gl5_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lgs8gl5_attach); + + +static struct dvb_frontend_ops lgs8gl5_ops = { + .info = { + .name = "Legend Silicon LGS-8GL5 DMB-TH", + .type = FE_OFDM, + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_BANDWIDTH_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER + }, + + .release = lgs8gl5_release, + + .init = lgs8gl5_init, + + .set_frontend = lgs8gl5_set_frontend, + .get_frontend = lgs8gl5_get_frontend, + .get_tune_settings = lgs8gl5_get_tune_settings, + + .read_status = lgs8gl5_read_status, + .read_ber = lgs8gl5_read_ber, + .read_signal_strength = lgs8gl5_read_signal_strength, + .read_snr = lgs8gl5_read_snr, + .read_ucblocks = lgs8gl5_read_ucblocks, +}; + + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); +MODULE_AUTHOR("Timothy Lee"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/lgs8gl5.h b/drivers/media/dvb/frontends/lgs8gl5.h new file mode 100644 index 000000000000..d14176787a7d --- /dev/null +++ b/drivers/media/dvb/frontends/lgs8gl5.h @@ -0,0 +1,45 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee + + 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 LGS8GL5_H +#define LGS8GL5_H + +#include + +struct lgs8gl5_config { + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_LGS8GL5) || \ + (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) +extern struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGS8GL5 */ + +#endif /* LGS8GL5_H */ -- cgit v1.2.1 From 3a6b974d37370e89637f870657f93fd859e09ee3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 15:29:46 -0300 Subject: V4L/DVB (8658): lgs8gl5: fix build warnings Fix the following build warnings: lgs8gl5.c: In function 'lgs8gl5_read_reg': lgs8gl5.c:95: warning: unused variable 'j' lgs8gl5.c: In function 'lgs8gl5_update_alt_reg': lgs8gl5.c:135: warning: unused variable 'j' lgs8gl5.c: In function 'lgs8gl5_read_ber': lgs8gl5.c:300: warning: unused variable 'state' lgs8gl5.c: In function 'lgs8gl5_read_ucblocks': lgs8gl5.c:332: warning: unused variable 'state' lgs8gl5.c: At top level: lgs8gl5.c:181: warning: 'lgs8gl5_set_inversion' defined but not used Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/lgs8gl5.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c index c0a223d28b0f..855852fddf22 100644 --- a/drivers/media/dvb/frontends/lgs8gl5.c +++ b/drivers/media/dvb/frontends/lgs8gl5.c @@ -92,7 +92,7 @@ lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) static int lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) { - int ret, j; + int ret; u8 b0[] = {reg}; u8 b1[] = {0}; struct i2c_msg msg[2] = { @@ -132,7 +132,7 @@ lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) static int lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) { - int ret, j; + int ret; u8 b0[] = {reg}; u8 b1[] = {0}; u8 b2[] = {reg, data}; @@ -176,30 +176,6 @@ lgs8gl5_soft_reset(struct lgs8gl5_state *state) } -static int -lgs8gl5_set_inversion(struct lgs8gl5_state *state, int inversion) -{ - u8 val; - - dprintk("%s\n", __func__); - - switch (inversion) { - case INVERSION_AUTO: - return -EOPNOTSUPP; - case INVERSION_ON: - val = lgs8gl5_read_reg(state, REG_INVERSION); - return lgs8gl5_write_reg(state, REG_INVERSION, - val | REG_INVERSION_ON); - case INVERSION_OFF: - val = lgs8gl5_read_reg(state, REG_INVERSION); - return lgs8gl5_write_reg(state, REG_INVERSION, - val & ~REG_INVERSION_ON); - default: - return -EINVAL; - } -} - - /* Starts demodulation */ static void lgs8gl5_start_demod(struct lgs8gl5_state *state) @@ -297,7 +273,6 @@ lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) static int lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct lgs8gl5_state *state = fe->demodulator_priv; *ber = 0; return 0; @@ -329,7 +304,6 @@ lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) static int lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct lgs8gl5_state *state = fe->demodulator_priv; *ucblocks = 0; return 0; -- cgit v1.2.1 From 06a3f58496462f25cc031d1cb6d49cb78af1f636 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 19 Aug 2008 20:40:30 -0300 Subject: V4L/DVB (8724): dvb: drx397xD: checkpatch.pl cleanups This driver sure needs some rework. For now, let's try to clean it up a bit before start reimplementing anything. checkpatch.pl still not happy with this driver after this patch, but the most annoying errors are gone, comments now use C-style only, labels are well placed and some other minor fixes. Some more clean up patches will come as I work on this driver. Please review it carefully. Cc: Mauro Carvalho Chehab Cc: Henk Vergonet [mchehab@infradead.org: Manually fixed some conflicts with a previous patch] Signed-off-by: Felipe Balbi Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/drx397xD.c | 242 +++++++++++++++++---------------- 1 file changed, 124 insertions(+), 118 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index e19147bad178..77dd4f2c6260 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -38,35 +38,32 @@ static const char mod_name[] = "drx397xD"; #define F_SET_0D0h 1 #define F_SET_0D4h 2 -typedef enum fw_ix { +enum fw_ix { #define _FW_ENTRY(a, b) b #include "drx397xD_fw.h" -} fw_ix_t; +}; /* chip specifics */ struct drx397xD_state { struct i2c_adapter *i2c; struct dvb_frontend frontend; struct drx397xD_config config; - fw_ix_t chip_rev; + enum fw_ix chip_rev; int flags; u32 bandwidth_parm; /* internal bandwidth conversions */ u32 f_osc; /* w90: actual osc frequency [Hz] */ }; -/******************************************************************************* - * Firmware - ******************************************************************************/ - +/* Firmware */ static const char *blob_name[] = { #define _BLOB_ENTRY(a, b) a #include "drx397xD_fw.h" }; -typedef enum blob_ix { +enum blob_ix { #define _BLOB_ENTRY(a, b) b #include "drx397xD_fw.h" -} blob_ix_t; +}; static struct { const char *name; @@ -85,7 +82,7 @@ static struct { }; /* use only with writer lock aquired */ -static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) +static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix) { memset(&fw[ix].data[0], 0, sizeof(fw[0].data)); if (fw[ix].file) @@ -94,7 +91,7 @@ static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix) static void drx_release_fw(struct drx397xD_state *s) { - fw_ix_t ix = s->chip_rev; + enum fw_ix ix = s->chip_rev; pr_debug("%s\n", __func__); @@ -107,7 +104,7 @@ static void drx_release_fw(struct drx397xD_state *s) write_unlock(&fw[ix].lock); } -static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) +static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix) { const u8 *data; size_t size, len; @@ -175,26 +172,28 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) goto exit_corrupt; } } while (i < size); - exit_corrupt: + +exit_corrupt: printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name); - exit_err: +exit_err: _drx_release_fw(s, ix); fw[ix].refcnt--; - exit_ok: +exit_ok: fw[ix].refcnt++; write_unlock(&fw[ix].lock); + return rc; } -/******************************************************************************* - * i2c bus IO - ******************************************************************************/ - -static int write_fw(struct drx397xD_state *s, blob_ix_t ix) +/* i2c bus IO */ +static int write_fw(struct drx397xD_state *s, enum blob_ix ix) { - struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 }; const u8 *data; int len, rc = 0, i = 0; + struct i2c_msg msg = { + .addr = s->config.demod_address, + .flags = 0 + }; if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { pr_debug("%s drx_fw_ix_t out of range\n", __func__); @@ -229,8 +228,9 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix) goto exit_rc; } } - exit_rc: +exit_rc: read_unlock(&fw[s->chip_rev].lock); + return 0; } @@ -242,17 +242,16 @@ static int _read16(struct drx397xD_state *s, u32 i2c_adr) u16 v; struct i2c_msg msg[2] = { { - .addr = s->config.demod_address, - .flags = 0, - .buf = a, - .len = sizeof(a) - } - , { - .addr = s->config.demod_address, - .flags = I2C_M_RD, - .buf = (u8 *) & v, - .len = sizeof(v) - } + .addr = s->config.demod_address, + .flags = 0, + .buf = a, + .len = sizeof(a) + }, { + .addr = s->config.demod_address, + .flags = I2C_M_RD, + .buf = (u8 *) &v, + .len = sizeof(v) + } }; *(u32 *) a = i2c_adr; @@ -277,27 +276,27 @@ static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) }; *(u32 *) a = i2c_adr; - *(u16 *) & a[4] = val; + *(u16 *) &a[4] = val; rc = i2c_transfer(s->i2c, &msg, 1); if (rc != 1) return -EIO; + return 0; } -#define WR16(ss,adr, val) \ +#define WR16(ss, adr, val) \ _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val)) -#define WR16_E0(ss,adr, val) \ +#define WR16_E0(ss, adr, val) \ _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val)) -#define RD16(ss,adr) \ +#define RD16(ss, adr) \ _read16(ss, I2C_ADR_C0(adr)) -#define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc - -/******************************************************************************* - * Tuner callback - ******************************************************************************/ +#define EXIT_RC(cmd) \ + if ((rc = (cmd)) < 0) \ + goto exit_rc +/* Tuner callback */ static int PLL_Set(struct drx397xD_state *s, struct dvb_frontend_parameters *fep, int *df_tuner) { @@ -331,10 +330,7 @@ static int PLL_Set(struct drx397xD_state *s, return 0; } -/******************************************************************************* - * Demodulator helper functions - ******************************************************************************/ - +/* Demodulator helper functions */ static int SC_WaitForReady(struct drx397xD_state *s) { int cnt = 1000; @@ -347,6 +343,7 @@ static int SC_WaitForReady(struct drx397xD_state *s) if (rc == 0) return 0; } + return -1; } @@ -361,6 +358,7 @@ static int SC_SendCommand(struct drx397xD_state *s, int cmd) rc = RD16(s, 0x820042); if ((rc & 0xffff) == 0xffff) return -1; + return 0; } @@ -383,6 +381,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) if (rc < 0) return rc; } while (--cnt); + return rc; } @@ -392,13 +391,14 @@ static int HI_CfgCommand(struct drx397xD_state *s) pr_debug("%s\n", __func__); WR16(s, 0x420033, 0x3973); - WR16(s, 0x420034, s->config.w50); // code 4, log 4 - WR16(s, 0x420035, s->config.w52); // code 15, log 9 + WR16(s, 0x420034, s->config.w50); /* code 4, log 4 */ + WR16(s, 0x420035, s->config.w52); /* code 15, log 9 */ WR16(s, 0x420036, s->config.demod_address << 1); - WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1 -// WR16(s, 0x420033, 0x3973); + WR16(s, 0x420037, s->config.w56); /* code (set_i2c ?? initX 1 ), log 1 */ + /* WR16(s, 0x420033, 0x3973); */ if ((s->config.w56 & 8) == 0) return HI_Command(s, 3); + return WR16(s, 0x420032, 0x3); } @@ -468,7 +468,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) i = slowIncrDecLUT_15272[rem / 28]; EXIT_RC(WR16(s, 0x0c2002b, i)); rc = WR16(s, 0x0c2002c, i); - exit_rc: +exit_rc: return rc; } @@ -498,7 +498,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) rc &= ~2; break; case 0: - // loc_8000659 + /* loc_8000659 */ s->config.w9C &= ~2; EXIT_RC(WR16(s, 0x0c20015, s->config.w9C)); EXIT_RC(RD16(s, 0x0c20010)); @@ -522,7 +522,8 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) rc |= 2; } rc = WR16(s, 0x0c20013, rc); - exit_rc: + +exit_rc: return rc; } @@ -602,7 +603,8 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) s->config.f_osc * 1000, clk - s->config.f_osc * 1000); } rc = WR16(s, 0x08200e8, 0); - exit_rc: + +exit_rc: return rc; } @@ -620,17 +622,17 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) si &= ~1; bp = 0x200; } - if (s->config.w9A == 0) { + if (s->config.w9A == 0) si |= 0x80; - } else { + else si &= ~0x80; - } EXIT_RC(WR16(s, 0x2150045, 0)); EXIT_RC(WR16(s, 0x2150010, si)); EXIT_RC(WR16(s, 0x2150011, bp)); rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0)); - exit_rc: + +exit_rc: return rc; } @@ -658,7 +660,7 @@ static int drx_tune(struct drx397xD_state *s, rc = ConfigureMPEGOutput(s, 0); if (rc < 0) goto set_tuner; - set_tuner: +set_tuner: rc = PLL_Set(s, fep, &df_tuner); if (rc < 0) { @@ -835,16 +837,16 @@ static int drx_tune(struct drx397xD_state *s, rc = WR16(s, 0x2010012, 0); if (rc < 0) goto exit_rc; - // QPSK QAM16 QAM64 - ebx = 0x19f; // 62 - ebp = 0x1fb; // 15 - v20 = 0x16a; // 62 - v1E = 0x195; // 62 - v16 = 0x1bb; // 15 - v14 = 0x1ef; // 15 - v12 = 5; // 16 - v10 = 5; // 16 - v0E = 5; // 16 + /* QPSK QAM16 QAM64 */ + ebx = 0x19f; /* 62 */ + ebp = 0x1fb; /* 15 */ + v20 = 0x16a; /* 62 */ + v1E = 0x195; /* 62 */ + v16 = 0x1bb; /* 15 */ + v14 = 0x1ef; /* 15 */ + v12 = 5; /* 16 */ + v10 = 5; /* 16 */ + v0E = 5; /* 16 */ } switch (fep->u.ofdm.constellation) { @@ -997,17 +999,17 @@ static int drx_tune(struct drx397xD_state *s, case BANDWIDTH_8_MHZ: /* 0 */ case BANDWIDTH_AUTO: rc = WR16(s, 0x0c2003f, 0x32); - s->bandwidth_parm = ebx = 0x8b8249; // 9142857 + s->bandwidth_parm = ebx = 0x8b8249; edx = 0; break; case BANDWIDTH_7_MHZ: rc = WR16(s, 0x0c2003f, 0x3b); - s->bandwidth_parm = ebx = 0x7a1200; // 8000000 + s->bandwidth_parm = ebx = 0x7a1200; edx = 0x4807; break; case BANDWIDTH_6_MHZ: rc = WR16(s, 0x0c2003f, 0x47); - s->bandwidth_parm = ebx = 0x68a1b6; // 6857142 + s->bandwidth_parm = ebx = 0x68a1b6; edx = 0x0f07; break; }; @@ -1060,8 +1062,6 @@ static int drx_tune(struct drx397xD_state *s, WR16(s, 0x0820040, 1); SC_SendCommand(s, 1); -// rc = WR16(s, 0x2150000, 1); -// if (rc < 0) goto exit_rc; rc = WR16(s, 0x2150000, 2); rc = WR16(s, 0x2150016, a); @@ -1069,7 +1069,8 @@ static int drx_tune(struct drx397xD_state *s, rc = WR16(s, 0x2150036, 0); rc = WR16(s, 0x2150000, 1); s->config.d60 = 2; - exit_rc: + +exit_rc: return rc; } @@ -1102,18 +1103,18 @@ static int drx397x_init(struct dvb_frontend *fe) /* HI_CfgCommand */ s->config.w50 = 4; - s->config.w52 = 9; // 0xf; + s->config.w52 = 9; - s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ - s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ - s->config.w92 = 12000; // 20000; + s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */ + s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */ + s->config.w92 = 12000; s->config.w9C = 0x000e; s->config.w9E = 0x0000; /* ConfigureMPEGOutput params */ s->config.wA0 = 4; - s->config.w98 = 1; // 0; + s->config.w98 = 1; s->config.w9A = 1; /* get chip revision */ @@ -1248,7 +1249,7 @@ static int drx397x_init(struct dvb_frontend *fe) rc = WR16(s, 0x0c20012, 1); } - write_DRXD_InitFE_1: +write_DRXD_InitFE_1: rc = write_fw(s, DRXD_InitFE_1); if (rc < 0) @@ -1311,7 +1312,8 @@ static int drx397x_init(struct dvb_frontend *fe) s->config.d5C = 0; s->config.d60 = 1; s->config.d48 = 1; - error: + +error: return rc; } @@ -1326,7 +1328,8 @@ static int drx397x_set_frontend(struct dvb_frontend *fe, { struct drx397xD_state *s = fe->demodulator_priv; - s->config.s20d24 = 1; // 0; + s->config.s20d24 = 1; + return drx_tune(s, params); } @@ -1337,18 +1340,16 @@ static int drx397x_get_tune_settings(struct dvb_frontend *fe, fe_tune_settings->min_delay_ms = 10000; fe_tune_settings->step_size = 0; fe_tune_settings->max_drift = 0; + return 0; } -static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) +static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct drx397xD_state *s = fe->demodulator_priv; int lockstat; GetLockStatus(s, &lockstat); - /* TODO */ -// if (lockstat & 1) -// CorrectSysClockDeviation(s); *status = 0; if (lockstat & 2) { @@ -1356,9 +1357,8 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) ConfigureMPEGOutput(s, 1); *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; } - if (lockstat & 4) { + if (lockstat & 4) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; - } return 0; } @@ -1366,16 +1366,18 @@ static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status) static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber) { *ber = 0; + return 0; } -static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr) +static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr) { *snr = 0; + return 0; } -static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct drx397xD_state *s = fe->demodulator_priv; int rc; @@ -1401,6 +1403,7 @@ static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength) * The following does the same but with less rounding errors: */ *strength = ~(7720 + (rc * 30744 >> 10)); + return 0; } @@ -1408,6 +1411,7 @@ static int drx397x_read_ucblocks(struct dvb_frontend *fe, unsigned int *ucblocks) { *ucblocks = 0; + return 0; } @@ -1436,22 +1440,22 @@ static struct dvb_frontend_ops drx397x_ops = { .frequency_max = 855250000, .frequency_stepsize = 166667, .frequency_tolerance = 0, - .caps = /* 0x0C01B2EAE */ - FE_CAN_FEC_1_2 | // = 0x2, - FE_CAN_FEC_2_3 | // = 0x4, - FE_CAN_FEC_3_4 | // = 0x8, - FE_CAN_FEC_5_6 | // = 0x20, - FE_CAN_FEC_7_8 | // = 0x80, - FE_CAN_FEC_AUTO | // = 0x200, - FE_CAN_QPSK | // = 0x400, - FE_CAN_QAM_16 | // = 0x800, - FE_CAN_QAM_64 | // = 0x2000, - FE_CAN_QAM_AUTO | // = 0x10000, - FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000, - FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000, - FE_CAN_HIERARCHY_AUTO | // = 0x100000, - FE_CAN_RECOVER | // = 0x40000000, - FE_CAN_MUTE_TS // = 0x80000000 + .caps = /* 0x0C01B2EAE */ + FE_CAN_FEC_1_2 | /* = 0x2, */ + FE_CAN_FEC_2_3 | /* = 0x4, */ + FE_CAN_FEC_3_4 | /* = 0x8, */ + FE_CAN_FEC_5_6 | /* = 0x20, */ + FE_CAN_FEC_7_8 | /* = 0x80, */ + FE_CAN_FEC_AUTO | /* = 0x200, */ + FE_CAN_QPSK | /* = 0x400, */ + FE_CAN_QAM_16 | /* = 0x800, */ + FE_CAN_QAM_64 | /* = 0x2000, */ + FE_CAN_QAM_AUTO | /* = 0x10000, */ + FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */ + FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */ + FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */ + FE_CAN_RECOVER | /* = 0x40000000, */ + FE_CAN_MUTE_TS /* = 0x80000000 */ }, .release = drx397x_release, @@ -1472,33 +1476,35 @@ static struct dvb_frontend_ops drx397x_ops = { struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, struct i2c_adapter *i2c) { - struct drx397xD_state *s = NULL; + struct drx397xD_state *state; /* allocate memory for the internal state */ - s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); - if (s == NULL) + state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL); + if (!state) goto error; /* setup the state */ - s->i2c = i2c; - memcpy(&s->config, config, sizeof(struct drx397xD_config)); + state->i2c = i2c; + memcpy(&state->config, config, sizeof(struct drx397xD_config)); /* check if the demod is there */ if (RD16(s, 0x2410019) < 0) goto error; /* create dvb_frontend */ - memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops)); - s->frontend.demodulator_priv = s; + memcpy(&state->frontend.ops, &drx397x_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = s; + + return &state->frontend; +error: + kfree(state); - return &s->frontend; - error: - kfree(s); return NULL; } +EXPORT_SYMBOL(drx397xD_attach); MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend"); MODULE_AUTHOR("Henk Vergonet"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(drx397xD_attach); -- cgit v1.2.1 From 95908ece60443ceb188fccf021d62823de8e6f0c Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 20 Aug 2008 20:44:50 -0300 Subject: V4L/DVB (8725): drx397xD.c sparse annotations Signed-off-by: Harvey Harrison Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/drx397xD.c | 14 +++++++------- drivers/media/dvb/frontends/drx397xD.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index 77dd4f2c6260..0cf3af2f7da2 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -235,11 +235,11 @@ exit_rc: } /* Function is not endian safe, use the RD16 wrapper below */ -static int _read16(struct drx397xD_state *s, u32 i2c_adr) +static int _read16(struct drx397xD_state *s, __le32 i2c_adr) { int rc; u8 a[4]; - u16 v; + __le16 v; struct i2c_msg msg[2] = { { .addr = s->config.demod_address, @@ -249,12 +249,12 @@ static int _read16(struct drx397xD_state *s, u32 i2c_adr) }, { .addr = s->config.demod_address, .flags = I2C_M_RD, - .buf = (u8 *) &v, + .buf = (u8 *)&v, .len = sizeof(v) } }; - *(u32 *) a = i2c_adr; + *(__le32 *) a = i2c_adr; rc = i2c_transfer(s->i2c, msg, 2); if (rc != 2) @@ -264,7 +264,7 @@ static int _read16(struct drx397xD_state *s, u32 i2c_adr) } /* Function is not endian safe, use the WR16.. wrappers below */ -static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) +static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val) { u8 a[6]; int rc; @@ -275,8 +275,8 @@ static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val) .len = sizeof(a) }; - *(u32 *) a = i2c_adr; - *(u16 *) &a[4] = val; + *(__le32 *)a = i2c_adr; + *(__le16 *)&a[4] = val; rc = i2c_transfer(s->i2c, &msg, 1); if (rc != 1) diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h index 2ad1ea0ccfb0..ba05d17290c6 100644 --- a/drivers/media/dvb/frontends/drx397xD.h +++ b/drivers/media/dvb/frontends/drx397xD.h @@ -28,7 +28,7 @@ #define DRX_F_OFFSET 36000000 #define I2C_ADR_C0(x) \ -( (u32)cpu_to_le32( \ +( cpu_to_le32( \ (u32)( \ (((u32)(x) & (u32)0x000000ffUL) ) | \ (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ @@ -38,7 +38,7 @@ ) #define I2C_ADR_E0(x) \ -( (u32)cpu_to_le32( \ +( cpu_to_le32( \ (u32)( \ (((u32)(x) & (u32)0x000000ffUL) ) | \ (((u32)(x) & (u32)0x0000ff00UL) << 16) | \ -- cgit v1.2.1 From 06fcadbf8b63e395d3ae8421a8c3cb2dfd0bc56b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Aug 2008 13:31:59 -0300 Subject: V4L/DVB (8730): drx397xD: fix compilation error caused by changeset 71046dfb0853 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/drx397xD.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index 0cf3af2f7da2..b9ca5c8d2dd9 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -1488,13 +1488,13 @@ struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config, memcpy(&state->config, config, sizeof(struct drx397xD_config)); /* check if the demod is there */ - if (RD16(s, 0x2410019) < 0) + if (RD16(state, 0x2410019) < 0) goto error; /* create dvb_frontend */ memcpy(&state->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = s; + state->frontend.demodulator_priv = state; return &state->frontend; error: -- cgit v1.2.1 From 8466028be7926679ff794ec2ed7a8938eafba521 Mon Sep 17 00:00:00 2001 From: Antoine Jacquet Date: Mon, 11 Aug 2008 13:12:19 -0300 Subject: V4L/DVB (8734): Initial support for AME DTV-5100 USB2.0 DVB-T Basic support for AME DTV-5100 USB2.0 DVB-T using the qt1010 tuner and a dummy frontend. Signed-off-by: Antoine Jacquet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 7 ++ drivers/media/dvb/dvb-usb/Makefile | 3 + drivers/media/dvb/dvb-usb/dtv5100-fe.c | 147 ++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dtv5100.c | 217 +++++++++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dtv5100.h | 128 +++++++++++++++++++ 5 files changed, 502 insertions(+) create mode 100644 drivers/media/dvb/dvb-usb/dtv5100-fe.c create mode 100644 drivers/media/dvb/dvb-usb/dtv5100.c create mode 100644 drivers/media/dvb/dvb-usb/dtv5100.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 8a54cb48322f..1d9e98cee9e7 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -264,3 +264,10 @@ config DVB_USB_ANYSEE help Say Y here to support the Anysee E30, Anysee E30 Plus or Anysee E30 C Plus DVB USB2.0 receiver. + +config DVB_USB_DTV5100 + tristate "AME DTV-5100 USB2.0 DVB-T support" + depends on DVB_USB + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + help + Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index e206f1ea0027..5e170fba1092 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -67,6 +67,9 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o dvb-usb-dw2102-objs = dw2102.o obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o +dvb-usb-dtv5100-objs = dtv5100.o dtv5100-fe.o +obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/dtv5100-fe.c b/drivers/media/dvb/dvb-usb/dtv5100-fe.c new file mode 100644 index 000000000000..08fe33bcc5d6 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtv5100-fe.c @@ -0,0 +1,147 @@ +/* + * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T + * + * Copyright (C) 2008 Antoine Jacquet + * http://royale.zerezo.com/dtv5100/ + * + * Inspired by dvb_dummy_fe.c + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "dvb-usb.h" +#include "qt1010_priv.h" + +struct dtv5100_fe_state { + struct dvb_frontend frontend; +}; + +static int dtv5100_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + *status = FE_HAS_SIGNAL + | FE_HAS_CARRIER + | FE_HAS_VITERBI + | FE_HAS_SYNC + | FE_HAS_LOCK; + + return 0; +} + +static int dtv5100_fe_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; + return 0; +} + +static int dtv5100_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + *strength = 0; + return 0; +} + +static int dtv5100_fe_read_snr(struct dvb_frontend* fe, u16* snr) +{ + *snr = 0; + return 0; +} + +static int dtv5100_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + *ucblocks = 0; + return 0; +} + +static int dtv5100_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + return 0; +} + +static int dtv5100_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + return 0; +} + +static int dtv5100_fe_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int dtv5100_fe_init(struct dvb_frontend* fe) +{ + return 0; +} + +static void dtv5100_fe_release(struct dvb_frontend* fe) +{ + struct dtv5100_fe_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops dtv5100_fe_ops; + +struct dvb_frontend* dtv5100_fe_attach(void) +{ + struct dtv5100_fe_state* state = NULL; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct dtv5100_fe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &dtv5100_fe_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops dtv5100_fe_ops = { + + .info = { + .name = "Dummy DVB-T", + .type = FE_OFDM, + .frequency_min = QT1010_MIN_FREQ, + .frequency_max = QT1010_MAX_FREQ, + .frequency_stepsize = QT1010_STEP, + .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, + }, + + .release = dtv5100_fe_release, + + .init = dtv5100_fe_init, + .sleep = dtv5100_fe_sleep, + + .set_frontend = dtv5100_fe_set_frontend, + .get_frontend = dtv5100_fe_get_frontend, + + .read_status = dtv5100_fe_read_status, + .read_ber = dtv5100_fe_read_ber, + .read_signal_strength = dtv5100_fe_read_signal_strength, + .read_snr = dtv5100_fe_read_snr, + .read_ucblocks = dtv5100_fe_read_ucblocks, +}; diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c new file mode 100644 index 000000000000..f89d01755eab --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtv5100.c @@ -0,0 +1,217 @@ +/* + * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T + * + * Copyright (C) 2008 Antoine Jacquet + * http://royale.zerezo.com/dtv5100/ + * + * Inspired by gl861.c and au6610.c drivers + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "dtv5100.h" +#include "qt1010.h" + +/* debug */ +static int dvb_usb_dtv5100_debug; +module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int dtv5100_read_reg(struct dvb_usb_device *d, u8 addr, u8 reg, u8 *value) +{ + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + DTV5100_I2C_READ, USB_TYPE_VENDOR|USB_DIR_IN, + 0, (addr << 8) + reg, value, 1, + DTV5100_USB_TIMEOUT); +} + +static int dtv5100_write_reg(struct dvb_usb_device *d, u8 addr, u8 reg, u8 value) +{ + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + DTV5100_I2C_WRITE, USB_TYPE_VENDOR|USB_DIR_OUT, + value, (addr << 8) + reg, NULL, 0, + DTV5100_USB_TIMEOUT); +} + +/* I2C */ +static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (num > 2) + return -EINVAL; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + /* write/read request, 2 messages + * msg = { + * { reg }, + * { val }, + * } + */ + if (dtv5100_read_reg(d, msg[i].addr, msg[i].buf[0], msg[i+1].buf) < 0) + break; + i++; + } else { + /* write request, 1 message + * msg = { + * { reg, val }, + * } + */ + if (dtv5100_write_reg(d, msg[i].addr, msg[i].buf[0], msg[i].buf[1]) < 0) + break; + } + } + + mutex_unlock(&d->i2c_mutex); + return i; +} + +static u32 dtv5100_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dtv5100_i2c_algo = { + .master_xfer = dtv5100_i2c_xfer, + .functionality = dtv5100_i2c_func, +}; + +/* Callbacks for DVB USB */ +static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) +{ + adap->fe = dtv5100_fe_attach(); + return 0; +} + +static struct qt1010_config dtv5100_qt1010_config = { + .i2c_address = 0xc4 +}; + +static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(qt1010_attach, + adap->fe, &adap->dev->i2c_adap, + &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties dtv5100_properties; + +static int dtv5100_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int i, ret; + struct usb_device *udev = interface_to_usbdev(intf); + + ret = dvb_usb_device_init(intf, &dtv5100_properties, + THIS_MODULE, NULL, adapter_nr); + if (ret) + return ret; + + /* initialize frontend & non qt1010 part? */ + for (i = 0; dtv5100_init[i].request; i++) + { + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + dtv5100_init[i].request, + USB_TYPE_VENDOR|USB_DIR_OUT, + dtv5100_init[i].value, + dtv5100_init[i].index, NULL, 0, + DTV5100_USB_TIMEOUT); + if (ret) + return ret; + } + + return 0; +} + +static struct usb_device_id dtv5100_table [] = { + { USB_DEVICE(0x06be, 0xa232) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, dtv5100_table); + +static struct dvb_usb_device_properties dtv5100_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + + .size_of_priv = 0, + + .num_adapters = 1, + .adapter = {{ + .frontend_attach = dtv5100_frontend_attach, + .tuner_attach = dtv5100_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } }, + + .i2c_algo = &dtv5100_i2c_algo, + + .num_device_descs = 1, + .devices = { + { + .name = "AME DTV-5100 USB2.0 DVB-T", + .cold_ids = { NULL }, + .warm_ids = { &dtv5100_table[0], NULL }, + }, + } +}; + +static struct usb_driver dtv5100_driver = { + .name = "dvb_usb_dtv5100", + .probe = dtv5100_probe, + .disconnect = dvb_usb_device_exit, + .id_table = dtv5100_table, +}; + +/* module stuff */ +static int __init dtv5100_module_init(void) +{ + int ret; + + ret = usb_register(&dtv5100_driver); + if (ret) + err("usb_register failed. Error number %d", ret); + + return ret; +} + +static void __exit dtv5100_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dtv5100_driver); +} + +module_init(dtv5100_module_init); +module_exit(dtv5100_module_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h new file mode 100644 index 000000000000..1aadb86f70e6 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dtv5100.h @@ -0,0 +1,128 @@ +/* + * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T + * + * Copyright (C) 2008 Antoine Jacquet + * http://royale.zerezo.com/dtv5100/ + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _DVB_USB_DTV5100_H_ +#define _DVB_USB_DTV5100_H_ + +#define DVB_USB_LOG_PREFIX "dtv5100" +#include "dvb-usb.h" + +#define DTV5100_USB_TIMEOUT 500 +#define DTV5100_I2C_WRITE 0xc7 +#define DTV5100_I2C_READ 0xc8 + +#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" +#define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T" + +static struct { + u8 request; + u8 value; + u16 index; +} dtv5100_init[] = { + { 0x000000c5, 0x00000000, 0x00000001 }, + { 0x000000c5, 0x00000001, 0x00000001 }, + { 0x000000c0, 0x0000000b, 0x00000050 }, + { 0x000000c0, 0x00000044, 0x00000051 }, + { 0x000000c0, 0x00000046, 0x00000052 }, + { 0x000000c0, 0x00000015, 0x00000053 }, + { 0x000000c0, 0x0000000f, 0x00000054 }, + { 0x000000c0, 0x00000080, 0x00000055 }, + { 0x000000c0, 0x00000001, 0x000000ea }, + { 0x000000c0, 0x00000000, 0x000000ea }, + { 0x000000c0, 0x00000075, 0x0000005c }, + { 0x000000c0, 0x000000a1, 0x0000009c }, + { 0x000000c0, 0x00000000, 0x0000008e }, + { 0x000000c0, 0x00000000, 0x00000090 }, + { 0x000000c0, 0x000000ff, 0x00000091 }, + { 0x000000c0, 0x000000ff, 0x00000092 }, + { 0x000000c0, 0x00000000, 0x00000093 }, + { 0x000000c0, 0x000000ff, 0x00000094 }, + { 0x000000c0, 0x00000000, 0x00000058 }, + { 0x000000c0, 0x0000003f, 0x00000095 }, + { 0x000000c0, 0x0000003f, 0x00000096 }, + { 0x000000c0, 0x0000000c, 0x0000005a }, + { 0x000000c0, 0x0000002b, 0x00000056 }, + { 0x000000c0, 0x00000017, 0x0000005f }, + { 0x000000c0, 0x00000040, 0x0000005e }, + { 0x000000c0, 0x00000036, 0x00000064 }, + { 0x000000c0, 0x00000067, 0x00000065 }, + { 0x000000c0, 0x000000e5, 0x00000066 }, + { 0x000000c0, 0x00000073, 0x000000cc }, + { 0x000000c0, 0x000000cd, 0x0000006c }, + { 0x000000c0, 0x0000007e, 0x0000006d }, + { 0x000000c0, 0x00000001, 0x00000071 }, + { 0x000000c0, 0x00000001, 0x00000070 }, + /**/ + { 0x000000c7, 0x00000080, 0x0000c401 }, + { 0x000000c7, 0x0000003f, 0x0000c402 }, + { 0x000000c7, 0x00000034, 0x0000c405 }, // 2 + { 0x000000c7, 0x00000044, 0x0000c406 }, + { 0x000000c7, 0x00000038, 0x0000c407 }, // 4 + { 0x000000c7, 0x00000008, 0x0000c408 }, + { 0x000000c7, 0x0000001c, 0x0000c409 }, // 6 + { 0x000000c7, 0x0000000d, 0x0000c40a }, // 7 + { 0x000000c7, 0x00000045, 0x0000c40b }, // 8 + { 0x000000c7, 0x000000e1, 0x0000c40c }, + { 0x000000c7, 0x00000078, 0x0000c41a }, // 10 + { 0x000000c7, 0x00000000, 0x0000c41b }, + { 0x000000c7, 0x00000089, 0x0000c41c }, + { 0x000000c7, 0x000000fd, 0x0000c411 }, // 13 + { 0x000000c7, 0x00000095, 0x0000c412 }, // 14 + { 0x000000c7, 0x000000d6, 0x0000c422 }, // 15 + { 0x000000c7, 0x00000000, 0x0000c41e }, + { 0x000000c7, 0x000000d0, 0x0000c41e }, + { 0x000000c8, 0x00000000, 0x0000c422 }, + { 0x000000c7, 0x00000000, 0x0000c41e }, + { 0x000000c8, 0x00000000, 0x0000c405 }, + { 0x000000c8, 0x00000000, 0x0000c422 }, + { 0x000000c7, 0x000000d0, 0x0000c423 }, + { 0x000000c7, 0x00000000, 0x0000c41e }, + { 0x000000c7, 0x000000e0, 0x0000c41e }, + { 0x000000c8, 0x00000000, 0x0000c423 }, + { 0x000000c8, 0x00000000, 0x0000c423 }, + { 0x000000c7, 0x00000000, 0x0000c41e }, + { 0x000000c7, 0x000000d0, 0x0000c424 }, + { 0x000000c7, 0x00000000, 0x0000c41e }, + { 0x000000c7, 0x000000f0, 0x0000c41e }, + { 0x000000c8, 0x00000000, 0x0000c424 }, + { 0x000000c7, 0x00000000, 0x0000c41e }, + { 0x000000c7, 0x0000007f, 0x0000c414 }, + { 0x000000c7, 0x0000007f, 0x0000c415 }, + { 0x000000c7, 0x00000030, 0x0000c405 }, + { 0x000000c7, 0x00000000, 0x0000c406 }, + { 0x000000c7, 0x0000001f, 0x0000c415 }, + { 0x000000c7, 0x000000ff, 0x0000c416 }, + { 0x000000c7, 0x000000ff, 0x0000c418 }, + { 0x000000c7, 0x00000051, 0x0000c41f }, // here + { 0x000000c7, 0x00000016, 0x0000c420 }, // here + { 0x000000c7, 0x00000053, 0x0000c421 }, + { 0x000000c7, 0x000000c1, 0x0000c425 }, // here + { 0x000000c7, 0x00000014, 0x0000c426 }, // here + { 0x000000c7, 0x00000082, 0x0000c400 }, + { 0x000000c7, 0x00000000, 0x0000c402 }, + { 0x000000c7, 0x00000000, 0x0000c401 }, + /**/ + { } /* Terminating entry */ +}; + +extern struct dvb_frontend* dtv5100_fe_attach(void); + +#endif -- cgit v1.2.1 From 60688d5e6e6e2ae62f29762d1e3b2aec2dbd3817 Mon Sep 17 00:00:00 2001 From: Antoine Jacquet Date: Mon, 11 Aug 2008 19:21:33 -0300 Subject: V4L/DVB (8735): dtv5100: replace dummy frontend by zl10353 Remove the dtv5100-fe.c dummy frontend and replace it by the real frontend for the chipset. Signed-off-by: Antoine Jacquet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Makefile | 2 +- drivers/media/dvb/dvb-usb/dtv5100-fe.c | 147 --------------------------------- drivers/media/dvb/dvb-usb/dtv5100.c | 94 +++++++++++++-------- drivers/media/dvb/dvb-usb/dtv5100.h | 91 ++------------------ 4 files changed, 68 insertions(+), 266 deletions(-) delete mode 100644 drivers/media/dvb/dvb-usb/dtv5100-fe.c (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 5e170fba1092..116544f4272d 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -67,7 +67,7 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o dvb-usb-dw2102-objs = dw2102.o obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o -dvb-usb-dtv5100-objs = dtv5100.o dtv5100-fe.o +dvb-usb-dtv5100-objs = dtv5100.o obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/dvb-usb/dtv5100-fe.c b/drivers/media/dvb/dvb-usb/dtv5100-fe.c deleted file mode 100644 index 08fe33bcc5d6..000000000000 --- a/drivers/media/dvb/dvb-usb/dtv5100-fe.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T - * - * Copyright (C) 2008 Antoine Jacquet - * http://royale.zerezo.com/dtv5100/ - * - * Inspired by dvb_dummy_fe.c - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "dvb-usb.h" -#include "qt1010_priv.h" - -struct dtv5100_fe_state { - struct dvb_frontend frontend; -}; - -static int dtv5100_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) -{ - *status = FE_HAS_SIGNAL - | FE_HAS_CARRIER - | FE_HAS_VITERBI - | FE_HAS_SYNC - | FE_HAS_LOCK; - - return 0; -} - -static int dtv5100_fe_read_ber(struct dvb_frontend* fe, u32* ber) -{ - *ber = 0; - return 0; -} - -static int dtv5100_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) -{ - *strength = 0; - return 0; -} - -static int dtv5100_fe_read_snr(struct dvb_frontend* fe, u16* snr) -{ - *snr = 0; - return 0; -} - -static int dtv5100_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) -{ - *ucblocks = 0; - return 0; -} - -static int dtv5100_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - return 0; -} - -static int dtv5100_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) -{ - if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - } - - return 0; -} - -static int dtv5100_fe_sleep(struct dvb_frontend* fe) -{ - return 0; -} - -static int dtv5100_fe_init(struct dvb_frontend* fe) -{ - return 0; -} - -static void dtv5100_fe_release(struct dvb_frontend* fe) -{ - struct dtv5100_fe_state* state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops dtv5100_fe_ops; - -struct dvb_frontend* dtv5100_fe_attach(void) -{ - struct dtv5100_fe_state* state = NULL; - - /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct dtv5100_fe_state), GFP_KERNEL); - if (state == NULL) goto error; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, &dtv5100_fe_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; - return &state->frontend; - -error: - kfree(state); - return NULL; -} - -static struct dvb_frontend_ops dtv5100_fe_ops = { - - .info = { - .name = "Dummy DVB-T", - .type = FE_OFDM, - .frequency_min = QT1010_MIN_FREQ, - .frequency_max = QT1010_MAX_FREQ, - .frequency_stepsize = QT1010_STEP, - .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, - }, - - .release = dtv5100_fe_release, - - .init = dtv5100_fe_init, - .sleep = dtv5100_fe_sleep, - - .set_frontend = dtv5100_fe_set_frontend, - .get_frontend = dtv5100_fe_get_frontend, - - .read_status = dtv5100_fe_read_status, - .read_ber = dtv5100_fe_read_ber, - .read_signal_strength = dtv5100_fe_read_signal_strength, - .read_snr = dtv5100_fe_read_snr, - .read_ucblocks = dtv5100_fe_read_ucblocks, -}; diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c index f89d01755eab..7168a49cecf4 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.c +++ b/drivers/media/dvb/dvb-usb/dtv5100.c @@ -22,6 +22,7 @@ */ #include "dtv5100.h" +#include "zl10353.h" #include "qt1010.h" /* debug */ @@ -30,25 +31,44 @@ module_param_named(debug, dvb_usb_dtv5100_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static int dtv5100_read_reg(struct dvb_usb_device *d, u8 addr, u8 reg, u8 *value) +static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { - return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - DTV5100_I2C_READ, USB_TYPE_VENDOR|USB_DIR_IN, - 0, (addr << 8) + reg, value, 1, - DTV5100_USB_TIMEOUT); -} + u8 request; + u8 type; + u16 value; + u16 index; + + switch (wlen) { + case 1: + /* write { reg }, read { value } */ + request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : + DTV5100_TUNER_READ); + type = USB_TYPE_VENDOR|USB_DIR_IN; + value = 0; + break; + case 2: + /* write { reg, value } */ + request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : + DTV5100_TUNER_WRITE); + type = USB_TYPE_VENDOR|USB_DIR_OUT; + value = wbuf[1]; + break; + default: + warn("wlen = %x, aborting.", wlen); + return -EINVAL; + } + index = (addr << 8) + wbuf[0]; -static int dtv5100_write_reg(struct dvb_usb_device *d, u8 addr, u8 reg, u8 value) -{ - return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - DTV5100_I2C_WRITE, USB_TYPE_VENDOR|USB_DIR_OUT, - value, (addr << 8) + reg, NULL, 0, + msleep(1); /* avoid I2C errors */ + return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), request, + type, value, index, rbuf, rlen, DTV5100_USB_TIMEOUT); } /* I2C */ static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; @@ -60,25 +80,16 @@ static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], return -EAGAIN; for (i = 0; i < num; i++) { + /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - /* write/read request, 2 messages - * msg = { - * { reg }, - * { val }, - * } - */ - if (dtv5100_read_reg(d, msg[i].addr, msg[i].buf[0], msg[i+1].buf) < 0) + if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, msg[i+1].buf, + msg[i+1].len) < 0) break; i++; - } else { - /* write request, 1 message - * msg = { - * { reg, val }, - * } - */ - if (dtv5100_write_reg(d, msg[i].addr, msg[i].buf[0], msg[i].buf[1]) < 0) + } else if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf, + msg[i].len, NULL, 0) < 0) break; - } } mutex_unlock(&d->i2c_mutex); @@ -96,14 +107,27 @@ static struct i2c_algorithm dtv5100_i2c_algo = { }; /* Callbacks for DVB USB */ +static struct zl10353_config dtv5100_zl10353_config = { + .demod_address = DTV5100_DEMOD_ADDR, + .no_tuner = 1, + .parallel_ts = 1, +}; + static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dtv5100_fe_attach(); + adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + /* disable i2c gate, or it won't work... is this safe? */ + adap->fe->ops.i2c_gate_ctrl = NULL; + return 0; } static struct qt1010_config dtv5100_qt1010_config = { - .i2c_address = 0xc4 + .i2c_address = DTV5100_TUNER_ADDR }; static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) @@ -122,12 +146,7 @@ static int dtv5100_probe(struct usb_interface *intf, int i, ret; struct usb_device *udev = interface_to_usbdev(intf); - ret = dvb_usb_device_init(intf, &dtv5100_properties, - THIS_MODULE, NULL, adapter_nr); - if (ret) - return ret; - - /* initialize frontend & non qt1010 part? */ + /* initialize non qt1010/zl10353 part? */ for (i = 0; dtv5100_init[i].request; i++) { ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), @@ -140,6 +159,11 @@ static int dtv5100_probe(struct usb_interface *intf, return ret; } + ret = dvb_usb_device_init(intf, &dtv5100_properties, + THIS_MODULE, NULL, adapter_nr); + if (ret) + return ret; + return 0; } diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h index 1aadb86f70e6..e36bf2d5c944 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.h +++ b/drivers/media/dvb/dvb-usb/dtv5100.h @@ -26,8 +26,14 @@ #include "dvb-usb.h" #define DTV5100_USB_TIMEOUT 500 -#define DTV5100_I2C_WRITE 0xc7 -#define DTV5100_I2C_READ 0xc8 + +#define DTV5100_DEMOD_ADDR 0x00 +#define DTV5100_DEMOD_WRITE 0xc0 +#define DTV5100_DEMOD_READ 0xc1 + +#define DTV5100_TUNER_ADDR 0xc4 +#define DTV5100_TUNER_WRITE 0xc7 +#define DTV5100_TUNER_READ 0xc8 #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" #define DRIVER_DESC "AME DTV-5100 USB2.0 DVB-T" @@ -39,87 +45,6 @@ static struct { } dtv5100_init[] = { { 0x000000c5, 0x00000000, 0x00000001 }, { 0x000000c5, 0x00000001, 0x00000001 }, - { 0x000000c0, 0x0000000b, 0x00000050 }, - { 0x000000c0, 0x00000044, 0x00000051 }, - { 0x000000c0, 0x00000046, 0x00000052 }, - { 0x000000c0, 0x00000015, 0x00000053 }, - { 0x000000c0, 0x0000000f, 0x00000054 }, - { 0x000000c0, 0x00000080, 0x00000055 }, - { 0x000000c0, 0x00000001, 0x000000ea }, - { 0x000000c0, 0x00000000, 0x000000ea }, - { 0x000000c0, 0x00000075, 0x0000005c }, - { 0x000000c0, 0x000000a1, 0x0000009c }, - { 0x000000c0, 0x00000000, 0x0000008e }, - { 0x000000c0, 0x00000000, 0x00000090 }, - { 0x000000c0, 0x000000ff, 0x00000091 }, - { 0x000000c0, 0x000000ff, 0x00000092 }, - { 0x000000c0, 0x00000000, 0x00000093 }, - { 0x000000c0, 0x000000ff, 0x00000094 }, - { 0x000000c0, 0x00000000, 0x00000058 }, - { 0x000000c0, 0x0000003f, 0x00000095 }, - { 0x000000c0, 0x0000003f, 0x00000096 }, - { 0x000000c0, 0x0000000c, 0x0000005a }, - { 0x000000c0, 0x0000002b, 0x00000056 }, - { 0x000000c0, 0x00000017, 0x0000005f }, - { 0x000000c0, 0x00000040, 0x0000005e }, - { 0x000000c0, 0x00000036, 0x00000064 }, - { 0x000000c0, 0x00000067, 0x00000065 }, - { 0x000000c0, 0x000000e5, 0x00000066 }, - { 0x000000c0, 0x00000073, 0x000000cc }, - { 0x000000c0, 0x000000cd, 0x0000006c }, - { 0x000000c0, 0x0000007e, 0x0000006d }, - { 0x000000c0, 0x00000001, 0x00000071 }, - { 0x000000c0, 0x00000001, 0x00000070 }, - /**/ - { 0x000000c7, 0x00000080, 0x0000c401 }, - { 0x000000c7, 0x0000003f, 0x0000c402 }, - { 0x000000c7, 0x00000034, 0x0000c405 }, // 2 - { 0x000000c7, 0x00000044, 0x0000c406 }, - { 0x000000c7, 0x00000038, 0x0000c407 }, // 4 - { 0x000000c7, 0x00000008, 0x0000c408 }, - { 0x000000c7, 0x0000001c, 0x0000c409 }, // 6 - { 0x000000c7, 0x0000000d, 0x0000c40a }, // 7 - { 0x000000c7, 0x00000045, 0x0000c40b }, // 8 - { 0x000000c7, 0x000000e1, 0x0000c40c }, - { 0x000000c7, 0x00000078, 0x0000c41a }, // 10 - { 0x000000c7, 0x00000000, 0x0000c41b }, - { 0x000000c7, 0x00000089, 0x0000c41c }, - { 0x000000c7, 0x000000fd, 0x0000c411 }, // 13 - { 0x000000c7, 0x00000095, 0x0000c412 }, // 14 - { 0x000000c7, 0x000000d6, 0x0000c422 }, // 15 - { 0x000000c7, 0x00000000, 0x0000c41e }, - { 0x000000c7, 0x000000d0, 0x0000c41e }, - { 0x000000c8, 0x00000000, 0x0000c422 }, - { 0x000000c7, 0x00000000, 0x0000c41e }, - { 0x000000c8, 0x00000000, 0x0000c405 }, - { 0x000000c8, 0x00000000, 0x0000c422 }, - { 0x000000c7, 0x000000d0, 0x0000c423 }, - { 0x000000c7, 0x00000000, 0x0000c41e }, - { 0x000000c7, 0x000000e0, 0x0000c41e }, - { 0x000000c8, 0x00000000, 0x0000c423 }, - { 0x000000c8, 0x00000000, 0x0000c423 }, - { 0x000000c7, 0x00000000, 0x0000c41e }, - { 0x000000c7, 0x000000d0, 0x0000c424 }, - { 0x000000c7, 0x00000000, 0x0000c41e }, - { 0x000000c7, 0x000000f0, 0x0000c41e }, - { 0x000000c8, 0x00000000, 0x0000c424 }, - { 0x000000c7, 0x00000000, 0x0000c41e }, - { 0x000000c7, 0x0000007f, 0x0000c414 }, - { 0x000000c7, 0x0000007f, 0x0000c415 }, - { 0x000000c7, 0x00000030, 0x0000c405 }, - { 0x000000c7, 0x00000000, 0x0000c406 }, - { 0x000000c7, 0x0000001f, 0x0000c415 }, - { 0x000000c7, 0x000000ff, 0x0000c416 }, - { 0x000000c7, 0x000000ff, 0x0000c418 }, - { 0x000000c7, 0x00000051, 0x0000c41f }, // here - { 0x000000c7, 0x00000016, 0x0000c420 }, // here - { 0x000000c7, 0x00000053, 0x0000c421 }, - { 0x000000c7, 0x000000c1, 0x0000c425 }, // here - { 0x000000c7, 0x00000014, 0x0000c426 }, // here - { 0x000000c7, 0x00000082, 0x0000c400 }, - { 0x000000c7, 0x00000000, 0x0000c402 }, - { 0x000000c7, 0x00000000, 0x0000c401 }, - /**/ { } /* Terminating entry */ }; -- cgit v1.2.1 From 736949862ceda7b6a9e5a867f81898e90be919d0 Mon Sep 17 00:00:00 2001 From: Antoine Jacquet Date: Tue, 12 Aug 2008 16:56:34 -0300 Subject: V4L/DVB (8736): dtv5100: CodingStyle cleanups Signed-off-by: Antoine Jacquet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dtv5100.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c index 7168a49cecf4..b2e6f7ff1a08 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.c +++ b/drivers/media/dvb/dvb-usb/dtv5100.c @@ -32,7 +32,7 @@ MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { u8 request; u8 type; @@ -44,14 +44,14 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, /* write { reg }, read { value } */ request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : DTV5100_TUNER_READ); - type = USB_TYPE_VENDOR|USB_DIR_IN; + type = USB_TYPE_VENDOR | USB_DIR_IN; value = 0; break; case 2: /* write { reg, value } */ request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : DTV5100_TUNER_WRITE); - type = USB_TYPE_VENDOR|USB_DIR_OUT; + type = USB_TYPE_VENDOR | USB_DIR_OUT; value = wbuf[1]; break; default: @@ -68,7 +68,7 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, /* I2C */ static int dtv5100_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; @@ -116,7 +116,7 @@ static struct zl10353_config dtv5100_zl10353_config = { static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) { adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, - &adap->dev->i2c_adap); + &adap->dev->i2c_adap); if (adap->fe == NULL) return -EIO; @@ -147,11 +147,10 @@ static int dtv5100_probe(struct usb_interface *intf, struct usb_device *udev = interface_to_usbdev(intf); /* initialize non qt1010/zl10353 part? */ - for (i = 0; dtv5100_init[i].request; i++) - { + for (i = 0; dtv5100_init[i].request; i++) { ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), dtv5100_init[i].request, - USB_TYPE_VENDOR|USB_DIR_OUT, + USB_TYPE_VENDOR | USB_DIR_OUT, dtv5100_init[i].value, dtv5100_init[i].index, NULL, 0, DTV5100_USB_TIMEOUT); -- cgit v1.2.1 From 5ebcfa4f92ed06129d9439198f65456abe1bfe3a Mon Sep 17 00:00:00 2001 From: Antoine Jacquet Date: Mon, 18 Aug 2008 18:22:00 -0300 Subject: V4L/DVB (8738): dtv5100: remove old definition from header Signed-off-by: Antoine Jacquet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dtv5100.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dtv5100.h b/drivers/media/dvb/dvb-usb/dtv5100.h index e36bf2d5c944..93e96e04a82a 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.h +++ b/drivers/media/dvb/dvb-usb/dtv5100.h @@ -48,6 +48,4 @@ static struct { { } /* Terminating entry */ }; -extern struct dvb_frontend* dtv5100_fe_attach(void); - #endif -- cgit v1.2.1 From 664b11fc725830b59265cd9ec35a4396514d2b26 Mon Sep 17 00:00:00 2001 From: Antoine Jacquet Date: Mon, 18 Aug 2008 18:38:51 -0300 Subject: V4L/DVB (8739): dtv5100: remove prohibited space... Signed-off-by: Antoine Jacquet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dtv5100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c index b2e6f7ff1a08..078ce92ca436 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.c +++ b/drivers/media/dvb/dvb-usb/dtv5100.c @@ -166,7 +166,7 @@ static int dtv5100_probe(struct usb_interface *intf, return 0; } -static struct usb_device_id dtv5100_table [] = { +static struct usb_device_id dtv5100_table[] = { { USB_DEVICE(0x06be, 0xa232) }, { } /* Terminating entry */ }; -- cgit v1.2.1 From 614b147b4f8f38a090f88ac02f67b01225bb5d54 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 22 Aug 2008 17:01:45 -0300 Subject: V4L/DVB (8745): v4l2: fix a bunch of compile warnings. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c index a91ed28f03a4..26f0011a5078 100644 --- a/drivers/media/dvb/b2c2/flexcop-dma.c +++ b/drivers/media/dvb/b2c2/flexcop-dma.c @@ -10,7 +10,7 @@ int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size) { u8 *tcpu; - dma_addr_t tdma; + dma_addr_t tdma = 0; if (size % 2) { err("dma buffersize has to be even."); -- cgit v1.2.1 From eda9e4e29492aff55ceb3f719a6011bddc60a892 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 22 Aug 2008 17:12:08 -0300 Subject: V4L/DVB (8746): v4l-dvb: fix compile warnings. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/nxt200x.c | 4 ++-- drivers/media/dvb/frontends/or51211.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index af298358e822..a8429ebfa8a2 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -80,7 +80,7 @@ static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len return 0; } -static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len) +static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) { int err; struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; @@ -111,7 +111,7 @@ static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, return 0; } -static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len) +static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 len) { u8 reg2 [] = { reg }; diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 6afe12aaca4e..16cf2fdd5d7d 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -88,7 +88,7 @@ static int i2c_writebytes (struct or51211_state* state, u8 reg, const u8 *buf, return 0; } -static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len) +static int i2c_readbytes(struct or51211_state *state, u8 reg, u8 *buf, int len) { int err; struct i2c_msg msg; -- cgit v1.2.1 From bccd7003aef20e040cef95d1216dac26199d7071 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 30 Aug 2008 12:15:54 -0300 Subject: V4L/DVB (8866): Add dummy FE to the Kconfig-file and fix it Reactivated dummy frontend driver which is extremely useful for debugging. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 6 ++++++ drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dvb_dummy_fe.c | 7 ++++--- 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 774f5c2a71e8..e2444f270f0a 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -392,4 +392,10 @@ config DVB_LGS8GL5 help A DMB-TH tuner module. Say Y when you want to support this frontend. +comment "Tools to develop new frontends" + +config DVB_DUMMY_FE + tristate "Dummy frontend driver" + default n + endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 262eaa429f5d..ca24618d5da8 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o +obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index fed09dfb2b7c..cb4d8a3b9d8b 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -75,9 +75,10 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - if (fe->ops->tuner_ops->set_params) { - fe->ops->tuner_ops->set_params(fe, p); - if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } return 0; -- cgit v1.2.1 From 81ae953b687e7cdfa094b07a6544523f3bb81aa3 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Wed, 3 Sep 2008 18:16:09 -0300 Subject: V4L/DVB (8888): budget: Support Activy DVB-T with TDHD1 tuner Support Fujitsu-Siemens Activy DVB-T card rev AL (ALPS TDHD1-204A tuner). Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tdhd1.h | 70 +++++++++++++++++++++++++++++++++++++ drivers/media/dvb/ttpci/Kconfig | 1 + drivers/media/dvb/ttpci/budget.c | 11 ++++++ 3 files changed, 82 insertions(+) create mode 100644 drivers/media/dvb/frontends/tdhd1.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h new file mode 100644 index 000000000000..de8aac7d7ae0 --- /dev/null +++ b/drivers/media/dvb/frontends/tdhd1.h @@ -0,0 +1,70 @@ +/* + * tdhd1.h - ALPS TDHD1-204A tuner support + * + * Copyright (C) 2008 Oliver Endriss + * + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * The project's page is at http://www.linuxtv.org + */ + +#ifndef TDHD1_H +#define TDHD1_H + +#include "tda1004x.h" + +static struct tda1004x_config alps_tdhd1_204a_config = { + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, +}; + +static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct i2c_adapter *i2c = fe->tuner_priv; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + u32 div; + + div = (params->frequency + 36166666) / 166666; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85; + + if (params->frequency >= 174000000 && params->frequency <= 230000000) + data[3] = 0x02; + else if (params->frequency >= 470000000 && params->frequency <= 823000000) + data[3] = 0x0C; + else if (params->frequency > 823000000 && params->frequency <= 862000000) + data[3] = 0x8C; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + return 0; +} + +#endif /* TDHD1_H */ diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 41b5a988b619..867027ceab3e 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -86,6 +86,7 @@ config DVB_BUDGET select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, and without diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 851e523fbffc..a4664ba5aded 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -46,6 +46,7 @@ #include "lnbp21.h" #include "bsru6.h" #include "bsbe1.h" +#include "tdhd1.h" static int diseqc_method; module_param(diseqc_method, int, 0444); @@ -511,6 +512,14 @@ static void frontend_init(struct budget *budget) } break; + case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ + budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + } + break; + case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); if (budget->dvb_frontend) { @@ -624,6 +633,7 @@ MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), @@ -634,6 +644,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), + MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), { .vendor = 0, -- cgit v1.2.1 From 9e615eac827094147401c44c9ff955b468d4fa79 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Wed, 3 Sep 2008 19:15:27 -0300 Subject: V4L/DVB (8889): dvb-ttpci: Support full-ts hardware modification Add support for the 'full-ts' hardware modification. On full-featured cards the data throughput is limited by the hardware design. The full-ts mod removes this bottleneck, i.e. the card is able to deliver the complete transport stream of a transponder. For details see http://www.escape-edv.de/endriss/dvb-full-ts-mod Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/av7110.c | 113 ++++++++++++++++++++++++++++-------- drivers/media/dvb/ttpci/av7110.h | 1 + drivers/media/dvb/ttpci/av7110_av.c | 3 + 3 files changed, 92 insertions(+), 25 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 3b641804f6cb..404108f09d77 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -88,6 +88,7 @@ static int budgetpatch; static int wss_cfg_4_3 = 0x4008; static int wss_cfg_16_9 = 0x0007; static int tv_standard; +static int full_ts; module_param_named(debug, av7110_debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); @@ -106,6 +107,8 @@ module_param(volume, int, 0444); MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); module_param(budgetpatch, int, 0444); MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); +module_param(full_ts, int, 0444); +MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); module_param(wss_cfg_4_3, int, 0444); MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); module_param(wss_cfg_16_9, int, 0444); @@ -116,6 +119,8 @@ MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static void restart_feeds(struct av7110 *av7110); +static int budget_start_feed(struct dvb_demux_feed *feed); +static int budget_stop_feed(struct dvb_demux_feed *feed); static int av7110_num; @@ -806,6 +811,9 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) dprintk(4, "%p\n", av7110); + if (av7110->full_ts) + return 0; + if (dvbdmxfilter->type == DMX_TYPE_SEC) { if (hw_sections) { buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | @@ -854,6 +862,9 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) dprintk(4, "%p\n", av7110); + if (av7110->full_ts) + return 0; + handle = dvbdmxfilter->hw_handle; if (handle >= 32) { printk("%s tried to stop invalid filter %04x, filter type = %x\n", @@ -913,7 +924,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) return ret; } - if ((dvbdmxfeed->ts_type & TS_PACKET)) { + if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) @@ -974,7 +985,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - if (feed->pid > 0x1fff) + if (!av7110->full_ts && feed->pid > 0x1fff) return -EINVAL; if (feed->type == DMX_TYPE_TS) { @@ -1003,7 +1014,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) } } - else if (feed->type == DMX_TYPE_SEC) { + if (av7110->full_ts) { + budget_start_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { int i; for (i = 0; i < demux->filternum; i++) { @@ -1050,7 +1066,12 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) ret = StopHWFilter(feed->filter); } - if (!ret && feed->type == DMX_TYPE_SEC) { + if (av7110->full_ts) { + budget_stop_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { for (i = 0; ifilternum; i++) { if (demux->filter[i].state == DMX_STATE_GO && demux->filter[i].filter.parent == &feed->feed.sec) { @@ -1074,6 +1095,7 @@ static void restart_feeds(struct av7110 *av7110) struct dvb_demux *dvbdmx = &av7110->demux; struct dvb_demux_feed *feed; int mode; + int feeding; int i, j; dprintk(4, "%p\n", av7110); @@ -1082,6 +1104,8 @@ static void restart_feeds(struct av7110 *av7110) av7110->playing = 0; av7110->rec_mode = 0; + feeding = av7110->feeding1; /* full_ts mod */ + for (i = 0; i < dvbdmx->feednum; i++) { feed = &dvbdmx->feed[i]; if (feed->state == DMX_STATE_GO) { @@ -1099,6 +1123,8 @@ static void restart_feeds(struct av7110 *av7110) } } + av7110->feeding1 = feeding; /* full_ts mod */ + if (mode) av7110_av_start_play(av7110, mode); } @@ -1197,8 +1223,9 @@ static int start_ts_capture(struct av7110 *budget) if (budget->feeding1) return ++budget->feeding1; - memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); + memset(budget->grabbing, 0x00, TS_BUFLEN); budget->ttbp = 0; + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ return ++budget->feeding1; @@ -1239,12 +1266,8 @@ static void vpeirq(unsigned long data) u8 *mem = (u8 *) (budget->grabbing); u32 olddma = budget->ttbp; u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; - if (!budgetpatch) { - printk("av7110.c: vpeirq() called while budgetpatch disabled!" - " check saa7146 IER register\n"); - BUG(); - } /* nearest lower position divisible by 188 */ newdma -= newdma % 188; @@ -1268,11 +1291,11 @@ static void vpeirq(unsigned long data) if (newdma > olddma) /* no wraparound, dump olddma..newdma */ - dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188); + dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); else { /* wraparound, dump olddma..buflen and 0..newdma */ - dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188); - dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188); + dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + dvb_dmx_swfilter_packets(demux, mem, newdma / 188); } } @@ -1294,8 +1317,8 @@ static int av7110_register(struct av7110 *av7110) for (i = 0; i < 32; i++) av7110->handle2filter[i] = NULL; - dvbdemux->filternum = 32; - dvbdemux->feednum = 32; + dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; + dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; dvbdemux->start_feed = av7110_start_feed; dvbdemux->stop_feed = av7110_stop_feed; dvbdemux->write_to_decoder = av7110_write_to_decoder; @@ -1305,7 +1328,7 @@ static int av7110_register(struct av7110 *av7110) dvb_dmx_init(&av7110->demux); av7110->demux.dmx.get_stc = dvb_get_stc; - av7110->dmxdev.filternum = 32; + av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; av7110->dmxdev.demux = &dvbdemux->dmx; av7110->dmxdev.capabilities = 0; @@ -1422,7 +1445,6 @@ int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) return i2c_transfer(&av7110->i2c_adap, &msgs, 1); } -#if 0 u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) { u8 mm1[] = {0x00}; @@ -1439,7 +1461,6 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) return mm2[0]; } -#endif /**************************************************************************** * INITIALIZATION @@ -2484,7 +2505,47 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, av7110->dvb_adapter.proposed_mac); ret = -ENOMEM; - if (budgetpatch) { + /* full-ts mod? */ + if (full_ts) + av7110->full_ts = true; + + /* check for full-ts flag in eeprom */ + if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { + u8 flags = i2c_readreg(av7110, 0xaa, 2); + if (flags != 0xff && (flags & 0x01)) + av7110->full_ts = true; + } + + if (av7110->full_ts) { + printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x00000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, MC2, MASK_08 | MASK_24); + + /* dma3 */ + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + saa7146_write(dev, MC2, MASK_04 | MASK_20); + + tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); + + } else if (budgetpatch) { spin_lock_init(&av7110->feedlock1); av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, &av7110->pt); @@ -2710,11 +2771,13 @@ static int __devexit av7110_detach(struct saa7146_dev* saa) #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) av7110_ir_exit(av7110); #endif - if (budgetpatch) { - /* Disable RPS1 */ - saa7146_write(saa, MC1, MASK_29); - /* VSYNC LOW (inactive) */ - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + if (budgetpatch || av7110->full_ts) { + if (budgetpatch) { + /* Disable RPS1 */ + saa7146_write(saa, MC1, MASK_29); + /* VSYNC LOW (inactive) */ + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ SAA7146_IER_DISABLE(saa, MASK_10); SAA7146_ISR_CLEAR(saa, MASK_10); @@ -2794,7 +2857,7 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr) tasklet_schedule(&av7110->gpio_tasklet); } - if ((*isr & MASK_10) && budgetpatch) + if (*isr & MASK_10) tasklet_schedule(&av7110->vpe_tasklet); } diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 55f23ddcb994..d85b8512ac30 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -192,6 +192,7 @@ struct av7110 { unsigned char *grabbing; struct saa7146_pgtable pt; struct tasklet_struct vpe_tasklet; + bool full_ts; int fe_synced; struct mutex pid_mutex; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 184647ad1c7c..bdc62acf2099 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -788,6 +788,9 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l dprintk(2, "av7110:%p, \n", av7110); + if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) + return 0; + switch (feed->pes_type) { case 0: if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) -- cgit v1.2.1 From 83512e207479d0bdb83ee1e000a306af9e6e870e Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 4 Sep 2008 20:35:19 -0300 Subject: V4L/DVB (8890): budget: Add callback to load firmware for the TDHD1 tuner Supply callback to load firmware for the TDHD1 tuner (using request_firmware). Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/tdhd1.h | 3 +++ drivers/media/dvb/ttpci/budget.c | 7 +++++++ 2 files changed, 10 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h index de8aac7d7ae0..51f170678650 100644 --- a/drivers/media/dvb/frontends/tdhd1.h +++ b/drivers/media/dvb/frontends/tdhd1.h @@ -28,6 +28,8 @@ #include "tda1004x.h" +static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name); + static struct tda1004x_config alps_tdhd1_204a_config = { .demod_address = 0x8, .invert = 1, @@ -35,6 +37,7 @@ static struct tda1004x_config alps_tdhd1_204a_config = { .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, + .request_firmware = alps_tdhd1_204_request_firmware }; static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index a4664ba5aded..d95203d55403 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -391,6 +391,13 @@ static struct stv0299_config alps_bsbe1_config_activy = { .set_symbol_rate = alps_bsbe1_set_symbol_rate, }; +static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) +{ + struct budget *budget = (struct budget *)fe->dvb->priv; + + return request_firmware(fw, name, &budget->dev->pci->dev); +} + static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) { -- cgit v1.2.1 From d45b9b8ab43c8973a9630ac54f4ede6c3e009f9e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Sep 2008 03:33:43 -0300 Subject: V4L/DVB (8906): v4l-dvb: fix assorted sparse warnings Fix sparse warnings. None are serious, but cutting down on these helps find future serious sparse warnings/errors. Redid the av7710.c patch based on a suggestion by Oliver Endriss. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9005-remote.c | 2 +- drivers/media/dvb/dvb-usb/af9005-script.h | 2 +- drivers/media/dvb/dvb-usb/af9005.c | 23 +++++++++-------------- drivers/media/dvb/frontends/cx24110.h | 15 ++++++++++----- drivers/media/dvb/frontends/dib7000m.c | 3 ++- drivers/media/dvb/frontends/dvb_dummy_fe.c | 4 ++-- drivers/media/dvb/frontends/sp887x.c | 3 ++- drivers/media/dvb/ttpci/av7110.c | 12 ++++++------ 8 files changed, 33 insertions(+), 31 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c index ff00c0e8f4a1..7c596f926764 100644 --- a/drivers/media/dvb/dvb-usb/af9005-remote.c +++ b/drivers/media/dvb/dvb-usb/af9005-remote.c @@ -25,7 +25,7 @@ */ #include "af9005.h" /* debug */ -int dvb_usb_af9005_remote_debug; +static int dvb_usb_af9005_remote_debug; module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); MODULE_PARM_DESC(debug, "enable (1) or disable (0) debug messages." diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h index 6eeaae51b1ca..4d69045426dd 100644 --- a/drivers/media/dvb/dvb-usb/af9005-script.h +++ b/drivers/media/dvb/dvb-usb/af9005-script.h @@ -14,7 +14,7 @@ typedef struct { u8 val; } RegDesc; -RegDesc script[] = { +static RegDesc script[] = { {0xa180, 0x0, 0x8, 0xa}, {0xa181, 0x0, 0x8, 0xd7}, {0xa182, 0x0, 0x8, 0xa3}, diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index cfe71feefcad..ca5a0a4d2a47 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -35,17 +35,17 @@ module_param_named(led, dvb_usb_af9005_led, bool, 0644); MODULE_PARM_DESC(led, "enable led (default: 1)."); /* eeprom dump */ -int dvb_usb_af9005_dump_eeprom = 0; +static int dvb_usb_af9005_dump_eeprom; module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* remote control decoder */ -int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event, - int *state); -void *rc_keys; -int *rc_keys_size; +static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, + u32 *event, int *state); +static void *rc_keys; +static int *rc_keys_size; u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; @@ -54,8 +54,8 @@ struct af9005_device_state { int led_state; }; -int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, - u8 * rbuf, u16 rlen, int delay_ms) +static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, + u8 *rbuf, u16 rlen, int delay_ms) { int actlen, ret = -ENOMEM; @@ -98,12 +98,7 @@ int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, return ret; } -int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len) -{ - return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0); -} - -int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, +static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, int readwrite, int type, u8 * values, int len) { struct af9005_device_state *st = d->priv; @@ -765,7 +760,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) return 0; } -int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) +static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) { int i, packets, ret, act_len; diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h index 1792adb23c4d..fdcceee91f3a 100644 --- a/drivers/media/dvb/frontends/cx24110.h +++ b/drivers/media/dvb/frontends/cx24110.h @@ -33,12 +33,17 @@ struct cx24110_config u8 demod_address; }; -static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) { - int r = 0; - u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)}; +static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) +{ + u8 buf[] = { + (u8)((val >> 24) & 0xff), + (u8)((val >> 16) & 0xff), + (u8)((val >> 8) & 0xff) + }; + if (fe->ops.write) - r = fe->ops.write(fe, buf, 3); - return r; + return fe->ops.write(fe, buf, 3); + return 0; } #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 5f1375e30dfc..4de0fa9b69ad 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -1284,7 +1284,8 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di } EXPORT_SYMBOL(dib7000m_get_i2c_master); -int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[]) +static int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, + u8 default_addr, struct dib7000m_config cfg[]) { struct dib7000m_state st = { .i2c_adap = i2c }; int k = 0; diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index cb4d8a3b9d8b..db8a937cc630 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -132,7 +132,7 @@ error: static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; -struct dvb_frontend* dvb_dummy_fe_qpsk_attach() +struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) { struct dvb_dummy_fe_state* state = NULL; @@ -152,7 +152,7 @@ error: static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; -struct dvb_frontend* dvb_dummy_fe_qam_attach() +struct dvb_frontend *dvb_dummy_fe_qam_attach(void) { struct dvb_dummy_fe_state* state = NULL; diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 4543609e1816..559509ab4dab 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -337,7 +337,8 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct sp887x_state* state = fe->demodulator_priv; - int actual_freq, err; + unsigned actual_freq; + int err; u16 val, reg0xc05; if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 404108f09d77..c7c770c28988 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -381,9 +381,9 @@ static inline void start_debi_dma(struct av7110 *av7110, int dir, irdebi(av7110, DEBISWAB, addr, 0, len); } -static void debiirq(unsigned long data) +static void debiirq(unsigned long cookie) { - struct av7110 *av7110 = (struct av7110 *) data; + struct av7110 *av7110 = (struct av7110 *)cookie; int type = av7110->debitype; int handle = (type >> 8) & 0x1f; unsigned int xfer = 0; @@ -492,9 +492,9 @@ debi_done: } /* irq from av7110 firmware writing the mailbox register in the DPRAM */ -static void gpioirq(unsigned long data) +static void gpioirq(unsigned long cookie) { - struct av7110 *av7110 = (struct av7110 *) data; + struct av7110 *av7110 = (struct av7110 *)cookie; u32 rxbuf, txbuf; int len; @@ -1260,9 +1260,9 @@ static int budget_stop_feed(struct dvb_demux_feed *feed) return status; } -static void vpeirq(unsigned long data) +static void vpeirq(unsigned long cookie) { - struct av7110 *budget = (struct av7110 *) data; + struct av7110 *budget = (struct av7110 *)cookie; u8 *mem = (u8 *) (budget->grabbing); u32 olddma = budget->ttbp; u32 newdma = saa7146_read(budget->dev, PCI_VDP3); -- cgit v1.2.1 From 942648af36e4d4b91e52b3e1a87d4cafd6f7aa46 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Sep 2008 08:38:50 -0300 Subject: V4L/DVB (8946): dib7000m: fix powerpc build error The dib7000m_i2c_enumeration() function is not used by any public drivers, however some prototype board use it. So '#if 0' for now, but don't remove it. Thanks to Patrick Boettcher for clarifying this. Cc: Patrick Boettcher Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib7000m.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 4de0fa9b69ad..0109720353bd 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -1284,7 +1284,9 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di } EXPORT_SYMBOL(dib7000m_get_i2c_master); -static int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, +#if 0 +/* used with some prototype boards */ +int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[]) { struct dib7000m_state st = { .i2c_adap = i2c }; @@ -1330,6 +1332,7 @@ static int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, return 0; } EXPORT_SYMBOL(dib7000m_i2c_enumeration); +#endif static struct dvb_frontend_ops dib7000m_ops; struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) -- cgit v1.2.1 From 26dc4d0487bb8b8de32d09c18a83c63d622156f2 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Sun, 21 Sep 2008 20:50:11 -0300 Subject: V4L/DVB (8964): dvb/budget: push adapter_nr mod option down to individual drivers adapter_nr mod option does not make sense for budget-core since it is only common code shared by all budget drivers Signed-off-by: Janne Grunau Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget-av.c | 6 +++++- drivers/media/dvb/ttpci/budget-ci.c | 5 ++++- drivers/media/dvb/ttpci/budget-core.c | 6 ++---- drivers/media/dvb/ttpci/budget-patch.c | 7 +++++-- drivers/media/dvb/ttpci/budget.c | 5 ++++- drivers/media/dvb/ttpci/budget.h | 2 +- 6 files changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 839c94101b4e..1032ea77837e 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -57,6 +57,8 @@ #define SLOTSTATUS_READY 8 #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + struct budget_av { struct budget budget; struct video_device *vd; @@ -1127,7 +1129,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio dev->ext_priv = budget_av; - if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) { + err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, + adapter_nr); + if (err) { kfree(budget_av); return err; } diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 38dd5cf1aed2..0a5aad45435d 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -92,6 +92,8 @@ static int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + struct budget_ci_ir { struct input_dev *dev; struct tasklet_struct msp430_irq_tasklet; @@ -1183,7 +1185,8 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio dev->ext_priv = budget_ci; - err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE); + err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, + adapter_nr); if (err) goto out2; diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 6f4ddb643fee..ba18e56d5f11 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -57,8 +57,6 @@ module_param_named(bufsize, dma_buffer_size, int, 0444); MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - /**************************************************************************** * TT budget / WinTV Nova ****************************************************************************/ @@ -411,7 +409,7 @@ static void budget_unregister(struct budget *budget) int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, struct saa7146_pci_extension_data *info, - struct module *owner) + struct module *owner, short *adapter_nums) { int ret = 0; struct budget_info *bi = info->ext_priv; @@ -474,7 +472,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, - owner, &budget->dev->pci->dev, adapter_nr); + owner, &budget->dev->pci->dev, adapter_nums); if (ret < 0) return ret; diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index bbd234fe11c1..60136688a9a4 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -39,6 +39,8 @@ #include "bsru6.h" +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + #define budget_patch budget static struct saa7146_extension budget_extension; @@ -592,8 +594,9 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte dprintk(2, "budget: %p\n", budget); - if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { - kfree (budget); + err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); + if (err) { + kfree(budget); return err; } diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index d95203d55403..1638e1d9f538 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -52,6 +52,8 @@ static int diseqc_method; module_param(diseqc_method, int, 0444); MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + static void Set22K (struct budget *budget, int state) { struct saa7146_dev *dev=budget->dev; @@ -598,7 +600,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_ dev->ext_priv = budget; - if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { + err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); + if (err) { printk("==> failed\n"); kfree (budget); return err; diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index dd450b739bff..86435bf16260 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -109,7 +109,7 @@ static struct saa7146_pci_extension_data x_var = { \ extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, struct saa7146_pci_extension_data *info, - struct module *owner); + struct module *owner, short *adapter_nums); extern void ttpci_budget_init_hooks(struct budget *budget); extern int ttpci_budget_deinit(struct budget *budget); extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); -- cgit v1.2.1 From ef80bfeb30f82fb718731a3323a75ae08396a4ea Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 16 Sep 2008 02:15:30 -0300 Subject: V4L/DVB (8968): replace xc3028 firmware filenames with defined default firmware names Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index bffb44380389..1a746127cbda 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -773,7 +773,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) .callback = dvico_bluebird_xc2028_callback, }; static struct xc2028_ctrl ctl = { - .fname = "xc3028-v27.fw", + .fname = XC2028_DEFAULT_FIRMWARE, .max_len = 64, .demod = XC3028_FE_ZARLINK456, }; -- cgit v1.2.1 From 825b96708054ca16d6e4d56a29326d3b2cdd697d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 15 Sep 2008 15:01:52 -0300 Subject: V4L/DVB (8971): initial driver for af9013 demodulator - initial driver for the Afatech AF9013 demodulator Signed-off-by: Antti Palosaari [mchehab.redhat.com: having a global var called 'debug' is not a good idea. rename it to af9013_debug] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 6 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/af9013.c | 1691 +++++++++++++++++++++++++++++ drivers/media/dvb/frontends/af9013.h | 107 ++ drivers/media/dvb/frontends/af9013_priv.h | 869 +++++++++++++++ 5 files changed, 2674 insertions(+) create mode 100644 drivers/media/dvb/frontends/af9013.c create mode 100644 drivers/media/dvb/frontends/af9013.h create mode 100644 drivers/media/dvb/frontends/af9013_priv.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index e2444f270f0a..097d9f00144f 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -398,4 +398,10 @@ config DVB_DUMMY_FE tristate "Dummy frontend driver" default n +config DVB_AF9013 + tristate "Afatech AF9013 demodulator" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index ca24618d5da8..1b5478886240 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -50,3 +50,4 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o +obj-$(CONFIG_DVB_AF9013) += af9013.o diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c new file mode 100644 index 000000000000..9f2129d544c5 --- /dev/null +++ b/drivers/media/dvb/frontends/af9013.c @@ -0,0 +1,1691 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "af9013_priv.h" +#include "af9013.h" + +int af9013_debug; + +struct af9013_state { + struct i2c_adapter *i2c; + struct dvb_frontend frontend; + + struct af9013_config config; + + u16 signal_strength; + u32 ber; + u32 ucblocks; + u16 snr; + u32 frequency; + unsigned long next_statistics_check; +}; + +static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + +static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg, + u8 *val, u8 len) +{ + u8 buf[3+len]; + struct i2c_msg msg = { + .addr = state->config.demod_address, + .flags = 0, + .len = sizeof(buf), + .buf = buf }; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + buf[2] = mbox; + memcpy(&buf[3], val, len); + + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + warn("I2C write failed reg:%04x len:%d", reg, len); + return -EREMOTEIO; + } + return 0; +} + +static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val, + u8 len) +{ + u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7); + return af9013_write_regs(state, mbox, reg, val, len); +} + +static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, + u8 len) +{ + u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7); + return af9013_write_regs(state, mbox, reg, val, len); +} + +/* write single register */ +static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val) +{ + return af9013_write_ofdm_regs(state, reg, &val, 1); +} + +/* read single register */ +static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val) +{ + u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; + u8 ibuf[1]; + struct i2c_msg msg[2] = { + { + .addr = state->config.demod_address, + .flags = 0, + .len = sizeof(obuf), + .buf = obuf + }, { + .addr = state->config.demod_address, + .flags = I2C_M_RD, + .len = sizeof(ibuf), + .buf = ibuf + } + }; + + if (i2c_transfer(state->i2c, msg, 2) != 2) { + warn("I2C read failed reg:%04x", reg); + return -EREMOTEIO; + } + *val = ibuf[0]; + return 0; +} + +static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos, + u8 len, u8 val) +{ + int ret; + u8 tmp, mask; + + ret = af9013_read_reg(state, reg, &tmp); + if (ret) + return ret; + + mask = regmask[len - 1] << pos; + tmp = (tmp & ~mask) | ((val << pos) & mask); + + return af9013_write_reg(state, reg, tmp); +} + +static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos, + u8 len, u8 *val) +{ + int ret; + u8 tmp; + + ret = af9013_read_reg(state, reg, &tmp); + if (ret) + return ret; + *val = (tmp >> pos) & regmask[len - 1]; + return 0; +} + +static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) +{ + int ret; + u8 pos; + u16 addr; + deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); + +/* GPIO0 & GPIO1 0xd735 + GPIO2 & GPIO3 0xd736 */ + + switch (gpio) { + case 0: + case 1: + addr = 0xd735; + break; + case 2: + case 3: + addr = 0xd736; + break; + + default: + err("invalid gpio:%d\n", gpio); + ret = -EINVAL; + goto error; + }; + + switch (gpio) { + case 0: + case 2: + pos = 0; + break; + case 1: + case 3: + default: + pos = 4; + break; + }; + + ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval); + +error: + return ret; +} + +static u32 af913_div(u32 a, u32 b, u32 x) +{ + u32 r = 0, c = 0, i; + deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x); + + if (a > b) { + c = a / b; + a = a - c * b; + } + + for (i = 0; i < x; i++) { + if (a >= b) { + r += 1; + a -= b; + } + a <<= 1; + r <<= 1; + } + r = (c << (u32)x) + r; + + deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r); + return r; +} + +static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) +{ + int ret = 0; + u8 i = 0; + u8 buf[24]; + u32 ns_coeff1_2048nu; + u32 ns_coeff1_8191nu; + u32 ns_coeff1_8192nu; + u32 ns_coeff1_8193nu; + u32 ns_coeff2_2k; + u32 ns_coeff2_8k; + + deb_info("%s: adc_clock:%d bw:%d\n", __func__, + state->config.adc_clock, bw); + + switch (state->config.adc_clock) { + case 28800: /* 28.800 MHz */ + switch (bw) { + case BANDWIDTH_6_MHZ: + ns_coeff1_2048nu = 0x01e79e7a; + ns_coeff1_8191nu = 0x0079eb6e; + ns_coeff1_8192nu = 0x0079e79e; + ns_coeff1_8193nu = 0x0079e3cf; + ns_coeff2_2k = 0x00f3cf3d; + ns_coeff2_8k = 0x003cf3cf; + break; + case BANDWIDTH_7_MHZ: + ns_coeff1_2048nu = 0x0238e38e; + ns_coeff1_8191nu = 0x008e3d55; + ns_coeff1_8192nu = 0x008e38e4; + ns_coeff1_8193nu = 0x008e3472; + ns_coeff2_2k = 0x011c71c7; + ns_coeff2_8k = 0x00471c72; + break; + case BANDWIDTH_8_MHZ: + ns_coeff1_2048nu = 0x028a28a3; + ns_coeff1_8191nu = 0x00a28f3d; + ns_coeff1_8192nu = 0x00a28a29; + ns_coeff1_8193nu = 0x00a28514; + ns_coeff2_2k = 0x01451451; + ns_coeff2_8k = 0x00514514; + break; + default: + ret = -EINVAL; + } + break; + case 20480: /* 20.480 MHz */ + switch (bw) { + case BANDWIDTH_6_MHZ: + ns_coeff1_2048nu = 0x02adb6dc; + ns_coeff1_8191nu = 0x00ab7313; + ns_coeff1_8192nu = 0x00ab6db7; + ns_coeff1_8193nu = 0x00ab685c; + ns_coeff2_2k = 0x0156db6e; + ns_coeff2_8k = 0x0055b6dc; + break; + case BANDWIDTH_7_MHZ: + ns_coeff1_2048nu = 0x03200001; + ns_coeff1_8191nu = 0x00c80640; + ns_coeff1_8192nu = 0x00c80000; + ns_coeff1_8193nu = 0x00c7f9c0; + ns_coeff2_2k = 0x01900000; + ns_coeff2_8k = 0x00640000; + break; + case BANDWIDTH_8_MHZ: + ns_coeff1_2048nu = 0x03924926; + ns_coeff1_8191nu = 0x00e4996e; + ns_coeff1_8192nu = 0x00e49249; + ns_coeff1_8193nu = 0x00e48b25; + ns_coeff2_2k = 0x01c92493; + ns_coeff2_8k = 0x00724925; + break; + default: + ret = -EINVAL; + } + break; + case 28000: /* 28.000 MHz */ + switch (bw) { + case BANDWIDTH_6_MHZ: + ns_coeff1_2048nu = 0x01f58d10; + ns_coeff1_8191nu = 0x007d672f; + ns_coeff1_8192nu = 0x007d6344; + ns_coeff1_8193nu = 0x007d5f59; + ns_coeff2_2k = 0x00fac688; + ns_coeff2_8k = 0x003eb1a2; + break; + case BANDWIDTH_7_MHZ: + ns_coeff1_2048nu = 0x02492492; + ns_coeff1_8191nu = 0x00924db7; + ns_coeff1_8192nu = 0x00924925; + ns_coeff1_8193nu = 0x00924492; + ns_coeff2_2k = 0x01249249; + ns_coeff2_8k = 0x00492492; + break; + case BANDWIDTH_8_MHZ: + ns_coeff1_2048nu = 0x029cbc15; + ns_coeff1_8191nu = 0x00a7343f; + ns_coeff1_8192nu = 0x00a72f05; + ns_coeff1_8193nu = 0x00a729cc; + ns_coeff2_2k = 0x014e5e0a; + ns_coeff2_8k = 0x00539783; + break; + default: + ret = -EINVAL; + } + break; + case 25000: /* 25.000 MHz */ + switch (bw) { + case BANDWIDTH_6_MHZ: + ns_coeff1_2048nu = 0x0231bcb5; + ns_coeff1_8191nu = 0x008c7391; + ns_coeff1_8192nu = 0x008c6f2d; + ns_coeff1_8193nu = 0x008c6aca; + ns_coeff2_2k = 0x0118de5b; + ns_coeff2_8k = 0x00463797; + break; + case BANDWIDTH_7_MHZ: + ns_coeff1_2048nu = 0x028f5c29; + ns_coeff1_8191nu = 0x00a3dc29; + ns_coeff1_8192nu = 0x00a3d70a; + ns_coeff1_8193nu = 0x00a3d1ec; + ns_coeff2_2k = 0x0147ae14; + ns_coeff2_8k = 0x0051eb85; + break; + case BANDWIDTH_8_MHZ: + ns_coeff1_2048nu = 0x02ecfb9d; + ns_coeff1_8191nu = 0x00bb44c1; + ns_coeff1_8192nu = 0x00bb3ee7; + ns_coeff1_8193nu = 0x00bb390d; + ns_coeff2_2k = 0x01767dce; + ns_coeff2_8k = 0x005d9f74; + break; + default: + ret = -EINVAL; + } + break; + default: + err("invalid xtal"); + return -EINVAL; + } + if (ret) { + err("invalid bandwidth"); + return ret; + } + + buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24); + buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16); + buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8); + buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff)); + buf[i++] = (u8) ((ns_coeff2_2k & 0x01c00000) >> 22); + buf[i++] = (u8) ((ns_coeff2_2k & 0x003fc000) >> 14); + buf[i++] = (u8) ((ns_coeff2_2k & 0x00003fc0) >> 6); + buf[i++] = (u8) ((ns_coeff2_2k & 0x0000003f)); + buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24); + buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16); + buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8); + buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff)); + buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24); + buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16); + buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8); + buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff)); + buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24); + buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16); + buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8); + buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff)); + buf[i++] = (u8) ((ns_coeff2_8k & 0x01c00000) >> 22); + buf[i++] = (u8) ((ns_coeff2_8k & 0x003fc000) >> 14); + buf[i++] = (u8) ((ns_coeff2_8k & 0x00003fc0) >> 6); + buf[i++] = (u8) ((ns_coeff2_8k & 0x0000003f)); + + deb_info("%s: coeff:", __func__); + debug_dump(buf, sizeof(buf), deb_info); + + /* program */ + for (i = 0; i < sizeof(buf); i++) { + ret = af9013_write_reg(state, 0xae00 + i, buf[i]); + if (ret) + break; + } + + return ret; +} + +static int af9013_set_adc_ctrl(struct af9013_state *state) +{ + int ret; + u8 buf[3], tmp, i; + u32 adc_cw; + + deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock); + + /* adc frequency type */ + switch (state->config.adc_clock) { + case 28800: /* 28.800 MHz */ + tmp = 0; + break; + case 20480: /* 20.480 MHz */ + tmp = 1; + break; + case 28000: /* 28.000 MHz */ + tmp = 2; + break; + case 25000: /* 25.000 MHz */ + tmp = 3; + break; + default: + err("invalid xtal"); + return -EINVAL; + } + + adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul); + + buf[0] = (u8) ((adc_cw & 0x000000ff)); + buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8); + buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16); + + deb_info("%s: adc_cw:", __func__); + debug_dump(buf, sizeof(buf), deb_info); + + /* program */ + for (i = 0; i < sizeof(buf); i++) { + ret = af9013_write_reg(state, 0xd180 + i, buf[i]); + if (ret) + goto error; + } + ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp); +error: + return ret; +} + +static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) +{ + int ret; + u16 addr; + u8 buf[3], i, j; + u32 adc_freq, freq_cw; + s8 bfs_spec_inv; + int if_sample_freq; + + for (j = 0; j < 3; j++) { + if (j == 0) { + addr = 0xd140; /* fcw normal */ + bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; + } else if (j == 1) { + addr = 0x9be7; /* fcw dummy ram */ + bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; + } else { + addr = 0x9bea; /* fcw inverted */ + bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1; + } + + adc_freq = state->config.adc_clock * 1000; + if_sample_freq = state->config.tuner_if * 1000; + + /* TDA18271 uses different sampling freq for every bw */ + if (state->config.tuner == AF9013_TUNER_TDA18271) { + switch (bw) { + case BANDWIDTH_6_MHZ: + if_sample_freq = 3300000; /* 3.3 MHz */ + break; + case BANDWIDTH_7_MHZ: + if_sample_freq = 3800000; /* 3.8 MHz */ + break; + case BANDWIDTH_8_MHZ: + default: + if_sample_freq = 4300000; /* 4.3 MHz */ + break; + } + } + + while (if_sample_freq > (adc_freq / 2)) + if_sample_freq = if_sample_freq - adc_freq; + + if (if_sample_freq >= 0) + bfs_spec_inv = bfs_spec_inv * (-1); + else + if_sample_freq = if_sample_freq * (-1); + + freq_cw = af913_div(if_sample_freq, adc_freq, 23ul); + + if (bfs_spec_inv == -1) + freq_cw = 0x00800000 - freq_cw; + + buf[0] = (u8) ((freq_cw & 0x000000ff)); + buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8); + buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16); + + + deb_info("%s: freq_cw:", __func__); + debug_dump(buf, sizeof(buf), deb_info); + + /* program */ + for (i = 0; i < sizeof(buf); i++) { + ret = af9013_write_reg(state, addr++, buf[i]); + if (ret) + goto error; + } + } +error: + return ret; +} + +static int af9013_set_ofdm_params(struct af9013_state *state, + struct dvb_ofdm_parameters *params, u8 *auto_mode) +{ + int ret; + u8 i, buf[3] = {0, 0, 0}; + *auto_mode = 0; /* set if parameters are requested to auto set */ + + switch (params->transmission_mode) { + case TRANSMISSION_MODE_AUTO: + *auto_mode = 1; + case TRANSMISSION_MODE_2K: + break; + case TRANSMISSION_MODE_8K: + buf[0] |= (1 << 0); + break; + default: + return -EINVAL; + } + + switch (params->guard_interval) { + case GUARD_INTERVAL_AUTO: + *auto_mode = 1; + case GUARD_INTERVAL_1_32: + break; + case GUARD_INTERVAL_1_16: + buf[0] |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + buf[0] |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + buf[0] |= (3 << 2); + break; + default: + return -EINVAL; + } + + switch (params->hierarchy_information) { + case HIERARCHY_AUTO: + *auto_mode = 1; + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + buf[0] |= (1 << 4); + break; + case HIERARCHY_2: + buf[0] |= (2 << 4); + break; + case HIERARCHY_4: + buf[0] |= (3 << 4); + break; + default: + return -EINVAL; + }; + + switch (params->constellation) { + case QAM_AUTO: + *auto_mode = 1; + case QPSK: + break; + case QAM_16: + buf[1] |= (1 << 6); + break; + case QAM_64: + buf[1] |= (2 << 6); + break; + default: + return -EINVAL; + } + + /* Use HP. How and which case we can switch to LP? */ + buf[1] |= (1 << 4); + + switch (params->code_rate_HP) { + case FEC_AUTO: + *auto_mode = 1; + case FEC_1_2: + break; + case FEC_2_3: + buf[2] |= (1 << 0); + break; + case FEC_3_4: + buf[2] |= (2 << 0); + break; + case FEC_5_6: + buf[2] |= (3 << 0); + break; + case FEC_7_8: + buf[2] |= (4 << 0); + break; + default: + return -EINVAL; + } + + switch (params->code_rate_LP) { + case FEC_AUTO: + /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO + by dvb_frontend.c for compatibility */ + if (params->hierarchy_information != HIERARCHY_NONE) + *auto_mode = 1; + case FEC_1_2: + break; + case FEC_2_3: + buf[2] |= (1 << 3); + break; + case FEC_3_4: + buf[2] |= (2 << 3); + break; + case FEC_5_6: + buf[2] |= (3 << 3); + break; + case FEC_7_8: + buf[2] |= (4 << 3); + break; + case FEC_NONE: + if (params->hierarchy_information == HIERARCHY_AUTO) + break; + default: + return -EINVAL; + } + + switch (params->bandwidth) { + case BANDWIDTH_6_MHZ: + break; + case BANDWIDTH_7_MHZ: + buf[1] |= (1 << 2); + break; + case BANDWIDTH_8_MHZ: + buf[1] |= (2 << 2); + break; + default: + return -EINVAL; + } + + /* program */ + for (i = 0; i < sizeof(buf); i++) { + ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]); + if (ret) + break; + } + + return ret; +} + +static int af9013_reset(struct af9013_state *state, u8 sleep) +{ + int ret; + u8 tmp, i; + deb_info("%s\n", __func__); + + /* enable OFDM reset */ + ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1); + if (ret) + goto error; + + /* start reset mechanism */ + ret = af9013_write_reg(state, 0xaeff, 1); + if (ret) + goto error; + + /* reset is done when bit 1 is set */ + for (i = 0; i < 150; i++) { + ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp); + if (ret) + goto error; + if (tmp) + break; /* reset done */ + msleep(10); + } + if (!tmp) + return -ETIMEDOUT; + + /* don't clear reset when going to sleep */ + if (!sleep) { + /* clear OFDM reset */ + ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); + if (ret) + goto error; + + /* disable OFDM reset */ + ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); + } +error: + return ret; +} + +static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) { + /* power on */ + ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0); + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); + } else { + /* power off */ + ret = af9013_reset(state, 1); + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1); + } +error: + return ret; +} + +static int af9013_lock_led(struct af9013_state *state, u8 onoff) +{ + deb_info("%s: onoff:%d\n", __func__, onoff); + + return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff); +} + +static int af9013_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 auto_mode; /* auto set TPS */ + + deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, + params->u.ofdm.bandwidth); + + state->frequency = params->frequency; + + /* program CFOE coefficients */ + ret = af9013_set_coeff(state, params->u.ofdm.bandwidth); + if (ret) + goto error; + + /* program frequency control */ + ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth); + if (ret) + goto error; + + /* clear TPS lock flag (inverted flag) */ + ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1); + if (ret) + goto error; + + /* clear MPEG2 lock flag */ + ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0); + if (ret) + goto error; + + /* empty channel function */ + ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0); + if (ret) + goto error; + + /* empty DVB-T channel function */ + ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0); + if (ret) + goto error; + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe, params); + + /* program TPS and bandwidth, check if auto mode needed */ + ret = af9013_set_ofdm_params(state, ¶ms->u.ofdm, &auto_mode); + if (ret) + goto error; + + if (auto_mode) { + /* clear easy mode flag */ + ret = af9013_write_reg(state, 0xaefd, 0); + deb_info("%s: auto TPS\n", __func__); + } else { + /* set easy mode flag */ + ret = af9013_write_reg(state, 0xaefd, 1); + if (ret) + goto error; + ret = af9013_write_reg(state, 0xaefe, 0); + deb_info("%s: manual TPS\n", __func__); + } + if (ret) + goto error; + + /* everything is set, lets try to receive channel - OFSM GO! */ + ret = af9013_write_reg(state, 0xffff, 0); + if (ret) + goto error; + +error: + return ret; +} + +static int af9013_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 i, buf[3]; + deb_info("%s\n", __func__); + + /* read TPS registers */ + for (i = 0; i < 3; i++) { + ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]); + if (ret) + goto error; + } + + switch ((buf[1] >> 6) & 3) { + case 0: + p->u.ofdm.constellation = QPSK; + break; + case 1: + p->u.ofdm.constellation = QAM_16; + break; + case 2: + p->u.ofdm.constellation = QAM_64; + break; + } + + switch ((buf[0] >> 0) & 3) { + case 0: + p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + } + + switch ((buf[0] >> 2) & 3) { + case 0: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; + } + + switch ((buf[0] >> 4) & 7) { + case 0: + p->u.ofdm.hierarchy_information = HIERARCHY_NONE; + break; + case 1: + p->u.ofdm.hierarchy_information = HIERARCHY_1; + break; + case 2: + p->u.ofdm.hierarchy_information = HIERARCHY_2; + break; + case 3: + p->u.ofdm.hierarchy_information = HIERARCHY_4; + break; + } + + switch ((buf[2] >> 0) & 7) { + case 0: + p->u.ofdm.code_rate_HP = FEC_1_2; + break; + case 1: + p->u.ofdm.code_rate_HP = FEC_2_3; + break; + case 2: + p->u.ofdm.code_rate_HP = FEC_3_4; + break; + case 3: + p->u.ofdm.code_rate_HP = FEC_5_6; + break; + case 4: + p->u.ofdm.code_rate_HP = FEC_7_8; + break; + } + + switch ((buf[2] >> 3) & 7) { + case 0: + p->u.ofdm.code_rate_LP = FEC_1_2; + break; + case 1: + p->u.ofdm.code_rate_LP = FEC_2_3; + break; + case 2: + p->u.ofdm.code_rate_LP = FEC_3_4; + break; + case 3: + p->u.ofdm.code_rate_LP = FEC_5_6; + break; + case 4: + p->u.ofdm.code_rate_LP = FEC_7_8; + break; + } + + switch ((buf[1] >> 2) & 3) { + case 0: + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + break; + case 1: + p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + break; + case 2: + p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + break; + } + + p->inversion = INVERSION_AUTO; + p->frequency = state->frequency; + +error: + return ret; +} + +static int af9013_update_ber_unc(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 buf[3], i; + u32 error_bit_count = 0; + u32 total_bit_count = 0; + u32 abort_packet_count = 0; + u64 numerator, denominator; + + state->ber = 0; + + /* check if error bit count is ready */ + ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]); + if (ret) + goto error; + if (!buf[0]) + goto exit; + + /* get RSD packet abort count */ + for (i = 0; i < 2; i++) { + ret = af9013_read_reg(state, 0xd38a + i, &buf[i]); + if (ret) + goto error; + } + abort_packet_count = (buf[1] << 8) + buf[0]; + + /* get error bit count */ + for (i = 0; i < 3; i++) { + ret = af9013_read_reg(state, 0xd387 + i, &buf[i]); + if (ret) + goto error; + } + error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0]; + error_bit_count = error_bit_count - abort_packet_count * 8 * 8; + + /* get used RSD counting period (10000 RSD packets used) */ + for (i = 0; i < 2; i++) { + ret = af9013_read_reg(state, 0xd385 + i, &buf[i]); + if (ret) + goto error; + } + total_bit_count = (buf[1] << 8) + buf[0]; + total_bit_count = total_bit_count - abort_packet_count; + total_bit_count = total_bit_count * 204 * 8; + + if (total_bit_count) { + numerator = error_bit_count * 1000000000; + denominator = total_bit_count; + state->ber = numerator / denominator; + } + + state->ucblocks += abort_packet_count; + + deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__, + error_bit_count, total_bit_count, abort_packet_count); + + /* set BER counting range */ + ret = af9013_write_reg(state, 0xd385, 10000 & 0xff); + if (ret) + goto error; + ret = af9013_write_reg(state, 0xd386, 10000 >> 8); + if (ret) + goto error; + /* reset and start BER counter */ + ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1); + if (ret) + goto error; + +exit: +error: + return ret; +} + +static int af9013_update_snr(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 buf[3], i, len; + u32 quant = 0; + struct snr_table *snr_table; + + /* check if quantizer ready (for snr) */ + ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); + if (ret) + goto error; + if (buf[0]) { + /* quantizer ready - read it */ + for (i = 0; i < 3; i++) { + ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]); + if (ret) + goto error; + } + quant = (buf[2] << 16) + (buf[1] << 8) + buf[0]; + + /* read current constellation */ + ret = af9013_read_reg(state, 0xd3c1, &buf[0]); + if (ret) + goto error; + + switch ((buf[0] >> 6) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_table); + snr_table = qpsk_snr_table; + break; + case 1: + len = ARRAY_SIZE(qam16_snr_table); + snr_table = qam16_snr_table; + break; + case 2: + len = ARRAY_SIZE(qam64_snr_table); + snr_table = qam64_snr_table; + break; + default: + len = 0; + break; + } + + if (len) { + for (i = 0; i < len; i++) { + if (quant < snr_table[i].val) { + state->snr = snr_table[i].snr * 10; + break; + } + } + } + + /* set quantizer super frame count */ + ret = af9013_write_reg(state, 0xd2e2, 1); + if (ret) + goto error; + + /* check quantizer availability */ + for (i = 0; i < 10; i++) { + msleep(10); + ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1, + &buf[0]); + if (ret) + goto error; + if (!buf[0]) + break; + } + + /* reset quantizer */ + ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1); + if (ret) + goto error; + } + +error: + return ret; +} + +static int af9013_update_signal_strength(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + u8 tmp0; + u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80; + int signal_strength; + + deb_info("%s\n", __func__); + + state->signal_strength = 0; + + ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0); + if (ret) + goto error; + if (tmp0) { + ret = af9013_read_reg(state, 0x9bbd, &rf_50); + if (ret) + goto error; + ret = af9013_read_reg(state, 0x9bd0, &rf_80); + if (ret) + goto error; + ret = af9013_read_reg(state, 0x9be2, &if_50); + if (ret) + goto error; + ret = af9013_read_reg(state, 0x9be4, &if_80); + if (ret) + goto error; + ret = af9013_read_reg(state, 0xd07c, &rf_gain); + if (ret) + goto error; + ret = af9013_read_reg(state, 0xd07d, &if_gain); + if (ret) + goto error; + signal_strength = (0xffff / (9 * (rf_50 + if_50) - \ + 11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \ + 11 * (rf_80 + if_80)); + if (signal_strength < 0) + signal_strength = 0; + else if (signal_strength > 0xffff) + signal_strength = 0xffff; + + state->signal_strength = signal_strength; + } + +error: + return ret; +} + +static int af9013_update_statistics(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + if (time_before(jiffies, state->next_statistics_check)) + return 0; + + /* set minimum statistic update interval */ + state->next_statistics_check = jiffies + msecs_to_jiffies(1200); + + ret = af9013_update_signal_strength(fe); + if (ret) + goto error; + ret = af9013_update_snr(fe); + if (ret) + goto error; + ret = af9013_update_ber_unc(fe); + if (ret) + goto error; + +error: + return ret; +} + +static int af9013_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 800; + fesettings->step_size = 0; + fesettings->max_drift = 0; + + return 0; +} + +static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret = 0; + u8 tmp; + *status = 0; + + /* TPS lock */ + ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; + + /* MPEG2 lock */ + ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + + if (!*status & FE_HAS_SIGNAL) { + /* AGC lock */ + ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_SIGNAL; + } + + if (!*status & FE_HAS_CARRIER) { + /* CFO lock */ + ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_CARRIER; + } + + if (!*status & FE_HAS_CARRIER) { + /* SFOE lock */ + ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); + if (ret) + goto error; + if (tmp) + *status |= FE_HAS_CARRIER; + } + + ret = af9013_update_statistics(fe); + +error: + return ret; +} + + +static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *ber = state->ber; + return ret; +} + +static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *strength = state->signal_strength; + return ret; +} + +static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *snr = state->snr; + return ret; +} + +static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + ret = af9013_update_statistics(fe); + *ucblocks = state->ucblocks; + return ret; +} + +static int af9013_sleep(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + deb_info("%s\n", __func__); + + ret = af9013_lock_led(state, 0); + if (ret) + goto error; + + ret = af9013_power_ctrl(state, 0); +error: + return ret; +} + +static int af9013_init(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret, i, len; + u8 tmp0, tmp1; + struct regdesc *init; + deb_info("%s\n", __func__); + + /* reset OFDM */ + ret = af9013_reset(state, 0); + if (ret) + goto error; + + /* power on */ + ret = af9013_power_ctrl(state, 1); + if (ret) + goto error; + + /* enable ADC */ + ret = af9013_write_reg(state, 0xd73a, 0xa4); + if (ret) + goto error; + + /* write API version to firmware */ + for (i = 0; i < sizeof(state->config.api_version); i++) { + ret = af9013_write_reg(state, 0x9bf2 + i, + state->config.api_version[i]); + if (ret) + goto error; + } + + /* program ADC control */ + ret = af9013_set_adc_ctrl(state); + if (ret) + goto error; + + /* set I2C master clock */ + ret = af9013_write_reg(state, 0xd416, 0x14); + if (ret) + goto error; + + /* set 16 embx */ + ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1); + if (ret) + goto error; + + /* set no trigger */ + ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0); + if (ret) + goto error; + + /* set read-update bit for constellation */ + ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1); + if (ret) + goto error; + + /* enable FEC monitor */ + ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1); + if (ret) + goto error; + + /* load OFSM settings */ + deb_info("%s: load ofsm settings\n", __func__); + len = ARRAY_SIZE(ofsm_init); + init = ofsm_init; + for (i = 0; i < len; i++) { + ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + init[i].len, init[i].val); + if (ret) + goto error; + } + + /* load tuner specific settings */ + deb_info("%s: load tuner specific settings\n", __func__); + switch (state->config.tuner) { + case AF9013_TUNER_MXL5003D: + len = ARRAY_SIZE(tuner_init_mxl5003d); + init = tuner_init_mxl5003d; + break; + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + len = ARRAY_SIZE(tuner_init_mxl5005); + init = tuner_init_mxl5005; + break; + case AF9013_TUNER_ENV77H11D5: + len = ARRAY_SIZE(tuner_init_env77h11d5); + init = tuner_init_env77h11d5; + break; + case AF9013_TUNER_MT2060: + len = ARRAY_SIZE(tuner_init_mt2060); + init = tuner_init_mt2060; + break; + case AF9013_TUNER_MC44S803: + len = ARRAY_SIZE(tuner_init_mc44s803); + init = tuner_init_mc44s803; + break; + case AF9013_TUNER_QT1010: + case AF9013_TUNER_QT1010A: + len = ARRAY_SIZE(tuner_init_qt1010); + init = tuner_init_qt1010; + break; + case AF9013_TUNER_MT2060_2: + len = ARRAY_SIZE(tuner_init_mt2060_2); + init = tuner_init_mt2060_2; + break; + case AF9013_TUNER_TDA18271: + len = ARRAY_SIZE(tuner_init_tda18271); + init = tuner_init_tda18271; + break; + case AF9013_TUNER_UNKNOWN: + default: + len = ARRAY_SIZE(tuner_init_unknown); + init = tuner_init_unknown; + break; + } + + for (i = 0; i < len; i++) { + ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + init[i].len, init[i].val); + if (ret) + goto error; + } + + /* set TS mode */ + deb_info("%s: setting ts mode\n", __func__); + tmp0 = 0; /* parallel mode */ + tmp1 = 0; /* serial mode */ + switch (state->config.output_mode) { + case AF9013_OUTPUT_MODE_PARALLEL: + tmp0 = 1; + break; + case AF9013_OUTPUT_MODE_SERIAL: + tmp1 = 1; + break; + case AF9013_OUTPUT_MODE_USB: + /* usb mode for AF9015 */ + default: + break; + } + ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */ + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */ + if (ret) + goto error; + + /* enable lock led */ + ret = af9013_lock_led(state, 1); + if (ret) + goto error; + +error: + return ret; +} + +static struct dvb_frontend_ops af9013_ops; + +static int af9013_download_firmware(struct af9013_state *state) +{ + int i, len, packets, remainder, ret; + const struct firmware *fw; + u16 addr = 0x5100; /* firmware start address */ + u16 checksum = 0; + u8 val; + u8 fw_params[4]; + u8 *data; + u8 *fw_file = AF9013_DEFAULT_FIRMWARE; + + msleep(100); + /* check whether firmware is already running */ + ret = af9013_read_reg(state, 0x98be, &val); + if (ret) + goto error; + else + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c) /* fw is running, no need for download */ + goto exit; + + info("found a '%s' in cold state, will try to load a firmware", + af9013_ops.info.name); + + /* request the firmware, this will block and timeout */ + ret = request_firmware(&fw, fw_file, &state->i2c->dev); + if (ret) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details" \ + " on firmware-problems. (%d)", + fw_file, ret); + goto error; + } + + info("downloading firmware from file '%s'", fw_file); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + fw_params[0] = checksum >> 8; + fw_params[1] = checksum & 0xff; + fw_params[2] = fw->size >> 8; + fw_params[3] = fw->size & 0xff; + + /* write fw checksum & size */ + ret = af9013_write_ofsm_regs(state, 0x50fc, + fw_params, sizeof(fw_params)); + if (ret) + goto error_release; + + #define FW_PACKET_MAX_DATA 16 + + packets = fw->size / FW_PACKET_MAX_DATA; + remainder = fw->size % FW_PACKET_MAX_DATA; + len = FW_PACKET_MAX_DATA; + for (i = 0; i <= packets; i++) { + if (i == packets) /* set size of the last packet */ + len = remainder; + + data = (fw->data + i * FW_PACKET_MAX_DATA); + ret = af9013_write_ofsm_regs(state, addr, data, len); + addr += FW_PACKET_MAX_DATA; + + if (ret) { + err("firmware download failed at %d with %d", i, ret); + goto error_release; + } + } + + #undef FW_PACKET_MAX_DATA + + /* request boot firmware */ + ret = af9013_write_reg(state, 0xe205, 1); + if (ret) + goto error_release; + + for (i = 0; i < 15; i++) { + msleep(100); + + /* check firmware status */ + ret = af9013_read_reg(state, 0x98be, &val); + if (ret) + goto error_release; + + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c || val == 0x04) /* success or fail */ + break; + } + + if (val == 0x04) { + err("firmware did not run"); + ret = -1; + } else if (val != 0x0c) { + err("firmware boot timeout"); + ret = -1; + } + +error_release: + release_firmware(fw); +error: +exit: + if (!ret) + info("found a '%s' in warm state.", af9013_ops.info.name); + return ret; +} + +static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int ret; + struct af9013_state *state = fe->demodulator_priv; + deb_info("%s: enable:%d\n", __func__, enable); + + if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) + ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable); + else + ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable); + + return ret; +} + +static void af9013_release(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops af9013_ops; + +struct dvb_frontend *af9013_attach(const struct af9013_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct af9013_state *state = NULL; + u8 buf[3], i; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + memcpy(&state->config, config, sizeof(struct af9013_config)); + + /* chip version */ + ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); + if (ret) + goto error; + + /* ROM version */ + for (i = 0; i < 2; i++) { + ret = af9013_read_reg(state, 0x116b + i, &buf[i]); + if (ret) + goto error; + } + deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, + buf[2], buf[0], buf[1]); + + /* download firmware */ + if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { + ret = af9013_download_firmware(state); + if (ret) + goto error; + } + + /* firmware version */ + for (i = 0; i < 3; i++) { + ret = af9013_read_reg(state, 0x5103 + i, &buf[i]); + if (ret) + goto error; + } + info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]); + + /* settings for mp2if */ + if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { + /* AF9015 split PSB to 1.5k + 0.5k */ + ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1); + } else { + /* AF9013 change the output bit to data7 */ + ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1); + if (ret) + goto error; + /* AF9013 set mpeg to full speed */ + ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1); + } + if (ret) + goto error; + ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1); + if (ret) + goto error; + + /* set GPIOs */ + for (i = 0; i < sizeof(state->config.gpio); i++) { + ret = af9013_set_gpio(state, i, state->config.gpio[i]); + if (ret) + goto error; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &af9013_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + return &state->frontend; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(af9013_attach); + +static struct dvb_frontend_ops af9013_ops = { + .info = { + .name = "Afatech AF9013 DVB-T", + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 250000, + .frequency_tolerance = 0, + .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_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, + + .release = af9013_release, + .init = af9013_init, + .sleep = af9013_sleep, + .i2c_gate_ctrl = af9013_i2c_gate_ctrl, + + .set_frontend = af9013_set_frontend, + .get_frontend = af9013_get_frontend, + + .get_tune_settings = af9013_get_tune_settings, + + .read_status = af9013_read_status, + .read_ber = af9013_read_ber, + .read_signal_strength = af9013_read_signal_strength, + .read_snr = af9013_read_snr, + .read_ucblocks = af9013_read_ucblocks, +}; + +module_param_named(debug, af9013_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h new file mode 100644 index 000000000000..28b90c91c766 --- /dev/null +++ b/drivers/media/dvb/frontends/af9013.h @@ -0,0 +1,107 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 _AF9013_H_ +#define _AF9013_H_ + +#include + +enum af9013_ts_mode { + AF9013_OUTPUT_MODE_PARALLEL, + AF9013_OUTPUT_MODE_SERIAL, + AF9013_OUTPUT_MODE_USB, /* only for AF9015 */ +}; + +enum af9013_tuner { + AF9013_TUNER_MXL5003D = 3, /* MaxLinear */ + AF9013_TUNER_MXL5005D = 13, /* MaxLinear */ + AF9013_TUNER_MXL5005R = 30, /* MaxLinear */ + AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */ + AF9013_TUNER_MT2060 = 130, /* Microtune */ + AF9013_TUNER_MC44S803 = 133, /* Freescale */ + AF9013_TUNER_QT1010 = 134, /* Quantek */ + AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */ + AF9013_TUNER_MT2060_2 = 147, /* Microtune */ + AF9013_TUNER_TDA18271 = 156, /* NXP */ + AF9013_TUNER_QT1010A = 162, /* Quantek */ +}; + +/* AF9013/5 GPIOs (mostly guessed) + demod#1-gpio#0 - set demod#2 i2c-addr for dual devices + demod#1-gpio#1 - xtal setting (?) + demod#1-gpio#3 - tuner#1 + demod#2-gpio#0 - tuner#2 + demod#2-gpio#1 - xtal setting (?) +*/ +#define AF9013_GPIO_ON (1 << 0) +#define AF9013_GPIO_EN (1 << 1) +#define AF9013_GPIO_O (1 << 2) +#define AF9013_GPIO_I (1 << 3) + +#define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN) +#define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) + +#define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN) +#define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) + +struct af9013_config { + /* demodulator's I2C address */ + u8 demod_address; + + /* frequencies in kHz */ + u32 adc_clock; + + /* tuner ID */ + u8 tuner; + + /* tuner IF */ + u16 tuner_if; + + /* TS data output mode */ + u8 output_mode:2; + + /* RF spectrum inversion */ + u8 rf_spec_inv:1; + + /* API version */ + u8 api_version[4]; + + /* GPIOs */ + u8 gpio[4]; +}; + + +#if defined(CONFIG_DVB_AF9013) || \ + (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) +extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *af9013_attach( +const struct af9013_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_AF9013 */ + +#endif /* _AF9013_H_ */ diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h new file mode 100644 index 000000000000..163e251d0b73 --- /dev/null +++ b/drivers/media/dvb/frontends/af9013_priv.h @@ -0,0 +1,869 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 _AF9013_PRIV_ +#define _AF9013_PRIV_ + +#define LOG_PREFIX "af9013" +extern int af9013_debug; + +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) + +#define debug_dump(b, l, func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ + func("\n");\ +} + +#define deb_info(args...) dprintk(af9013_debug, 0x01, args) + +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +#define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw" + +struct regdesc { + u16 addr; + u8 pos:4; + u8 len:4; + u8 val; +}; + +struct snr_table { + u32 val; + u8 snr; +}; + +/* QPSK SNR lookup table */ +static struct snr_table qpsk_snr_table[] = { + { 0x0b4771, 0 }, + { 0x0c1aed, 1 }, + { 0x0d0d27, 2 }, + { 0x0e4d19, 3 }, + { 0x0e5da8, 4 }, + { 0x107097, 5 }, + { 0x116975, 6 }, + { 0x1252d9, 7 }, + { 0x131fa4, 8 }, + { 0x13d5e1, 9 }, + { 0x148e53, 10 }, + { 0x15358b, 11 }, + { 0x15dd29, 12 }, + { 0x168112, 13 }, + { 0x170b61, 14 }, + { 0xffffff, 15 }, +}; + +/* QAM16 SNR lookup table */ +static struct snr_table qam16_snr_table[] = { + { 0x05eb62, 5 }, + { 0x05fecf, 6 }, + { 0x060b80, 7 }, + { 0x062501, 8 }, + { 0x064865, 9 }, + { 0x069604, 10 }, + { 0x06f356, 11 }, + { 0x07706a, 12 }, + { 0x0804d3, 13 }, + { 0x089d1a, 14 }, + { 0x093e3d, 15 }, + { 0x09e35d, 16 }, + { 0x0a7c3c, 17 }, + { 0x0afaf8, 18 }, + { 0x0b719d, 19 }, + { 0xffffff, 20 }, +}; + +/* QAM64 SNR lookup table */ +static struct snr_table qam64_snr_table[] = { + { 0x03109b, 12 }, + { 0x0310d4, 13 }, + { 0x031920, 14 }, + { 0x0322d0, 15 }, + { 0x0339fc, 16 }, + { 0x0364a1, 17 }, + { 0x038bcc, 18 }, + { 0x03c7d3, 19 }, + { 0x0408cc, 20 }, + { 0x043bed, 21 }, + { 0x048061, 22 }, + { 0x04be95, 23 }, + { 0x04fa7d, 24 }, + { 0x052405, 25 }, + { 0x05570d, 26 }, + { 0xffffff, 27 }, +}; + +static struct regdesc ofsm_init[] = { + { 0xd73a, 0, 8, 0xa1 }, + { 0xd73b, 0, 8, 0x1f }, + { 0xd73c, 4, 4, 0x0a }, + { 0xd732, 3, 1, 0x00 }, + { 0xd731, 4, 2, 0x03 }, + { 0xd73d, 7, 1, 0x01 }, + { 0xd740, 0, 1, 0x00 }, + { 0xd740, 1, 1, 0x00 }, + { 0xd740, 2, 1, 0x00 }, + { 0xd740, 3, 1, 0x01 }, + { 0xd3c1, 4, 1, 0x01 }, + { 0xd3a2, 0, 8, 0x00 }, + { 0xd3a3, 0, 8, 0x04 }, + { 0xd305, 0, 8, 0x32 }, + { 0xd306, 0, 8, 0x10 }, + { 0xd304, 0, 8, 0x04 }, + { 0x9112, 0, 1, 0x01 }, + { 0x911d, 0, 1, 0x01 }, + { 0x911a, 0, 1, 0x01 }, + { 0x911b, 0, 1, 0x01 }, + { 0x9bce, 0, 4, 0x02 }, + { 0x9116, 0, 1, 0x01 }, + { 0x9bd1, 0, 1, 0x01 }, + { 0xd2e0, 0, 8, 0xd0 }, + { 0xd2e9, 0, 4, 0x0d }, + { 0xd38c, 0, 8, 0xfc }, + { 0xd38d, 0, 8, 0x00 }, + { 0xd38e, 0, 8, 0x7e }, + { 0xd38f, 0, 8, 0x00 }, + { 0xd390, 0, 8, 0x2f }, + { 0xd145, 4, 1, 0x01 }, + { 0xd1a9, 4, 1, 0x01 }, + { 0xd158, 5, 3, 0x01 }, + { 0xd159, 0, 6, 0x06 }, + { 0xd167, 0, 8, 0x00 }, + { 0xd168, 0, 4, 0x07 }, + { 0xd1c3, 5, 3, 0x00 }, + { 0xd1c4, 0, 6, 0x00 }, + { 0xd1c5, 0, 7, 0x10 }, + { 0xd1c6, 0, 3, 0x02 }, + { 0xd080, 2, 5, 0x03 }, + { 0xd081, 4, 4, 0x09 }, + { 0xd098, 4, 4, 0x0f }, + { 0xd098, 0, 4, 0x03 }, + { 0xdbc0, 3, 1, 0x01 }, + { 0xdbc0, 4, 1, 0x01 }, + { 0xdbc7, 0, 8, 0x08 }, + { 0xdbc8, 4, 4, 0x00 }, + { 0xdbc9, 0, 5, 0x01 }, + { 0xd280, 0, 8, 0xe0 }, + { 0xd281, 0, 8, 0xff }, + { 0xd282, 0, 8, 0xff }, + { 0xd283, 0, 8, 0xc3 }, + { 0xd284, 0, 8, 0xff }, + { 0xd285, 0, 4, 0x01 }, + { 0xd0f0, 0, 7, 0x1a }, + { 0xd0f1, 4, 1, 0x01 }, + { 0xd0f2, 0, 8, 0x0c }, + { 0xd103, 0, 4, 0x08 }, + { 0xd0f8, 0, 7, 0x20 }, + { 0xd111, 5, 1, 0x00 }, + { 0xd111, 6, 1, 0x00 }, + { 0x910b, 0, 8, 0x0a }, + { 0x9115, 0, 8, 0x02 }, + { 0x910c, 0, 8, 0x02 }, + { 0x910d, 0, 8, 0x08 }, + { 0x910e, 0, 8, 0x0a }, + { 0x9bf6, 0, 8, 0x06 }, + { 0x9bf8, 0, 8, 0x02 }, + { 0x9bf7, 0, 8, 0x05 }, + { 0x9bf9, 0, 8, 0x0f }, + { 0x9bfc, 0, 8, 0x13 }, + { 0x9bd3, 0, 8, 0xff }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, +}; + +/* Panasonic ENV77H11D5 tuner init + AF9013_TUNER_ENV77H11D5 = 129 */ +static struct regdesc tuner_init_env77h11d5[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x03 }, + { 0x9bbe, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0xd015, 0, 8, 0x50 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0xdf }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x44 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0xeb }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xf4 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bba, 0, 8, 0xf9 }, + { 0x9bc3, 0, 8, 0xdf }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0xeb }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bc9, 0, 8, 0x52 }, + { 0xd011, 0, 8, 0x3c }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xf7 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x0b }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x4d }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* Microtune MT2060 tuner init + AF9013_TUNER_MT2060 = 130 */ +static struct regdesc tuner_init_mt2060[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x07 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0x9bbe, 0, 1, 0x00 }, + { 0x9bcc, 0, 1, 0x00 }, + { 0x9bb9, 0, 8, 0x75 }, + { 0x9bcd, 0, 8, 0x24 }, + { 0x9bff, 0, 8, 0x30 }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x32 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x36 }, + { 0xd00d, 0, 2, 0x03 }, + { 0xd00a, 0, 8, 0x35 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x07 }, + { 0x9bc8, 0, 8, 0x90 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x36 }, + { 0x9bc6, 0, 8, 0x03 }, + { 0x9bba, 0, 8, 0xc9 }, + { 0x9bc9, 0, 8, 0x79 }, + { 0xd011, 0, 8, 0x10 }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0x45 }, + { 0xd014, 0, 2, 0x03 }, + { 0xd040, 0, 8, 0x98 }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0xcf }, + { 0xd043, 0, 2, 0x03 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0xcc }, + { 0x9be4, 0, 8, 0xa0 }, + { 0x9bbd, 0, 8, 0x8e }, + { 0x9be2, 0, 8, 0x4d }, + { 0x9bee, 0, 1, 0x01 }, +}; + +/* Microtune MT2060 tuner init + AF9013_TUNER_MT2060_2 = 147 */ +static struct regdesc tuner_init_mt2060_2[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x06 }, + { 0x9bbe, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x32 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x36 }, + { 0xd00d, 0, 2, 0x03 }, + { 0xd00a, 0, 8, 0x35 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x07 }, + { 0x9bc8, 0, 8, 0x90 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x36 }, + { 0x9bc6, 0, 8, 0x03 }, + { 0x9bba, 0, 8, 0xc9 }, + { 0x9bc9, 0, 8, 0x79 }, + { 0xd011, 0, 8, 0x10 }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0x45 }, + { 0xd014, 0, 2, 0x03 }, + { 0xd040, 0, 8, 0x98 }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0xcf }, + { 0xd043, 0, 2, 0x03 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 8, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x96 }, + { 0xd054, 0, 8, 0x46 }, + { 0xd045, 7, 1, 0x00 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* MaxLinear MXL5003 tuner init + AF9013_TUNER_MXL5003D = 3 */ +static struct regdesc tuner_init_mxl5003d[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x09 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0x9bfc, 0, 8, 0x0f }, + { 0x9bf6, 0, 8, 0x01 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0xd015, 0, 8, 0x33 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x40 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x6c }, + { 0xd007, 0, 2, 0x00 }, + { 0xd00c, 0, 8, 0x3d }, + { 0xd00d, 0, 2, 0x00 }, + { 0xd00a, 0, 8, 0x45 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x07 }, + { 0x9bc8, 0, 8, 0x52 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x3d }, + { 0x9bc6, 0, 8, 0x00 }, + { 0x9bba, 0, 8, 0xa2 }, + { 0x9bc9, 0, 8, 0xa0 }, + { 0xd011, 0, 8, 0x56 }, + { 0xd012, 0, 2, 0x00 }, + { 0xd013, 0, 8, 0x50 }, + { 0xd014, 0, 2, 0x00 }, + { 0xd040, 0, 8, 0x56 }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0x50 }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 8, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* MaxLinear MXL5005 tuner init + AF9013_TUNER_MXL5005D = 13 + AF9013_TUNER_MXL5005R = 30 */ +static struct regdesc tuner_init_mxl5005[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x07 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x28 }, + { 0x9bff, 0, 8, 0x24 }, + { 0xd015, 0, 8, 0x40 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x40 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x73 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0xfa }, + { 0xd00d, 0, 2, 0x01 }, + { 0xd00a, 0, 8, 0xff }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x23 }, + { 0x9bc8, 0, 8, 0x55 }, + { 0x9bc3, 0, 8, 0x01 }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0xfa }, + { 0x9bc6, 0, 8, 0x01 }, + { 0x9bba, 0, 8, 0xff }, + { 0x9bc9, 0, 8, 0xff }, + { 0x9bd3, 0, 8, 0x95 }, + { 0xd011, 0, 8, 0x70 }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xfb }, + { 0xd014, 0, 2, 0x01 }, + { 0xd040, 0, 8, 0x70 }, + { 0xd041, 0, 2, 0x01 }, + { 0xd042, 0, 8, 0xfb }, + { 0xd043, 0, 2, 0x01 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0x93 }, + { 0x9be4, 0, 8, 0xfe }, + { 0x9bbd, 0, 8, 0x63 }, + { 0x9be2, 0, 8, 0xfe }, + { 0x9bee, 0, 1, 0x01 }, +}; + +/* Quantek QT1010 tuner init + AF9013_TUNER_QT1010 = 134 + AF9013_TUNER_QT1010A = 162 */ +static struct regdesc tuner_init_qt1010[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x09 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x28 }, + { 0x9bff, 0, 8, 0x20 }, + { 0xd008, 0, 8, 0x0f }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x99 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x0f }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0x50 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x00 }, + { 0x9bc8, 0, 8, 0x00 }, + { 0x9bc3, 0, 8, 0x0f }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x0f }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bba, 0, 8, 0xc5 }, + { 0x9bc9, 0, 8, 0xff }, + { 0xd011, 0, 8, 0x58 }, + { 0xd012, 0, 2, 0x02 }, + { 0xd013, 0, 8, 0x89 }, + { 0xd014, 0, 2, 0x01 }, + { 0xd040, 0, 8, 0x58 }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x89 }, + { 0xd043, 0, 2, 0x01 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0xcd }, + { 0x9be4, 0, 8, 0xbb }, + { 0x9bbd, 0, 8, 0x93 }, + { 0x9be2, 0, 8, 0x80 }, + { 0x9bee, 0, 1, 0x01 }, +}; + +/* Freescale MC44S803 tuner init + AF9013_TUNER_MC44S803 = 133 */ +static struct regdesc tuner_init_mc44s803[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x06 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x00 }, + { 0x9be3, 0, 8, 0x00 }, + { 0x9bf6, 0, 8, 0x01 }, + { 0x9bf8, 0, 8, 0x02 }, + { 0x9bf9, 0, 8, 0x02 }, + { 0x9bfc, 0, 8, 0x1f }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x24 }, + { 0x9bff, 0, 8, 0x24 }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0x01 }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x7b }, + { 0xd007, 0, 2, 0x00 }, + { 0xd00c, 0, 8, 0x7c }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xfe }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bc7, 0, 8, 0x08 }, + { 0x9bc8, 0, 8, 0x9a }, + { 0x9bc3, 0, 8, 0x01 }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x7c }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bba, 0, 8, 0xfc }, + { 0x9bc9, 0, 8, 0xaa }, + { 0xd011, 0, 8, 0x6b }, + { 0xd012, 0, 2, 0x00 }, + { 0xd013, 0, 8, 0x88 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x6b }, + { 0xd041, 0, 2, 0x00 }, + { 0xd042, 0, 8, 0x7c }, + { 0xd043, 0, 2, 0x02 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0x9e }, + { 0x9be4, 0, 8, 0xff }, + { 0x9bbd, 0, 8, 0x9e }, + { 0x9be2, 0, 8, 0x25 }, + { 0x9bee, 0, 1, 0x01 }, + { 0xd73b, 3, 1, 0x00 }, +}; + +/* unknown, probably for tin can tuner, tuner init + AF9013_TUNER_UNKNOWN = 140 */ +static struct regdesc tuner_init_unknown[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x02 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x00 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x18 }, + { 0x9bff, 0, 8, 0x2c }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0xdf }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x44 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x00 }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xf6 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bba, 0, 8, 0xf9 }, + { 0x9bc8, 0, 8, 0xaa }, + { 0x9bc3, 0, 8, 0xdf }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x00 }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bc9, 0, 8, 0xf0 }, + { 0xd011, 0, 8, 0x3c }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xf7 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x0b }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x4d }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, +}; + +/* NXP TDA18271 tuner init + AF9013_TUNER_TDA18271 = 156 */ +static struct regdesc tuner_init_tda18271[] = { + { 0x9bd5, 0, 8, 0x01 }, + { 0x9bd6, 0, 8, 0x04 }, + { 0xd1a0, 1, 1, 0x01 }, + { 0xd000, 0, 1, 0x01 }, + { 0xd000, 1, 1, 0x00 }, + { 0xd001, 1, 1, 0x01 }, + { 0xd001, 0, 1, 0x00 }, + { 0xd001, 5, 1, 0x00 }, + { 0xd002, 0, 5, 0x19 }, + { 0xd003, 0, 5, 0x1a }, + { 0xd004, 0, 5, 0x19 }, + { 0xd005, 0, 5, 0x1a }, + { 0xd00e, 0, 5, 0x10 }, + { 0xd00f, 0, 3, 0x04 }, + { 0xd00f, 3, 3, 0x05 }, + { 0xd010, 0, 3, 0x04 }, + { 0xd010, 3, 3, 0x05 }, + { 0xd016, 4, 4, 0x03 }, + { 0xd01f, 0, 6, 0x0a }, + { 0xd020, 0, 6, 0x0a }, + { 0x9bda, 0, 8, 0x01 }, + { 0x9be3, 0, 8, 0x01 }, + { 0xd1a0, 1, 1, 0x00 }, + { 0x9bbe, 0, 1, 0x01 }, + { 0x9bcc, 0, 1, 0x01 }, + { 0x9bb9, 0, 8, 0x00 }, + { 0x9bcd, 0, 8, 0x18 }, + { 0x9bff, 0, 8, 0x2c }, + { 0xd015, 0, 8, 0x46 }, + { 0xd016, 0, 1, 0x00 }, + { 0xd044, 0, 8, 0x46 }, + { 0xd045, 0, 1, 0x00 }, + { 0xd008, 0, 8, 0xdf }, + { 0xd009, 0, 2, 0x02 }, + { 0xd006, 0, 8, 0x44 }, + { 0xd007, 0, 2, 0x01 }, + { 0xd00c, 0, 8, 0x00 }, + { 0xd00d, 0, 2, 0x02 }, + { 0xd00a, 0, 8, 0xf6 }, + { 0xd00b, 0, 2, 0x01 }, + { 0x9bba, 0, 8, 0xf9 }, + { 0x9bc8, 0, 8, 0xaa }, + { 0x9bc3, 0, 8, 0xdf }, + { 0x9bc4, 0, 8, 0x02 }, + { 0x9bc5, 0, 8, 0x00 }, + { 0x9bc6, 0, 8, 0x02 }, + { 0x9bc9, 0, 8, 0xf0 }, + { 0xd011, 0, 8, 0x3c }, + { 0xd012, 0, 2, 0x01 }, + { 0xd013, 0, 8, 0xf7 }, + { 0xd014, 0, 2, 0x02 }, + { 0xd040, 0, 8, 0x0b }, + { 0xd041, 0, 2, 0x02 }, + { 0xd042, 0, 8, 0x4d }, + { 0xd043, 0, 2, 0x00 }, + { 0xd045, 1, 1, 0x00 }, + { 0x9bcf, 0, 1, 0x01 }, + { 0xd045, 2, 1, 0x01 }, + { 0xd04f, 0, 8, 0x9a }, + { 0xd050, 0, 1, 0x01 }, + { 0xd051, 0, 8, 0x5a }, + { 0xd052, 0, 1, 0x01 }, + { 0xd053, 0, 8, 0x50 }, + { 0xd054, 0, 8, 0x46 }, + { 0x9bd7, 0, 8, 0x0a }, + { 0x9bd8, 0, 8, 0x14 }, + { 0x9bd9, 0, 8, 0x08 }, + { 0x9bd0, 0, 8, 0xa8 }, + { 0x9be4, 0, 8, 0x7f }, + { 0x9bbd, 0, 8, 0xa8 }, + { 0x9be2, 0, 8, 0x20 }, + { 0x9bee, 0, 1, 0x01 }, +}; + +#endif /* _AF9013_PRIV_ */ -- cgit v1.2.1 From 80619de8117701cad1fb5526be6fcfe6fc2a6cc2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 15 Sep 2008 17:18:09 -0300 Subject: V4L/DVB (8972): initial driver for af9015 chipset - initial driver for the Afatech AF9015 chipset Thanks-to: Mark Spieth Thanks-to: Lee Essen Thanks-to: Luca Olivetti Thanks-to: Andrew Leech Thanks-to: Nick Andrew Thanks-to: Rafael Antoniello Thanks-to: Jarryd Beck Thanks-to: Jose Alberto Reguero Thanks-to: Benjamin Larsson Thanks-to: Wolfgang Breyha Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 12 + drivers/media/dvb/dvb-usb/Makefile | 3 + drivers/media/dvb/dvb-usb/af9015.c | 1459 +++++++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/af9015.h | 524 +++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 17 +- 5 files changed, 2014 insertions(+), 1 deletion(-) create mode 100644 drivers/media/dvb/dvb-usb/af9015.c create mode 100644 drivers/media/dvb/dvb-usb/af9015.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 1d9e98cee9e7..b35d7f0db9aa 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -271,3 +271,15 @@ config DVB_USB_DTV5100 select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. + +config DVB_USB_AF9015 + tristate "Afatech AF9015 DVB-T USB2.0 support" + depends on DVB_USB && EXPERIMENTAL + select DVB_AF9013 + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + help + Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 116544f4272d..ece8c9dfed18 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -70,6 +70,9 @@ obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o dvb-usb-dtv5100-objs = dtv5100.o obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o +dvb-usb-af9015-objs = af9015.o +obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c new file mode 100644 index 000000000000..a284648094c2 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -0,0 +1,1459 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 "af9015.h" +#include "af9013.h" +#include "mt2060.h" +#include "qt1010.h" +#include "tda18271.h" +#include "mxl5005s.h" +#if 0 +#include "mc44s80x.h" +#endif + +int dvb_usb_af9015_debug; +module_param_named(debug, dvb_usb_af9015_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +int dvb_usb_af9015_remote; +module_param_named(remote, dvb_usb_af9015_remote, int, 0644); +MODULE_PARM_DESC(remote, "select remote"); +int dvb_usb_af9015_dual_mode; +module_param_named(dual_mode, dvb_usb_af9015_dual_mode, int, 0644); +MODULE_PARM_DESC(dual_mode, "enable dual mode"); +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static DEFINE_MUTEX(af9015_usb_mutex); + +static struct af9015_config af9015_config; +static struct dvb_usb_device_properties af9015_properties[2]; +int af9015_properties_count = ARRAY_SIZE(af9015_properties); + +static struct af9013_config af9015_af9013_config[] = { + { + .demod_address = AF9015_I2C_DEMOD, + .output_mode = AF9013_OUTPUT_MODE_USB, + .api_version = { 0, 1, 9, 0 }, + .gpio[0] = AF9013_GPIO_HI, + .gpio[1] = AF9013_GPIO_LO, + .gpio[3] = AF9013_GPIO_TUNER_ON, + + }, { + .output_mode = AF9013_OUTPUT_MODE_SERIAL, + .api_version = { 0, 1, 9, 0 }, + .gpio[0] = AF9013_GPIO_TUNER_ON, + .gpio[1] = AF9013_GPIO_LO, + } +}; + +static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) +{ + int act_len, ret; + u8 buf[64]; + u8 write = 1; + u8 msg_len = 8; + static u8 seq; /* packet sequence number */ + + if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) + return -EAGAIN; + + buf[0] = req->cmd; + buf[1] = seq++; + buf[2] = req->i2c_addr; + buf[3] = req->addr >> 8; + buf[4] = req->addr & 0xff; + buf[5] = req->mbox; + buf[6] = req->addr_len; + buf[7] = req->data_len; + + switch (req->cmd) { + case GET_CONFIG: + case BOOT: + case READ_MEMORY: + case RECONNECT_USB: + case GET_IR_CODE: + write = 0; + break; + case READ_I2C: + write = 0; + buf[2] |= 0x01; /* set I2C direction */ + case WRITE_I2C: + buf[0] = READ_WRITE_I2C; + break; + case WRITE_MEMORY: + if (((req->addr & 0xff00) == 0xff00) || + ((req->addr & 0xae00) == 0xae00)) + buf[0] = WRITE_VIRTUAL_MEMORY; + case WRITE_VIRTUAL_MEMORY: + case COPY_FIRMWARE: + case DOWNLOAD_FIRMWARE: + break; + default: + err("unknown command:%d", req->cmd); + ret = -1; + goto error_unlock; + } + + /* write requested */ + if (write) { + memcpy(&buf[8], req->data, req->data_len); + msg_len += req->data_len; + } + deb_xfer(">>> "); + debug_dump(buf, msg_len, deb_xfer); + + /* send req */ + ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, + &act_len, AF9015_USB_TIMEOUT); + if (ret) + err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); + else + if (act_len != msg_len) + ret = -1; /* all data is not send */ + if (ret) + goto error_unlock; + + /* no ack for those packets */ + if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) + goto exit_unlock; + + /* receive ack and data if read req */ + msg_len = 1 + 1 + req->data_len; /* seq + status + data len */ + ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, + &act_len, AF9015_USB_TIMEOUT); + if (ret) { + err("recv bulk message failed:%d", ret); + ret = -1; + goto error_unlock; + } + + deb_xfer("<<< "); + debug_dump(buf, act_len, deb_xfer); + + /* remote controller query status is 1 if remote code is not received */ + if (req->cmd == GET_IR_CODE && buf[1] == 1) { + buf[1] = 0; /* clear command "error" status */ + memset(&buf[2], 0, req->data_len); + buf[3] = 1; /* no remote code received mark */ + } + + /* check status */ + if (buf[1]) { + err("command failed:%d", buf[1]); + ret = -1; + goto error_unlock; + } + + /* read request, copy returned data to return buf */ + if (!write) + memcpy(req->data, &buf[2], req->data_len); + +error_unlock: +exit_unlock: + mutex_unlock(&af9015_usb_mutex); + + return ret; +} + +static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) +{ + return af9015_rw_udev(d->udev, req); +} + +static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, + u8 len) +{ + struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, + val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) +{ + return af9015_write_regs(d, addr, &val, 1); +} + +static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) +{ + struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val}; + return af9015_ctrl_msg(d, &req); +} + +static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 val) +{ + struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; + + if (addr == af9015_af9013_config[0].demod_address || + addr == af9015_af9013_config[1].demod_address) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, + u8 *val) +{ + struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; + + if (addr == af9015_af9013_config[0].demod_address || + addr == af9015_af9013_config[1].demod_address) + req.addr_len = 3; + + return af9015_ctrl_msg(d, &req); +} + +static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0, i = 0; + u16 addr; + u8 mbox, addr_len; + struct req_t req; + +/* TODO: implement bus lock + +The bus lock is needed because there is two tuners both using same I2C-address. +Due to that the only way to select correct tuner is use demodulator I2C-gate. + +................................................ +. AF9015 includes integrated AF9013 demodulator. +. ____________ ____________ . ____________ +.| uC | | demod | . | tuner | +.|------------| |------------| . |------------| +.| AF9015 | | AF9013/5 | . | MXL5003 | +.| |--+----I2C-------|-----/ -----|-.-----I2C-------| | +.| | | | addr 0x38 | . | addr 0xc6 | +.|____________| | |____________| . |____________| +.................|.............................. + | ____________ ____________ + | | demod | | tuner | + | |------------| |------------| + | | AF9013 | | MXL5003 | + +----I2C-------|-----/ -----|-------I2C-------| | + | addr 0x3a | | addr 0xc6 | + |____________| |____________| +*/ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + while (i < num) { + if (msg[i].addr == af9015_af9013_config[0].demod_address || + msg[i].addr == af9015_af9013_config[1].demod_address) { + addr = msg[i].buf[0] << 8; + addr += msg[i].buf[1]; + mbox = msg[i].buf[2]; + addr_len = 3; + } else { + addr = msg[i].buf[0]; + addr_len = 1; + mbox = 0; + } + + if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].addr == + af9015_af9013_config[0].demod_address) + req.cmd = READ_MEMORY; + else + req.cmd = READ_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i+1].len; + req.data = &msg[i+1].buf[0]; + ret = af9015_ctrl_msg(d, &req); + i += 2; + } else { + if (msg[i].addr == + af9015_af9013_config[0].demod_address) + req.cmd = WRITE_MEMORY; + else + req.cmd = WRITE_I2C; + req.i2c_addr = msg[i].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[i].len-addr_len; + req.data = &msg[i].buf[addr_len]; + ret = af9015_ctrl_msg(d, &req); + i += 1; + } + if (ret) + goto error; + + } + ret = i; + +error: + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 af9015_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm af9015_i2c_algo = { + .master_xfer = af9015_i2c_xfer, + .functionality = af9015_i2c_func, +}; + +static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) +{ + int ret; + u8 val, mask = 0x01; + + ret = af9015_read_reg(d, addr, &val); + if (ret) + return ret; + + mask <<= bit; + if (op) { + /* set bit */ + val |= mask; + } else { + /* clear bit */ + mask ^= 0xff; + val &= mask; + } + + return af9015_write_reg(d, addr, val); +} + +static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 1); +} + +static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 0); +} + +static int af9015_init_endpoint(struct dvb_usb_device *d) +{ + int ret; + u16 frame_size; + u8 packet_size; + deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); + +#define TS_PACKET_SIZE 188 + +#define TS_USB20_PACKET_COUNT 348 +#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) + +#define TS_USB11_PACKET_COUNT 21 +#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) + +#define TS_USB20_MAX_PACKET_SIZE 512 +#define TS_USB11_MAX_PACKET_SIZE 64 + + if (d->udev->speed == USB_SPEED_FULL) { + frame_size = TS_USB11_FRAME_SIZE/4; + packet_size = TS_USB11_MAX_PACKET_SIZE/4; + } else { + frame_size = TS_USB20_FRAME_SIZE/4; + packet_size = TS_USB20_MAX_PACKET_SIZE/4; + } + + ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ + if (ret) + goto error; + } + ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ + if (ret) + goto error; + } + /* EP4 xfer length */ + ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); + if (ret) + goto error; + /* EP5 xfer length */ + ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ + if (ret) + goto error; + if (af9015_config.dual_mode) { + ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ + if (ret) + goto error; + } + + /* enable / disable mp2if2 */ + if (af9015_config.dual_mode) + ret = af9015_set_reg_bit(d, 0xd50b, 0); + else + ret = af9015_clear_reg_bit(d, 0xd50b, 0); +error: + if (ret) + err("endpoint init failed:%d", ret); + return ret; +} + +static int af9015_copy_firmware(struct dvb_usb_device *d) +{ + int ret; + u8 fw_params[4]; + u8 val, i; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), + fw_params }; + deb_info("%s:\n", __func__); + + fw_params[0] = af9015_config.firmware_size >> 8; + fw_params[1] = af9015_config.firmware_size & 0xff; + fw_params[2] = af9015_config.firmware_checksum >> 8; + fw_params[3] = af9015_config.firmware_checksum & 0xff; + + /* wait 2nd demodulator ready */ + msleep(100); + + ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val); + if (ret) + goto error; + else + deb_info("%s: firmware status:%02x\n", __func__, val); + + if (val == 0x0c) /* fw is running, no need for download */ + goto exit; + + /* set I2C master clock to fast (to speed up firmware copy) */ + ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ + if (ret) + goto error; + + msleep(50); + + /* copy firmware */ + ret = af9015_ctrl_msg(d, &req); + if (ret) + err("firmware copy cmd failed:%d", ret); + deb_info("%s: firmware copy done\n", __func__); + + /* set I2C master clock back to normal */ + ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + if (ret) + goto error; + + /* request boot firmware */ + ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address, + 0xe205, 1); + deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); + if (ret) + goto error; + + for (i = 0; i < 15; i++) { + msleep(100); + + /* check firmware status */ + ret = af9015_read_reg_i2c(d, + af9015_af9013_config[1].demod_address, 0x98be, &val); + deb_info("%s: firmware status cmd status:%d fw status:%02x\n", + __func__, ret, val); + if (ret) + goto error; + + if (val == 0x0c || val == 0x04) /* success or fail */ + break; + } + + if (val == 0x04) { + err("firmware did not run"); + ret = -1; + } else if (val != 0x0c) { + err("firmware boot timeout"); + ret = -1; + } + +error: +exit: + return ret; +} + +/* dump eeprom */ +static int af9015_eeprom_dump(struct dvb_usb_device *d) +{ + char buf[52], buf2[4]; + u8 reg, val; + + for (reg = 0; ; reg++) { + if (reg % 16 == 0) { + if (reg) + deb_info("%s\n", buf); + sprintf(buf, "%02x: ", reg); + } + if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0) + sprintf(buf2, "%02x ", val); + else + strcpy(buf2, "-- "); + strcat(buf, buf2); + if (reg == 0xff) + break; + } + deb_info("%s\n", buf); + return 0; +} + +int af9015_download_ir_table(struct dvb_usb_device *d) +{ + int i, packets = 0, ret; + u16 addr = 0x9a56; /* ir-table start address */ + struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL}; + u8 *data = NULL; + deb_info("%s:\n", __func__); + + data = af9015_config.ir_table; + packets = af9015_config.ir_table_size; + + /* no remote */ + if (!packets) + goto exit; + + /* load remote ir-table */ + for (i = 0; i < packets; i++) { + req.addr = addr + i; + req.data = &data[i]; + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("ir-table download failed at packet %d with " \ + "code %d", i, ret); + return ret; + } + } + +exit: + return 0; +} + +static int af9015_init(struct dvb_usb_device *d) +{ + int ret; + deb_info("%s:\n", __func__); + + ret = af9015_init_endpoint(d); + if (ret) + goto error; + + ret = af9015_download_ir_table(d); + if (ret) + goto error; + +error: + return ret; +} + +static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) + ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); + else + ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); + + return ret; +} + +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + int ret; + u8 idx; + + deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", + __func__, index, pid, onoff); + + ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); + if (ret) + goto error; + + ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); + if (ret) + goto error; + + idx = ((index & 0x1f) | (1 << 5)); + ret = af9015_write_reg(adap->dev, 0xd504, idx); + +error: + return ret; +} + +static int af9015_download_firmware(struct usb_device *udev, + const struct firmware *fw) +{ + int i, len, packets, remainder, ret; + struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; + u16 addr = 0x5100; /* firmware start address */ + u16 checksum = 0; + + deb_info("%s:\n", __func__); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + af9015_config.firmware_size = fw->size; + af9015_config.firmware_checksum = checksum; + + #define FW_PACKET_MAX_DATA 55 + + packets = fw->size / FW_PACKET_MAX_DATA; + remainder = fw->size % FW_PACKET_MAX_DATA; + len = FW_PACKET_MAX_DATA; + for (i = 0; i <= packets; i++) { + if (i == packets) /* set size of the last packet */ + len = remainder; + + req.data_len = len; + req.data = (fw->data + i * FW_PACKET_MAX_DATA); + req.addr = addr; + addr += FW_PACKET_MAX_DATA; + + ret = af9015_rw_udev(udev, &req); + if (ret) { + err("firmware download failed at packet %d with " \ + "code %d", i, ret); + goto error; + } + } + #undef FW_PACKET_MAX_DATA + + /* firmware loaded, request boot */ + req.cmd = BOOT; + ret = af9015_rw_udev(udev, &req); + if (ret) { + err("firmware boot failed:%d", ret); + goto error; + } + + /* firmware is running, reconnect device in the usb bus */ + req.cmd = RECONNECT_USB; + ret = af9015_rw_udev(udev, &req); + if (ret) + err("reconnect failed: %d", ret); + +error: + return ret; +} + +static int af9015_read_config(struct usb_device *udev) +{ + int ret; + u8 val, i, offset = 0; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + char manufacturer[10]; + + /* IR remote controller */ + req.addr = AF9015_EEPROM_IR_MODE; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + deb_info("%s: IR mode:%d\n", __func__, val); + for (i = 0; i < af9015_properties_count; i++) { + if (val == AF9015_IR_MODE_DISABLED || val == 0x04) { + af9015_properties[i].rc_key_map = NULL; + af9015_properties[i].rc_key_map_size = 0; + } else if (dvb_usb_af9015_remote) { + /* load remote defined as module param */ + switch (dvb_usb_af9015_remote) { + case AF9015_REMOTE_A_LINK_DTU_M: + af9015_properties[i].rc_key_map = + af9015_rc_keys_a_link; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_a_link); + af9015_config.ir_table = af9015_ir_table_a_link; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_a_link); + break; + case AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3: + af9015_properties[i].rc_key_map = + af9015_rc_keys_msi; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_msi); + af9015_config.ir_table = af9015_ir_table_msi; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_msi); + break; + case AF9015_REMOTE_MYGICTV_U718: + af9015_properties[i].rc_key_map = + af9015_rc_keys_mygictv; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_mygictv); + af9015_config.ir_table = + af9015_ir_table_mygictv; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_mygictv); + break; + } + } else { + switch (udev->descriptor.idVendor) { + case cpu_to_le16(USB_VID_LEADTEK): + af9015_properties[i].rc_key_map = + af9015_rc_keys_leadtek; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_leadtek); + af9015_config.ir_table = + af9015_ir_table_leadtek; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_leadtek); + break; + case cpu_to_le16(USB_VID_VISIONPLUS): + if (udev->descriptor.idProduct == + cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) { + af9015_properties[i].rc_key_map = + af9015_rc_keys_twinhan; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_twinhan); + af9015_config.ir_table = + af9015_ir_table_twinhan; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_twinhan); + } + break; + case cpu_to_le16(USB_VID_KWORLD_2): + /* TODO: use correct rc keys */ + af9015_properties[i].rc_key_map = + af9015_rc_keys_twinhan; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_twinhan); + af9015_config.ir_table = af9015_ir_table_kworld; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_kworld); + break; + /* Check USB manufacturer and product strings and try + to determine correct remote in case of chip vendor + reference IDs are used. */ + case cpu_to_le16(USB_VID_AFATECH): + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(udev, udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + if (!strcmp("Geniatech", manufacturer)) { + /* iManufacturer 1 Geniatech + iProduct 2 AF9015 */ + af9015_properties[i].rc_key_map = + af9015_rc_keys_mygictv; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_mygictv); + af9015_config.ir_table = + af9015_ir_table_mygictv; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_mygictv); + } else if (!strcmp("MSI", manufacturer)) { + /* iManufacturer 1 MSI + iProduct 2 MSI K-VOX */ + af9015_properties[i].rc_key_map = + af9015_rc_keys_msi; + af9015_properties[i].rc_key_map_size = + ARRAY_SIZE(af9015_rc_keys_msi); + af9015_config.ir_table = + af9015_ir_table_msi; + af9015_config.ir_table_size = + ARRAY_SIZE(af9015_ir_table_msi); + } + break; + } + } + } + + /* TS mode - one or two receivers */ + req.addr = AF9015_EEPROM_TS_MODE; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_config.dual_mode = val; + deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode); + /* disable dual mode by default because it is buggy */ + if (!dvb_usb_af9015_dual_mode) + af9015_config.dual_mode = 0; + + /* set buffer size according to USB port speed */ + for (i = 0; i < af9015_properties_count; i++) { + /* USB1.1 set smaller buffersize and disable 2nd adapter */ + if (udev->speed == USB_SPEED_FULL) { + af9015_properties[i].adapter->stream.u.bulk.buffersize = + TS_USB11_MAX_PACKET_SIZE; + /* disable 2nd adapter because we don't have + PID-filters */ + af9015_config.dual_mode = 0; + } else { + af9015_properties[i].adapter->stream.u.bulk.buffersize = + TS_USB20_MAX_PACKET_SIZE; + } + } + + if (af9015_config.dual_mode) { + /* read 2nd demodulator I2C address */ + req.addr = AF9015_EEPROM_DEMOD2_I2C; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_af9013_config[1].demod_address = val; + + /* enable 2nd adapter */ + for (i = 0; i < af9015_properties_count; i++) + af9015_properties[i].num_adapters = 2; + + } else { + /* disable 2nd adapter */ + for (i = 0; i < af9015_properties_count; i++) + af9015_properties[i].num_adapters = 1; + } + + for (i = 0; i < af9015_properties[0].num_adapters; i++) { + if (i == 1) + offset = AF9015_EEPROM_OFFSET; + /* xtal */ + req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + switch (val) { + case 0: + af9015_af9013_config[i].adc_clock = 28800; + break; + case 1: + af9015_af9013_config[i].adc_clock = 20480; + break; + case 2: + af9015_af9013_config[i].adc_clock = 28000; + break; + case 3: + af9015_af9013_config[i].adc_clock = 25000; + break; + }; + deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i, + val, af9015_af9013_config[i].adc_clock); + + /* tuner IF */ + req.addr = AF9015_EEPROM_IF1H + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_af9013_config[i].tuner_if = val << 8; + req.addr = AF9015_EEPROM_IF1L + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_af9013_config[i].tuner_if += val; + deb_info("%s: [%d] IF1:%d\n", __func__, i, + af9015_af9013_config[0].tuner_if); + + /* MT2060 IF1 */ + req.addr = AF9015_EEPROM_MT2060_IF1H + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_config.mt2060_if1[i] = val << 8; + req.addr = AF9015_EEPROM_MT2060_IF1L + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + af9015_config.mt2060_if1[i] += val; + deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i, + af9015_config.mt2060_if1[i]); + + /* tuner */ + req.addr = AF9015_EEPROM_TUNER_ID1 + offset; + ret = af9015_rw_udev(udev, &req); + if (ret) + goto error; + switch (val) { + case AF9013_TUNER_ENV77H11D5: + case AF9013_TUNER_MT2060: + case AF9013_TUNER_MC44S803: + case AF9013_TUNER_QT1010: + case AF9013_TUNER_UNKNOWN: + case AF9013_TUNER_MT2060_2: + case AF9013_TUNER_TDA18271: + case AF9013_TUNER_QT1010A: + af9015_af9013_config[i].rf_spec_inv = 1; + break; + case AF9013_TUNER_MXL5003D: + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + af9015_af9013_config[i].rf_spec_inv = 0; + break; + default: + warn("tuner id:%d not supported, please report!", val); + return -ENODEV; + }; + + af9015_af9013_config[i].tuner = val; + deb_info("%s: [%d] tuner id:%d\n", __func__, i, val); + } + +error: + if (ret) + err("eeprom read failed:%d", ret); + + return ret; +} + +static int af9015_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int ret; + u8 reply; + struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; + + ret = af9015_rw_udev(udev, &req); + if (ret) + return ret; + + deb_info("%s: reply:%02x\n", __func__, reply); + if (reply == 0x02) + *cold = 0; + else + *cold = 1; + + return ret; +} + +static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 buf[8]; + struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf}; + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + int i, ret; + + memset(buf, 0, sizeof(buf)); + + ret = af9015_ctrl_msg(d, &req); + if (ret) + return ret; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (!buf[1] && keymap[i].custom == buf[0] && + keymap[i].data == buf[2]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + break; + } + } + if (!buf[1]) + deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n", + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7]); + + return 0; +} + +/* init 2nd I2C adapter */ +int af9015_i2c_init(struct dvb_usb_device *d) +{ + int ret; + struct af9015_state *state = d->priv; + deb_info("%s:\n", __func__); + + strncpy(state->i2c_adap.name, d->desc->name, + sizeof(state->i2c_adap.name)); +#ifdef I2C_ADAP_CLASS_TV_DIGITAL + state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, +#else + state->i2c_adap.class = I2C_CLASS_TV_DIGITAL, +#endif + state->i2c_adap.algo = d->props.i2c_algo; + state->i2c_adap.algo_data = NULL; + state->i2c_adap.dev.parent = &d->udev->dev; + + i2c_set_adapdata(&state->i2c_adap, d); + + ret = i2c_add_adapter(&state->i2c_adap); + if (ret < 0) + err("could not add i2c adapter"); + + return ret; +} + +static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) +{ + int ret; + struct af9015_state *state = adap->dev->priv; + struct i2c_adapter *i2c_adap; + + if (adap->id == 0) { + /* select I2C adapter */ + i2c_adap = &adap->dev->i2c_adap; + + deb_info("%s: init I2C\n", __func__); + ret = af9015_i2c_init(adap->dev); + + /* dump eeprom (debug) */ + ret = af9015_eeprom_dump(adap->dev); + if (ret) + return ret; + } else { + /* select I2C adapter */ + i2c_adap = &state->i2c_adap; + + /* copy firmware to 2nd demodulator */ + if (af9015_config.dual_mode) { + ret = af9015_copy_firmware(adap->dev); + if (ret) { + err("firmware copy to 2nd frontend " \ + "failed, will disable it"); + af9015_config.dual_mode = 0; + return -ENODEV; + } + } else { + return -ENODEV; + } + } + + /* attach demodulator */ + adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], + i2c_adap); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static struct mt2060_config af9015_mt2060_config = { + .i2c_address = 0xc0, + .clock_out = 0, +}; + +static struct qt1010_config af9015_qt1010_config = { + .i2c_address = 0xc4, +}; + +static struct tda18271_config af9015_tda18271_config = { + .gate = TDA18271_GATE_DIGITAL, + .small_i2c = 1, +}; + +static struct mxl5005s_config af9015_mxl5003_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_DEFAULT, + .rssi_enable = MXL_RSSI_DISABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static struct mxl5005s_config af9015_mxl5005_config = { + .i2c_address = 0xc6, + .if_freq = IF_FREQ_4570000HZ, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_OFF, + .rssi_enable = MXL_RSSI_DISABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + +static int af9015_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct af9015_state *state = adap->dev->priv; + struct i2c_adapter *i2c_adap; + int ret; + deb_info("%s: \n", __func__); + + /* select I2C adapter */ + if (adap->id == 0) + i2c_adap = &adap->dev->i2c_adap; + else + i2c_adap = &state->i2c_adap; + + switch (af9015_af9013_config[adap->id].tuner) { + case AF9013_TUNER_MT2060: + case AF9013_TUNER_MT2060_2: + ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap, + &af9015_mt2060_config, + af9015_config.mt2060_if1[adap->id]) + == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_QT1010: + case AF9013_TUNER_QT1010A: + ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap, + &af9015_qt1010_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_TDA18271: + ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap, + &af9015_tda18271_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5003D: + ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, + &af9015_mxl5003_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap, + &af9015_mxl5005_config) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_ENV77H11D5: + ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap, + DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; + break; + case AF9013_TUNER_MC44S803: +#if 0 + ret = dvb_attach(mc44s80x_attach, adap->fe, i2c_adap) + == NULL ? -ENODEV : 0; +#else + ret = -ENODEV; + info("Freescale MC44S803 tuner found but no driver for that" \ + "tuner. Look at the Linuxtv.org for tuner driver" \ + "status."); +#endif + break; + case AF9013_TUNER_UNKNOWN: + default: + ret = -ENODEV; + err("Unknown tuner id:%d", + af9015_af9013_config[adap->id].tuner); + } + return ret; +} + +static struct usb_device_id af9015_usb_table[] = { +/* 0 */{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, + {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, + {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, +/* 5 */{USB_DEVICE(USB_VID_VISIONPLUS, + USB_PID_TINYTWIN)}, + {USB_DEVICE(USB_VID_VISIONPLUS, + USB_PID_AZUREWAVE_AD_TU700)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, +/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, + {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, + {0}, +}; +MODULE_DEVICE_TABLE(usb, af9015_usb_table); + +static struct dvb_usb_device_properties af9015_properties[] = { + { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9015_download_firmware, + .firmware = "dvb-usb-af9015.fw", + + .size_of_priv = sizeof(struct af9015_state), \ + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + }, + { + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + }, + } + }, + + .identify_state = af9015_identify_state, + + .rc_query = af9015_rc_query, + .rc_interval = 150, + + .i2c_algo = &af9015_i2c_algo, + + .num_device_descs = 9, + .devices = { + { + .name = "Afatech AF9015 DVB-T USB2.0 stick", + .cold_ids = {&af9015_usb_table[0], + &af9015_usb_table[1], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Leadtek WinFast DTV Dongle Gold", + .cold_ids = {&af9015_usb_table[2], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Pinnacle PCTV 71e", + .cold_ids = {&af9015_usb_table[3], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld PlusTV Dual DVB-T Stick " \ + "(DVB-T 399U)", + .cold_ids = {&af9015_usb_table[4], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "DigitalNow TinyTwin DVB-T Receiver", + .cold_ids = {&af9015_usb_table[5], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "TwinHan AzureWave AD-TU700(704J)", + .cold_ids = {&af9015_usb_table[6], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "TerraTec Cinergy T USB XE", + .cold_ids = {&af9015_usb_table[7], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "KWorld PlusTV Dual DVB-T PCI " \ + "(DVB-T PC160-2T)", + .cold_ids = {&af9015_usb_table[8], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "AVerMedia AVerTV DVB-T Volar X", + .cold_ids = {&af9015_usb_table[9], NULL}, + .warm_ids = {NULL}, + }, + } + }, { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .download_firmware = af9015_download_firmware, + .firmware = "dvb-usb-af9015.fw", + + .size_of_priv = sizeof(struct af9015_state), \ + + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x84, + }, + }, + { + .frontend_attach = + af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, + .stream = { + .type = USB_BULK, + .count = 6, + .endpoint = 0x85, + }, + } + }, + + .identify_state = af9015_identify_state, + + .rc_query = af9015_rc_query, + .rc_interval = 150, + + .i2c_algo = &af9015_i2c_algo, + + .num_device_descs = 3, + .devices = { + { + .name = "Xtensions XD-380", + .cold_ids = {&af9015_usb_table[10], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "MSI DIGIVOX Duo", + .cold_ids = {&af9015_usb_table[11], NULL}, + .warm_ids = {NULL}, + }, + { + .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", + .cold_ids = {&af9015_usb_table[12], NULL}, + .warm_ids = {NULL}, + }, + } + } +}; +#undef AF9015_DEFAULT_PROPERTIES + +static int af9015_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = 0; + struct dvb_usb_device *d = NULL; + struct usb_device *udev = interface_to_usbdev(intf); + u8 i; + + deb_info("%s: interface:%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); + + /* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ + if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { + ret = af9015_read_config(udev); + if (ret) + return ret; + + for (i = 0; i < af9015_properties_count; i++) { + ret = dvb_usb_device_init(intf, &af9015_properties[i], + THIS_MODULE, &d, adapter_nr); + if (!ret) + break; + if (ret != -ENODEV) + return ret; + } + if (ret) + return ret; + + if (d) + ret = af9015_init(d); + } + + return ret; +} + +void af9015_i2c_exit(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + deb_info("%s: \n", __func__); + + /* remove 2nd I2C adapter */ + if (d->state & DVB_USB_STATE_I2C) + i2c_del_adapter(&state->i2c_adap); +} + +static void af9015_usb_device_exit(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + deb_info("%s: \n", __func__); + + /* remove 2nd I2C adapter */ + if (d != NULL && d->desc != NULL) + af9015_i2c_exit(d); + + dvb_usb_device_exit(intf); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver af9015_usb_driver = { + .name = "dvb_usb_af9015", + .probe = af9015_usb_probe, + .disconnect = af9015_usb_device_exit, + .id_table = af9015_usb_table, +}; + +/* module stuff */ +static int __init af9015_usb_module_init(void) +{ + int ret; + ret = usb_register(&af9015_usb_driver); + if (ret) + err("module init failed:%d", ret); + + return ret; +} + +static void __exit af9015_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&af9015_usb_driver); +} + +module_init(af9015_usb_module_init); +module_exit(af9015_usb_module_exit); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h new file mode 100644 index 000000000000..882e8a4b3681 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/af9015.h @@ -0,0 +1,524 @@ +/* + * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver + * + * Copyright (C) 2007 Antti Palosaari + * + * Thanks to Afatech who kindly provided information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 _DVB_USB_AF9015_H_ +#define _DVB_USB_AF9015_H_ + +#define DVB_USB_LOG_PREFIX "af9015" +#include "dvb-usb.h" + +extern int dvb_usb_af9015_debug; +#define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) +#define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) +#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args) +#define deb_reg(args...) dprintk(dvb_usb_af9015_debug, 0x08, args) +#define deb_i2c(args...) dprintk(dvb_usb_af9015_debug, 0x10, args) +#define deb_fw(args...) dprintk(dvb_usb_af9015_debug, 0x20, args) + +#define AF9015_I2C_EEPROM 0xa0 +#define AF9015_I2C_DEMOD 0x38 +#define AF9015_USB_TIMEOUT 2000 + +/* EEPROM locations */ +#define AF9015_EEPROM_IR_MODE 0x18 +#define AF9015_EEPROM_IR_REMOTE_TYPE 0x34 +#define AF9015_EEPROM_TS_MODE 0x31 +#define AF9015_EEPROM_DEMOD2_I2C 0x32 + +#define AF9015_EEPROM_SAW_BW1 0x35 +#define AF9015_EEPROM_XTAL_TYPE1 0x36 +#define AF9015_EEPROM_SPEC_INV1 0x37 +#define AF9015_EEPROM_IF1L 0x38 +#define AF9015_EEPROM_IF1H 0x39 +#define AF9015_EEPROM_MT2060_IF1L 0x3a +#define AF9015_EEPROM_MT2060_IF1H 0x3b +#define AF9015_EEPROM_TUNER_ID1 0x3c + +#define AF9015_EEPROM_SAW_BW2 0x45 +#define AF9015_EEPROM_XTAL_TYPE2 0x46 +#define AF9015_EEPROM_SPEC_INV2 0x47 +#define AF9015_EEPROM_IF2L 0x48 +#define AF9015_EEPROM_IF2H 0x49 +#define AF9015_EEPROM_MT2060_IF2L 0x4a +#define AF9015_EEPROM_MT2060_IF2H 0x4b +#define AF9015_EEPROM_TUNER_ID2 0x4c + +#define AF9015_EEPROM_OFFSET (AF9015_EEPROM_SAW_BW2 - AF9015_EEPROM_SAW_BW1) + +#define AF9015_GPIO_ON (1 << 0) +#define AF9015_GPIO_EN (1 << 1) +#define AF9015_GPIO_O (1 << 2) +#define AF9015_GPIO_I (1 << 3) + +#define AF9015_GPIO_TUNER_ON (AF9015_GPIO_ON|AF9015_GPIO_EN) +#define AF9015_GPIO_TUNER_OFF (AF9015_GPIO_ON|AF9015_GPIO_EN|AF9015_GPIO_O) + +struct req_t { + u8 cmd; /* [0] */ + /* seq */ /* [1] */ + u8 i2c_addr; /* [2] */ + u16 addr; /* [3|4] */ + u8 mbox; /* [5] */ + u8 addr_len; /* [6] */ + u8 data_len; /* [7] */ + u8 *data; +}; + +enum af9015_cmd { + GET_CONFIG = 0x10, + DOWNLOAD_FIRMWARE = 0x11, + BOOT = 0x13, + READ_MEMORY = 0x20, + WRITE_MEMORY = 0x21, + READ_WRITE_I2C = 0x22, + COPY_FIRMWARE = 0x23, + RECONNECT_USB = 0x5a, + WRITE_VIRTUAL_MEMORY = 0x26, + GET_IR_CODE = 0x27, + READ_I2C, + WRITE_I2C, +}; + +enum af9015_ir_mode { + AF9015_IR_MODE_DISABLED = 0, + AF9015_IR_MODE_HID, + AF9015_IR_MODE_RLC, + AF9015_IR_MODE_RC6, +}; + +struct af9015_state { + struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */ +}; + +struct af9015_config { + u8 dual_mode:1; + u16 mt2060_if1[2]; + u16 firmware_size; + u16 firmware_checksum; + u8 *ir_table; + u16 ir_table_size; +}; + +enum af9015_remote { + AF9015_REMOTE_NONE = 0, + AF9015_REMOTE_A_LINK_DTU_M, + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + AF9015_REMOTE_MYGICTV_U718, +}; + +/* Leadtek WinFast DTV Dongle Gold */ +static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = { + { 0x00, 0x1e, KEY_1 }, + { 0x00, 0x1f, KEY_2 }, + { 0x00, 0x20, KEY_3 }, + { 0x00, 0x21, KEY_4 }, + { 0x00, 0x22, KEY_5 }, + { 0x00, 0x23, KEY_6 }, + { 0x00, 0x24, KEY_7 }, + { 0x00, 0x25, KEY_8 }, + { 0x00, 0x26, KEY_9 }, + { 0x00, 0x27, KEY_0 }, + { 0x00, 0x28, KEY_ENTER }, + { 0x00, 0x4f, KEY_VOLUMEUP }, + { 0x00, 0x50, KEY_VOLUMEDOWN }, + { 0x00, 0x51, KEY_CHANNELDOWN }, + { 0x00, 0x52, KEY_CHANNELUP }, +}; + +static u8 af9015_ir_table_leadtek[] = { + 0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, + 0x03, 0xfc, 0x56, 0xa9, 0x00, 0x00, 0x00, + 0x03, 0xfc, 0x4b, 0xb4, 0x00, 0x00, 0x00, + 0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, + 0x03, 0xfc, 0x4d, 0xb2, 0x00, 0x00, 0x00, + 0x03, 0xfc, 0x4e, 0xb1, 0x00, 0x00, 0x00, + 0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, + 0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, + 0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, + 0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, + 0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, + 0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, + 0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, + 0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, + 0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, + 0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, + 0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, + 0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, + 0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, + 0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, + 0x03, 0xfc, 0x43, 0xbc, 0x00, 0x00, 0x00, + 0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, + 0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, + 0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, + 0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, + 0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, + 0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, + 0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, + 0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, + 0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, + 0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, + 0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, + 0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, + 0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, + 0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, + 0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, + 0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, + 0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, + 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, + 0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, + 0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, + 0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, + 0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, + 0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, + 0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, + 0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, + 0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, + 0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, + 0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, + 0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, +}; + +/* TwinHan AzureWave AD-TU700(704J) */ +static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = { + { 0x05, 0x3f, KEY_POWER }, + { 0x00, 0x19, KEY_FAVORITES }, /* Favorite List */ + { 0x00, 0x04, KEY_TEXT }, /* Teletext */ + { 0x00, 0x0e, KEY_POWER }, + { 0x00, 0x0e, KEY_INFO }, /* Preview */ + { 0x00, 0x08, KEY_EPG }, /* Info/EPG */ + { 0x00, 0x0f, KEY_LIST }, /* Record List */ + { 0x00, 0x1e, KEY_1 }, + { 0x00, 0x1f, KEY_2 }, + { 0x00, 0x20, KEY_3 }, + { 0x00, 0x21, KEY_4 }, + { 0x00, 0x22, KEY_5 }, + { 0x00, 0x23, KEY_6 }, + { 0x00, 0x24, KEY_7 }, + { 0x00, 0x25, KEY_8 }, + { 0x00, 0x26, KEY_9 }, + { 0x00, 0x27, KEY_0 }, + { 0x00, 0x29, KEY_CANCEL }, /* Cancel */ + { 0x00, 0x4c, KEY_CLEAR }, /* Clear */ + { 0x00, 0x2a, KEY_BACK }, /* Back */ + { 0x00, 0x2b, KEY_TAB }, /* Tab */ + { 0x00, 0x52, KEY_UP }, /* up arrow */ + { 0x00, 0x51, KEY_DOWN }, /* down arrow */ + { 0x00, 0x4f, KEY_RIGHT }, /* right arrow */ + { 0x00, 0x50, KEY_LEFT }, /* left arrow */ + { 0x00, 0x28, KEY_ENTER }, /* Enter / ok */ + { 0x02, 0x52, KEY_VOLUMEUP }, + { 0x02, 0x51, KEY_VOLUMEDOWN }, + { 0x00, 0x4e, KEY_CHANNELDOWN }, + { 0x00, 0x4b, KEY_CHANNELUP }, + { 0x00, 0x4a, KEY_RECORD }, + { 0x01, 0x11, KEY_PLAY }, + { 0x00, 0x17, KEY_PAUSE }, + { 0x00, 0x0c, KEY_REWIND }, /* FR << */ + { 0x00, 0x11, KEY_FASTFORWARD }, /* FF >> */ + { 0x01, 0x15, KEY_PREVIOUS }, /* Replay */ + { 0x01, 0x0e, KEY_NEXT }, /* Skip */ + { 0x00, 0x13, KEY_CAMERA }, /* Capture */ + { 0x01, 0x0f, KEY_LANGUAGE }, /* SAP */ + { 0x01, 0x13, KEY_TV2 }, /* PIP */ + { 0x00, 0x1d, KEY_ZOOM }, /* Full Screen */ + { 0x01, 0x17, KEY_SUBTITLE }, /* Subtitle / CC */ + { 0x00, 0x10, KEY_MUTE }, + { 0x01, 0x19, KEY_AUDIO }, /* L/R */ /* TODO better event */ + { 0x01, 0x16, KEY_SLEEP }, /* Hibernate */ + { 0x01, 0x16, KEY_SWITCHVIDEOMODE }, + /* A/V */ /* TODO does not work */ + { 0x00, 0x06, KEY_AGAIN }, /* Recall */ + { 0x01, 0x16, KEY_KPPLUS }, /* Zoom+ */ /* TODO does not work */ + { 0x01, 0x16, KEY_KPMINUS }, /* Zoom- */ /* TODO does not work */ + { 0x02, 0x15, KEY_RED }, + { 0x02, 0x0a, KEY_GREEN }, + { 0x02, 0x1c, KEY_YELLOW }, + { 0x02, 0x05, KEY_BLUE }, +}; + +static u8 af9015_ir_table_twinhan[] = { + 0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00, + 0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00, + 0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00, + 0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00, + 0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00, + 0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00, + 0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00, + 0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00, + 0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00, + 0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00, + 0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00, + 0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00, + 0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00, + 0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00, + 0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00, + 0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00, + 0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00, + 0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00, + 0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00, + 0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00, + 0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00, + 0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00, + 0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00, + 0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00, + 0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00, + 0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00, + 0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00, + 0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00, + 0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00, + 0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00, + 0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00, + 0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00, + 0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00, + 0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00, + 0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00, + 0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00, + 0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00, + 0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00, + 0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00, + 0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00, + 0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00, + 0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00, + 0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00, + 0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00, + 0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00, + 0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00, + 0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00, + 0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00, + 0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00, + 0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00, +}; + +/* A-Link DTU(m) */ +static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = { + { 0x00, 0x1e, KEY_1 }, + { 0x00, 0x1f, KEY_2 }, + { 0x00, 0x20, KEY_3 }, + { 0x00, 0x21, KEY_4 }, + { 0x00, 0x22, KEY_5 }, + { 0x00, 0x23, KEY_6 }, + { 0x00, 0x24, KEY_7 }, + { 0x00, 0x25, KEY_8 }, + { 0x00, 0x26, KEY_9 }, + { 0x00, 0x27, KEY_0 }, + { 0x00, 0x2e, KEY_CHANNELUP }, + { 0x00, 0x2d, KEY_CHANNELDOWN }, + { 0x04, 0x28, KEY_ZOOM }, + { 0x00, 0x41, KEY_MUTE }, + { 0x00, 0x42, KEY_VOLUMEDOWN }, + { 0x00, 0x43, KEY_VOLUMEUP }, + { 0x00, 0x44, KEY_GOTO }, /* jump */ + { 0x05, 0x45, KEY_POWER }, +}; + +static u8 af9015_ir_table_a_link[] = { + 0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */ + 0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */ + 0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */ + 0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */ + 0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */ + 0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */ + 0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */ + 0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */ + 0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */ + 0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */ + 0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */ + 0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */ + 0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */ + 0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */ + 0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */ + 0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */ + 0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */ + 0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */ +}; + +/* MSI DIGIVOX mini II V3.0 */ +static struct dvb_usb_rc_key af9015_rc_keys_msi[] = { + { 0x00, 0x1e, KEY_1 }, + { 0x00, 0x1f, KEY_2 }, + { 0x00, 0x20, KEY_3 }, + { 0x00, 0x21, KEY_4 }, + { 0x00, 0x22, KEY_5 }, + { 0x00, 0x23, KEY_6 }, + { 0x00, 0x24, KEY_7 }, + { 0x00, 0x25, KEY_8 }, + { 0x00, 0x26, KEY_9 }, + { 0x00, 0x27, KEY_0 }, + { 0x03, 0x0f, KEY_CHANNELUP }, + { 0x03, 0x0e, KEY_CHANNELDOWN }, + { 0x00, 0x42, KEY_VOLUMEDOWN }, + { 0x00, 0x43, KEY_VOLUMEUP }, + { 0x05, 0x45, KEY_POWER }, + { 0x00, 0x52, KEY_UP }, /* up */ + { 0x00, 0x51, KEY_DOWN }, /* down */ + { 0x00, 0x28, KEY_ENTER }, +}; + +static u8 af9015_ir_table_msi[] = { + 0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */ + 0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */ + 0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */ + 0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */ + 0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */ + 0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */ + 0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */ + 0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */ + 0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */ + 0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */ + 0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */ + 0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */ + 0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */ + 0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */ + 0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */ + 0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */ + 0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */ + 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */ +}; + +/* MYGICTV U718 */ +static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = { + { 0x00, 0x3d, KEY_SWITCHVIDEOMODE }, + /* TV / AV */ + { 0x05, 0x45, KEY_POWER }, + { 0x00, 0x1e, KEY_1 }, + { 0x00, 0x1f, KEY_2 }, + { 0x00, 0x20, KEY_3 }, + { 0x00, 0x21, KEY_4 }, + { 0x00, 0x22, KEY_5 }, + { 0x00, 0x23, KEY_6 }, + { 0x00, 0x24, KEY_7 }, + { 0x00, 0x25, KEY_8 }, + { 0x00, 0x26, KEY_9 }, + { 0x00, 0x27, KEY_0 }, + { 0x00, 0x41, KEY_MUTE }, + { 0x00, 0x2a, KEY_ESC }, /* Esc */ + { 0x00, 0x2e, KEY_CHANNELUP }, + { 0x00, 0x2d, KEY_CHANNELDOWN }, + { 0x00, 0x42, KEY_VOLUMEDOWN }, + { 0x00, 0x43, KEY_VOLUMEUP }, + { 0x00, 0x52, KEY_UP }, /* up arrow */ + { 0x00, 0x51, KEY_DOWN }, /* down arrow */ + { 0x00, 0x4f, KEY_RIGHT }, /* right arrow */ + { 0x00, 0x50, KEY_LEFT }, /* left arrow */ + { 0x00, 0x28, KEY_ENTER }, /* ok */ + { 0x01, 0x15, KEY_RECORD }, + { 0x03, 0x13, KEY_PLAY }, + { 0x01, 0x13, KEY_PAUSE }, + { 0x01, 0x16, KEY_STOP }, + { 0x03, 0x07, KEY_REWIND }, /* FR << */ + { 0x03, 0x09, KEY_FASTFORWARD }, /* FF >> */ + { 0x00, 0x3b, KEY_TIME }, /* TimeShift */ + { 0x00, 0x3e, KEY_CAMERA }, /* Snapshot */ + { 0x03, 0x16, KEY_CYCLEWINDOWS }, /* yellow, min / max */ + { 0x00, 0x00, KEY_ZOOM }, /* 'select' (?) */ + { 0x03, 0x16, KEY_SHUFFLE }, /* Shuffle */ + { 0x03, 0x45, KEY_POWER }, +}; + +static u8 af9015_ir_table_mygictv[] = { + 0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */ + 0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */ + 0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */ + 0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */ + 0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */ + 0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */ + 0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */ + 0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */ + 0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */ + 0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */ + 0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */ + 0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */ + 0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */ + 0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */ + 0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */ + 0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */ + 0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */ + 0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */ + 0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */ + 0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */ + 0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */ + 0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */ + 0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */ + 0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */ + 0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */ + 0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */ + 0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */ + 0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */ + 0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */ + 0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */ + 0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */ + 0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */ + 0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */ + 0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */ + 0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */ +}; + +/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */ +static u8 af9015_ir_table_kworld[] = { + 0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00, + 0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00, + 0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00, + 0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00, + 0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00, + 0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00, + 0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00, + 0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00, + 0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00, + 0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00, + 0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00, + 0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00, + 0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00, + 0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00, + 0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00, + 0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00, + 0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00, + 0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00, + 0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00, + 0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00, + 0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00, + 0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00, + 0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00, + 0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00, + 0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00, + 0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00, + 0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00, + 0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00, + 0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00, + 0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00, + 0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00, + 0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00, + 0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00, + 0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00, + 0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00, + 0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00, + 0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00, + 0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00, + 0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00, + 0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00, + 0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00, + 0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00, + 0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00, + 0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00, +}; + +#endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 81369b79e75a..2558f2b51c2b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -34,12 +34,14 @@ #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 #define USB_VID_KWORLD 0xeb2a +#define USB_VID_KWORLD_2 0x1b80 #define USB_VID_KYE 0x0458 #define USB_VID_LEADTEK 0x0413 #define USB_VID_LITEON 0x04ca #define USB_VID_MEDION 0x1660 #define USB_VID_MIGLIA 0x18f3 #define USB_VID_MSI 0x0db0 +#define USB_VID_MSI_2 0x1462 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 #define USB_VID_TECHNOTREND 0x0b48 @@ -51,15 +53,18 @@ #define USB_VID_WIDEVIEW 0x14aa #define USB_VID_GIGABYTE 0x1044 #define USB_VID_YUAN 0x1164 - +#define USB_VID_XTENSIONS 0x1ae7 /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 #define USB_PID_ADSTECH_USB2_WARM 0xa334 #define USB_PID_AFATECH_AF9005 0x9020 +#define USB_PID_AFATECH_AF9015_9015 0x9015 +#define USB_PID_AFATECH_AF9015_9016 0x9016 #define USB_VID_ALINK_DTU 0xf170 #define USB_PID_ANSONIC_DVBT_USB 0x6000 #define USB_PID_ANYSEE 0x861f +#define USB_PID_AZUREWAVE_AD_TU700 0x3237 #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 @@ -89,9 +94,12 @@ #define USB_PID_UNIWILL_STK7700P 0x6003 #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 +#define USB_PID_KWORLD_399U 0xe399 +#define USB_PID_KWORLD_PC160_2T 0xc160 #define USB_PID_KWORLD_VSTREAM_COLD 0x17de #define USB_PID_KWORLD_VSTREAM_WARM 0x17df #define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055 +#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069 #define USB_PID_TWINHAN_VP7041_COLD 0x3201 #define USB_PID_TWINHAN_VP7041_WARM 0x3202 #define USB_PID_TWINHAN_VP7020_COLD 0x3203 @@ -100,6 +108,7 @@ #define USB_PID_TWINHAN_VP7045_WARM 0x3206 #define USB_PID_TWINHAN_VP7021_COLD 0x3207 #define USB_PID_TWINHAN_VP7021_WARM 0x3208 +#define USB_PID_TINYTWIN 0x3226 #define USB_PID_DNTV_TINYUSB2_COLD 0x3223 #define USB_PID_DNTV_TINYUSB2_WARM 0x3224 #define USB_PID_ULTIMA_TVBOX_COLD 0x8105 @@ -146,6 +155,8 @@ #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039 #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039 +#define USB_PID_AVERMEDIA_VOLAR_X 0xa815 +#define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 @@ -155,6 +166,7 @@ #define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 #define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229 +#define USB_PID_PINNACLE_PCTV71E 0x022b #define USB_PID_PINNACLE_PCTV72E 0x0236 #define USB_PID_PINNACLE_PCTV73E 0x0237 #define USB_PID_PCTV_200E 0x020e @@ -193,6 +205,7 @@ #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01 +#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029 #define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200 #define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201 #define USB_PID_GENPIX_8PSK_REV_2 0x0202 @@ -200,6 +213,7 @@ #define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204 #define USB_PID_SIGMATEK_DVB_110 0x6610 #define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513 +#define USB_PID_MSI_DIGIVOX_DUO 0x8801 #define USB_PID_OPERA1_COLD 0x2830 #define USB_PID_OPERA1_WARM 0x3829 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 @@ -209,5 +223,6 @@ #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc #define USB_PID_DW2102 0x2102 +#define USB_PID_XTENSIONS_XD_380 0x0381 #endif -- cgit v1.2.1 From 28f947a95386861c54de2bf7753dda011c8e15c3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 16 Sep 2008 14:22:43 -0300 Subject: V4L/DVB (8973): af9013: fix compile error coming from u64 div - fix compile error coming from u64 div Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/af9013.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 9f2129d544c5..50e1e3f300a0 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -941,7 +941,6 @@ static int af9013_update_ber_unc(struct dvb_frontend *fe) u32 error_bit_count = 0; u32 total_bit_count = 0; u32 abort_packet_count = 0; - u64 numerator, denominator; state->ber = 0; @@ -979,11 +978,8 @@ static int af9013_update_ber_unc(struct dvb_frontend *fe) total_bit_count = total_bit_count - abort_packet_count; total_bit_count = total_bit_count * 204 * 8; - if (total_bit_count) { - numerator = error_bit_count * 1000000000; - denominator = total_bit_count; - state->ber = numerator / denominator; - } + if (total_bit_count) + state->ber = error_bit_count * 1000000000 / total_bit_count; state->ucblocks += abort_packet_count; -- cgit v1.2.1 From 111f9ecf174655f3da2b266602f20f11e6a6a4c7 Mon Sep 17 00:00:00 2001 From: Mikko Ohtamaa Date: Fri, 19 Sep 2008 18:26:05 -0300 Subject: V4L/DVB (8974): af9015: Add USB ID for Telestar Starstick 2 - Add USB ID for Telestar Starstick 2 (10b9:8000) Signed-off-by: Mikko Ohtamaa Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 8 +++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index a284648094c2..505432b10b8d 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1196,6 +1196,7 @@ static struct usb_device_id af9015_usb_table[] = { /* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, + {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1346,7 +1347,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { .name = "Xtensions XD-380", @@ -1363,6 +1364,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = {&af9015_usb_table[12], NULL}, .warm_ids = {NULL}, }, + { + .name = "Telestar USB DVB-T", + .cold_ids = {&af9015_usb_table[13], NULL}, + .warm_ids = {NULL}, + }, } } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2558f2b51c2b..60c241e0236f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -46,6 +46,7 @@ #define USB_VID_PINNACLE 0x2304 #define USB_VID_TECHNOTREND 0x0b48 #define USB_VID_TERRATEC 0x0ccd +#define USB_VID_TELESTAR 0x10b9 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 @@ -224,5 +225,6 @@ #define USB_PID_YUAN_EC372S 0x1edc #define USB_PID_DW2102 0x2102 #define USB_PID_XTENSIONS_XD_380 0x0381 +#define USB_PID_TELESTAR 0x8000 #endif -- cgit v1.2.1 From a3765888a7edc4efe54293d8f7c6676cae61057e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 19 Sep 2008 18:34:06 -0300 Subject: V4L/DVB (8975): af9015: cleanup - cleanup Telestar Starstick 2 patch Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 4 ++-- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 505432b10b8d..f962d89db134 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1196,7 +1196,7 @@ static struct usb_device_id af9015_usb_table[] = { /* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, - {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR)}, + {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1365,7 +1365,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .warm_ids = {NULL}, }, { - .name = "Telestar USB DVB-T", + .name = "Telestar Starstick 2", .cold_ids = {&af9015_usb_table[13], NULL}, .warm_ids = {NULL}, }, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 60c241e0236f..66dc000d4e49 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -225,6 +225,6 @@ #define USB_PID_YUAN_EC372S 0x1edc #define USB_PID_DW2102 0x2102 #define USB_PID_XTENSIONS_XD_380 0x0381 -#define USB_PID_TELESTAR 0x8000 +#define USB_PID_TELESTAR_STARSTICK_2 0x8000 #endif -- cgit v1.2.1 From 05c1cab55c282199b85138dc1900b5d9bd6fb32a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 22 Sep 2008 12:32:37 -0300 Subject: V4L/DVB (8976): af9015: Add USB ID for AVerMedia A309 - AVerMedia A309 Mini Card (07ca:a309) Thanks-to: Dirk Vornheder Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 8 +++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index f962d89db134..3f6217bd0638 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1197,6 +1197,7 @@ static struct usb_device_id af9015_usb_table[] = { {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1347,7 +1348,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 4, + .num_device_descs = 5, .devices = { { .name = "Xtensions XD-380", @@ -1369,6 +1370,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = {&af9015_usb_table[13], NULL}, .warm_ids = {NULL}, }, + { + .name = "AVerMedia A309", + .cold_ids = {&af9015_usb_table[14], NULL}, + .warm_ids = {NULL}, + }, } } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 66dc000d4e49..7ae262e08f8f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -158,6 +158,7 @@ #define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039 #define USB_PID_AVERMEDIA_VOLAR_X 0xa815 #define USB_PID_AVERMEDIA_VOLAR_X_2 0x8150 +#define USB_PID_AVERMEDIA_A309 0xa309 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 -- cgit v1.2.1 From 6b73eeafbc856c0cef7166242f0e55403407f355 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 4 Sep 2008 01:12:25 -0300 Subject: V4L/DVB (8985): S2API: Added dvb frontend changes to support a newer tuning API This is an experimental patch to add a new tuning mechanism for dvb frontends. Rather than passing fixed structures across the user/kernel boundary, which need to be revised for each new modulation type (or feature the kernel developers want to add), this implements a simpler message based approach, allowing fe commands to be broken down into a series of small fixed size transactions, presented in an array. The goal is to avoid changing the user/kernel ABI in the future, by simply creating new frontend commands (and sequencies of commands) that help us add support for brand new demodulator, delivery system or statistics related commmands. known issues: checkpatch voilations feedback from various developers yet to be implemented, relating to namespace conventions, variable length array passing conventions, and generally some optimization. This patch should support all existing tuning mechanisms through the new API, as well as adding 8PSK, DVB-S2 NBC-QPSK and ISDB-T API support. For testing and exercise purposes, see the latest tune.c tool available from http://www.steventoth.net/linux/s2 Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 571 +++++++++++++++++++++++++++++- drivers/media/dvb/dvb-core/dvb_frontend.h | 44 +++ 2 files changed, 609 insertions(+), 6 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 3526e3ee9487..e68974b2fee9 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -755,6 +755,535 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe, return 0; } +struct tv_cmds_h tv_cmds[] = { + [TV_SEQ_UNDEFINED] = { + .name = "TV_SEQ_UNDEFINED", + .cmd = TV_SEQ_UNDEFINED, + .set = 1, + }, + [TV_SEQ_START] = { + .name = "TV_SEQ_START", + .cmd = TV_SEQ_START, + .set = 1, + }, + [TV_SEQ_CONTINUE] = { + .name = "TV_SEQ_CONTINUE", + .cmd = TV_SEQ_CONTINUE, + .set = 1, + }, + [TV_SEQ_COMPLETE] = { + .name = "TV_SEQ_COMPLETE", + .cmd = TV_SEQ_COMPLETE, + .set = 1, + }, + [TV_SEQ_TERMINATE] = { + .name = "TV_SEQ_TERMINATE", + .cmd = TV_SEQ_TERMINATE, + .set = 1, + }, + + /* Set */ + [TV_SET_FREQUENCY] = { + .name = "TV_SET_FREQUENCY", + .cmd = TV_SET_FREQUENCY, + .set = 1, + }, + [TV_SET_BANDWIDTH] = { + .name = "TV_SET_BANDWIDTH", + .cmd = TV_SET_BANDWIDTH, + .set = 1, + }, + [TV_SET_MODULATION] = { + .name = "TV_SET_MODULATION", + .cmd = TV_SET_MODULATION, + .set = 1, + }, + [TV_SET_INVERSION] = { + .name = "TV_SET_INVERSION", + .cmd = TV_SET_INVERSION, + .set = 1, + }, + [TV_SET_DISEQC_MASTER] = { + .name = "TV_SET_DISEQC_MASTER", + .cmd = TV_SET_DISEQC_MASTER, + .set = 1, + .buffer = 1, + }, + [TV_SET_SYMBOLRATE] = { + .name = "TV_SET_SYMBOLRATE", + .cmd = TV_SET_SYMBOLRATE, + .set = 1, + }, + [TV_SET_INNERFEC] = { + .name = "TV_SET_INNERFEC", + .cmd = TV_SET_INNERFEC, + .set = 1, + }, + [TV_SET_VOLTAGE] = { + .name = "TV_SET_VOLTAGE", + .cmd = TV_SET_VOLTAGE, + .set = 1, + }, + [TV_SET_TONE] = { + .name = "TV_SET_TONE", + .cmd = TV_SET_TONE, + .set = 1, + }, + [TV_SET_PILOT] = { + .name = "TV_SET_PILOT", + .cmd = TV_SET_PILOT, + .set = 1, + }, + [TV_SET_ROLLOFF] = { + .name = "TV_SET_ROLLOFF", + .cmd = TV_SET_ROLLOFF, + .set = 1, + }, + [TV_SET_DELIVERY_SYSTEM] = { + .name = "TV_SET_DELIVERY_SYSTEM", + .cmd = TV_SET_DELIVERY_SYSTEM, + .set = 1, + }, + [TV_SET_ISDB_SEGMENT_NUM] = { + .name = "TV_SET_ISDB_SEGMENT_NUM", + .cmd = TV_SET_ISDB_SEGMENT_NUM, + .set = 1, + }, + [TV_SET_ISDB_SEGMENT_WIDTH] = { + .name = "TV_SET_ISDB_SEGMENT_WIDTH", + .cmd = TV_SET_ISDB_SEGMENT_WIDTH, + .set = 1, + }, + + /* Get */ + [TV_GET_FREQUENCY] = { + .name = "TV_GET_FREQUENCY", + .cmd = TV_GET_FREQUENCY, + .set = 0, + }, + [TV_GET_BANDWIDTH] = { + .name = "TV_GET_BANDWIDTH", + .cmd = TV_GET_BANDWIDTH, + .set = 0, + }, + [TV_GET_MODULATION] = { + .name = "TV_GET_MODULATION", + .cmd = TV_GET_MODULATION, + .set = 0, + }, + [TV_GET_INVERSION] = { + .name = "TV_GET_INVERSION", + .cmd = TV_GET_INVERSION, + .set = 0, + }, + [TV_GET_DISEQC_SLAVE_REPLY] = { + .name = "TV_GET_DISEQC_SLAVE_REPLY", + .cmd = TV_GET_DISEQC_SLAVE_REPLY, + .set = 0, + .buffer = 1, + }, + [TV_GET_SYMBOLRATE] = { + .name = "TV_GET_SYMBOLRATE", + .cmd = TV_GET_SYMBOLRATE, + .set = 0, + }, + [TV_GET_INNERFEC] = { + .name = "TV_GET_INNERFEC", + .cmd = TV_GET_INNERFEC, + .set = 0, + }, + [TV_GET_VOLTAGE] = { + .name = "TV_GET_VOLTAGE", + .cmd = TV_GET_VOLTAGE, + .set = 0, + }, + [TV_GET_TONE] = { + .name = "TV_GET_TONE", + .cmd = TV_GET_TONE, + .set = 0, + }, + [TV_GET_PILOT] = { + .name = "TV_GET_PILOT", + .cmd = TV_GET_PILOT, + .set = 0, + }, + [TV_GET_ROLLOFF] = { + .name = "TV_GET_ROLLOFF", + .cmd = TV_GET_ROLLOFF, + .set = 0, + }, + [TV_GET_DELIVERY_SYSTEM] = { + .name = "TV_GET_DELIVERY_SYSTEM", + .cmd = TV_GET_DELIVERY_SYSTEM, + .set = 0, + }, + [TV_GET_ISDB_SEGMENT_NUM] = { + .name = "TV_GET_ISDB_SEGMENT_NUM", + .cmd = TV_GET_ISDB_SEGMENT_NUM, + .set = 0, + }, + [TV_GET_ISDB_SEGMENT_WIDTH] = { + .name = "TV_GET_ISDB_SEGMENT_WIDTH", + .cmd = TV_GET_ISDB_SEGMENT_WIDTH, + .set = 0, + }, + [TV_GET_ISDB_LAYERA_FEC] = { + .name = "TV_GET_ISDB_LAYERA_FEC", + .cmd = TV_GET_ISDB_LAYERA_FEC, + .set = 0, + }, + [TV_GET_ISDB_LAYERA_MODULATION] = { + .name = "TV_GET_ISDB_LAYERA_MODULATION", + .cmd = TV_GET_ISDB_LAYERA_MODULATION, + .set = 0, + }, + [TV_GET_ISDB_LAYERA_SEGMENT_WIDTH] = { + .name = "TV_GET_ISDB_LAYERA_SEGMENT_WIDTH", + .cmd = TV_GET_ISDB_LAYERA_SEGMENT_WIDTH, + .set = 0, + }, + [TV_GET_ISDB_LAYERB_FEC] = { + .name = "TV_GET_ISDB_LAYERB_FEC", + .cmd = TV_GET_ISDB_LAYERB_FEC, + .set = 0, + }, + [TV_GET_ISDB_LAYERB_MODULATION] = { + .name = "TV_GET_ISDB_LAYERB_MODULATION", + .cmd = TV_GET_ISDB_LAYERB_MODULATION, + .set = 0, + }, + [TV_GET_ISDB_LAYERB_SEGMENT_WIDTH] = { + .name = "TV_GET_ISDB_LAYERB_SEGMENT_WIDTH", + .cmd = TV_GET_ISDB_LAYERB_SEGMENT_WIDTH, + .set = 0, + }, + [TV_GET_ISDB_LAYERC_FEC] = { + .name = "TV_GET_ISDB_LAYERC_FEC", + .cmd = TV_GET_ISDB_LAYERC_FEC, + .set = 0, + }, + [TV_GET_ISDB_LAYERC_MODULATION] = { + .name = "TV_GET_ISDB_LAYERC_MODULATION", + .cmd = TV_GET_ISDB_LAYERC_MODULATION, + .set = 0, + }, + [TV_GET_ISDB_LAYERC_SEGMENT_WIDTH] = { + .name = "TV_GET_ISDB_LAYERC_SEGMENT_WIDTH", + .cmd = TV_GET_ISDB_LAYERC_SEGMENT_WIDTH, + .set = 0, + }, +}; + +void tv_property_dump(tv_property_t *tvp) +{ + int i; + + printk("%s() tvp.cmd = 0x%08x (%s)\n" + ,__FUNCTION__ + ,tvp->cmd + ,tv_cmds[ tvp->cmd ].name); + + if(tv_cmds[ tvp->cmd ].buffer) { + + printk("%s() tvp.u.buffer.len = 0x%02x\n" + ,__FUNCTION__ + ,tvp->u.buffer.len); + + for(i = 0; i < tvp->u.buffer.len; i++) + printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n" + ,__FUNCTION__ + ,i + ,tvp->u.buffer.data[i]); + + } else + printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data); +} + +int is_legacy_delivery_system(fe_delivery_system_t s) +{ + if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || + (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS)) + return 1; + + return 0; +} + +int tv_property_cache_submit(struct dvb_frontend *fe) +{ + + /* We have to do one of two things: + * To support legacy devices using the new API we take values from + * the tv_cache and generate a legacy truning structure. + * + * Or, + * + * To support advanced tuning devices with the new API we + * notify the new advance driver type that a tuning operation is required + * and let it pull values from the cache as is, we don't need to + * pass structures. + * + * We'll use the modulation type to assess how this is handled. as the API + * progresses we'll probably want to have a flag in dvb_frontend_ops + * to allow the frontend driver to dictate how it likes to be tuned. + * + * Because of how this is attached to the ioctl handler for legacy support, + * it's important to return an appropriate result code with atleast the following + * three meanings: + * < 0 = processing error + * 0 = lecagy ioctl handler to submit a traditional set_frontend() call. + * 1 = lecagy ioctl handler should NOT submit a traditional set_frontend() call. + */ + + int r; + + struct tv_frontend_properties *c = &fe->tv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_frontend_parameters p; + + printk("%s()\n", __FUNCTION__); + + /* For legacy delivery systems we don't need the delivery_system to be specified */ + if(is_legacy_delivery_system(c->delivery_system)) { + switch(c->modulation) { + case QPSK: + printk("%s() Preparing QPSK req\n", __FUNCTION__); + p.frequency = c->frequency; + p.inversion = c->inversion; + p.u.qpsk.symbol_rate = c->symbol_rate; + p.u.qpsk.fec_inner = c->fec_inner; + memcpy(&fepriv->parameters, &p, + sizeof (struct dvb_frontend_parameters)); + + /* Call the traditional tuning mechanisms. */ + + r = 0; + break; + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + case QAM_256: + case QAM_AUTO: + printk("%s() Preparing QAM req\n", __FUNCTION__); + p.frequency = c->frequency; + p.inversion = c->inversion; + p.u.qam.symbol_rate = c->symbol_rate; + p.u.vsb.modulation = c->modulation; + printk("%s() frequency = %d\n", __FUNCTION__, p.frequency); + printk("%s() QAM = %d\n", __FUNCTION__, p.u.vsb.modulation); + memcpy(&fepriv->parameters, &p, + sizeof (struct dvb_frontend_parameters)); + + /* At this point we're fully formed for backwards + * compatability and we need to return this + * via the ioctl handler as SET_FRONTEND (arg). + * We've already patched the new values into the + * frontends tuning structures so the ioctl code just + * continues as if a legacy tune structure was passed + * from userspace. + */ + + r = 0; + break; + case VSB_8: + case VSB_16: + printk("%s() Preparing VSB req\n", __FUNCTION__); + p.frequency = c->frequency; + p.u.vsb.modulation = c->modulation; + memcpy(&fepriv->parameters, &p, + sizeof (struct dvb_frontend_parameters)); + + /* Call the traditional tuning mechanisms. */ + + r = 0; + break; + /* TODO: Add any missing modulation types */ + default: + r = -1; + } + } else { + /* For advanced delivery systems / modulation types ... + * we seed the lecacy dvb_frontend_parameters structure + * so that the sanity checking code later in the IOCTL processing + * can validate our basic frequency ranges, symbolrates, modulation + * etc. + */ + r = -1; + + switch(c->modulation) { + case _8PSK: + case _16APSK: + case NBC_QPSK: + /* Just post a notification to the demod driver and let it pull + * the specific values it wants from its tv_property_cache. + * It can decide how best to use those parameters. + * IOCTL will call set_frontend (by default) due to zigzag + * support etc. + */ + if (fe->ops.set_params) + r = fe->ops.set_params(fe); + + p.frequency = c->frequency; + p.inversion = c->inversion; + p.u.qpsk.symbol_rate = c->symbol_rate; + p.u.qpsk.fec_inner = c->fec_inner; + memcpy(&fepriv->parameters, &p, + sizeof (struct dvb_frontend_parameters)); + + r = 0; + break; + default: + r = -1; + } + + if(c->delivery_system == SYS_ISDBT) { + /* Fake out a generic DVB-T request so we pass validation in the ioctl */ + p.frequency = c->frequency; + p.inversion = INVERSION_AUTO; + p.u.ofdm.constellation = QAM_AUTO; + p.u.ofdm.code_rate_HP = FEC_AUTO; + p.u.ofdm.code_rate_LP = FEC_AUTO; + p.u.ofdm.bandwidth = BANDWIDTH_AUTO; + p.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + p.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + p.u.ofdm.hierarchy_information = HIERARCHY_AUTO; + memcpy(&fepriv->parameters, &p, + sizeof (struct dvb_frontend_parameters)); + + r = 0; + } + } + return r; +} + +int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp) +{ + int r = 0; + printk("%s()\n", __FUNCTION__); + tv_property_dump(tvp); + + switch(tvp->cmd) { + case TV_SEQ_START: + case TV_SEQ_TERMINATE: + /* Reset a cache of data specific to the frontend here. This does + * not effect hardware. + */ + printk("%s() Flushing property cache\n", __FUNCTION__); + memset(&fe->tv_property_cache, 0, sizeof(struct tv_frontend_properties)); + fe->tv_property_cache.state = TV_SEQ_START; + fe->tv_property_cache.delivery_system = SYS_UNDEFINED; + break; + case TV_SEQ_COMPLETE: + /* interpret the cache of data, build either a traditional frontend + * tunerequest and submit it to a subset of the ioctl handler, + * or, call a new undefined method on the frontend to deal with + * all new tune requests. + */ + fe->tv_property_cache.state = TV_SEQ_COMPLETE; + printk("%s() Finalised property cache\n", __FUNCTION__); + r = tv_property_cache_submit(fe); + break; + case TV_SET_FREQUENCY: + fe->tv_property_cache.frequency = tvp->u.data; + break; + case TV_GET_FREQUENCY: + tvp->u.data = fe->tv_property_cache.frequency; + break; + case TV_SET_MODULATION: + fe->tv_property_cache.modulation = tvp->u.data; + break; + case TV_GET_MODULATION: + tvp->u.data = fe->tv_property_cache.modulation; + break; + case TV_SET_BANDWIDTH: + fe->tv_property_cache.bandwidth = tvp->u.data; + break; + case TV_GET_BANDWIDTH: + tvp->u.data = fe->tv_property_cache.bandwidth; + break; + case TV_SET_INVERSION: + fe->tv_property_cache.inversion = tvp->u.data; + break; + case TV_GET_INVERSION: + tvp->u.data = fe->tv_property_cache.inversion; + break; + case TV_SET_SYMBOLRATE: + fe->tv_property_cache.symbol_rate = tvp->u.data; + break; + case TV_GET_SYMBOLRATE: + tvp->u.data = fe->tv_property_cache.symbol_rate; + break; + case TV_SET_INNERFEC: + fe->tv_property_cache.fec_inner = tvp->u.data; + break; + case TV_GET_INNERFEC: + tvp->u.data = fe->tv_property_cache.fec_inner; + break; + case TV_SET_PILOT: + fe->tv_property_cache.pilot = tvp->u.data; + break; + case TV_GET_PILOT: + tvp->u.data = fe->tv_property_cache.pilot; + break; + case TV_SET_ROLLOFF: + fe->tv_property_cache.rolloff = tvp->u.data; + break; + case TV_GET_ROLLOFF: + tvp->u.data = fe->tv_property_cache.rolloff; + break; + case TV_SET_DELIVERY_SYSTEM: + fe->tv_property_cache.delivery_system = tvp->u.data; + break; + case TV_GET_DELIVERY_SYSTEM: + tvp->u.data = fe->tv_property_cache.delivery_system; + break; + + /* ISDB-T Support here */ + case TV_SET_ISDB_SEGMENT_NUM: + fe->tv_property_cache.isdb_segment_num = tvp->u.data; + break; + case TV_GET_ISDB_SEGMENT_NUM: + tvp->u.data = fe->tv_property_cache.isdb_segment_num; + break; + case TV_SET_ISDB_SEGMENT_WIDTH: + fe->tv_property_cache.isdb_segment_width = tvp->u.data; + break; + case TV_GET_ISDB_SEGMENT_WIDTH: + tvp->u.data = fe->tv_property_cache.isdb_segment_width; + break; + case TV_GET_ISDB_LAYERA_FEC: + tvp->u.data = fe->tv_property_cache.isdb_layera_fec; + break; + case TV_GET_ISDB_LAYERA_MODULATION: + tvp->u.data = fe->tv_property_cache.isdb_layera_modulation; + break; + case TV_GET_ISDB_LAYERA_SEGMENT_WIDTH: + tvp->u.data = fe->tv_property_cache.isdb_layera_segment_width; + break; + case TV_GET_ISDB_LAYERB_FEC: + tvp->u.data = fe->tv_property_cache.isdb_layerb_fec; + break; + case TV_GET_ISDB_LAYERB_MODULATION: + tvp->u.data = fe->tv_property_cache.isdb_layerb_modulation; + break; + case TV_GET_ISDB_LAYERB_SEGMENT_WIDTH: + tvp->u.data = fe->tv_property_cache.isdb_layerb_segment_width; + break; + case TV_GET_ISDB_LAYERC_FEC: + tvp->u.data = fe->tv_property_cache.isdb_layerc_fec; + break; + case TV_GET_ISDB_LAYERC_MODULATION: + tvp->u.data = fe->tv_property_cache.isdb_layerc_modulation; + break; + case TV_GET_ISDB_LAYERC_SEGMENT_WIDTH: + tvp->u.data = fe->tv_property_cache.isdb_layerc_segment_width; + break; + + } + + return 0; +} + static int dvb_frontend_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { @@ -762,6 +1291,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; int err = -EOPNOTSUPP; + tv_property_t* tvp; dprintk ("%s\n", __func__); @@ -776,6 +1306,27 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, if (down_interruptible (&fepriv->sem)) return -ERESTARTSYS; + if(cmd == FE_SET_PROPERTY) { + printk("%s() FE_SET_PROPERTY\n", __FUNCTION__); + + /* TODO: basic property validation here */ + + /* TODO: ioctl userdata out of range check here */ + tvp = parg; + while(tvp->cmd != TV_SEQ_UNDEFINED) { + tv_property_process(fe, tvp); + if( (tvp->cmd == TV_SEQ_TERMINATE) || (tvp->cmd == TV_SEQ_COMPLETE) ) + break; + tvp++; + } + + if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) { + printk("%s() Property cache is full, tuning\n", __FUNCTION__); + cmd = FE_SET_FRONTEND; + } + err = 0; + } + switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* info = parg; @@ -942,13 +1493,20 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; - if (dvb_frontend_check_parameters(fe, parg) < 0) { - err = -EINVAL; - break; - } + if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) { + if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) { + err = -EINVAL; + break; + } + } else { + if (dvb_frontend_check_parameters(fe, parg) < 0) { + err = -EINVAL; + break; + } - memcpy (&fepriv->parameters, parg, - sizeof (struct dvb_frontend_parameters)); + memcpy (&fepriv->parameters, parg, + sizeof (struct dvb_frontend_parameters)); + } memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); memcpy(&fetunesettings.parameters, parg, @@ -1031,6 +1589,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, return err; } + static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) { struct dvb_device *dvbdev = file->private_data; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index aa4133f0bd19..61d53ee70f2a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -169,6 +169,10 @@ struct dvb_frontend_ops { struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; + + int (*set_property)(struct dvb_frontend* fe, tv_property_t* tvp); + int (*get_property)(struct dvb_frontend* fe, tv_property_t* tvp); + int (*set_params)(struct dvb_frontend* fe); }; #define MAX_EVENT 8 @@ -182,6 +186,45 @@ struct dvb_fe_events { struct mutex mtx; }; +struct tv_frontend_properties { + + /* Cache State */ + u32 state; + + u32 frequency; + fe_modulation_t modulation; + + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t sectone; + fe_spectral_inversion_t inversion; + fe_code_rate_t fec_inner; + fe_transmit_mode_t transmission_mode; + fe_bandwidth_t bandwidth; + fe_guard_interval_t guard_interval; + fe_hierarchy_t hierarchy; + u32 symbol_rate; + fe_code_rate_t code_rate_HP; + fe_code_rate_t code_rate_LP; + + fe_pilot_t pilot; + fe_rolloff_t rolloff; + + fe_delivery_system_t delivery_system; + + /* ISDB-T specifics */ + u32 isdb_segment_num; + u32 isdb_segment_width; + fe_code_rate_t isdb_layera_fec; + fe_modulation_t isdb_layera_modulation; + u32 isdb_layera_segment_width; + fe_code_rate_t isdb_layerb_fec; + fe_modulation_t isdb_layerb_modulation; + u32 isdb_layerb_segment_width; + fe_code_rate_t isdb_layerc_fec; + fe_modulation_t isdb_layerc_modulation; + u32 isdb_layerc_segment_width; +}; + struct dvb_frontend { struct dvb_frontend_ops ops; struct dvb_adapter *dvb; @@ -190,6 +233,7 @@ struct dvb_frontend { void *frontend_priv; void *sec_priv; void *analog_demod_priv; + struct tv_frontend_properties tv_property_cache; }; extern int dvb_register_frontend(struct dvb_adapter *dvb, -- cgit v1.2.1 From 0d46748c3f874defbbbf98bcf40c7b18964abbc0 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 4 Sep 2008 01:14:43 -0300 Subject: V4L/DVB (8986): cx24116: Adding DVB-S2 demodulator support Adds support for the COnexant cx24116 DVB-S2 demodulator. TODO: checkpatch cleanup. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/cx24116.c | 950 ++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/cx24116.h | 50 ++ 4 files changed, 1008 insertions(+) create mode 100644 drivers/media/dvb/frontends/cx24116.c create mode 100644 drivers/media/dvb/frontends/cx24116.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 097d9f00144f..d2f31da26cbc 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -92,6 +92,13 @@ config DVB_TUA6100 help A DVB-S PLL chip. +config DVB_CX24116 + tristate "Conexant CX24116 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/S2 tuner module. Say Y when you want to support this frontend. + comment "DVB-T (terrestrial) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 1b5478886240..5deb8a542abd 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_DVB_S5H1411) += s5h1411.o obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o obj-$(CONFIG_DVB_AF9013) += af9013.o +obj-$(CONFIG_DVB_CX24116) += cx24116.o diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c new file mode 100644 index 000000000000..1402086a5c44 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24116.c @@ -0,0 +1,950 @@ +/* + Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver + + Copyright (C) 2006-2008 Steven Toth + + 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. +*/ + +/* + * Updates by Darron Broad 2007. + * + * March + * Fixed some bugs. + * Added diseqc support. + * Added corrected signal strength support. + * + * August + * Sync with legacy version. + * Some clean ups. + */ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "cx24116.h" + +/* + * Fetch firmware in the following manner. + * + * #!/bin/sh + * wget ftp://167.206.143.11/outgoing/Oxford/88x_2_117_24275_1_INF.zip + * unzip 88x_2_117_24275_1_INF.zip + * dd if=Driver88/hcw88bda.sys of=dvb-fe-cx24116.fw skip=81768 bs=1 count=32522 + */ +#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" +#define CX24116_SEARCH_RANGE_KHZ 5000 + +/* registers (TO BE COMPLETED) */ +#define CX24116_REG_SIGNAL (0xd5) + +/* arg buffer size */ +#define CX24116_ARGLEN (0x1e) + +/* arg offset for DiSEqC */ +#define CX24116_DISEQC_BURST (1) +#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ +#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */ +#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */ +#define CX24116_DISEQC_MSGLEN (5) +#define CX24116_DISEQC_MSGOFS (6) + +/* DiSEqC burst */ +#define CX24116_DISEQC_MINI_A (0) +#define CX24116_DISEQC_MINI_B (1) + +static int debug = 0; +#define dprintk(args...) \ + do { \ + if (debug) printk ("cx24116: " args); \ + } while (0) + +enum cmds +{ + CMD_INIT_CMD10 = 0x10, + CMD_TUNEREQUEST = 0x11, + CMD_INIT_CMD13 = 0x13, + CMD_INIT_CMD14 = 0x14, + CMD_SEND_DISEQC = 0x21, + CMD_SET_TONEPRE = 0x22, + CMD_SET_TONE = 0x23, +}; + +/* The Demod/Tuner can't easily provide these, we cache them */ +struct cx24116_tuning +{ + u32 frequency; + u32 symbol_rate; + fe_spectral_inversion_t inversion; + fe_code_rate_t fec; + + fe_modulation_t modulation; + + /* Demod values */ + u8 fec_val; + u8 fec_mask; + u8 inversion_val; +}; + +/* Basic commands that are sent to the firmware */ +struct cx24116_cmd +{ + u8 len; + u8 args[CX24116_ARGLEN]; +}; + +struct cx24116_state +{ + struct i2c_adapter* i2c; + const struct cx24116_config* config; + + struct dvb_frontend frontend; + + struct cx24116_tuning dcur; + struct cx24116_tuning dnxt; + + u8 skip_fw_load; + u8 burst; +}; + +static int cx24116_writereg(struct cx24116_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 (debug>1) + printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", + __func__,reg, data); + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk("%s: writereg error(err == %i, reg == 0x%02x," + " value == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +/* Bulk byte writes to a single I2C address, for 32k firmware load */ +static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len) +{ + int ret = -EREMOTEIO; + struct i2c_msg msg; + u8 *buf; + + buf = kmalloc(len + 1, GFP_KERNEL); + if (buf == NULL) { + printk("Unable to kmalloc\n"); + ret = -ENOMEM; + goto error; + } + + *(buf) = reg; + memcpy(buf + 1, data, len); + + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.buf = buf; + msg.len = len + 1; + + if (debug>1) + printk("cx24116: %s: write regN 0x%02x, len = %d\n", + __func__,reg, len); + + if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk("%s: writereg error(err == %i, reg == 0x%02x\n", + __func__, ret, reg); + ret = -EREMOTEIO; + } + +error: + kfree(buf); + + return ret; +} + +static int cx24116_readreg(struct cx24116_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", __func__, reg, ret); + return ret; + } + + if (debug>1) + printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]); + + return b1[0]; +} + +static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion) +{ + dprintk("%s(%d)\n", __func__, inversion); + + switch (inversion) { + case INVERSION_OFF: + state->dnxt.inversion_val = 0x00; + break; + case INVERSION_ON: + state->dnxt.inversion_val = 0x04; + break; + case INVERSION_AUTO: + state->dnxt.inversion_val = 0x0C; + break; + default: + return -EINVAL; + } + + state->dnxt.inversion = inversion; + + return 0; +} + +/* A table of modulation, fec and configuration bytes for the demod. + * Not all S2 mmodulation schemes are support and not all rates with + * a scheme are support. Especially, no auto detect when in S2 mode. + */ +struct cx24116_modfec { + fe_modulation_t modulation; + fe_code_rate_t fec; + u8 mask; /* In DVBS mode this is used to autodetect */ + u8 val; /* Passed to the firmware to indicate mode selection */ +} CX24116_MODFEC_MODES[] = { + /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ + { QPSK, FEC_NONE, 0xfe, 0x30 }, + { QPSK, FEC_1_2, 0x02, 0x2e }, + { QPSK, FEC_2_3, 0x04, 0x2f }, + { QPSK, FEC_3_4, 0x08, 0x30 }, + { QPSK, FEC_4_5, 0xfe, 0x30 }, + { QPSK, FEC_5_6, 0x20, 0x31 }, + { QPSK, FEC_6_7, 0xfe, 0x30 }, + { QPSK, FEC_7_8, 0x80, 0x32 }, + { QPSK, FEC_8_9, 0xfe, 0x30 }, + { QPSK, FEC_AUTO, 0xfe, 0x30 }, + /* NBC-QPSK */ + { NBC_QPSK, FEC_1_2, 0x00, 0x04 }, + { NBC_QPSK, FEC_3_5, 0x00, 0x05 }, + { NBC_QPSK, FEC_2_3, 0x00, 0x06 }, + { NBC_QPSK, FEC_3_4, 0x00, 0x07 }, + { NBC_QPSK, FEC_4_5, 0x00, 0x08 }, + { NBC_QPSK, FEC_5_6, 0x00, 0x09 }, + { NBC_QPSK, FEC_8_9, 0x00, 0x0a }, + { NBC_QPSK, FEC_9_10, 0x00, 0x0b }, + /* 8PSK */ + { _8PSK, FEC_3_5, 0x00, 0x0c }, + { _8PSK, FEC_2_3, 0x00, 0x0d }, + { _8PSK, FEC_3_4, 0x00, 0x0e }, + { _8PSK, FEC_5_6, 0x00, 0x0f }, + { _8PSK, FEC_9_10, 0x00, 0x11 }, +}; + +static int cx24116_lookup_fecmod(struct cx24116_state* state, + fe_modulation_t m, fe_code_rate_t f) +{ + int i, ret = -EOPNOTSUPP; + + for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++) + { + if( (m == CX24116_MODFEC_MODES[i].modulation) && + (f == CX24116_MODFEC_MODES[i].fec) ) + { + ret = i; + break; + } + } + + return ret; +} + +static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec) +{ + int ret = 0; + dprintk("%s()\n", __func__); + + ret = cx24116_lookup_fecmod(state, mod, fec); + + if(ret < 0) + return ret; + + state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; + state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; + dprintk("%s() fec_val/mask = 0x%02x/0x%02x\n", __func__, + state->dnxt.fec_val, state->dnxt.fec_mask); + + return 0; +} + +static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate) +{ + int ret = 0; + + dprintk("%s()\n", __func__); + + state->dnxt.symbol_rate = rate; + + dprintk("%s() symbol_rate = %d\n", __func__, state->dnxt.symbol_rate); + + /* check if symbol rate is within limits */ + if ((state->dnxt.symbol_rate > state->frontend.ops.info.symbol_rate_max) || + (state->dnxt.symbol_rate < state->frontend.ops.info.symbol_rate_min)) + ret = -EOPNOTSUPP; + + return ret; +} + +static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw); + +static int cx24116_firmware_ondemand(struct dvb_frontend* fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + const struct firmware *fw; + int ret = 0; + + dprintk("%s()\n",__func__); + + if (cx24116_readreg(state, 0x20) > 0) + { + + if (state->skip_fw_load) + return 0; + + /* Load firmware */ + /* request the firmware, this will block until someone uploads it */ + printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev); + printk("%s: Waiting for firmware upload(2)...\n", __func__); + if (ret) { + printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__); + return ret; + } + + /* Make sure we don't recurse back through here during loading */ + state->skip_fw_load = 1; + + ret = cx24116_load_firmware(fe, fw); + if (ret) + printk("%s: Writing firmware to device failed\n", __func__); + + release_firmware(fw); + + printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed"); + + /* Ensure firmware is always loaded if required */ + state->skip_fw_load = 0; + } + + return ret; +} + +/* Take a basic firmware command structure, format it and forward it for processing */ +static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd) +{ + struct cx24116_state *state = fe->demodulator_priv; + int i, ret; + + dprintk("%s()\n", __func__); + + /* Load the firmware if required */ + if ( (ret = cx24116_firmware_ondemand(fe)) != 0) + { + printk("%s(): Unable initialise the firmware\n", __func__); + return ret; + } + + /* Write the command */ + for(i = 0; i < cmd->len ; i++) + { + dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); + cx24116_writereg(state, i, cmd->args[i]); + } + + /* Start execution and wait for cmd to terminate */ + cx24116_writereg(state, 0x1f, 0x01); + while( cx24116_readreg(state, 0x1f) ) + { + msleep(10); + if(i++ > 64) + { + /* Avoid looping forever if the firmware does no respond */ + printk("%s() Firmware not responding\n", __func__); + return -EREMOTEIO; + } + } + return 0; +} + +static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + struct cx24116_state* state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + + dprintk("%s\n", __func__); + dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n" + ,fw->size + ,fw->data[0] + ,fw->data[1] + ,fw->data[ fw->size-2 ] + ,fw->data[ fw->size-1 ] + ); + + /* Toggle 88x SRST pin to reset demod */ + if (state->config->reset_device) + state->config->reset_device(fe); + + /* Begin the firmware load process */ + /* Prepare the demod, load the firmware, cleanup after load */ + cx24116_writereg(state, 0xF1, 0x08); + cx24116_writereg(state, 0xF2, cx24116_readreg(state, 0xF2) | 0x03); + cx24116_writereg(state, 0xF3, 0x46); + cx24116_writereg(state, 0xF9, 0x00); + + cx24116_writereg(state, 0xF0, 0x03); + cx24116_writereg(state, 0xF4, 0x81); + cx24116_writereg(state, 0xF5, 0x00); + cx24116_writereg(state, 0xF6, 0x00); + + /* write the entire firmware as one transaction */ + cx24116_writeregN(state, 0xF7, fw->data, fw->size); + + cx24116_writereg(state, 0xF4, 0x10); + cx24116_writereg(state, 0xF0, 0x00); + cx24116_writereg(state, 0xF8, 0x06); + + /* Firmware CMD 10: Chip config? */ + cmd.args[0x00] = CMD_INIT_CMD10; + cmd.args[0x01] = 0x05; + cmd.args[0x02] = 0xdc; + cmd.args[0x03] = 0xda; + cmd.args[0x04] = 0xae; + cmd.args[0x05] = 0xaa; + cmd.args[0x06] = 0x04; + cmd.args[0x07] = 0x9d; + cmd.args[0x08] = 0xfc; + cmd.args[0x09] = 0x06; + cmd.len= 0x0a; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + cx24116_writereg(state, 0x9d, 0x00); + + /* Firmware CMD 14: Unknown */ + cmd.args[0x00] = CMD_INIT_CMD14; + cmd.args[0x01] = 0x00; + cmd.args[0x02] = 0x00; + cmd.len= 0x03; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + cx24116_writereg(state, 0xe5, 0x00); + + /* Firmware CMD 13: Unknown - Firmware config? */ + cmd.args[0x00] = CMD_INIT_CMD13; + cmd.args[0x01] = 0x01; + cmd.args[0x02] = 0x75; + cmd.args[0x03] = 0x00; + cmd.args[0x04] = 0x02; + cmd.args[0x05] = 0x00; + cmd.len= 0x06; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + return 0; +} + +static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + /* The isl6421 module will override this function in the fops. */ + dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__); + + return -EOPNOTSUPP; +} + +static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct cx24116_state *state = fe->demodulator_priv; + + int lock = cx24116_readreg(state, 0x9d); + + dprintk("%s: status = 0x%02x\n", __func__, lock); + + *status = 0; + + if (lock & 0x01) + *status |= FE_HAS_SIGNAL; + if (lock & 0x02) + *status |= FE_HAS_CARRIER; + if (lock & 0x04) + *status |= FE_HAS_VITERBI; + if (lock & 0x08) + *status |= FE_HAS_SYNC | FE_HAS_LOCK; + + return 0; +} + +/* TODO: Not clear how we do this */ +static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber) +{ + //struct cx24116_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + *ber = 0; + + return 0; +} + +/* Signal strength (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ +static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct cx24116_state *state = fe->demodulator_priv; + u8 strength_reg; + static const u32 strength_tab[] = { /* 10 x Table (rounded up) */ + 0x00000,0x0199A,0x03333,0x04ccD,0x06667,0x08000,0x0999A,0x0b333,0x0cccD,0x0e667, + 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 }; + + dprintk("%s()\n", __func__); + + strength_reg = cx24116_readreg(state, CX24116_REG_SIGNAL); + + if(strength_reg < 0xa0) + *signal_strength = strength_tab [ ( strength_reg & 0xf0 ) >> 4 ] + + ( strength_tab [ ( strength_reg & 0x0f ) ] >> 4 ); + else + *signal_strength = 0xffff; + + dprintk("%s: Signal strength (raw / cooked) = (0x%02x / 0x%04x)\n", + __func__,strength_reg,*signal_strength); + + return 0; +} + +/* TODO: Not clear how we do this */ +static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) +{ + //struct cx24116_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + *snr = 0; + + return 0; +} + +/* TODO: Not clear how we do this */ +static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + //struct cx24116_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); + *ucblocks = 0; + + return 0; +} + +/* Overwrite the current tuning params, we are about to tune */ +static void cx24116_clone_params(struct dvb_frontend* fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); +} + +static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct cx24116_cmd cmd; + int ret; + + dprintk("%s(%d)\n", __func__, tone); + if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) { + printk("%s: Invalid, tone=%d\n", __func__, tone); + return -EINVAL; + } + + /* This is always done before the tone is set */ + cmd.args[0x00] = CMD_SET_TONEPRE; + cmd.args[0x01] = 0x00; + cmd.len= 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + /* Now we set the tone */ + cmd.args[0x00] = CMD_SET_TONE; + cmd.args[0x01] = 0x00; + cmd.args[0x02] = 0x00; + + switch (tone) { + case SEC_TONE_ON: + dprintk("%s: setting tone on\n", __func__); + cmd.args[0x03] = 0x01; + break; + case SEC_TONE_OFF: + dprintk("%s: setting tone off\n",__func__); + cmd.args[0x03] = 0x00; + break; + } + cmd.len= 0x04; + + return cx24116_cmd_execute(fe, &cmd); +} + +/* Initialise DiSEqC */ +static int cx24116_diseqc_init(struct dvb_frontend* fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + + /* Default DiSEqC burst state */ + state->burst = CX24116_DISEQC_MINI_A; + + return 0; +} + +/* Send DiSEqC message with derived burst (hack) || previous burst */ +static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int i, ret; + + /* Dump DiSEqC message */ + if (debug) { + printk("cx24116: %s(", __func__); + for(i = 0 ; i < d->msg_len ;) { + printk("0x%02x", d->msg[i]); + if(++i < d->msg_len) + printk(", "); + } + printk(")\n"); + } + + if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) + return -EINVAL; + + cmd.args[0x00] = CMD_SEND_DISEQC; + cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; + cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; + cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; + + /* DiSEqC message */ + for (i = 0; i < d->msg_len; i++) + cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; + + /* Hack: Derive burst from command else use previous burst */ + if(d->msg_len >= 4 && d->msg[2] == 0x38) + cmd.args[CX24116_DISEQC_BURST] = (d->msg[3] >> 2) & 1; + else + cmd.args[CX24116_DISEQC_BURST] = state->burst; + + cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; + cmd.len = CX24116_DISEQC_MSGOFS + d->msg_len; + + ret = cx24116_cmd_execute(fe, &cmd); + + /* Firmware command duration is unknown, so guess... + * + * Eutelsat spec: + * >15ms delay + + * 13.5ms per byte + + * >15ms delay + + * 12.5ms burst + + * >15ms delay + */ + if(ret == 0) + msleep( (cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 ); + + return ret; +} + +/* Send DiSEqC burst */ +static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + + dprintk("%s(%d)\n",__func__,(int)burst); + + cmd.args[0x00] = CMD_SEND_DISEQC; + cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; + cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; + cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; + + if (burst == SEC_MINI_A) + cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; + else if(burst == SEC_MINI_B) + cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B; + else + return -EINVAL; + + /* Cache as previous burst state */ + state->burst= cmd.args[CX24116_DISEQC_BURST]; + + cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; + cmd.len= CX24116_DISEQC_MSGOFS; + + ret= cx24116_cmd_execute(fe, &cmd); + + /* Firmware command duration is unknown, so guess... */ + if(ret == 0) + msleep(60); + + return ret; +} + +static void cx24116_release(struct dvb_frontend* fe) +{ + struct cx24116_state* state = fe->demodulator_priv; + dprintk("%s\n",__func__); + kfree(state); +} + +static struct dvb_frontend_ops cx24116_ops; + +struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, + struct i2c_adapter* i2c) +{ + struct cx24116_state* state = NULL; + int ret; + + dprintk("%s\n",__func__); + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL); + if (state == NULL) { + printk("Unable to kmalloc\n"); + goto error; + } + + /* setup the state */ + memset(state, 0, sizeof(struct cx24116_state)); + + state->config = config; + state->i2c = i2c; + + /* check if the demod is present */ + ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); + if (ret != 0x0501) { + printk("Invalid probe, probably not a CX24116 device\n"); + goto error; + } + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + + return NULL; +} + +static int cx24116_get_params(struct dvb_frontend* fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct tv_frontend_properties *cache = &fe->tv_property_cache; + + dprintk("%s()\n",__func__); + + cache->frequency = state->dcur.frequency; + cache->inversion = state->dcur.inversion; + cache->modulation = state->dcur.modulation; + cache->fec_inner = state->dcur.fec; + cache->symbol_rate = state->dcur.symbol_rate; + + return 0; +} + +static int cx24116_initfe(struct dvb_frontend* fe) +{ + dprintk("%s()\n",__func__); + + return cx24116_diseqc_init(fe); +} + +static int cx24116_set_property(struct dvb_frontend *fe, tv_property_t* tvp) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int cx24116_set_params(struct dvb_frontend *fe) +{ + dprintk("%s(..) We were notified that a tune request may occur\n", __func__); + return 0; +} + +/* dvb-core told us to tune, the tv property cache will be complete, + * it's safe for is to pull values and use them for tuning purposes. + */ +static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx24116_state *state = fe->demodulator_priv; + struct tv_frontend_properties *c = &fe->tv_property_cache; + struct cx24116_cmd cmd; + fe_status_t tunerstat; + int ret; + u8 retune=4; + + dprintk("%s()\n",__func__); + + state->dnxt.modulation = c->modulation; + state->dnxt.frequency = c->frequency; + + if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) + return ret; + + if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0) + return ret; + + if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0) + return ret; + + /* discard the 'current' tuning parameters and prepare to tune */ + cx24116_clone_params(fe); + + dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); + dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); + dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, + state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); + dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, + state->dcur.inversion, state->dcur.inversion_val); + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + /* Prepare a tune request */ + cmd.args[0x00] = CMD_TUNEREQUEST; + + /* Frequency */ + cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16; + cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8; + cmd.args[0x03] = (state->dcur.frequency & 0x0000ff); + + /* Symbol Rate */ + cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; + cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff); + + /* Automatic Inversion */ + cmd.args[0x06] = state->dcur.inversion_val; + + /* Modulation / FEC & Pilot Off */ + cmd.args[0x07] = state->dcur.fec_val; + + if (c->pilot == PILOT_ON) + cmd.args[0x07] |= 0x40; + + cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; + cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; + cmd.args[0x0a] = 0x00; + cmd.args[0x0b] = 0x00; + cmd.args[0x0c] = 0x02; + cmd.args[0x0d] = state->dcur.fec_mask; + cmd.args[0x0e] = 0x06; + cmd.args[0x0f] = 0x00; + cmd.args[0x10] = 0x00; + cmd.args[0x11] = 0xFA; + cmd.args[0x12] = 0x24; + cmd.len= 0x13; + + /* We need to support pilot and non-pilot tuning in the + * driver automatically. This is a workaround for because + * the demod does not support autodetect. + */ + do { + /* Reset status register? */ + cx24116_writereg(state, 0x9d, 0xc1); + + /* Tune */ + ret = cx24116_cmd_execute(fe, &cmd); + if( ret != 0 ) + break; + + /* The hardware can take time to lock, wait a while */ + msleep(500); + + cx24116_read_status(fe, &tunerstat); + if(tunerstat & FE_HAS_SIGNAL) { + if(tunerstat & FE_HAS_SYNC) + /* Tuned */ + break; + else if(c->pilot == PILOT_AUTO) + /* Toggle pilot bit */ + cmd.args[0x07] ^= 0x40; + } + } + while(--retune); + + return ret; +} + +static struct dvb_frontend_ops cx24116_ops = { + + .info = { + .name = "Conexant CX24116/CX24118", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 5000, + .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_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = cx24116_release, + + .init = cx24116_initfe, + .read_status = cx24116_read_status, + .read_ber = cx24116_read_ber, + .read_signal_strength = cx24116_read_signal_strength, + .read_snr = cx24116_read_snr, + .read_ucblocks = cx24116_read_ucblocks, + .set_tone = cx24116_set_tone, + .set_voltage = cx24116_set_voltage, + .diseqc_send_master_cmd = cx24116_send_diseqc_msg, + .diseqc_send_burst = cx24116_diseqc_send_burst, + + .set_property = cx24116_set_property, + .set_params = cx24116_set_params, + .set_frontend = cx24116_set_frontend, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); + +MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); +MODULE_AUTHOR("Steven Toth"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cx24116_attach); diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h new file mode 100644 index 000000000000..27896725204a --- /dev/null +++ b/drivers/media/dvb/frontends/cx24116.h @@ -0,0 +1,50 @@ +/* + Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver + + Copyright (C) 2006 Steven Toth + + 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 CX24116_H +#define CX24116_H + +#include + +struct cx24116_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); + + /* Need to reset device during firmware loading */ + int (*reset_device)(struct dvb_frontend* fe); +}; + +#if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE) +extern struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_CX24116 + +#endif /* CX24116_H */ -- cgit v1.2.1 From 13c97bf56724b4f2d3dac139fb4cb081a3c401dc Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 4 Sep 2008 21:19:43 -0300 Subject: V4L/DVB (8988): S2API: Allow the properties to call legacy ioctls SET_TONE and SET_VOLTAGE were not previously implemented. Two options existed. Either cut/paste from the previous ioctl handler into the process_properties function, which is code duplication. Or, split the current ioctl handler into it's two major pieces. Piece 1, responsible for input validation and semaphore acquiring Piece 2 the processing of the previous ioctls and finally, a new third pieces where the array of properties is processed, and can freely call the legacy ioctl handler without having to re-acquire the fepriv->sem semaphore. This is a clean approach and ensures the existing legacy ioctls are processed as they were previously (but with an extra function call) and allows the new API to share code without duplication. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 67 +++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index e68974b2fee9..86af06cf578c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1156,9 +1156,16 @@ int tv_property_cache_submit(struct dvb_frontend *fe) return r; } -int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp) +static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, + unsigned int cmd, void *parg); +static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, + unsigned int cmd, void *parg); + +int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp, + struct inode *inode, struct file *file) { int r = 0; + struct dvb_frontend_private *fepriv = fe->frontend_priv; printk("%s()\n", __FUNCTION__); tv_property_dump(tvp); @@ -1181,7 +1188,9 @@ int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp) */ fe->tv_property_cache.state = TV_SEQ_COMPLETE; printk("%s() Finalised property cache\n", __FUNCTION__); - r = tv_property_cache_submit(fe); + r |= tv_property_cache_submit(fe); + r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, + &fepriv->parameters); break; case TV_SET_FREQUENCY: fe->tv_property_cache.frequency = tvp->u.data; @@ -1278,10 +1287,25 @@ int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp) case TV_GET_ISDB_LAYERC_SEGMENT_WIDTH: tvp->u.data = fe->tv_property_cache.isdb_layerc_segment_width; break; - + case TV_SET_VOLTAGE: + fe->tv_property_cache.voltage = tvp->u.data; + r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE, + &fe->tv_property_cache.voltage); + break; + case TV_GET_VOLTAGE: + tvp->u.data = fe->tv_property_cache.voltage; + break; + case TV_SET_TONE: + fe->tv_property_cache.sectone = tvp->u.data; + r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE, + (void *)fe->tv_property_cache.sectone); + break; + case TV_GET_TONE: + tvp->u.data = fe->tv_property_cache.sectone; + break; } - return 0; + return r; } static int dvb_frontend_ioctl(struct inode *inode, struct file *file, @@ -1291,7 +1315,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; int err = -EOPNOTSUPP; - tv_property_t* tvp; dprintk ("%s\n", __func__); @@ -1306,6 +1329,25 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, if (down_interruptible (&fepriv->sem)) return -ERESTARTSYS; + if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) + err = dvb_frontend_ioctl_properties(inode, file, cmd, parg); + else + err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg); + + up(&fepriv->sem); + return err; +} + +static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + int err = -EOPNOTSUPP; + tv_property_t *tvp; + + dprintk("%s\n", __func__); + if(cmd == FE_SET_PROPERTY) { printk("%s() FE_SET_PROPERTY\n", __FUNCTION__); @@ -1314,7 +1356,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, /* TODO: ioctl userdata out of range check here */ tvp = parg; while(tvp->cmd != TV_SEQ_UNDEFINED) { - tv_property_process(fe, tvp); + tv_property_process(fe, tvp, inode, file); if( (tvp->cmd == TV_SEQ_TERMINATE) || (tvp->cmd == TV_SEQ_COMPLETE) ) break; tvp++; @@ -1322,11 +1364,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) { printk("%s() Property cache is full, tuning\n", __FUNCTION__); - cmd = FE_SET_FRONTEND; } err = 0; } + return err; +} + +static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + int err = -EOPNOTSUPP; + switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* info = parg; @@ -1585,7 +1637,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; }; - up (&fepriv->sem); return err; } -- cgit v1.2.1 From 2cf801e3e38f649d25fe3b4e236976f45e26289f Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 8 Sep 2008 12:07:06 -0300 Subject: V4L/DVB (8990): S2API: DVB-S/S2 voltage selection bug fix Thanks to Hans Werner for finding the problem. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 86af06cf578c..620c62084029 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1290,7 +1290,7 @@ int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp, case TV_SET_VOLTAGE: fe->tv_property_cache.voltage = tvp->u.data; r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE, - &fe->tv_property_cache.voltage); + (void *)fe->tv_property_cache.voltage); break; case TV_GET_VOLTAGE: tvp->u.data = fe->tv_property_cache.voltage; -- cgit v1.2.1 From fe03d5ee6758a2533dbc5e69a693d264d270d04b Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Mon, 8 Sep 2008 17:16:40 -0300 Subject: V4L/DVB (8991): Added support for DVBWorld 2104 and TeVii S650 USB DVB-S2 cards Added support for DVBWorld 2104 and TeVii S650 USB DVB-S2 cards This cards based on cx24116 demodulator. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 305 ++++++++++++++++++++++++++++++------- drivers/media/dvb/dvb-usb/dw2102.h | 1 - 2 files changed, 248 insertions(+), 58 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index a4d898b44e55..0f3f962b35bf 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1,4 +1,5 @@ -/* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card +/* 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) * @@ -12,18 +13,23 @@ #include "dw2102.h" #include "stv0299.h" #include "z0194a.h" +#include "cx24116.h" #ifndef USB_PID_DW2102 #define USB_PID_DW2102 0x2102 #endif +#ifndef USB_PID_DW2104 +#define USB_PID_DW2104 0x2104 +#endif + #define DW2102_READ_MSG 0 #define DW2102_WRITE_MSG 1 #define REG_1F_SYMBOLRATE_BYTE0 0x1f #define REG_20_SYMBOLRATE_BYTE1 0x20 #define REG_21_SYMBOLRATE_BYTE2 0x21 - +/* on my own*/ #define DW2102_VOLTAGE_CTRL (0x1800) #define DW2102_RC_QUERY (0x1a00) @@ -35,22 +41,27 @@ struct dw2102_rc_keys { u32 event; }; +/* 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); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value, - u8 *data, u16 len, int flags) + u16 index, u8 * data, u16 len, int flags) { int ret; u8 u8buf[len]; unsigned int pipe = (flags == DW2102_READ_MSG) ? - usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); + usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; if (flags == DW2102_WRITE_MSG) memcpy(u8buf, data, len); - ret = usb_control_msg(dev, pipe, request, - request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000); + ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, + value, index , u8buf, len, 2000); if (flags == DW2102_READ_MSG) memcpy(data, u8buf, len); @@ -65,7 +76,6 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i = 0, ret = 0; u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0}; - u8 request; u16 value; if (!d) @@ -76,12 +86,11 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); switch (num) { case 2: /* read stv0299 register */ - request = 0xb5; value = msg[0].buf[0];/* register */ for (i = 0; i < msg[1].len; i++) { value = value + i; - ret = dw2102_op_rw(d->udev, 0xb5, - value, buf6, 2, DW2102_READ_MSG); + ret = dw2102_op_rw(d->udev, 0xb5, value, 0, + buf6, 2, DW2102_READ_MSG); msg[1].buf[i] = buf6[0]; } @@ -93,8 +102,8 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); buf6[0] = 0x2a; buf6[1] = msg[0].buf[0]; buf6[2] = msg[0].buf[1]; - ret = dw2102_op_rw(d->udev, 0xb2, - 0, buf6, 3, DW2102_WRITE_MSG); + ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, + buf6, 3, DW2102_WRITE_MSG); break; case 0x60: if (msg[0].flags == 0) { @@ -106,26 +115,26 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); buf6[4] = msg[0].buf[1]; buf6[5] = msg[0].buf[2]; buf6[6] = msg[0].buf[3]; - ret = dw2102_op_rw(d->udev, 0xb2, - 0, buf6, 7, DW2102_WRITE_MSG); + ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, + buf6, 7, DW2102_WRITE_MSG); } else { - /* write to tuner pll */ - ret = dw2102_op_rw(d->udev, 0xb5, - 0, buf6, 1, DW2102_READ_MSG); + /* read from tuner */ + ret = dw2102_op_rw(d->udev, 0xb5, 0,0, + buf6, 1, DW2102_READ_MSG); msg[0].buf[0] = buf6[0]; } break; case (DW2102_RC_QUERY): - ret = dw2102_op_rw(d->udev, 0xb8, - 0, buf6, 2, DW2102_READ_MSG); + ret = dw2102_op_rw(d->udev, 0xb8, 0, 0, + buf6, 2, DW2102_READ_MSG); msg[0].buf[0] = buf6[0]; msg[0].buf[1] = buf6[1]; break; case (DW2102_VOLTAGE_CTRL): buf6[0] = 0x30; buf6[1] = msg[0].buf[0]; - ret = dw2102_op_rw(d->udev, 0xb2, - 0, buf6, 2, DW2102_WRITE_MSG); + ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, + buf6, 2, DW2102_WRITE_MSG); break; } @@ -136,6 +145,88 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); return num; } +static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0; + int len, 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] = 0xaa; + obuf[1] = msg[0].len; + obuf[2] = msg[0].buf[0]; + ret = dw2102_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW2102_WRITE_MSG); + /* second read registers */ + ret = dw2102_op_rw(d->udev, 0xc3, 0xab , 0, + ibuf, msg[1].len + 2, DW2102_READ_MSG); + memcpy(msg[1].buf, ibuf + 2, msg[1].len); + + break; + } + case 1: + switch (msg[0].addr) { + case 0x55: { + if (msg[0].buf[0] == 0xf7) { + /* firmware */ + /* Write in small blocks */ + u8 obuf[19]; + obuf[0] = 0xaa; + obuf[1] = 0x11; + obuf[2] = 0xf7; + len = msg[0].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len)); + ret = dw2102_op_rw(d->udev, 0xc2, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, DW2102_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = 0xaa; + obuf[1] = msg[0].len; + memcpy(obuf + 2, msg[0].buf, msg[0].len); + ret = dw2102_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW2102_WRITE_MSG); + } + break; + } + case(DW2102_RC_QUERY): { + u8 ibuf[2]; + ret = dw2102_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW2102_READ_MSG); + memcpy(msg[0].buf, ibuf , 2); + break; + } + case(DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + obuf[0] = 0x30; + obuf[1] = msg[0].buf[0]; + ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, + obuf, 2, DW2102_WRITE_MSG); + break; + } + } + + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + static u32 dw2102_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; @@ -146,6 +237,34 @@ static struct i2c_algorithm dw2102_i2c_algo = { .functionality = dw2102_i2c_func, }; +static struct i2c_algorithm dw2104_i2c_algo = { + .master_xfer = dw2104_i2c_transfer, + .functionality = dw2102_i2c_func, +}; + +static int dw2102_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 ibuf[] = {0, 0}; + u8 eeprom[256], eepromline[16]; + + for (i = 0; i < 256; i++) { + if (dw2102_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW2102_READ_MSG) < 0) { + err("read eeprom failed."); + return -1; + } else { + eepromline[i%16] = ibuf[0]; + eeprom[i] = ibuf[0]; + } + if ((i % 16) == 15) { + deb_xfer("%02x: ", i - 15); + debug_dump(eepromline, 16, deb_xfer); + } + } + memcpy(mac, eeprom + 8, 6); + return 0; +}; + static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { static u8 command_13v[1] = {0x00}; @@ -163,6 +282,22 @@ static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } +static struct cx24116_config dw2104_config = { + .demod_address = 0x55, + /*.mpg_clk_pos_pol = 0x01,*/ +}; + +static int dw2104_frontend_attach(struct dvb_usb_adapter *d) +{ + if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, + &d->dev->i2c_adap)) != NULL) { + d->fe->ops.set_voltage = dw2102_set_voltage; + info("Attached cx24116!\n"); + return 0; + } + return -EIO; +} + static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, @@ -249,6 +384,8 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) 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)}, { } }; @@ -273,25 +410,23 @@ static int dw2102_load_firmware(struct usb_device *dev, return ret; } break; - case USB_PID_DW2102: + default: fw = frmwr; break; } - info("start downloading DW2102 firmware"); + info("start downloading DW210X firmware"); p = kmalloc(fw->size, GFP_KERNEL); reset = 1; /*stop the CPU*/ - dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG); - dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG); + dw2102_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW2102_WRITE_MSG); + dw2102_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW2102_WRITE_MSG); if (p != NULL) { memcpy(p, fw->data, fw->size); for (i = 0; i < fw->size; i += 0x40) { b = (u8 *) p + i; - if (dw2102_op_rw - (dev, 0xa0, i, b , 0x40, - DW2102_WRITE_MSG) != 0x40 - ) { + if (dw2102_op_rw(dev, 0xa0, i, 0, b , 0x40, + DW2102_WRITE_MSG) != 0x40) { err("error while transferring firmware"); ret = -EINVAL; break; @@ -299,43 +434,45 @@ static int dw2102_load_firmware(struct usb_device *dev, } /* restart the CPU */ reset = 0; - if (ret || dw2102_op_rw - (dev, 0xa0, 0x7f92, &reset, 1, - DW2102_WRITE_MSG) != 1) { + if (ret || dw2102_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, + DW2102_WRITE_MSG) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } - if (ret || dw2102_op_rw - (dev, 0xa0, 0xe600, &reset, 1, - DW2102_WRITE_MSG) != 1) { + if (ret || dw2102_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, + DW2102_WRITE_MSG) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } /* init registers */ switch (dev->descriptor.idProduct) { + case USB_PID_DW2104: + case 0xd650: + reset = 1; + dw2102_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, + DW2102_WRITE_MSG); + reset = 0; + dw2102_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW2102_WRITE_MSG); + break; case USB_PID_DW2102: - dw2102_op_rw - (dev, 0xbf, 0x0040, &reset, 0, - DW2102_WRITE_MSG); - dw2102_op_rw - (dev, 0xb9, 0x0000, &reset16[0], 2, - DW2102_READ_MSG); + dw2102_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW2102_WRITE_MSG); + dw2102_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW2102_READ_MSG); break; case 0x2101: - dw2102_op_rw - (dev, 0xbc, 0x0030, &reset16[0], 2, - DW2102_READ_MSG); - dw2102_op_rw - (dev, 0xba, 0x0000, &reset16[0], 7, - DW2102_READ_MSG); - dw2102_op_rw - (dev, 0xba, 0x0000, &reset16[0], 7, - DW2102_READ_MSG); - dw2102_op_rw - (dev, 0xb9, 0x0000, &reset16[0], 2, - DW2102_READ_MSG); + dw2102_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, + DW2102_READ_MSG); + dw2102_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW2102_READ_MSG); + dw2102_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW2102_READ_MSG); + dw2102_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW2102_READ_MSG); break; } + msleep(100); kfree(p); } return ret; @@ -358,7 +495,8 @@ static struct dvb_usb_device_properties dw2102_properties = { /* parameter for the MPEG2-data transfer */ .num_adapters = 1, .download_firmware = dw2102_load_firmware, - .adapter = { + .read_mac_address = dw2102_read_mac_address, + .adapter = { { .frontend_attach = dw2102_frontend_attach, .streaming_ctrl = NULL, @@ -388,11 +526,64 @@ static struct dvb_usb_device_properties dw2102_properties = { } }; +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 dw2102_state), + .no_reconnect = 1, + + .i2c_algo = &dw2104_i2c_algo, + .rc_key_map = dw2102_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dw2102_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 = dw2102_read_mac_address, + .adapter = { + { + .frontend_attach = dw2104_frontend_attach, + .streaming_ctrl = NULL, + /*.tuner_attach = dw2104_tuner_attach,*/ + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } + }, + .num_device_descs = 2, + .devices = { + { "DVBWorld DW2104 USB2.0", + {&dw2102_table[2], NULL}, + {NULL}, + }, + { "TeVii S650 USB2.0", + {&dw2102_table[3], NULL}, + {NULL}, + }, + } +}; + static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf, &dw2102_properties, - THIS_MODULE, NULL, adapter_nr); + 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)) { + return 0; + } + return -ENODEV; } static struct usb_driver dw2102_driver = { @@ -420,6 +611,6 @@ 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 USB2.0 device"); +MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h index 7a310f906837..e3370734e95a 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.h +++ b/drivers/media/dvb/dvb-usb/dw2102.h @@ -4,6 +4,5 @@ #define DVB_USB_LOG_PREFIX "dw2102" #include "dvb-usb.h" -extern int dvb_usb_dw2102_debug; #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args) #endif -- cgit v1.2.1 From 4e54676895a867621f8451b8d97549172730997d Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 9 Sep 2008 11:29:43 -0300 Subject: V4L/DVB (8992): Kconfig corrections for DVBWorld 2104 and TeVii S650 USB DVB-S2 cards Change menu item in Kconfig for DVBWorld 2104 and TeVii S650 USB DVB-S2 cards Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index b35d7f0db9aa..aee3b5dd651b 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -247,12 +247,14 @@ config DVB_USB_AF9005_REMOTE Afatech AF9005 based receiver. config DVB_USB_DW2102 - tristate "DvbWorld 2102 DVB-S USB2.0 receiver" + tristate "DvbWorld DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE help - Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver. + Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers + and the TeVii S650. config DVB_USB_ANYSEE tristate "Anysee DVB-T/C USB2.0 support" -- cgit v1.2.1 From 3f8e51add2b7d37f16343e6bdcc63862d87ccd04 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 9 Sep 2008 13:22:29 -0300 Subject: V4L/DVB (8993): cx24116: Fix lock for high (above 30000 kSyms) symbol rates cx24116: Fix lock for high (above 30000 kSyms) symbol rates Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 37 +++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 1402086a5c44..2ff9e20c595f 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -30,6 +30,11 @@ * Sync with legacy version. * Some clean ups. */ +/* Updates by Igor Liplianin + * + * September, 9th 2008 + * Fixed locking on high symbol rates (>30000). + */ #include #include @@ -809,7 +814,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par struct tv_frontend_properties *c = &fe->tv_property_cache; struct cx24116_cmd cmd; fe_status_t tunerstat; - int ret; + int ret, above30msps; u8 retune=4; dprintk("%s()\n",__func__); @@ -839,6 +844,16 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (state->config->set_ts_params) state->config->set_ts_params(fe, 0); + above30msps = (state->dcur.symbol_rate > 30000000); + + if (above30msps){ + cx24116_writereg(state, 0xF9, 0x01); + cx24116_writereg(state, 0xF3, 0x44); + } else { + cx24116_writereg(state, 0xF9, 0x00); + cx24116_writereg(state, 0xF3, 0x46); + } + /* Prepare a tune request */ cmd.args[0x00] = CMD_TUNEREQUEST; @@ -866,11 +881,21 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par cmd.args[0x0b] = 0x00; cmd.args[0x0c] = 0x02; cmd.args[0x0d] = state->dcur.fec_mask; - cmd.args[0x0e] = 0x06; - cmd.args[0x0f] = 0x00; - cmd.args[0x10] = 0x00; - cmd.args[0x11] = 0xFA; - cmd.args[0x12] = 0x24; + + if (above30msps){ + cmd.args[0x0e] = 0x04; + cmd.args[0x0f] = 0x00; + cmd.args[0x10] = 0x01; + cmd.args[0x11] = 0x77; + cmd.args[0x12] = 0x36; + } else { + cmd.args[0x0e] = 0x06; + cmd.args[0x0f] = 0x00; + cmd.args[0x10] = 0x00; + cmd.args[0x11] = 0xFA; + cmd.args[0x12] = 0x24; + } + cmd.len= 0x13; /* We need to support pilot and non-pilot tuning in the -- cgit v1.2.1 From cc8c4f3a9c8dacff198438debd159ae4753744fc Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 9 Sep 2008 13:57:47 -0300 Subject: V4L/DVB (8994): Adjust MPEG initialization in cx24116 Adjust MPEG initialization in cx24116 in order to accomodate different MPEG CLK position and polarity in different cards. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 2 +- drivers/media/dvb/frontends/cx24116.c | 5 ++++- drivers/media/dvb/frontends/cx24116.h | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 0f3f962b35bf..ad3d6fca9ab8 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -284,7 +284,7 @@ static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) static struct cx24116_config dw2104_config = { .demod_address = 0x55, - /*.mpg_clk_pos_pol = 0x01,*/ + .mpg_clk_pos_pol = 0x01, }; static int dw2104_frontend_attach(struct dvb_usb_adapter *d) diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 2ff9e20c595f..666a0d89e83c 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -478,7 +478,10 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware cmd.args[0x01] = 0x01; cmd.args[0x02] = 0x75; cmd.args[0x03] = 0x00; - cmd.args[0x04] = 0x02; + if (state->config->mpg_clk_pos_pol) + cmd.args[0x04] = state->config->mpg_clk_pos_pol; + else + cmd.args[0x04] = 0x02; cmd.args[0x05] = 0x00; cmd.len= 0x06; ret = cx24116_cmd_execute(fe, &cmd); diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h index 27896725204a..8dbcec268394 100644 --- a/drivers/media/dvb/frontends/cx24116.h +++ b/drivers/media/dvb/frontends/cx24116.h @@ -33,6 +33,9 @@ struct cx24116_config /* Need to reset device during firmware loading */ int (*reset_device)(struct dvb_frontend* fe); + + /* Need to set MPEG parameters */ + u8 mpg_clk_pos_pol:0x02; }; #if defined(CONFIG_DVB_CX24116) || defined(CONFIG_DVB_CX24116_MODULE) -- cgit v1.2.1 From 56f0680a28397f4b412fc14f60ac380b910ee328 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 11 Sep 2008 10:19:27 -0300 Subject: V4L/DVB (8995): S2API: tv_ / TV_ to dtv_ / DTV_ namespace changes The group preferred dtv_ over tv_, this implements it. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 442 +++++++++++++++--------------- drivers/media/dvb/dvb-core/dvb_frontend.h | 8 +- drivers/media/dvb/frontends/cx24116.c | 6 +- 3 files changed, 228 insertions(+), 228 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 620c62084029..9c4761506d2d 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -755,235 +755,235 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe, return 0; } -struct tv_cmds_h tv_cmds[] = { - [TV_SEQ_UNDEFINED] = { - .name = "TV_SEQ_UNDEFINED", - .cmd = TV_SEQ_UNDEFINED, +struct dtv_cmds_h dtv_cmds[] = { + [DTV_SEQ_UNDEFINED] = { + .name = "DTV_SEQ_UNDEFINED", + .cmd = DTV_SEQ_UNDEFINED, .set = 1, }, - [TV_SEQ_START] = { - .name = "TV_SEQ_START", - .cmd = TV_SEQ_START, + [DTV_SEQ_START] = { + .name = "DTV_SEQ_START", + .cmd = DTV_SEQ_START, .set = 1, }, - [TV_SEQ_CONTINUE] = { - .name = "TV_SEQ_CONTINUE", - .cmd = TV_SEQ_CONTINUE, + [DTV_SEQ_CONTINUE] = { + .name = "DTV_SEQ_CONTINUE", + .cmd = DTV_SEQ_CONTINUE, .set = 1, }, - [TV_SEQ_COMPLETE] = { - .name = "TV_SEQ_COMPLETE", - .cmd = TV_SEQ_COMPLETE, + [DTV_SEQ_COMPLETE] = { + .name = "DTV_SEQ_COMPLETE", + .cmd = DTV_SEQ_COMPLETE, .set = 1, }, - [TV_SEQ_TERMINATE] = { - .name = "TV_SEQ_TERMINATE", - .cmd = TV_SEQ_TERMINATE, + [DTV_SEQ_TERMINATE] = { + .name = "DTV_SEQ_TERMINATE", + .cmd = DTV_SEQ_TERMINATE, .set = 1, }, /* Set */ - [TV_SET_FREQUENCY] = { - .name = "TV_SET_FREQUENCY", - .cmd = TV_SET_FREQUENCY, + [DTV_SET_FREQUENCY] = { + .name = "DTV_SET_FREQUENCY", + .cmd = DTV_SET_FREQUENCY, .set = 1, }, - [TV_SET_BANDWIDTH] = { - .name = "TV_SET_BANDWIDTH", - .cmd = TV_SET_BANDWIDTH, + [DTV_SET_BANDWIDTH] = { + .name = "DTV_SET_BANDWIDTH", + .cmd = DTV_SET_BANDWIDTH, .set = 1, }, - [TV_SET_MODULATION] = { - .name = "TV_SET_MODULATION", - .cmd = TV_SET_MODULATION, + [DTV_SET_MODULATION] = { + .name = "DTV_SET_MODULATION", + .cmd = DTV_SET_MODULATION, .set = 1, }, - [TV_SET_INVERSION] = { - .name = "TV_SET_INVERSION", - .cmd = TV_SET_INVERSION, + [DTV_SET_INVERSION] = { + .name = "DTV_SET_INVERSION", + .cmd = DTV_SET_INVERSION, .set = 1, }, - [TV_SET_DISEQC_MASTER] = { - .name = "TV_SET_DISEQC_MASTER", - .cmd = TV_SET_DISEQC_MASTER, + [DTV_SET_DISEQC_MASTER] = { + .name = "DTV_SET_DISEQC_MASTER", + .cmd = DTV_SET_DISEQC_MASTER, .set = 1, .buffer = 1, }, - [TV_SET_SYMBOLRATE] = { - .name = "TV_SET_SYMBOLRATE", - .cmd = TV_SET_SYMBOLRATE, + [DTV_SET_SYMBOLRATE] = { + .name = "DTV_SET_SYMBOLRATE", + .cmd = DTV_SET_SYMBOLRATE, .set = 1, }, - [TV_SET_INNERFEC] = { - .name = "TV_SET_INNERFEC", - .cmd = TV_SET_INNERFEC, + [DTV_SET_INNERFEC] = { + .name = "DTV_SET_INNERFEC", + .cmd = DTV_SET_INNERFEC, .set = 1, }, - [TV_SET_VOLTAGE] = { - .name = "TV_SET_VOLTAGE", - .cmd = TV_SET_VOLTAGE, + [DTV_SET_VOLTAGE] = { + .name = "DTV_SET_VOLTAGE", + .cmd = DTV_SET_VOLTAGE, .set = 1, }, - [TV_SET_TONE] = { - .name = "TV_SET_TONE", - .cmd = TV_SET_TONE, + [DTV_SET_TONE] = { + .name = "DTV_SET_TONE", + .cmd = DTV_SET_TONE, .set = 1, }, - [TV_SET_PILOT] = { - .name = "TV_SET_PILOT", - .cmd = TV_SET_PILOT, + [DTV_SET_PILOT] = { + .name = "DTV_SET_PILOT", + .cmd = DTV_SET_PILOT, .set = 1, }, - [TV_SET_ROLLOFF] = { - .name = "TV_SET_ROLLOFF", - .cmd = TV_SET_ROLLOFF, + [DTV_SET_ROLLOFF] = { + .name = "DTV_SET_ROLLOFF", + .cmd = DTV_SET_ROLLOFF, .set = 1, }, - [TV_SET_DELIVERY_SYSTEM] = { - .name = "TV_SET_DELIVERY_SYSTEM", - .cmd = TV_SET_DELIVERY_SYSTEM, + [DTV_SET_DELIVERY_SYSTEM] = { + .name = "DTV_SET_DELIVERY_SYSTEM", + .cmd = DTV_SET_DELIVERY_SYSTEM, .set = 1, }, - [TV_SET_ISDB_SEGMENT_NUM] = { - .name = "TV_SET_ISDB_SEGMENT_NUM", - .cmd = TV_SET_ISDB_SEGMENT_NUM, + [DTV_SET_ISDB_SEGMENT_NUM] = { + .name = "DTV_SET_ISDB_SEGMENT_NUM", + .cmd = DTV_SET_ISDB_SEGMENT_NUM, .set = 1, }, - [TV_SET_ISDB_SEGMENT_WIDTH] = { - .name = "TV_SET_ISDB_SEGMENT_WIDTH", - .cmd = TV_SET_ISDB_SEGMENT_WIDTH, + [DTV_SET_ISDB_SEGMENT_WIDTH] = { + .name = "DTV_SET_ISDB_SEGMENT_WIDTH", + .cmd = DTV_SET_ISDB_SEGMENT_WIDTH, .set = 1, }, /* Get */ - [TV_GET_FREQUENCY] = { - .name = "TV_GET_FREQUENCY", - .cmd = TV_GET_FREQUENCY, + [DTV_GET_FREQUENCY] = { + .name = "DTV_GET_FREQUENCY", + .cmd = DTV_GET_FREQUENCY, .set = 0, }, - [TV_GET_BANDWIDTH] = { - .name = "TV_GET_BANDWIDTH", - .cmd = TV_GET_BANDWIDTH, + [DTV_GET_BANDWIDTH] = { + .name = "DTV_GET_BANDWIDTH", + .cmd = DTV_GET_BANDWIDTH, .set = 0, }, - [TV_GET_MODULATION] = { - .name = "TV_GET_MODULATION", - .cmd = TV_GET_MODULATION, + [DTV_GET_MODULATION] = { + .name = "DTV_GET_MODULATION", + .cmd = DTV_GET_MODULATION, .set = 0, }, - [TV_GET_INVERSION] = { - .name = "TV_GET_INVERSION", - .cmd = TV_GET_INVERSION, + [DTV_GET_INVERSION] = { + .name = "DTV_GET_INVERSION", + .cmd = DTV_GET_INVERSION, .set = 0, }, - [TV_GET_DISEQC_SLAVE_REPLY] = { - .name = "TV_GET_DISEQC_SLAVE_REPLY", - .cmd = TV_GET_DISEQC_SLAVE_REPLY, + [DTV_GET_DISEQC_SLAVE_REPLY] = { + .name = "DTV_GET_DISEQC_SLAVE_REPLY", + .cmd = DTV_GET_DISEQC_SLAVE_REPLY, .set = 0, .buffer = 1, }, - [TV_GET_SYMBOLRATE] = { - .name = "TV_GET_SYMBOLRATE", - .cmd = TV_GET_SYMBOLRATE, + [DTV_GET_SYMBOLRATE] = { + .name = "DTV_GET_SYMBOLRATE", + .cmd = DTV_GET_SYMBOLRATE, .set = 0, }, - [TV_GET_INNERFEC] = { - .name = "TV_GET_INNERFEC", - .cmd = TV_GET_INNERFEC, + [DTV_GET_INNERFEC] = { + .name = "DTV_GET_INNERFEC", + .cmd = DTV_GET_INNERFEC, .set = 0, }, - [TV_GET_VOLTAGE] = { - .name = "TV_GET_VOLTAGE", - .cmd = TV_GET_VOLTAGE, + [DTV_GET_VOLTAGE] = { + .name = "DTV_GET_VOLTAGE", + .cmd = DTV_GET_VOLTAGE, .set = 0, }, - [TV_GET_TONE] = { - .name = "TV_GET_TONE", - .cmd = TV_GET_TONE, + [DTV_GET_TONE] = { + .name = "DTV_GET_TONE", + .cmd = DTV_GET_TONE, .set = 0, }, - [TV_GET_PILOT] = { - .name = "TV_GET_PILOT", - .cmd = TV_GET_PILOT, + [DTV_GET_PILOT] = { + .name = "DTV_GET_PILOT", + .cmd = DTV_GET_PILOT, .set = 0, }, - [TV_GET_ROLLOFF] = { - .name = "TV_GET_ROLLOFF", - .cmd = TV_GET_ROLLOFF, + [DTV_GET_ROLLOFF] = { + .name = "DTV_GET_ROLLOFF", + .cmd = DTV_GET_ROLLOFF, .set = 0, }, - [TV_GET_DELIVERY_SYSTEM] = { - .name = "TV_GET_DELIVERY_SYSTEM", - .cmd = TV_GET_DELIVERY_SYSTEM, + [DTV_GET_DELIVERY_SYSTEM] = { + .name = "DTV_GET_DELIVERY_SYSTEM", + .cmd = DTV_GET_DELIVERY_SYSTEM, .set = 0, }, - [TV_GET_ISDB_SEGMENT_NUM] = { - .name = "TV_GET_ISDB_SEGMENT_NUM", - .cmd = TV_GET_ISDB_SEGMENT_NUM, + [DTV_GET_ISDB_SEGMENT_NUM] = { + .name = "DTV_GET_ISDB_SEGMENT_NUM", + .cmd = DTV_GET_ISDB_SEGMENT_NUM, .set = 0, }, - [TV_GET_ISDB_SEGMENT_WIDTH] = { - .name = "TV_GET_ISDB_SEGMENT_WIDTH", - .cmd = TV_GET_ISDB_SEGMENT_WIDTH, + [DTV_GET_ISDB_SEGMENT_WIDTH] = { + .name = "DTV_GET_ISDB_SEGMENT_WIDTH", + .cmd = DTV_GET_ISDB_SEGMENT_WIDTH, .set = 0, }, - [TV_GET_ISDB_LAYERA_FEC] = { - .name = "TV_GET_ISDB_LAYERA_FEC", - .cmd = TV_GET_ISDB_LAYERA_FEC, + [DTV_GET_ISDB_LAYERA_FEC] = { + .name = "DTV_GET_ISDB_LAYERA_FEC", + .cmd = DTV_GET_ISDB_LAYERA_FEC, .set = 0, }, - [TV_GET_ISDB_LAYERA_MODULATION] = { - .name = "TV_GET_ISDB_LAYERA_MODULATION", - .cmd = TV_GET_ISDB_LAYERA_MODULATION, + [DTV_GET_ISDB_LAYERA_MODULATION] = { + .name = "DTV_GET_ISDB_LAYERA_MODULATION", + .cmd = DTV_GET_ISDB_LAYERA_MODULATION, .set = 0, }, - [TV_GET_ISDB_LAYERA_SEGMENT_WIDTH] = { - .name = "TV_GET_ISDB_LAYERA_SEGMENT_WIDTH", - .cmd = TV_GET_ISDB_LAYERA_SEGMENT_WIDTH, + [DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH] = { + .name = "DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH", + .cmd = DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH, .set = 0, }, - [TV_GET_ISDB_LAYERB_FEC] = { - .name = "TV_GET_ISDB_LAYERB_FEC", - .cmd = TV_GET_ISDB_LAYERB_FEC, + [DTV_GET_ISDB_LAYERB_FEC] = { + .name = "DTV_GET_ISDB_LAYERB_FEC", + .cmd = DTV_GET_ISDB_LAYERB_FEC, .set = 0, }, - [TV_GET_ISDB_LAYERB_MODULATION] = { - .name = "TV_GET_ISDB_LAYERB_MODULATION", - .cmd = TV_GET_ISDB_LAYERB_MODULATION, + [DTV_GET_ISDB_LAYERB_MODULATION] = { + .name = "DTV_GET_ISDB_LAYERB_MODULATION", + .cmd = DTV_GET_ISDB_LAYERB_MODULATION, .set = 0, }, - [TV_GET_ISDB_LAYERB_SEGMENT_WIDTH] = { - .name = "TV_GET_ISDB_LAYERB_SEGMENT_WIDTH", - .cmd = TV_GET_ISDB_LAYERB_SEGMENT_WIDTH, + [DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH] = { + .name = "DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH", + .cmd = DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH, .set = 0, }, - [TV_GET_ISDB_LAYERC_FEC] = { - .name = "TV_GET_ISDB_LAYERC_FEC", - .cmd = TV_GET_ISDB_LAYERC_FEC, + [DTV_GET_ISDB_LAYERC_FEC] = { + .name = "DTV_GET_ISDB_LAYERC_FEC", + .cmd = DTV_GET_ISDB_LAYERC_FEC, .set = 0, }, - [TV_GET_ISDB_LAYERC_MODULATION] = { - .name = "TV_GET_ISDB_LAYERC_MODULATION", - .cmd = TV_GET_ISDB_LAYERC_MODULATION, + [DTV_GET_ISDB_LAYERC_MODULATION] = { + .name = "DTV_GET_ISDB_LAYERC_MODULATION", + .cmd = DTV_GET_ISDB_LAYERC_MODULATION, .set = 0, }, - [TV_GET_ISDB_LAYERC_SEGMENT_WIDTH] = { - .name = "TV_GET_ISDB_LAYERC_SEGMENT_WIDTH", - .cmd = TV_GET_ISDB_LAYERC_SEGMENT_WIDTH, + [DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH] = { + .name = "DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH", + .cmd = DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH, .set = 0, }, }; -void tv_property_dump(tv_property_t *tvp) +void dtv_property_dump(dtv_property_t *tvp) { int i; printk("%s() tvp.cmd = 0x%08x (%s)\n" ,__FUNCTION__ ,tvp->cmd - ,tv_cmds[ tvp->cmd ].name); + ,dtv_cmds[ tvp->cmd ].name); - if(tv_cmds[ tvp->cmd ].buffer) { + if(dtv_cmds[ tvp->cmd ].buffer) { printk("%s() tvp.u.buffer.len = 0x%02x\n" ,__FUNCTION__ @@ -1008,7 +1008,7 @@ int is_legacy_delivery_system(fe_delivery_system_t s) return 0; } -int tv_property_cache_submit(struct dvb_frontend *fe) +int dtv_property_cache_submit(struct dvb_frontend *fe) { /* We have to do one of two things: @@ -1036,7 +1036,7 @@ int tv_property_cache_submit(struct dvb_frontend *fe) int r; - struct tv_frontend_properties *c = &fe->tv_property_cache; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_frontend_parameters p; @@ -1115,7 +1115,7 @@ int tv_property_cache_submit(struct dvb_frontend *fe) case _16APSK: case NBC_QPSK: /* Just post a notification to the demod driver and let it pull - * the specific values it wants from its tv_property_cache. + * the specific values it wants from its dtv_property_cache. * It can decide how best to use those parameters. * IOCTL will call set_frontend (by default) due to zigzag * support etc. @@ -1161,147 +1161,147 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, unsigned int cmd, void *parg); -int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp, +int dtv_property_process(struct dvb_frontend *fe, dtv_property_t *tvp, struct inode *inode, struct file *file) { int r = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; printk("%s()\n", __FUNCTION__); - tv_property_dump(tvp); + dtv_property_dump(tvp); switch(tvp->cmd) { - case TV_SEQ_START: - case TV_SEQ_TERMINATE: + case DTV_SEQ_START: + case DTV_SEQ_TERMINATE: /* Reset a cache of data specific to the frontend here. This does * not effect hardware. */ printk("%s() Flushing property cache\n", __FUNCTION__); - memset(&fe->tv_property_cache, 0, sizeof(struct tv_frontend_properties)); - fe->tv_property_cache.state = TV_SEQ_START; - fe->tv_property_cache.delivery_system = SYS_UNDEFINED; + memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties)); + fe->dtv_property_cache.state = DTV_SEQ_START; + fe->dtv_property_cache.delivery_system = SYS_UNDEFINED; break; - case TV_SEQ_COMPLETE: + case DTV_SEQ_COMPLETE: /* interpret the cache of data, build either a traditional frontend * tunerequest and submit it to a subset of the ioctl handler, * or, call a new undefined method on the frontend to deal with * all new tune requests. */ - fe->tv_property_cache.state = TV_SEQ_COMPLETE; + fe->dtv_property_cache.state = DTV_SEQ_COMPLETE; printk("%s() Finalised property cache\n", __FUNCTION__); - r |= tv_property_cache_submit(fe); + r |= dtv_property_cache_submit(fe); r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; - case TV_SET_FREQUENCY: - fe->tv_property_cache.frequency = tvp->u.data; + case DTV_SET_FREQUENCY: + fe->dtv_property_cache.frequency = tvp->u.data; break; - case TV_GET_FREQUENCY: - tvp->u.data = fe->tv_property_cache.frequency; + case DTV_GET_FREQUENCY: + tvp->u.data = fe->dtv_property_cache.frequency; break; - case TV_SET_MODULATION: - fe->tv_property_cache.modulation = tvp->u.data; + case DTV_SET_MODULATION: + fe->dtv_property_cache.modulation = tvp->u.data; break; - case TV_GET_MODULATION: - tvp->u.data = fe->tv_property_cache.modulation; + case DTV_GET_MODULATION: + tvp->u.data = fe->dtv_property_cache.modulation; break; - case TV_SET_BANDWIDTH: - fe->tv_property_cache.bandwidth = tvp->u.data; + case DTV_SET_BANDWIDTH: + fe->dtv_property_cache.bandwidth = tvp->u.data; break; - case TV_GET_BANDWIDTH: - tvp->u.data = fe->tv_property_cache.bandwidth; + case DTV_GET_BANDWIDTH: + tvp->u.data = fe->dtv_property_cache.bandwidth; break; - case TV_SET_INVERSION: - fe->tv_property_cache.inversion = tvp->u.data; + case DTV_SET_INVERSION: + fe->dtv_property_cache.inversion = tvp->u.data; break; - case TV_GET_INVERSION: - tvp->u.data = fe->tv_property_cache.inversion; + case DTV_GET_INVERSION: + tvp->u.data = fe->dtv_property_cache.inversion; break; - case TV_SET_SYMBOLRATE: - fe->tv_property_cache.symbol_rate = tvp->u.data; + case DTV_SET_SYMBOLRATE: + fe->dtv_property_cache.symbol_rate = tvp->u.data; break; - case TV_GET_SYMBOLRATE: - tvp->u.data = fe->tv_property_cache.symbol_rate; + case DTV_GET_SYMBOLRATE: + tvp->u.data = fe->dtv_property_cache.symbol_rate; break; - case TV_SET_INNERFEC: - fe->tv_property_cache.fec_inner = tvp->u.data; + case DTV_SET_INNERFEC: + fe->dtv_property_cache.fec_inner = tvp->u.data; break; - case TV_GET_INNERFEC: - tvp->u.data = fe->tv_property_cache.fec_inner; + case DTV_GET_INNERFEC: + tvp->u.data = fe->dtv_property_cache.fec_inner; break; - case TV_SET_PILOT: - fe->tv_property_cache.pilot = tvp->u.data; + case DTV_SET_PILOT: + fe->dtv_property_cache.pilot = tvp->u.data; break; - case TV_GET_PILOT: - tvp->u.data = fe->tv_property_cache.pilot; + case DTV_GET_PILOT: + tvp->u.data = fe->dtv_property_cache.pilot; break; - case TV_SET_ROLLOFF: - fe->tv_property_cache.rolloff = tvp->u.data; + case DTV_SET_ROLLOFF: + fe->dtv_property_cache.rolloff = tvp->u.data; break; - case TV_GET_ROLLOFF: - tvp->u.data = fe->tv_property_cache.rolloff; + case DTV_GET_ROLLOFF: + tvp->u.data = fe->dtv_property_cache.rolloff; break; - case TV_SET_DELIVERY_SYSTEM: - fe->tv_property_cache.delivery_system = tvp->u.data; + case DTV_SET_DELIVERY_SYSTEM: + fe->dtv_property_cache.delivery_system = tvp->u.data; break; - case TV_GET_DELIVERY_SYSTEM: - tvp->u.data = fe->tv_property_cache.delivery_system; + case DTV_GET_DELIVERY_SYSTEM: + tvp->u.data = fe->dtv_property_cache.delivery_system; break; /* ISDB-T Support here */ - case TV_SET_ISDB_SEGMENT_NUM: - fe->tv_property_cache.isdb_segment_num = tvp->u.data; + case DTV_SET_ISDB_SEGMENT_NUM: + fe->dtv_property_cache.isdb_segment_num = tvp->u.data; break; - case TV_GET_ISDB_SEGMENT_NUM: - tvp->u.data = fe->tv_property_cache.isdb_segment_num; + case DTV_GET_ISDB_SEGMENT_NUM: + tvp->u.data = fe->dtv_property_cache.isdb_segment_num; break; - case TV_SET_ISDB_SEGMENT_WIDTH: - fe->tv_property_cache.isdb_segment_width = tvp->u.data; + case DTV_SET_ISDB_SEGMENT_WIDTH: + fe->dtv_property_cache.isdb_segment_width = tvp->u.data; break; - case TV_GET_ISDB_SEGMENT_WIDTH: - tvp->u.data = fe->tv_property_cache.isdb_segment_width; + case DTV_GET_ISDB_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_segment_width; break; - case TV_GET_ISDB_LAYERA_FEC: - tvp->u.data = fe->tv_property_cache.isdb_layera_fec; + case DTV_GET_ISDB_LAYERA_FEC: + tvp->u.data = fe->dtv_property_cache.isdb_layera_fec; break; - case TV_GET_ISDB_LAYERA_MODULATION: - tvp->u.data = fe->tv_property_cache.isdb_layera_modulation; + case DTV_GET_ISDB_LAYERA_MODULATION: + tvp->u.data = fe->dtv_property_cache.isdb_layera_modulation; break; - case TV_GET_ISDB_LAYERA_SEGMENT_WIDTH: - tvp->u.data = fe->tv_property_cache.isdb_layera_segment_width; + case DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_layera_segment_width; break; - case TV_GET_ISDB_LAYERB_FEC: - tvp->u.data = fe->tv_property_cache.isdb_layerb_fec; + case DTV_GET_ISDB_LAYERB_FEC: + tvp->u.data = fe->dtv_property_cache.isdb_layerb_fec; break; - case TV_GET_ISDB_LAYERB_MODULATION: - tvp->u.data = fe->tv_property_cache.isdb_layerb_modulation; + case DTV_GET_ISDB_LAYERB_MODULATION: + tvp->u.data = fe->dtv_property_cache.isdb_layerb_modulation; break; - case TV_GET_ISDB_LAYERB_SEGMENT_WIDTH: - tvp->u.data = fe->tv_property_cache.isdb_layerb_segment_width; + case DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_layerb_segment_width; break; - case TV_GET_ISDB_LAYERC_FEC: - tvp->u.data = fe->tv_property_cache.isdb_layerc_fec; + case DTV_GET_ISDB_LAYERC_FEC: + tvp->u.data = fe->dtv_property_cache.isdb_layerc_fec; break; - case TV_GET_ISDB_LAYERC_MODULATION: - tvp->u.data = fe->tv_property_cache.isdb_layerc_modulation; + case DTV_GET_ISDB_LAYERC_MODULATION: + tvp->u.data = fe->dtv_property_cache.isdb_layerc_modulation; break; - case TV_GET_ISDB_LAYERC_SEGMENT_WIDTH: - tvp->u.data = fe->tv_property_cache.isdb_layerc_segment_width; + case DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_layerc_segment_width; break; - case TV_SET_VOLTAGE: - fe->tv_property_cache.voltage = tvp->u.data; + case DTV_SET_VOLTAGE: + fe->dtv_property_cache.voltage = tvp->u.data; r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE, - (void *)fe->tv_property_cache.voltage); + (void *)fe->dtv_property_cache.voltage); break; - case TV_GET_VOLTAGE: - tvp->u.data = fe->tv_property_cache.voltage; + case DTV_GET_VOLTAGE: + tvp->u.data = fe->dtv_property_cache.voltage; break; - case TV_SET_TONE: - fe->tv_property_cache.sectone = tvp->u.data; + case DTV_SET_TONE: + fe->dtv_property_cache.sectone = tvp->u.data; r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE, - (void *)fe->tv_property_cache.sectone); + (void *)fe->dtv_property_cache.sectone); break; - case TV_GET_TONE: - tvp->u.data = fe->tv_property_cache.sectone; + case DTV_GET_TONE: + tvp->u.data = fe->dtv_property_cache.sectone; break; } @@ -1344,7 +1344,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; int err = -EOPNOTSUPP; - tv_property_t *tvp; + dtv_property_t *tvp; dprintk("%s\n", __func__); @@ -1355,14 +1355,14 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, /* TODO: ioctl userdata out of range check here */ tvp = parg; - while(tvp->cmd != TV_SEQ_UNDEFINED) { - tv_property_process(fe, tvp, inode, file); - if( (tvp->cmd == TV_SEQ_TERMINATE) || (tvp->cmd == TV_SEQ_COMPLETE) ) + while(tvp->cmd != DTV_SEQ_UNDEFINED) { + dtv_property_process(fe, tvp, inode, file); + if( (tvp->cmd == DTV_SEQ_TERMINATE) || (tvp->cmd == DTV_SEQ_COMPLETE) ) break; tvp++; } - if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) { + if(fe->dtv_property_cache.state == DTV_SEQ_COMPLETE) { printk("%s() Property cache is full, tuning\n", __FUNCTION__); } err = 0; @@ -1545,7 +1545,7 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; - if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) { + if(fe->dtv_property_cache.state == DTV_SEQ_COMPLETE) { if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) { err = -EINVAL; break; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 61d53ee70f2a..f376f281cde2 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -170,8 +170,8 @@ struct dvb_frontend_ops { struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; - int (*set_property)(struct dvb_frontend* fe, tv_property_t* tvp); - int (*get_property)(struct dvb_frontend* fe, tv_property_t* tvp); + int (*set_property)(struct dvb_frontend* fe, dtv_property_t* tvp); + int (*get_property)(struct dvb_frontend* fe, dtv_property_t* tvp); int (*set_params)(struct dvb_frontend* fe); }; @@ -186,7 +186,7 @@ struct dvb_fe_events { struct mutex mtx; }; -struct tv_frontend_properties { +struct dtv_frontend_properties { /* Cache State */ u32 state; @@ -233,7 +233,7 @@ struct dvb_frontend { void *frontend_priv; void *sec_priv; void *analog_demod_priv; - struct tv_frontend_properties tv_property_cache; + struct dtv_frontend_properties dtv_property_cache; }; extern int dvb_register_frontend(struct dvb_adapter *dvb, diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 666a0d89e83c..f150fa24ff9f 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -776,7 +776,7 @@ error: static int cx24116_get_params(struct dvb_frontend* fe) { struct cx24116_state *state = fe->demodulator_priv; - struct tv_frontend_properties *cache = &fe->tv_property_cache; + struct dtv_frontend_properties *cache = &fe->dtv_property_cache; dprintk("%s()\n",__func__); @@ -796,7 +796,7 @@ static int cx24116_initfe(struct dvb_frontend* fe) return cx24116_diseqc_init(fe); } -static int cx24116_set_property(struct dvb_frontend *fe, tv_property_t* tvp) +static int cx24116_set_property(struct dvb_frontend *fe, dtv_property_t* tvp) { dprintk("%s(..)\n", __func__); return 0; @@ -814,7 +814,7 @@ static int cx24116_set_params(struct dvb_frontend *fe) static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct cx24116_state *state = fe->demodulator_priv; - struct tv_frontend_properties *c = &fe->tv_property_cache; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24116_cmd cmd; fe_status_t tunerstat; int ret, above30msps; -- cgit v1.2.1 From e7fee0f3aa111d42cdcfc1470cfdc21dde0cdbe2 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 11 Sep 2008 10:23:01 -0300 Subject: V4L/DVB (8996): S2API: typedefs replaced, _SEQ_'s removed, fixed 16 command arrays replaced After discussion the following changes were made: 1. Removed the typedefs in frontend.h, use structures. 2. In the frontend.h, remove the 16 command limit on the API and switch to a flexible variable length API. For practical reasons a #define limits this to 64, this should be discussed. 3. Changed dvb-core ioctl handing to deal with variable sequences of commands. tune-v0.0.3.c is required to use this API, it contains the interface changes. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 83 ++++++++++++++++--------------- drivers/media/dvb/dvb-core/dvb_frontend.h | 4 +- drivers/media/dvb/frontends/cx24116.c | 2 +- 3 files changed, 46 insertions(+), 43 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 9c4761506d2d..763da968236f 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -756,29 +756,14 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe, } struct dtv_cmds_h dtv_cmds[] = { - [DTV_SEQ_UNDEFINED] = { - .name = "DTV_SEQ_UNDEFINED", - .cmd = DTV_SEQ_UNDEFINED, + [DTV_TUNE] = { + .name = "DTV_TUNE", + .cmd = DTV_TUNE, .set = 1, }, - [DTV_SEQ_START] = { - .name = "DTV_SEQ_START", - .cmd = DTV_SEQ_START, - .set = 1, - }, - [DTV_SEQ_CONTINUE] = { - .name = "DTV_SEQ_CONTINUE", - .cmd = DTV_SEQ_CONTINUE, - .set = 1, - }, - [DTV_SEQ_COMPLETE] = { - .name = "DTV_SEQ_COMPLETE", - .cmd = DTV_SEQ_COMPLETE, - .set = 1, - }, - [DTV_SEQ_TERMINATE] = { - .name = "DTV_SEQ_TERMINATE", - .cmd = DTV_SEQ_TERMINATE, + [DTV_CLEAR] = { + .name = "DTV_CLEAR", + .cmd = DTV_CLEAR, .set = 1, }, @@ -974,7 +959,7 @@ struct dtv_cmds_h dtv_cmds[] = { }, }; -void dtv_property_dump(dtv_property_t *tvp) +void dtv_property_dump(struct dtv_property *tvp) { int i; @@ -1044,6 +1029,7 @@ int dtv_property_cache_submit(struct dvb_frontend *fe) /* For legacy delivery systems we don't need the delivery_system to be specified */ if(is_legacy_delivery_system(c->delivery_system)) { + printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation); switch(c->modulation) { case QPSK: printk("%s() Preparing QPSK req\n", __FUNCTION__); @@ -1161,7 +1147,7 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, unsigned int cmd, void *parg); -int dtv_property_process(struct dvb_frontend *fe, dtv_property_t *tvp, +int dtv_property_process(struct dvb_frontend *fe, struct dtv_property *tvp, struct inode *inode, struct file *file) { int r = 0; @@ -1170,23 +1156,22 @@ int dtv_property_process(struct dvb_frontend *fe, dtv_property_t *tvp, dtv_property_dump(tvp); switch(tvp->cmd) { - case DTV_SEQ_START: - case DTV_SEQ_TERMINATE: + case DTV_CLEAR: /* Reset a cache of data specific to the frontend here. This does * not effect hardware. */ printk("%s() Flushing property cache\n", __FUNCTION__); memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties)); - fe->dtv_property_cache.state = DTV_SEQ_START; + fe->dtv_property_cache.state = tvp->cmd; fe->dtv_property_cache.delivery_system = SYS_UNDEFINED; break; - case DTV_SEQ_COMPLETE: + case DTV_TUNE: /* interpret the cache of data, build either a traditional frontend * tunerequest and submit it to a subset of the ioctl handler, * or, call a new undefined method on the frontend to deal with * all new tune requests. */ - fe->dtv_property_cache.state = DTV_SEQ_COMPLETE; + fe->dtv_property_cache.state = tvp->cmd; printk("%s() Finalised property cache\n", __FUNCTION__); r |= dtv_property_cache_submit(fe); r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, @@ -1344,30 +1329,48 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; int err = -EOPNOTSUPP; - dtv_property_t *tvp; + + struct dtv_properties *tvps = NULL; + struct dtv_property *tvp = NULL; + int i; dprintk("%s\n", __func__); if(cmd == FE_SET_PROPERTY) { printk("%s() FE_SET_PROPERTY\n", __FUNCTION__); - /* TODO: basic property validation here */ + tvps = (struct dtv_properties __user *)parg; - /* TODO: ioctl userdata out of range check here */ - tvp = parg; - while(tvp->cmd != DTV_SEQ_UNDEFINED) { - dtv_property_process(fe, tvp, inode, file); - if( (tvp->cmd == DTV_SEQ_TERMINATE) || (tvp->cmd == DTV_SEQ_COMPLETE) ) - break; - tvp++; + printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num); + printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props); + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if (tvps->num > DTV_IOCTL_MAX_MSGS) + return -EINVAL; + + tvp = (struct dtv_property *) kmalloc(tvps->num * + sizeof(struct dtv_property), GFP_KERNEL); + if (!tvp) { + err = -ENOMEM; + goto out; } - if(fe->dtv_property_cache.state == DTV_SEQ_COMPLETE) { + if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + for (i = 0; i < tvps->num; i++) + dtv_property_process(fe, tvp + i, inode, file); + + if(fe->dtv_property_cache.state == DTV_TUNE) { printk("%s() Property cache is full, tuning\n", __FUNCTION__); } err = 0; } - +out: + kfree(tvp); return err; } @@ -1545,7 +1548,7 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; - if(fe->dtv_property_cache.state == DTV_SEQ_COMPLETE) { + if(fe->dtv_property_cache.state == DTV_TUNE) { if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) { err = -EINVAL; break; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f376f281cde2..85d30201a695 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -170,8 +170,8 @@ struct dvb_frontend_ops { struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; - int (*set_property)(struct dvb_frontend* fe, dtv_property_t* tvp); - int (*get_property)(struct dvb_frontend* fe, dtv_property_t* tvp); + int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); + int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); int (*set_params)(struct dvb_frontend* fe); }; diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index f150fa24ff9f..9f93930a2594 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -796,7 +796,7 @@ static int cx24116_initfe(struct dvb_frontend* fe) return cx24116_diseqc_init(fe); } -static int cx24116_set_property(struct dvb_frontend *fe, dtv_property_t* tvp) +static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp) { dprintk("%s(..)\n", __func__); return 0; -- cgit v1.2.1 From 177b868d93861077619261dcecd0147d1c033026 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 11 Sep 2008 10:34:19 -0300 Subject: V4L/DVB (8997): S2API: Cleanup SYMBOLRATE, INNERFEC -> SYMBOL_RATE, INNER_FEC This is now consistent with the existing API. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 763da968236f..ce1de403e99e 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -794,14 +794,14 @@ struct dtv_cmds_h dtv_cmds[] = { .set = 1, .buffer = 1, }, - [DTV_SET_SYMBOLRATE] = { - .name = "DTV_SET_SYMBOLRATE", - .cmd = DTV_SET_SYMBOLRATE, + [DTV_SET_SYMBOL_RATE] = { + .name = "DTV_SET_SYMBOL_RATE", + .cmd = DTV_SET_SYMBOL_RATE, .set = 1, }, - [DTV_SET_INNERFEC] = { - .name = "DTV_SET_INNERFEC", - .cmd = DTV_SET_INNERFEC, + [DTV_SET_INNER_FEC] = { + .name = "DTV_SET_INNER_FEC", + .cmd = DTV_SET_INNER_FEC, .set = 1, }, [DTV_SET_VOLTAGE] = { @@ -867,14 +867,14 @@ struct dtv_cmds_h dtv_cmds[] = { .set = 0, .buffer = 1, }, - [DTV_GET_SYMBOLRATE] = { - .name = "DTV_GET_SYMBOLRATE", - .cmd = DTV_GET_SYMBOLRATE, + [DTV_GET_SYMBOL_RATE] = { + .name = "DTV_GET_SYMBOL_RATE", + .cmd = DTV_GET_SYMBOL_RATE, .set = 0, }, - [DTV_GET_INNERFEC] = { - .name = "DTV_GET_INNERFEC", - .cmd = DTV_GET_INNERFEC, + [DTV_GET_INNER_FEC] = { + .name = "DTV_GET_INNER_FEC", + .cmd = DTV_GET_INNER_FEC, .set = 0, }, [DTV_GET_VOLTAGE] = { @@ -1201,16 +1201,16 @@ int dtv_property_process(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_GET_INVERSION: tvp->u.data = fe->dtv_property_cache.inversion; break; - case DTV_SET_SYMBOLRATE: + case DTV_SET_SYMBOL_RATE: fe->dtv_property_cache.symbol_rate = tvp->u.data; break; - case DTV_GET_SYMBOLRATE: + case DTV_GET_SYMBOL_RATE: tvp->u.data = fe->dtv_property_cache.symbol_rate; break; - case DTV_SET_INNERFEC: + case DTV_SET_INNER_FEC: fe->dtv_property_cache.fec_inner = tvp->u.data; break; - case DTV_GET_INNERFEC: + case DTV_GET_INNER_FEC: tvp->u.data = fe->dtv_property_cache.fec_inner; break; case DTV_SET_PILOT: -- cgit v1.2.1 From ee33c525c4d09756156cd4c18e6586da900eb310 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 11 Sep 2008 23:52:32 -0300 Subject: V4L/DVB (8999): S2API: Reduce demod driver complexity by using a cache sync For demod drivers, we want a single tuning function (set_frontend) to have access to the properly constructed dvb_frontend_parameters structure, or the cache values - regardless of whether the legacy or new API is being used. This cuts down on redundant code in the demod drivers and ensures the tuning parameters are consistent regardless of the API entry type. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index ce1de403e99e..7e9cd7921314 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -993,6 +993,42 @@ int is_legacy_delivery_system(fe_delivery_system_t s) return 0; } +/* Synchronise the legacy tuning parameters into the cache, so that demodulator + * drivers can use a single set_frontend tuning function, regardless of whether + * it's being used for the legacy or new API, reducing code and complexity. + */ +void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + c->frequency = p->frequency; + c->inversion = p->inversion; + + switch (fe->ops.info.type) { + case FE_QPSK: + c->symbol_rate = p->u.qpsk.symbol_rate; + c->fec_inner = p->u.qpsk.fec_inner; + break; + case FE_QAM: + c->symbol_rate = p->u.qam.symbol_rate; + c->fec_inner = p->u.qam.fec_inner; + c->modulation = p->u.qam.modulation; + break; + case FE_OFDM: + c->bandwidth = p->u.ofdm.bandwidth; + c->code_rate_HP = p->u.ofdm.code_rate_HP; + c->code_rate_LP = p->u.ofdm.code_rate_LP; + c->modulation = p->u.ofdm.constellation; + c->transmission_mode = p->u.ofdm.transmission_mode; + c->guard_interval = p->u.ofdm.guard_interval; + c->hierarchy = p->u.ofdm.hierarchy_information; + break; + case FE_ATSC: + c->modulation = p->u.vsb.modulation; + break; + } +} + int dtv_property_cache_submit(struct dvb_frontend *fe) { @@ -1548,6 +1584,8 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; + dtv_property_cache_sync(fe, &fepriv->parameters); + if(fe->dtv_property_cache.state == DTV_TUNE) { if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) { err = -EINVAL; -- cgit v1.2.1 From d5748f1079c01c8861b05e0de7c4cda271532cb9 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 12 Sep 2008 00:27:13 -0300 Subject: V4L/DVB (9000): S2API: Cleanup code that prepares tuning structures. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 219 +++++++++++++----------------- 1 file changed, 91 insertions(+), 128 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 7e9cd7921314..2aaaca620033 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1001,6 +1001,8 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame { struct dtv_frontend_properties *c = &fe->dtv_property_cache; + printk("%s()\n", __FUNCTION__); + c->frequency = p->frequency; c->inversion = p->inversion; @@ -1029,153 +1031,114 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame } } -int dtv_property_cache_submit(struct dvb_frontend *fe) +/* Ensure the cached values are set correctly in the frontend + * legacy tuning structures, for the advanced tuning API. + */ +void dtv_property_legacy_params_sync(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_frontend_parameters *p = &fepriv->parameters; - /* We have to do one of two things: - * To support legacy devices using the new API we take values from - * the tv_cache and generate a legacy truning structure. - * - * Or, - * - * To support advanced tuning devices with the new API we - * notify the new advance driver type that a tuning operation is required - * and let it pull values from the cache as is, we don't need to - * pass structures. - * - * We'll use the modulation type to assess how this is handled. as the API - * progresses we'll probably want to have a flag in dvb_frontend_ops - * to allow the frontend driver to dictate how it likes to be tuned. - * - * Because of how this is attached to the ioctl handler for legacy support, - * it's important to return an appropriate result code with atleast the following - * three meanings: - * < 0 = processing error - * 0 = lecagy ioctl handler to submit a traditional set_frontend() call. - * 1 = lecagy ioctl handler should NOT submit a traditional set_frontend() call. - */ + printk("%s()\n", __FUNCTION__); - int r; + p->frequency = c->frequency; + p->inversion = c->inversion; + switch (fe->ops.info.type) { + case FE_QPSK: + printk("%s() Preparing QPSK req\n", __FUNCTION__); + p->u.qpsk.symbol_rate = c->symbol_rate; + p->u.qpsk.fec_inner = c->fec_inner; + break; + case FE_QAM: + printk("%s() Preparing QAM req\n", __FUNCTION__); + p->u.qam.symbol_rate = c->symbol_rate; + p->u.qam.fec_inner = c->fec_inner; + p->u.qam.modulation = c->modulation; + break; + case FE_OFDM: + printk("%s() Preparing OFDM req\n", __FUNCTION__); + p->u.ofdm.bandwidth = c->bandwidth; + p->u.ofdm.code_rate_HP = c->code_rate_HP; + p->u.ofdm.code_rate_LP = c->code_rate_LP; + p->u.ofdm.constellation = c->modulation; + p->u.ofdm.transmission_mode = c->transmission_mode; + p->u.ofdm.guard_interval = c->guard_interval; + p->u.ofdm.hierarchy_information = c->hierarchy; + break; + case FE_ATSC: + printk("%s() Preparing VSB req\n", __FUNCTION__); + p->u.vsb.modulation = c->modulation; + break; + } +} + +/* Ensure the cached values are set correctly in the frontend + * legacy tuning structures, for the legacy tuning API. + */ +void dtv_property_adv_params_sync(struct dvb_frontend *fe) +{ struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_frontend_parameters p; + struct dvb_frontend_parameters *p = &fepriv->parameters; printk("%s()\n", __FUNCTION__); - /* For legacy delivery systems we don't need the delivery_system to be specified */ - if(is_legacy_delivery_system(c->delivery_system)) { - printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation); - switch(c->modulation) { - case QPSK: - printk("%s() Preparing QPSK req\n", __FUNCTION__); - p.frequency = c->frequency; - p.inversion = c->inversion; - p.u.qpsk.symbol_rate = c->symbol_rate; - p.u.qpsk.fec_inner = c->fec_inner; - memcpy(&fepriv->parameters, &p, - sizeof (struct dvb_frontend_parameters)); + p->frequency = c->frequency; + p->inversion = c->inversion; - /* Call the traditional tuning mechanisms. */ + switch(c->modulation) { + case _8PSK: + case _16APSK: + case NBC_QPSK: + p->u.qpsk.symbol_rate = c->symbol_rate; + p->u.qpsk.fec_inner = c->fec_inner; + break; + default: + break; + } - r = 0; - break; - case QAM_16: - case QAM_32: - case QAM_64: - case QAM_128: - case QAM_256: - case QAM_AUTO: - printk("%s() Preparing QAM req\n", __FUNCTION__); - p.frequency = c->frequency; - p.inversion = c->inversion; - p.u.qam.symbol_rate = c->symbol_rate; - p.u.vsb.modulation = c->modulation; - printk("%s() frequency = %d\n", __FUNCTION__, p.frequency); - printk("%s() QAM = %d\n", __FUNCTION__, p.u.vsb.modulation); - memcpy(&fepriv->parameters, &p, - sizeof (struct dvb_frontend_parameters)); + if(c->delivery_system == SYS_ISDBT) { + /* Fake out a generic DVB-T request so we pass validation in the ioctl */ + p->frequency = c->frequency; + p->inversion = INVERSION_AUTO; + p->u.ofdm.constellation = QAM_AUTO; + p->u.ofdm.code_rate_HP = FEC_AUTO; + p->u.ofdm.code_rate_LP = FEC_AUTO; + p->u.ofdm.bandwidth = BANDWIDTH_AUTO; + p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; + } +} - /* At this point we're fully formed for backwards - * compatability and we need to return this - * via the ioctl handler as SET_FRONTEND (arg). - * We've already patched the new values into the - * frontends tuning structures so the ioctl code just - * continues as if a legacy tune structure was passed - * from userspace. - */ +void dtv_property_cache_submit(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; - r = 0; - break; - case VSB_8: - case VSB_16: - printk("%s() Preparing VSB req\n", __FUNCTION__); - p.frequency = c->frequency; - p.u.vsb.modulation = c->modulation; - memcpy(&fepriv->parameters, &p, - sizeof (struct dvb_frontend_parameters)); + printk("%s()\n", __FUNCTION__); - /* Call the traditional tuning mechanisms. */ + /* For legacy delivery systems we don't need the delivery_system to + * be specified, but we populate the older structures from the cache + * so we can call set_frontend on older drivers. + */ + if(is_legacy_delivery_system(c->delivery_system)) { + + printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation); + dtv_property_legacy_params_sync(fe); - r = 0; - break; - /* TODO: Add any missing modulation types */ - default: - r = -1; - } } else { + printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation); + /* For advanced delivery systems / modulation types ... * we seed the lecacy dvb_frontend_parameters structure * so that the sanity checking code later in the IOCTL processing * can validate our basic frequency ranges, symbolrates, modulation * etc. */ - r = -1; - - switch(c->modulation) { - case _8PSK: - case _16APSK: - case NBC_QPSK: - /* Just post a notification to the demod driver and let it pull - * the specific values it wants from its dtv_property_cache. - * It can decide how best to use those parameters. - * IOCTL will call set_frontend (by default) due to zigzag - * support etc. - */ - if (fe->ops.set_params) - r = fe->ops.set_params(fe); - - p.frequency = c->frequency; - p.inversion = c->inversion; - p.u.qpsk.symbol_rate = c->symbol_rate; - p.u.qpsk.fec_inner = c->fec_inner; - memcpy(&fepriv->parameters, &p, - sizeof (struct dvb_frontend_parameters)); - - r = 0; - break; - default: - r = -1; - } - - if(c->delivery_system == SYS_ISDBT) { - /* Fake out a generic DVB-T request so we pass validation in the ioctl */ - p.frequency = c->frequency; - p.inversion = INVERSION_AUTO; - p.u.ofdm.constellation = QAM_AUTO; - p.u.ofdm.code_rate_HP = FEC_AUTO; - p.u.ofdm.code_rate_LP = FEC_AUTO; - p.u.ofdm.bandwidth = BANDWIDTH_AUTO; - p.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - p.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p.u.ofdm.hierarchy_information = HIERARCHY_AUTO; - memcpy(&fepriv->parameters, &p, - sizeof (struct dvb_frontend_parameters)); - - r = 0; - } + dtv_property_adv_params_sync(fe); } - return r; } static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, @@ -1203,13 +1166,13 @@ int dtv_property_process(struct dvb_frontend *fe, struct dtv_property *tvp, break; case DTV_TUNE: /* interpret the cache of data, build either a traditional frontend - * tunerequest and submit it to a subset of the ioctl handler, - * or, call a new undefined method on the frontend to deal with - * all new tune requests. + * tunerequest so we can pass validation in the FE_SET_FRONTEND + * ioctl. */ fe->dtv_property_cache.state = tvp->cmd; printk("%s() Finalised property cache\n", __FUNCTION__); - r |= dtv_property_cache_submit(fe); + dtv_property_cache_submit(fe); + r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; -- cgit v1.2.1 From d7c1500183bc138b634377ed90c046e722b887d8 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 12 Sep 2008 00:33:04 -0300 Subject: V4L/DVB (9001): S2API: ISDBT_SEGMENT_NUM -> ISDBT_SEGMENT_IDX Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 20 ++++++++++---------- drivers/media/dvb/dvb-core/dvb_frontend.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2aaaca620033..dc76f9935c81 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -829,9 +829,9 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_SET_DELIVERY_SYSTEM, .set = 1, }, - [DTV_SET_ISDB_SEGMENT_NUM] = { - .name = "DTV_SET_ISDB_SEGMENT_NUM", - .cmd = DTV_SET_ISDB_SEGMENT_NUM, + [DTV_SET_ISDB_SEGMENT_IDX] = { + .name = "DTV_SET_ISDB_SEGMENT_IDX", + .cmd = DTV_SET_ISDB_SEGMENT_IDX, .set = 1, }, [DTV_SET_ISDB_SEGMENT_WIDTH] = { @@ -902,9 +902,9 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_GET_DELIVERY_SYSTEM, .set = 0, }, - [DTV_GET_ISDB_SEGMENT_NUM] = { - .name = "DTV_GET_ISDB_SEGMENT_NUM", - .cmd = DTV_GET_ISDB_SEGMENT_NUM, + [DTV_GET_ISDB_SEGMENT_IDX] = { + .name = "DTV_GET_ISDB_SEGMENT_IDX", + .cmd = DTV_GET_ISDB_SEGMENT_IDX, .set = 0, }, [DTV_GET_ISDB_SEGMENT_WIDTH] = { @@ -1232,11 +1232,11 @@ int dtv_property_process(struct dvb_frontend *fe, struct dtv_property *tvp, break; /* ISDB-T Support here */ - case DTV_SET_ISDB_SEGMENT_NUM: - fe->dtv_property_cache.isdb_segment_num = tvp->u.data; + case DTV_SET_ISDB_SEGMENT_IDX: + fe->dtv_property_cache.isdb_segment_idx = tvp->u.data; break; - case DTV_GET_ISDB_SEGMENT_NUM: - tvp->u.data = fe->dtv_property_cache.isdb_segment_num; + case DTV_GET_ISDB_SEGMENT_IDX: + tvp->u.data = fe->dtv_property_cache.isdb_segment_idx; break; case DTV_SET_ISDB_SEGMENT_WIDTH: fe->dtv_property_cache.isdb_segment_width = tvp->u.data; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 85d30201a695..1c2090966baf 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -212,7 +212,7 @@ struct dtv_frontend_properties { fe_delivery_system_t delivery_system; /* ISDB-T specifics */ - u32 isdb_segment_num; + u32 isdb_segment_idx; u32 isdb_segment_width; fe_code_rate_t isdb_layera_fec; fe_modulation_t isdb_layera_modulation; -- cgit v1.2.1 From 80a773c9bcc6f67944e186de3d2ab8b582889bc8 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 12 Sep 2008 00:53:50 -0300 Subject: V4L/DVB (9002): S2API: Ensure cache->delivery_system is set at all times. This helps complex demods which support different modulation types be better informed. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index dc76f9935c81..205f60262c37 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1010,11 +1010,13 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame case FE_QPSK: c->symbol_rate = p->u.qpsk.symbol_rate; c->fec_inner = p->u.qpsk.fec_inner; + c->delivery_system = SYS_DVBS; break; case FE_QAM: c->symbol_rate = p->u.qam.symbol_rate; c->fec_inner = p->u.qam.fec_inner; c->modulation = p->u.qam.modulation; + c->delivery_system = SYS_DVBC_ANNEX_AC; break; case FE_OFDM: c->bandwidth = p->u.ofdm.bandwidth; @@ -1024,9 +1026,14 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame c->transmission_mode = p->u.ofdm.transmission_mode; c->guard_interval = p->u.ofdm.guard_interval; c->hierarchy = p->u.ofdm.hierarchy_information; + c->delivery_system = SYS_DVBT; break; case FE_ATSC: c->modulation = p->u.vsb.modulation; + if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) + c->delivery_system = SYS_ATSC; + else + c->delivery_system = SYS_DVBC_ANNEX_B; break; } } @@ -1050,12 +1057,14 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe) printk("%s() Preparing QPSK req\n", __FUNCTION__); p->u.qpsk.symbol_rate = c->symbol_rate; p->u.qpsk.fec_inner = c->fec_inner; + c->delivery_system = SYS_DVBS; break; case FE_QAM: printk("%s() Preparing QAM req\n", __FUNCTION__); p->u.qam.symbol_rate = c->symbol_rate; p->u.qam.fec_inner = c->fec_inner; p->u.qam.modulation = c->modulation; + c->delivery_system = SYS_DVBC_ANNEX_AC; break; case FE_OFDM: printk("%s() Preparing OFDM req\n", __FUNCTION__); @@ -1066,10 +1075,15 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe) p->u.ofdm.transmission_mode = c->transmission_mode; p->u.ofdm.guard_interval = c->guard_interval; p->u.ofdm.hierarchy_information = c->hierarchy; + c->delivery_system = SYS_DVBT; break; case FE_ATSC: printk("%s() Preparing VSB req\n", __FUNCTION__); p->u.vsb.modulation = c->modulation; + if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) + c->delivery_system = SYS_ATSC; + else + c->delivery_system = SYS_DVBC_ANNEX_B; break; } } -- cgit v1.2.1 From 363429a089590f3f4071ebc492b3712fdcba770b Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 12 Sep 2008 01:34:28 -0300 Subject: V4L/DVB (9003): S2API: Remove the DTV_SET_ and DTV_GET_ prefixes The API now assumes that ioctl calls for FE_SET_PROPERTY and all set commands, and FE_GET_PROPERTY are get commands. Simplification. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 431 +++++++++++++++--------------- 1 file changed, 212 insertions(+), 219 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 205f60262c37..2ed748486e57 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -768,193 +768,128 @@ struct dtv_cmds_h dtv_cmds[] = { }, /* Set */ - [DTV_SET_FREQUENCY] = { - .name = "DTV_SET_FREQUENCY", - .cmd = DTV_SET_FREQUENCY, + [DTV_FREQUENCY] = { + .name = "DTV_FREQUENCY", + .cmd = DTV_FREQUENCY, .set = 1, }, - [DTV_SET_BANDWIDTH] = { - .name = "DTV_SET_BANDWIDTH", - .cmd = DTV_SET_BANDWIDTH, + [DTV_BANDWIDTH] = { + .name = "DTV_BANDWIDTH", + .cmd = DTV_BANDWIDTH, .set = 1, }, - [DTV_SET_MODULATION] = { - .name = "DTV_SET_MODULATION", - .cmd = DTV_SET_MODULATION, + [DTV_MODULATION] = { + .name = "DTV_MODULATION", + .cmd = DTV_MODULATION, .set = 1, }, - [DTV_SET_INVERSION] = { - .name = "DTV_SET_INVERSION", - .cmd = DTV_SET_INVERSION, + [DTV_INVERSION] = { + .name = "DTV_INVERSION", + .cmd = DTV_INVERSION, .set = 1, }, - [DTV_SET_DISEQC_MASTER] = { - .name = "DTV_SET_DISEQC_MASTER", - .cmd = DTV_SET_DISEQC_MASTER, + [DTV_DISEQC_MASTER] = { + .name = "DTV_DISEQC_MASTER", + .cmd = DTV_DISEQC_MASTER, .set = 1, .buffer = 1, }, - [DTV_SET_SYMBOL_RATE] = { - .name = "DTV_SET_SYMBOL_RATE", - .cmd = DTV_SET_SYMBOL_RATE, + [DTV_SYMBOL_RATE] = { + .name = "DTV_SYMBOL_RATE", + .cmd = DTV_SYMBOL_RATE, .set = 1, }, - [DTV_SET_INNER_FEC] = { - .name = "DTV_SET_INNER_FEC", - .cmd = DTV_SET_INNER_FEC, + [DTV_INNER_FEC] = { + .name = "DTV_INNER_FEC", + .cmd = DTV_INNER_FEC, .set = 1, }, - [DTV_SET_VOLTAGE] = { - .name = "DTV_SET_VOLTAGE", - .cmd = DTV_SET_VOLTAGE, + [DTV_VOLTAGE] = { + .name = "DTV_VOLTAGE", + .cmd = DTV_VOLTAGE, .set = 1, }, - [DTV_SET_TONE] = { - .name = "DTV_SET_TONE", - .cmd = DTV_SET_TONE, + [DTV_TONE] = { + .name = "DTV_TONE", + .cmd = DTV_TONE, .set = 1, }, - [DTV_SET_PILOT] = { - .name = "DTV_SET_PILOT", - .cmd = DTV_SET_PILOT, + [DTV_PILOT] = { + .name = "DTV_PILOT", + .cmd = DTV_PILOT, .set = 1, }, - [DTV_SET_ROLLOFF] = { - .name = "DTV_SET_ROLLOFF", - .cmd = DTV_SET_ROLLOFF, + [DTV_ROLLOFF] = { + .name = "DTV_ROLLOFF", + .cmd = DTV_ROLLOFF, .set = 1, }, - [DTV_SET_DELIVERY_SYSTEM] = { - .name = "DTV_SET_DELIVERY_SYSTEM", - .cmd = DTV_SET_DELIVERY_SYSTEM, + [DTV_DELIVERY_SYSTEM] = { + .name = "DTV_DELIVERY_SYSTEM", + .cmd = DTV_DELIVERY_SYSTEM, .set = 1, }, - [DTV_SET_ISDB_SEGMENT_IDX] = { - .name = "DTV_SET_ISDB_SEGMENT_IDX", - .cmd = DTV_SET_ISDB_SEGMENT_IDX, + [DTV_ISDB_SEGMENT_IDX] = { + .name = "DTV_ISDB_SEGMENT_IDX", + .cmd = DTV_ISDB_SEGMENT_IDX, .set = 1, }, - [DTV_SET_ISDB_SEGMENT_WIDTH] = { - .name = "DTV_SET_ISDB_SEGMENT_WIDTH", - .cmd = DTV_SET_ISDB_SEGMENT_WIDTH, + [DTV_ISDB_SEGMENT_WIDTH] = { + .name = "DTV_ISDB_SEGMENT_WIDTH", + .cmd = DTV_ISDB_SEGMENT_WIDTH, .set = 1, }, /* Get */ - [DTV_GET_FREQUENCY] = { - .name = "DTV_GET_FREQUENCY", - .cmd = DTV_GET_FREQUENCY, - .set = 0, - }, - [DTV_GET_BANDWIDTH] = { - .name = "DTV_GET_BANDWIDTH", - .cmd = DTV_GET_BANDWIDTH, - .set = 0, - }, - [DTV_GET_MODULATION] = { - .name = "DTV_GET_MODULATION", - .cmd = DTV_GET_MODULATION, - .set = 0, - }, - [DTV_GET_INVERSION] = { - .name = "DTV_GET_INVERSION", - .cmd = DTV_GET_INVERSION, - .set = 0, - }, - [DTV_GET_DISEQC_SLAVE_REPLY] = { - .name = "DTV_GET_DISEQC_SLAVE_REPLY", - .cmd = DTV_GET_DISEQC_SLAVE_REPLY, + [DTV_DISEQC_SLAVE_REPLY] = { + .name = "DTV_DISEQC_SLAVE_REPLY", + .cmd = DTV_DISEQC_SLAVE_REPLY, .set = 0, .buffer = 1, }, - [DTV_GET_SYMBOL_RATE] = { - .name = "DTV_GET_SYMBOL_RATE", - .cmd = DTV_GET_SYMBOL_RATE, - .set = 0, - }, - [DTV_GET_INNER_FEC] = { - .name = "DTV_GET_INNER_FEC", - .cmd = DTV_GET_INNER_FEC, - .set = 0, - }, - [DTV_GET_VOLTAGE] = { - .name = "DTV_GET_VOLTAGE", - .cmd = DTV_GET_VOLTAGE, - .set = 0, - }, - [DTV_GET_TONE] = { - .name = "DTV_GET_TONE", - .cmd = DTV_GET_TONE, - .set = 0, - }, - [DTV_GET_PILOT] = { - .name = "DTV_GET_PILOT", - .cmd = DTV_GET_PILOT, - .set = 0, - }, - [DTV_GET_ROLLOFF] = { - .name = "DTV_GET_ROLLOFF", - .cmd = DTV_GET_ROLLOFF, - .set = 0, - }, - [DTV_GET_DELIVERY_SYSTEM] = { - .name = "DTV_GET_DELIVERY_SYSTEM", - .cmd = DTV_GET_DELIVERY_SYSTEM, - .set = 0, - }, - [DTV_GET_ISDB_SEGMENT_IDX] = { - .name = "DTV_GET_ISDB_SEGMENT_IDX", - .cmd = DTV_GET_ISDB_SEGMENT_IDX, - .set = 0, - }, - [DTV_GET_ISDB_SEGMENT_WIDTH] = { - .name = "DTV_GET_ISDB_SEGMENT_WIDTH", - .cmd = DTV_GET_ISDB_SEGMENT_WIDTH, + [DTV_ISDB_LAYERA_FEC] = { + .name = "DTV_ISDB_LAYERA_FEC", + .cmd = DTV_ISDB_LAYERA_FEC, .set = 0, }, - [DTV_GET_ISDB_LAYERA_FEC] = { - .name = "DTV_GET_ISDB_LAYERA_FEC", - .cmd = DTV_GET_ISDB_LAYERA_FEC, + [DTV_ISDB_LAYERA_MODULATION] = { + .name = "DTV_ISDB_LAYERA_MODULATION", + .cmd = DTV_ISDB_LAYERA_MODULATION, .set = 0, }, - [DTV_GET_ISDB_LAYERA_MODULATION] = { - .name = "DTV_GET_ISDB_LAYERA_MODULATION", - .cmd = DTV_GET_ISDB_LAYERA_MODULATION, + [DTV_ISDB_LAYERA_SEGMENT_WIDTH] = { + .name = "DTV_ISDB_LAYERA_SEGMENT_WIDTH", + .cmd = DTV_ISDB_LAYERA_SEGMENT_WIDTH, .set = 0, }, - [DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH] = { - .name = "DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH", - .cmd = DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH, + [DTV_ISDB_LAYERB_FEC] = { + .name = "DTV_ISDB_LAYERB_FEC", + .cmd = DTV_ISDB_LAYERB_FEC, .set = 0, }, - [DTV_GET_ISDB_LAYERB_FEC] = { - .name = "DTV_GET_ISDB_LAYERB_FEC", - .cmd = DTV_GET_ISDB_LAYERB_FEC, + [DTV_ISDB_LAYERB_MODULATION] = { + .name = "DTV_ISDB_LAYERB_MODULATION", + .cmd = DTV_ISDB_LAYERB_MODULATION, .set = 0, }, - [DTV_GET_ISDB_LAYERB_MODULATION] = { - .name = "DTV_GET_ISDB_LAYERB_MODULATION", - .cmd = DTV_GET_ISDB_LAYERB_MODULATION, + [DTV_ISDB_LAYERB_SEGMENT_WIDTH] = { + .name = "DTV_ISDB_LAYERB_SEGMENT_WIDTH", + .cmd = DTV_ISDB_LAYERB_SEGMENT_WIDTH, .set = 0, }, - [DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH] = { - .name = "DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH", - .cmd = DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH, + [DTV_ISDB_LAYERC_FEC] = { + .name = "DTV_ISDB_LAYERC_FEC", + .cmd = DTV_ISDB_LAYERC_FEC, .set = 0, }, - [DTV_GET_ISDB_LAYERC_FEC] = { - .name = "DTV_GET_ISDB_LAYERC_FEC", - .cmd = DTV_GET_ISDB_LAYERC_FEC, + [DTV_ISDB_LAYERC_MODULATION] = { + .name = "DTV_ISDB_LAYERC_MODULATION", + .cmd = DTV_ISDB_LAYERC_MODULATION, .set = 0, }, - [DTV_GET_ISDB_LAYERC_MODULATION] = { - .name = "DTV_GET_ISDB_LAYERC_MODULATION", - .cmd = DTV_GET_ISDB_LAYERC_MODULATION, - .set = 0, - }, - [DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH] = { - .name = "DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH", - .cmd = DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH, + [DTV_ISDB_LAYERC_SEGMENT_WIDTH] = { + .name = "DTV_ISDB_LAYERC_SEGMENT_WIDTH", + .cmd = DTV_ISDB_LAYERC_SEGMENT_WIDTH, .set = 0, }, }; @@ -1160,7 +1095,92 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, unsigned int cmd, void *parg); -int dtv_property_process(struct dvb_frontend *fe, struct dtv_property *tvp, +int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, + struct inode *inode, struct file *file) +{ + int r = 0; + + printk("%s()\n", __FUNCTION__); + + dtv_property_dump(tvp); + + switch(tvp->cmd) { + case DTV_FREQUENCY: + tvp->u.data = fe->dtv_property_cache.frequency; + break; + case DTV_MODULATION: + tvp->u.data = fe->dtv_property_cache.modulation; + break; + case DTV_BANDWIDTH: + tvp->u.data = fe->dtv_property_cache.bandwidth; + break; + case DTV_INVERSION: + tvp->u.data = fe->dtv_property_cache.inversion; + break; + case DTV_SYMBOL_RATE: + tvp->u.data = fe->dtv_property_cache.symbol_rate; + break; + case DTV_INNER_FEC: + tvp->u.data = fe->dtv_property_cache.fec_inner; + break; + case DTV_PILOT: + tvp->u.data = fe->dtv_property_cache.pilot; + break; + case DTV_ROLLOFF: + tvp->u.data = fe->dtv_property_cache.rolloff; + break; + case DTV_DELIVERY_SYSTEM: + tvp->u.data = fe->dtv_property_cache.delivery_system; + break; + + /* ISDB-T Support here */ + case DTV_ISDB_SEGMENT_IDX: + tvp->u.data = fe->dtv_property_cache.isdb_segment_idx; + break; + case DTV_ISDB_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_segment_width; + break; + case DTV_ISDB_LAYERA_FEC: + tvp->u.data = fe->dtv_property_cache.isdb_layera_fec; + break; + case DTV_ISDB_LAYERA_MODULATION: + tvp->u.data = fe->dtv_property_cache.isdb_layera_modulation; + break; + case DTV_ISDB_LAYERA_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_layera_segment_width; + break; + case DTV_ISDB_LAYERB_FEC: + tvp->u.data = fe->dtv_property_cache.isdb_layerb_fec; + break; + case DTV_ISDB_LAYERB_MODULATION: + tvp->u.data = fe->dtv_property_cache.isdb_layerb_modulation; + break; + case DTV_ISDB_LAYERB_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_layerb_segment_width; + break; + case DTV_ISDB_LAYERC_FEC: + tvp->u.data = fe->dtv_property_cache.isdb_layerc_fec; + break; + case DTV_ISDB_LAYERC_MODULATION: + tvp->u.data = fe->dtv_property_cache.isdb_layerc_modulation; + break; + case DTV_ISDB_LAYERC_SEGMENT_WIDTH: + tvp->u.data = fe->dtv_property_cache.isdb_layerc_segment_width; + break; + case DTV_VOLTAGE: + tvp->u.data = fe->dtv_property_cache.voltage; + break; + case DTV_TONE: + tvp->u.data = fe->dtv_property_cache.sectone; + break; + default: + r = -1; + } + + return r; +} + +int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, struct inode *inode, struct file *file) { int r = 0; @@ -1190,117 +1210,53 @@ int dtv_property_process(struct dvb_frontend *fe, struct dtv_property *tvp, r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; - case DTV_SET_FREQUENCY: + case DTV_FREQUENCY: fe->dtv_property_cache.frequency = tvp->u.data; break; - case DTV_GET_FREQUENCY: - tvp->u.data = fe->dtv_property_cache.frequency; - break; - case DTV_SET_MODULATION: + case DTV_MODULATION: fe->dtv_property_cache.modulation = tvp->u.data; break; - case DTV_GET_MODULATION: - tvp->u.data = fe->dtv_property_cache.modulation; - break; - case DTV_SET_BANDWIDTH: + case DTV_BANDWIDTH: fe->dtv_property_cache.bandwidth = tvp->u.data; break; - case DTV_GET_BANDWIDTH: - tvp->u.data = fe->dtv_property_cache.bandwidth; - break; - case DTV_SET_INVERSION: + case DTV_INVERSION: fe->dtv_property_cache.inversion = tvp->u.data; break; - case DTV_GET_INVERSION: - tvp->u.data = fe->dtv_property_cache.inversion; - break; - case DTV_SET_SYMBOL_RATE: + case DTV_SYMBOL_RATE: fe->dtv_property_cache.symbol_rate = tvp->u.data; break; - case DTV_GET_SYMBOL_RATE: - tvp->u.data = fe->dtv_property_cache.symbol_rate; - break; - case DTV_SET_INNER_FEC: + case DTV_INNER_FEC: fe->dtv_property_cache.fec_inner = tvp->u.data; break; - case DTV_GET_INNER_FEC: - tvp->u.data = fe->dtv_property_cache.fec_inner; - break; - case DTV_SET_PILOT: + case DTV_PILOT: fe->dtv_property_cache.pilot = tvp->u.data; break; - case DTV_GET_PILOT: - tvp->u.data = fe->dtv_property_cache.pilot; - break; - case DTV_SET_ROLLOFF: + case DTV_ROLLOFF: fe->dtv_property_cache.rolloff = tvp->u.data; break; - case DTV_GET_ROLLOFF: - tvp->u.data = fe->dtv_property_cache.rolloff; - break; - case DTV_SET_DELIVERY_SYSTEM: + case DTV_DELIVERY_SYSTEM: fe->dtv_property_cache.delivery_system = tvp->u.data; break; - case DTV_GET_DELIVERY_SYSTEM: - tvp->u.data = fe->dtv_property_cache.delivery_system; - break; /* ISDB-T Support here */ - case DTV_SET_ISDB_SEGMENT_IDX: + case DTV_ISDB_SEGMENT_IDX: fe->dtv_property_cache.isdb_segment_idx = tvp->u.data; break; - case DTV_GET_ISDB_SEGMENT_IDX: - tvp->u.data = fe->dtv_property_cache.isdb_segment_idx; - break; - case DTV_SET_ISDB_SEGMENT_WIDTH: + case DTV_ISDB_SEGMENT_WIDTH: fe->dtv_property_cache.isdb_segment_width = tvp->u.data; break; - case DTV_GET_ISDB_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_segment_width; - break; - case DTV_GET_ISDB_LAYERA_FEC: - tvp->u.data = fe->dtv_property_cache.isdb_layera_fec; - break; - case DTV_GET_ISDB_LAYERA_MODULATION: - tvp->u.data = fe->dtv_property_cache.isdb_layera_modulation; - break; - case DTV_GET_ISDB_LAYERA_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_layera_segment_width; - break; - case DTV_GET_ISDB_LAYERB_FEC: - tvp->u.data = fe->dtv_property_cache.isdb_layerb_fec; - break; - case DTV_GET_ISDB_LAYERB_MODULATION: - tvp->u.data = fe->dtv_property_cache.isdb_layerb_modulation; - break; - case DTV_GET_ISDB_LAYERB_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_layerb_segment_width; - break; - case DTV_GET_ISDB_LAYERC_FEC: - tvp->u.data = fe->dtv_property_cache.isdb_layerc_fec; - break; - case DTV_GET_ISDB_LAYERC_MODULATION: - tvp->u.data = fe->dtv_property_cache.isdb_layerc_modulation; - break; - case DTV_GET_ISDB_LAYERC_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_layerc_segment_width; - break; - case DTV_SET_VOLTAGE: + case DTV_VOLTAGE: fe->dtv_property_cache.voltage = tvp->u.data; r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE, (void *)fe->dtv_property_cache.voltage); break; - case DTV_GET_VOLTAGE: - tvp->u.data = fe->dtv_property_cache.voltage; - break; - case DTV_SET_TONE: + case DTV_TONE: fe->dtv_property_cache.sectone = tvp->u.data; r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE, (void *)fe->dtv_property_cache.sectone); break; - case DTV_GET_TONE: - tvp->u.data = fe->dtv_property_cache.sectone; - break; + default: + r = -1; } return r; @@ -1375,13 +1331,50 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, } for (i = 0; i < tvps->num; i++) - dtv_property_process(fe, tvp + i, inode, file); + dtv_property_process_set(fe, tvp + i, inode, file); if(fe->dtv_property_cache.state == DTV_TUNE) { printk("%s() Property cache is full, tuning\n", __FUNCTION__); } err = 0; - } + } else + if(cmd == FE_GET_PROPERTY) { + printk("%s() FE_GET_PROPERTY\n", __FUNCTION__); + + tvps = (struct dtv_properties __user *)parg; + + printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num); + printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props); + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if (tvps->num > DTV_IOCTL_MAX_MSGS) + return -EINVAL; + + tvp = (struct dtv_property *) kmalloc(tvps->num * + sizeof(struct dtv_property), GFP_KERNEL); + if (!tvp) { + err = -ENOMEM; + goto out; + } + + if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + for (i = 0; i < tvps->num; i++) + dtv_property_process_get(fe, tvp + i, inode, file); + + if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + err = 0; + } else + err = -EOPNOTSUPP; + out: kfree(tvp); return err; -- cgit v1.2.1 From bfbf2dae30ed75bceccc6a88d2d9368694d6bf40 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 12 Sep 2008 01:37:37 -0300 Subject: V4L/DVB (9004): S2API: Implement GET/SET handing to the demods The frontends will be notified (if they chose) of all _get and _set commands so they can help determine result or action. Results are now returned to userspace correctly. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 21 +++++++++++++++++---- drivers/media/dvb/dvb-core/dvb_frontend.h | 1 - drivers/media/dvb/frontends/cx24116.c | 6 +++--- 3 files changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2ed748486e57..8bc3c0842b3d 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1104,6 +1104,13 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, dtv_property_dump(tvp); + /* Allow the frontend to validate incoming properties */ + if (fe->ops.get_property) + r = fe->ops.get_property(fe, tvp); + + if (r < 0) + return r; + switch(tvp->cmd) { case DTV_FREQUENCY: tvp->u.data = fe->dtv_property_cache.frequency; @@ -1188,6 +1195,13 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, printk("%s()\n", __FUNCTION__); dtv_property_dump(tvp); + /* Allow the frontend to validate incoming properties */ + if (fe->ops.set_property) + r = fe->ops.set_property(fe, tvp); + + if (r < 0) + return r; + switch(tvp->cmd) { case DTV_CLEAR: /* Reset a cache of data specific to the frontend here. This does @@ -1331,12 +1345,12 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, } for (i = 0; i < tvps->num; i++) - dtv_property_process_set(fe, tvp + i, inode, file); + err |= dtv_property_process_set(fe, tvp + i, inode, file); if(fe->dtv_property_cache.state == DTV_TUNE) { printk("%s() Property cache is full, tuning\n", __FUNCTION__); } - err = 0; + } else if(cmd == FE_GET_PROPERTY) { printk("%s() FE_GET_PROPERTY\n", __FUNCTION__); @@ -1364,14 +1378,13 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, } for (i = 0; i < tvps->num; i++) - dtv_property_process_get(fe, tvp + i, inode, file); + err |= dtv_property_process_get(fe, tvp + i, inode, file); if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; goto out; } - err = 0; } else err = -EOPNOTSUPP; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 1c2090966baf..784e8fe1d3bd 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -172,7 +172,6 @@ struct dvb_frontend_ops { int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); - int (*set_params)(struct dvb_frontend* fe); }; #define MAX_EVENT 8 diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 9f93930a2594..0ac2c5493087 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -802,9 +802,9 @@ static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tv return 0; } -static int cx24116_set_params(struct dvb_frontend *fe) +static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp) { - dprintk("%s(..) We were notified that a tune request may occur\n", __func__); + dprintk("%s(..)\n", __func__); return 0; } @@ -964,7 +964,7 @@ static struct dvb_frontend_ops cx24116_ops = { .diseqc_send_burst = cx24116_diseqc_send_burst, .set_property = cx24116_set_property, - .set_params = cx24116_set_params, + .get_property = cx24116_get_property, .set_frontend = cx24116_set_frontend, }; -- cgit v1.2.1 From e6f9ec86575358309cf9d4b2643df2f3b1f6f9fa Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 12 Sep 2008 14:49:06 -0300 Subject: V4L/DVB (9005): Bug fix: ioctl FE_SET_PROPERTY/FE_GET_PROPERTY always return error Bug fix: ioctl FE_SET_PROPERTY/FE_GET_PROPERTY always return error Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 8bc3c0842b3d..161ebcf9258a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1311,7 +1311,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - int err = -EOPNOTSUPP; + int err = 0; struct dtv_properties *tvps = NULL; struct dtv_property *tvp = NULL; -- cgit v1.2.1 From 4dd88bec368a6e4caa86a511f7adbc4c08992c5c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 13 Sep 2008 15:09:07 -0300 Subject: V4L/DVB (9006): S2API: Allow reliable use of old and new api on the same frontend, regardless. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 161ebcf9258a..6b914f9a03c5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1299,8 +1299,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) err = dvb_frontend_ioctl_properties(inode, file, cmd, parg); - else + else { + fe->dtv_property_cache.state = DTV_UNDEFINED; err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg); + } up(&fepriv->sem); return err; @@ -1567,8 +1569,6 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; - dtv_property_cache_sync(fe, &fepriv->parameters); - if(fe->dtv_property_cache.state == DTV_TUNE) { if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) { err = -EINVAL; @@ -1580,6 +1580,7 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, break; } + dtv_property_cache_sync(fe, &fepriv->parameters); memcpy (&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); } -- cgit v1.2.1 From 75b7f9437b1cf63750bb58efaaeb6d72d04b3c7f Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 13 Sep 2008 16:56:34 -0300 Subject: V4L/DVB (9007): S2API: Changed bandwidth to be expressed in HZ Also added some compat code for the older API. Added more ISDB message/command suggestions, current not connected in dvb-core. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 33 ++++++++++++++++++++++--------- drivers/media/dvb/dvb-core/dvb_frontend.h | 2 +- 2 files changed, 25 insertions(+), 10 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 6b914f9a03c5..7dffb48e55e5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -773,9 +773,9 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_FREQUENCY, .set = 1, }, - [DTV_BANDWIDTH] = { - .name = "DTV_BANDWIDTH", - .cmd = DTV_BANDWIDTH, + [DTV_BANDWIDTH_HZ] = { + .name = "DTV_BANDWIDTH_HZ", + .cmd = DTV_BANDWIDTH_HZ, .set = 1, }, [DTV_MODULATION] = { @@ -954,7 +954,15 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame c->delivery_system = SYS_DVBC_ANNEX_AC; break; case FE_OFDM: - c->bandwidth = p->u.ofdm.bandwidth; + if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + c->bandwidth_hz = 6000000; + else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + c->bandwidth_hz = 7000000; + else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + c->bandwidth_hz = 8000000; + else + /* Including BANDWIDTH_AUTO */ + c->bandwidth_hz = 0; c->code_rate_HP = p->u.ofdm.code_rate_HP; c->code_rate_LP = p->u.ofdm.code_rate_LP; c->modulation = p->u.ofdm.constellation; @@ -1003,7 +1011,14 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe) break; case FE_OFDM: printk("%s() Preparing OFDM req\n", __FUNCTION__); - p->u.ofdm.bandwidth = c->bandwidth; + if (c->bandwidth_hz == 6000000) + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + else if (c->bandwidth_hz == 7000000) + p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + else if (c->bandwidth_hz == 8000000) + p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + else + p->u.ofdm.bandwidth = BANDWIDTH_AUTO; p->u.ofdm.code_rate_HP = c->code_rate_HP; p->u.ofdm.code_rate_LP = c->code_rate_LP; p->u.ofdm.constellation = c->modulation; @@ -1118,8 +1133,8 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_MODULATION: tvp->u.data = fe->dtv_property_cache.modulation; break; - case DTV_BANDWIDTH: - tvp->u.data = fe->dtv_property_cache.bandwidth; + case DTV_BANDWIDTH_HZ: + tvp->u.data = fe->dtv_property_cache.bandwidth_hz; break; case DTV_INVERSION: tvp->u.data = fe->dtv_property_cache.inversion; @@ -1230,8 +1245,8 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_MODULATION: fe->dtv_property_cache.modulation = tvp->u.data; break; - case DTV_BANDWIDTH: - fe->dtv_property_cache.bandwidth = tvp->u.data; + case DTV_BANDWIDTH_HZ: + fe->dtv_property_cache.bandwidth_hz = tvp->u.data; break; case DTV_INVERSION: fe->dtv_property_cache.inversion = tvp->u.data; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 784e8fe1d3bd..2fa37f5a0d9a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -198,7 +198,7 @@ struct dtv_frontend_properties { fe_spectral_inversion_t inversion; fe_code_rate_t fec_inner; fe_transmit_mode_t transmission_mode; - fe_bandwidth_t bandwidth; + u32 bandwidth_hz; /* 0 = AUTO */ fe_guard_interval_t guard_interval; fe_hierarchy_t hierarchy; u32 symbol_rate; -- cgit v1.2.1 From 1d78cac4779be3ae6bef4791b3b12928e2499fef Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 13 Sep 2008 18:15:17 -0300 Subject: V4L/DVB (9008): S2API: Bugfix related to syncing the cache when used with the old API. Many thanks to Darron Broad for pointing out the obvious. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 7dffb48e55e5..05d0b73cf9a3 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1595,9 +1595,9 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, break; } - dtv_property_cache_sync(fe, &fepriv->parameters); memcpy (&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); + dtv_property_cache_sync(fe, &fepriv->parameters); } memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); -- cgit v1.2.1 From a611d0ca006fe76d88b8dd5ac44f4468293b6760 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sat, 13 Sep 2008 10:10:53 -0300 Subject: V4L/DVB (9010): Add support for SDMC DM1105 PCI chip Add support for SDMC DM1105 PCI chip. There is a lot of cards based on it, like DvbWorld 2002 DVB-S , 2004 DVB-S2 Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/Kconfig | 4 + drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/dm1105/Kconfig | 14 + drivers/media/dvb/dm1105/Makefile | 3 + drivers/media/dvb/dm1105/dm1105.c | 917 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 939 insertions(+), 1 deletion(-) create mode 100644 drivers/media/dvb/dm1105/Kconfig create mode 100644 drivers/media/dvb/dm1105/Makefile create mode 100644 drivers/media/dvb/dm1105/dm1105.c (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 8bc1445bd33b..5858744e70de 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -35,6 +35,10 @@ comment "Supported Pluto2 Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/pluto2/Kconfig" +comment "Supported SDMC DM1105 Adapters" + depends on DVB_CORE && PCI && I2C +source "drivers/media/dvb/dm1105/Kconfig" + comment "Supported DVB Frontends" depends on DVB_CORE source "drivers/media/dvb/frontends/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index d6ba4d195201..ea953a03e24d 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,4 +2,4 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/ +obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/ dm1105/ diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig new file mode 100644 index 000000000000..fc2ca7dca6b2 --- /dev/null +++ b/drivers/media/dvb/dm1105/Kconfig @@ -0,0 +1,14 @@ +config DVB_DM1105 + tristate "SDMC DM1105 based PCI cards" + depends on DVB_CORE && PCI && I2C + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + help + Support for cards based on the SDMC DM1105 PCI chip like + DvbWorld 2002 + + 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. + + Say Y or M if you own such a device and want to use it. diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile new file mode 100644 index 000000000000..8ac28b0546af --- /dev/null +++ b/drivers/media/dvb/dm1105/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_DM1105) += dm1105.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c new file mode 100644 index 000000000000..fe8d0e58c0ea --- /dev/null +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -0,0 +1,917 @@ +/* + * dm1105.c - driver for DVB cards based on SDMC DM1105 PCI chip + * + * Copyright (C) 2008 Igor M. Liplianin + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" +#include "dvb-pll.h" + +#include "stv0299.h" +/*#include "stv0288.h" + *#include "si21xx.h" + *#include "stb6000.h" + *#include "cx24116.h"*/ +#include "z0194a.h" + +/* ----------------------------------------------- */ +/* + * PCI ID's + */ +#ifndef PCI_VENDOR_ID_TRIGEM +#define PCI_VENDOR_ID_TRIGEM 0x109f +#endif +#ifndef PCI_DEVICE_ID_DM1105 +#define PCI_DEVICE_ID_DM1105 0x036f +#endif +#ifndef PCI_DEVICE_ID_DW2002 +#define PCI_DEVICE_ID_DW2002 0x2002 +#endif +#ifndef PCI_DEVICE_ID_DW2004 +#define PCI_DEVICE_ID_DW2004 0x2004 +#endif +/* ----------------------------------------------- */ +/* sdmc dm1105 registers */ + +/* TS Control */ +#define DM1105_TSCTR 0x00 +#define DM1105_DTALENTH 0x04 + +/* GPIO Interface */ +#define DM1105_GPIOVAL 0x08 +#define DM1105_GPIOCTR 0x0c + +/* PID serial number */ +#define DM1105_PIDN 0x10 + +/* Odd-even secret key select */ +#define DM1105_CWSEL 0x14 + +/* Host Command Interface */ +#define DM1105_HOST_CTR 0x18 +#define DM1105_HOST_AD 0x1c + +/* PCI Interface */ +#define DM1105_CR 0x30 +#define DM1105_RST 0x34 +#define DM1105_STADR 0x38 +#define DM1105_RLEN 0x3c +#define DM1105_WRP 0x40 +#define DM1105_INTCNT 0x44 +#define DM1105_INTMAK 0x48 +#define DM1105_INTSTS 0x4c + +/* CW Value */ +#define DM1105_ODD 0x50 +#define DM1105_EVEN 0x58 + +/* PID Value */ +#define DM1105_PID 0x60 + +/* IR Control */ +#define DM1105_IRCTR 0x64 +#define DM1105_IRMODE 0x68 +#define DM1105_SYSTEMCODE 0x6c +#define DM1105_IRCODE 0x70 + +/* Unknown Values */ +#define DM1105_ENCRYPT 0x74 +#define DM1105_VER 0x7c + +/* I2C Interface */ +#define DM1105_I2CCTR 0x80 +#define DM1105_I2CSTS 0x81 +#define DM1105_I2CDAT 0x82 +#define DM1105_I2C_RA 0x83 +/* ----------------------------------------------- */ +/* Interrupt Mask Bits */ + +#define INTMAK_TSIRQM 0x01 +#define INTMAK_HIRQM 0x04 +#define INTMAK_IRM 0x08 +#define INTMAK_ALLMASK (INTMAK_TSIRQM | \ + INTMAK_HIRQM | \ + INTMAK_IRM) +#define INTMAK_NONEMASK 0x00 + +/* Interrupt Status Bits */ +#define INTSTS_TSIRQ 0x01 +#define INTSTS_HIRQ 0x04 +#define INTSTS_IR 0x08 + +/* IR Control Bits */ +#define DM1105_IR_EN 0x01 +#define DM1105_SYS_CHK 0x02 +#define DM1105_REP_FLG 0x08 + +/* EEPROM addr */ +#define IIC_24C01_addr 0xa0 +/* Max board count */ +#define DM1105_MAX 0x04 + +#define DRIVER_NAME "dm1105" + +#define DM1105_DMA_PACKETS 47 +#define DM1105_DMA_PACKET_LENGTH (128*4) +#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) + +/* GPIO's for LNB power control */ +#define DM1105_LNB_MASK 0x00000000 +#define DM1105_LNB_13V 0x00010100 +#define DM1105_LNB_18V 0x00000100 + +static int ir_debug; +module_param(ir_debug, int, 0644); +MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static u16 ir_codes_dm1105_nec[128] = { + [0x0a] = KEY_Q, /*power*/ + [0x0c] = KEY_M, /*mute*/ + [0x11] = KEY_1, + [0x12] = KEY_2, + [0x13] = KEY_3, + [0x14] = KEY_4, + [0x15] = KEY_5, + [0x16] = KEY_6, + [0x17] = KEY_7, + [0x18] = KEY_8, + [0x19] = KEY_9, + [0x10] = KEY_0, + [0x1c] = KEY_PAGEUP, /*ch+*/ + [0x0f] = KEY_PAGEDOWN, /*ch-*/ + [0x1a] = KEY_O, /*vol+*/ + [0x0e] = KEY_Z, /*vol-*/ + [0x04] = KEY_R, /*rec*/ + [0x09] = KEY_D, /*fav*/ + [0x08] = KEY_BACKSPACE, /*rewind*/ + [0x07] = KEY_A, /*fast*/ + [0x0b] = KEY_P, /*pause*/ + [0x02] = KEY_ESC, /*cancel*/ + [0x03] = KEY_G, /*tab*/ + [0x00] = KEY_UP, /*up*/ + [0x1f] = KEY_ENTER, /*ok*/ + [0x01] = KEY_DOWN, /*down*/ + [0x05] = KEY_C, /*cap*/ + [0x06] = KEY_S, /*stop*/ + [0x40] = KEY_F, /*full*/ + [0x1e] = KEY_W, /*tvmode*/ + [0x1b] = KEY_B, /*recall*/ +}; + +/* infrared remote control */ +struct infrared { + u16 key_map[128]; + struct input_dev *input_dev; + char input_phys[32]; + struct tasklet_struct ir_tasklet; + u32 ir_command; +}; + +struct dm1105dvb { + /* pci */ + struct pci_dev *pdev; + u8 __iomem *io_mem; + + /* ir */ + struct infrared ir; + + /* dvb */ + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + unsigned int full_ts_users; + + /* i2c */ + struct i2c_adapter i2c_adap; + + /* dma */ + dma_addr_t dma_addr; + unsigned char *ts_buf; + u32 wrp; + u32 buffer_size; + unsigned int PacketErrorCount; + unsigned int dmarst; + spinlock_t lock; + +}; + +#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg])) + +static struct dm1105dvb *dm1105dvb_local; + +static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + struct dm1105dvb *dm1105dvb ; + + int addr, rc, i, j, k, len, byte, data; + u8 status; + + dm1105dvb = i2c_adap->algo_data; + for (i = 0; i < num; i++) { + outb(0x00, dm_io_mem(DM1105_I2CCTR)); + if (msgs[i].flags & I2C_M_RD) { + /* read bytes */ + addr = msgs[i].addr << 1; + addr |= 1; + outb(addr, dm_io_mem(DM1105_I2CDAT)); + for (byte = 0; byte < msgs[i].len; byte++) + outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1)); + + outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR)); + for (j = 0; j < 55; j++) { + mdelay(10); + status = inb(dm_io_mem(DM1105_I2CSTS)); + if ((status & 0xc0) == 0x40) + break; + } + if (j >= 55) + return -1; + + for (byte = 0; byte < msgs[i].len; byte++) { + rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1)); + if (rc < 0) + goto err; + msgs[i].buf[byte] = rc; + } + } else { + if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { + /* prepaired for cx24116 firmware */ + /* Write in small blocks */ + len = msgs[i].len - 1; + k = 1; + do { + outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT)); + outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1)); + for (byte = 0; byte < (len > 48 ? 48 : len); byte++) { + data = msgs[i].buf[k+byte]; + outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2)); + } + outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR)); + for (j = 0; j < 25; j++) { + mdelay(10); + status = inb(dm_io_mem(DM1105_I2CSTS)); + if ((status & 0xc0) == 0x40) + break; + } + + if (j >= 25) + return -1; + + k += 48; + len -= 48; + } while (len > 0); + } else { + /* write bytes */ + outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT)); + for (byte = 0; byte < msgs[i].len; byte++) { + data = msgs[i].buf[byte]; + outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1)); + } + outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR)); + for (j = 0; j < 25; j++) { + mdelay(10); + status = inb(dm_io_mem(DM1105_I2CSTS)); + if ((status & 0xc0) == 0x40) + break; + } + + if (j >= 25) + return -1; + } + } + } + return num; + err: + return rc; +} + +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dm1105_algo = { + .master_xfer = dm1105_i2c_xfer, + .functionality = functionality, +}; + +static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed) +{ + return container_of(feed->demux, struct dm1105dvb, demux); +} + +static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe) +{ + return container_of(fe->dvb, struct dm1105dvb, dvb_adapter); +} + +static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe); + + 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)); + } + + return 0; +} + +static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb) +{ + outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR)); +} + +static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb) +{ + dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr); + + return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr); +} + +static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb) +{ + pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr); +} + +static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb) +{ + outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK)); + outb(1, dm_io_mem(DM1105_CR)); +} + +static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb) +{ + outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK)); + outb(0, dm_io_mem(DM1105_CR)); +} + +static int dm1105dvb_start_feed(struct dvb_demux_feed *f) +{ + struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f); + + if (dm1105dvb->full_ts_users++ == 0) + dm1105dvb_enable_irqs(dm1105dvb); + + return 0; +} + +static int dm1105dvb_stop_feed(struct dvb_demux_feed *f) +{ + struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f); + + if (--dm1105dvb->full_ts_users == 0) + dm1105dvb_disable_irqs(dm1105dvb); + + return 0; +} + +/* ir tasklet */ +static void dm1105_emit_key(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + u32 ircom = ir->ir_command; + u8 data; + u16 keycode; + + data = (ircom >> 8) & 0x7f; + + input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data); + input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); + keycode = ir->key_map[data]; + + if (!keycode) + return; + + input_event(ir->input_dev, EV_KEY, keycode, 1); + input_sync(ir->input_dev); + input_event(ir->input_dev, EV_KEY, keycode, 0); + input_sync(ir->input_dev); + +} + +static irqreturn_t dm1105dvb_irq(int irq, void *dev_id) +{ + struct dm1105dvb *dm1105dvb = dev_id; + unsigned int piece; + unsigned int nbpackets; + u32 command; + u32 nextwrp; + u32 oldwrp; + + /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ + unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS)); + outb(intsts, dm_io_mem(DM1105_INTSTS)); + + switch (intsts) { + case INTSTS_TSIRQ: + case (INTSTS_TSIRQ | INTSTS_IR): + nextwrp = inl(dm_io_mem(DM1105_WRP)) - + inl(dm_io_mem(DM1105_STADR)) ; + oldwrp = dm1105dvb->wrp; + spin_lock(&dm1105dvb->lock); + if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) && + (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) && + (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) { + dm1105dvb->PacketErrorCount++; + /* bad packet found */ + if ((dm1105dvb->PacketErrorCount >= 2) && + (dm1105dvb->dmarst == 0)) { + outb(1, dm_io_mem(DM1105_RST)); + dm1105dvb->wrp = 0; + dm1105dvb->PacketErrorCount = 0; + dm1105dvb->dmarst = 0; + spin_unlock(&dm1105dvb->lock); + return IRQ_HANDLED; + } + } + if (nextwrp < oldwrp) { + piece = dm1105dvb->buffer_size - oldwrp; + memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp); + nbpackets = (piece + nextwrp)/188; + } else { + nbpackets = (nextwrp - oldwrp)/188; + } + dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets); + dm1105dvb->wrp = nextwrp; + spin_unlock(&dm1105dvb->lock); + break; + case INTSTS_IR: + command = inl(dm_io_mem(DM1105_IRCODE)); + if (ir_debug) + printk("dm1105: received byte 0x%04x\n", command); + + dm1105dvb->ir.ir_command = command; + tasklet_schedule(&dm1105dvb->ir.ir_tasklet); + break; + } + return IRQ_HANDLED; + + +} + +/* register with input layer */ +static void input_register_keys(struct infrared *ir) +{ + int i; + + memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); + + for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) + set_bit(ir->key_map[i], ir->input_dev->keybit); + + ir->input_dev->keycode = ir->key_map; + ir->input_dev->keycodesize = sizeof(ir->key_map[0]); + ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); +} + +int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) +{ + struct input_dev *input_dev; + int err; + + dm1105dvb_local = dm1105; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + dm1105->ir.input_dev = input_dev; + snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), + "pci-%s/ir0", pci_name(dm1105->pdev)); + + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->name = "DVB on-card IR receiver"; + + input_dev->phys = dm1105->ir.input_phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 2; + if (dm1105->pdev->subsystem_vendor) { + input_dev->id.vendor = dm1105->pdev->subsystem_vendor; + input_dev->id.product = dm1105->pdev->subsystem_device; + } else { + input_dev->id.vendor = dm1105->pdev->vendor; + input_dev->id.product = dm1105->pdev->device; + } + input_dev->dev.parent = &dm1105->pdev->dev; + /* initial keymap */ + memcpy(dm1105->ir.key_map, ir_codes_dm1105_nec, sizeof dm1105->ir.key_map); + input_register_keys(&dm1105->ir); + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + + tasklet_init(&dm1105->ir.ir_tasklet, dm1105_emit_key, (unsigned long) &dm1105->ir); + + return 0; +} + + +void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105) +{ + tasklet_kill(&dm1105->ir.ir_tasklet); + input_unregister_device(dm1105->ir.input_dev); + +} + +static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb) +{ + dm1105dvb_disable_irqs(dm1105dvb); + + outb(0, dm_io_mem(DM1105_HOST_CTR)); + + /*DATALEN 188,*/ + outb(188, dm_io_mem(DM1105_DTALENTH)); + /*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/ + outw(0xc10a, dm_io_mem(DM1105_TSCTR)); + + /* map DMA and set address */ + dm1105dvb_dma_map(dm1105dvb); + dm1105dvb_set_dma_addr(dm1105dvb); + /* big buffer */ + outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN)); + outb(47, dm_io_mem(DM1105_INTCNT)); + + /* IR NEC mode enable */ + outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR)); + outb(0, dm_io_mem(DM1105_IRMODE)); + outw(0, dm_io_mem(DM1105_SYSTEMCODE)); + + return 0; +} + +static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb) +{ + dm1105dvb_disable_irqs(dm1105dvb); + + /* IR disable */ + outb(0, dm_io_mem(DM1105_IRCTR)); + outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK)); + + dm1105dvb_dma_unmap(dm1105dvb); +} +#if 0 +static struct stv0288_config earda_config = { + .demod_address = 0x68, + .min_delay_ms = 100, +}; + +static struct si21xx_config serit_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + +}; + +static struct cx24116_config serit_sp2633_config = { + .demod_address = 0x55, +}; +#endif /* keep */ + +static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) +{ + int ret; + + switch (dm1105dvb->pdev->subsystem_device) { + case PCI_DEVICE_ID_DW2002: + 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); + } +#if 0 + 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); + } + } + + 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; + } +#endif /* keep */ + break; + case PCI_DEVICE_ID_DW2004: +#if 0 + dm1105dvb->fe = dvb_attach( + cx24116_attach, &serit_sp2633_config, + &dm1105dvb->i2c_adap); + if (dm1105dvb->fe) + dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; +#else /* keep */ + dev_err(&dm1105dvb->pdev->dev, "needs cx24116 module\n"); +#endif /* keep */ + break; + } + + if (!dm1105dvb->fe) { + dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n"); + return -ENODEV; + } + + ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe); + if (ret < 0) { + if (dm1105dvb->fe->ops.release) + dm1105dvb->fe->ops.release(dm1105dvb->fe); + dm1105dvb->fe = NULL; + return ret; + } + + return 0; +} + +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 }, + }; + + dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2); + dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static int __devinit dm1105_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct dm1105dvb *dm1105dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENOMEM; + + dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL); + if (!dm1105dvb) + goto out; + + dm1105dvb->pdev = pdev; + dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES; + dm1105dvb->PacketErrorCount = 0; + dm1105dvb->dmarst = 0; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_kfree; + + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (ret < 0) + goto err_pci_disable_device; + + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret < 0) + goto err_pci_disable_device; + + dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); + if (!dm1105dvb->io_mem) { + ret = -EIO; + goto err_pci_release_regions; + } + + spin_lock_init(&dm1105dvb->lock); + pci_set_drvdata(pdev, dm1105dvb); + + ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb); + if (ret < 0) + goto err_pci_iounmap; + + ret = dm1105dvb_hw_init(dm1105dvb); + if (ret < 0) + goto err_free_irq; + + /* i2c */ + i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb); + strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME); + dm1105dvb->i2c_adap.owner = THIS_MODULE; + dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL; + dm1105dvb->i2c_adap.dev.parent = &pdev->dev; + dm1105dvb->i2c_adap.algo = &dm1105_algo; + dm1105dvb->i2c_adap.algo_data = dm1105dvb; + ret = i2c_add_adapter(&dm1105dvb->i2c_adap); + + if (ret < 0) + goto err_dm1105dvb_hw_exit; + + /* dvb */ + ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME, + THIS_MODULE, &pdev->dev, adapter_nr); + if (ret < 0) + goto err_i2c_del_adapter; + + dvb_adapter = &dm1105dvb->dvb_adapter; + + dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac); + + dvbdemux = &dm1105dvb->demux; + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = dm1105dvb_start_feed; + dvbdemux->stop_feed = dm1105dvb_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + dm1105dvb->dmxdev.filternum = 256; + dm1105dvb->dmxdev.demux = dmx; + dm1105dvb->dmxdev.capabilities = 0; + + ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + dm1105dvb->hw_frontend.source = DMX_FRONTEND_0; + + ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + dm1105dvb->mem_frontend.source = DMX_MEMORY_FE; + + ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = frontend_init(dm1105dvb); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx); + dm1105_ir_init(dm1105dvb); +out: + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&dm1105dvb->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +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: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(dm1105dvb); + goto out; +} + +static void __devexit dm1105_remove(struct pci_dev *pdev) +{ + struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev); + struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter; + struct dvb_demux *dvbdemux = &dm1105dvb->demux; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dm1105_ir_exit(dm1105dvb); + dmx->close(dmx); + dvb_net_release(&dm1105dvb->dvbnet); + if (dm1105dvb->fe) + dvb_unregister_frontend(dm1105dvb->fe); + + dmx->disconnect_frontend(dmx); + dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend); + dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend); + dvb_dmxdev_release(&dm1105dvb->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_adapter(dvb_adapter); + if (&dm1105dvb->i2c_adap) + i2c_del_adapter(&dm1105dvb->i2c_adap); + + dm1105dvb_hw_exit(dm1105dvb); + synchronize_irq(pdev->irq); + free_irq(pdev->irq, dm1105dvb); + pci_iounmap(pdev, dm1105dvb->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(dm1105dvb); +} + +static struct pci_device_id dm1105_id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_TRIGEM, + .device = PCI_DEVICE_ID_DM1105, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_DEVICE_ID_DW2002, + }, { + .vendor = PCI_VENDOR_ID_TRIGEM, + .device = PCI_DEVICE_ID_DM1105, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_DEVICE_ID_DW2004, + }, { + /* empty */ + }, +}; + +MODULE_DEVICE_TABLE(pci, dm1105_id_table); + +static struct pci_driver dm1105_driver = { + .name = DRIVER_NAME, + .id_table = dm1105_id_table, + .probe = dm1105_probe, + .remove = __devexit_p(dm1105_remove), +}; + +static int __init dm1105_init(void) +{ + return pci_register_driver(&dm1105_driver); +} + +static void __exit dm1105_exit(void) +{ + pci_unregister_driver(&dm1105_driver); +} + +module_init(dm1105_init); +module_exit(dm1105_exit); + +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_DESCRIPTION("SDMC DM1105 DVB driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 490c868408bc57a756550148313ac8582fe501ef Mon Sep 17 00:00:00 2001 From: Darron Broad Date: Sat, 13 Sep 2008 19:42:16 -0300 Subject: V4L/DVB (9011): S2API: A number of cleanusp from the last 24 months. I was given these changes by Darron Broad and Igor Liplianin and represent a series of patches they've been making to the cx24116 driver over the last two years. Changes for handling symbolrates >30Ksps Tone handling changes. Diseqc support. Sleep support, shutting down the clocks correctly. Cleanup on ROLL_OFF and PILOT support. *** ST - We need to cleanup the sysclt control, this is abnormal in a demod driver. We should work towards understanding the missing API's and ensure we have them in S2API. *** Signed-off-by: Steven Toth Signed-off-by: Darron Broad Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 808 ++++++++++++++++++++++++++-------- 1 file changed, 617 insertions(+), 191 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 0ac2c5493087..cfb265de5229 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -2,6 +2,18 @@ Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver Copyright (C) 2006-2008 Steven Toth + Copyright (C) 2006-2007 Georg Acher + Copyright (C) 2007-2008 Darron Broad + March 2007 + Fixed some bugs. + Added diseqc support. + Added corrected signal strength support. + August 2007 + Sync with legacy version. + Some clean ups. + Copyright (C) 2008 Igor Liplianin + September, 9th 2008 + Fixed locking on high symbol rates (>30000). 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 @@ -18,51 +30,69 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - * Updates by Darron Broad 2007. - * - * March - * Fixed some bugs. - * Added diseqc support. - * Added corrected signal strength support. - * - * August - * Sync with legacy version. - * Some clean ups. - */ -/* Updates by Igor Liplianin - * - * September, 9th 2008 - * Fixed locking on high symbol rates (>30000). - */ - #include #include #include #include #include #include +#include #include "dvb_frontend.h" #include "cx24116.h" -/* - * Fetch firmware in the following manner. - * - * #!/bin/sh - * wget ftp://167.206.143.11/outgoing/Oxford/88x_2_117_24275_1_INF.zip - * unzip 88x_2_117_24275_1_INF.zip - * dd if=Driver88/hcw88bda.sys of=dvb-fe-cx24116.fw skip=81768 bs=1 count=32522 - */ +static int debug = 0; +#define dprintk(args...) \ + do { \ + if (debug) printk ("cx24116: " args); \ + } while (0) + #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" #define CX24116_SEARCH_RANGE_KHZ 5000 -/* registers (TO BE COMPLETED) */ -#define CX24116_REG_SIGNAL (0xd5) +/* known registers */ +#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */ +#define CX24116_REG_EXECUTE (0x1f) /* execute command */ +#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */ +#define CX24116_REG_RESET (0x20) /* reset status > 0 */ +#define CX24116_REG_SIGNAL (0x9e) /* signal low */ +#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ +#define CX24116_REG_QSTATUS (0xbc) +#define CX24116_REG_QUALITY (0xd5) +#define CX24116_REG_BER0 (0xc9) +#define CX24116_REG_BER8 (0xc8) +#define CX24116_REG_BER16 (0xc7) +#define CX24116_REG_BER24 (0xc6) +#define CX24116_REG_UCB0 (0xcb) +#define CX24116_REG_UCB8 (0xca) +#define CX24116_REG_CLKDIV (0xf3) +#define CX24116_REG_RATEDIV (0xf9) /* arg buffer size */ #define CX24116_ARGLEN (0x1e) +/* rolloff */ +#define CX24116_ROLLOFF_020 (0x00) +#define CX24116_ROLLOFF_025 (0x01) +#define CX24116_ROLLOFF_035 (0x02) + +/* pilot bit */ +#define CX24116_PILOT (0x40) + +/* signal status */ +#define CX24116_HAS_SIGNAL (0x01) +#define CX24116_HAS_CARRIER (0x02) +#define CX24116_HAS_VITERBI (0x04) +#define CX24116_HAS_SYNCLOCK (0x08) +#define CX24116_HAS_UNKNOWN1 (0x10) +#define CX24116_HAS_UNKNOWN2 (0x20) +#define CX24116_STATUS_MASK (0x3f) +#define CX24116_SIGNAL_MASK (0xc0) + +#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ +#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */ +#define CX24116_DISEQC_MESGCACHE (2) /* message cached */ + /* arg offset for DiSEqC */ #define CX24116_DISEQC_BURST (1) #define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ @@ -75,21 +105,88 @@ #define CX24116_DISEQC_MINI_A (0) #define CX24116_DISEQC_MINI_B (1) -static int debug = 0; -#define dprintk(args...) \ - do { \ - if (debug) printk ("cx24116: " args); \ - } while (0) +/* DiSEqC tone burst */ +static int toneburst = 1; + +/* debug & toneburst sysctl */ +static struct ctl_table_header *kernel_table_header; +static ctl_table toneburst_table[] = { +{ + .ctl_name = 0, + .procname = "toneburst", + .data = &toneburst, + .maxlen = sizeof(int), + .mode = 0666, + .child = NULL, + .parent = NULL, + .proc_handler = &proc_dointvec, + .strategy = NULL, + .extra1 = NULL, + .extra2 = NULL, +}, +{ + .ctl_name = 0, + .procname = "debug", + .data = &debug, + .maxlen = sizeof(int), + .mode = 0666, + .child = NULL, + .parent = NULL, + .proc_handler = &proc_dointvec, + .strategy = NULL, + .extra1 = NULL, + .extra2 = NULL, + }, + {0}, +}; +static ctl_table cx24116_table[] = { +{ + .ctl_name = 0, + .procname = "cx24116", + .data = NULL, + .maxlen = 0, + .mode = 0555, + .child = toneburst_table, + .parent = NULL, + .proc_handler = NULL, + .strategy = NULL, + .extra1 = NULL, + .extra2 = NULL, + }, + {0}, +}; +static ctl_table kernel_table[] = { +{ + .ctl_name = CTL_DEV, + .procname = "dev", + .data = NULL, + .maxlen = 0, + .mode = 0555, + .child = cx24116_table, + .parent = NULL, + .proc_handler = NULL, + .strategy = NULL, + .extra1 = NULL, + .extra2 = NULL, + }, + {0}, +}; enum cmds { - CMD_INIT_CMD10 = 0x10, + CMD_SET_VCO = 0x10, CMD_TUNEREQUEST = 0x11, - CMD_INIT_CMD13 = 0x13, - CMD_INIT_CMD14 = 0x14, - CMD_SEND_DISEQC = 0x21, + CMD_MPEGCONFIG = 0x13, + CMD_TUNERINIT = 0x14, + CMD_BANDWIDTH = 0x15, + CMD_GETAGC = 0x19, + CMD_LNBCONFIG = 0x20, + CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ CMD_SET_TONEPRE = 0x22, CMD_SET_TONE = 0x23, + CMD_UPDFWVERS = 0x35, + CMD_TUNERSLEEP = 0x36, + CMD_AGCCONTROL = 0x3b, /* Unknown */ }; /* The Demod/Tuner can't easily provide these, we cache them */ @@ -101,11 +198,14 @@ struct cx24116_tuning fe_code_rate_t fec; fe_modulation_t modulation; + fe_pilot_t pilot; + fe_rolloff_t rolloff; /* Demod values */ u8 fec_val; u8 fec_mask; u8 inversion_val; + u8 rolloff_val; }; /* Basic commands that are sent to the firmware */ @@ -127,6 +227,7 @@ struct cx24116_state u8 skip_fw_load; u8 burst; + struct cx24116_cmd dsec_cmd; }; static int cx24116_writereg(struct cx24116_state* state, int reg, int data) @@ -233,6 +334,66 @@ static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_invers return 0; } +/* + * modfec (modulation and FEC) + * =========================== + * + * MOD FEC mask/val standard + * ---- -------- ----------- -------- + * QPSK FEC_1_2 0x02 0x02+X DVB-S + * QPSK FEC_2_3 0x04 0x02+X DVB-S + * QPSK FEC_3_4 0x08 0x02+X DVB-S + * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) + * QPSK FEC_5_6 0x20 0x02+X DVB-S + * QPSK FEC_6_7 0x40 0x02+X DVB-S + * QPSK FEC_7_8 0x80 0x02+X DVB-S + * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) + * QPSK AUTO 0xff 0x02+X DVB-S + * + * For DVB-S high byte probably represents FEC + * and low byte selects the modulator. The high + * byte is search range mask. Bit 5 may turn + * on DVB-S and remaining bits represent some + * kind of calibration (how/what i do not know). + * + * Eg.(2/3) szap "Zone Horror" + * + * mask/val = 0x04, 0x20 + * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK + * + * mask/val = 0x04, 0x30 + * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK + * + * After tuning FECSTATUS contains actual FEC + * in use numbered 1 through to 8 for 1/2 .. 2/3 etc + * + * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) + * + * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 + * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 + * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 + * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 + * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 + * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 + * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 + * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 + * + * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 + * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 + * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 + * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 + * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 + * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 + * + * For DVB-S2 low bytes selects both modulator + * and FEC. High byte is meaningless here. To + * set pilot, bit 6 (0x40) is set. When inspecting + * FECSTATUS bit 7 (0x80) represents the pilot + * selection whilst not tuned. When tuned, actual FEC + * in use is found in FECSTATUS as per above. Pilot + * value is reset. + */ + /* A table of modulation, fec and configuration bytes for the demod. * Not all S2 mmodulation schemes are support and not all rates with * a scheme are support. Especially, no auto detect when in S2 mode. @@ -244,15 +405,17 @@ struct cx24116_modfec { u8 val; /* Passed to the firmware to indicate mode selection */ } CX24116_MODFEC_MODES[] = { /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ + + /*mod fec mask val */ { QPSK, FEC_NONE, 0xfe, 0x30 }, - { QPSK, FEC_1_2, 0x02, 0x2e }, - { QPSK, FEC_2_3, 0x04, 0x2f }, - { QPSK, FEC_3_4, 0x08, 0x30 }, - { QPSK, FEC_4_5, 0xfe, 0x30 }, - { QPSK, FEC_5_6, 0x20, 0x31 }, - { QPSK, FEC_6_7, 0xfe, 0x30 }, - { QPSK, FEC_7_8, 0x80, 0x32 }, - { QPSK, FEC_8_9, 0xfe, 0x30 }, + { QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ + { QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ + { QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ + { QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ + { QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ + { QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ + { QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ + { QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ { QPSK, FEC_AUTO, 0xfe, 0x30 }, /* NBC-QPSK */ { NBC_QPSK, FEC_1_2, 0x00, 0x04 }, @@ -268,7 +431,12 @@ struct cx24116_modfec { { _8PSK, FEC_2_3, 0x00, 0x0d }, { _8PSK, FEC_3_4, 0x00, 0x0e }, { _8PSK, FEC_5_6, 0x00, 0x0f }, + { _8PSK, FEC_8_9, 0x00, 0x10 }, { _8PSK, FEC_9_10, 0x00, 0x11 }, + /* + * `val' can be found in the FECSTATUS register when tuning. + * FECSTATUS will give the actual FEC in use if tuning was successful. + */ }; static int cx24116_lookup_fecmod(struct cx24116_state* state, @@ -276,6 +444,8 @@ static int cx24116_lookup_fecmod(struct cx24116_state* state, { int i, ret = -EOPNOTSUPP; + dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); + for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++) { if( (m == CX24116_MODFEC_MODES[i].modulation) && @@ -292,37 +462,38 @@ static int cx24116_lookup_fecmod(struct cx24116_state* state, static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec) { int ret = 0; - dprintk("%s()\n", __func__); + + dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); ret = cx24116_lookup_fecmod(state, mod, fec); if(ret < 0) return ret; + state->dnxt.fec = fec; state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; - dprintk("%s() fec_val/mask = 0x%02x/0x%02x\n", __func__, - state->dnxt.fec_val, state->dnxt.fec_mask); + dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__, + state->dnxt.fec_mask, state->dnxt.fec_val); return 0; } static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate) { - int ret = 0; + dprintk("%s(%d)\n", __func__, rate); - dprintk("%s()\n", __func__); + /* check if symbol rate is within limits */ + if ((rate > state->frontend.ops.info.symbol_rate_max) || + (rate < state->frontend.ops.info.symbol_rate_min)) { + dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate); + return -EOPNOTSUPP; + } state->dnxt.symbol_rate = rate; + dprintk("%s() symbol_rate = %d\n", __func__, rate); - dprintk("%s() symbol_rate = %d\n", __func__, state->dnxt.symbol_rate); - - /* check if symbol rate is within limits */ - if ((state->dnxt.symbol_rate > state->frontend.ops.info.symbol_rate_max) || - (state->dnxt.symbol_rate < state->frontend.ops.info.symbol_rate_min)) - ret = -EOPNOTSUPP; - - return ret; + return 0; } static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw); @@ -392,8 +563,8 @@ static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd) } /* Start execution and wait for cmd to terminate */ - cx24116_writereg(state, 0x1f, 0x01); - while( cx24116_readreg(state, 0x1f) ) + cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); + while( cx24116_readreg(state, CX24116_REG_EXECUTE) ) { msleep(10); if(i++ > 64) @@ -410,7 +581,8 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware { struct cx24116_state* state = fe->demodulator_priv; struct cx24116_cmd cmd; - int ret; + int i, ret; + unsigned char vers[4]; dprintk("%s\n", __func__); dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n" @@ -427,11 +599,21 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware /* Begin the firmware load process */ /* Prepare the demod, load the firmware, cleanup after load */ + + /* Init PLL */ + cx24116_writereg(state, 0xE5, 0x00); cx24116_writereg(state, 0xF1, 0x08); - cx24116_writereg(state, 0xF2, cx24116_readreg(state, 0xF2) | 0x03); - cx24116_writereg(state, 0xF3, 0x46); - cx24116_writereg(state, 0xF9, 0x00); + cx24116_writereg(state, 0xF2, 0x13); + + /* Start PLL */ + cx24116_writereg(state, 0xe0, 0x03); + cx24116_writereg(state, 0xe0, 0x00); + + /* Unknown */ + cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); + cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); + /* Unknown */ cx24116_writereg(state, 0xF0, 0x03); cx24116_writereg(state, 0xF4, 0x81); cx24116_writereg(state, 0xF5, 0x00); @@ -444,8 +626,8 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware cx24116_writereg(state, 0xF0, 0x00); cx24116_writereg(state, 0xF8, 0x06); - /* Firmware CMD 10: Chip config? */ - cmd.args[0x00] = CMD_INIT_CMD10; + /* Firmware CMD 10: VCO config */ + cmd.args[0x00] = CMD_SET_VCO; cmd.args[0x01] = 0x05; cmd.args[0x02] = 0xdc; cmd.args[0x03] = 0xda; @@ -460,10 +642,10 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware if (ret != 0) return ret; - cx24116_writereg(state, 0x9d, 0x00); + cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00); - /* Firmware CMD 14: Unknown */ - cmd.args[0x00] = CMD_INIT_CMD14; + /* Firmware CMD 14: Tuner config */ + cmd.args[0x00] = CMD_TUNERINIT; cmd.args[0x01] = 0x00; cmd.args[0x02] = 0x00; cmd.len= 0x03; @@ -473,8 +655,8 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware cx24116_writereg(state, 0xe5, 0x00); - /* Firmware CMD 13: Unknown - Firmware config? */ - cmd.args[0x00] = CMD_INIT_CMD13; + /* Firmware CMD 13: MPEG config */ + cmd.args[0x00] = CMD_MPEGCONFIG; cmd.args[0x01] = 0x01; cmd.args[0x02] = 0x75; cmd.args[0x03] = 0x00; @@ -488,6 +670,19 @@ static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware if (ret != 0) return ret; + /* Firmware CMD 35: Get firmware version */ + cmd.args[0x00] = CMD_UPDFWVERS; + cmd.len= 0x02; + for(i=0; i<4; i++) { + cmd.args[0x01] = i; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX); + } + printk("%s: FW version %i.%i.%i.%i\n", __func__, + vers[0], vers[1], vers[2], vers[3]); + return 0; } @@ -503,75 +698,98 @@ static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct cx24116_state *state = fe->demodulator_priv; - int lock = cx24116_readreg(state, 0x9d); + int lock = cx24116_readreg(state, CX24116_REG_SSTATUS); dprintk("%s: status = 0x%02x\n", __func__, lock); *status = 0; - if (lock & 0x01) + if (lock & CX24116_HAS_SIGNAL) *status |= FE_HAS_SIGNAL; - if (lock & 0x02) + if (lock & CX24116_HAS_CARRIER) *status |= FE_HAS_CARRIER; - if (lock & 0x04) + if (lock & CX24116_HAS_VITERBI) *status |= FE_HAS_VITERBI; - if (lock & 0x08) + if (lock & CX24116_HAS_SYNCLOCK) *status |= FE_HAS_SYNC | FE_HAS_LOCK; return 0; } -/* TODO: Not clear how we do this */ static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber) { - //struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); - *ber = 0; + + *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) | + ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) | + ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) | + cx24116_readreg(state, CX24116_REG_BER0 ); return 0; } -/* Signal strength (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ +/* TODO Determine function and scale appropriately */ static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { struct cx24116_state *state = fe->demodulator_priv; - u8 strength_reg; - static const u32 strength_tab[] = { /* 10 x Table (rounded up) */ - 0x00000,0x0199A,0x03333,0x04ccD,0x06667,0x08000,0x0999A,0x0b333,0x0cccD,0x0e667, - 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 }; + struct cx24116_cmd cmd; + int ret; + u16 sig_reading; dprintk("%s()\n", __func__); - strength_reg = cx24116_readreg(state, CX24116_REG_SIGNAL); + /* Firmware CMD 19: Get AGC */ + cmd.args[0x00] = CMD_GETAGC; + cmd.len= 0x01; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; - if(strength_reg < 0xa0) - *signal_strength = strength_tab [ ( strength_reg & 0xf0 ) >> 4 ] + - ( strength_tab [ ( strength_reg & 0x0f ) ] >> 4 ); - else - *signal_strength = 0xffff; + sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) | + ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 ); + *signal_strength= 0 - sig_reading; - dprintk("%s: Signal strength (raw / cooked) = (0x%02x / 0x%04x)\n", - __func__,strength_reg,*signal_strength); + dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength); return 0; } -/* TODO: Not clear how we do this */ +/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) { - //struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_state *state = fe->demodulator_priv; + u8 snr_reading; + static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ + 0x00000,0x0199A,0x03333,0x04ccD,0x06667, + 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667, + 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 }; + dprintk("%s()\n", __func__); - *snr = 0; + + snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY); + + if(snr_reading >= 0xa0 /* 100% */) + *snr = 0xffff; + else + *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] + + ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 ); + + dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, + snr_reading, *snr); return 0; } -/* TODO: Not clear how we do this */ static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - //struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_state *state = fe->demodulator_priv; + dprintk("%s()\n", __func__); - *ucblocks = 0; + + *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) | + cx24116_readreg(state, CX24116_REG_UCB0); return 0; } @@ -583,6 +801,27 @@ static void cx24116_clone_params(struct dvb_frontend* fe) memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); } +/* Wait for LNB */ +static int cx24116_wait_for_lnb(struct dvb_frontend* fe) +{ + struct cx24116_state *state = fe->demodulator_priv; + int i; + + dprintk("%s() qstatus = 0x%02x\n", __func__, + cx24116_readreg(state, CX24116_REG_QSTATUS)); + + /* Wait for up to 300 ms */ + for(i = 0; i < 30 ; i++) { + if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) + return 0; + msleep(10); + } + + dprintk("%s(): LNB not ready\n", __func__); + + return -ETIMEDOUT; /* -EBUSY ? */ +} + static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { struct cx24116_cmd cmd; @@ -594,6 +833,14 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) return -EINVAL; } + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if(ret != 0) + return ret; + + /* Min delay time after DiSEqC send */ + msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ + /* This is always done before the tone is set */ cmd.args[0x00] = CMD_SET_TONEPRE; cmd.args[0x01] = 0x00; @@ -619,6 +866,9 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) } cmd.len= 0x04; + /* Min delay time before DiSEqC send */ + msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ + return cx24116_cmd_execute(fe, &cmd); } @@ -626,9 +876,39 @@ static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) static int cx24116_diseqc_init(struct dvb_frontend* fe) { struct cx24116_state *state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + + /* Firmware CMD 20: LNB/DiSEqC config */ + cmd.args[0x00] = CMD_LNBCONFIG; + cmd.args[0x01] = 0x00; + cmd.args[0x02] = 0x10; + cmd.args[0x03] = 0x00; + cmd.args[0x04] = 0x8f; + cmd.args[0x05] = 0x28; + cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; + cmd.args[0x07] = 0x01; + cmd.len= 0x08; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + + /* Prepare a DiSEqC command */ + state->dsec_cmd.args[0x00] = CMD_LNBSEND; + + /* DiSEqC burst */ + state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; + + /* Unknown */ + state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; + state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; + state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */ - /* Default DiSEqC burst state */ - state->burst = CX24116_DISEQC_MINI_A; + /* DiSEqC message length */ + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; + + /* Command length */ + state->dsec_cmd.len= CX24116_DISEQC_MSGOFS; return 0; } @@ -637,7 +917,6 @@ static int cx24116_diseqc_init(struct dvb_frontend* fe) static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d) { struct cx24116_state *state = fe->demodulator_priv; - struct cx24116_cmd cmd; int i, ret; /* Dump DiSEqC message */ @@ -647,82 +926,134 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma printk("0x%02x", d->msg[i]); if(++i < d->msg_len) printk(", "); - } - printk(")\n"); + } + printk(") toneburst=%d\n", toneburst); } + /* Validate length */ if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) return -EINVAL; - cmd.args[0x00] = CMD_SEND_DISEQC; - cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; - cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; - cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; - /* DiSEqC message */ for (i = 0; i < d->msg_len; i++) - cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; + state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; + + /* DiSEqC message length */ + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; + + /* Command length */ + state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; + + /* DiSEqC toneburst */ + if(toneburst == CX24116_DISEQC_MESGCACHE) + /* Message is cached */ + return 0; + + else if(toneburst == CX24116_DISEQC_TONEOFF) + /* Message is sent without burst */ + state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; + + else if(toneburst == CX24116_DISEQC_TONECACHE) { + /* + * Message is sent with derived else cached burst + * + * WRITE PORT GROUP COMMAND 38 + * + * 0/A/A: E0 10 38 F0..F3 + * 1/B/B: E0 10 38 F4..F7 + * 2/C/A: E0 10 38 F8..FB + * 3/D/B: E0 10 38 FC..FF + * + * datebyte[3]= 8421:8421 + * ABCD:WXYZ + * CLR :SET + * + * WX= PORT SELECT 0..3 (X=TONEBURST) + * Y = VOLTAGE (0=13V, 1=18V) + * Z = BAND (0=LOW, 1=HIGH(22K)) + */ + if(d->msg_len >= 4 && d->msg[2] == 0x38) + state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2); + if(debug) + dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]); + } - /* Hack: Derive burst from command else use previous burst */ - if(d->msg_len >= 4 && d->msg[2] == 0x38) - cmd.args[CX24116_DISEQC_BURST] = (d->msg[3] >> 2) & 1; - else - cmd.args[CX24116_DISEQC_BURST] = state->burst; + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if(ret != 0) + return ret; - cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; - cmd.len = CX24116_DISEQC_MSGOFS + d->msg_len; + /* Wait for voltage/min repeat delay */ + msleep(100); - ret = cx24116_cmd_execute(fe, &cmd); - - /* Firmware command duration is unknown, so guess... + /* Command */ + ret = cx24116_cmd_execute(fe, &state->dsec_cmd); + if(ret != 0) + return ret; + /* + * Wait for send * * Eutelsat spec: - * >15ms delay + - * 13.5ms per byte + - * >15ms delay + - * 12.5ms burst + - * >15ms delay + * >15ms delay + (XXX determine if FW does this, see set_tone) + * 13.5ms per byte + + * >15ms delay + + * 12.5ms burst + + * >15ms delay (XXX determine if FW does this, see set_tone) */ - if(ret == 0) - msleep( (cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 ); + msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) ); - return ret; + return 0; } /* Send DiSEqC burst */ static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { struct cx24116_state *state = fe->demodulator_priv; - struct cx24116_cmd cmd; int ret; - dprintk("%s(%d)\n",__func__,(int)burst); - - cmd.args[0x00] = CMD_SEND_DISEQC; - cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; - cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; - cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; + dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst); + /* DiSEqC burst */ if (burst == SEC_MINI_A) - cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; + state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; else if(burst == SEC_MINI_B) - cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B; + state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B; else return -EINVAL; - /* Cache as previous burst state */ - state->burst= cmd.args[CX24116_DISEQC_BURST]; + /* DiSEqC toneburst */ + if(toneburst != CX24116_DISEQC_MESGCACHE) + /* Burst is cached */ + return 0; - cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; - cmd.len= CX24116_DISEQC_MSGOFS; + /* Burst is to be sent with cached message */ - ret= cx24116_cmd_execute(fe, &cmd); + /* Wait for LNB ready */ + ret = cx24116_wait_for_lnb(fe); + if(ret != 0) + return ret; - /* Firmware command duration is unknown, so guess... */ - if(ret == 0) - msleep(60); + /* Wait for voltage/min repeat delay */ + msleep(100); - return ret; + /* Command */ + ret = cx24116_cmd_execute(fe, &state->dsec_cmd); + if(ret != 0) + return ret; + + /* + * Wait for send + * + * Eutelsat spec: + * >15ms delay + (XXX determine if FW does this, see set_tone) + * 13.5ms per byte + + * >15ms delay + + * 12.5ms burst + + * >15ms delay (XXX determine if FW does this, see set_tone) + */ + msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 ); + + return 0; } static void cx24116_release(struct dvb_frontend* fe) @@ -730,6 +1061,7 @@ static void cx24116_release(struct dvb_frontend* fe) struct cx24116_state* state = fe->demodulator_priv; dprintk("%s\n",__func__); kfree(state); + unregister_sysctl_table(kernel_table_header); } static struct dvb_frontend_ops cx24116_ops; @@ -742,11 +1074,15 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, dprintk("%s\n",__func__); + kernel_table_header = register_sysctl_table(kernel_table); + if(!kernel_table_header) + goto error1; + /* allocate memory for the internal state */ state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL); if (state == NULL) { printk("Unable to kmalloc\n"); - goto error; + goto error2; } /* setup the state */ @@ -759,7 +1095,7 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); if (ret != 0x0501) { printk("Invalid probe, probably not a CX24116 device\n"); - goto error; + goto error3; } /* create dvb_frontend */ @@ -767,33 +1103,64 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, state->frontend.demodulator_priv = state; return &state->frontend; -error: - kfree(state); - - return NULL; +error3: kfree(state); +error2: unregister_sysctl_table(kernel_table_header); +error1: return NULL; } - -static int cx24116_get_params(struct dvb_frontend* fe) +/* + * Initialise or wake up device + * + * Power config will reset and load initial firmware if required + */ +static int cx24116_initfe(struct dvb_frontend* fe) { - struct cx24116_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *cache = &fe->dtv_property_cache; + struct cx24116_state* state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; dprintk("%s()\n",__func__); - cache->frequency = state->dcur.frequency; - cache->inversion = state->dcur.inversion; - cache->modulation = state->dcur.modulation; - cache->fec_inner = state->dcur.fec; - cache->symbol_rate = state->dcur.symbol_rate; + /* Power on */ + cx24116_writereg(state, 0xe0, 0); + cx24116_writereg(state, 0xe1, 0); + cx24116_writereg(state, 0xea, 0); - return 0; + /* Firmware CMD 36: Power config */ + cmd.args[0x00] = CMD_TUNERSLEEP; + cmd.args[0x01] = 0; + cmd.len= 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if(ret != 0) + return ret; + + return cx24116_diseqc_init(fe); } -static int cx24116_initfe(struct dvb_frontend* fe) +/* + * Put device to sleep + */ +static int cx24116_sleep(struct dvb_frontend* fe) { + struct cx24116_state* state = fe->demodulator_priv; + struct cx24116_cmd cmd; + int ret; + dprintk("%s()\n",__func__); - return cx24116_diseqc_init(fe); + /* Firmware CMD 36: Power config */ + cmd.args[0x00] = CMD_TUNERSLEEP; + cmd.args[0x01] = 1; + cmd.len= 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if(ret != 0) + return ret; + + /* Power off (Shutdown clocks) */ + cx24116_writereg(state, 0xea, 0xff); + cx24116_writereg(state, 0xe1, 1); + cx24116_writereg(state, 0xe0, 1); + + return 0; } static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp) @@ -817,14 +1184,45 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24116_cmd cmd; fe_status_t tunerstat; - int ret, above30msps; - u8 retune=4; + int i, status, ret, retune = 1; dprintk("%s()\n",__func__); state->dnxt.modulation = c->modulation; state->dnxt.frequency = c->frequency; + switch(c->delivery_system) { + case SYS_DVBS: + dprintk("%s: DVB-S delivery system selected\n",__func__); + state->dnxt.pilot = PILOT_OFF; + state->dnxt.rolloff = CX24116_ROLLOFF_035; + break; + case SYS_DVBS2: + dprintk("%s: DVB-S2 delivery system selected\n",__func__); + if(c->pilot == PILOT_AUTO) + retune++; + state->dnxt.pilot = c->pilot; + switch(c->rolloff) { + case ROLLOFF_20: + state->dnxt.rolloff_val= CX24116_ROLLOFF_020; + break; + case ROLLOFF_25: + state->dnxt.rolloff_val= CX24116_ROLLOFF_025; + break; + case ROLLOFF_35: + state->dnxt.rolloff_val= CX24116_ROLLOFF_035; + break; + case ROLLOFF_AUTO: + return -EOPNOTSUPP; + } + state->dnxt.rolloff = c->rolloff; + break; + default: + dprintk("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) return ret; @@ -837,6 +1235,9 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* discard the 'current' tuning parameters and prepare to tune */ cx24116_clone_params(fe); + dprintk("%s: retune = %d\n", __func__, retune); + dprintk("%s: rolloff = %d\n", __func__, state->dcur.rolloff); + dprintk("%s: pilot = %d\n", __func__, state->dcur.pilot); dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, @@ -844,18 +1245,17 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, state->dcur.inversion, state->dcur.inversion_val); + /* This is also done in advise/acquire on HVR4000 but not on LITE */ if (state->config->set_ts_params) state->config->set_ts_params(fe, 0); - above30msps = (state->dcur.symbol_rate > 30000000); - - if (above30msps){ - cx24116_writereg(state, 0xF9, 0x01); - cx24116_writereg(state, 0xF3, 0x44); - } else { - cx24116_writereg(state, 0xF9, 0x00); - cx24116_writereg(state, 0xF3, 0x46); - } + /* Set/Reset B/W */ + cmd.args[0x00] = CMD_BANDWIDTH; + cmd.args[0x01] = 0x01; + cmd.len= 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; /* Prepare a tune request */ cmd.args[0x00] = CMD_TUNEREQUEST; @@ -875,28 +1275,32 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* Modulation / FEC & Pilot Off */ cmd.args[0x07] = state->dcur.fec_val; - if (c->pilot == PILOT_ON) - cmd.args[0x07] |= 0x40; + if (state->dcur.pilot == PILOT_ON) + cmd.args[0x07] |= CX24116_PILOT; cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; cmd.args[0x0a] = 0x00; cmd.args[0x0b] = 0x00; - cmd.args[0x0c] = 0x02; + cmd.args[0x0c] = state->dcur.rolloff_val; cmd.args[0x0d] = state->dcur.fec_mask; - if (above30msps){ + if (state->dcur.symbol_rate > 30000000) { cmd.args[0x0e] = 0x04; cmd.args[0x0f] = 0x00; cmd.args[0x10] = 0x01; cmd.args[0x11] = 0x77; cmd.args[0x12] = 0x36; + cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44); + cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01); } else { cmd.args[0x0e] = 0x06; cmd.args[0x0f] = 0x00; cmd.args[0x10] = 0x00; cmd.args[0x11] = 0xFA; cmd.args[0x12] = 0x24; + cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); + cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); } cmd.len= 0x13; @@ -906,29 +1310,47 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par * the demod does not support autodetect. */ do { - /* Reset status register? */ - cx24116_writereg(state, 0x9d, 0xc1); + /* Reset status register */ + status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK; + cx24116_writereg(state, CX24116_REG_SSTATUS, status); /* Tune */ ret = cx24116_cmd_execute(fe, &cmd); if( ret != 0 ) break; - /* The hardware can take time to lock, wait a while */ - msleep(500); - - cx24116_read_status(fe, &tunerstat); - if(tunerstat & FE_HAS_SIGNAL) { - if(tunerstat & FE_HAS_SYNC) - /* Tuned */ - break; - else if(c->pilot == PILOT_AUTO) - /* Toggle pilot bit */ - cmd.args[0x07] ^= 0x40; + /* + * Wait for up to 500 ms before retrying + * + * If we are able to tune then generally it occurs within 100ms. + * If it takes longer, try a different toneburst setting. + */ + for(i = 0; i < 50 ; i++) { + cx24116_read_status(fe, &tunerstat); + status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); + if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { + dprintk("%s: Tuned\n",__func__); + goto tuned; + } + msleep(10); } + + dprintk("%s: Not tuned\n",__func__); + + /* Toggle pilot bit when in auto-pilot */ + if(state->dcur.pilot == PILOT_AUTO) + cmd.args[0x07] ^= CX24116_PILOT; } while(--retune); +tuned: /* Set/Reset B/W */ + cmd.args[0x00] = CMD_BANDWIDTH; + cmd.args[0x01] = 0x00; + cmd.len= 0x02; + ret = cx24116_cmd_execute(fe, &cmd); + if (ret != 0) + return ret; + return ret; } @@ -953,6 +1375,7 @@ static struct dvb_frontend_ops cx24116_ops = { .release = cx24116_release, .init = cx24116_initfe, + .sleep = cx24116_sleep, .read_status = cx24116_read_status, .read_ber = cx24116_read_ber, .read_signal_strength = cx24116_read_signal_strength, @@ -971,6 +1394,9 @@ static struct dvb_frontend_ops cx24116_ops = { module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); +module_param(toneburst, int, 0644); +MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); + MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 35d9c42779ef5e8cb46902bb6987443e136c0517 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sat, 13 Sep 2008 20:56:59 -0300 Subject: V4L/DVB (9012): Add support for DvbWorld 2004 DVB-S2 PCI adapter Add support for DvbWorld 2004 DVB-S2 PCI adapter. The card contains dm1105 PCI chip and cx24116 demodulator Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/Kconfig | 2 +- drivers/media/dvb/dm1105/Kconfig | 19 ++++++++++--------- drivers/media/dvb/dm1105/dm1105.c | 10 +++------- 3 files changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 5858744e70de..14488f644792 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -36,7 +36,7 @@ comment "Supported Pluto2 Adapters" source "drivers/media/dvb/pluto2/Kconfig" comment "Supported SDMC DM1105 Adapters" - depends on DVB_CORE && PCI && I2C + depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/dm1105/Kconfig" comment "Supported DVB Frontends" diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig index fc2ca7dca6b2..4b96bbba9f42 100644 --- a/drivers/media/dvb/dm1105/Kconfig +++ b/drivers/media/dvb/dm1105/Kconfig @@ -1,14 +1,15 @@ config DVB_DM1105 - tristate "SDMC DM1105 based PCI cards" - depends on DVB_CORE && PCI && I2C + tristate "SDMC DM1105 based PCI cards" + depends on DVB_CORE && PCI && I2C select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE - help - Support for cards based on the SDMC DM1105 PCI chip like - DvbWorld 2002 + select DVB_CX24116 if !DVB_FE_CUSTOMISE + help + Support for cards based on the SDMC DM1105 PCI chip like + DvbWorld 2002 - 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. + 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. - Say Y or M if you own such a device and want to use it. + Say Y or M if you own such a device and want to use it. diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index fe8d0e58c0ea..204763d2de41 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -41,8 +41,8 @@ #include "stv0299.h" /*#include "stv0288.h" *#include "si21xx.h" - *#include "stb6000.h" - *#include "cx24116.h"*/ + *#include "stb6000.h"*/ +#include "cx24116.h" #include "z0194a.h" /* ----------------------------------------------- */ @@ -605,11 +605,11 @@ static struct si21xx_config serit_config = { .min_delay_ms = 100, }; +#endif /* keep */ static struct cx24116_config serit_sp2633_config = { .demod_address = 0x55, }; -#endif /* keep */ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) { @@ -651,15 +651,11 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) #endif /* keep */ break; case PCI_DEVICE_ID_DW2004: -#if 0 dm1105dvb->fe = dvb_attach( cx24116_attach, &serit_sp2633_config, &dm1105dvb->i2c_adap); if (dm1105dvb->fe) dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; -#else /* keep */ - dev_err(&dm1105dvb->pdev->dev, "needs cx24116 module\n"); -#endif /* keep */ break; } -- cgit v1.2.1 From 7396d3ea94b871de66940ea27d4bf81513404990 Mon Sep 17 00:00:00 2001 From: Darron Broad Date: Sun, 14 Sep 2008 10:45:58 -0300 Subject: V4L/DVB (9013): S2API: cx24116 Rolloff changes, sysctls cleanup, isl power changes. Remove the debugging sysctls. Rolloff was broken, not it works as expected and has been tested in kaffeine. Power related changes for the isl6421 are not implemented on the HVR4000/4000LITE. Signed-off-by: Steven Toth Signed-off-by: Darron Broad Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 82 +++-------------------------------- 1 file changed, 6 insertions(+), 76 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index cfb265de5229..fdc741e7e769 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "dvb_frontend.h" #include "cx24116.h" @@ -108,70 +107,6 @@ static int debug = 0; /* DiSEqC tone burst */ static int toneburst = 1; -/* debug & toneburst sysctl */ -static struct ctl_table_header *kernel_table_header; -static ctl_table toneburst_table[] = { -{ - .ctl_name = 0, - .procname = "toneburst", - .data = &toneburst, - .maxlen = sizeof(int), - .mode = 0666, - .child = NULL, - .parent = NULL, - .proc_handler = &proc_dointvec, - .strategy = NULL, - .extra1 = NULL, - .extra2 = NULL, -}, -{ - .ctl_name = 0, - .procname = "debug", - .data = &debug, - .maxlen = sizeof(int), - .mode = 0666, - .child = NULL, - .parent = NULL, - .proc_handler = &proc_dointvec, - .strategy = NULL, - .extra1 = NULL, - .extra2 = NULL, - }, - {0}, -}; -static ctl_table cx24116_table[] = { -{ - .ctl_name = 0, - .procname = "cx24116", - .data = NULL, - .maxlen = 0, - .mode = 0555, - .child = toneburst_table, - .parent = NULL, - .proc_handler = NULL, - .strategy = NULL, - .extra1 = NULL, - .extra2 = NULL, - }, - {0}, -}; -static ctl_table kernel_table[] = { -{ - .ctl_name = CTL_DEV, - .procname = "dev", - .data = NULL, - .maxlen = 0, - .mode = 0555, - .child = cx24116_table, - .parent = NULL, - .proc_handler = NULL, - .strategy = NULL, - .extra1 = NULL, - .extra2 = NULL, - }, - {0}, -}; - enum cmds { CMD_SET_VCO = 0x10, @@ -964,7 +899,7 @@ static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma * 2/C/A: E0 10 38 F8..FB * 3/D/B: E0 10 38 FC..FF * - * datebyte[3]= 8421:8421 + * databyte[3]= 8421:8421 * ABCD:WXYZ * CLR :SET * @@ -1061,7 +996,6 @@ static void cx24116_release(struct dvb_frontend* fe) struct cx24116_state* state = fe->demodulator_priv; dprintk("%s\n",__func__); kfree(state); - unregister_sysctl_table(kernel_table_header); } static struct dvb_frontend_ops cx24116_ops; @@ -1074,15 +1008,11 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, dprintk("%s\n",__func__); - kernel_table_header = register_sysctl_table(kernel_table); - if(!kernel_table_header) - goto error1; - /* allocate memory for the internal state */ state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL); if (state == NULL) { printk("Unable to kmalloc\n"); - goto error2; + goto error1; } /* setup the state */ @@ -1095,7 +1025,7 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); if (ret != 0x0501) { printk("Invalid probe, probably not a CX24116 device\n"); - goto error3; + goto error2; } /* create dvb_frontend */ @@ -1103,8 +1033,7 @@ struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, state->frontend.demodulator_priv = state; return &state->frontend; -error3: kfree(state); -error2: unregister_sysctl_table(kernel_table_header); +error2: kfree(state); error1: return NULL; } /* @@ -1195,7 +1124,8 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par case SYS_DVBS: dprintk("%s: DVB-S delivery system selected\n",__func__); state->dnxt.pilot = PILOT_OFF; - state->dnxt.rolloff = CX24116_ROLLOFF_035; + state->dnxt.rolloff_val = CX24116_ROLLOFF_035; + state->dnxt.rolloff = c->rolloff; break; case SYS_DVBS2: dprintk("%s: DVB-S2 delivery system selected\n",__func__); -- cgit v1.2.1 From c063a48923525dcf20924eb8f1af3b22248f1e13 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 14 Sep 2008 07:43:53 -0300 Subject: V4L/DVB (9014): History update: MPEG initialization in cx24116. Adjust MPEG initialization in cx24116 in order to accomodate different MPEG CLK position and polarity in different cards. For example, HVR4000 uses 0x02 value, but DvbWorld & TeVii USB cards uses 0x01. Without it MPEG stream was broken on that cards for symbol rates > 30000 kSyms/s. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index fdc741e7e769..4ad86d84875f 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -13,7 +13,8 @@ Some clean ups. Copyright (C) 2008 Igor Liplianin September, 9th 2008 - Fixed locking on high symbol rates (>30000). + Fixed locking on high symbol rates (>30000). + Implement MPEG initialization parameter. 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 -- cgit v1.2.1 From 681faa0b7a1d67576df07e0ad55ca42b2eab174a Mon Sep 17 00:00:00 2001 From: Darron Broad Date: Mon, 22 Sep 2008 00:47:20 -0300 Subject: V4L/DVB (9015): S2API: cx24116 register description fixes. From the author: Here is a simple patch detailing some reverse engineered register detail lost in my latest merge. The comments in the code refer to this register but it is never defined. This corrects this. Signed-off-by: Steven Toth Signed-off-by: Darron Broad Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 4ad86d84875f..02ed4ef79c67 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -67,6 +67,13 @@ static int debug = 0; #define CX24116_REG_UCB8 (0xca) #define CX24116_REG_CLKDIV (0xf3) #define CX24116_REG_RATEDIV (0xf9) +#define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ + +/* FECSTATUS bits */ +#define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */ +#define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */ +#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ +#define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */ /* arg buffer size */ #define CX24116_ARGLEN (0x1e) -- cgit v1.2.1 From 04ad28c9916da709f38b1d43817892142c2c3508 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 16 Sep 2008 18:21:11 -0300 Subject: V4L/DVB (9017): Add support for Silicon Laboratories SI2109/2110 demodulators. Add support for Silicon Laboratories SI2109/2110 demodulator and cards with it, such as DvbWorld PCI2002. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dm1105/Kconfig | 1 + drivers/media/dvb/dm1105/dm1105.c | 7 +- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/si21xx.c | 974 +++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/si21xx.h | 37 ++ 6 files changed, 1023 insertions(+), 4 deletions(-) create mode 100644 drivers/media/dvb/frontends/si21xx.c create mode 100644 drivers/media/dvb/frontends/si21xx.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig index 4b96bbba9f42..2af5fffe138e 100644 --- a/drivers/media/dvb/dm1105/Kconfig +++ b/drivers/media/dvb/dm1105/Kconfig @@ -4,6 +4,7 @@ config DVB_DM1105 select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE help Support for cards based on the SDMC DM1105 PCI chip like DvbWorld 2002 diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 204763d2de41..0c1790fe2b56 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -40,8 +40,8 @@ #include "stv0299.h" /*#include "stv0288.h" - *#include "si21xx.h" *#include "stb6000.h"*/ +#include "si21xx.h" #include "cx24116.h" #include "z0194a.h" @@ -600,12 +600,12 @@ static struct stv0288_config earda_config = { .min_delay_ms = 100, }; +#endif /* keep */ static struct si21xx_config serit_config = { .demod_address = 0x68, .min_delay_ms = 100, }; -#endif /* keep */ static struct cx24116_config serit_sp2633_config = { .demod_address = 0x55, @@ -639,7 +639,7 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) &dm1105dvb->i2c_adap); } } - +#endif /* keep */ if (!dm1105dvb->fe) { dm1105dvb->fe = dvb_attach( si21xx_attach, &serit_config, @@ -648,7 +648,6 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage; } -#endif /* keep */ break; case PCI_DEVICE_ID_DW2004: dm1105dvb->fe = dvb_attach( diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index d2f31da26cbc..7697391ca86c 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -99,6 +99,13 @@ config DVB_CX24116 help A DVB-S/S2 tuner module. Say Y when you want to support this frontend. +config DVB_SI21XX + tristate "Silicon Labs SI21XX based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + comment "DVB-T (terrestrial) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 5deb8a542abd..c719b7fdce4a 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -52,3 +52,4 @@ obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o obj-$(CONFIG_DVB_AF9013) += af9013.o obj-$(CONFIG_DVB_CX24116) += cx24116.o +obj-$(CONFIG_DVB_SI21XX) += si21xx.o diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c new file mode 100644 index 000000000000..3ddbe69c45ce --- /dev/null +++ b/drivers/media/dvb/frontends/si21xx.c @@ -0,0 +1,974 @@ +/* DVB compliant Linux driver for the DVB-S si2109/2110 demodulator +* +* Copyright (C) 2008 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 Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "si21xx.h" + +#define REVISION_REG 0x00 +#define SYSTEM_MODE_REG 0x01 +#define TS_CTRL_REG_1 0x02 +#define TS_CTRL_REG_2 0x03 +#define PIN_CTRL_REG_1 0x04 +#define PIN_CTRL_REG_2 0x05 +#define LOCK_STATUS_REG_1 0x0f +#define LOCK_STATUS_REG_2 0x10 +#define ACQ_STATUS_REG 0x11 +#define ACQ_CTRL_REG_1 0x13 +#define ACQ_CTRL_REG_2 0x14 +#define PLL_DIVISOR_REG 0x15 +#define COARSE_TUNE_REG 0x16 +#define FINE_TUNE_REG_L 0x17 +#define FINE_TUNE_REG_H 0x18 + +#define ANALOG_AGC_POWER_LEVEL_REG 0x28 +#define CFO_ESTIMATOR_CTRL_REG_1 0x29 +#define CFO_ESTIMATOR_CTRL_REG_2 0x2a +#define CFO_ESTIMATOR_CTRL_REG_3 0x2b + +#define SYM_RATE_ESTIMATE_REG_L 0x31 +#define SYM_RATE_ESTIMATE_REG_M 0x32 +#define SYM_RATE_ESTIMATE_REG_H 0x33 + +#define CFO_ESTIMATOR_OFFSET_REG_L 0x36 +#define CFO_ESTIMATOR_OFFSET_REG_H 0x37 +#define CFO_ERROR_REG_L 0x38 +#define CFO_ERROR_REG_H 0x39 +#define SYM_RATE_ESTIMATOR_CTRL_REG 0x3a + +#define SYM_RATE_REG_L 0x3f +#define SYM_RATE_REG_M 0x40 +#define SYM_RATE_REG_H 0x41 +#define SYM_RATE_ESTIMATOR_MAXIMUM_REG 0x42 +#define SYM_RATE_ESTIMATOR_MINIMUM_REG 0x43 + +#define C_N_ESTIMATOR_CTRL_REG 0x7c +#define C_N_ESTIMATOR_THRSHLD_REG 0x7d +#define C_N_ESTIMATOR_LEVEL_REG_L 0x7e +#define C_N_ESTIMATOR_LEVEL_REG_H 0x7f + +#define BLIND_SCAN_CTRL_REG 0x80 + +#define LSA_CTRL_REG_1 0x8D +#define SPCTRM_TILT_CORR_THRSHLD_REG 0x8f +#define ONE_DB_BNDWDTH_THRSHLD_REG 0x90 +#define TWO_DB_BNDWDTH_THRSHLD_REG 0x91 +#define THREE_DB_BNDWDTH_THRSHLD_REG 0x92 +#define INBAND_POWER_THRSHLD_REG 0x93 +#define REF_NOISE_LVL_MRGN_THRSHLD_REG 0x94 + +#define VIT_SRCH_CTRL_REG_1 0xa0 +#define VIT_SRCH_CTRL_REG_2 0xa1 +#define VIT_SRCH_CTRL_REG_3 0xa2 +#define VIT_SRCH_STATUS_REG 0xa3 +#define VITERBI_BER_COUNT_REG_L 0xab +#define REED_SOLOMON_CTRL_REG 0xb0 +#define REED_SOLOMON_ERROR_COUNT_REG_L 0xb1 +#define PRBS_CTRL_REG 0xb5 + +#define LNB_CTRL_REG_1 0xc0 +#define LNB_CTRL_REG_2 0xc1 +#define LNB_CTRL_REG_3 0xc2 +#define LNB_CTRL_REG_4 0xc3 +#define LNB_CTRL_STATUS_REG 0xc4 +#define LNB_FIFO_REGS_0 0xc5 +#define LNB_FIFO_REGS_1 0xc6 +#define LNB_FIFO_REGS_2 0xc7 +#define LNB_FIFO_REGS_3 0xc8 +#define LNB_FIFO_REGS_4 0xc9 +#define LNB_FIFO_REGS_5 0xca +#define LNB_SUPPLY_CTRL_REG_1 0xcb +#define LNB_SUPPLY_CTRL_REG_2 0xcc +#define LNB_SUPPLY_CTRL_REG_3 0xcd +#define LNB_SUPPLY_CTRL_REG_4 0xce +#define LNB_SUPPLY_STATUS_REG 0xcf + +#define FALSE 0 +#define TRUE 1 +#define FAIL -1 +#define PASS 0 + +#define ALLOWABLE_FS_COUNT 10 +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "si21xx: " args); \ + } while (0) + +enum { + ACTIVE_HIGH, + ACTIVE_LOW +}; +enum { + BYTE_WIDE, + BIT_WIDE +}; +enum { + CLK_GAPPED_MODE, + CLK_CONTINUOUS_MODE +}; +enum { + RISING_EDGE, + FALLING_EDGE +}; +enum { + MSB_FIRST, + LSB_FIRST +}; +enum { + SERIAL, + PARALLEL +}; + +struct si21xx_state { + struct i2c_adapter *i2c; + const struct si21xx_config *config; + struct dvb_frontend frontend; + u8 initialised:1; + int errmode; + int fs; /*Sampling rate of the ADC in MHz*/ +}; + +/* register default initialization */ +static u8 serit_sp1511lhb_inittab[] = { + 0x01, 0x28, /* set i2c_inc_disable */ + 0x20, 0x03, + 0x27, 0x20, + 0xe0, 0x45, + 0xe1, 0x08, + 0xfe, 0x01, + 0x01, 0x28, + 0x89, 0x09, + 0x04, 0x80, + 0x05, 0x01, + 0x06, 0x00, + 0x20, 0x03, + 0x24, 0x88, + 0x29, 0x09, + 0x2a, 0x0f, + 0x2c, 0x10, + 0x2d, 0x19, + 0x2e, 0x08, + 0x2f, 0x10, + 0x30, 0x19, + 0x34, 0x20, + 0x35, 0x03, + 0x45, 0x02, + 0x46, 0x45, + 0x47, 0xd0, + 0x48, 0x00, + 0x49, 0x40, + 0x4a, 0x03, + 0x4c, 0xfd, + 0x4f, 0x2e, + 0x50, 0x2e, + 0x51, 0x10, + 0x52, 0x10, + 0x56, 0x92, + 0x59, 0x00, + 0x5a, 0x2d, + 0x5b, 0x33, + 0x5c, 0x1f, + 0x5f, 0x76, + 0x62, 0xc0, + 0x63, 0xc0, + 0x64, 0xf3, + 0x65, 0xf3, + 0x79, 0x40, + 0x6a, 0x40, + 0x6b, 0x0a, + 0x6c, 0x80, + 0x6d, 0x27, + 0x71, 0x06, + 0x75, 0x60, + 0x78, 0x00, + 0x79, 0xb5, + 0x7c, 0x05, + 0x7d, 0x1a, + 0x87, 0x55, + 0x88, 0x72, + 0x8f, 0x08, + 0x90, 0xe0, + 0x94, 0x40, + 0xa0, 0x3f, + 0xa1, 0xc0, + 0xa4, 0xcc, + 0xa5, 0x66, + 0xa6, 0x66, + 0xa7, 0x7b, + 0xa8, 0x7b, + 0xa9, 0x7b, + 0xaa, 0x9a, + 0xed, 0x04, + 0xad, 0x00, + 0xae, 0x03, + 0xcc, 0xab, + 0x01, 0x08, + 0xff, 0xff +}; + +/* low level read/writes */ +static int si21_writeregs(struct si21xx_state *state, u8 reg1, + u8 *data, int len) +{ + int ret; + u8 buf[60];/* = { reg1, data };*/ + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = len + 1 + }; + + msg.buf[0] = reg1; + memcpy(msg.buf + 1, data, len); + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, " + "ret == %i)\n", __func__, reg1, data[0], ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int si21_write(struct dvb_frontend *fe, u8 *buf, int len) +{ + struct si21xx_state *state = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return si21_writereg(state, buf[0], buf[1]); +} + +static u8 si21_readreg(struct si21xx_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) + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __func__, reg, ret); + + return b1[0]; +} + +static int si21_readregs(struct si21xx_state *state, u8 reg1, u8 *b, u8 len) +{ + int ret; + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = ®1, + .len = 1 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b, + .len = len + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (ret == %i)\n", __func__, ret); + + return ret == 2 ? 0 : -1; +} + +static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) +{ + unsigned long start = jiffies; + + dprintk("%s\n", __func__); + + while ((si21_readreg(state, LNB_CTRL_REG_1) & 0x8) == 8) { + if (jiffies - start > timeout) { + dprintk("%s: timeout!!\n", __func__); + return -ETIMEDOUT; + } + msleep(10); + }; + + return 0; +} + +static int si21xx_set_symbolrate(struct dvb_frontend *fe, u32 srate) +{ + struct si21xx_state *state = fe->demodulator_priv; + u32 sym_rate, data_rate; + int i; + u8 sym_rate_bytes[3]; + + dprintk("%s : srate = %i\n", __func__ , srate); + + if ((srate < 1000000) || (srate > 45000000)) + return -EINVAL; + + data_rate = srate; + sym_rate = 0; + + for (i = 0; i < 4; ++i) { + sym_rate /= 100; + sym_rate = sym_rate + ((data_rate % 100) * 0x800000) / + state->fs; + data_rate /= 100; + } + for (i = 0; i < 3; ++i) + sym_rate_bytes[i] = (u8)((sym_rate >> (i * 8)) & 0xff); + + si21_writeregs(state, SYM_RATE_REG_L, sym_rate_bytes, 0x03); + + return 0; +} + +static int si21xx_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *m) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 lnb_status; + u8 LNB_CTRL_1; + int status; + + dprintk("%s\n", __func__); + + status = PASS; + LNB_CTRL_1 = 0; + + status |= si21_readregs(state, LNB_CTRL_STATUS_REG, &lnb_status, 0x01); + status |= si21_readregs(state, LNB_CTRL_REG_1, &lnb_status, 0x01); + + /*fill the FIFO*/ + status |= si21_writeregs(state, LNB_FIFO_REGS_0, m->msg, m->msg_len); + + LNB_CTRL_1 = (lnb_status & 0x70); + LNB_CTRL_1 |= m->msg_len; + + LNB_CTRL_1 |= 0x80; /* begin LNB signaling */ + + status |= si21_writeregs(state, LNB_CTRL_REG_1, &LNB_CTRL_1, 0x01); + + return status; +} + +static int si21xx_send_diseqc_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 val; + + dprintk("%s\n", __func__); + + if (si21xx_wait_diseqc_idle(state, 100) < 0) + return -ETIMEDOUT; + + val = (0x80 | si21_readreg(state, 0xc1)); + if (si21_writereg(state, LNB_CTRL_REG_1, + burst == SEC_MINI_A ? (val & ~0x10) : (val | 0x10))) + return -EREMOTEIO; + + if (si21xx_wait_diseqc_idle(state, 100) < 0) + return -ETIMEDOUT; + + if (si21_writereg(state, LNB_CTRL_REG_1, val)) + return -EREMOTEIO; + + return 0; +} +/* 30.06.2008 */ +static int si21xx_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 val; + + dprintk("%s\n", __func__); + val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); + + switch (tone) { + case SEC_TONE_ON: + return si21_writereg(state, LNB_CTRL_REG_1, val | 0x20); + + case SEC_TONE_OFF: + return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x20)); + + default: + return -EINVAL; + } +} + +static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +{ + struct si21xx_state *state = fe->demodulator_priv; + + u8 val; + dprintk("%s: %s\n", __func__, + volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + + + val = (0x80 | si21_readreg(state, LNB_CTRL_REG_1)); + + switch (volt) { + case SEC_VOLTAGE_18: + return si21_writereg(state, LNB_CTRL_REG_1, val | 0x40); + break; + case SEC_VOLTAGE_13: + return si21_writereg(state, LNB_CTRL_REG_1, (val & ~0x40)); + break; + default: + return -EINVAL; + }; +} + +static int si21xx_init(struct dvb_frontend *fe) +{ + struct si21xx_state *state = fe->demodulator_priv; + int i; + int status = 0; + u8 reg1; + u8 val; + u8 reg2[2]; + + dprintk("%s\n", __func__); + + for (i = 0; ; i += 2) { + reg1 = serit_sp1511lhb_inittab[i]; + val = serit_sp1511lhb_inittab[i+1]; + if (reg1 == 0xff && val == 0xff) + break; + si21_writeregs(state, reg1, &val, 1); + } + + /*DVB QPSK SYSTEM MODE REG*/ + reg1 = 0x08; + si21_writeregs(state, SYSTEM_MODE_REG, ®1, 0x01); + + /*transport stream config*/ + /* + mode = PARALLEL; + sdata_form = LSB_FIRST; + clk_edge = FALLING_EDGE; + clk_mode = CLK_GAPPED_MODE; + strt_len = BYTE_WIDE; + sync_pol = ACTIVE_HIGH; + val_pol = ACTIVE_HIGH; + err_pol = ACTIVE_HIGH; + sclk_rate = 0x00; + parity = 0x00 ; + data_delay = 0x00; + clk_delay = 0x00; + pclk_smooth = 0x00; + */ + reg2[0] = + PARALLEL + (LSB_FIRST << 1) + + (FALLING_EDGE << 2) + (CLK_GAPPED_MODE << 3) + + (BYTE_WIDE << 4) + (ACTIVE_HIGH << 5) + + (ACTIVE_HIGH << 6) + (ACTIVE_HIGH << 7); + + reg2[1] = 0; + /* sclk_rate + (parity << 2) + + (data_delay << 3) + (clk_delay << 4) + + (pclk_smooth << 5); + */ + status |= si21_writeregs(state, TS_CTRL_REG_1, reg2, 0x02); + if (status != 0) + dprintk(" %s : TS Set Error\n", __func__); + + return 0; + +} + +static int si21_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 regs_read[2]; + u8 reg_read; + u8 i; + u8 lock; + u8 signal = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG); + + si21_readregs(state, LOCK_STATUS_REG_1, regs_read, 0x02); + reg_read = 0; + + for (i = 0; i < 7; ++i) + reg_read |= ((regs_read[0] >> i) & 0x01) << (6 - i); + + lock = ((reg_read & 0x7f) | (regs_read[1] & 0x80)); + + dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, lock); + *status = 0; + + if (signal > 10) + *status |= FE_HAS_SIGNAL; + + if (lock & 0x2) + *status |= FE_HAS_CARRIER; + + if (lock & 0x20) + *status |= FE_HAS_VITERBI; + + if (lock & 0x40) + *status |= FE_HAS_SYNC; + + if ((lock & 0x7b) == 0x7b) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int si21_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct si21xx_state *state = fe->demodulator_priv; + + /*status = si21_readreg(state, ANALOG_AGC_POWER_LEVEL_REG, + (u8*)agclevel, 0x01);*/ + + u16 signal = (3 * si21_readreg(state, 0x27) * + si21_readreg(state, 0x28)); + + dprintk("%s : AGCPWR: 0x%02x%02x, signal=0x%04x\n", __func__, + si21_readreg(state, 0x27), + si21_readreg(state, 0x28), (int) signal); + + signal <<= 4; + *strength = signal; + + return 0; +} + +static int si21_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct si21xx_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (state->errmode != STATUS_BER) + return 0; + + *ber = (si21_readreg(state, 0x1d) << 8) | + si21_readreg(state, 0x1e); + + return 0; +} + +static int si21_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct si21xx_state *state = fe->demodulator_priv; + + s32 xsnr = 0xffff - ((si21_readreg(state, 0x24) << 8) | + si21_readreg(state, 0x25)); + xsnr = 3 * (xsnr - 0xa100); + *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; + + dprintk("%s\n", __func__); + + return 0; +} + +static int si21_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct si21xx_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (state->errmode != STATUS_UCBLOCKS) + *ucblocks = 0; + else + *ucblocks = (si21_readreg(state, 0x1d) << 8) | + si21_readreg(state, 0x1e); + + return 0; +} + +/* initiates a channel acquisition sequence + using the specified symbol rate and code rate */ +static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, + fe_code_rate_t crate) +{ + + struct si21xx_state *state = fe->demodulator_priv; + u8 coderates[] = { + 0x0, 0x01, 0x02, 0x04, 0x00, + 0x8, 0x10, 0x20, 0x00, 0x3f + }; + + u8 coderate_ptr; + int status; + u8 start_acq = 0x80; + u8 reg, regs[3]; + + dprintk("%s\n", __func__); + + status = PASS; + coderate_ptr = coderates[crate]; + + si21xx_set_symbolrate(fe, symbrate); + + /* write code rates to use in the Viterbi search */ + status |= si21_writeregs(state, + VIT_SRCH_CTRL_REG_1, + &coderate_ptr, 0x01); + + /* clear acq_start bit */ + status |= si21_readregs(state, ACQ_CTRL_REG_2, ®, 0x01); + reg &= ~start_acq; + status |= si21_writeregs(state, ACQ_CTRL_REG_2, ®, 0x01); + + /* use new Carrier Frequency Offset Estimator (QuickLock) */ + regs[0] = 0xCB; + regs[1] = 0x40; + regs[2] = 0xCB; + + status |= si21_writeregs(state, + TWO_DB_BNDWDTH_THRSHLD_REG, + ®s[0], 0x03); + reg = 0x56; + status |= si21_writeregs(state, + LSA_CTRL_REG_1, ®, 1); + reg = 0x05; + status |= si21_writeregs(state, + BLIND_SCAN_CTRL_REG, ®, 1); + /* start automatic acq */ + status |= si21_writeregs(state, + ACQ_CTRL_REG_2, &start_acq, 0x01); + + return status; +} + +static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int si21xx_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *dfp) +{ + struct si21xx_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + /* freq Channel carrier frequency in KHz (i.e. 1550000 KHz) + datarate Channel symbol rate in Sps (i.e. 22500000 Sps)*/ + + /* in MHz */ + unsigned char coarse_tune_freq; + int fine_tune_freq; + unsigned char sample_rate = 0; + /* boolean */ + unsigned int inband_interferer_ind; + + /* INTERMEDIATE VALUES */ + int icoarse_tune_freq; /* MHz */ + int ifine_tune_freq; /* MHz */ + unsigned int band_high; + unsigned int band_low; + unsigned int x1; + unsigned int x2; + int i; + unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = { + FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE + }; + unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = { + FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE + }; + + int status; + + /* allowable sample rates for ADC in MHz */ + int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, + 196, 204, 205, 206, 207 + }; + /* in MHz */ + int if_limit_high; + int if_limit_low; + int lnb_lo; + int lnb_uncertanity; + + int rf_freq; + int data_rate; + unsigned char regs[4]; + + dprintk("%s : FE_SET_FRONTEND\n", __func__); + + if (c->delivery_system != SYS_DVBS) { + dprintk("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) + inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE; + + if_limit_high = -700000; + if_limit_low = -100000; + /* in MHz */ + lnb_lo = 0; + lnb_uncertanity = 0; + + rf_freq = 10 * c->frequency ; + data_rate = c->symbol_rate / 100; + + status = PASS; + + band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) + + (data_rate * 135)) / 200; + + band_high = (rf_freq - lnb_lo) + ((lnb_uncertanity * 200) + + (data_rate * 135)) / 200; + + + icoarse_tune_freq = 100000 * + (((rf_freq - lnb_lo) - + (if_limit_low + if_limit_high) / 2) + / 100000); + + ifine_tune_freq = (rf_freq - lnb_lo) - icoarse_tune_freq ; + + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + x1 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * + (afs[i] * 2500) + afs[i] * 2500; + + x2 = ((rf_freq - lnb_lo) / (afs[i] * 2500)) * + (afs[i] * 2500); + + if (((band_low < x1) && (x1 < band_high)) || + ((band_low < x2) && (x2 < band_high))) + inband_interferer_div4[i] = TRUE; + + } + + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + x1 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * + (afs[i] * 5000) + afs[i] * 5000; + + x2 = ((rf_freq - lnb_lo) / (afs[i] * 5000)) * + (afs[i] * 5000); + + if (((band_low < x1) && (x1 < band_high)) || + ((band_low < x2) && (x2 < band_high))) + inband_interferer_div2[i] = TRUE; + } + + inband_interferer_ind = TRUE; + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) + inband_interferer_ind &= inband_interferer_div2[i] | + inband_interferer_div4[i]; + + if (inband_interferer_ind) { + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + if (inband_interferer_div2[i] == FALSE) { + sample_rate = (u8) afs[i]; + break; + } + } + } else { + for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) { + if ((inband_interferer_div2[i] | + inband_interferer_div4[i]) == FALSE) { + sample_rate = (u8) afs[i]; + break; + } + } + + } + + if (sample_rate > 207 || sample_rate < 192) + sample_rate = 200; + + fine_tune_freq = ((0x4000 * (ifine_tune_freq / 10)) / + ((sample_rate) * 1000)); + + coarse_tune_freq = (u8)(icoarse_tune_freq / 100000); + + regs[0] = sample_rate; + regs[1] = coarse_tune_freq; + regs[2] = fine_tune_freq & 0xFF; + regs[3] = fine_tune_freq >> 8 & 0xFF; + + status |= si21_writeregs(state, PLL_DIVISOR_REG, ®s[0], 0x04); + + state->fs = sample_rate;/*ADC MHz*/ + si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); + + return 0; +} + +static int si21xx_sleep(struct dvb_frontend *fe) +{ + struct si21xx_state *state = fe->demodulator_priv; + u8 regdata; + + dprintk("%s\n", __func__); + + si21_readregs(state, SYSTEM_MODE_REG, ®data, 0x01); + regdata |= 1 << 6; + si21_writeregs(state, SYSTEM_MODE_REG, ®data, 0x01); + state->initialised = 0; + + return 0; +} + +static void si21xx_release(struct dvb_frontend *fe) +{ + struct si21xx_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + kfree(state); +} + +static struct dvb_frontend_ops si21xx_ops = { + + .info = { + .name = "SL SI21XX DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + + .release = si21xx_release, + .init = si21xx_init, + .sleep = si21xx_sleep, + .write = si21_write, + .read_status = si21_read_status, + .read_ber = si21_read_ber, + .read_signal_strength = si21_read_signal_strength, + .read_snr = si21_read_snr, + .read_ucblocks = si21_read_ucblocks, + .diseqc_send_master_cmd = si21xx_send_diseqc_msg, + .diseqc_send_burst = si21xx_send_diseqc_burst, + .set_tone = si21xx_set_tone, + .set_voltage = si21xx_set_voltage, + + .set_property = si21xx_set_property, + .get_property = si21xx_get_property, + .set_frontend = si21xx_set_frontend, +}; + +struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, + struct i2c_adapter *i2c) +{ + struct si21xx_state *state = NULL; + int id; + + dprintk("%s\n", __func__); + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct si21xx_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + state->errmode = STATUS_BER; + + /* check if the demod is there */ + id = si21_readreg(state, SYSTEM_MODE_REG); + si21_writereg(state, SYSTEM_MODE_REG, id | 0x40); /* standby off */ + msleep(200); + id = si21_readreg(state, 0x00); + + /* register 0x00 contains: + 0x34 for SI2107 + 0x24 for SI2108 + 0x14 for SI2109 + 0x04 for SI2110 + */ + if (id != 0x04 && id != 0x14) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &si21xx_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(si21xx_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("SL SI21XX DVB Demodulator driver"); +MODULE_AUTHOR("Igor M. Liplianin"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/si21xx.h b/drivers/media/dvb/frontends/si21xx.h new file mode 100644 index 000000000000..141b5b8a5f63 --- /dev/null +++ b/drivers/media/dvb/frontends/si21xx.h @@ -0,0 +1,37 @@ +#ifndef SI21XX_H +#define SI21XX_H + +#include +#include "dvb_frontend.h" + +struct si21xx_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* minimum delay before retuning */ + int min_delay_ms; +}; + +#if defined(CONFIG_DVB_SI21XX) || \ + (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE)) +extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *si21xx_attach( + const struct si21xx_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +static inline int si21xx_writeregister(struct dvb_frontend *fe, u8 reg, u8 val) +{ + int r = 0; + u8 buf[] = {reg, val}; + if (fe->ops.write) + r = fe->ops.write(fe, buf, 2); + return r; +} + +#endif -- cgit v1.2.1 From 21b007b94c714cda3ebf0fa5b4e40342d2444f79 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Wed, 17 Sep 2008 19:19:19 -0300 Subject: V4L/DVB (9018): Add support for USB card modification with SI2109/2110 demodulator. Add support for USB card modification with SI2109/2110 demodulator. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 260 ++++++++++++++++++++++++------------- 1 file changed, 173 insertions(+), 87 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index ad3d6fca9ab8..20ba3f129001 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -11,6 +11,7 @@ */ #include #include "dw2102.h" +#include "si21xx.h" #include "stv0299.h" #include "z0194a.h" #include "cx24116.h" @@ -23,8 +24,8 @@ #define USB_PID_DW2104 0x2104 #endif -#define DW2102_READ_MSG 0 -#define DW2102_WRITE_MSG 1 +#define DW210X_READ_MSG 0 +#define DW210X_WRITE_MSG 1 #define REG_1F_SYMBOLRATE_BYTE0 0x1f #define REG_20_SYMBOLRATE_BYTE1 0x20 @@ -33,10 +34,10 @@ #define DW2102_VOLTAGE_CTRL (0x1800) #define DW2102_RC_QUERY (0x1a00) -struct dw2102_state { +struct dw210x_state { u32 last_key_pressed; }; -struct dw2102_rc_keys { +struct dw210x_rc_keys { u32 keycode; u32 event; }; @@ -48,28 +49,27 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value, +static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, u16 index, u8 * data, u16 len, int flags) { int ret; u8 u8buf[len]; - unsigned int pipe = (flags == DW2102_READ_MSG) ? + unsigned int pipe = (flags == DW210X_READ_MSG) ? usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0); - u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; + u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT; - if (flags == DW2102_WRITE_MSG) + if (flags == DW210X_WRITE_MSG) memcpy(u8buf, data, len); ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR, value, index , u8buf, len, 2000); - if (flags == DW2102_READ_MSG) + if (flags == DW210X_READ_MSG) memcpy(data, u8buf, len); return ret; } /* I2C */ - static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -89,10 +89,9 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); value = msg[0].buf[0];/* register */ for (i = 0; i < msg[1].len; i++) { value = value + i; - ret = dw2102_op_rw(d->udev, 0xb5, value, 0, - buf6, 2, DW2102_READ_MSG); + ret = dw210x_op_rw(d->udev, 0xb5, value, 0, + buf6, 2, DW210X_READ_MSG); msg[1].buf[i] = buf6[0]; - } break; case 1: @@ -102,8 +101,8 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); buf6[0] = 0x2a; buf6[1] = msg[0].buf[0]; buf6[2] = msg[0].buf[1]; - ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, - buf6, 3, DW2102_WRITE_MSG); + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 3, DW210X_WRITE_MSG); break; case 0x60: if (msg[0].flags == 0) { @@ -115,26 +114,26 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); buf6[4] = msg[0].buf[1]; buf6[5] = msg[0].buf[2]; buf6[6] = msg[0].buf[3]; - ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, - buf6, 7, DW2102_WRITE_MSG); + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 7, DW210X_WRITE_MSG); } else { /* read from tuner */ - ret = dw2102_op_rw(d->udev, 0xb5, 0,0, - buf6, 1, DW2102_READ_MSG); + ret = dw210x_op_rw(d->udev, 0xb5, 0, 0, + buf6, 1, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; } break; case (DW2102_RC_QUERY): - ret = dw2102_op_rw(d->udev, 0xb8, 0, 0, - buf6, 2, DW2102_READ_MSG); + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + buf6, 2, DW210X_READ_MSG); msg[0].buf[0] = buf6[0]; msg[0].buf[1] = buf6[1]; break; case (DW2102_VOLTAGE_CTRL): buf6[0] = 0x30; buf6[1] = msg[0].buf[0]; - ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, - buf6, 2, DW2102_WRITE_MSG); + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 2, DW210X_WRITE_MSG); break; } @@ -145,6 +144,62 @@ struct dvb_usb_device *d = i2c_get_adapdata(adap); return num; } +static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int ret = 0; + u8 buf6[] = {0, 0, 0, 0, 0, 0, 0}; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 2: + /* read si2109 register by number */ + buf6[0] = 0xd0; + buf6[1] = msg[0].len; + buf6[2] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + buf6, msg[0].len + 2, DW210X_WRITE_MSG); + /* read si2109 register */ + ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0, + buf6, msg[1].len + 2, DW210X_READ_MSG); + memcpy(msg[1].buf, buf6 + 2, msg[1].len); + + break; + case 1: + switch (msg[0].addr) { + case 0x68: + /* write to si2109 register */ + buf6[0] = 0xd0; + buf6[1] = msg[0].len; + memcpy(buf6 + 2, msg[0].buf, msg[0].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, + msg[0].len + 2, DW210X_WRITE_MSG); + break; + case(DW2102_RC_QUERY): + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + buf6, 2, DW210X_READ_MSG); + msg[0].buf[0] = buf6[0]; + msg[0].buf[1] = buf6[1]; + break; + case(DW2102_VOLTAGE_CTRL): + buf6[0] = 0x30; + buf6[1] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + buf6, 2, DW210X_WRITE_MSG); + break; + } + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} + static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); @@ -164,11 +219,11 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i obuf[0] = 0xaa; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; - ret = dw2102_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW2102_WRITE_MSG); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[0].len + 2, DW210X_WRITE_MSG); /* second read registers */ - ret = dw2102_op_rw(d->udev, 0xc3, 0xab , 0, - ibuf, msg[1].len + 2, DW2102_READ_MSG); + ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0, + ibuf, msg[1].len + 2, DW210X_READ_MSG); memcpy(msg[1].buf, ibuf + 2, msg[1].len); break; @@ -187,8 +242,8 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i i = 1; do { memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len)); - ret = dw2102_op_rw(d->udev, 0xc2, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, DW2102_WRITE_MSG); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); i += 16; len -= 16; } while (len > 0); @@ -198,15 +253,15 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i obuf[0] = 0xaa; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw2102_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW2102_WRITE_MSG); + 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 = dw2102_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 2, DW2102_READ_MSG); + ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, + ibuf, 2, DW210X_READ_MSG); memcpy(msg[0].buf, ibuf , 2); break; } @@ -214,8 +269,8 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i u8 obuf[2]; obuf[0] = 0x30; obuf[1] = msg[0].buf[0]; - ret = dw2102_op_rw(d->udev, 0xb2, 0, 0, - obuf, 2, DW2102_WRITE_MSG); + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + obuf, 2, DW210X_WRITE_MSG); break; } } @@ -227,29 +282,34 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i return num; } -static u32 dw2102_i2c_func(struct i2c_adapter *adapter) +static u32 dw210x_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; } static struct i2c_algorithm dw2102_i2c_algo = { .master_xfer = dw2102_i2c_transfer, - .functionality = dw2102_i2c_func, + .functionality = dw210x_i2c_func, +}; + +static struct i2c_algorithm dw2102_serit_i2c_algo = { + .master_xfer = dw2102_serit_i2c_transfer, + .functionality = dw210x_i2c_func, }; static struct i2c_algorithm dw2104_i2c_algo = { .master_xfer = dw2104_i2c_transfer, - .functionality = dw2102_i2c_func, + .functionality = dw210x_i2c_func, }; -static int dw2102_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) { int i; u8 ibuf[] = {0, 0}; u8 eeprom[256], eepromline[16]; for (i = 0; i < 256; i++) { - if (dw2102_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW2102_READ_MSG) < 0) { + if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) { err("read eeprom failed."); return -1; } else { @@ -265,7 +325,7 @@ static int dw2102_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) return 0; }; -static int dw2102_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { static u8 command_13v[1] = {0x00}; static u8 command_18v[1] = {0x01}; @@ -287,25 +347,46 @@ static struct cx24116_config dw2104_config = { .mpg_clk_pos_pol = 0x01, }; +static struct si21xx_config serit_sp1511lhb_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + +}; + static int dw2104_frontend_attach(struct dvb_usb_adapter *d) { if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, &d->dev->i2c_adap)) != NULL) { - d->fe->ops.set_voltage = dw2102_set_voltage; + d->fe->ops.set_voltage = dw210x_set_voltage; info("Attached cx24116!\n"); return 0; } return -EIO; } +static struct dvb_usb_device_properties dw2102_properties; + static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { - d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, - &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw2102_set_voltage; - info("Attached stv0299!\n"); - return 0; + if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { + /*dw2102_properties.adapter->tuner_attach = NULL;*/ + d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached si21xx!\n"); + return 0; + } + } + if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { + /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ + d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0299!\n"); + return 0; + } } return -EIO; } @@ -317,7 +398,7 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static struct dvb_usb_rc_key dw2102_rc_keys[] = { +static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf8, 0x0a, KEY_Q }, /*power*/ { 0xf8, 0x0c, KEY_M }, /*mute*/ { 0xf8, 0x11, KEY_1 }, @@ -356,7 +437,7 @@ static struct dvb_usb_rc_key dw2102_rc_keys[] = { static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { - struct dw2102_state *st = d->priv; + struct dw210x_state *st = d->priv; u8 key[2]; struct i2c_msg msg[] = { {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key, @@ -366,12 +447,12 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) *state = REMOTE_NO_KEY_PRESSED; if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) { - for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) { - if (dw2102_rc_keys[i].data == msg[0].buf[0]) { + for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) { + if (dw210x_rc_keys[i].data == msg[0].buf[0]) { *state = REMOTE_KEY_PRESSED; - *event = dw2102_rc_keys[i].event; + *event = dw210x_rc_keys[i].event; st->last_key_pressed = - dw2102_rc_keys[i].event; + dw210x_rc_keys[i].event; break; } st->last_key_pressed = 0; @@ -418,15 +499,15 @@ static int dw2102_load_firmware(struct usb_device *dev, p = kmalloc(fw->size, GFP_KERNEL); reset = 1; /*stop the CPU*/ - dw2102_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW2102_WRITE_MSG); - dw2102_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW2102_WRITE_MSG); + dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG); if (p != NULL) { memcpy(p, fw->data, fw->size); for (i = 0; i < fw->size; i += 0x40) { b = (u8 *) p + i; - if (dw2102_op_rw(dev, 0xa0, i, 0, b , 0x40, - DW2102_WRITE_MSG) != 0x40) { + if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40, + DW210X_WRITE_MSG) != 0x40) { err("error while transferring firmware"); ret = -EINVAL; break; @@ -434,13 +515,13 @@ static int dw2102_load_firmware(struct usb_device *dev, } /* restart the CPU */ reset = 0; - if (ret || dw2102_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, - DW2102_WRITE_MSG) != 1) { + if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, + DW210X_WRITE_MSG) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } - if (ret || dw2102_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, - DW2102_WRITE_MSG) != 1) { + if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, + DW210X_WRITE_MSG) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } @@ -449,27 +530,32 @@ static int dw2102_load_firmware(struct usb_device *dev, case USB_PID_DW2104: case 0xd650: reset = 1; - dw2102_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, - DW2102_WRITE_MSG); + dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, + DW210X_WRITE_MSG); reset = 0; - dw2102_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW2102_WRITE_MSG); + dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW210X_WRITE_MSG); break; case USB_PID_DW2102: - dw2102_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, - DW2102_WRITE_MSG); - dw2102_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW2102_READ_MSG); + dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, + DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW210X_READ_MSG); + /* check STV0299 frontend */ + dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, + DW210X_READ_MSG); + if (reset16[0] == 0xa1) + dw2102_properties.i2c_algo = &dw2102_i2c_algo; break; case 0x2101: - dw2102_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, - DW2102_READ_MSG); - dw2102_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW2102_READ_MSG); - dw2102_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, - DW2102_READ_MSG); - dw2102_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, - DW2102_READ_MSG); + dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7, + DW210X_READ_MSG); + dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, + DW210X_READ_MSG); break; } msleep(100); @@ -482,12 +568,12 @@ 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 dw2102_state), + .size_of_priv = sizeof(struct dw210x_state), .no_reconnect = 1, - .i2c_algo = &dw2102_i2c_algo, - .rc_key_map = dw2102_rc_keys, - .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys), + .i2c_algo = &dw2102_serit_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, @@ -495,7 +581,7 @@ static struct dvb_usb_device_properties dw2102_properties = { /* parameter for the MPEG2-data transfer */ .num_adapters = 1, .download_firmware = dw2102_load_firmware, - .read_mac_address = dw2102_read_mac_address, + .read_mac_address = dw210x_read_mac_address, .adapter = { { .frontend_attach = dw2102_frontend_attach, @@ -530,12 +616,12 @@ 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 dw2102_state), + .size_of_priv = sizeof(struct dw210x_state), .no_reconnect = 1, .i2c_algo = &dw2104_i2c_algo, - .rc_key_map = dw2102_rc_keys, - .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys), + .rc_key_map = dw210x_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys), .rc_interval = 150, .rc_query = dw2102_rc_query, @@ -543,7 +629,7 @@ static struct dvb_usb_device_properties dw2104_properties = { /* parameter for the MPEG2-data transfer */ .num_adapters = 1, .download_firmware = dw2102_load_firmware, - .read_mac_address = dw2102_read_mac_address, + .read_mac_address = dw210x_read_mac_address, .adapter = { { .frontend_attach = dw2104_frontend_attach, -- cgit v1.2.1 From 8316568930074723bdc47d6777f822be0422a5b7 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 23 Sep 2008 22:21:26 -0300 Subject: V4L/DVB (9025): S2API: Deactivate the ISDB-T definitions We don't want to push the ISDB-T definitions into the kernel until we have a high level of confidence in the ISDB-T API. More testing is required before this code is released. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 99 ------------------------------- drivers/media/dvb/dvb-core/dvb_frontend.h | 13 ---- 2 files changed, 112 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 05d0b73cf9a3..7da25372078c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -829,17 +829,6 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_DELIVERY_SYSTEM, .set = 1, }, - [DTV_ISDB_SEGMENT_IDX] = { - .name = "DTV_ISDB_SEGMENT_IDX", - .cmd = DTV_ISDB_SEGMENT_IDX, - .set = 1, - }, - [DTV_ISDB_SEGMENT_WIDTH] = { - .name = "DTV_ISDB_SEGMENT_WIDTH", - .cmd = DTV_ISDB_SEGMENT_WIDTH, - .set = 1, - }, - /* Get */ [DTV_DISEQC_SLAVE_REPLY] = { .name = "DTV_DISEQC_SLAVE_REPLY", @@ -847,51 +836,6 @@ struct dtv_cmds_h dtv_cmds[] = { .set = 0, .buffer = 1, }, - [DTV_ISDB_LAYERA_FEC] = { - .name = "DTV_ISDB_LAYERA_FEC", - .cmd = DTV_ISDB_LAYERA_FEC, - .set = 0, - }, - [DTV_ISDB_LAYERA_MODULATION] = { - .name = "DTV_ISDB_LAYERA_MODULATION", - .cmd = DTV_ISDB_LAYERA_MODULATION, - .set = 0, - }, - [DTV_ISDB_LAYERA_SEGMENT_WIDTH] = { - .name = "DTV_ISDB_LAYERA_SEGMENT_WIDTH", - .cmd = DTV_ISDB_LAYERA_SEGMENT_WIDTH, - .set = 0, - }, - [DTV_ISDB_LAYERB_FEC] = { - .name = "DTV_ISDB_LAYERB_FEC", - .cmd = DTV_ISDB_LAYERB_FEC, - .set = 0, - }, - [DTV_ISDB_LAYERB_MODULATION] = { - .name = "DTV_ISDB_LAYERB_MODULATION", - .cmd = DTV_ISDB_LAYERB_MODULATION, - .set = 0, - }, - [DTV_ISDB_LAYERB_SEGMENT_WIDTH] = { - .name = "DTV_ISDB_LAYERB_SEGMENT_WIDTH", - .cmd = DTV_ISDB_LAYERB_SEGMENT_WIDTH, - .set = 0, - }, - [DTV_ISDB_LAYERC_FEC] = { - .name = "DTV_ISDB_LAYERC_FEC", - .cmd = DTV_ISDB_LAYERC_FEC, - .set = 0, - }, - [DTV_ISDB_LAYERC_MODULATION] = { - .name = "DTV_ISDB_LAYERC_MODULATION", - .cmd = DTV_ISDB_LAYERC_MODULATION, - .set = 0, - }, - [DTV_ISDB_LAYERC_SEGMENT_WIDTH] = { - .name = "DTV_ISDB_LAYERC_SEGMENT_WIDTH", - .cmd = DTV_ISDB_LAYERC_SEGMENT_WIDTH, - .set = 0, - }, }; void dtv_property_dump(struct dtv_property *tvp) @@ -1154,41 +1098,6 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_DELIVERY_SYSTEM: tvp->u.data = fe->dtv_property_cache.delivery_system; break; - - /* ISDB-T Support here */ - case DTV_ISDB_SEGMENT_IDX: - tvp->u.data = fe->dtv_property_cache.isdb_segment_idx; - break; - case DTV_ISDB_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_segment_width; - break; - case DTV_ISDB_LAYERA_FEC: - tvp->u.data = fe->dtv_property_cache.isdb_layera_fec; - break; - case DTV_ISDB_LAYERA_MODULATION: - tvp->u.data = fe->dtv_property_cache.isdb_layera_modulation; - break; - case DTV_ISDB_LAYERA_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_layera_segment_width; - break; - case DTV_ISDB_LAYERB_FEC: - tvp->u.data = fe->dtv_property_cache.isdb_layerb_fec; - break; - case DTV_ISDB_LAYERB_MODULATION: - tvp->u.data = fe->dtv_property_cache.isdb_layerb_modulation; - break; - case DTV_ISDB_LAYERB_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_layerb_segment_width; - break; - case DTV_ISDB_LAYERC_FEC: - tvp->u.data = fe->dtv_property_cache.isdb_layerc_fec; - break; - case DTV_ISDB_LAYERC_MODULATION: - tvp->u.data = fe->dtv_property_cache.isdb_layerc_modulation; - break; - case DTV_ISDB_LAYERC_SEGMENT_WIDTH: - tvp->u.data = fe->dtv_property_cache.isdb_layerc_segment_width; - break; case DTV_VOLTAGE: tvp->u.data = fe->dtv_property_cache.voltage; break; @@ -1266,14 +1175,6 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_DELIVERY_SYSTEM: fe->dtv_property_cache.delivery_system = tvp->u.data; break; - - /* ISDB-T Support here */ - case DTV_ISDB_SEGMENT_IDX: - fe->dtv_property_cache.isdb_segment_idx = tvp->u.data; - break; - case DTV_ISDB_SEGMENT_WIDTH: - fe->dtv_property_cache.isdb_segment_width = tvp->u.data; - break; case DTV_VOLTAGE: fe->dtv_property_cache.voltage = tvp->u.data; r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE, diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 2fa37f5a0d9a..1c575402814d 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -209,19 +209,6 @@ struct dtv_frontend_properties { fe_rolloff_t rolloff; fe_delivery_system_t delivery_system; - - /* ISDB-T specifics */ - u32 isdb_segment_idx; - u32 isdb_segment_width; - fe_code_rate_t isdb_layera_fec; - fe_modulation_t isdb_layera_modulation; - u32 isdb_layera_segment_width; - fe_code_rate_t isdb_layerb_fec; - fe_modulation_t isdb_layerb_modulation; - u32 isdb_layerb_segment_width; - fe_code_rate_t isdb_layerc_fec; - fe_modulation_t isdb_layerc_modulation; - u32 isdb_layerc_segment_width; }; struct dvb_frontend { -- cgit v1.2.1 From e4aab64cb78a42e45e1d387f272712e06cf89a66 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 23 Sep 2008 15:43:57 -0300 Subject: V4L/DVB (9026): Add support for ST STV0288 demodulator and cards with it. Add support for ST STV0288 demodulator and cards with it, such as TeVii S420. Patch is co-authored with Georg Acher Signed-off-by: Georg Acher Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dm1105/dm1105.c | 11 +- drivers/media/dvb/frontends/Kconfig | 14 + drivers/media/dvb/frontends/Makefile | 2 + drivers/media/dvb/frontends/stb6000.c | 254 ++++++++++++++ drivers/media/dvb/frontends/stb6000.h | 51 +++ drivers/media/dvb/frontends/stv0288.c | 606 ++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/stv0288.h | 65 ++++ drivers/media/dvb/frontends/stv0299.c | 2 + drivers/media/dvb/frontends/stv0299.h | 13 +- 9 files changed, 1007 insertions(+), 11 deletions(-) create mode 100644 drivers/media/dvb/frontends/stb6000.c create mode 100644 drivers/media/dvb/frontends/stb6000.h create mode 100644 drivers/media/dvb/frontends/stv0288.c create mode 100644 drivers/media/dvb/frontends/stv0288.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 0c1790fe2b56..f7321448b4b1 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -39,8 +39,8 @@ #include "dvb-pll.h" #include "stv0299.h" -/*#include "stv0288.h" - *#include "stb6000.h"*/ +#include "stv0288.h" +#include "stb6000.h" #include "si21xx.h" #include "cx24116.h" #include "z0194a.h" @@ -594,13 +594,12 @@ static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb) dm1105dvb_dma_unmap(dm1105dvb); } -#if 0 + static struct stv0288_config earda_config = { .demod_address = 0x68, .min_delay_ms = 100, }; -#endif /* keep */ static struct si21xx_config serit_config = { .demod_address = 0x68, .min_delay_ms = 100, @@ -627,7 +626,7 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60, &dm1105dvb->i2c_adap, DVB_PLL_OPERA1); } -#if 0 + if (!dm1105dvb->fe) { dm1105dvb->fe = dvb_attach( stv0288_attach, &earda_config, @@ -639,7 +638,7 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb) &dm1105dvb->i2c_adap); } } -#endif /* keep */ + if (!dm1105dvb->fe) { dm1105dvb->fe = dvb_attach( si21xx_attach, &serit_config, diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 7697391ca86c..96b93e21a84b 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -43,6 +43,20 @@ config DVB_S5H1420 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_STV0288 + tristate "ST STV0288 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_STB6000 + tristate "ST STB6000 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S silicon tuner module. Say Y when you want to support this tuner. + config DVB_STV0299 tristate "ST STV0299 based" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index c719b7fdce4a..491eb5c55855 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -53,3 +53,5 @@ obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o obj-$(CONFIG_DVB_AF9013) += af9013.o obj-$(CONFIG_DVB_CX24116) += cx24116.o obj-$(CONFIG_DVB_SI21XX) += si21xx.o +obj-$(CONFIG_DVB_STV0299) += stv0288.o +obj-$(CONFIG_DVB_STB6000) += stb6000.o diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c new file mode 100644 index 000000000000..7d65123b4ec9 --- /dev/null +++ b/drivers/media/dvb/frontends/stb6000.c @@ -0,0 +1,254 @@ + /* + Driver for ST STB6000 DVBS Silicon tuner + + Copyright (C) 2008 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 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 +#include +#include + +#include "stb6000.h" + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "stb6000: " args); \ + } while (0) + +struct stb6000_priv { + /* i2c details */ + int i2c_address; + struct i2c_adapter *i2c; + u32 frequency; +}; + +static int stb6000_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int stb6000_sleep(struct dvb_frontend *fe) +{ + struct stb6000_priv *priv = fe->tuner_priv; + int ret; + u8 buf[] = { 10, 0 }; + struct i2c_msg msg = { + .addr = priv->i2c_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + dprintk("%s:\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer(priv->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: i2c error\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return (ret == 1) ? 0 : ret; +} + +static int stb6000_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct stb6000_priv *priv = fe->tuner_priv; + unsigned int n, m; + int ret; + u32 freq_mhz; + int bandwidth; + u8 buf[12]; + struct i2c_msg msg = { + .addr = priv->i2c_address, + .flags = 0, + .buf = buf, + .len = 12 + }; + + dprintk("%s:\n", __func__); + + freq_mhz = params->frequency / 1000; + bandwidth = params->u.qpsk.symbol_rate / 1000000; + + if (bandwidth > 31) + bandwidth = 31; + + if ((freq_mhz > 949) && (freq_mhz < 2151)) { + buf[0] = 0x01; + buf[1] = 0xac; + if (freq_mhz < 1950) + buf[1] = 0xaa; + if (freq_mhz < 1800) + buf[1] = 0xa8; + if (freq_mhz < 1650) + buf[1] = 0xa6; + if (freq_mhz < 1530) + buf[1] = 0xa5; + if (freq_mhz < 1470) + buf[1] = 0xa4; + if (freq_mhz < 1370) + buf[1] = 0xa2; + if (freq_mhz < 1300) + buf[1] = 0xa1; + if (freq_mhz < 1200) + buf[1] = 0xa0; + if (freq_mhz < 1075) + buf[1] = 0xbc; + if (freq_mhz < 1000) + buf[1] = 0xba; + if (freq_mhz < 1075) { + n = freq_mhz / 8; /* vco=lo*4 */ + m = 2; + } else { + n = freq_mhz / 16; /* vco=lo*2 */ + m = 1; + } + buf[2] = n >> 1; + buf[3] = (unsigned char)(((n & 1) << 7) | + (m * freq_mhz - n * 16) | 0x60); + buf[4] = 0x04; + buf[5] = 0x0e; + + buf[6] = (unsigned char)(bandwidth); + + buf[7] = 0xd8; + buf[8] = 0xd0; + buf[9] = 0x50; + buf[10] = 0xeb; + buf[11] = 0x4f; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer(priv->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: i2c error\n", __func__); + + udelay(10); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + buf[0] = 0x07; + buf[1] = 0xdf; + buf[2] = 0xd0; + buf[3] = 0x50; + buf[4] = 0xfb; + msg.len = 5; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = i2c_transfer(priv->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: i2c error\n", __func__); + + udelay(10); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + priv->frequency = freq_mhz * 1000; + + return (ret == 1) ? 0 : ret; + } + return -1; +} + +static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct stb6000_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static struct dvb_tuner_ops stb6000_tuner_ops = { + .info = { + .name = "ST STB6000", + .frequency_min = 950000, + .frequency_max = 2150000 + }, + .release = stb6000_release, + .sleep = stb6000_sleep, + .set_params = stb6000_set_params, + .get_frequency = stb6000_get_frequency, +}; + +struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c) +{ + struct stb6000_priv *priv = NULL; + u8 b1[] = { 0, 0 }; + struct i2c_msg msg[2] = { + { + .addr = addr, + .flags = 0, + .buf = NULL, + .len = 0 + }, { + .addr = addr, + .flags = I2C_M_RD, + .buf = b1, + .len = 2 + } + }; + int ret; + + dprintk("%s:\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* is some i2c device here ? */ + ret = i2c_transfer(i2c, msg, 2); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret != 2) + return NULL; + + priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->i2c_address = addr; + priv->i2c = i2c; + + memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL(stb6000_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("DVB STB6000 driver"); +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/stb6000.h b/drivers/media/dvb/frontends/stb6000.h new file mode 100644 index 000000000000..7be479c22d5b --- /dev/null +++ b/drivers/media/dvb/frontends/stb6000.h @@ -0,0 +1,51 @@ + /* + Driver for ST stb6000 DVBS Silicon tuner + + Copyright (C) 2008 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 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 __DVB_STB6000_H__ +#define __DVB_STB6000_H__ + +#include +#include "dvb_frontend.h" + +/** + * Attach a stb6000 tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param addr i2c address of the tuner. + * @param i2c i2c adapter to use. + * @return FE pointer on success, NULL on failure. + */ +#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_STB6000 */ + +#endif /* __DVB_STB6000_H__ */ diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c new file mode 100644 index 000000000000..90e72e771a04 --- /dev/null +++ b/drivers/media/dvb/frontends/stv0288.c @@ -0,0 +1,606 @@ +/* + Driver for ST STV0288 demodulator + Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de + for Reel Multimedia + Copyright (C) 2008 TurboSight.com, Bob Liu + Copyright (C) 2008 Igor M. Liplianin + Removed stb6000 specific tuner code and revised some + procedures. + + 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 +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "stv0288.h" + +struct stv0288_state { + struct i2c_adapter *i2c; + const struct stv0288_config *config; + struct dvb_frontend frontend; + + u8 initialised:1; + u32 tuner_frequency; + u32 symbol_rate; + fe_code_rate_t fec_inner; + int errmode; +}; + +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 + +static int debug; +static int debug_legacy_dish_switch; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "stv0288: " args); \ + } while (0) + + +static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = { reg, data }; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " + "ret == %i)\n", __func__, reg, data, ret); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (len != 2) + return -EINVAL; + + return stv0288_writeregI(state, buf[0], buf[1]); +} + +static u8 stv0288_readreg(struct stv0288_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) + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __func__, reg, ret); + + return b1[0]; +} + +static int stv0288_set_symbolrate(struct dvb_frontend *fe, u32 srate) +{ + struct stv0288_state *state = fe->demodulator_priv; + unsigned int temp; + unsigned char b[3]; + + if ((srate < 1000000) || (srate > 45000000)) + return -EINVAL; + + temp = (unsigned int)srate / 1000; + + temp = temp * 32768; + temp = temp / 25; + temp = temp / 125; + b[0] = (unsigned char)((temp >> 12) & 0xff); + b[1] = (unsigned char)((temp >> 4) & 0xff); + b[2] = (unsigned char)((temp << 4) & 0xf0); + stv0288_writeregI(state, 0x28, 0x80); /* SFRH */ + stv0288_writeregI(state, 0x29, 0); /* SFRM */ + stv0288_writeregI(state, 0x2a, 0); /* SFRL */ + + stv0288_writeregI(state, 0x28, b[0]); + stv0288_writeregI(state, 0x29, b[1]); + stv0288_writeregI(state, 0x2a, b[2]); + dprintk("stv0288: stv0288_set_symbolrate\n"); + + return 0; +} + +static int stv0288_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *m) +{ + struct stv0288_state *state = fe->demodulator_priv; + + int i; + + dprintk("%s\n", __func__); + + stv0288_writeregI(state, 0x09, 0); + msleep(30); + stv0288_writeregI(state, 0x05, 0x16); + + for (i = 0; i < m->msg_len; i++) { + if (stv0288_writeregI(state, 0x06, m->msg[i])) + return -EREMOTEIO; + msleep(12); + } + + return 0; +} + +static int stv0288_send_diseqc_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t burst) +{ + struct stv0288_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */ + return -EREMOTEIO; + + if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff)) + return -EREMOTEIO; + + if (stv0288_writeregI(state, 0x06, 0x12)) + return -EREMOTEIO; + + return 0; +} + +static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct stv0288_state *state = fe->demodulator_priv; + + switch (tone) { + case SEC_TONE_ON: + if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */ + return -EREMOTEIO; + return stv0288_writeregI(state, 0x06, 0xff); + + case SEC_TONE_OFF: + if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */ + return -EREMOTEIO; + return stv0288_writeregI(state, 0x06, 0x00); + + default: + return -EINVAL; + } +} + +static u8 stv0288_inittab[] = { + 0x01, 0x15, + 0x02, 0x20, + 0x09, 0x0, + 0x0a, 0x4, + 0x0b, 0x0, + 0x0c, 0x0, + 0x0d, 0x0, + 0x0e, 0xd4, + 0x0f, 0x30, + 0x11, 0x80, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0x45, + 0x16, 0xb7, + 0x17, 0x9c, + 0x18, 0x0, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0x0, + 0x23, 0x0, + 0x2b, 0xff, + 0x2c, 0xf7, + 0x30, 0x0, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbe, + 0x3a, 0x0, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x60, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x38, + 0x52, 0x21, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x0, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0x0, + 0x5f, 0xff, + 0x70, 0x0, + 0x71, 0x0, + 0x72, 0x0, + 0x74, 0x0, + 0x75, 0x0, + 0x76, 0x0, + 0x81, 0x0, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x0, + 0x85, 0x0, + 0x88, 0x0, + 0x89, 0x0, + 0x8a, 0x0, + 0x8b, 0x0, + 0x8c, 0x0, + 0x90, 0x0, + 0x91, 0x0, + 0x92, 0x0, + 0x93, 0x0, + 0x94, 0x1c, + 0x97, 0x0, + 0xa0, 0x48, + 0xa1, 0x0, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x0, + 0xf0, 0x0, + 0xf1, 0x0, + 0xf2, 0xc0, + 0x51, 0x36, + 0x52, 0x09, + 0x53, 0x94, + 0x54, 0x62, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0xff, 0xff, +}; + +static int stv0288_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +{ + dprintk("%s: %s\n", __func__, + volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : + volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); + + return 0; +} + +static int stv0288_init(struct dvb_frontend *fe) +{ + struct stv0288_state *state = fe->demodulator_priv; + int i; + + dprintk("stv0288: init chip\n"); + stv0288_writeregI(state, 0x41, 0x04); + msleep(50); + + for (i = 0; !(stv0288_inittab[i] == 0xff && + stv0288_inittab[i + 1] == 0xff); i += 2) + stv0288_writeregI(state, stv0288_inittab[i], + stv0288_inittab[i + 1]); + + return 0; +} + +static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct stv0288_state *state = fe->demodulator_priv; + + u8 sync = stv0288_readreg(state, 0x24); + if (sync == 255) + sync = 0; + + dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); + + *status = 0; + + if ((sync & 0x08) == 0x08) { + *status |= FE_HAS_LOCK; + dprintk("stv0288 has locked\n"); + } + + return 0; +} + +static int stv0288_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (state->errmode != STATUS_BER) + return 0; + *ber = (stv0288_readreg(state, 0x26) << 8) | + stv0288_readreg(state, 0x27); + dprintk("stv0288_read_ber %d\n", *ber); + + return 0; +} + + +static int stv0288_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stv0288_state *state = fe->demodulator_priv; + + s32 signal = 0xffff - ((stv0288_readreg(state, 0x10) << 8)); + + + signal = signal * 5 / 4; + *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; + dprintk("stv0288_read_signal_strength %d\n", *strength); + + return 0; +} +static int stv0288_sleep(struct dvb_frontend *fe) +{ + struct stv0288_state *state = fe->demodulator_priv; + + stv0288_writeregI(state, 0x41, 0x84); + state->initialised = 0; + + return 0; +} +static int stv0288_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0288_state *state = fe->demodulator_priv; + + s32 xsnr = 0xffff - ((stv0288_readreg(state, 0x2d) << 8) + | stv0288_readreg(state, 0x2e)); + xsnr = 3 * (xsnr - 0xa100); + *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; + dprintk("stv0288_read_snr %d\n", *snr); + + return 0; +} + +static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (state->errmode != STATUS_BER) + return 0; + *ucblocks = (stv0288_readreg(state, 0x26) << 8) | + stv0288_readreg(state, 0x27); + dprintk("stv0288_read_ber %d\n", *ucblocks); + + return 0; +} + +static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p) +{ + dprintk("%s(..)\n", __func__); + return 0; +} + +static int stv0288_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *dfp) +{ + struct stv0288_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + char tm; + unsigned char tda[3]; + + dprintk("%s : FE_SET_FRONTEND\n", __func__); + + if (c->delivery_system != SYS_DVBS) { + dprintk("%s: unsupported delivery " + "system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; + } + + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + /* only frequency & symbol_rate are used for tuner*/ + dfp->frequency = c->frequency; + dfp->u.qpsk.symbol_rate = c->symbol_rate; + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, dfp); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + udelay(10); + stv0288_set_symbolrate(fe, c->symbol_rate); + /* Carrier lock control register */ + stv0288_writeregI(state, 0x15, 0xc5); + + tda[0] = 0x2b; /* CFRM */ + tda[2] = 0x0; /* CFRL */ + for (tm = -6; tm < 7;) { + /* Viterbi status */ + if (stv0288_readreg(state, 0x24) & 0x80) + break; + + tda[2] += 40; + if (tda[2] < 40) + tm++; + tda[1] = (unsigned char)tm; + stv0288_writeregI(state, 0x2b, tda[1]); + stv0288_writeregI(state, 0x2c, tda[2]); + udelay(30); + } + + state->tuner_frequency = c->frequency; + state->fec_inner = FEC_AUTO; + state->symbol_rate = c->symbol_rate; + + return 0; +} + +static int stv0288_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0288_state *state = fe->demodulator_priv; + + if (enable) + stv0288_writeregI(state, 0x01, 0xb5); + else + stv0288_writeregI(state, 0x01, 0x35); + + udelay(1); + + return 0; +} + +static void stv0288_release(struct dvb_frontend *fe) +{ + struct stv0288_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops stv0288_ops = { + + .info = { + .name = "ST STV0288 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + + .release = stv0288_release, + .init = stv0288_init, + .sleep = stv0288_sleep, + .write = stv0288_write, + .i2c_gate_ctrl = stv0288_i2c_gate_ctrl, + .read_status = stv0288_read_status, + .read_ber = stv0288_read_ber, + .read_signal_strength = stv0288_read_signal_strength, + .read_snr = stv0288_read_snr, + .read_ucblocks = stv0288_read_ucblocks, + .diseqc_send_master_cmd = stv0288_send_diseqc_msg, + .diseqc_send_burst = stv0288_send_diseqc_burst, + .set_tone = stv0288_set_tone, + .set_voltage = stv0288_set_voltage, + + .set_property = stv0288_set_property, + .get_property = stv0288_get_property, + .set_frontend = stv0288_set_frontend, +}; + +struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, + struct i2c_adapter *i2c) +{ + struct stv0288_state *state = NULL; + int id; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct stv0288_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + state->tuner_frequency = 0; + state->symbol_rate = 0; + state->fec_inner = 0; + state->errmode = STATUS_BER; + + stv0288_writeregI(state, 0x41, 0x04); + msleep(200); + id = stv0288_readreg(state, 0x00); + dprintk("stv0288 id %x\n", id); + + /* register 0x00 contains 0x11 for STV0288 */ + if (id != 0x11) + goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &stv0288_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + + return NULL; +} +EXPORT_SYMBOL(stv0288_attach); + +module_param(debug_legacy_dish_switch, int, 0444); +MODULE_PARM_DESC(debug_legacy_dish_switch, + "Enable timing analysis for Dish Network legacy switches"); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("ST STV0288 DVB Demodulator driver"); +MODULE_AUTHOR("Georg Acher, Bob Liu, Igor liplianin"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb/frontends/stv0288.h new file mode 100644 index 000000000000..aa0cdd273040 --- /dev/null +++ b/drivers/media/dvb/frontends/stv0288.h @@ -0,0 +1,65 @@ +/* + Driver for ST STV0288 demodulator + + Copyright (C) 2006 Georg Acher, BayCom GmbH, acher (at) baycom (dot) de + for Reel Multimedia + Copyright (C) 2008 TurboSight.com, + Copyright (C) 2008 Igor M. Liplianin + Removed stb6000 specific tuner code and revised some + procedures. + + 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 STV0288_H +#define STV0288_H + +#include +#include "dvb_frontend.h" + +struct stv0288_config { + /* the demodulator's i2c address */ + u8 demod_address; + + /* minimum delay before retuning */ + int min_delay_ms; + + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); +}; + +#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \ + defined(MODULE)) +extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_STV0288 */ + +static inline int stv0288_writereg(struct dvb_frontend *fe, u8 reg, u8 val) +{ + int r = 0; + u8 buf[] = { reg, val }; + if (fe->ops.write) + r = fe->ops.write(fe, buf, 2); + return r; +} + +#endif /* STV0288_H */ diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 35435bef8e79..6c1cb1973c6e 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -559,6 +559,8 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par int invval = 0; dprintk ("%s : FE_SET_FRONTEND\n", __func__); + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); // set the inversion if (p->inversion == INVERSION_OFF) invval = 0; diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 3282f43022f5..0fd96e22b650 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -89,15 +89,18 @@ struct stv0299_config int min_delay_ms; /* Set the symbol rate */ - int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); + int (*set_symbol_rate)(struct dvb_frontend *fe, u32 srate, u32 ratio); + + /* Set device param to start dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); }; #if defined(CONFIG_DVB_STV0299) || (defined(CONFIG_DVB_STV0299_MODULE) && defined(MODULE)) -extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, - struct i2c_adapter* i2c); +extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, + struct i2c_adapter *i2c); #else -static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, - struct i2c_adapter* i2c) +static inline struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, + struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; -- cgit v1.2.1 From 17a370bcca661a849c9af07feae86f42d0c6dfd1 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 6 Sep 2008 13:42:47 -0300 Subject: V4L/DVB (9038): Add support for the Gigabyte R8000-HT USB DVB-T adapter. Thanks to Ilia Penev for the tip-off that this device is much the same as (identical to?) a Terratec Cinergy HT USB XE, and for the firmware hints: http://linuxtv.org/pipermail/linux-dvb/2008-August/028108.html DVB functionality tested OK with xine using the usual dib0700 firmware. This diff is based on the latest latest linuxtv.org v4l-dvb mercurial repo. Signed-off-by: Finn Thain Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 6c0e5c5f4362..110d9344bc92 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1119,6 +1119,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1408,7 +1409,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "Terratec Cinergy HT USB XE", { &dib0700_usb_id_table[27], NULL }, @@ -1422,6 +1423,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[32], NULL }, { NULL }, }, + { "Gigabyte U8000-RH", + { &dib0700_usb_id_table[37], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 7ae262e08f8f..e60e87315548 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -221,6 +221,7 @@ #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 #define USB_PID_GIGABYTE_U7000 0x7001 +#define USB_PID_GIGABYTE_U8000 0x7002 #define USB_PID_ASUS_U3000 0x171f #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc -- cgit v1.2.1 From bdc203e156ce938e12d957912bd29ca53d160540 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Sat, 6 Sep 2008 13:45:27 -0300 Subject: V4L/DVB (9039): Add support for new i2c API provided in firmware version 1.20 The Pinnacle PCTV HD Pro has an xc5000, which exposed a bug in the dib0700's i2c implementation where it did not properly support a single i2c read request (sending it as an i2c write request instead). Version 1.20 of the firmware added support for a new i2c API which supported such requests. This change defaults to fw 1.20 for all devices, but does not default to using the new i2c API (since initial testing suggests problems interacting with the mt2060). Maintainers can enable the use of the new i2c API by putting the following into their frontend initialization: struct dib0700_state *st = adap->dev->priv; st->fw_use_new_i2c_api = 1; Also note that the code expects i2c repeated start to be supported. If the i2c slave does not support repeated start, i2c messsages should have the I2C_M_NOSTART flag set. Thanks to Patrick Boettcher for providing new firmware fixing the issue as well as example i2c code utilizing the interface. Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700.h | 3 + drivers/media/dvb/dvb-usb/dib0700_core.c | 108 +++++++++++++++++++++++++++- drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- 3 files changed, 110 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 66d4dc6ba46f..cc0c51d82f2c 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -31,6 +31,8 @@ extern int dvb_usb_dib0700_debug; // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) #define REQUEST_SET_RC 0x11 +#define REQUEST_NEW_I2C_READ 0x12 +#define REQUEST_NEW_I2C_WRITE 0x13 #define REQUEST_GET_VERSION 0x15 struct dib0700_state { @@ -39,6 +41,7 @@ struct dib0700_state { u8 rc_toggle; u8 rc_counter; u8 is_dib7000pc; + u8 fw_use_new_i2c_api; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 595a04696c87..4daac8642006 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -82,9 +82,98 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ } /* - * I2C master xfer function + * I2C master xfer function (supported in 1.20 firmware) */ -static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num) +static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + /* The new i2c firmware messages are more reliable and in particular + properly support i2c read calls not preceded by a write */ + + struct dvb_usb_device *d = i2c_get_adapdata(adap); + uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */ + uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */ + uint8_t en_start = 0; + uint8_t en_stop = 0; + uint8_t buf[255]; /* TBV: malloc ? */ + int result, i; + + /* Ensure nobody else hits the i2c bus while we're sending our + sequence of messages, (such as the remote control thread) */ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (i == 0) { + /* First message in the transaction */ + en_start = 1; + } else if (!(msg[i].flags & I2C_M_NOSTART)) { + /* Device supports repeated-start */ + en_start = 1; + } else { + /* Not the first packet and device doesn't support + repeated start */ + en_start = 0; + } + if (i == (num - 1)) { + /* Last message in the transaction */ + en_stop = 1; + } + + if (msg[i].flags & I2C_M_RD) { + /* Read request */ + u16 index, value; + uint8_t i2c_dest; + + i2c_dest = (msg[i].addr << 1); + value = ((en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F)) << 8 | i2c_dest; + /* I2C ctrl + FE bus; */ + index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); + + result = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_READ, + USB_TYPE_VENDOR | USB_DIR_IN, + value, index, msg[i].buf, + msg[i].len, + USB_CTRL_GET_TIMEOUT); + if (result < 0) { + err("i2c read error (status = %d)\n", result); + break; + } + } else { + /* Write request */ + buf[0] = REQUEST_NEW_I2C_WRITE; + buf[1] = (msg[i].addr << 1); + buf[2] = (en_start << 7) | (en_stop << 6) | + (msg[i].len & 0x3F); + /* I2C ctrl + FE bus; */ + buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30); + /* The Actual i2c payload */ + memcpy(&buf[4], msg[i].buf, msg[i].len); + + result = usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev, 0), + REQUEST_NEW_I2C_WRITE, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, buf, msg[i].len + 4, + USB_CTRL_GET_TIMEOUT); + if (result < 0) { + err("i2c write error (status = %d)\n", result); + break; + } + } + } + mutex_unlock(&d->i2c_mutex); + return i; +} + +/* + * I2C master xfer function (pre-1.20 firmware) + */ +static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, + struct i2c_msg *msg, int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int i,len; @@ -124,6 +213,21 @@ static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num return i; } +static int dib0700_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct dib0700_state *st = d->priv; + + if (st->fw_use_new_i2c_api == 1) { + /* User running at least fw 1.20 */ + return dib0700_i2c_xfer_new(adap, msg, num); + } else { + /* Use legacy calls */ + return dib0700_i2c_xfer_legacy(adap, msg, num); + } +} + static u32 dib0700_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 110d9344bc92..2555e53b31dd 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1127,7 +1127,7 @@ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ .usb_ctrl = DEVICE_SPECIFIC, \ - .firmware = "dvb-usb-dib0700-1.10.fw", \ + .firmware = "dvb-usb-dib0700-1.20.fw", \ .download_firmware = dib0700_download_firmware, \ .no_reconnect = 1, \ .size_of_priv = sizeof(struct dib0700_state), \ -- cgit v1.2.1 From 4d2858c65bbd9a98d109b3548b4742d7fd74dcb0 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Sat, 6 Sep 2008 13:54:06 -0300 Subject: V4L/DVB (9040): TTUSB-DEC DVB-S: claim to have lock As reported by BOUWSMA Barry the readout of the signal status doesn't work on dec3000-s models. Since we don't know how to do it better, revert back to the old behaviour and always report a signal lock. Reported by Barry Bouwsma Signed-off-by: Peter Beutner Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttusb-dec/ttusbdecfe.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 443af24097f3..21260aad1e54 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -38,7 +38,17 @@ struct ttusbdecfe_state { }; -static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int ttusbdecfe_dvbs_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; + return 0; +} + + +static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, + fe_status_t *status) { struct ttusbdecfe_state* state = fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x00, @@ -251,7 +261,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { .get_tune_settings = ttusbdecfe_dvbt_get_tune_settings, - .read_status = ttusbdecfe_read_status, + .read_status = ttusbdecfe_dvbt_read_status, }; static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { @@ -273,7 +283,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { .set_frontend = ttusbdecfe_dvbs_set_frontend, - .read_status = ttusbdecfe_read_status, + .read_status = ttusbdecfe_dvbs_read_status, .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, .set_voltage = ttusbdecfe_dvbs_set_voltage, -- cgit v1.2.1 From 8751aaa6c8be191171cd8c7db01a9b4e01892b08 Mon Sep 17 00:00:00 2001 From: Daniel Oliveira Nascimento Date: Sun, 7 Sep 2008 12:39:44 -0300 Subject: V4L/DVB (9041): Add support YUAN High-Tech STK7700D (1164:1f08) This patch extends the dib0700 driver to support the DVB-part of the Asus notebook M51Sn tv-tunner (USB-ID 1164:1f08). Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 2555e53b31dd..a5e970ecab2c 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1120,6 +1120,7 @@ struct usb_device_id dib0700_usb_id_table[] = { /* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, + { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1409,7 +1410,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 4, + .num_device_descs = 5, .devices = { { "Terratec Cinergy HT USB XE", { &dib0700_usb_id_table[27], NULL }, @@ -1427,6 +1428,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[37], NULL }, { NULL }, }, + { "YUAN High-Tech STK7700PH", + { &dib0700_usb_id_table[38], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index e60e87315548..7bf5a1cdb49c 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -225,6 +225,7 @@ #define USB_PID_ASUS_U3000 0x171f #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc +#define USB_PID_YUAN_STK7700PH 0x1f08 #define USB_PID_DW2102 0x2102 #define USB_PID_XTENSIONS_XD_380 0x0381 #define USB_PID_TELESTAR_STARSTICK_2 0x8000 -- cgit v1.2.1 From 5769743ad345881911cee4e73ddf6120b00ed3eb Mon Sep 17 00:00:00 2001 From: Albert Comerma Date: Sun, 7 Sep 2008 12:43:33 -0300 Subject: V4L/DVB (9042): Add support for Asus My Cinema U3000 Hybrid This patch introduces support for dvb-t for the following dibcom based cards: Asus My Cinema U3000 Hybrid (USB-ID: 0b05:1736) Signed-off-by: Albert Comerma Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 5 +++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index a5e970ecab2c..d08cd4562097 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1121,6 +1121,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1432,6 +1433,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[38], NULL }, { NULL }, }, + { "Asus My Cinema-U3000Hybrid", + { &dib0700_usb_id_table[39], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 7bf5a1cdb49c..8926db2fc489 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -223,6 +223,7 @@ #define USB_PID_GIGABYTE_U7000 0x7001 #define USB_PID_GIGABYTE_U8000 0x7002 #define USB_PID_ASUS_U3000 0x171f +#define USB_PID_ASUS_U3000H 0x1736 #define USB_PID_ASUS_U3100 0x173f #define USB_PID_YUAN_EC372S 0x1edc #define USB_PID_YUAN_STK7700PH 0x1f08 -- cgit v1.2.1 From cb22cb5213192d2c0baaeec0ae4961e268916419 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 8 Sep 2008 05:42:42 -0300 Subject: V4L/DVB (9044): Add support for Pinnacle PCTV HD Pro 801e (ATSC only) Add digital support for the Pinnacle PCTV HD Pro 801e (usb id 2304:023a) Thanks to Patrick Boettcher for providing new firmware fixing the issue with the i2c that prevented the xc5000 from working. Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700.h | 1 + drivers/media/dvb/dvb-usb/dib0700_core.c | 7 +- drivers/media/dvb/dvb-usb/dib0700_devices.c | 111 ++++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 4 files changed, 119 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index cc0c51d82f2c..739193943c17 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -42,6 +42,7 @@ struct dib0700_state { u8 rc_counter; u8 is_dib7000pc; u8 fw_use_new_i2c_api; + u8 disable_streaming_master_mode; }; extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val); diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 4daac8642006..dd53cee3896d 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -350,7 +350,12 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) b[0] = REQUEST_ENABLE_VIDEO; b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ - b[2] = (0x01 << 4); /* Master mode */ + + if (st->disable_streaming_master_mode == 1) + b[2] = 0x00; + else + b[2] = (0x01 << 4); /* Master mode */ + b[3] = 0x00; deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index d08cd4562097..7d9efd702129 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -14,6 +14,8 @@ #include "mt2060.h" #include "mt2266.h" #include "tuner-xc2028.h" +#include "xc5000.h" +#include "s5h1411.h" #include "dib0070.h" static int force_lna_activation; @@ -1078,6 +1080,89 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) return adap->fe == NULL ? -ENODEV : 0; } +/* S5H1411 */ +static struct s5h1411_config pinnacle_801e_config = { + .output_mode = S5H1411_PARALLEL_OUTPUT, + .gpio = S5H1411_GPIO_OFF, + .mpeg_timing = S5H1411_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, + .qam_if = S5H1411_IF_44000, + .vsb_if = S5H1411_IF_44000, + .inversion = S5H1411_INVERSION_OFF, + .status_mode = S5H1411_DEMODLOCKING +}; + +/* Pinnacle PCTV HD Pro 801e GPIOs map: + GPIO0 - currently unknown + GPIO1 - xc5000 tuner reset + GPIO2 - CX25843 sleep + GPIO3 - currently unknown + GPIO4 - currently unknown + GPIO6 - currently unknown + GPIO7 - currently unknown + GPIO9 - currently unknown + GPIO10 - CX25843 reset + */ +static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* Make use of the new i2c functions from FW 1.20 */ + st->fw_use_new_i2c_api = 1; + + /* The s5h1411 requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + /* All msleep values taken from Windows USB trace */ + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO3, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(400); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(60); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(30); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 0); + msleep(30); + + /* Put the CX25843 to sleep for now since we're in digital mode */ + dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); + + /* GPIOs are initialized, do the attach */ + adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, + &adap->dev->i2c_adap); + return adap->fe == NULL ? -ENODEV : 0; +} + +int dib0700_xc5000_tuner_callback(void *priv, int command, int arg) +{ + struct dvb_usb_adapter *adap = priv; + + /* Reset the tuner */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); + msleep(330); /* from Windows USB trace */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); + msleep(330); /* from Windows USB trace */ + + return 0; +} + +static struct xc5000_config s5h1411_xc5000_tunerconfig = { + .i2c_address = 0x64, + .if_khz = 5380, + .tuner_callback = dib0700_xc5000_tuner_callback +}; + +static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) +{ + return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, + &s5h1411_xc5000_tunerconfig, adap) + == NULL ? -ENODEV : 0; +} + /* DVB-USB and USB stuff follows */ struct usb_device_id dib0700_usb_id_table[] = { /* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, @@ -1122,6 +1207,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, +/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1442,6 +1528,31 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map = dib0700_rc_keys, .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .frontend_attach = s5h1411_frontend_attach, + .tuner_attach = xc5000_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = sizeof(struct + dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "Pinnacle PCTV HD Pro USB Stick", + { &dib0700_usb_id_table[40], NULL }, + { NULL }, + }, + }, + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 8926db2fc489..38a23be68dbc 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -171,6 +171,7 @@ #define USB_PID_PINNACLE_PCTV71E 0x022b #define USB_PID_PINNACLE_PCTV72E 0x0236 #define USB_PID_PINNACLE_PCTV73E 0x0237 +#define USB_PID_PINNACLE_PCTV801E 0x023a #define USB_PID_PCTV_200E 0x020e #define USB_PID_PCTV_400E 0x020f #define USB_PID_PCTV_450E 0x0222 -- cgit v1.2.1 From a58843743ca0a774fbfc551adb2e5ecd04d96079 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Thu, 25 Sep 2008 06:21:11 -0300 Subject: V4L/DVB (9045): Add Pinnacle 801e dependencies to KConfig Support for the Pinnacle PCTV HD Pro 801e creates a dib0700 dependency on the xc5000 tuner and s5h1411 demodulator drivers. Update KConfig accordingly. Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index aee3b5dd651b..5880f2d4513f 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -72,9 +72,11 @@ config DVB_USB_DIB0700 select DVB_DIB7000P select DVB_DIB7000M select DVB_DIB3000MC + select DVB_S5H1411 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The -- cgit v1.2.1 From d2fc3bfcc3abd14ffd1191b37d2809e780919ef4 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Thu, 25 Sep 2008 06:22:23 -0300 Subject: V4L/DVB (9046): Add support for Non-Pro version of Pinnacle PCTV HD USB Stick Add USB ID for Pinnacle PCTV HD USB Stick. According to the USB trace and photos, the only difference is the removal of the port for the analog S-video/audio input. Thanks to Mike Pringle for providing the USB trace of the device starting up, and testing the support. Signed-off-by: Devin Heitmueller Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 7d9efd702129..7e692b3b078e 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1208,6 +1208,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, /* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1542,12 +1543,16 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "Pinnacle PCTV HD Pro USB Stick", { &dib0700_usb_id_table[40], NULL }, { NULL }, }, + { "Pinnacle PCTV HD USB Stick", + { &dib0700_usb_id_table[41], NULL }, + { NULL }, + }, }, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dib0700_rc_keys, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 38a23be68dbc..dfaf1d2574db 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -172,6 +172,7 @@ #define USB_PID_PINNACLE_PCTV72E 0x0236 #define USB_PID_PINNACLE_PCTV73E 0x0237 #define USB_PID_PINNACLE_PCTV801E 0x023a +#define USB_PID_PINNACLE_PCTV801E_SE 0x023b #define USB_PID_PCTV_200E 0x020e #define USB_PID_PCTV_400E 0x020f #define USB_PID_PCTV_450E 0x0222 -- cgit v1.2.1 From 48aa739164ca6430b8b1da12ea367b44bb14ce82 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 25 Sep 2008 06:52:24 -0300 Subject: V4L/DVB (9047): [PATCH] Add remote control support to Nova-TD (52009) This patch adds remote control support for the Hauppauge WinTV Nova-TD (Diversity) model. (That's the 52009 version.) It also adds the key-codes for the credit-card style remote control that comes with this particular adapter. Signed-off-by: Chris Rankin Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 44 ++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 7e692b3b078e..565563e68103 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -679,6 +679,43 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0x01, 0x7d, KEY_VOLUMEDOWN }, { 0x02, 0x42, KEY_CHANNELUP }, { 0x00, 0x7d, KEY_CHANNELDOWN }, + + /* Key codes for Nova-TD "credit card" remote control. */ + { 0x1d, 0x00, KEY_0 }, + { 0x1d, 0x01, KEY_1 }, + { 0x1d, 0x02, KEY_2 }, + { 0x1d, 0x03, KEY_3 }, + { 0x1d, 0x04, KEY_4 }, + { 0x1d, 0x05, KEY_5 }, + { 0x1d, 0x06, KEY_6 }, + { 0x1d, 0x07, KEY_7 }, + { 0x1d, 0x08, KEY_8 }, + { 0x1d, 0x09, KEY_9 }, + { 0x1d, 0x0a, KEY_TEXT }, + { 0x1d, 0x0d, KEY_MENU }, + { 0x1d, 0x0f, KEY_MUTE }, + { 0x1d, 0x10, KEY_VOLUMEUP }, + { 0x1d, 0x11, KEY_VOLUMEDOWN }, + { 0x1d, 0x12, KEY_CHANNEL }, + { 0x1d, 0x14, KEY_UP }, + { 0x1d, 0x15, KEY_DOWN }, + { 0x1d, 0x16, KEY_LEFT }, + { 0x1d, 0x17, KEY_RIGHT }, + { 0x1d, 0x1c, KEY_TV }, + { 0x1d, 0x1e, KEY_NEXT }, + { 0x1d, 0x1f, KEY_BACK }, + { 0x1d, 0x20, KEY_CHANNELUP }, + { 0x1d, 0x21, KEY_CHANNELDOWN }, + { 0x1d, 0x24, KEY_LAST }, + { 0x1d, 0x25, KEY_OK }, + { 0x1d, 0x30, KEY_PAUSE }, + { 0x1d, 0x32, KEY_REWIND }, + { 0x1d, 0x34, KEY_FASTFORWARD }, + { 0x1d, 0x35, KEY_PLAY }, + { 0x1d, 0x36, KEY_STOP }, + { 0x1d, 0x37, KEY_RECORD }, + { 0x1d, 0x3b, KEY_GOTO }, + { 0x1d, 0x3d, KEY_POWER }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ @@ -1383,7 +1420,12 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[31], NULL }, { NULL }, } - } + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 1, -- cgit v1.2.1 From ebb8d68a5c8c236acd8e8cf8f0d6046e027a8e21 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Wed, 10 Sep 2008 01:39:20 -0300 Subject: V4L/DVB (9048): add a general-purpose callback pointer to struct dvb_frontend Remove tuner_callback pointers from tuner driver configuration and private state structures, replaced with a general-purpose callback pointer within struct dvb_frontend. A new parameter is added to the callback function, called component. This allows us to use this callback pointer by frontend components other than the tuner, if need be. So far, this is only used by tuner drivers. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 1c575402814d..3055301ff3ca 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -220,6 +220,8 @@ struct dvb_frontend { void *sec_priv; void *analog_demod_priv; struct dtv_frontend_properties dtv_property_cache; +#define DVB_FRONTEND_COMPONENT_TUNER 0 + int (*callback)(void *adapter_priv, int component, int cmd, int arg); }; extern int dvb_register_frontend(struct dvb_adapter *dvb, -- cgit v1.2.1 From d7cba043d7ec840d67bd5143779d1febe7d83407 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Fri, 12 Sep 2008 13:31:45 -0300 Subject: V4L/DVB (9049): convert tuner drivers to use dvb_frontend->callback Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cxusb.c | 7 +++++-- drivers/media/dvb/dvb-usb/dib0700_devices.c | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 1a746127cbda..406d7fba369d 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -742,7 +742,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) +static int dvico_bluebird_xc2028_callback(void *ptr, int component, + int command, int arg) { struct dvb_usb_adapter *adap = ptr; struct dvb_usb_device *d = adap->dev; @@ -770,7 +771,6 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) struct xc2028_config cfg = { .i2c_adap = &adap->dev->i2c_adap, .i2c_addr = 0x61, - .callback = dvico_bluebird_xc2028_callback, }; static struct xc2028_ctrl ctl = { .fname = XC2028_DEFAULT_FIRMWARE, @@ -778,6 +778,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) .demod = XC3028_FE_ZARLINK456, }; + /* FIXME: generalize & move to common area */ + adap->fe->callback = dvico_bluebird_xc2028_callback; + fe = dvb_attach(xc2028_attach, adap->fe, &cfg); if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) return -EIO; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 565563e68103..8b74e13a6460 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -368,7 +368,8 @@ static struct dib7000p_config stk7700ph_dib7700_xc3028_config = { .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, }; -static int stk7700ph_xc3028_callback(void *ptr, int command, int arg) +static int stk7700ph_xc3028_callback(void *ptr, int component, + int command, int arg) { struct dvb_usb_adapter *adap = ptr; @@ -396,7 +397,6 @@ static struct xc2028_ctrl stk7700ph_xc3028_ctrl = { static struct xc2028_config stk7700ph_xc3028_config = { .i2c_addr = 0x61, - .callback = stk7700ph_xc3028_callback, .ctrl = &stk7700ph_xc3028_ctrl, }; @@ -437,7 +437,9 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) DIBX000_I2C_INTERFACE_TUNER, 1); stk7700ph_xc3028_config.i2c_adap = tun_i2c; - stk7700ph_xc3028_config.video_dev = adap; + + /* FIXME: generalize & move to common area */ + adap->fe->callback = stk7700ph_xc3028_callback; return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) == NULL ? -ENODEV : 0; -- cgit v1.2.1 From 767f3b3bf23244d52be0492df20b0eaf14f501c5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 25 Sep 2008 09:47:07 -0300 Subject: V4L/DVB (9051): dib0700: use dvb_frontend->callback for xc5000 gpio reset The tuner_callback function pointer from struct xc5000_config has been removed. Use dvb_frontend->callback instead. Also, mark function dib0700_xc5000_tuner_callback as static int. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 8b74e13a6460..9891ca0924a3 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1176,7 +1176,8 @@ static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) return adap->fe == NULL ? -ENODEV : 0; } -int dib0700_xc5000_tuner_callback(void *priv, int command, int arg) +static int dib0700_xc5000_tuner_callback(void *priv, int component, + int command, int arg) { struct dvb_usb_adapter *adap = priv; @@ -1192,14 +1193,16 @@ int dib0700_xc5000_tuner_callback(void *priv, int command, int arg) static struct xc5000_config s5h1411_xc5000_tunerconfig = { .i2c_address = 0x64, .if_khz = 5380, - .tuner_callback = dib0700_xc5000_tuner_callback }; static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, - &s5h1411_xc5000_tunerconfig, adap) + &s5h1411_xc5000_tunerconfig) == NULL ? -ENODEV : 0; + + /* FIXME: generalize & move to common area */ + adap->fe->callback = dib0700_xc5000_tuner_callback; } /* DVB-USB and USB stuff follows */ -- cgit v1.2.1 From 1dc7b76a89ea639a575c33710879c425d416dbdb Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Wed, 24 Sep 2008 22:48:53 -0300 Subject: V4L/DVB (9067): Kconfig correction for USB card modification with SI2109/2110 demodulator. Kconfig correction for USB card modification with SI2109/2110 demodulator. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 5880f2d4513f..241c9ab54b1b 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -254,6 +254,7 @@ config DVB_USB_DW2102 select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_SI21XX if !DVB_FE_CUSTOMISE help Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers and the TeVii S650. -- cgit v1.2.1 From f907c0207924dd598db37092d331738e3fcb9fbd Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Wed, 24 Sep 2008 23:18:27 -0300 Subject: V4L/DVB (9068): Kconfig dependency fix for DW2002 card with ST STV0288 demodulator. Kconfig dependency fix for DW2002 card with ST STV0288 demodulator. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dm1105/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig index 2af5fffe138e..1332301ef3ae 100644 --- a/drivers/media/dvb/dm1105/Kconfig +++ b/drivers/media/dvb/dm1105/Kconfig @@ -3,6 +3,8 @@ config DVB_DM1105 depends on DVB_CORE && PCI && I2C select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_SI21XX if !DVB_FE_CUSTOMISE help -- cgit v1.2.1 From d48cb402a1ba48c4ad4a36c3c561386027318459 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 26 Sep 2008 00:16:25 -0300 Subject: V4L/DVB (9071): S2API: Implement result codes for individual commands This allows application developers to determine which particular command in a sequence is invalid, or failing with error. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 7da25372078c..0ef9c2a2af87 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1262,8 +1262,10 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, goto out; } - for (i = 0; i < tvps->num; i++) - err |= dtv_property_process_set(fe, tvp + i, inode, file); + for (i = 0; i < tvps->num; i++) { + (tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file); + err |= (tvp + i)->result; + } if(fe->dtv_property_cache.state == DTV_TUNE) { printk("%s() Property cache is full, tuning\n", __FUNCTION__); @@ -1295,8 +1297,10 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, goto out; } - for (i = 0; i < tvps->num; i++) - err |= dtv_property_process_get(fe, tvp + i, inode, file); + for (i = 0; i < tvps->num; i++) { + (tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file); + err |= (tvp + i)->result; + } if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; -- cgit v1.2.1 From eacf8d8d6bc6798f6870a2cf2c159bfcde3759ac Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 26 Sep 2008 00:29:49 -0300 Subject: V4L/DVB (9072): S2API: Add DTV_API_VERSION command This allows application developers to query the dvb-core API version dynamically, helping developers understand whether certain features will be available. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 0ef9c2a2af87..4c3f0d7e355c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -40,6 +40,7 @@ #include "dvb_frontend.h" #include "dvbdev.h" +#include static int dvb_frontend_debug; static int dvb_shutdown_timeout; @@ -836,6 +837,11 @@ struct dtv_cmds_h dtv_cmds[] = { .set = 0, .buffer = 1, }, + [DTV_API_VERSION] = { + .name = "DTV_API_VERSION", + .cmd = DTV_API_VERSION, + .set = 0, + }, }; void dtv_property_dump(struct dtv_property *tvp) @@ -1104,6 +1110,9 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_TONE: tvp->u.data = fe->dtv_property_cache.sectone; break; + case DTV_API_VERSION: + tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR; + break; default: r = -1; } -- cgit v1.2.1 From 07c6bb9e6e5c9b8d0f697493cdd3978fc193ca90 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 30 Sep 2008 13:57:42 -0300 Subject: V4L/DVB (9105): correct Makefile symbol for stv0288 frontend Signed-off-by: Janne Grunau Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 491eb5c55855..aba79f4a63a7 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -53,5 +53,5 @@ obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o obj-$(CONFIG_DVB_AF9013) += af9013.o obj-$(CONFIG_DVB_CX24116) += cx24116.o obj-$(CONFIG_DVB_SI21XX) += si21xx.o -obj-$(CONFIG_DVB_STV0299) += stv0288.o +obj-$(CONFIG_DVB_STV0288) += stv0288.o obj-$(CONFIG_DVB_STB6000) += stb6000.o -- cgit v1.2.1 From 986bd1e58b18c09b753f797df19251804bfe3e84 Mon Sep 17 00:00:00 2001 From: Tomi Orava Date: Fri, 19 Sep 2008 00:48:31 -0300 Subject: V4L/DVB (9107): Alternative version of Terratec Cinergy T2 driver Alternative version of the Terratec Cinergy T2 driver that uses the dvb framework. Signed-off-by: Tomi Orava Signed-off-by: Thierry MERLE [mchehab@redhat.com: fix dvb Makefile] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/Kconfig | 1 - drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/cinergyT2/Kconfig | 85 --- drivers/media/dvb/cinergyT2/Makefile | 3 - drivers/media/dvb/cinergyT2/cinergyT2.c | 1105 ---------------------------- drivers/media/dvb/dvb-usb/Kconfig | 8 + drivers/media/dvb/dvb-usb/Makefile | 4 + drivers/media/dvb/dvb-usb/cinergyT2-core.c | 230 ++++++ drivers/media/dvb/dvb-usb/cinergyT2-fe.c | 351 +++++++++ drivers/media/dvb/dvb-usb/cinergyT2.h | 95 +++ 10 files changed, 689 insertions(+), 1195 deletions(-) delete mode 100644 drivers/media/dvb/cinergyT2/Kconfig delete mode 100644 drivers/media/dvb/cinergyT2/Makefile delete mode 100644 drivers/media/dvb/cinergyT2/cinergyT2.c create mode 100644 drivers/media/dvb/dvb-usb/cinergyT2-core.c create mode 100644 drivers/media/dvb/dvb-usb/cinergyT2-fe.c create mode 100644 drivers/media/dvb/dvb-usb/cinergyT2.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 14488f644792..0bcd852576d6 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -20,7 +20,6 @@ comment "Supported USB Adapters" source "drivers/media/dvb/dvb-usb/Kconfig" source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig" -source "drivers/media/dvb/cinergyT2/Kconfig" source "drivers/media/dvb/siano/Kconfig" comment "Supported FlexCopII (B2C2) Adapters" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index ea953a03e24d..f91e9eb15e52 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,4 +2,4 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/ dm1105/ +obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig deleted file mode 100644 index c03513b2ccae..000000000000 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ /dev/null @@ -1,85 +0,0 @@ -config DVB_CINERGYT2 - tristate "Terratec CinergyT2/qanu USB2 DVB-T receiver" - depends on DVB_CORE && USB && INPUT - help - Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers - - Say Y if you own such a device and want to use it. - - -config DVB_CINERGYT2_TUNING - bool "sophisticated fine-tuning for CinergyT2 cards" - depends on DVB_CINERGYT2 - help - Here you can fine-tune some parameters of the CinergyT2 driver. - - Normally you don't need to touch this, but in exotic setups you - may fine-tune your setup and adjust e.g. DMA buffer sizes for - a particular application. - - -config DVB_CINERGYT2_STREAM_URB_COUNT - int "Number of queued USB Request Blocks for Highspeed Stream Transfers" - depends on DVB_CINERGYT2_TUNING - 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 - 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" - 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 - sharing the same USB bus. - - -config DVB_CINERGYT2_QUERY_INTERVAL - int "Status update interval [milliseconds]" - depends on DVB_CINERGYT2_TUNING - 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 - measurements. - - Please keep in mind that these updates cause traffic on the tuner - control bus and thus may or may not affect reception sensitivity. - - The default value should be a safe choice for common applications. - - -config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE - bool "Register the onboard IR Remote Control Receiver as Input Device" - depends on DVB_CINERGYT2_TUNING - default y - help - 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 - delivered with the device is supported, please see the driver - source code to find out how to add support for other controls. - - -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" - help - If you have a very fast-repeating remote control you can try lower - values, for normal consumer receivers the default value should be - a safe choice. - diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile deleted file mode 100644 index d762d8cb0cf1..000000000000 --- a/drivers/media/dvb/cinergyT2/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o - -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c deleted file mode 100644 index a824f3719f81..000000000000 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ /dev/null @@ -1,1105 +0,0 @@ -/* - * TerraTec Cinergy T²/qanu USB2 DVB-T adapter. - * - * Copyright (C) 2004 Daniel Mack and - * Holger Waechtler - * - * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_net.h" - -#ifdef CONFIG_DVB_CINERGYT2_TUNING - #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT) - #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE) - #define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL) - #ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE - #define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL) - #define ENABLE_RC (1) - #endif -#else - #define STREAM_URB_COUNT (32) - #define STREAM_BUF_SIZE (512) /* bytes */ - #define ENABLE_RC (1) - #define RC_QUERY_INTERVAL (50) /* milliseconds */ - #define QUERY_INTERVAL (333) /* milliseconds */ -#endif - -#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" - -static int debug; -module_param_named(debug, debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(level, args...) \ -do { \ - if ((debug & level)) { \ - printk("%s: %s(): ", KBUILD_MODNAME, \ - __func__); \ - printk(args); } \ -} while (0) - -enum cinergyt2_ep1_cmd { - CINERGYT2_EP1_PID_TABLE_RESET = 0x01, - CINERGYT2_EP1_PID_SETUP = 0x02, - CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, - CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, - CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, - CINERGYT2_EP1_START_SCAN = 0x06, - CINERGYT2_EP1_CONTINUE_SCAN = 0x07, - CINERGYT2_EP1_GET_RC_EVENTS = 0x08, - CINERGYT2_EP1_SLEEP_MODE = 0x09 -}; - -struct dvbt_set_parameters_msg { - uint8_t cmd; - __le32 freq; - uint8_t bandwidth; - __le16 tps; - uint8_t flags; -} __attribute__((packed)); - -struct dvbt_get_status_msg { - __le32 freq; - uint8_t bandwidth; - __le16 tps; - uint8_t flags; - __le16 gain; - uint8_t snr; - __le32 viterbi_error_rate; - __le32 rs_error_rate; - __le32 uncorrected_block_count; - uint8_t lock_bits; - uint8_t prev_lock_bits; -} __attribute__((packed)); - -static struct dvb_frontend_info cinergyt2_fe_info = { - .name = DRIVER_NAME, - .type = FE_OFDM, - .frequency_min = 174000000, - .frequency_max = 862000000, - .frequency_stepsize = 166667, - .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_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_RECOVER | FE_CAN_MUTE_TS -}; - -struct cinergyt2 { - struct dvb_demux demux; - struct usb_device *udev; - struct mutex sem; - struct mutex wq_sem; - struct dvb_adapter adapter; - struct dvb_device *fedev; - struct dmxdev dmxdev; - struct dvb_net dvbnet; - - int streaming; - int sleeping; - - struct dvbt_set_parameters_msg param; - struct dvbt_get_status_msg status; - struct delayed_work query_work; - - wait_queue_head_t poll_wq; - int pending_fe_events; - int disconnect_pending; - unsigned int uncorrected_block_count; - atomic_t inuse; - - void *streambuf; - dma_addr_t streambuf_dmahandle; - struct urb *stream_urb [STREAM_URB_COUNT]; - -#ifdef ENABLE_RC - struct input_dev *rc_input_dev; - char phys[64]; - struct delayed_work rc_query_work; - int rc_input_event; - __le32 rc_last_code; - unsigned long last_event_jiffies; -#endif -}; - -enum { - CINERGYT2_RC_EVENT_TYPE_NONE = 0x00, - CINERGYT2_RC_EVENT_TYPE_NEC = 0x01, - CINERGYT2_RC_EVENT_TYPE_RC5 = 0x02 -}; - -struct cinergyt2_rc_event { - char type; - __le32 value; -} __attribute__((packed)); - -static const uint32_t rc_keys[] = { - CINERGYT2_RC_EVENT_TYPE_NEC, 0xfe01eb04, KEY_POWER, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xfd02eb04, KEY_1, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xfc03eb04, KEY_2, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xfb04eb04, KEY_3, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xfa05eb04, KEY_4, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf906eb04, KEY_5, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf807eb04, KEY_6, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf708eb04, KEY_7, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf609eb04, KEY_8, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf50aeb04, KEY_9, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf30ceb04, KEY_0, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf40beb04, KEY_VIDEO, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf20deb04, KEY_REFRESH, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf10eeb04, KEY_SELECT, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xf00feb04, KEY_EPG, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xef10eb04, KEY_UP, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xeb14eb04, KEY_DOWN, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xee11eb04, KEY_LEFT, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xec13eb04, KEY_RIGHT, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xed12eb04, KEY_OK, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xea15eb04, KEY_TEXT, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe916eb04, KEY_INFO, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe817eb04, KEY_RED, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe718eb04, KEY_GREEN, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe619eb04, KEY_YELLOW, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe51aeb04, KEY_BLUE, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe31ceb04, KEY_VOLUMEUP, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe11eeb04, KEY_VOLUMEDOWN, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe21deb04, KEY_MUTE, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe41beb04, KEY_CHANNELUP, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xe01feb04, KEY_CHANNELDOWN, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xbf40eb04, KEY_PAUSE, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xb34ceb04, KEY_PLAY, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xa758eb04, KEY_RECORD, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xab54eb04, KEY_PREVIOUS, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xb748eb04, KEY_STOP, - CINERGYT2_RC_EVENT_TYPE_NEC, 0xa35ceb04, KEY_NEXT -}; - -static int cinergyt2_command (struct cinergyt2 *cinergyt2, - char *send_buf, int send_buf_len, - char *recv_buf, int recv_buf_len) -{ - int actual_len; - char dummy; - int ret; - - ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1), - send_buf, send_buf_len, &actual_len, 1000); - - if (ret) - dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret); - - if (!recv_buf) - recv_buf = &dummy; - - ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1), - recv_buf, recv_buf_len, &actual_len, 1000); - - if (ret) - dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret); - - return ret ? ret : actual_len; -} - -static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable) -{ - char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; - cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); -} - -static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep) -{ - char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 }; - cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); - cinergyt2->sleeping = sleep; -} - -static void cinergyt2_stream_irq (struct urb *urb); - -static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb) -{ - int err; - - usb_fill_bulk_urb(urb, - cinergyt2->udev, - usb_rcvbulkpipe(cinergyt2->udev, 0x2), - urb->transfer_buffer, - STREAM_BUF_SIZE, - cinergyt2_stream_irq, - cinergyt2); - - if ((err = usb_submit_urb(urb, GFP_ATOMIC))) - dprintk(1, "urb submission failed (err = %i)!\n", err); - - return err; -} - -static void cinergyt2_stream_irq (struct urb *urb) -{ - struct cinergyt2 *cinergyt2 = urb->context; - - if (urb->actual_length > 0) - dvb_dmx_swfilter(&cinergyt2->demux, - urb->transfer_buffer, urb->actual_length); - - if (cinergyt2->streaming) - cinergyt2_submit_stream_urb(cinergyt2, urb); -} - -static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2) -{ - int i; - - for (i=0; istream_urb[i]); - - usb_buffer_free(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE, - cinergyt2->streambuf, cinergyt2->streambuf_dmahandle); -} - -static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2) -{ - int i; - - cinergyt2->streambuf = usb_buffer_alloc(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE, - GFP_KERNEL, &cinergyt2->streambuf_dmahandle); - if (!cinergyt2->streambuf) { - dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n"); - return -ENOMEM; - } - - memset(cinergyt2->streambuf, 0, STREAM_URB_COUNT*STREAM_BUF_SIZE); - - for (i=0; itransfer_buffer = cinergyt2->streambuf + i * STREAM_BUF_SIZE; - urb->transfer_buffer_length = STREAM_BUF_SIZE; - - cinergyt2->stream_urb[i] = urb; - } - - return 0; -} - -static void cinergyt2_stop_stream_xfer (struct cinergyt2 *cinergyt2) -{ - int i; - - cinergyt2_control_stream_transfer(cinergyt2, 0); - - for (i=0; istream_urb[i]); -} - -static int cinergyt2_start_stream_xfer (struct cinergyt2 *cinergyt2) -{ - int i, err; - - for (i=0; istream_urb[i]))) { - cinergyt2_stop_stream_xfer(cinergyt2); - dprintk(1, "failed urb submission (%i: err = %i)!\n", i, err); - return err; - } - } - - cinergyt2_control_stream_transfer(cinergyt2, 1); - return 0; -} - -static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *demux = dvbdmxfeed->demux; - struct cinergyt2 *cinergyt2 = demux->priv; - - if (cinergyt2->disconnect_pending) - return -EAGAIN; - if (mutex_lock_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; - - if (cinergyt2->streaming == 0) - cinergyt2_start_stream_xfer(cinergyt2); - - cinergyt2->streaming++; - mutex_unlock(&cinergyt2->sem); - return 0; -} - -static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *demux = dvbdmxfeed->demux; - struct cinergyt2 *cinergyt2 = demux->priv; - - if (cinergyt2->disconnect_pending) - return -EAGAIN; - if (mutex_lock_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; - - if (--cinergyt2->streaming == 0) - cinergyt2_stop_stream_xfer(cinergyt2); - - mutex_unlock(&cinergyt2->sem); - return 0; -} - -/** - * convert linux-dvb frontend parameter set into TPS. - * See ETSI ETS-300744, section 4.6.2, table 9 for details. - * - * This function is probably reusable and may better get placed in a support - * library. - * - * We replace errornous fields by default TPS fields (the ones with value 0). - */ -static uint16_t compute_tps (struct dvb_frontend_parameters *p) -{ - struct dvb_ofdm_parameters *op = &p->u.ofdm; - uint16_t tps = 0; - - switch (op->code_rate_HP) { - case FEC_2_3: - tps |= (1 << 7); - break; - case FEC_3_4: - tps |= (2 << 7); - break; - case FEC_5_6: - tps |= (3 << 7); - break; - case FEC_7_8: - tps |= (4 << 7); - break; - case FEC_1_2: - case FEC_AUTO: - default: - /* tps |= (0 << 7) */; - } - - switch (op->code_rate_LP) { - case FEC_2_3: - tps |= (1 << 4); - break; - case FEC_3_4: - tps |= (2 << 4); - break; - case FEC_5_6: - tps |= (3 << 4); - break; - case FEC_7_8: - tps |= (4 << 4); - break; - case FEC_1_2: - case FEC_AUTO: - default: - /* tps |= (0 << 4) */; - } - - switch (op->constellation) { - case QAM_16: - tps |= (1 << 13); - break; - case QAM_64: - tps |= (2 << 13); - break; - case QPSK: - default: - /* tps |= (0 << 13) */; - } - - switch (op->transmission_mode) { - case TRANSMISSION_MODE_8K: - tps |= (1 << 0); - break; - case TRANSMISSION_MODE_2K: - default: - /* tps |= (0 << 0) */; - } - - switch (op->guard_interval) { - case GUARD_INTERVAL_1_16: - tps |= (1 << 2); - break; - case GUARD_INTERVAL_1_8: - tps |= (2 << 2); - break; - case GUARD_INTERVAL_1_4: - tps |= (3 << 2); - break; - case GUARD_INTERVAL_1_32: - default: - /* tps |= (0 << 2) */; - } - - switch (op->hierarchy_information) { - case HIERARCHY_1: - tps |= (1 << 10); - break; - case HIERARCHY_2: - tps |= (2 << 10); - break; - case HIERARCHY_4: - tps |= (3 << 10); - break; - case HIERARCHY_NONE: - default: - /* tps |= (0 << 10) */; - } - - return tps; -} - -static int cinergyt2_open (struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - int err = -EAGAIN; - - if (cinergyt2->disconnect_pending) - goto out; - err = mutex_lock_interruptible(&cinergyt2->wq_sem); - if (err) - goto out; - - err = mutex_lock_interruptible(&cinergyt2->sem); - if (err) - goto out_unlock1; - - if ((err = dvb_generic_open(inode, file))) - goto out_unlock2; - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - cinergyt2_sleep(cinergyt2, 0); - schedule_delayed_work(&cinergyt2->query_work, HZ/2); - } - - atomic_inc(&cinergyt2->inuse); - -out_unlock2: - mutex_unlock(&cinergyt2->sem); -out_unlock1: - mutex_unlock(&cinergyt2->wq_sem); -out: - return err; -} - -static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) -{ - 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_free_stream_urbs(cinergyt2); - kfree(cinergyt2); -} - -static int cinergyt2_release (struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - - mutex_lock(&cinergyt2->wq_sem); - - if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) { - cancel_rearming_delayed_work(&cinergyt2->query_work); - - mutex_lock(&cinergyt2->sem); - cinergyt2_sleep(cinergyt2, 1); - mutex_unlock(&cinergyt2->sem); - } - - mutex_unlock(&cinergyt2->wq_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); -} - -static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait) -{ - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - unsigned int mask = 0; - - if (cinergyt2->disconnect_pending) - return -EAGAIN; - if (mutex_lock_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; - - poll_wait(file, &cinergyt2->poll_wq, wait); - - if (cinergyt2->pending_fe_events != 0) - mask |= (POLLIN | POLLRDNORM | POLLPRI); - - mutex_unlock(&cinergyt2->sem); - - return mask; -} - - -static int cinergyt2_ioctl (struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - struct dvbt_get_status_msg *stat = &cinergyt2->status; - fe_status_t status = 0; - - switch (cmd) { - case FE_GET_INFO: - return copy_to_user((void __user*) arg, &cinergyt2_fe_info, - sizeof(struct dvb_frontend_info)); - - case FE_READ_STATUS: - if (0xffff - le16_to_cpu(stat->gain) > 30) - status |= FE_HAS_SIGNAL; - if (stat->lock_bits & (1 << 6)) - status |= FE_HAS_LOCK; - if (stat->lock_bits & (1 << 5)) - status |= FE_HAS_SYNC; - if (stat->lock_bits & (1 << 4)) - status |= FE_HAS_CARRIER; - if (stat->lock_bits & (1 << 1)) - status |= FE_HAS_VITERBI; - - return copy_to_user((void __user*) arg, &status, sizeof(status)); - - case FE_READ_BER: - return put_user(le32_to_cpu(stat->viterbi_error_rate), - (__u32 __user *) arg); - - case FE_READ_SIGNAL_STRENGTH: - return put_user(0xffff - le16_to_cpu(stat->gain), - (__u16 __user *) arg); - - case FE_READ_SNR: - return put_user((stat->snr << 8) | stat->snr, - (__u16 __user *) arg); - - case FE_READ_UNCORRECTED_BLOCKS: - { - uint32_t unc_count; - - if (mutex_lock_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; - unc_count = cinergyt2->uncorrected_block_count; - cinergyt2->uncorrected_block_count = 0; - mutex_unlock(&cinergyt2->sem); - - /* 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; - struct dvb_frontend_parameters p; - int err; - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - return -EPERM; - - if (copy_from_user(&p, (void __user*) arg, sizeof(p))) - return -EFAULT; - - if (cinergyt2->disconnect_pending) - return -EAGAIN; - if (mutex_lock_interruptible(&cinergyt2->sem)) - return -ERESTARTSYS; - - param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; - param->tps = cpu_to_le16(compute_tps(&p)); - param->freq = cpu_to_le32(p.frequency / 1000); - param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ; - - stat->lock_bits = 0; - cinergyt2->pending_fe_events++; - wake_up_interruptible(&cinergyt2->poll_wq); - - err = cinergyt2_command(cinergyt2, - (char *) param, sizeof(*param), - NULL, 0); - - mutex_unlock(&cinergyt2->sem); - - return (err < 0) ? err : 0; - } - - case FE_GET_FRONTEND: - /** - * trivial to implement (see struct dvbt_get_status_msg). - * equivalent to FE_READ ioctls, but needs - * TPS -> linux-dvb parameter set conversion. Feel free - * to implement this and send us a patch if you need this - * functionality. - */ - break; - - case FE_GET_EVENT: - { - /** - * for now we only fill the status field. the parameters - * are trivial to fill as soon FE_GET_FRONTEND is done. - */ - struct dvb_frontend_event __user *e = (void __user *) arg; - if (cinergyt2->pending_fe_events == 0) { - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - wait_event_interruptible(cinergyt2->poll_wq, - cinergyt2->pending_fe_events > 0); - } - cinergyt2->pending_fe_events = 0; - return cinergyt2_ioctl(inode, file, FE_READ_STATUS, - (unsigned long) &e->status); - } - - default: - ; - } - - return -EINVAL; -} - -static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct dvb_device *dvbdev = file->private_data; - struct cinergyt2 *cinergyt2 = dvbdev->priv; - int ret = 0; - - lock_kernel(); - - if (vma->vm_flags & (VM_WRITE | VM_EXEC)) { - ret = -EPERM; - goto bailout; - } - - if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) { - ret = -EINVAL; - goto bailout; - } - - vma->vm_flags |= (VM_IO | VM_DONTCOPY); - vma->vm_file = file; - - ret = remap_pfn_range(vma, vma->vm_start, - virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot) ? -EAGAIN : 0; -bailout: - unlock_kernel(); - return ret; -} - -static struct file_operations cinergyt2_fops = { - .owner = THIS_MODULE, - .ioctl = cinergyt2_ioctl, - .poll = cinergyt2_poll, - .open = cinergyt2_open, - .release = cinergyt2_release, - .mmap = cinergyt2_mmap -}; - -static struct dvb_device cinergyt2_fe_template = { - .users = ~0, - .writers = 1, - .readers = (~0)-1, - .fops = &cinergyt2_fops -}; - -#ifdef ENABLE_RC - -static void cinergyt2_query_rc (struct work_struct *work) -{ - struct cinergyt2 *cinergyt2 = - container_of(work, struct cinergyt2, rc_query_work.work); - char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS }; - struct cinergyt2_rc_event rc_events[12]; - int n, len, i; - - if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) - return; - - len = cinergyt2_command(cinergyt2, buf, sizeof(buf), - (char *) rc_events, sizeof(rc_events)); - if (len < 0) - goto out; - if (len == 0) { - if (time_after(jiffies, cinergyt2->last_event_jiffies + - msecs_to_jiffies(150))) { - /* stop key repeat */ - if (cinergyt2->rc_input_event != KEY_MAX) { - dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); - input_report_key(cinergyt2->rc_input_dev, - cinergyt2->rc_input_event, 0); - input_sync(cinergyt2->rc_input_dev); - cinergyt2->rc_input_event = KEY_MAX; - } - cinergyt2->rc_last_code = cpu_to_le32(~0); - } - goto out; - } - cinergyt2->last_event_jiffies = jiffies; - - for (n = 0; n < (len / sizeof(rc_events[0])); n++) { - dprintk(1, "rc_events[%d].value = %x, type=%x\n", - n, le32_to_cpu(rc_events[n].value), rc_events[n].type); - - if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC && - rc_events[n].value == cpu_to_le32(~0)) { - /* keyrepeat bit -> just repeat last rc_input_event */ - } else { - cinergyt2->rc_input_event = KEY_MAX; - for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) { - if (rc_keys[i + 0] == rc_events[n].type && - rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) { - cinergyt2->rc_input_event = rc_keys[i + 2]; - break; - } - } - } - - if (cinergyt2->rc_input_event != KEY_MAX) { - if (rc_events[n].value == cinergyt2->rc_last_code && - cinergyt2->rc_last_code != cpu_to_le32(~0)) { - /* emit a key-up so the double event is recognized */ - dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event); - input_report_key(cinergyt2->rc_input_dev, - cinergyt2->rc_input_event, 0); - } - dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); - input_report_key(cinergyt2->rc_input_dev, - cinergyt2->rc_input_event, 1); - input_sync(cinergyt2->rc_input_dev); - cinergyt2->rc_last_code = rc_events[n].value; - } - } - -out: - schedule_delayed_work(&cinergyt2->rc_query_work, - msecs_to_jiffies(RC_QUERY_INTERVAL)); - - mutex_unlock(&cinergyt2->sem); -} - -static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) -{ - struct input_dev *input_dev; - int i; - int err; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys)); - strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys)); - cinergyt2->rc_input_event = KEY_MAX; - cinergyt2->rc_last_code = cpu_to_le32(~0); - INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc); - - input_dev->name = DRIVER_NAME " remote control"; - input_dev->phys = cinergyt2->phys; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) - set_bit(rc_keys[i + 2], input_dev->keybit); - input_dev->keycodesize = 0; - input_dev->keycodemax = 0; - input_dev->id.bustype = BUS_USB; - input_dev->id.vendor = le16_to_cpu(cinergyt2->udev->descriptor.idVendor); - input_dev->id.product = le16_to_cpu(cinergyt2->udev->descriptor.idProduct); - input_dev->id.version = 1; - input_dev->dev.parent = &cinergyt2->udev->dev; - - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; - } - - cinergyt2->rc_input_dev = input_dev; - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); - - return 0; -} - -static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) -{ - cancel_rearming_delayed_work(&cinergyt2->rc_query_work); - input_unregister_device(cinergyt2->rc_input_dev); -} - -static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) -{ - cancel_rearming_delayed_work(&cinergyt2->rc_query_work); -} - -static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) -{ - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -} - -#else - -static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; } -static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { } -static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { } -static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { } - -#endif /* ENABLE_RC */ - -static void cinergyt2_query (struct work_struct *work) -{ - struct cinergyt2 *cinergyt2 = - container_of(work, struct cinergyt2, query_work.work); - char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; - struct dvbt_get_status_msg *s = &cinergyt2->status; - uint8_t lock_bits; - - if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) - return; - - lock_bits = s->lock_bits; - - cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s)); - - cinergyt2->uncorrected_block_count += - le32_to_cpu(s->uncorrected_block_count); - - if (lock_bits != s->lock_bits) { - wake_up_interruptible(&cinergyt2->poll_wq); - cinergyt2->pending_fe_events++; - } - - schedule_delayed_work(&cinergyt2->query_work, - msecs_to_jiffies(QUERY_INTERVAL)); - - mutex_unlock(&cinergyt2->sem); -} - -static int cinergyt2_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct cinergyt2 *cinergyt2; - int err; - - if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { - dprintk(1, "out of memory?!?\n"); - return -ENOMEM; - } - - usb_set_intfdata (intf, (void *) cinergyt2); - - mutex_init(&cinergyt2->sem); - mutex_init(&cinergyt2->wq_sem); - init_waitqueue_head (&cinergyt2->poll_wq); - INIT_DELAYED_WORK(&cinergyt2->query_work, cinergyt2_query); - - cinergyt2->udev = interface_to_usbdev(intf); - cinergyt2->param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; - - if (cinergyt2_alloc_stream_urbs (cinergyt2) < 0) { - dprintk(1, "unable to allocate stream urbs\n"); - kfree(cinergyt2); - return -ENOMEM; - } - - err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, - THIS_MODULE, &cinergyt2->udev->dev, - adapter_nr); - if (err < 0) { - kfree(cinergyt2); - return err; - } - - cinergyt2->demux.priv = cinergyt2; - cinergyt2->demux.filternum = 256; - cinergyt2->demux.feednum = 256; - cinergyt2->demux.start_feed = cinergyt2_start_feed; - cinergyt2->demux.stop_feed = cinergyt2_stop_feed; - cinergyt2->demux.dmx.capabilities = DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - - if ((err = dvb_dmx_init(&cinergyt2->demux)) < 0) { - dprintk(1, "dvb_dmx_init() failed (err = %d)\n", err); - goto bailout; - } - - cinergyt2->dmxdev.filternum = cinergyt2->demux.filternum; - cinergyt2->dmxdev.demux = &cinergyt2->demux.dmx; - cinergyt2->dmxdev.capabilities = 0; - - if ((err = dvb_dmxdev_init(&cinergyt2->dmxdev, &cinergyt2->adapter)) < 0) { - dprintk(1, "dvb_dmxdev_init() failed (err = %d)\n", err); - goto bailout; - } - - if (dvb_net_init(&cinergyt2->adapter, &cinergyt2->dvbnet, &cinergyt2->demux.dmx)) - dprintk(1, "dvb_net_init() failed!\n"); - - dvb_register_device(&cinergyt2->adapter, &cinergyt2->fedev, - &cinergyt2_fe_template, cinergyt2, - DVB_DEVICE_FRONTEND); - - err = cinergyt2_register_rc(cinergyt2); - if (err) - goto bailout; - - return 0; - -bailout: - dvb_net_release(&cinergyt2->dvbnet); - dvb_dmxdev_release(&cinergyt2->dmxdev); - dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_adapter(&cinergyt2->adapter); - cinergyt2_free_stream_urbs(cinergyt2); - kfree(cinergyt2); - return -ENOMEM; -} - -static void cinergyt2_disconnect (struct usb_interface *intf) -{ - struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); - - cinergyt2_unregister_rc(cinergyt2); - cancel_rearming_delayed_work(&cinergyt2->query_work); - wake_up_interruptible(&cinergyt2->poll_wq); - - cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); - cinergyt2->disconnect_pending = 1; - - 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 (cinergyt2->disconnect_pending) - return -EAGAIN; - if (mutex_lock_interruptible(&cinergyt2->wq_sem)) - return -ERESTARTSYS; - - cinergyt2_suspend_rc(cinergyt2); - cancel_rearming_delayed_work(&cinergyt2->query_work); - - mutex_lock(&cinergyt2->sem); - if (cinergyt2->streaming) - cinergyt2_stop_stream_xfer(cinergyt2); - cinergyt2_sleep(cinergyt2, 1); - mutex_unlock(&cinergyt2->sem); - - mutex_unlock(&cinergyt2->wq_sem); - - return 0; -} - -static int cinergyt2_resume (struct usb_interface *intf) -{ - struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); - struct dvbt_set_parameters_msg *param = &cinergyt2->param; - int err = -EAGAIN; - - if (cinergyt2->disconnect_pending) - goto out; - err = mutex_lock_interruptible(&cinergyt2->wq_sem); - if (err) - goto out; - - err = mutex_lock_interruptible(&cinergyt2->sem); - if (err) - goto out_unlock1; - - if (!cinergyt2->sleeping) { - cinergyt2_sleep(cinergyt2, 0); - cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0); - if (cinergyt2->streaming) - cinergyt2_start_stream_xfer(cinergyt2); - schedule_delayed_work(&cinergyt2->query_work, HZ/2); - } - - cinergyt2_resume_rc(cinergyt2); - - mutex_unlock(&cinergyt2->sem); -out_unlock1: - mutex_unlock(&cinergyt2->wq_sem); -out: - return err; -} - -static const struct usb_device_id cinergyt2_table [] __devinitdata = { - { USB_DEVICE(0x0ccd, 0x0038) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(usb, cinergyt2_table); - -static struct usb_driver cinergyt2_driver = { - .name = "cinergyT2", - .probe = cinergyt2_probe, - .disconnect = cinergyt2_disconnect, - .suspend = cinergyt2_suspend, - .resume = cinergyt2_resume, - .id_table = cinergyt2_table -}; - -static int __init cinergyt2_init (void) -{ - int err; - - if ((err = usb_register(&cinergyt2_driver)) < 0) - dprintk(1, "usb_register() failed! (err %i)\n", err); - - return err; -} - -static void __exit cinergyt2_exit (void) -{ - usb_deregister(&cinergyt2_driver); -} - -module_init (cinergyt2_init); -module_exit (cinergyt2_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 241c9ab54b1b..57bb470bd064 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -259,6 +259,14 @@ config DVB_USB_DW2102 Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers and the TeVii S650. +config DVB_USB_CINERGY_T2 + tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" + depends on DVB_USB + help + Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers + + Say Y if you own such a device and want to use it. + config DVB_USB_ANYSEE tristate "Anysee DVB-T/C USB2.0 support" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index ece8c9dfed18..3122b7cc2c23 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -73,6 +73,10 @@ obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o dvb-usb-af9015-objs = af9015.o obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o +dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o +obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o + + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c new file mode 100644 index 000000000000..25863033c480 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -0,0 +1,230 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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 "cinergyT2.h" + + +/* debug */ +int dvb_usb_cinergyt2_debug; +int disable_remote; + +module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " + "(or-able))."); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + + +/* We are missing a release hook with usb_device data */ +struct dvb_usb_device *cinergyt2_usb_device; + +static struct dvb_usb_device_properties cinergyt2_properties; + +static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) +{ + char buf[] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; + char result[64]; + return dvb_usb_generic_rw(adap->dev, buf, sizeof(buf), result, + sizeof(result), 0); +} + +static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) +{ + char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; + char state[3]; + return dvb_usb_generic_rw(d, buf, sizeof(buf), state, sizeof(state), 0); +} + +static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) +{ + char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; + char state[3]; + int ret; + + adap->fe = cinergyt2_fe_attach(adap->dev); + + ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, + sizeof(state), 0); + if (ret < 0) { + deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " + "state info\n"); + } + + /* Copy this pointer as we are gonna need it in the release phase */ + cinergyt2_usb_device = adap->dev; + + return 0; +} + +static struct dvb_usb_rc_key cinergyt2_rc_keys[] = { + { 0x04, 0x01, KEY_POWER }, + { 0x04, 0x02, KEY_1 }, + { 0x04, 0x03, KEY_2 }, + { 0x04, 0x04, KEY_3 }, + { 0x04, 0x05, KEY_4 }, + { 0x04, 0x06, KEY_5 }, + { 0x04, 0x07, KEY_6 }, + { 0x04, 0x08, KEY_7 }, + { 0x04, 0x09, KEY_8 }, + { 0x04, 0x0a, KEY_9 }, + { 0x04, 0x0c, KEY_0 }, + { 0x04, 0x0b, KEY_VIDEO }, + { 0x04, 0x0d, KEY_REFRESH }, + { 0x04, 0x0e, KEY_SELECT }, + { 0x04, 0x0f, KEY_EPG }, + { 0x04, 0x10, KEY_UP }, + { 0x04, 0x14, KEY_DOWN }, + { 0x04, 0x11, KEY_LEFT }, + { 0x04, 0x13, KEY_RIGHT }, + { 0x04, 0x12, KEY_OK }, + { 0x04, 0x15, KEY_TEXT }, + { 0x04, 0x16, KEY_INFO }, + { 0x04, 0x17, KEY_RED }, + { 0x04, 0x18, KEY_GREEN }, + { 0x04, 0x19, KEY_YELLOW }, + { 0x04, 0x1a, KEY_BLUE }, + { 0x04, 0x1c, KEY_VOLUMEUP }, + { 0x04, 0x1e, KEY_VOLUMEDOWN }, + { 0x04, 0x1d, KEY_MUTE }, + { 0x04, 0x1b, KEY_CHANNELUP }, + { 0x04, 0x1f, KEY_CHANNELDOWN }, + { 0x04, 0x40, KEY_PAUSE }, + { 0x04, 0x4c, KEY_PLAY }, + { 0x04, 0x58, KEY_RECORD }, + { 0x04, 0x54, KEY_PREVIOUS }, + { 0x04, 0x48, KEY_STOP }, + { 0x04, 0x5c, KEY_NEXT } +}; + +static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +{ + u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; + *state = REMOTE_NO_KEY_PRESSED; + + dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); + if (key[4] == 0xff) + return 0; + + /* hack to pass checksum on the custom field (is set to 0xeb) */ + key[2] = ~0x04; + dvb_usb_nec_rc_key_to_event(d, key, event, state); + if (key[0] != 0) + deb_info("key: %x %x %x %x %x\n", + key[0], key[1], key[2], key[3], key[4]); + + return 0; +} + +static int cinergyt2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf, &cinergyt2_properties, + THIS_MODULE, NULL, adapter_nr); +} + + +static struct usb_device_id cinergyt2_usb_table[] = { + { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); + +static struct dvb_usb_device_properties cinergyt2_properties = { + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cinergyt2_streaming_ctrl, + .frontend_attach = cinergyt2_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + } + }, + + .power_ctrl = cinergyt2_power_ctrl, + + .rc_interval = 50, + .rc_key_map = cinergyt2_rc_keys, + .rc_key_map_size = ARRAY_SIZE(cinergyt2_rc_keys), + .rc_query = cinergyt2_rc_query, + + .generic_bulk_ctrl_endpoint = 1, + + .num_device_descs = 1, + .devices = { + { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", + .cold_ids = {NULL}, + .warm_ids = { &cinergyt2_usb_table[0], NULL }, + }, + { NULL }, + } +}; + + +static struct usb_driver cinergyt2_driver = { + .name = "cinergyT2", + .probe = cinergyt2_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cinergyt2_usb_table +}; + +static int __init cinergyt2_usb_init(void) +{ + int err; + + err = usb_register(&cinergyt2_driver); + if (err) { + err("usb_register() failed! (err %i)\n", err); + return err; + } + return 0; +} + +static void __exit cinergyt2_usb_exit(void) +{ + usb_deregister(&cinergyt2_driver); +} + +module_init(cinergyt2_usb_init); +module_exit(cinergyt2_usb_exit); + +MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tomi Orava"); diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c new file mode 100644 index 000000000000..649f25cca49e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c @@ -0,0 +1,351 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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 "cinergyT2.h" + + +/** + * convert linux-dvb frontend parameter set into TPS. + * See ETSI ETS-300744, section 4.6.2, table 9 for details. + * + * This function is probably reusable and may better get placed in a support + * library. + * + * We replace errornous fields by default TPS fields (the ones with value 0). + */ + +static uint16_t compute_tps(struct dvb_frontend_parameters *p) +{ + struct dvb_ofdm_parameters *op = &p->u.ofdm; + uint16_t tps = 0; + + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 7) */; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 4) */; + } + + switch (op->constellation) { + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + case QPSK: + default: + /* tps |= (0 << 13) */; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + case TRANSMISSION_MODE_2K: + default: + /* tps |= (0 << 0) */; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + case GUARD_INTERVAL_1_32: + default: + /* tps |= (0 << 2) */; + } + + switch (op->hierarchy_information) { + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + case HIERARCHY_NONE: + default: + /* tps |= (0 << 10) */; + } + + return tps; +} + +struct cinergyt2_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; +}; + +static int cinergyt2_fe_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg result; + u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, + sizeof(result), 0); + if (ret < 0) + return ret; + + *status = 0; + + if (0xffff - le16_to_cpu(result.gain) > 30) + *status |= FE_HAS_SIGNAL; + if (result.lock_bits & (1 << 6)) + *status |= FE_HAS_LOCK; + if (result.lock_bits & (1 << 5)) + *status |= FE_HAS_SYNC; + if (result.lock_bits & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (result.lock_bits & (1 << 1)) + *status |= FE_HAS_VITERBI; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) + return ret; + + *ber = le32_to_cpu(status.viterbi_error_rate); + return 0; +} + +static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", + ret); + return ret; + } + *unc = le32_to_cpu(status.uncorrected_block_count); + return 0; +} + +static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_signal_strength() Failed!" + " (Error=%d)\n", ret); + return ret; + } + *strength = (0xffff - le16_to_cpu(status.gain)); + return 0; +} + +static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status, + sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); + return ret; + } + *snr = (status.snr << 8) | status.snr; + return 0; +} + +static int cinergyt2_fe_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int cinergyt2_fe_sleep(struct dvb_frontend *fe) +{ + deb_info("cinergyt2_fe_sleep() Called\n"); + return 0; +} + +static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_set_parameters_msg param; + char result[2]; + int err; + + param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; + param.tps = cpu_to_le16(compute_tps(fep)); + param.freq = cpu_to_le32(fep->frequency / 1000); + param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + + err = dvb_usb_generic_rw(state->d, + (char *)¶m, sizeof(param), + result, sizeof(result), 0); + if (err < 0) + err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); + + return (err < 0) ? err : 0; +} + +static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + return 0; +} + +static void cinergyt2_fe_release(struct dvb_frontend *fe) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + if (state != NULL) + kfree(state); +} + +static struct dvb_frontend_ops cinergyt2_fe_ops; + +struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) +{ + struct cinergyt2_fe_state *s = kzalloc(sizeof( + struct cinergyt2_fe_state), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->d = d; + memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + return &s->fe; +} + + +static struct dvb_frontend_ops cinergyt2_fe_ops = { + .info = { + .name = DRIVER_NAME, + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .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_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_RECOVER + | FE_CAN_MUTE_TS + }, + + .release = cinergyt2_fe_release, + + .init = cinergyt2_fe_init, + .sleep = cinergyt2_fe_sleep, + + .set_frontend = cinergyt2_fe_set_frontend, + .get_frontend = cinergyt2_fe_get_frontend, + .get_tune_settings = cinergyt2_fe_get_tune_settings, + + .read_status = cinergyt2_fe_read_status, + .read_ber = cinergyt2_fe_read_ber, + .read_signal_strength = cinergyt2_fe_read_signal_strength, + .read_snr = cinergyt2_fe_read_snr, + .read_ucblocks = cinergyt2_fe_read_unc_blocks, +}; diff --git a/drivers/media/dvb/dvb-usb/cinergyT2.h b/drivers/media/dvb/dvb-usb/cinergyT2.h new file mode 100644 index 000000000000..11d79eb384c8 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cinergyT2.h @@ -0,0 +1,95 @@ +/* + * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack and + * Holger Waechtler + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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 _DVB_USB_CINERGYT2_H_ +#define _DVB_USB_CINERGYT2_H_ + +#include + +#define DVB_USB_LOG_PREFIX "cinergyT2" +#include "dvb-usb.h" + +#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" + +extern int dvb_usb_cinergyt2_debug; + +#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug, 0x001, args) +#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x002, args) +#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug, 0x004, args) +#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug, 0x008, args) +#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug, 0x010, args) +#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug, 0x020, args) +#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug, 0x040, args) +#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug, 0x080, args) +#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug, 0x100, args) + + + +enum cinergyt2_ep1_cmd { + CINERGYT2_EP1_PID_TABLE_RESET = 0x01, + CINERGYT2_EP1_PID_SETUP = 0x02, + CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, + CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, + CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, + CINERGYT2_EP1_START_SCAN = 0x06, + CINERGYT2_EP1_CONTINUE_SCAN = 0x07, + CINERGYT2_EP1_GET_RC_EVENTS = 0x08, + CINERGYT2_EP1_SLEEP_MODE = 0x09, + CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A +}; + + +struct dvbt_get_status_msg { + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; + uint16_t gain; + uint8_t snr; + uint32_t viterbi_error_rate; + uint32_t rs_error_rate; + uint32_t uncorrected_block_count; + uint8_t lock_bits; + uint8_t prev_lock_bits; +} __attribute__((packed)); + + +struct dvbt_set_parameters_msg { + uint8_t cmd; + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; +} __attribute__((packed)); + + +extern struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d); + +#endif /* _DVB_USB_CINERGYT2_H_ */ + -- cgit v1.2.1 From 7f9876785276ac7f8606f8bf53a3dae4c10b8adb Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Fri, 19 Sep 2008 00:24:51 -0300 Subject: V4L/DVB (9108): cinergyT2: add remote key repeat feature Implement key repeat feature for the cinergyT2 remote controller. Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/cinergyT2-core.c | 52 ++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c index 25863033c480..3ac9f74e9fbf 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -40,6 +40,9 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +struct cinergyt2_state { + u8 rc_counter; +}; /* We are missing a release hook with usb_device data */ struct dvb_usb_device *cinergyt2_usb_device; @@ -122,22 +125,57 @@ static struct dvb_usb_rc_key cinergyt2_rc_keys[] = { { 0x04, 0x5c, KEY_NEXT } }; +/* Number of keypresses to ignore before detect repeating */ +#define RC_REPEAT_DELAY 3 + +static int repeatable_keys[] = { + KEY_UP, + KEY_DOWN, + KEY_LEFT, + KEY_RIGHT, + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, + KEY_CHANNELUP, + KEY_CHANNELDOWN +}; + static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { + struct cinergyt2_state *st = d->priv; u8 key[5] = {0, 0, 0, 0, 0}, cmd = CINERGYT2_EP1_GET_RC_EVENTS; + int i; + *state = REMOTE_NO_KEY_PRESSED; dvb_usb_generic_rw(d, &cmd, 1, key, sizeof(key), 0); - if (key[4] == 0xff) + if (key[4] == 0xff) { + /* key repeat */ + st->rc_counter++; + if (st->rc_counter > RC_REPEAT_DELAY) { + for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) { + if (d->last_event == repeatable_keys[i]) { + *state = REMOTE_KEY_REPEAT; + *event = d->last_event; + deb_rc("repeat key, event %x\n", + *event); + return 0; + } + } + deb_rc("repeated key (non repeatable)\n"); + } return 0; + } - /* hack to pass checksum on the custom field (is set to 0xeb) */ - key[2] = ~0x04; + /* hack to pass checksum on the custom field */ + key[2] = ~key[1]; dvb_usb_nec_rc_key_to_event(d, key, event, state); - if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n", - key[0], key[1], key[2], key[3], key[4]); + if (key[0] != 0) { + if (*event != d->last_event) + st->rc_counter = 0; + deb_rc("key: %x %x %x %x %x\n", + key[0], key[1], key[2], key[3], key[4]); + } return 0; } @@ -157,7 +195,7 @@ static struct usb_device_id cinergyt2_usb_table[] = { MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); static struct dvb_usb_device_properties cinergyt2_properties = { - + .size_of_priv = sizeof(struct cinergyt2_state), .num_adapters = 1, .adapter = { { -- cgit v1.2.1 From 79025a9ed9132880d5197611dec6d8533c121ac7 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 6 Oct 2008 12:07:48 -0300 Subject: V4L/DVB (9114): dib0700: fix bad assignment of dib0700_xc5000_tuner_callback after return call Put callback definition before function return and cleanup callback: Fix a bug where the xc5000 callback was being set *after* the return call (essentially resulting in dead code). Also cleanup the callback function to detect unknown commands. Signed-off-by: Devin Heitmueller Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 9891ca0924a3..0cfccc24b190 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1181,11 +1181,16 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component, { struct dvb_usb_adapter *adap = priv; - /* Reset the tuner */ - dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); - msleep(330); /* from Windows USB trace */ - dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); - msleep(330); /* from Windows USB trace */ + if (command == XC5000_TUNER_RESET) { + /* Reset the tuner */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0); + msleep(330); /* from Windows USB trace */ + dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1); + msleep(330); /* from Windows USB trace */ + } else { + err("xc5000: unknown tuner callback command: %d\n", command); + return -EINVAL; + } return 0; } @@ -1197,12 +1202,12 @@ static struct xc5000_config s5h1411_xc5000_tunerconfig = { static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) { + /* FIXME: generalize & move to common area */ + adap->fe->callback = dib0700_xc5000_tuner_callback; + return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, &s5h1411_xc5000_tunerconfig) == NULL ? -ENODEV : 0; - - /* FIXME: generalize & move to common area */ - adap->fe->callback = dib0700_xc5000_tuner_callback; } /* DVB-USB and USB stuff follows */ -- cgit v1.2.1 From e613f8fa5432d4cacaf81615f62b6d25d77947c5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 11 Aug 2008 10:36:43 -0300 Subject: V4L/DVB (9140): anysee: unlock I2C-mutex in error case - unlock I2C-mutex also in error case Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/anysee.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 2f408d2e1ef3..f511d105081f 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -178,14 +178,14 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, inc = 1; } if (ret) - return ret; + break; i += inc; } mutex_unlock(&d->i2c_mutex); - return i; + return ret ? ret : i; } static u32 anysee_i2c_func(struct i2c_adapter *adapter) -- cgit v1.2.1 From 0f77c3a4880f33127bc8d593e0e466f004a4adde Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 11 Aug 2008 10:54:16 -0300 Subject: V4L/DVB (9141): anysee: support for Anysee E30 Combo Plus - add module parameter for selecting DVB-T / DVB-C mode Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/anysee.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index f511d105081f..c786359fba03 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -41,6 +41,9 @@ static int dvb_usb_anysee_debug; module_param_named(debug, dvb_usb_anysee_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); +int dvb_usb_anysee_delsys; +module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644); +MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static struct mutex anysee_usb_mutex; @@ -272,9 +275,11 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) model demod hw firmware 1. E30 MT352 02 0.2.1 2. E30 ZL10353 02 0.2.1 - 3. E30 Plus ZL10353 06 0.1.0 - 4. E30C Plus TDA10023 0a 0.1.0 rev 0.2 - 4. E30C Plus TDA10023 0f 0.1.2 rev 0.4 + 3. E30 Combo ZL10353 0f 0.1.2 DVB-T/C combo + 4. E30 Plus ZL10353 06 0.1.0 + 5. E30C Plus TDA10023 0a 0.1.0 rev 0.2 + E30C Plus TDA10023 0f 0.1.2 rev 0.4 + E30 Combo TDA10023 0f 0.1.2 DVB-T/C combo */ /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */ @@ -293,6 +298,21 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) return 0; } + /* for E30 Combo Plus DVB-T demodulator */ + if (dvb_usb_anysee_delsys) { + ret = anysee_write_reg(adap->dev, 0xb0, 0x01); + if (ret) + return ret; + + /* Zarlink ZL10353 DVB-T demod */ + adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &adap->dev->i2c_adap); + if (adap->fe != NULL) { + state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A; + return 0; + } + } + /* connect demod on IO port D for TDA10023 & ZL10353 */ ret = anysee_write_reg(adap->dev, 0xb0, 0x25); if (ret) -- cgit v1.2.1 From 2dcd4e4766697f3d15284c48d2ef5192bf58131e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 22 Sep 2008 13:48:26 -0300 Subject: V4L/DVB (9143): af9015: fix wrong GPIO - fix wrong GPIO that causes 2nd FE not to work ater warmboot Thanks to Andrew Williams for reporting this. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 3f6217bd0638..87752ca9772a 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -54,7 +54,6 @@ static struct af9013_config af9015_af9013_config[] = { .output_mode = AF9013_OUTPUT_MODE_USB, .api_version = { 0, 1, 9, 0 }, .gpio[0] = AF9013_GPIO_HI, - .gpio[1] = AF9013_GPIO_LO, .gpio[3] = AF9013_GPIO_TUNER_ON, }, { -- cgit v1.2.1 From a131077d57d0c52d0d481cb7c588752d0a211aa5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 22 Sep 2008 13:59:25 -0300 Subject: V4L/DVB (9144): af9015: enable Maxlinear mxl5005s tuner RSSI - enable Maxlinear mxl5005s tuner RSSI Thaks to Jose Alberto for finding this setting. Thanks-to: Jose Alberto Reguero Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 87752ca9772a..1168e4b508db 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1088,7 +1088,7 @@ static struct mxl5005s_config af9015_mxl5003_config = { .xtal_freq = CRYSTAL_FREQ_16000000HZ, .agc_mode = MXL_SINGLE_AGC, .tracking_filter = MXL_TF_DEFAULT, - .rssi_enable = MXL_RSSI_DISABLE, + .rssi_enable = MXL_RSSI_ENABLE, .cap_select = MXL_CAP_SEL_ENABLE, .div_out = MXL_DIV_OUT_4, .clock_out = MXL_CLOCK_OUT_DISABLE, @@ -1105,7 +1105,7 @@ static struct mxl5005s_config af9015_mxl5005_config = { .xtal_freq = CRYSTAL_FREQ_16000000HZ, .agc_mode = MXL_SINGLE_AGC, .tracking_filter = MXL_TF_OFF, - .rssi_enable = MXL_RSSI_DISABLE, + .rssi_enable = MXL_RSSI_ENABLE, .cap_select = MXL_CAP_SEL_ENABLE, .div_out = MXL_DIV_OUT_4, .clock_out = MXL_CLOCK_OUT_DISABLE, -- cgit v1.2.1 From d4e80beae1eef31df5749516ecb36f0fb366daf1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 26 Sep 2008 11:40:53 -0300 Subject: V4L/DVB (9145): af901x: clean-up - remove unnecessary #undef's Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 2 -- drivers/media/dvb/frontends/af9013.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 1168e4b508db..8c183e55daa4 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -672,7 +672,6 @@ static int af9015_download_firmware(struct usb_device *udev, goto error; } } - #undef FW_PACKET_MAX_DATA /* firmware loaded, request boot */ req.cmd = BOOT; @@ -1377,7 +1376,6 @@ static struct dvb_usb_device_properties af9015_properties[] = { } } }; -#undef AF9015_DEFAULT_PROPERTIES static int af9015_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 50e1e3f300a0..0d2a0ad2bc4d 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -1500,8 +1500,6 @@ static int af9013_download_firmware(struct af9013_state *state) } } - #undef FW_PACKET_MAX_DATA - /* request boot firmware */ ret = af9013_write_reg(state, 0xe205, 1); if (ret) -- cgit v1.2.1 From 541dfa87f9285b2ff7e703a5eab81ad821de7f6e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 6 Oct 2008 13:57:45 -0300 Subject: V4L/DVB (9146): af901x: fix some compiler errors and warnings - cast firmware data to u8 - remove cpu_to_le16 from switch-case label Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 12 ++++++------ drivers/media/dvb/frontends/af9013.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 8c183e55daa4..67b13062a148 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -661,7 +661,7 @@ static int af9015_download_firmware(struct usb_device *udev, len = remainder; req.data_len = len; - req.data = (fw->data + i * FW_PACKET_MAX_DATA); + req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); req.addr = addr; addr += FW_PACKET_MAX_DATA; @@ -742,7 +742,7 @@ static int af9015_read_config(struct usb_device *udev) } } else { switch (udev->descriptor.idVendor) { - case cpu_to_le16(USB_VID_LEADTEK): + case USB_VID_LEADTEK: af9015_properties[i].rc_key_map = af9015_rc_keys_leadtek; af9015_properties[i].rc_key_map_size = @@ -752,9 +752,9 @@ static int af9015_read_config(struct usb_device *udev) af9015_config.ir_table_size = ARRAY_SIZE(af9015_ir_table_leadtek); break; - case cpu_to_le16(USB_VID_VISIONPLUS): + case USB_VID_VISIONPLUS: if (udev->descriptor.idProduct == - cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) { + USB_PID_AZUREWAVE_AD_TU700) { af9015_properties[i].rc_key_map = af9015_rc_keys_twinhan; af9015_properties[i].rc_key_map_size = @@ -765,7 +765,7 @@ static int af9015_read_config(struct usb_device *udev) ARRAY_SIZE(af9015_ir_table_twinhan); } break; - case cpu_to_le16(USB_VID_KWORLD_2): + case USB_VID_KWORLD_2: /* TODO: use correct rc keys */ af9015_properties[i].rc_key_map = af9015_rc_keys_twinhan; @@ -778,7 +778,7 @@ static int af9015_read_config(struct usb_device *udev) /* Check USB manufacturer and product strings and try to determine correct remote in case of chip vendor reference IDs are used. */ - case cpu_to_le16(USB_VID_AFATECH): + case USB_VID_AFATECH: memset(manufacturer, 0, sizeof(manufacturer)); usb_string(udev, udev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer)); diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 0d2a0ad2bc4d..21c1060cf10e 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -1490,7 +1490,7 @@ static int af9013_download_firmware(struct af9013_state *state) if (i == packets) /* set size of the last packet */ len = remainder; - data = (fw->data + i * FW_PACKET_MAX_DATA); + data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); ret = af9013_write_ofsm_regs(state, addr, data, len); addr += FW_PACKET_MAX_DATA; -- cgit v1.2.1 From 641015ab2c452e8e554625e2a8e95218182acb4b Mon Sep 17 00:00:00 2001 From: Herbert Graeber Date: Tue, 7 Oct 2008 10:06:36 -0300 Subject: V4L/DVB (9147): af9015: Add USB ID for MSI DIGIVOX mini III - Add USB ID for MSI DIGIVOX mini III (1462:8807) Signed-off-by: Herbert Graeber Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 8 +++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 67b13062a148..cb0829c038ce 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1196,6 +1196,7 @@ static struct usb_device_id af9015_usb_table[] = { {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, +/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1346,7 +1347,7 @@ static struct dvb_usb_device_properties af9015_properties[] = { .i2c_algo = &af9015_i2c_algo, - .num_device_descs = 5, + .num_device_descs = 6, .devices = { { .name = "Xtensions XD-380", @@ -1373,6 +1374,11 @@ static struct dvb_usb_device_properties af9015_properties[] = { .cold_ids = {&af9015_usb_table[14], NULL}, .warm_ids = {NULL}, }, + { + .name = "MSI Digi VOX mini III", + .cold_ids = {&af9015_usb_table[15], NULL}, + .warm_ids = {NULL}, + }, } } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index dfaf1d2574db..7380b94b3b36 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -232,5 +232,6 @@ #define USB_PID_DW2102 0x2102 #define USB_PID_XTENSIONS_XD_380 0x0381 #define USB_PID_TELESTAR_STARSTICK_2 0x8000 +#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807 #endif -- cgit v1.2.1 From adeeac3b7989ad9f03651e9224c9c63e221d4310 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 5 Apr 2008 20:55:14 -0300 Subject: V4L/DVB (9149): hvr950q: led feedback based on snr Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/au8522.c | 133 +++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/au8522.h | 17 +++++ 2 files changed, 150 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c index 0b82cc2a1e16..eabf9a68e7ec 100644 --- a/drivers/media/dvb/frontends/au8522.c +++ b/drivers/media/dvb/frontends/au8522.c @@ -40,6 +40,8 @@ struct au8522_state { u32 current_frequency; fe_modulation_t current_modulation; + u32 fe_status; + unsigned int led_state; }; static int debug; @@ -538,11 +540,98 @@ static int au8522_init(struct dvb_frontend *fe) return 0; } +static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + u8 val; + + /* bail out if we cant control an LED */ + if (!led_config || !led_config->gpio_output || + !led_config->gpio_output_enable || !led_config->gpio_output_disable) + return 0; + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_output & ~0xc000)); + if (onoff) { + /* enable GPIO output */ + val &= ~((led_config->gpio_output_enable >> 8) & 0xff); + val |= (led_config->gpio_output_enable & 0xff); + } else { + /* disable GPIO output */ + val &= ~((led_config->gpio_output_disable >> 8) & 0xff); + val |= (led_config->gpio_output_disable & 0xff); + } + return au8522_writereg(state, 0x8000 | + (led_config->gpio_output & ~0xc000), val); +} + +/* led = 0 | off + * led = 1 | signal ok + * led = 2 | signal strong + * led < 0 | only light led if leds are currently off + */ +static int au8522_led_ctrl(struct au8522_state *state, int led) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + int i, ret = 0; + + /* bail out if we cant control an LED */ + if (!led_config || !led_config->gpio_leds || + !led_config->num_led_states || !led_config->led_states) + return 0; + + if (led < 0) { + /* if LED is already lit, then leave it as-is */ + if (state->led_state) + return 0; + else + led *= -1; + } + + /* toggle LED if changing state */ + if (state->led_state != led) { + u8 val; + + dprintk("%s: %d\n", __func__, led); + + au8522_led_gpio_enable(state, 1); + + val = au8522_readreg(state, 0x4000 | + (led_config->gpio_leds & ~0xc000)); + + /* start with all leds off */ + for (i = 0; i < led_config->num_led_states; i++) + val &= ~led_config->led_states[i]; + + /* set selected LED state */ + if (led < led_config->num_led_states) + val |= led_config->led_states[led]; + else if (led_config->num_led_states) + val |= + led_config->led_states[led_config->num_led_states - 1]; + + ret = au8522_writereg(state, 0x8000 | + (led_config->gpio_leds & ~0xc000), val); + if (ret < 0) + return ret; + + state->led_state = led; + + if (led == 0) + au8522_led_gpio_enable(state, 0); + } + + return 0; +} + static int au8522_sleep(struct dvb_frontend *fe) { struct au8522_state *state = fe->demodulator_priv; dprintk("%s()\n", __func__); + /* turn off led */ + au8522_led_ctrl(state, 0); + state->current_frequency = 0; return 0; @@ -592,12 +681,53 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; break; } + state->fe_status = *status; + + if (*status & FE_HAS_LOCK) + /* turn on LED, if it isn't on already */ + au8522_led_ctrl(state, -1); + else + /* turn off LED */ + au8522_led_ctrl(state, 0); dprintk("%s() status 0x%08x\n", __func__, *status); return 0; } +static int au8522_led_status(struct au8522_state *state, const u16 *snr) +{ + struct au8522_led_config *led_config = state->config->led_cfg; + int led; + u16 strong; + + /* bail out if we cant control an LED */ + if (!led_config) + return 0; + + if (0 == (state->fe_status & FE_HAS_LOCK)) + return au8522_led_ctrl(state, 0); + else if (state->current_modulation == QAM_256) + strong = led_config->qam256_strong; + else if (state->current_modulation == QAM_64) + strong = led_config->qam64_strong; + else /* (state->current_modulation == VSB_8) */ + strong = led_config->vsb8_strong; + + if (*snr >= strong) + led = 2; + else + led = 1; + + if ((state->led_state) && + (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10)) + /* snr didn't change enough to bother + * changing the color of the led */ + return 0; + + return au8522_led_ctrl(state, led); +} + static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) { struct au8522_state *state = fe->demodulator_priv; @@ -621,6 +751,9 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) au8522_readreg(state, 0x4311), snr); + if (state->config->led_cfg) + au8522_led_status(state, snr); + return ret; } diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h index 595915ade8c3..7b94f554a093 100644 --- a/drivers/media/dvb/frontends/au8522.h +++ b/drivers/media/dvb/frontends/au8522.h @@ -30,6 +30,21 @@ enum au8522_if_freq { AU8522_IF_3_25MHZ, }; +struct au8522_led_config { + u16 vsb8_strong; + u16 qam64_strong; + u16 qam256_strong; + + u16 gpio_output; + /* unset hi bits, set low bits */ + u16 gpio_output_enable; + u16 gpio_output_disable; + + u16 gpio_leds; + u8 *led_states; + unsigned int num_led_states; +}; + struct au8522_config { /* the demodulator's i2c address */ u8 demod_address; @@ -39,6 +54,8 @@ struct au8522_config { #define AU8522_DEMODLOCKING 1 u8 status_mode; + struct au8522_led_config *led_cfg; + enum au8522_if_freq vsb_if; enum au8522_if_freq qam_if; }; -- cgit v1.2.1 From 01a8f038c07c4119029c63f1ed1c6ac986665d48 Mon Sep 17 00:00:00 2001 From: Darron Broad Date: Fri, 3 Oct 2008 11:47:46 -0300 Subject: V4L/DVB (9170): cx24116: Sanity checking to data input via S2API to the cx24116 demod. Add some sanity checking to data input via S2API to the cx24116 demod. This patch is valid for both s2-mfe and s2. It was found when testing KAFFEINE with S2API support that invalid modulation modes amongst other parameters were being delivered to the demod. In order to debug this sanity checking has been added. An example session would involve kaffeine setting QAM_AUTO when querying DVB-T, then later when trying to tune to DVB-S this cached value would be presented in error. Signed-off-by: Darron Broad Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 89 ++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 21 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 02ed4ef79c67..808ef2995d80 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -84,7 +84,8 @@ static int debug = 0; #define CX24116_ROLLOFF_035 (0x02) /* pilot bit */ -#define CX24116_PILOT (0x40) +#define CX24116_PILOT_OFF (0x00) +#define CX24116_PILOT_ON (0x40) /* signal status */ #define CX24116_HAS_SIGNAL (0x01) @@ -148,6 +149,7 @@ struct cx24116_tuning u8 fec_val; u8 fec_mask; u8 inversion_val; + u8 pilot_val; u8 rolloff_val; }; @@ -1121,25 +1123,62 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24116_cmd cmd; fe_status_t tunerstat; - int i, status, ret, retune = 1; + int i, status, ret, retune; dprintk("%s()\n",__func__); - state->dnxt.modulation = c->modulation; - state->dnxt.frequency = c->frequency; - switch(c->delivery_system) { case SYS_DVBS: dprintk("%s: DVB-S delivery system selected\n",__func__); - state->dnxt.pilot = PILOT_OFF; + + /* Only QPSK is supported for DVB-S */ + if(c->modulation != QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + /* Pilot doesn't exist in DVB-S, turn bit off */ + state->dnxt.pilot_val = CX24116_PILOT_OFF; + retune = 1; + + /* DVB-S only supports 0.35 */ + if(c->rolloff != ROLLOFF_35) { + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); + return -EOPNOTSUPP; + } state->dnxt.rolloff_val = CX24116_ROLLOFF_035; - state->dnxt.rolloff = c->rolloff; break; + case SYS_DVBS2: dprintk("%s: DVB-S2 delivery system selected\n",__func__); - if(c->pilot == PILOT_AUTO) - retune++; - state->dnxt.pilot = c->pilot; + + /* + * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, + * but not hardware auto detection + */ + if(c->modulation != _8PSK && c->modulation != NBC_QPSK) { + dprintk("%s: unsupported modulation selected (%d)\n", + __func__, c->modulation); + return -EOPNOTSUPP; + } + + switch(c->pilot) { + case PILOT_AUTO: /* Not supported but emulated */ + retune = 2; /* Fall-through */ + case PILOT_OFF: + state->dnxt.pilot_val = CX24116_PILOT_OFF; + break; + case PILOT_ON: + state->dnxt.pilot_val = CX24116_PILOT_ON; + break; + default: + dprintk("%s: unsupported pilot mode selected (%d)\n", + __func__, c->pilot); + return -EOPNOTSUPP; + } + switch(c->rolloff) { case ROLLOFF_20: state->dnxt.rolloff_val= CX24116_ROLLOFF_020; @@ -1150,20 +1189,28 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par case ROLLOFF_35: state->dnxt.rolloff_val= CX24116_ROLLOFF_035; break; - case ROLLOFF_AUTO: + case ROLLOFF_AUTO: /* Rolloff must be explicit */ + default: + dprintk("%s: unsupported rolloff selected (%d)\n", + __func__, c->rolloff); return -EOPNOTSUPP; } - state->dnxt.rolloff = c->rolloff; break; + default: dprintk("%s: unsupported delivery system selected (%d)\n", __func__, c->delivery_system); return -EOPNOTSUPP; } + state->dnxt.modulation = c->modulation; + state->dnxt.frequency = c->frequency; + state->dnxt.pilot = c->pilot; + state->dnxt.rolloff = c->rolloff; if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) return ret; + /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0) return ret; @@ -1173,10 +1220,13 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* discard the 'current' tuning parameters and prepare to tune */ cx24116_clone_params(fe); - dprintk("%s: retune = %d\n", __func__, retune); - dprintk("%s: rolloff = %d\n", __func__, state->dcur.rolloff); - dprintk("%s: pilot = %d\n", __func__, state->dcur.pilot); + dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); + dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, + state->dcur.pilot, state->dcur.pilot_val); + dprintk("%s: retune = %d\n", __func__, retune); + dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, + state->dcur.rolloff, state->dcur.rolloff_val); dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); @@ -1210,11 +1260,8 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* Automatic Inversion */ cmd.args[0x06] = state->dcur.inversion_val; - /* Modulation / FEC & Pilot Off */ - cmd.args[0x07] = state->dcur.fec_val; - - if (state->dcur.pilot == PILOT_ON) - cmd.args[0x07] |= CX24116_PILOT; + /* Modulation / FEC / Pilot */ + cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; @@ -1277,7 +1324,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par /* Toggle pilot bit when in auto-pilot */ if(state->dcur.pilot == PILOT_AUTO) - cmd.args[0x07] ^= CX24116_PILOT; + cmd.args[0x07] ^= CX24116_PILOT_ON; } while(--retune); -- cgit v1.2.1 From 4aae8efb4908fa3f80dc1177d093443bc09adf5f Mon Sep 17 00:00:00 2001 From: Darron Broad Date: Fri, 3 Oct 2008 11:50:00 -0300 Subject: V4L/DVB (9171): S2API: Stop an OOPS if illegal commands are dumped in S2API. Quick fix to stop an OOPS if illegal commands are dumped in S2API. Signed-off-by: Darron Broad Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 4c3f0d7e355c..f44b64b8e614 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -848,6 +848,13 @@ void dtv_property_dump(struct dtv_property *tvp) { int i; + if( (tvp->cmd <= 0 || tvp->cmd > DTV_DELIVERY_SYSTEM) && + tvp->cmd != DTV_API_VERSION) { + printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n", + __func__, tvp->cmd); + return; + } + printk("%s() tvp.cmd = 0x%08x (%s)\n" ,__FUNCTION__ ,tvp->cmd -- cgit v1.2.1 From e5cefa82ce31b14574947e570d638a6d58225338 Mon Sep 17 00:00:00 2001 From: Darron Broad Date: Fri, 3 Oct 2008 11:53:18 -0300 Subject: V4L/DVB (9172): S2API: Bugfix related to DVB-S / DVB-S2 tuning for the legacy API. Fixes switching from S2API to legacy where legacy params given to S2API aware demods are cached ones and not those implied in the legacy API. It was found (on an S2API aware demod at least) that after using an S2API aware application and then switching to a legacy application that prior S2API params were in effect were legacy has only implied values. This fixes this. Signed-off-by: Darron Broad Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index f44b64b8e614..ff8cda0ac333 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -900,6 +900,8 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame switch (fe->ops.info.type) { case FE_QPSK: + c->modulation = QPSK; /* implied for DVB-S in legacy API */ + c->rolloff = ROLLOFF_35;/* implied for DVB-S */ c->symbol_rate = p->u.qpsk.symbol_rate; c->fec_inner = p->u.qpsk.fec_inner; c->delivery_system = SYS_DVBS; -- cgit v1.2.1 From 82d7669dc3c0e795c24111fed88e9d5d70f209e0 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 6 Oct 2008 20:44:04 -0300 Subject: V4L/DVB (9173): S2API: Remove the hardcoded command limit during validation This means that when developers add new commands then they'll be see the DTV_MAX_COMMAND define and will be more likely to modify it, without having to modify the command validation code. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index ff8cda0ac333..7fe9b3fb1e34 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -848,8 +848,7 @@ void dtv_property_dump(struct dtv_property *tvp) { int i; - if( (tvp->cmd <= 0 || tvp->cmd > DTV_DELIVERY_SYSTEM) && - tvp->cmd != DTV_API_VERSION) { + if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { printk("%s: tvp.cmd = 0x%08x (undefined/unknown/invalid)\n", __func__, tvp->cmd); return; -- cgit v1.2.1 From de9be0eaae2a23b1782ae0d271961b83abc6e200 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 5 Oct 2008 08:52:18 -0300 Subject: V4L/DVB (9174): Allow custom inittab for ST STV0288 demodulator. Allow custom inittab for ST STV0288 demodulator, as it is needed for DvbWorld USB card. Signed-off-by: Igor M. Liplianin Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0288.c | 20 ++++++++++++++++---- drivers/media/dvb/frontends/stv0288.h | 2 ++ 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c index 90e72e771a04..ff1194de34c0 100644 --- a/drivers/media/dvb/frontends/stv0288.c +++ b/drivers/media/dvb/frontends/stv0288.c @@ -328,16 +328,28 @@ static int stv0288_init(struct dvb_frontend *fe) { struct stv0288_state *state = fe->demodulator_priv; int i; + u8 reg; + u8 val; dprintk("stv0288: init chip\n"); stv0288_writeregI(state, 0x41, 0x04); msleep(50); - for (i = 0; !(stv0288_inittab[i] == 0xff && + /* we have default inittab */ + if (state->config->inittab == NULL) { + for (i = 0; !(stv0288_inittab[i] == 0xff && stv0288_inittab[i + 1] == 0xff); i += 2) - stv0288_writeregI(state, stv0288_inittab[i], - stv0288_inittab[i + 1]); - + stv0288_writeregI(state, stv0288_inittab[i], + stv0288_inittab[i + 1]); + } else { + for (i = 0; ; i += 2) { + reg = state->config->inittab[i]; + val = state->config->inittab[i+1]; + if (reg == 0xff && val == 0xff) + break; + stv0288_writeregI(state, reg, val); + } + } return 0; } diff --git a/drivers/media/dvb/frontends/stv0288.h b/drivers/media/dvb/frontends/stv0288.h index aa0cdd273040..f2b53db0606d 100644 --- a/drivers/media/dvb/frontends/stv0288.h +++ b/drivers/media/dvb/frontends/stv0288.h @@ -34,6 +34,8 @@ struct stv0288_config { /* the demodulator's i2c address */ u8 demod_address; + u8* inittab; + /* minimum delay before retuning */ int min_delay_ms; -- cgit v1.2.1 From ceab2fe84987a9b2dbe6107f83ac99c98040abcc Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 5 Oct 2008 08:57:11 -0300 Subject: V4L/DVB (9175): Remove NULL pointer in stb6000 driver. Remove NULL pointer in stb6000 driver, as it raises error for DvbWorld USB card. Signed-off-by: Igor M. Liplianin Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stb6000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c index 7d65123b4ec9..0e2cb0df1441 100644 --- a/drivers/media/dvb/frontends/stb6000.c +++ b/drivers/media/dvb/frontends/stb6000.c @@ -201,12 +201,13 @@ struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) { struct stb6000_priv *priv = NULL; + u8 b0[] = { 0 }; u8 b1[] = { 0, 0 }; struct i2c_msg msg[2] = { { .addr = addr, .flags = 0, - .buf = NULL, + .buf = b0, .len = 0 }, { .addr = addr, -- cgit v1.2.1 From 8a4949b7e98cbb9e304416ecf6da978e1fb1fb9e Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 5 Oct 2008 09:11:21 -0300 Subject: V4L/DVB (9176): Add support for DvbWorld USB cards with STV0288 demodulator. Add support for DvbWorld USB cards with STV0288 demodulator. Those cards use Earda EDS-1547 tuner. Signed-off-by: Igor M. Liplianin Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 + drivers/media/dvb/dvb-usb/dw2102.c | 123 ++++++++++++++++++++++++++++++- drivers/media/dvb/frontends/eds1547.h | 133 ++++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+), 4 deletions(-) create mode 100644 drivers/media/dvb/frontends/eds1547.h (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 57bb470bd064..3c13bcfa6385 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -253,6 +253,8 @@ config DVB_USB_DW2102 depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_SI21XX if !DVB_FE_CUSTOMISE help diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 20ba3f129001..ca53df61caa8 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -14,6 +14,9 @@ #include "si21xx.h" #include "stv0299.h" #include "z0194a.h" +#include "stv0288.h" +#include "stb6000.h" +#include "eds1547.h" #include "cx24116.h" #ifndef USB_PID_DW2102 @@ -199,6 +202,78 @@ 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); + int ret = 0; + + 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] = 0xd0; + 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, 0xd1 , 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 0x68: { + /* write to register */ + u8 obuf[msg[0].len + 2]; + obuf[0] = 0xd0; + 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 0x61: { + /* write to tuner */ + u8 obuf[msg[0].len + 2]; + obuf[0] = 0xc2; + 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; + } + case(DW2102_VOLTAGE_CTRL): { + u8 obuf[2]; + obuf[0] = 0x30; + obuf[1] = msg[0].buf[0]; + ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } + } + + break; + } + + mutex_unlock(&d->i2c_mutex); + return num; +} static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -297,6 +372,11 @@ static struct i2c_algorithm dw2102_serit_i2c_algo = { .functionality = dw210x_i2c_func, }; +static struct i2c_algorithm dw2102_earda_i2c_algo = { + .master_xfer = dw2102_earda_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + static struct i2c_algorithm dw2104_i2c_algo = { .master_xfer = dw2104_i2c_transfer, .functionality = dw210x_i2c_func, @@ -378,6 +458,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) return 0; } } + if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { + /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ + d->fe = dvb_attach(stv0288_attach, &earda_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0288!\n"); + return 0; + } + } + if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, @@ -398,6 +489,14 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) +{ + dvb_attach(stb6000_attach, adap->fe, 0x61, + &adap->dev->i2c_adap); + + return 0; +} + static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf8, 0x0a, KEY_Q }, /*power*/ { 0xf8, 0x0c, KEY_M }, /*mute*/ @@ -478,7 +577,7 @@ static int dw2102_load_firmware(struct usb_device *dev, u8 *b, *p; int ret = 0, i; u8 reset; - u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0}; + u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; const struct firmware *fw; const char *filename = "dvb-usb-dw2101.fw"; switch (dev->descriptor.idProduct) { @@ -544,9 +643,25 @@ static int dw2102_load_firmware(struct usb_device *dev, /* check STV0299 frontend */ dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2, DW210X_READ_MSG); - if (reset16[0] == 0xa1) + if (reset16[0] == 0xa1) { dw2102_properties.i2c_algo = &dw2102_i2c_algo; - break; + dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach; + break; + } else { + /* check STV0288 frontend */ + reset16[0] = 0xd0; + reset16[1] = 1; + reset16[2] = 0; + dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3, + DW210X_WRITE_MSG); + dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3, + DW210X_READ_MSG); + if (reset16[2] == 0x11) { + dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; + dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach; + break; + } + } case 0x2101: dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2, DW210X_READ_MSG); @@ -586,7 +701,7 @@ static struct dvb_usb_device_properties dw2102_properties = { { .frontend_attach = dw2102_frontend_attach, .streaming_ctrl = NULL, - .tuner_attach = dw2102_tuner_attach, + .tuner_attach = NULL, .stream = { .type = USB_BULK, .count = 8, diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb/frontends/eds1547.h new file mode 100644 index 000000000000..fa79b7c83dd2 --- /dev/null +++ b/drivers/media/dvb/frontends/eds1547.h @@ -0,0 +1,133 @@ +/* eds1547.h Earda EDS-1547 tuner support +* +* Copyright (C) 2008 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 +* Free Software Foundation, version 2. +* +* see Documentation/dvb/README.dvb-usb for more information +*/ + +#ifndef EDS1547 +#define EDS1547 + +static u8 stv0288_earda_inittab[] = { + 0x01, 0x57, + 0x02, 0x20, + 0x03, 0x8e, + 0x04, 0x8e, + 0x05, 0x12, + 0x06, 0x00, + 0x07, 0x00, + 0x09, 0x00, + 0x0a, 0x04, + 0x0b, 0x00, + 0x0c, 0x00, + 0x0d, 0x00, + 0x0e, 0xd4, + 0x0f, 0x30, + 0x11, 0x44, + 0x12, 0x03, + 0x13, 0x48, + 0x14, 0x84, + 0x15, 0x45, + 0x16, 0xb7, + 0x17, 0x9c, + 0x18, 0x00, + 0x19, 0xa6, + 0x1a, 0x88, + 0x1b, 0x8f, + 0x1c, 0xf0, + 0x20, 0x0b, + 0x21, 0x54, + 0x22, 0x00, + 0x23, 0x00, + 0x2b, 0xff, + 0x2c, 0xf7, + 0x30, 0x00, + 0x31, 0x1e, + 0x32, 0x14, + 0x33, 0x0f, + 0x34, 0x09, + 0x35, 0x0c, + 0x36, 0x05, + 0x37, 0x2f, + 0x38, 0x16, + 0x39, 0xbd, + 0x3a, 0x00, + 0x3b, 0x13, + 0x3c, 0x11, + 0x3d, 0x30, + 0x40, 0x63, + 0x41, 0x04, + 0x42, 0x60, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x4a, 0x00, + 0x50, 0x10, + 0x51, 0x36, + 0x52, 0x09, + 0x53, 0x94, + 0x54, 0x62, + 0x55, 0x29, + 0x56, 0x64, + 0x57, 0x2b, + 0x58, 0x54, + 0x59, 0x86, + 0x5a, 0x00, + 0x5b, 0x9b, + 0x5c, 0x08, + 0x5d, 0x7f, + 0x5e, 0x00, + 0x5f, 0xff, + 0x70, 0x00, + 0x71, 0x00, + 0x72, 0x00, + 0x74, 0x00, + 0x75, 0x00, + 0x76, 0x00, + 0x81, 0x00, + 0x82, 0x3f, + 0x83, 0x3f, + 0x84, 0x00, + 0x85, 0x00, + 0x88, 0x00, + 0x89, 0x00, + 0x8a, 0x00, + 0x8b, 0x00, + 0x8c, 0x00, + 0x90, 0x00, + 0x91, 0x00, + 0x92, 0x00, + 0x93, 0x00, + 0x94, 0x1c, + 0x97, 0x00, + 0xa0, 0x48, + 0xa1, 0x00, + 0xb0, 0xb8, + 0xb1, 0x3a, + 0xb2, 0x10, + 0xb3, 0x82, + 0xb4, 0x80, + 0xb5, 0x82, + 0xb6, 0x82, + 0xb7, 0x82, + 0xb8, 0x20, + 0xb9, 0x00, + 0xf0, 0x00, + 0xf1, 0x00, + 0xf2, 0xc0, + 0xff,0xff, +}; + +static struct stv0288_config earda_config = { + .demod_address = 0x68, + .min_delay_ms = 100, + .inittab = stv0288_earda_inittab, +}; + +#endif -- cgit v1.2.1 From 0a6393ae21d58e85882185ce1e6b0fe28ff2dfa6 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 6 Oct 2008 21:06:48 -0300 Subject: V4L/DVB (9177): S2API: Change _8PSK / _16APSK to PSK_8 and APSK_16 ... and cleanup any drivers using them. I've also removed NBC_QPSK and modified the cx24116 driver to check the delivery_type also, removing some excess namespace baggage. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 6 ++-- drivers/media/dvb/frontends/cx24116.c | 51 ++++++++++++++++--------------- 2 files changed, 29 insertions(+), 28 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 7fe9b3fb1e34..7b4b1a5ac427 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1011,9 +1011,9 @@ void dtv_property_adv_params_sync(struct dvb_frontend *fe) p->inversion = c->inversion; switch(c->modulation) { - case _8PSK: - case _16APSK: - case NBC_QPSK: + case PSK_8: + case APSK_16: + case QPSK: p->u.qpsk.symbol_rate = c->symbol_rate; p->u.qpsk.fec_inner = c->fec_inner; break; diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 808ef2995d80..30f82cb0928b 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -344,6 +344,7 @@ static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_invers * a scheme are support. Especially, no auto detect when in S2 mode. */ struct cx24116_modfec { + fe_delivery_system_t delivery_system; fe_modulation_t modulation; fe_code_rate_t fec; u8 mask; /* In DVBS mode this is used to autodetect */ @@ -352,32 +353,32 @@ struct cx24116_modfec { /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ /*mod fec mask val */ - { QPSK, FEC_NONE, 0xfe, 0x30 }, - { QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ - { QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ - { QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ - { QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ - { QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ - { QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ - { QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ - { QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ - { QPSK, FEC_AUTO, 0xfe, 0x30 }, + { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, + { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ + { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ + { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ + { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ + { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ + { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ + { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ + { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ + { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, /* NBC-QPSK */ - { NBC_QPSK, FEC_1_2, 0x00, 0x04 }, - { NBC_QPSK, FEC_3_5, 0x00, 0x05 }, - { NBC_QPSK, FEC_2_3, 0x00, 0x06 }, - { NBC_QPSK, FEC_3_4, 0x00, 0x07 }, - { NBC_QPSK, FEC_4_5, 0x00, 0x08 }, - { NBC_QPSK, FEC_5_6, 0x00, 0x09 }, - { NBC_QPSK, FEC_8_9, 0x00, 0x0a }, - { NBC_QPSK, FEC_9_10, 0x00, 0x0b }, + { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, + { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, + { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, + { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, + { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, + { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, + { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, + { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, /* 8PSK */ - { _8PSK, FEC_3_5, 0x00, 0x0c }, - { _8PSK, FEC_2_3, 0x00, 0x0d }, - { _8PSK, FEC_3_4, 0x00, 0x0e }, - { _8PSK, FEC_5_6, 0x00, 0x0f }, - { _8PSK, FEC_8_9, 0x00, 0x10 }, - { _8PSK, FEC_9_10, 0x00, 0x11 }, + { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, + { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, + { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, + { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, + { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, + { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, /* * `val' can be found in the FECSTATUS register when tuning. * FECSTATUS will give the actual FEC in use if tuning was successful. @@ -1158,7 +1159,7 @@ static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, * but not hardware auto detection */ - if(c->modulation != _8PSK && c->modulation != NBC_QPSK) { + if(c->modulation != PSK_8 && c->modulation != QPSK) { dprintk("%s: unsupported modulation selected (%d)\n", __func__, c->modulation); return -EOPNOTSUPP; -- cgit v1.2.1 From 8953db793d5bdeea5ac92c9e97f57d3ff8a7dccf Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 6 Oct 2008 21:20:21 -0300 Subject: V4L/DVB (9178): cx24116: Add module parameter to return SNR as ESNO. I've retained the older percentage code after discussing this with Darron Broad, but made the ESNO option default. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 39 ++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index 30f82cb0928b..b8acc7b74c33 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -57,8 +57,9 @@ static int debug = 0; #define CX24116_REG_RESET (0x20) /* reset status > 0 */ #define CX24116_REG_SIGNAL (0x9e) /* signal low */ #define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ +#define CX24116_REG_QUALITY8 (0xa3) #define CX24116_REG_QSTATUS (0xbc) -#define CX24116_REG_QUALITY (0xd5) +#define CX24116_REG_QUALITY0 (0xd5) #define CX24116_REG_BER0 (0xc9) #define CX24116_REG_BER8 (0xc8) #define CX24116_REG_BER16 (0xc7) @@ -116,6 +117,9 @@ static int debug = 0; /* DiSEqC tone burst */ static int toneburst = 1; +/* SNR measurements */ +static int esno_snr = 1; + enum cmds { CMD_SET_VCO = 0x10, @@ -703,7 +707,7 @@ static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_str } /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ -static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) +static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr) { struct cx24116_state *state = fe->demodulator_priv; u8 snr_reading; @@ -714,7 +718,7 @@ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) dprintk("%s()\n", __func__); - snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY); + snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); if(snr_reading >= 0xa0 /* 100% */) *snr = 0xffff; @@ -728,6 +732,32 @@ static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) return 0; } +/* The reelbox patches show the value in the registers represents + * ESNO, from 0->30db (values 0->300). We provide this value by + * default. + */ +static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr) +{ + struct cx24116_state *state = fe->demodulator_priv; + + dprintk("%s()\n", __func__); + + *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | + cx24116_readreg(state, CX24116_REG_QUALITY0); + + dprintk("%s: raw 0x%04x\n", __func__, *snr); + + return 0; +} + +static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) +{ + if (esno_snr == 1) + return cx24116_read_snr_esno(fe, snr); + else + return cx24116_read_snr_pct(fe, snr); +} + static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct cx24116_state *state = fe->demodulator_priv; @@ -1383,6 +1413,9 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); module_param(toneburst, int, 0644); MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); +module_param(esno_snr, int, 0644); +MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:1)"); + MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); -- cgit v1.2.1 From a4de91be46b73ec6743b9d76155550e49507723c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 6 Oct 2008 21:55:46 -0300 Subject: V4L/DVB (9180): S2API: Added support for DTV_CODE_RATE_HP/LP Reports from users that using the new API for tuning DTV was failing, and the cache was missing some essential items. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 7b4b1a5ac427..104f40b7171d 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -830,6 +830,16 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_DELIVERY_SYSTEM, .set = 1, }, + [DTV_CODE_RATE_HP] = { + .name = "DTV_CODE_RATE_HP", + .cmd = DTV_CODE_RATE_HP, + .set = 1, + }, + [DTV_CODE_RATE_LP] = { + .name = "DTV_CODE_RATE_LP", + .cmd = DTV_CODE_RATE_LP, + .set = 1, + }, /* Get */ [DTV_DISEQC_SLAVE_REPLY] = { .name = "DTV_DISEQC_SLAVE_REPLY", @@ -842,6 +852,16 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_API_VERSION, .set = 0, }, + [DTV_CODE_RATE_HP] = { + .name = "DTV_CODE_RATE_HP", + .cmd = DTV_CODE_RATE_HP, + .set = 0, + }, + [DTV_CODE_RATE_LP] = { + .name = "DTV_CODE_RATE_LP", + .cmd = DTV_CODE_RATE_LP, + .set = 0, + }, }; void dtv_property_dump(struct dtv_property *tvp) @@ -1121,6 +1141,12 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_API_VERSION: tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR; break; + case DTV_CODE_RATE_HP: + tvp->u.data = fe->dtv_property_cache.code_rate_HP; + break; + case DTV_CODE_RATE_LP: + tvp->u.data = fe->dtv_property_cache.code_rate_LP; + break; default: r = -1; } @@ -1202,6 +1228,12 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE, (void *)fe->dtv_property_cache.sectone); break; + case DTV_CODE_RATE_HP: + fe->dtv_property_cache.code_rate_HP = tvp->u.data; + break; + case DTV_CODE_RATE_LP: + fe->dtv_property_cache.code_rate_LP = tvp->u.data; + break; default: r = -1; } -- cgit v1.2.1 From b87625f0ccbbc67efba356e73502fa9bbb784b1c Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 6 Oct 2008 21:56:59 -0300 Subject: V4L/DVB (9181): S2API: Add support fot DTV_GUARD_INTERVAL and DTV_TRANSMISSION_MODE Tuning DVB-T via the S2API was failing, missing some essential items. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 104f40b7171d..0ddc2f4ecd4a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -840,6 +840,16 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_CODE_RATE_LP, .set = 1, }, + [DTV_GUARD_INTERVAL] = { + .name = "DTV_GUARD_INTERVAL", + .cmd = DTV_GUARD_INTERVAL, + .set = 1, + }, + [DTV_TRANSMISSION_MODE] = { + .name = "DTV_TRANSMISSION_MODE", + .cmd = DTV_TRANSMISSION_MODE, + .set = 1, + }, /* Get */ [DTV_DISEQC_SLAVE_REPLY] = { .name = "DTV_DISEQC_SLAVE_REPLY", @@ -862,6 +872,16 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_CODE_RATE_LP, .set = 0, }, + [DTV_GUARD_INTERVAL] = { + .name = "DTV_GUARD_INTERVAL", + .cmd = DTV_GUARD_INTERVAL, + .set = 0, + }, + [DTV_TRANSMISSION_MODE] = { + .name = "DTV_TRANSMISSION_MODE", + .cmd = DTV_TRANSMISSION_MODE, + .set = 0, + }, }; void dtv_property_dump(struct dtv_property *tvp) @@ -1147,6 +1167,12 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_CODE_RATE_LP: tvp->u.data = fe->dtv_property_cache.code_rate_LP; break; + case DTV_GUARD_INTERVAL: + tvp->u.data = fe->dtv_property_cache.guard_interval; + break; + case DTV_TRANSMISSION_MODE: + tvp->u.data = fe->dtv_property_cache.transmission_mode; + break; default: r = -1; } @@ -1234,6 +1260,12 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_CODE_RATE_LP: fe->dtv_property_cache.code_rate_LP = tvp->u.data; break; + case DTV_GUARD_INTERVAL: + fe->dtv_property_cache.guard_interval = tvp->u.data; + break; + case DTV_TRANSMISSION_MODE: + fe->dtv_property_cache.transmission_mode = tvp->u.data; + break; default: r = -1; } -- cgit v1.2.1 From ef526f4246f566370218bb6e639f7549244ca5a2 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 6 Oct 2008 22:01:47 -0300 Subject: V4L/DVB (9182): S2API: Added support for DTV_HIERARCHY A user tuning DVB-T via the S2API reports that this was not implemented, and his tuning was failing. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 0ddc2f4ecd4a..bd59c9514ab5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -830,6 +830,11 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_DELIVERY_SYSTEM, .set = 1, }, + [DTV_HIERARCHY] = { + .name = "DTV_HIERARCHY", + .cmd = DTV_HIERARCHY, + .set = 1, + }, [DTV_CODE_RATE_HP] = { .name = "DTV_CODE_RATE_HP", .cmd = DTV_CODE_RATE_HP, @@ -882,6 +887,11 @@ struct dtv_cmds_h dtv_cmds[] = { .cmd = DTV_TRANSMISSION_MODE, .set = 0, }, + [DTV_HIERARCHY] = { + .name = "DTV_HIERARCHY", + .cmd = DTV_HIERARCHY, + .set = 0, + }, }; void dtv_property_dump(struct dtv_property *tvp) @@ -1173,6 +1183,9 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_TRANSMISSION_MODE: tvp->u.data = fe->dtv_property_cache.transmission_mode; break; + case DTV_HIERARCHY: + tvp->u.data = fe->dtv_property_cache.hierarchy; + break; default: r = -1; } @@ -1266,6 +1279,9 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, case DTV_TRANSMISSION_MODE: fe->dtv_property_cache.transmission_mode = tvp->u.data; break; + case DTV_HIERARCHY: + fe->dtv_property_cache.hierarchy = tvp->u.data; + break; default: r = -1; } -- cgit v1.2.1 From 6068f5063850984fe6c2490bc8384a7afa2728dc Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 6 Oct 2008 22:46:08 -0300 Subject: V4L/DVB (9183): S2API: Return error of the caller provides 0 commands. S2API: Return error of the caller provides 0 commands. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index bd59c9514ab5..f170e822fadc 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1344,7 +1344,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, /* Put an arbitrary limit on the number of messages that can * be sent at once */ - if (tvps->num > DTV_IOCTL_MAX_MSGS) + if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; tvp = (struct dtv_property *) kmalloc(tvps->num * @@ -1379,7 +1379,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file, /* Put an arbitrary limit on the number of messages that can * be sent at once */ - if (tvps->num > DTV_IOCTL_MAX_MSGS) + if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; tvp = (struct dtv_property *) kmalloc(tvps->num * -- cgit v1.2.1 From b40d29e0afac38f4ce6cb1db400a60f36c5cabee Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Tue, 7 Oct 2008 13:10:12 -0300 Subject: V4L/DVB (9184): cx24116: Change the default SNR units back to percentage by default. cx24116: Change the default SNR units back to percentage by default. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/cx24116.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/dvb') diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index b8acc7b74c33..deb36f469ada 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -118,7 +118,7 @@ static int debug = 0; static int toneburst = 1; /* SNR measurements */ -static int esno_snr = 1; +static int esno_snr = 0; enum cmds { @@ -1414,7 +1414,7 @@ module_param(toneburst, int, 0644); MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); module_param(esno_snr, int, 0644); -MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:1)"); +MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)"); MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); MODULE_AUTHOR("Steven Toth"); -- cgit v1.2.1