summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/dvb')
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-dma.c2
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c3
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-i2c.c12
-rw-r--r--linux/drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--linux/drivers/media/dvb/bt8xx/dst.c4
-rw-r--r--linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c2
-rw-r--r--linux/drivers/media/dvb/dvb-core/dmxdev.c1
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c4
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c8
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Kconfig23
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Makefile6
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9005-remote.c2
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9005-script.h2
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9005.c23
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9015.c1474
-rw-r--r--linux/drivers/media/dvb/dvb-usb/af9015.h524
-rw-r--r--linux/drivers/media/dvb/dvb-usb/anysee.c2
-rw-r--r--linux/drivers/media/dvb/dvb-usb/cxusb.c504
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dib0700_devices.c9
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dtv5100.c240
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dtv5100.h51
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h24
-rw-r--r--linux/drivers/media/dvb/frontends/Kconfig46
-rw-r--r--linux/drivers/media/dvb/frontends/Makefile3
-rw-r--r--linux/drivers/media/dvb/frontends/af9013.c1687
-rw-r--r--linux/drivers/media/dvb/frontends/af9013.h107
-rw-r--r--linux/drivers/media/dvb/frontends/af9013_priv.h869
-rw-r--r--linux/drivers/media/dvb/frontends/au8522.c47
-rw-r--r--linux/drivers/media/dvb/frontends/au8522.h11
-rw-r--r--linux/drivers/media/dvb/frontends/cx22702.c2
-rw-r--r--linux/drivers/media/dvb/frontends/cx22702.h2
-rw-r--r--linux/drivers/media/dvb/frontends/cx24110.h15
-rw-r--r--linux/drivers/media/dvb/frontends/cx24123.c6
-rw-r--r--linux/drivers/media/dvb/frontends/cx24123.h2
-rw-r--r--linux/drivers/media/dvb/frontends/dib0070.h8
-rw-r--r--linux/drivers/media/dvb/frontends/dib7000m.c6
-rw-r--r--linux/drivers/media/dvb/frontends/dib7000p.c3
-rw-r--r--linux/drivers/media/dvb/frontends/dib7000p.h41
-rw-r--r--linux/drivers/media/dvb/frontends/drx397xD.c296
-rw-r--r--linux/drivers/media/dvb/frontends/drx397xD.h6
-rw-r--r--linux/drivers/media/dvb/frontends/dvb_dummy_fe.c11
-rw-r--r--linux/drivers/media/dvb/frontends/lgs8gl5.c478
-rw-r--r--linux/drivers/media/dvb/frontends/lgs8gl5.h45
-rw-r--r--linux/drivers/media/dvb/frontends/nxt200x.c4
-rw-r--r--linux/drivers/media/dvb/frontends/or51211.c2
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1409.c3
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1409.h2
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1411.c3
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1411.h2
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1420.c3
-rw-r--r--linux/drivers/media/dvb/frontends/sp887x.c3
-rw-r--r--linux/drivers/media/dvb/frontends/tda10048.c4
-rw-r--r--linux/drivers/media/dvb/frontends/tda10048.h2
-rw-r--r--linux/drivers/media/dvb/frontends/tdhd1.h73
-rw-r--r--linux/drivers/media/dvb/pluto2/pluto2.c4
-rw-r--r--linux/drivers/media/dvb/ttpci/Kconfig5
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.c127
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.h1
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110_av.c3
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-av.c8
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-ci.c11
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-core.c6
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-patch.c12
-rw-r--r--linux/drivers/media/dvb/ttpci/budget.c28
-rw-r--r--linux/drivers/media/dvb/ttpci/budget.h2
-rw-r--r--linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c2
-rw-r--r--linux/drivers/media/dvb/ttusb-dec/Kconfig2
-rw-r--r--linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c6
68 files changed, 6620 insertions, 311 deletions
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-dma.c b/linux/drivers/media/dvb/b2c2/flexcop-dma.c
index 1df246a7f..02a0f07a1 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-dma.c
+++ b/linux/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.");
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index f9d087669..4eed783f4 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -137,7 +137,8 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
flexcop_diseqc_send_byte(fe, 0xff);
else {
flexcop_set_tone(fe, SEC_TONE_ON);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
flexcop_set_tone(fe, SEC_TONE_OFF);
}
msleep(20);
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
index 55973eaf3..43a112ec6 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -221,12 +221,12 @@ int flexcop_i2c_init(struct flexcop_device *fc)
fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
- strncpy(fc->fc_i2c_adap[0].i2c_adap.name,
- "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE);
- strncpy(fc->fc_i2c_adap[1].i2c_adap.name,
- "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE);
- strncpy(fc->fc_i2c_adap[2].i2c_adap.name,
- "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE);
+ strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+ sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+ sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+ sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
diff --git a/linux/drivers/media/dvb/bt8xx/Kconfig b/linux/drivers/media/dvb/bt8xx/Kconfig
index 7588db131..7e9c090fc 100644
--- a/linux/drivers/media/dvb/bt8xx/Kconfig
+++ b/linux/drivers/media/dvb/bt8xx/Kconfig
@@ -1,7 +1,6 @@
config DVB_BT8XX
tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
- depends on HOTPLUG # due to FW_LOADER
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_SP887X if !DVB_FE_CUSTOMISE
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
@@ -10,7 +9,6 @@ config DVB_BT8XX
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
- select FW_LOADER
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
diff --git a/linux/drivers/media/dvb/bt8xx/dst.c b/linux/drivers/media/dvb/bt8xx/dst.c
index a7637562e..aa3db57d3 100644
--- a/linux/drivers/media/dvb/bt8xx/dst.c
+++ b/linux/drivers/media/dvb/bt8xx/dst.c
@@ -1244,7 +1244,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
goto error;
}
if (state->type_flags & DST_TYPE_HAS_FW_1)
- udelay(3000);
+ mdelay(3);
if (read_dst(state, &reply, GET_ACK)) {
dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
if ((dst_error_recovery(state)) < 0) {
@@ -1260,7 +1260,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
goto error;
if (state->type_flags & DST_TYPE_HAS_FW_1)
- udelay(3000);
+ mdelay(3);
else
udelay(2000);
if (!dst_wait_dst_ready(state, NO_DELAY))
diff --git a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 5fb213cf9..c4b8b0677 100644
--- a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -703,7 +703,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/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c
index 1cf9fcb6f..069d847ba 100644
--- a/linux/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c
@@ -641,7 +641,6 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
struct timespec timeout = { 0 };
struct dmx_pes_filter_params *para = &filter->params.pes;
dmx_output_t otype;
- int ret;
int ts_type;
enum dmx_ts_pes ts_pes;
struct dmx_ts_feed **tsfeed = &filter->feed.ts;
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index c2954bf57..f6016feab 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1033,7 +1033,7 @@ static int dvb_ca_en50221_thread(void *data)
/* we need this extra check for annoying interfaces like the budget-av */
if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
(ca->pub->poll_slot_status)) {
- int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
dvb_ca_en50221_thread_update_delay(ca);
@@ -1090,7 +1090,7 @@ static int dvb_ca_en50221_thread(void *data)
/* we need this extra check for annoying interfaces like the budget-av */
if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
(ca->pub->poll_slot_status)) {
- int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
dvb_ca_en50221_thread_update_delay(ca);
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index 8a9c2283f..60a94dc85 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -900,13 +900,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
* initialization, so parg is 8 bits and does not
* include the initialization or start bit
*/
- unsigned long cmd = ((unsigned long) parg) << 1;
+ unsigned long swcmd = ((unsigned long) parg) << 1;
struct timeval nexttime;
struct timeval tv[10];
int i;
u8 last = 1;
if (dvb_frontend_debug)
- printk("%s switch command: 0x%04lx\n", __func__, cmd);
+ printk("%s switch command: 0x%04lx\n", __func__, swcmd);
do_gettimeofday(&nexttime);
if (dvb_frontend_debug)
memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -919,12 +919,12 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
for (i = 0; i < 9; i++) {
if (dvb_frontend_debug)
do_gettimeofday(&tv[i + 1]);
- if ((cmd & 0x01) != last) {
+ if ((swcmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
- cmd = cmd >> 1;
+ swcmd = swcmd >> 1;
if (i != 8)
dvb_frontend_sleep_until(&nexttime, 8000);
}
diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig
index 3c663c65e..b35d7f0db 100644
--- a/linux/drivers/media/dvb/dvb-usb/Kconfig
+++ b/linux/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,8 +1,6 @@
config DVB_USB
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB && I2C && INPUT
- depends on HOTPLUG # due to FW_LOADER
- select FW_LOADER
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -110,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 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
@@ -264,3 +264,22 @@ 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.
+
+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/linux/drivers/media/dvb/dvb-usb/Makefile b/linux/drivers/media/dvb/dvb-usb/Makefile
index e206f1ea0..ece8c9dfe 100644
--- a/linux/drivers/media/dvb/dvb-usb/Makefile
+++ b/linux/drivers/media/dvb/dvb-usb/Makefile
@@ -67,6 +67,12 @@ 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
+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/linux/drivers/media/dvb/dvb-usb/af9005-remote.c b/linux/drivers/media/dvb/dvb-usb/af9005-remote.c
index ff00c0e8f..7c596f926 100644
--- a/linux/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/linux/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/linux/drivers/media/dvb/dvb-usb/af9005-script.h b/linux/drivers/media/dvb/dvb-usb/af9005-script.h
index 6eeaae51b..4d6904542 100644
--- a/linux/drivers/media/dvb/dvb-usb/af9005-script.h
+++ b/linux/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/linux/drivers/media/dvb/dvb-usb/af9005.c b/linux/drivers/media/dvb/dvb-usb/af9005.c
index cfe71feef..ca5a0a4d2 100644
--- a/linux/drivers/media/dvb/dvb-usb/af9005.c
+++ b/linux/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/linux/drivers/media/dvb/dvb-usb/af9015.c b/linux/drivers/media/dvb/dvb-usb/af9015.c
new file mode 100644
index 000000000..776d01d4a
--- /dev/null
+++ b/linux/drivers/media/dvb/dvb-usb/af9015.c
@@ -0,0 +1,1474 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * 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 /* keep */
+#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 /* keep */
+ 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)},
+ {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);
+
+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 = 5,
+ .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},
+ },
+ {
+ .name = "Telestar Starstick 2",
+ .cold_ids = {&af9015_usb_table[13], NULL},
+ .warm_ids = {NULL},
+ },
+ {
+ .name = "AVerMedia A309",
+ .cold_ids = {&af9015_usb_table[14], 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 = {
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
+ .owner = THIS_MODULE,
+#endif
+ .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 <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/dvb-usb/af9015.h b/linux/drivers/media/dvb/dvb-usb/af9015.h
new file mode 100644
index 000000000..882e8a4b3
--- /dev/null
+++ b/linux/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 <crope@iki.fi>
+ *
+ * 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/linux/drivers/media/dvb/dvb-usb/anysee.c b/linux/drivers/media/dvb/dvb-usb/anysee.c
index adfd4fc82..2f408d2e1 100644
--- a/linux/drivers/media/dvb/dvb-usb/anysee.c
+++ b/linux/drivers/media/dvb/dvb-usb/anysee.c
@@ -43,7 +43,7 @@ module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-struct mutex anysee_usb_mutex;
+static struct mutex anysee_usb_mutex;
static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
u8 *rbuf, u8 rlen)
diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c
index 578afce68..1a746127c 100644
--- a/linux/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c
@@ -36,6 +36,9 @@
#include "tuner-xc2028.h"
#include "tuner-simple.h"
#include "mxl5005s.h"
+#include "dib7000p.h"
+#include "dib0070.h"
+#include "lgs8gl5.h"
/* debug */
static int dvb_usb_cxusb_debug;
@@ -109,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)
@@ -210,7 +232,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
if (d->state == DVB_USB_STATE_INIT &&
usb_set_interface(d->udev, 0, 0) < 0)
err("set interface failed");
- do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+ do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
!(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
!(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
if (!ret) {
@@ -262,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 };
@@ -283,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;
@@ -335,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 },
@@ -422,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 };
@@ -527,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)
{
@@ -565,7 +744,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
{
- struct dvb_usb_device *d = ptr;
+ struct dvb_usb_adapter *adap = ptr;
+ struct dvb_usb_device *d = adap->dev;
switch (command) {
case XC2028_TUNER_RESET:
@@ -593,9 +773,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
.callback = dvico_bluebird_xc2028_callback,
};
static struct xc2028_ctrl ctl = {
- .fname = "xc3028-dvico-au-01.fw",
+ .fname = XC2028_DEFAULT_FIRMWARE,
.max_len = 64,
- .scode_table = XC3028_FE_ZARLINK456,
+ .demod = XC3028_FE_ZARLINK456,
};
fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
@@ -614,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;
@@ -725,6 +913,159 @@ 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);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ &cxusb_dualdig4_rev2_config);
+ if (adap->fe == 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;
+ default:
+ case BAND_UHF: 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)
@@ -750,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
@@ -825,9 +1214,11 @@ 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;
+static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -851,6 +1242,11 @@ 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 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
0)
return 0;
@@ -875,6 +1271,8 @@ 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) },
+ { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1320,6 +1718,104 @@ 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 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/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 3dd20bfbe..6c0e5c5f4 100644
--- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -1117,7 +1117,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) },
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+/* 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) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1373,7 +1374,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .num_device_descs = 3,
+ .num_device_descs = 4,
.devices = {
{ "DiBcom STK7070PD reference design",
{ &dib0700_usb_id_table[17], NULL },
@@ -1386,6 +1387,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ "Hauppauge Nova-TD Stick (52009)",
{ &dib0700_usb_id_table[35], NULL },
{ NULL },
+ },
+ { "Hauppauge Nova-TD-500 (84xxx)",
+ { &dib0700_usb_id_table[36], NULL },
+ { NULL },
}
}
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
diff --git a/linux/drivers/media/dvb/dvb-usb/dtv5100.c b/linux/drivers/media/dvb/dvb-usb/dtv5100.c
new file mode 100644
index 000000000..078ce92ca
--- /dev/null
+++ b/linux/drivers/media/dvb/dvb-usb/dtv5100.c
@@ -0,0 +1,240 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com>
+ * 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 "zl10353.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_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ 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];
+
+ 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)
+{
+ 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++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ 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 if (dtv5100_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 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 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 = 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 = DTV5100_TUNER_ADDR
+};
+
+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);
+
+ /* initialize non qt1010/zl10353 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;
+ }
+
+ ret = dvb_usb_device_init(intf, &dtv5100_properties,
+ THIS_MODULE, NULL, adapter_nr);
+ 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/linux/drivers/media/dvb/dvb-usb/dtv5100.h b/linux/drivers/media/dvb/dvb-usb/dtv5100.h
new file mode 100644
index 000000000..93e96e04a
--- /dev/null
+++ b/linux/drivers/media/dvb/dvb-usb/dtv5100.h
@@ -0,0 +1,51 @@
+/*
+ * DVB USB Linux driver for AME DTV-5100 USB2.0 DVB-T
+ *
+ * Copyright (C) 2008 Antoine Jacquet <royale@zerezo.com>
+ * 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_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"
+
+static struct {
+ u8 request;
+ u8 value;
+ u16 index;
+} dtv5100_init[] = {
+ { 0x000000c5, 0x00000000, 0x00000001 },
+ { 0x000000c5, 0x00000001, 0x00000001 },
+ { } /* Terminating entry */
+};
+
+#endif
diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 029b437ca..7ae262e08 100644
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/linux/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
@@ -33,16 +34,19 @@
#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
#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
@@ -50,15 +54,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
@@ -69,6 +76,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
@@ -87,9 +95,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
@@ -98,6 +109,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
@@ -129,6 +141,7 @@
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941
#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400
#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070
@@ -143,6 +156,9 @@
#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_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
@@ -152,6 +168,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
@@ -170,6 +187,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
@@ -189,6 +207,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
@@ -196,6 +215,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
@@ -205,5 +225,7 @@
#define USB_PID_ASUS_U3100 0x173f
#define USB_PID_YUAN_EC372S 0x1edc
#define USB_PID_DW2102 0x2102
+#define USB_PID_XTENSIONS_XD_380 0x0381
+#define USB_PID_TELESTAR_STARSTICK_2 0x8000
#endif
diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig
index fa7f0c563..097d9f001 100644
--- a/linux/drivers/media/dvb/frontends/Kconfig
+++ b/linux/drivers/media/dvb/frontends/Kconfig
@@ -97,9 +97,8 @@ comment "DVB-T (terrestrial) frontends"
config DVB_SP8870
tristate "Spase sp8870 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -110,9 +109,8 @@ config DVB_SP8870
config DVB_SP887X
tristate "Spase sp887x based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -137,9 +135,8 @@ config DVB_CX22702
config DVB_DRX397XD
tristate "Micronas DRX3975D/DRX3977D based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -158,9 +155,8 @@ config DVB_L64781
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -225,9 +221,8 @@ config DVB_DIB7000P
config DVB_TDA10048
tristate "Philips TDA10048HN based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -267,9 +262,8 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
config DVB_NXT200X
tristate "NxtWave Communications NXT2002/NXT2004 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
@@ -282,9 +276,8 @@ config DVB_NXT200X
config DVB_OR51211
tristate "Oren OR51211 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
@@ -295,9 +288,8 @@ config DVB_OR51211
config DVB_OR51132
tristate "Oren OR51132 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
@@ -311,9 +303,8 @@ config DVB_OR51132
config DVB_BCM3510
tristate "Broadcom BCM3510"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
support this frontend.
@@ -394,4 +385,23 @@ 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.
+
+comment "Tools to develop new frontends"
+
+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/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile
index 028da5561..1b5478886 100644
--- a/linux/drivers/media/dvb/frontends/Makefile
+++ b/linux/drivers/media/dvb/frontends/Makefile
@@ -48,3 +48,6 @@ 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
+obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
+obj-$(CONFIG_DVB_AF9013) += af9013.o
diff --git a/linux/drivers/media/dvb/frontends/af9013.c b/linux/drivers/media/dvb/frontends/af9013.c
new file mode 100644
index 000000000..739d885b3
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/af9013.c
@@ -0,0 +1,1687 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "af9013_priv.h"
+#include "af9013.h"
+
+int 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, &params->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;
+
+ 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)
+ state->ber = error_bit_count * 1000000000 / total_bit_count;
+
+ 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(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/frontends/af9013.h b/linux/drivers/media/dvb/frontends/af9013.h
new file mode 100644
index 000000000..28b90c91c
--- /dev/null
+++ b/linux/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 <crope@iki.fi>
+ *
+ * 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 <linux/dvb/frontend.h>
+
+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/linux/drivers/media/dvb/frontends/af9013_priv.h b/linux/drivers/media/dvb/frontends/af9013_priv.h
new file mode 100644
index 000000000..b62e4cc9b
--- /dev/null
+++ b/linux/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 <crope@iki.fi>
+ *
+ * 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 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(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_ */
diff --git a/linux/drivers/media/dvb/frontends/au8522.c b/linux/drivers/media/dvb/frontends/au8522.c
index 37f6260e1..78e270ee0 100644
--- a/linux/drivers/media/dvb/frontends/au8522.c
+++ b/linux/drivers/media/dvb/frontends/au8522.c
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -304,6 +304,43 @@ static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
return ret;
}
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ u8 r0b5, r0b6, r0b7;
+ char *ifmhz;
+
+ switch (if_freq) {
+ case AU8522_IF_3_25MHZ:
+ ifmhz = "3.25";
+ r0b5 = 0x00;
+ r0b6 = 0x3d;
+ r0b7 = 0xa0;
+ break;
+ case AU8522_IF_4MHZ:
+ ifmhz = "4.00";
+ r0b5 = 0x00;
+ r0b6 = 0x4b;
+ r0b7 = 0xd9;
+ break;
+ case AU8522_IF_6MHZ:
+ ifmhz = "6.00";
+ r0b5 = 0xfb;
+ r0b6 = 0x8e;
+ r0b7 = 0x39;
+ break;
+ default:
+ dprintk("%s() IF Frequency not supported\n", __func__);
+ return -EINVAL;
+ }
+ dprintk("%s() %s MHz\n", __func__, ifmhz);
+ au8522_writereg(state, 0x80b5, r0b5);
+ au8522_writereg(state, 0x80b6, r0b6);
+ au8522_writereg(state, 0x80b7, r0b7);
+
+ return 0;
+}
+
/* VSB Modulation table */
static struct {
u16 reg;
@@ -334,9 +371,6 @@ static struct {
{ 0x80af, 0x66 },
{ 0x821b, 0xcc },
{ 0x821d, 0x80 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80a4, 0xe8 },
{ 0x8231, 0x13 },
};
@@ -350,9 +384,6 @@ static struct {
{ 0x80a4, 0x00 },
{ 0x8081, 0xc4 },
{ 0x80a5, 0x40 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80aa, 0x77 },
{ 0x80ad, 0x77 },
{ 0x80a6, 0x67 },
@@ -438,6 +469,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
VSB_mod_tab[i].reg,
VSB_mod_tab[i].data);
+ au8522_set_if(fe, state->config->vsb_if);
break;
case QAM_64:
case QAM_256:
@@ -446,6 +478,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
QAM_mod_tab[i].reg,
QAM_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
break;
default:
dprintk("%s() Invalid modulation\n", __func__);
diff --git a/linux/drivers/media/dvb/frontends/au8522.h b/linux/drivers/media/dvb/frontends/au8522.h
index d7affa3cd..595915ade 100644
--- a/linux/drivers/media/dvb/frontends/au8522.h
+++ b/linux/drivers/media/dvb/frontends/au8522.h
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -24,6 +24,12 @@
#include <linux/dvb/frontend.h>
+enum au8522_if_freq {
+ AU8522_IF_6MHZ = 0,
+ AU8522_IF_4MHZ,
+ AU8522_IF_3_25MHZ,
+};
+
struct au8522_config {
/* the demodulator's i2c address */
u8 demod_address;
@@ -32,6 +38,9 @@ struct au8522_config {
#define AU8522_TUNERLOCKING 0
#define AU8522_DEMODLOCKING 1
u8 status_mode;
+
+ enum au8522_if_freq vsb_if;
+ enum au8522_if_freq qam_if;
};
#if defined(CONFIG_DVB_AU8522) || \
diff --git a/linux/drivers/media/dvb/frontends/cx22702.c b/linux/drivers/media/dvb/frontends/cx22702.c
index cc1db4e37..9430e03db 100644
--- a/linux/drivers/media/dvb/frontends/cx22702.c
+++ b/linux/drivers/media/dvb/frontends/cx22702.c
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/linux/drivers/media/dvb/frontends/cx22702.h b/linux/drivers/media/dvb/frontends/cx22702.h
index 8af766a31..b1e465c6c 100644
--- a/linux/drivers/media/dvb/frontends/cx22702.h
+++ b/linux/drivers/media/dvb/frontends/cx22702.h
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/linux/drivers/media/dvb/frontends/cx24110.h b/linux/drivers/media/dvb/frontends/cx24110.h
index 1792adb23..fdcceee91 100644
--- a/linux/drivers/media/dvb/frontends/cx24110.h
+++ b/linux/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/linux/drivers/media/dvb/frontends/cx24123.c b/linux/drivers/media/dvb/frontends/cx24123.c
index 83b6793de..970e4df08 100644
--- a/linux/drivers/media/dvb/frontends/cx24123.c
+++ b/linux/drivers/media/dvb/frontends/cx24123.c
@@ -1,7 +1,7 @@
/*
* Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
*
- * Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
*
* Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
*
@@ -1083,8 +1083,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
if (config->dont_use_pll)
cx24123_repeater_mode(state, 1, 0);
- strncpy(state->tuner_i2c_adapter.name,
- "CX24123 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/linux/drivers/media/dvb/frontends/cx24123.h b/linux/drivers/media/dvb/frontends/cx24123.h
index 81ebc3d2f..cc6b411d6 100644
--- a/linux/drivers/media/dvb/frontends/cx24123.h
+++ b/linux/drivers/media/dvb/frontends/cx24123.h
@@ -1,7 +1,7 @@
/*
Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
- Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/linux/drivers/media/dvb/frontends/dib0070.h b/linux/drivers/media/dvb/frontends/dib0070.h
index 3eedfdf50..21f2c5161 100644
--- a/linux/drivers/media/dvb/frontends/dib0070.h
+++ b/linux/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/linux/drivers/media/dvb/frontends/dib7000m.c b/linux/drivers/media/dvb/frontends/dib7000m.c
index 188f6e853..763407d06 100644
--- a/linux/drivers/media/dvb/frontends/dib7000m.c
+++ b/linux/drivers/media/dvb/frontends/dib7000m.c
@@ -1320,7 +1320,10 @@ 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[])
+#if 0 /* keep */
+/* 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 };
int k = 0;
@@ -1365,6 +1368,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
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)
diff --git a/linux/drivers/media/dvb/frontends/dib7000p.c b/linux/drivers/media/dvb/frontends/dib7000p.c
index c74d373b6..ebb7594e3 100644
--- a/linux/drivers/media/dvb/frontends/dib7000p.c
+++ b/linux/drivers/media/dvb/frontends/dib7000p.c
@@ -1359,7 +1359,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;
diff --git a/linux/drivers/media/dvb/frontends/dib7000p.h b/linux/drivers/media/dvb/frontends/dib7000p.h
index 07c4d12ed..3e8126857 100644
--- a/linux/drivers/media/dvb/frontends/dib7000p.h
+++ b/linux/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
diff --git a/linux/drivers/media/dvb/frontends/drx397xD.c b/linux/drivers/media/dvb/frontends/drx397xD.c
index 52a9a6553..7a2b2d461 100644
--- a/linux/drivers/media/dvb/frontends/drx397xD.c
+++ b/linux/drivers/media/dvb/frontends/drx397xD.c
@@ -39,35 +39,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;
@@ -86,7 +83,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)
@@ -95,9 +92,9 @@ 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", __FUNCTION__);
+ pr_debug("%s\n", __func__);
write_lock(&fw[ix].lock);
if (fw[ix].refcnt) {
@@ -108,13 +105,13 @@ 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;
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;
@@ -176,32 +173,34 @@ 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", __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];
@@ -230,33 +229,33 @@ 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;
}
/* 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,
- .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;
+ *(__le32 *) a = i2c_adr;
rc = i2c_transfer(s->i2c, msg, 2);
if (rc != 2)
@@ -266,7 +265,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;
@@ -277,28 +276,28 @@ 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)
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)
{
@@ -306,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))
@@ -326,28 +325,26 @@ 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;
}
-/*******************************************************************************
- * Demodulator helper functions
- ******************************************************************************/
-
+/* Demodulator helper functions */
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);
if (rc == 0)
return 0;
}
+
return -1;
}
@@ -355,13 +352,14 @@ 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);
rc = RD16(s, 0x820042);
if ((rc & 0xffff) == 0xffff)
return -1;
+
return 0;
}
@@ -369,7 +367,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)
@@ -384,22 +382,24 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd)
if (rc < 0)
return rc;
} while (--cnt);
+
return rc;
}
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
- 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);
}
@@ -420,7 +420,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;
@@ -469,7 +469,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;
}
@@ -479,7 +479,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;
@@ -499,7 +499,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));
@@ -523,7 +523,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;
}
@@ -555,7 +556,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));
@@ -599,11 +600,12 @@ 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);
- exit_rc:
+
+exit_rc:
return rc;
}
@@ -611,7 +613,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) {
@@ -621,17 +623,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;
}
@@ -647,7 +649,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;
@@ -695,7 +697,7 @@ static int drx_tune(struct drx397xD_state *s,
}
loc_800111A:
#endif
- set_tuner:
+set_tuner:
rc = PLL_Set(s, fep, &df_tuner);
if (rc < 0) {
@@ -872,16 +874,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) {
@@ -1034,17 +1036,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;
};
@@ -1102,8 +1104,11 @@ 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;
+#if 0
+ rc = WR16(s, 0x2150000, 1);
+ if (rc < 0)
+ goto exit_rc;
+#endif
rc = WR16(s, 0x2150000, 2);
rc = WR16(s, 0x2150016, a);
@@ -1111,7 +1116,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;
}
@@ -1124,7 +1130,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;
@@ -1144,18 +1150,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 */
@@ -1312,7 +1318,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)
@@ -1390,7 +1396,8 @@ static int drx397x_init(struct dvb_frontend *fe)
#endif
s->config.d60 = 1;
s->config.d48 = 1;
- error:
+
+error:
return rc;
}
@@ -1405,7 +1412,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);
}
@@ -1416,18 +1424,21 @@ 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);
+#if 0
/* TODO */
-// if (lockstat & 1)
-// CorrectSysClockDeviation(s);
+ if (lockstat & 1)
+ CorrectSysClockDeviation(s);
+#endif
*status = 0;
if (lockstat & 2) {
@@ -1435,9 +1446,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;
}
@@ -1445,16 +1455,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;
@@ -1480,6 +1492,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;
}
@@ -1487,6 +1500,7 @@ static int drx397x_read_ucblocks(struct dvb_frontend *fe,
unsigned int *ucblocks)
{
*ucblocks = 0;
+
return 0;
}
@@ -1515,22 +1529,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,
@@ -1551,33 +1565,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)
+ if (RD16(state, 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 = state;
+
+ 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);
diff --git a/linux/drivers/media/dvb/frontends/drx397xD.h b/linux/drivers/media/dvb/frontends/drx397xD.h
index ddc7a0797..ba05d1729 100644
--- a/linux/drivers/media/dvb/frontends/drx397xD.h
+++ b/linux/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) | \
@@ -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 */
diff --git a/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c b/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c
index fed09dfb2..db8a937cc 100644
--- a/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/linux/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;
@@ -131,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;
@@ -151,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/linux/drivers/media/dvb/frontends/lgs8gl5.c b/linux/drivers/media/dvb/frontends/lgs8gl5.c
new file mode 100644
index 000000000..380ae1868
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/lgs8gl5.c
@@ -0,0 +1,478 @@
+/*
+ Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
+
+ Copyright (C) 2008 Sirius International (Hong Kong) Limited
+ Timothy Lee <timothy.lee@siriushk.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#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;
+ 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;
+ 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);
+}
+
+#if 0
+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;
+ }
+}
+#endif
+
+/* 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)
+{
+ *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)
+{
+ *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/linux/drivers/media/dvb/frontends/lgs8gl5.h b/linux/drivers/media/dvb/frontends/lgs8gl5.h
new file mode 100644
index 000000000..d14176787
--- /dev/null
+++ b/linux/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 <timothy.lee@siriushk.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LGS8GL5_H
+#define LGS8GL5_H
+
+#include <linux/dvb/frontend.h>
+
+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 */
diff --git a/linux/drivers/media/dvb/frontends/nxt200x.c b/linux/drivers/media/dvb/frontends/nxt200x.c
index a079fa824..846350bc4 100644
--- a/linux/drivers/media/dvb/frontends/nxt200x.c
+++ b/linux/drivers/media/dvb/frontends/nxt200x.c
@@ -81,7 +81,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 };
@@ -112,7 +112,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/linux/drivers/media/dvb/frontends/or51211.c b/linux/drivers/media/dvb/frontends/or51211.c
index 6afe12aac..16cf2fdd5 100644
--- a/linux/drivers/media/dvb/frontends/or51211.c
+++ b/linux/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;
diff --git a/linux/drivers/media/dvb/frontends/s5h1409.c b/linux/drivers/media/dvb/frontends/s5h1409.c
index 5ddb2dca3..7500a1c53 100644
--- a/linux/drivers/media/dvb/frontends/s5h1409.c
+++ b/linux/drivers/media/dvb/frontends/s5h1409.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
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
@@ -404,6 +404,7 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
if (state->if_freq != S5H1409_QAM_IF_FREQ)
s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
diff --git a/linux/drivers/media/dvb/frontends/s5h1409.h b/linux/drivers/media/dvb/frontends/s5h1409.h
index 59f433596..d1a1d2eb8 100644
--- a/linux/drivers/media/dvb/frontends/s5h1409.h
+++ b/linux/drivers/media/dvb/frontends/s5h1409.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/linux/drivers/media/dvb/frontends/s5h1411.c b/linux/drivers/media/dvb/frontends/s5h1411.c
index cff360ce1..2da1a3763 100644
--- a/linux/drivers/media/dvb/frontends/s5h1411.c
+++ b/linux/drivers/media/dvb/frontends/s5h1411.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -488,6 +488,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
s5h1411_set_if_freq(fe, state->config->qam_if);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
diff --git a/linux/drivers/media/dvb/frontends/s5h1411.h b/linux/drivers/media/dvb/frontends/s5h1411.h
index 1855f64ed..7d542bc00 100644
--- a/linux/drivers/media/dvb/frontends/s5h1411.h
+++ b/linux/drivers/media/dvb/frontends/s5h1411.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c
index 996f37704..b768da972 100644
--- a/linux/drivers/media/dvb/frontends/s5h1420.c
+++ b/linux/drivers/media/dvb/frontends/s5h1420.c
@@ -946,7 +946,8 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
state->frontend.demodulator_priv = state;
/* create tuner i2c adapter */
- strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/linux/drivers/media/dvb/frontends/sp887x.c b/linux/drivers/media/dvb/frontends/sp887x.c
index 4543609e1..559509ab4 100644
--- a/linux/drivers/media/dvb/frontends/sp887x.c
+++ b/linux/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/linux/drivers/media/dvb/frontends/tda10048.c b/linux/drivers/media/dvb/frontends/tda10048.c
index 7c718e247..7a882faf5 100644
--- a/linux/drivers/media/dvb/frontends/tda10048.c
+++ b/linux/drivers/media/dvb/frontends/tda10048.c
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -303,7 +303,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
- return -EIO;
+ ret = -EIO;
} else {
printk(KERN_INFO "%s: firmware uploading\n", __func__);
diff --git a/linux/drivers/media/dvb/frontends/tda10048.h b/linux/drivers/media/dvb/frontends/tda10048.h
index 2b5c78e62..0457b2460 100644
--- a/linux/drivers/media/dvb/frontends/tda10048.h
+++ b/linux/drivers/media/dvb/frontends/tda10048.h
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/linux/drivers/media/dvb/frontends/tdhd1.h b/linux/drivers/media/dvb/frontends/tdhd1.h
new file mode 100644
index 000000000..51f170678
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tdhd1.h
@@ -0,0 +1,73 @@
+/*
+ * tdhd1.h - ALPS TDHD1-204A tuner support
+ *
+ * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by 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 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,
+ .invert_oclk = 0,
+ .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)
+{
+ 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/linux/drivers/media/dvb/pluto2/pluto2.c b/linux/drivers/media/dvb/pluto2/pluto2.c
index d654d872e..cb368e2e0 100644
--- a/linux/drivers/media/dvb/pluto2/pluto2.c
+++ b/linux/drivers/media/dvb/pluto2/pluto2.c
@@ -242,7 +242,11 @@ static int __devinit pluto_dma_map(struct pluto *pluto)
pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
return pci_dma_mapping_error(pluto->dma_addr);
+#else
+ return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr);
+#endif
}
static void pluto_dma_unmap(struct pluto *pluto)
diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig
index 87c973ac6..867027cea 100644
--- a/linux/drivers/media/dvb/ttpci/Kconfig
+++ b/linux/drivers/media/dvb/ttpci/Kconfig
@@ -5,8 +5,6 @@ config TTPCI_EEPROM
config DVB_AV7110
tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
- depends on HOTPLUG
- select FW_LOADER if !DVB_AV7110_FIRMWARE
select TTPCI_EEPROM
select VIDEO_SAA7146_VV
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
@@ -88,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
@@ -127,14 +126,12 @@ config DVB_BUDGET_AV
depends on DVB_BUDGET_CORE && I2C
select VIDEO_SAA7146_VV
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
- depends on HOTPLUG # dependency of FW_LOADER
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_TUA6100 if !DVB_FE_CUSTOMISE
- select FW_LOADER
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c
index 0909eb861..bb63e2121 100644
--- a/linux/drivers/media/dvb/ttpci/av7110.c
+++ b/linux/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;
@@ -376,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;
@@ -487,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;
@@ -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; i<demux->filternum; 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;
@@ -1233,18 +1260,14 @@ 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);
+ 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 /* keep */
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
@@ -2256,7 +2277,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,
@@ -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/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h
index 61e4a7569..e82519e21 100644
--- a/linux/drivers/media/dvb/ttpci/av7110.h
+++ b/linux/drivers/media/dvb/ttpci/av7110.h
@@ -194,6 +194,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/linux/drivers/media/dvb/ttpci/av7110_av.c b/linux/drivers/media/dvb/ttpci/av7110_av.c
index 184647ad1..bdc62acf2 100644
--- a/linux/drivers/media/dvb/ttpci/av7110_av.c
+++ b/linux/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)
diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c
index b7d1f2f18..1032ea778 100644
--- a/linux/drivers/media/dvb/ttpci/budget-av.c
+++ b/linux/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;
@@ -1049,7 +1051,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,
@@ -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/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c
index f7388e5fc..969877f58 100644
--- a/linux/drivers/media/dvb/ttpci/budget-ci.c
+++ b/linux/drivers/media/dvb/ttpci/budget-ci.c
@@ -34,6 +34,10 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
+/* Fix compile warning */
+#undef BIT
+#endif
#include <linux/spinlock.h>
#include <media/ir-common.h>
@@ -92,6 +96,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;
@@ -1157,7 +1163,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,
@@ -1187,7 +1193,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/linux/drivers/media/dvb/ttpci/budget-core.c b/linux/drivers/media/dvb/ttpci/budget-core.c
index 6f4ddb643..ba18e56d5 100644
--- a/linux/drivers/media/dvb/ttpci/budget-core.c
+++ b/linux/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/linux/drivers/media/dvb/ttpci/budget-patch.c b/linux/drivers/media/dvb/ttpci/budget-patch.c
index 5139b481e..0f0bfcad1 100644
--- a/linux/drivers/media/dvb/ttpci/budget-patch.c
+++ b/linux/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;
@@ -116,7 +118,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
DiseqcSendByte(budget, 0xff);
else {
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
}
msleep(20);
@@ -359,7 +362,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,
@@ -591,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/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c
index 2293d80c6..1638e1d9f 100644
--- a/linux/drivers/media/dvb/ttpci/budget.c
+++ b/linux/drivers/media/dvb/ttpci/budget.c
@@ -46,11 +46,14 @@
#include "lnbp21.h"
#include "bsru6.h"
#include "bsbe1.h"
+#include "tdhd1.h"
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;
@@ -108,7 +111,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
DiseqcSendByte(budget, 0xff);
else {
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
}
msleep(20);
@@ -389,6 +393,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)
{
@@ -510,6 +521,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) {
@@ -549,7 +568,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,
@@ -581,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;
@@ -623,6 +643,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),
@@ -633,6 +654,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,
diff --git a/linux/drivers/media/dvb/ttpci/budget.h b/linux/drivers/media/dvb/ttpci/budget.h
index 6539c0171..6129196b8 100644
--- a/linux/drivers/media/dvb/ttpci/budget.h
+++ b/linux/drivers/media/dvb/ttpci/budget.h
@@ -110,7 +110,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);
diff --git a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index ceae085cb..13085a8e2 100644
--- a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1634,7 +1634,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/linux/drivers/media/dvb/ttusb-dec/Kconfig b/linux/drivers/media/dvb/ttusb-dec/Kconfig
index a23cc0aa1..d5f48a310 100644
--- a/linux/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/linux/drivers/media/dvb/ttusb-dec/Kconfig
@@ -1,8 +1,6 @@
config DVB_TTUSB_DEC
tristate "Technotrend/Hauppauge USB DEC devices"
depends on DVB_CORE && USB && INPUT
- depends on HOTPLUG # due to FW_LOADER
- select FW_LOADER
select CRC32
help
Support for external USB adapters designed by Technotrend and
diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 0fdcb19cb..5c2885e17 100644
--- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1284,11 +1284,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
u8 b1[] = { 0x61 };
u8 *b;
char idstring[21];
-#ifndef TTUSB_KERNEL
- u8 *firmware = NULL;
-#else
const u8 *firmware = NULL;
-#endif
size_t firmware_size = 0;
u16 firmware_csum = 0;
__be16 firmware_csum_ns;
@@ -1678,7 +1674,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 {