summary refs log tree commit diff
path: root/drivers/media/dvb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r--drivers/media/dvb/Kconfig4
-rw-r--r--drivers/media/dvb/Makefile3
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c21
-rw-r--r--drivers/media/dvb/bt8xx/dst.c12
-rw-r--r--drivers/media/dvb/dm1105/Kconfig1
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c505
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c12
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.c1
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig8
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c351
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h1
-rw-r--r--drivers/media/dvb/dvb-usb/az6027.c1151
-rw-r--r--drivers/media/dvb/dvb-usb/az6027.h14
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c3
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h1
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c197
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c160
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h9
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c1
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c95
-rw-r--r--drivers/media/dvb/dvb-usb/friio-fe.c2
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c141
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.h2
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c2
-rw-r--r--drivers/media/dvb/firewire/firedtv-1394.c19
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c514
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c1
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c2
-rw-r--r--drivers/media/dvb/firewire/firedtv.h6
-rw-r--r--drivers/media/dvb/frontends/af9013.h1
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c16
-rw-r--r--drivers/media/dvb/frontends/dib0090.c2
-rw-r--r--drivers/media/dvb/frontends/dib8000.c2
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c2
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c3
-rw-r--r--drivers/media/dvb/frontends/si21xx.c38
-rw-r--r--drivers/media/dvb/frontends/stv0900.h2
-rw-r--r--drivers/media/dvb/frontends/stv0900_core.c109
-rw-r--r--drivers/media/dvb/frontends/stv0900_priv.h11
-rw-r--r--drivers/media/dvb/frontends/stv0900_reg.h6
-rw-r--r--drivers/media/dvb/frontends/stv0900_sw.c54
-rw-r--r--drivers/media/dvb/frontends/stv090x.c486
-rw-r--r--drivers/media/dvb/frontends/stv090x.h13
-rw-r--r--drivers/media/dvb/frontends/stv090x_priv.h17
-rw-r--r--drivers/media/dvb/frontends/stv6110x.c188
-rw-r--r--drivers/media/dvb/frontends/stv6110x.h1
-rw-r--r--drivers/media/dvb/frontends/stv6110x_priv.h1
-rw-r--r--drivers/media/dvb/frontends/tda665x.c2
-rw-r--r--drivers/media/dvb/frontends/tda8261.c2
-rw-r--r--drivers/media/dvb/frontends/zl10036.c2
-rw-r--r--drivers/media/dvb/frontends/zl10039.c1
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_input.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.c5
-rw-r--r--drivers/media/dvb/ngene/Kconfig9
-rw-r--r--drivers/media/dvb/ngene/Makefile11
-rw-r--r--drivers/media/dvb/ngene/ngene-core.c2024
-rw-r--r--drivers/media/dvb/ngene/ngene.h859
-rw-r--r--drivers/media/dvb/siano/sms-cards.c1
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c7
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h77
-rw-r--r--drivers/media/dvb/siano/smsdvb.c318
-rw-r--r--drivers/media/dvb/siano/smsir.c6
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c14
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/dvb/ttpci/budget.c4
68 files changed, 6393 insertions, 1151 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index cf8f65f309da..161ccfd471cb 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -76,6 +76,10 @@ comment "Supported Mantis Adapters"
 	depends on DVB_CORE && PCI && I2C
 	source "drivers/media/dvb/mantis/Kconfig"
 
+comment "Supported nGene Adapters"
+	depends on DVB_CORE && PCI && I2C
+	source "drivers/media/dvb/ngene/Kconfig"
+
 comment "Supported DVB Frontends"
 	depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index c12922c3659b..a1a08758a6f2 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -14,6 +14,7 @@ obj-y        := dvb-core/	\
 		siano/		\
 		dm1105/		\
 		pt1/		\
-		mantis/
+		mantis/		\
+		ngene/
 
 obj-$(CONFIG_DVB_FIREDTV)	+= firewire/
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index a24c125331f0..99d62094f908 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -576,43 +576,30 @@ static struct pci_driver bt878_pci_driver = {
       .remove	= __devexit_p(bt878_remove),
 };
 
-static int bt878_pci_driver_registered;
-
 /*******************************/
 /* Module management functions */
 /*******************************/
 
-static int bt878_init_module(void)
+static int __init bt878_init_module(void)
 {
 	bt878_num = 0;
-	bt878_pci_driver_registered = 0;
 
 	printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
 	       (BT878_VERSION_CODE >> 16) & 0xff,
 	       (BT878_VERSION_CODE >> 8) & 0xff,
 	       BT878_VERSION_CODE & 0xff);
-/*
-	bt878_check_chipset();
-*/
-	/* later we register inside of bt878_find_audio_dma()
-	 * because we may want to ignore certain cards */
-	bt878_pci_driver_registered = 1;
+
 	return pci_register_driver(&bt878_pci_driver);
 }
 
-static void bt878_cleanup_module(void)
+static void __exit bt878_cleanup_module(void)
 {
-	if (bt878_pci_driver_registered) {
-		bt878_pci_driver_registered = 0;
-		pci_unregister_driver(&bt878_pci_driver);
-	}
-	return;
+	pci_unregister_driver(&bt878_pci_driver);
 }
 
 module_init(bt878_init_module);
 module_exit(bt878_cleanup_module);
 
-//MODULE_AUTHOR("XXX");
 MODULE_LICENSE("GPL");
 
 /*
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 91353a6faf1d..8b0cde38984d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1352,8 +1352,7 @@ static int dst_get_tuna(struct dst_state *state)
 		return retval;
 	}
 	if ((state->type_flags & DST_TYPE_HAS_VLF) &&
-		!(state->dst_type == DST_TYPE_IS_CABLE) &&
-		!(state->dst_type == DST_TYPE_IS_ATSC)) {
+	   !(state->dst_type == DST_TYPE_IS_ATSC)) {
 
 		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
 			dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
@@ -1820,8 +1819,13 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
 		.frequency_max = 858000000,
 		.symbol_rate_min = 1000000,
 		.symbol_rate_max = 45000000,
-	/*     . symbol_rate_tolerance	=	???,*/
-		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
+		.caps = FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_QAM_16	|
+			FE_CAN_QAM_32	|
+			FE_CAN_QAM_64	|
+			FE_CAN_QAM_128	|
+			FE_CAN_QAM_256
 	},
 
 	.release = dst_release,
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
index de3eeb0a8d6e..695239227cb7 100644
--- a/drivers/media/dvb/dm1105/Kconfig
+++ b/drivers/media/dvb/dm1105/Kconfig
@@ -8,6 +8,7 @@ config DVB_DM1105
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_SI21XX if !DVB_FE_CUSTOMISE
+	select DVB_DS3000 if !DVB_FE_CUSTOMISE
 	select VIDEO_IR
 	help
 	  Support for cards based on the SDMC DM1105 PCI chip like
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index f0f483ac8b89..383cca378b8c 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -43,6 +43,7 @@
 #include "si21xx.h"
 #include "cx24116.h"
 #include "z0194a.h"
+#include "ds3000.h"
 
 #define UNSET (-1U)
 
@@ -269,7 +270,7 @@ struct infrared {
 	u32			ir_command;
 };
 
-struct dm1105dvb {
+struct dm1105_dev {
 	/* pci */
 	struct pci_dev *pdev;
 	u8 __iomem *io_mem;
@@ -308,31 +309,47 @@ struct dm1105dvb {
 	spinlock_t lock;
 };
 
-#define dm_io_mem(reg)	((unsigned long)(&dm1105dvb->io_mem[reg]))
+#define dm_io_mem(reg)	((unsigned long)(&dev->io_mem[reg]))
+
+#define dm_readb(reg)		inb(dm_io_mem(reg))
+#define dm_writeb(reg, value)	outb((value), (dm_io_mem(reg)))
+
+#define dm_readw(reg)		inw(dm_io_mem(reg))
+#define dm_writew(reg, value)	outw((value), (dm_io_mem(reg)))
+
+#define dm_readl(reg)		inl(dm_io_mem(reg))
+#define dm_writel(reg, value)	outl((value), (dm_io_mem(reg)))
+
+#define dm_andorl(reg, mask, value) \
+	outl((inl(dm_io_mem(reg)) & ~(mask)) |\
+		((value) & (mask)), (dm_io_mem(reg)))
+
+#define dm_setl(reg, bit)	dm_andorl((reg), (bit), (bit))
+#define dm_clearl(reg, bit)	dm_andorl((reg), (bit), 0)
 
 static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
 			    struct i2c_msg *msgs, int num)
 {
-	struct dm1105dvb *dm1105dvb ;
+	struct dm1105_dev *dev ;
 
 	int addr, rc, i, j, k, len, byte, data;
 	u8 status;
 
-	dm1105dvb = i2c_adap->algo_data;
+	dev = i2c_adap->algo_data;
 	for (i = 0; i < num; i++) {
-		outb(0x00, dm_io_mem(DM1105_I2CCTR));
+		dm_writeb(DM1105_I2CCTR, 0x00);
 		if (msgs[i].flags & I2C_M_RD) {
 			/* read bytes */
 			addr  = msgs[i].addr << 1;
 			addr |= 1;
-			outb(addr, dm_io_mem(DM1105_I2CDAT));
+			dm_writeb(DM1105_I2CDAT, addr);
 			for (byte = 0; byte < msgs[i].len; byte++)
-				outb(0, dm_io_mem(DM1105_I2CDAT + byte + 1));
+				dm_writeb(DM1105_I2CDAT + byte + 1, 0);
 
-			outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
 			for (j = 0; j < 55; j++) {
 				mdelay(10);
-				status = inb(dm_io_mem(DM1105_I2CSTS));
+				status = dm_readb(DM1105_I2CSTS);
 				if ((status & 0xc0) == 0x40)
 					break;
 			}
@@ -340,56 +357,54 @@ static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
 				return -1;
 
 			for (byte = 0; byte < msgs[i].len; byte++) {
-				rc = inb(dm_io_mem(DM1105_I2CDAT + byte + 1));
+				rc = dm_readb(DM1105_I2CDAT + byte + 1);
 				if (rc < 0)
 					goto err;
 				msgs[i].buf[byte] = rc;
 			}
-		} else {
-			if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
-				/* prepaired for cx24116 firmware */
-				/* Write in small blocks */
-				len = msgs[i].len - 1;
-				k = 1;
-				do {
-					outb(msgs[i].addr << 1, dm_io_mem(DM1105_I2CDAT));
-					outb(0xf7, dm_io_mem(DM1105_I2CDAT + 1));
-					for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
-						data = msgs[i].buf[k+byte];
-						outb(data, dm_io_mem(DM1105_I2CDAT + byte + 2));
-					}
-					outb(0x82 + (len > 48 ? 48 : len), dm_io_mem(DM1105_I2CCTR));
-					for (j = 0; j < 25; j++) {
-						mdelay(10);
-						status = inb(dm_io_mem(DM1105_I2CSTS));
-						if ((status & 0xc0) == 0x40)
-							break;
-					}
-
-					if (j >= 25)
-						return -1;
-
-					k += 48;
-					len -= 48;
-				} while (len > 0);
-			} else {
-				/* write bytes */
-				outb(msgs[i].addr<<1, dm_io_mem(DM1105_I2CDAT));
-				for (byte = 0; byte < msgs[i].len; byte++) {
-					data = msgs[i].buf[byte];
-					outb(data, dm_io_mem(DM1105_I2CDAT + byte + 1));
+		} else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) {
+			/* prepaired for cx24116 firmware */
+			/* Write in small blocks */
+			len = msgs[i].len - 1;
+			k = 1;
+			do {
+				dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
+				dm_writeb(DM1105_I2CDAT + 1, 0xf7);
+				for (byte = 0; byte < (len > 48 ? 48 : len); byte++) {
+					data = msgs[i].buf[k + byte];
+					dm_writeb(DM1105_I2CDAT + byte + 2, data);
 				}
-				outb(0x81 + msgs[i].len, dm_io_mem(DM1105_I2CCTR));
+				dm_writeb(DM1105_I2CCTR, 0x82 + (len > 48 ? 48 : len));
 				for (j = 0; j < 25; j++) {
 					mdelay(10);
-					status = inb(dm_io_mem(DM1105_I2CSTS));
+					status = dm_readb(DM1105_I2CSTS);
 					if ((status & 0xc0) == 0x40)
 						break;
 				}
 
 				if (j >= 25)
 					return -1;
+
+				k += 48;
+				len -= 48;
+			} while (len > 0);
+		} else {
+			/* write bytes */
+			dm_writeb(DM1105_I2CDAT, msgs[i].addr << 1);
+			for (byte = 0; byte < msgs[i].len; byte++) {
+				data = msgs[i].buf[byte];
+				dm_writeb(DM1105_I2CDAT + byte + 1, data);
 			}
+			dm_writeb(DM1105_I2CCTR, 0x81 + msgs[i].len);
+			for (j = 0; j < 25; j++) {
+				mdelay(10);
+				status = dm_readb(DM1105_I2CSTS);
+				if ((status & 0xc0) == 0x40)
+					break;
+			}
+
+			if (j >= 25)
+				return -1;
 		}
 	}
 	return num;
@@ -407,22 +422,22 @@ static struct i2c_algorithm dm1105_algo = {
 	.functionality = functionality,
 };
 
-static inline struct dm1105dvb *feed_to_dm1105dvb(struct dvb_demux_feed *feed)
+static inline struct dm1105_dev *feed_to_dm1105_dev(struct dvb_demux_feed *feed)
 {
-	return container_of(feed->demux, struct dm1105dvb, demux);
+	return container_of(feed->demux, struct dm1105_dev, demux);
 }
 
-static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
+static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
 {
-	return container_of(fe->dvb, struct dm1105dvb, dvb_adapter);
+	return container_of(fe->dvb, struct dm1105_dev, dvb_adapter);
 }
 
-static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
-	struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+	struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
 	u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
 
-	switch (dm1105dvb->boardnr) {
+	switch (dev->boardnr) {
 	case DM1105_BOARD_AXESS_DM05:
 		lnb_mask = DM05_LNB_MASK;
 		lnb_off = DM05_LNB_OFF;
@@ -438,62 +453,67 @@ static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volta
 		lnb_18v = DM1105_LNB_18V;
 	}
 
-	outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
+	dm_writel(DM1105_GPIOCTR, lnb_mask);
 	if (voltage == SEC_VOLTAGE_18)
-		outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
+		dm_writel(DM1105_GPIOVAL, lnb_18v);
 	else if (voltage == SEC_VOLTAGE_13)
-		outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
+		dm_writel(DM1105_GPIOVAL, lnb_13v);
 	else
-		outl(lnb_off, dm_io_mem(DM1105_GPIOVAL));
+		dm_writel(DM1105_GPIOVAL, lnb_off);
 
 	return 0;
 }
 
-static void dm1105dvb_set_dma_addr(struct dm1105dvb *dm1105dvb)
+static void dm1105_set_dma_addr(struct dm1105_dev *dev)
 {
-	outl(cpu_to_le32(dm1105dvb->dma_addr), dm_io_mem(DM1105_STADR));
+	dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
 }
 
-static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
+static int __devinit dm1105_dma_map(struct dm1105_dev *dev)
 {
-	dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
+	dev->ts_buf = pci_alloc_consistent(dev->pdev,
+					6 * DM1105_DMA_BYTES,
+					&dev->dma_addr);
 
-	return !dm1105dvb->ts_buf;
+	return !dev->ts_buf;
 }
 
-static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
+static void dm1105_dma_unmap(struct dm1105_dev *dev)
 {
-	pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr);
+	pci_free_consistent(dev->pdev,
+			6 * DM1105_DMA_BYTES,
+			dev->ts_buf,
+			dev->dma_addr);
 }
 
-static void dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb)
+static void dm1105_enable_irqs(struct dm1105_dev *dev)
 {
-	outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK));
-	outb(1, dm_io_mem(DM1105_CR));
+	dm_writeb(DM1105_INTMAK, INTMAK_ALLMASK);
+	dm_writeb(DM1105_CR, 1);
 }
 
-static void dm1105dvb_disable_irqs(struct dm1105dvb *dm1105dvb)
+static void dm1105_disable_irqs(struct dm1105_dev *dev)
 {
-	outb(INTMAK_IRM, dm_io_mem(DM1105_INTMAK));
-	outb(0, dm_io_mem(DM1105_CR));
+	dm_writeb(DM1105_INTMAK, INTMAK_IRM);
+	dm_writeb(DM1105_CR, 0);
 }
 
-static int dm1105dvb_start_feed(struct dvb_demux_feed *f)
+static int dm1105_start_feed(struct dvb_demux_feed *f)
 {
-	struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
 
-	if (dm1105dvb->full_ts_users++ == 0)
-		dm1105dvb_enable_irqs(dm1105dvb);
+	if (dev->full_ts_users++ == 0)
+		dm1105_enable_irqs(dev);
 
 	return 0;
 }
 
-static int dm1105dvb_stop_feed(struct dvb_demux_feed *f)
+static int dm1105_stop_feed(struct dvb_demux_feed *f)
 {
-	struct dm1105dvb *dm1105dvb = feed_to_dm1105dvb(f);
+	struct dm1105_dev *dev = feed_to_dm1105_dev(f);
 
-	if (--dm1105dvb->full_ts_users == 0)
-		dm1105dvb_disable_irqs(dm1105dvb);
+	if (--dev->full_ts_users == 0)
+		dm1105_disable_irqs(dev);
 
 	return 0;
 }
@@ -517,68 +537,64 @@ static void dm1105_emit_key(struct work_struct *work)
 /* work handler */
 static void dm1105_dmx_buffer(struct work_struct *work)
 {
-	struct dm1105dvb *dm1105dvb =
-				container_of(work, struct dm1105dvb, work);
+	struct dm1105_dev *dev = container_of(work, struct dm1105_dev, work);
 	unsigned int nbpackets;
-	u32 oldwrp = dm1105dvb->wrp;
-	u32 nextwrp = dm1105dvb->nextwrp;
+	u32 oldwrp = dev->wrp;
+	u32 nextwrp = dev->nextwrp;
 
-	if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
-			(dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
-			(dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
-		dm1105dvb->PacketErrorCount++;
+	if (!((dev->ts_buf[oldwrp] == 0x47) &&
+			(dev->ts_buf[oldwrp + 188] == 0x47) &&
+			(dev->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+		dev->PacketErrorCount++;
 		/* bad packet found */
-		if ((dm1105dvb->PacketErrorCount >= 2) &&
-				(dm1105dvb->dmarst == 0)) {
-			outb(1, dm_io_mem(DM1105_RST));
-			dm1105dvb->wrp = 0;
-			dm1105dvb->PacketErrorCount = 0;
-			dm1105dvb->dmarst = 0;
+		if ((dev->PacketErrorCount >= 2) &&
+				(dev->dmarst == 0)) {
+			dm_writeb(DM1105_RST, 1);
+			dev->wrp = 0;
+			dev->PacketErrorCount = 0;
+			dev->dmarst = 0;
 			return;
 		}
 	}
 
 	if (nextwrp < oldwrp) {
-		memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size,
-						dm1105dvb->ts_buf, nextwrp);
-		nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188;
+		memcpy(dev->ts_buf + dev->buffer_size, dev->ts_buf, nextwrp);
+		nbpackets = ((dev->buffer_size - oldwrp) + nextwrp) / 188;
 	} else
 		nbpackets = (nextwrp - oldwrp) / 188;
 
-	dm1105dvb->wrp = nextwrp;
-	dvb_dmx_swfilter_packets(&dm1105dvb->demux,
-					&dm1105dvb->ts_buf[oldwrp], nbpackets);
+	dev->wrp = nextwrp;
+	dvb_dmx_swfilter_packets(&dev->demux, &dev->ts_buf[oldwrp], nbpackets);
 }
 
-static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
+static irqreturn_t dm1105_irq(int irq, void *dev_id)
 {
-	struct dm1105dvb *dm1105dvb = dev_id;
+	struct dm1105_dev *dev = dev_id;
 
 	/* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
-	unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
-	outb(intsts, dm_io_mem(DM1105_INTSTS));
+	unsigned int intsts = dm_readb(DM1105_INTSTS);
+	dm_writeb(DM1105_INTSTS, intsts);
 
 	switch (intsts) {
 	case INTSTS_TSIRQ:
 	case (INTSTS_TSIRQ | INTSTS_IR):
-		dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
-					inl(dm_io_mem(DM1105_STADR));
-		queue_work(dm1105dvb->wq, &dm1105dvb->work);
+		dev->nextwrp = dm_readl(DM1105_WRP) - dm_readl(DM1105_STADR);
+		queue_work(dev->wq, &dev->work);
 		break;
 	case INTSTS_IR:
-		dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
-		schedule_work(&dm1105dvb->ir.work);
+		dev->ir.ir_command = dm_readl(DM1105_IRCODE);
+		schedule_work(&dev->ir.work);
 		break;
 	}
 
 	return IRQ_HANDLED;
 }
 
-int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
+int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
 {
 	struct input_dev *input_dev;
 	struct ir_scancode_table *ir_codes = &ir_codes_dm1105_nec_table;
-	int ir_type = IR_TYPE_OTHER;
+	u64 ir_type = IR_TYPE_OTHER;
 	int err = -ENOMEM;
 
 	input_dev = input_allocate_device();
@@ -611,51 +627,51 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
 
 	INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
 
-	err = ir_input_register(input_dev, ir_codes);
+	err = ir_input_register(input_dev, ir_codes, NULL);
 
 	return err;
 }
 
-void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
+void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
 {
 	ir_input_unregister(dm1105->ir.input_dev);
 }
 
-static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
+static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
 {
-	dm1105dvb_disable_irqs(dm1105dvb);
+	dm1105_disable_irqs(dev);
 
-	outb(0, dm_io_mem(DM1105_HOST_CTR));
+	dm_writeb(DM1105_HOST_CTR, 0);
 
 	/*DATALEN 188,*/
-	outb(188, dm_io_mem(DM1105_DTALENTH));
+	dm_writeb(DM1105_DTALENTH, 188);
 	/*TS_STRT TS_VALP MSBFIRST TS_MODE ALPAS TSPES*/
-	outw(0xc10a, dm_io_mem(DM1105_TSCTR));
+	dm_writew(DM1105_TSCTR, 0xc10a);
 
 	/* map DMA and set address */
-	dm1105dvb_dma_map(dm1105dvb);
-	dm1105dvb_set_dma_addr(dm1105dvb);
+	dm1105_dma_map(dev);
+	dm1105_set_dma_addr(dev);
 	/* big buffer */
-	outl(5*DM1105_DMA_BYTES, dm_io_mem(DM1105_RLEN));
-	outb(47, dm_io_mem(DM1105_INTCNT));
+	dm_writel(DM1105_RLEN, 5 * DM1105_DMA_BYTES);
+	dm_writeb(DM1105_INTCNT, 47);
 
 	/* IR NEC mode enable */
-	outb((DM1105_IR_EN | DM1105_SYS_CHK), dm_io_mem(DM1105_IRCTR));
-	outb(0, dm_io_mem(DM1105_IRMODE));
-	outw(0, dm_io_mem(DM1105_SYSTEMCODE));
+	dm_writeb(DM1105_IRCTR, (DM1105_IR_EN | DM1105_SYS_CHK));
+	dm_writeb(DM1105_IRMODE, 0);
+	dm_writew(DM1105_SYSTEMCODE, 0);
 
 	return 0;
 }
 
-static void dm1105dvb_hw_exit(struct dm1105dvb *dm1105dvb)
+static void dm1105_hw_exit(struct dm1105_dev *dev)
 {
-	dm1105dvb_disable_irqs(dm1105dvb);
+	dm1105_disable_irqs(dev);
 
 	/* IR disable */
-	outb(0, dm_io_mem(DM1105_IRCTR));
-	outb(INTMAK_NONEMASK, dm_io_mem(DM1105_INTMAK));
+	dm_writeb(DM1105_IRCTR, 0);
+	dm_writeb(DM1105_INTMAK, INTMAK_NONEMASK);
 
-	dm1105dvb_dma_unmap(dm1105dvb);
+	dm1105_dma_unmap(dev);
 }
 
 static struct stv0299_config sharp_z0194a_config = {
@@ -685,70 +701,79 @@ static struct cx24116_config serit_sp2633_config = {
 	.demod_address = 0x55,
 };
 
-static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
+static struct ds3000_config dvbworld_ds3000_config = {
+	.demod_address = 0x68,
+};
+
+static int __devinit frontend_init(struct dm1105_dev *dev)
 {
 	int ret;
 
-	switch (dm1105dvb->boardnr) {
+	switch (dev->boardnr) {
 	case DM1105_BOARD_DVBWORLD_2004:
-		dm1105dvb->fe = dvb_attach(
+		dev->fe = dvb_attach(
 			cx24116_attach, &serit_sp2633_config,
-			&dm1105dvb->i2c_adap);
-		if (dm1105dvb->fe)
-			dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
+			&dev->i2c_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			break;
+		}
+
+		dev->fe = dvb_attach(
+			ds3000_attach, &dvbworld_ds3000_config,
+			&dev->i2c_adap);
+		if (dev->fe)
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
 
 		break;
 	case DM1105_BOARD_DVBWORLD_2002:
 	case DM1105_BOARD_AXESS_DM05:
 	default:
-		dm1105dvb->fe = dvb_attach(
+		dev->fe = dvb_attach(
 			stv0299_attach, &sharp_z0194a_config,
-			&dm1105dvb->i2c_adap);
-		if (dm1105dvb->fe) {
-			dm1105dvb->fe->ops.set_voltage =
-							dm1105dvb_set_voltage;
-			dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
-					&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+			&dev->i2c_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			dvb_attach(dvb_pll_attach, dev->fe, 0x60,
+					&dev->i2c_adap, DVB_PLL_OPERA1);
 			break;
 		}
 
-		dm1105dvb->fe = dvb_attach(
+		dev->fe = dvb_attach(
 			stv0288_attach, &earda_config,
-			&dm1105dvb->i2c_adap);
-		if (dm1105dvb->fe) {
-			dm1105dvb->fe->ops.set_voltage =
-						dm1105dvb_set_voltage;
-			dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
-					&dm1105dvb->i2c_adap);
+			&dev->i2c_adap);
+		if (dev->fe) {
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
+			dvb_attach(stb6000_attach, dev->fe, 0x61,
+					&dev->i2c_adap);
 			break;
 		}
 
-		dm1105dvb->fe = dvb_attach(
+		dev->fe = dvb_attach(
 			si21xx_attach, &serit_config,
-			&dm1105dvb->i2c_adap);
-		if (dm1105dvb->fe)
-			dm1105dvb->fe->ops.set_voltage =
-						dm1105dvb_set_voltage;
+			&dev->i2c_adap);
+		if (dev->fe)
+			dev->fe->ops.set_voltage = dm1105_set_voltage;
 
 	}
 
-	if (!dm1105dvb->fe) {
-		dev_err(&dm1105dvb->pdev->dev, "could not attach frontend\n");
+	if (!dev->fe) {
+		dev_err(&dev->pdev->dev, "could not attach frontend\n");
 		return -ENODEV;
 	}
 
-	ret = dvb_register_frontend(&dm1105dvb->dvb_adapter, dm1105dvb->fe);
+	ret = dvb_register_frontend(&dev->dvb_adapter, dev->fe);
 	if (ret < 0) {
-		if (dm1105dvb->fe->ops.release)
-			dm1105dvb->fe->ops.release(dm1105dvb->fe);
-		dm1105dvb->fe = NULL;
+		if (dev->fe->ops.release)
+			dev->fe->ops.release(dev->fe);
+		dev->fe = NULL;
 		return ret;
 	}
 
 	return 0;
 }
 
-static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
+static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
 {
 	static u8 command[1] = { 0x28 };
 
@@ -766,47 +791,47 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
 		},
 	};
 
-	dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
-	dev_info(&dm1105dvb->pdev->dev, "MAC %pM\n", mac);
+	dm1105_i2c_xfer(&dev->i2c_adap, msg , 2);
+	dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
 }
 
 static int __devinit dm1105_probe(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
-	struct dm1105dvb *dm1105dvb;
+	struct dm1105_dev *dev;
 	struct dvb_adapter *dvb_adapter;
 	struct dvb_demux *dvbdemux;
 	struct dmx_demux *dmx;
 	int ret = -ENOMEM;
 	int i;
 
-	dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
-	if (!dm1105dvb)
+	dev = kzalloc(sizeof(struct dm1105_dev), GFP_KERNEL);
+	if (!dev)
 		return -ENOMEM;
 
 	/* board config */
-	dm1105dvb->nr = dm1105_devcount;
-	dm1105dvb->boardnr = UNSET;
-	if (card[dm1105dvb->nr] < ARRAY_SIZE(dm1105_boards))
-		dm1105dvb->boardnr = card[dm1105dvb->nr];
-	for (i = 0; UNSET == dm1105dvb->boardnr &&
+	dev->nr = dm1105_devcount;
+	dev->boardnr = UNSET;
+	if (card[dev->nr] < ARRAY_SIZE(dm1105_boards))
+		dev->boardnr = card[dev->nr];
+	for (i = 0; UNSET == dev->boardnr &&
 				i < ARRAY_SIZE(dm1105_subids); i++)
 		if (pdev->subsystem_vendor ==
 			dm1105_subids[i].subvendor &&
 				pdev->subsystem_device ==
 					dm1105_subids[i].subdevice)
-			dm1105dvb->boardnr = dm1105_subids[i].card;
+			dev->boardnr = dm1105_subids[i].card;
 
-	if (UNSET == dm1105dvb->boardnr) {
-		dm1105dvb->boardnr = DM1105_BOARD_UNKNOWN;
+	if (UNSET == dev->boardnr) {
+		dev->boardnr = DM1105_BOARD_UNKNOWN;
 		dm1105_card_list(pdev);
 	}
 
 	dm1105_devcount++;
-	dm1105dvb->pdev = pdev;
-	dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
-	dm1105dvb->PacketErrorCount = 0;
-	dm1105dvb->dmarst = 0;
+	dev->pdev = pdev;
+	dev->buffer_size = 5 * DM1105_DMA_BYTES;
+	dev->PacketErrorCount = 0;
+	dev->dmarst = 0;
 
 	ret = pci_enable_device(pdev);
 	if (ret < 0)
@@ -822,47 +847,47 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
 	if (ret < 0)
 		goto err_pci_disable_device;
 
-	dm1105dvb->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
-	if (!dm1105dvb->io_mem) {
+	dev->io_mem = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!dev->io_mem) {
 		ret = -EIO;
 		goto err_pci_release_regions;
 	}
 
-	spin_lock_init(&dm1105dvb->lock);
-	pci_set_drvdata(pdev, dm1105dvb);
+	spin_lock_init(&dev->lock);
+	pci_set_drvdata(pdev, dev);
 
-	ret = dm1105dvb_hw_init(dm1105dvb);
+	ret = dm1105_hw_init(dev);
 	if (ret < 0)
 		goto err_pci_iounmap;
 
 	/* i2c */
-	i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
-	strcpy(dm1105dvb->i2c_adap.name, DRIVER_NAME);
-	dm1105dvb->i2c_adap.owner = THIS_MODULE;
-	dm1105dvb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-	dm1105dvb->i2c_adap.dev.parent = &pdev->dev;
-	dm1105dvb->i2c_adap.algo = &dm1105_algo;
-	dm1105dvb->i2c_adap.algo_data = dm1105dvb;
-	ret = i2c_add_adapter(&dm1105dvb->i2c_adap);
+	i2c_set_adapdata(&dev->i2c_adap, dev);
+	strcpy(dev->i2c_adap.name, DRIVER_NAME);
+	dev->i2c_adap.owner = THIS_MODULE;
+	dev->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+	dev->i2c_adap.dev.parent = &pdev->dev;
+	dev->i2c_adap.algo = &dm1105_algo;
+	dev->i2c_adap.algo_data = dev;
+	ret = i2c_add_adapter(&dev->i2c_adap);
 
 	if (ret < 0)
-		goto err_dm1105dvb_hw_exit;
+		goto err_dm1105_hw_exit;
 
 	/* dvb */
-	ret = dvb_register_adapter(&dm1105dvb->dvb_adapter, DRIVER_NAME,
+	ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
 					THIS_MODULE, &pdev->dev, adapter_nr);
 	if (ret < 0)
 		goto err_i2c_del_adapter;
 
-	dvb_adapter = &dm1105dvb->dvb_adapter;
+	dvb_adapter = &dev->dvb_adapter;
 
-	dm1105dvb_read_mac(dm1105dvb, dvb_adapter->proposed_mac);
+	dm1105_read_mac(dev, dvb_adapter->proposed_mac);
 
-	dvbdemux = &dm1105dvb->demux;
+	dvbdemux = &dev->demux;
 	dvbdemux->filternum = 256;
 	dvbdemux->feednum = 256;
-	dvbdemux->start_feed = dm1105dvb_start_feed;
-	dvbdemux->stop_feed = dm1105dvb_stop_feed;
+	dvbdemux->start_feed = dm1105_start_feed;
+	dvbdemux->stop_feed = dm1105_stop_feed;
 	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
 			DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
 	ret = dvb_dmx_init(dvbdemux);
@@ -870,113 +895,113 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
 		goto err_dvb_unregister_adapter;
 
 	dmx = &dvbdemux->dmx;
-	dm1105dvb->dmxdev.filternum = 256;
-	dm1105dvb->dmxdev.demux = dmx;
-	dm1105dvb->dmxdev.capabilities = 0;
+	dev->dmxdev.filternum = 256;
+	dev->dmxdev.demux = dmx;
+	dev->dmxdev.capabilities = 0;
 
-	ret = dvb_dmxdev_init(&dm1105dvb->dmxdev, dvb_adapter);
+	ret = dvb_dmxdev_init(&dev->dmxdev, dvb_adapter);
 	if (ret < 0)
 		goto err_dvb_dmx_release;
 
-	dm1105dvb->hw_frontend.source = DMX_FRONTEND_0;
+	dev->hw_frontend.source = DMX_FRONTEND_0;
 
-	ret = dmx->add_frontend(dmx, &dm1105dvb->hw_frontend);
+	ret = dmx->add_frontend(dmx, &dev->hw_frontend);
 	if (ret < 0)
 		goto err_dvb_dmxdev_release;
 
-	dm1105dvb->mem_frontend.source = DMX_MEMORY_FE;
+	dev->mem_frontend.source = DMX_MEMORY_FE;
 
-	ret = dmx->add_frontend(dmx, &dm1105dvb->mem_frontend);
+	ret = dmx->add_frontend(dmx, &dev->mem_frontend);
 	if (ret < 0)
 		goto err_remove_hw_frontend;
 
-	ret = dmx->connect_frontend(dmx, &dm1105dvb->hw_frontend);
+	ret = dmx->connect_frontend(dmx, &dev->hw_frontend);
 	if (ret < 0)
 		goto err_remove_mem_frontend;
 
-	ret = frontend_init(dm1105dvb);
+	ret = frontend_init(dev);
 	if (ret < 0)
 		goto err_disconnect_frontend;
 
-	dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
-	dm1105_ir_init(dm1105dvb);
+	dvb_net_init(dvb_adapter, &dev->dvbnet, dmx);
+	dm1105_ir_init(dev);
 
-	INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
-	sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
-	dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
-	if (!dm1105dvb->wq)
+	INIT_WORK(&dev->work, dm1105_dmx_buffer);
+	sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
+	dev->wq = create_singlethread_workqueue(dev->wqn);
+	if (!dev->wq)
 		goto err_dvb_net;
 
-	ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
-						DRIVER_NAME, dm1105dvb);
+	ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED,
+						DRIVER_NAME, dev);
 	if (ret < 0)
 		goto err_workqueue;
 
 	return 0;
 
 err_workqueue:
-	destroy_workqueue(dm1105dvb->wq);
+	destroy_workqueue(dev->wq);
 err_dvb_net:
-	dvb_net_release(&dm1105dvb->dvbnet);
+	dvb_net_release(&dev->dvbnet);
 err_disconnect_frontend:
 	dmx->disconnect_frontend(dmx);
 err_remove_mem_frontend:
-	dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
+	dmx->remove_frontend(dmx, &dev->mem_frontend);
 err_remove_hw_frontend:
-	dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
+	dmx->remove_frontend(dmx, &dev->hw_frontend);
 err_dvb_dmxdev_release:
-	dvb_dmxdev_release(&dm1105dvb->dmxdev);
+	dvb_dmxdev_release(&dev->dmxdev);
 err_dvb_dmx_release:
 	dvb_dmx_release(dvbdemux);
 err_dvb_unregister_adapter:
 	dvb_unregister_adapter(dvb_adapter);
 err_i2c_del_adapter:
-	i2c_del_adapter(&dm1105dvb->i2c_adap);
-err_dm1105dvb_hw_exit:
-	dm1105dvb_hw_exit(dm1105dvb);
+	i2c_del_adapter(&dev->i2c_adap);
+err_dm1105_hw_exit:
+	dm1105_hw_exit(dev);
 err_pci_iounmap:
-	pci_iounmap(pdev, dm1105dvb->io_mem);
+	pci_iounmap(pdev, dev->io_mem);
 err_pci_release_regions:
 	pci_release_regions(pdev);
 err_pci_disable_device:
 	pci_disable_device(pdev);
 err_kfree:
 	pci_set_drvdata(pdev, NULL);
-	kfree(dm1105dvb);
+	kfree(dev);
 	return ret;
 }
 
 static void __devexit dm1105_remove(struct pci_dev *pdev)
 {
-	struct dm1105dvb *dm1105dvb = pci_get_drvdata(pdev);
-	struct dvb_adapter *dvb_adapter = &dm1105dvb->dvb_adapter;
-	struct dvb_demux *dvbdemux = &dm1105dvb->demux;
+	struct dm1105_dev *dev = pci_get_drvdata(pdev);
+	struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
+	struct dvb_demux *dvbdemux = &dev->demux;
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 
-	dm1105_ir_exit(dm1105dvb);
+	dm1105_ir_exit(dev);
 	dmx->close(dmx);
-	dvb_net_release(&dm1105dvb->dvbnet);
-	if (dm1105dvb->fe)
-		dvb_unregister_frontend(dm1105dvb->fe);
+	dvb_net_release(&dev->dvbnet);
+	if (dev->fe)
+		dvb_unregister_frontend(dev->fe);
 
 	dmx->disconnect_frontend(dmx);
-	dmx->remove_frontend(dmx, &dm1105dvb->mem_frontend);
-	dmx->remove_frontend(dmx, &dm1105dvb->hw_frontend);
-	dvb_dmxdev_release(&dm1105dvb->dmxdev);
+	dmx->remove_frontend(dmx, &dev->mem_frontend);
+	dmx->remove_frontend(dmx, &dev->hw_frontend);
+	dvb_dmxdev_release(&dev->dmxdev);
 	dvb_dmx_release(dvbdemux);
 	dvb_unregister_adapter(dvb_adapter);
-	if (&dm1105dvb->i2c_adap)
-		i2c_del_adapter(&dm1105dvb->i2c_adap);
+	if (&dev->i2c_adap)
+		i2c_del_adapter(&dev->i2c_adap);
 
-	dm1105dvb_hw_exit(dm1105dvb);
+	dm1105_hw_exit(dev);
 	synchronize_irq(pdev->irq);
-	free_irq(pdev->irq, dm1105dvb);
-	pci_iounmap(pdev, dm1105dvb->io_mem);
+	free_irq(pdev->irq, dev);
+	pci_iounmap(pdev, dev->io_mem);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	dm1105_devcount--;
-	kfree(dm1105dvb);
+	kfree(dev);
 }
 
 static struct pci_device_id dm1105_id_table[] __devinitdata = {
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 07461222a7f5..55ea260572bf 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1199,8 +1199,6 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
 {
 	int r = 0;
 
-	dtv_property_dump(tvp);
-
 	/* Allow the frontend to validate incoming properties */
 	if (fe->ops.get_property)
 		r = fe->ops.get_property(fe, tvp);
@@ -1323,6 +1321,8 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
 		r = -1;
 	}
 
+	dtv_property_dump(tvp);
+
 	return r;
 }
 
@@ -1488,7 +1488,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int err = -EOPNOTSUPP;
 
-	dprintk ("%s\n", __func__);
+	dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
 
 	if (fepriv->exit)
 		return -ENODEV;
@@ -1536,8 +1536,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
 		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
 			return -EINVAL;
 
-		tvp = (struct dtv_property *) kmalloc(tvps->num *
-			sizeof(struct dtv_property), GFP_KERNEL);
+		tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
 		if (!tvp) {
 			err = -ENOMEM;
 			goto out;
@@ -1569,8 +1568,7 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
 		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
 			return -EINVAL;
 
-		tvp = (struct dtv_property *) kmalloc(tvps->num *
-			sizeof(struct dtv_property), GFP_KERNEL);
+		tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
 		if (!tvp) {
 			err = -ENOMEM;
 			goto out;
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 584bbd194dc8..a5712cd7c65f 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -89,6 +89,7 @@ void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
 	rbuf->pread = rbuf->pwrite;
 	rbuf->error = 0;
 }
+EXPORT_SYMBOL(dvb_ringbuffer_flush);
 
 void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
 {
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 465295b1d14b..e5f91f16ffa4 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -336,3 +336,11 @@ config DVB_USB_EC168
 	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
 	help
 	  Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
+
+config DVB_USB_AZ6027
+	tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
+	depends on DVB_USB
+	select DVB_STB0899 if !DVB_FE_CUSTOMISE
+	select DVB_STB6100 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the AZ6027 device
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 72c92cb69a22..1a192453b0e7 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -85,6 +85,9 @@ obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
 dvb-usb-ec168-objs = ec168.o
 obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
 
+dvb-usb-az6027-objs = az6027.o
+obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 # due to tuner-xc3028
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 8b60a601fb82..d7975383d31b 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -21,6 +21,8 @@
  *
  */
 
+#include <linux/hash.h>
+
 #include "af9015.h"
 #include "af9013.h"
 #include "mt2060.h"
@@ -553,26 +555,45 @@ exit:
 	return ret;
 }
 
-/* dump eeprom */
-static int af9015_eeprom_dump(struct dvb_usb_device *d)
+/* hash (and dump) eeprom */
+static int af9015_eeprom_hash(struct usb_device *udev)
 {
-	u8 reg, val;
+	static const unsigned int eeprom_size = 256;
+	unsigned int reg;
+	int ret;
+	u8 val, *eeprom;
+	struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
 
-	for (reg = 0; ; reg++) {
-		if (reg % 16 == 0) {
-			if (reg)
-				deb_info(KERN_CONT "\n");
-			deb_info(KERN_DEBUG "%02x:", reg);
-		}
-		if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
-			deb_info(KERN_CONT " %02x", val);
-		else
-			deb_info(KERN_CONT " --");
-		if (reg == 0xff)
-			break;
+	eeprom = kmalloc(eeprom_size, GFP_KERNEL);
+	if (eeprom == NULL)
+		return -ENOMEM;
+
+	for (reg = 0; reg < eeprom_size; reg++) {
+		req.addr = reg;
+		ret = af9015_rw_udev(udev, &req);
+		if (ret)
+			goto free;
+		eeprom[reg] = val;
 	}
-	deb_info(KERN_CONT "\n");
-	return 0;
+
+	if (dvb_usb_af9015_debug & 0x01)
+		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
+				eeprom_size);
+
+	BUG_ON(eeprom_size % 4);
+
+	af9015_config.eeprom_sum = 0;
+	for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
+		af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32;
+		af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
+	}
+
+	deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum);
+
+	ret = 0;
+free:
+	kfree(eeprom);
+	return ret;
 }
 
 static int af9015_download_ir_table(struct dvb_usb_device *d)
@@ -711,12 +732,132 @@ error:
 	return ret;
 }
 
+struct af9015_setup {
+	unsigned int id;
+	struct dvb_usb_rc_key *rc_key_map;
+	unsigned int rc_key_map_size;
+	u8 *ir_table;
+	unsigned int ir_table_size;
+};
+
+static const struct af9015_setup *af9015_setup_match(unsigned int id,
+		const struct af9015_setup *table)
+{
+	for (; table->rc_key_map; table++)
+		if (table->id == id)
+			return table;
+	return NULL;
+}
+
+static const struct af9015_setup af9015_setup_modparam[] = {
+	{ AF9015_REMOTE_A_LINK_DTU_M,
+		af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
+		af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
+	{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+		af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
+		af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
+	{ AF9015_REMOTE_MYGICTV_U718,
+		af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
+		af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
+	{ AF9015_REMOTE_DIGITTRADE_DVB_T,
+		af9015_rc_keys_digittrade, ARRAY_SIZE(af9015_rc_keys_digittrade),
+		af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
+	{ AF9015_REMOTE_AVERMEDIA_KS,
+		af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
+		af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
+	{ }
+};
+
+/* don't add new entries here anymore, use hashes instead */
+static const struct af9015_setup af9015_setup_usbids[] = {
+	{ USB_VID_LEADTEK,
+		af9015_rc_keys_leadtek, ARRAY_SIZE(af9015_rc_keys_leadtek),
+		af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
+	{ USB_VID_VISIONPLUS,
+		af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
+		af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
+	{ USB_VID_KWORLD_2, /* TODO: use correct rc keys */
+		af9015_rc_keys_twinhan, ARRAY_SIZE(af9015_rc_keys_twinhan),
+		af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
+	{ USB_VID_AVERMEDIA,
+		af9015_rc_keys_avermedia, ARRAY_SIZE(af9015_rc_keys_avermedia),
+		af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
+	{ USB_VID_MSI_2,
+		af9015_rc_keys_msi_digivox_iii, ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii),
+		af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
+	{ }
+};
+
+static const struct af9015_setup af9015_setup_hashes[] = {
+	{ 0xb8feb708,
+		af9015_rc_keys_msi, ARRAY_SIZE(af9015_rc_keys_msi),
+		af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
+	{ 0xa3703d00,
+		af9015_rc_keys_a_link, ARRAY_SIZE(af9015_rc_keys_a_link),
+		af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
+	{ 0x9b7dc64e,
+		af9015_rc_keys_mygictv, ARRAY_SIZE(af9015_rc_keys_mygictv),
+		af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
+	{ }
+};
+
+static void af9015_set_remote_config(struct usb_device *udev,
+		struct dvb_usb_device_properties *props)
+{
+	const struct af9015_setup *table = NULL;
+
+	if (dvb_usb_af9015_remote) {
+		/* load remote defined as module param */
+		table = af9015_setup_match(dvb_usb_af9015_remote,
+				af9015_setup_modparam);
+	} else {
+		u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
+
+		table = af9015_setup_match(af9015_config.eeprom_sum,
+				af9015_setup_hashes);
+
+		if (!table && vendor == USB_VID_AFATECH) {
+			/* Check USB manufacturer and product strings and try
+			   to determine correct remote in case of chip vendor
+			   reference IDs are used.
+			   DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
+			 */
+			char manufacturer[10];
+			memset(manufacturer, 0, sizeof(manufacturer));
+			usb_string(udev, udev->descriptor.iManufacturer,
+				manufacturer, sizeof(manufacturer));
+			if (!strcmp("MSI", manufacturer)) {
+				/* iManufacturer 1 MSI
+				   iProduct      2 MSI K-VOX */
+				table = af9015_setup_match(
+					AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+					af9015_setup_modparam);
+			} else if (udev->descriptor.idProduct ==
+				cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
+				table = &(const struct af9015_setup){ 0,
+					af9015_rc_keys_trekstor,
+					ARRAY_SIZE(af9015_rc_keys_trekstor),
+					af9015_ir_table_trekstor,
+					ARRAY_SIZE(af9015_ir_table_trekstor)
+				};
+			}
+		} else if (!table)
+			table = af9015_setup_match(vendor, af9015_setup_usbids);
+	}
+
+	if (table) {
+		props->rc_key_map = table->rc_key_map;
+		props->rc_key_map_size = table->rc_key_map_size;
+		af9015_config.ir_table = table->ir_table;
+		af9015_config.ir_table_size = table->ir_table_size;
+	}
+}
+
 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;
@@ -728,158 +869,18 @@ static int af9015_read_config(struct usb_device *udev)
 	}
 	if (ret)
 		goto error;
+
+	ret = af9015_eeprom_hash(udev);
+	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) {
 			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;
-			case AF9015_REMOTE_DIGITTRADE_DVB_T:
-				af9015_properties[i].rc_key_map =
-				  af9015_rc_keys_digittrade;
-				af9015_properties[i].rc_key_map_size =
-				  ARRAY_SIZE(af9015_rc_keys_digittrade);
-				af9015_config.ir_table =
-				  af9015_ir_table_digittrade;
-				af9015_config.ir_table_size =
-				  ARRAY_SIZE(af9015_ir_table_digittrade);
-				break;
-			case AF9015_REMOTE_AVERMEDIA_KS:
-				af9015_properties[i].rc_key_map =
-				  af9015_rc_keys_avermedia;
-				af9015_properties[i].rc_key_map_size =
-				  ARRAY_SIZE(af9015_rc_keys_avermedia);
-				af9015_config.ir_table =
-				  af9015_ir_table_avermedia_ks;
-				af9015_config.ir_table_size =
-				  ARRAY_SIZE(af9015_ir_table_avermedia_ks);
-				break;
-			}
-		} else {
-			switch (le16_to_cpu(udev->descriptor.idVendor)) {
-			case 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 USB_VID_VISIONPLUS:
-				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 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 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);
-				} else if (udev->descriptor.idProduct ==
-					cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
-					af9015_properties[i].rc_key_map =
-					  af9015_rc_keys_trekstor;
-					af9015_properties[i].rc_key_map_size =
-					  ARRAY_SIZE(af9015_rc_keys_trekstor);
-					af9015_config.ir_table =
-					  af9015_ir_table_trekstor;
-					af9015_config.ir_table_size =
-					  ARRAY_SIZE(af9015_ir_table_trekstor);
-				}
-				break;
-			case USB_VID_AVERMEDIA:
-				af9015_properties[i].rc_key_map =
-				  af9015_rc_keys_avermedia;
-				af9015_properties[i].rc_key_map_size =
-				  ARRAY_SIZE(af9015_rc_keys_avermedia);
-				af9015_config.ir_table =
-				  af9015_ir_table_avermedia;
-				af9015_config.ir_table_size =
-				  ARRAY_SIZE(af9015_ir_table_avermedia);
-				break;
-			case USB_VID_MSI_2:
-				af9015_properties[i].rc_key_map =
-				  af9015_rc_keys_msi_digivox_iii;
-				af9015_properties[i].rc_key_map_size =
-				  ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii);
-				af9015_config.ir_table =
-				  af9015_ir_table_msi_digivox_iii;
-				af9015_config.ir_table_size =
-				  ARRAY_SIZE(af9015_ir_table_msi_digivox_iii);
-				break;
-			}
-		}
+		} else
+			af9015_set_remote_config(udev, &af9015_properties[i]);
 	}
 
 	/* TS mode - one or two receivers */
@@ -1001,6 +1002,9 @@ static int af9015_read_config(struct usb_device *udev)
 			af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
 			af9015_af9013_config[i].rf_spec_inv = 1;
 			break;
+		case AF9013_TUNER_TDA18218:
+			warn("tuner NXP TDA18218 not supported yet");
+			return -ENODEV;
 		default:
 			warn("tuner id:%d not supported, please report!", val);
 			return -ENODEV;
@@ -1125,11 +1129,6 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *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;
@@ -1295,6 +1294,8 @@ static struct usb_device_id af9015_usb_table[] = {
 /* 25 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U_2)},
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_PC160_T)},
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_SVEON_STV20)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_TINYTWIN_2)},
+	{USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV2000DS)},
 	{0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1381,7 +1382,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 			},
 			{
 				.name = "DigitalNow TinyTwin DVB-T Receiver",
-				.cold_ids = {&af9015_usb_table[5], NULL},
+				.cold_ids = {&af9015_usb_table[5],
+					     &af9015_usb_table[28], NULL},
 				.warm_ids = {NULL},
 			},
 			{
@@ -1566,7 +1568,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
 		.i2c_algo = &af9015_i2c_algo,
 
-		.num_device_descs = 6, /* max 9 */
+		.num_device_descs = 7, /* max 9 */
 		.devices = {
 			{
 				.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1600,6 +1602,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 				.cold_ids = {&af9015_usb_table[27], NULL},
 				.warm_ids = {NULL},
 			},
+			{
+				.name = "Leadtek WinFast DTV2000DS",
+				.cold_ids = {&af9015_usb_table[29], NULL},
+				.warm_ids = {NULL},
+			},
 		}
 	},
 };
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index 931c8515830d..ef36b1831490 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -107,6 +107,7 @@ struct af9015_config {
 	u16 mt2060_if1[2];
 	u16 firmware_size;
 	u16 firmware_checksum;
+	u32 eeprom_sum;
 	u8  *ir_table;
 	u16 ir_table_size;
 };
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
new file mode 100644
index 000000000000..d7290b2c0913
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/az6027.c
@@ -0,0 +1,1151 @@
+/* DVB USB compliant Linux driver for the AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)
+ * receiver.
+ *
+ * Copyright (C) 2009 Adams.Xu <adams.xu@azwave.com.cn>
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the Free
+ *	Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "az6027.h"
+
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+
+#include "stb6100.h"
+#include "stb6100_cfg.h"
+#include "dvb_ca_en50221.h"
+
+int dvb_usb_az6027_debug;
+module_param_named(debug, dvb_usb_az6027_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct az6027_device_state {
+	struct dvb_ca_en50221 ca;
+	struct mutex ca_mutex;
+	u8 power_state;
+};
+
+static const struct stb0899_s1_reg az6027_stb0899_s1_init_1[] = {
+
+	/* 0x0000000b, SYSREG */
+	{ STB0899_DEV_ID		, 0x30 },
+	{ STB0899_DISCNTRL1		, 0x32 },
+	{ STB0899_DISCNTRL2     	, 0x80 },
+	{ STB0899_DISRX_ST0     	, 0x04 },
+	{ STB0899_DISRX_ST1     	, 0x00 },
+	{ STB0899_DISPARITY     	, 0x00 },
+	{ STB0899_DISFIFO       	, 0x00 },
+	{ STB0899_DISSTATUS		, 0x20 },
+	{ STB0899_DISF22        	, 0x99 },
+	{ STB0899_DISF22RX      	, 0xa8 },
+	/* SYSREG ? */
+	{ STB0899_ACRPRESC      	, 0x11 },
+	{ STB0899_ACRDIV1       	, 0x0a },
+	{ STB0899_ACRDIV2       	, 0x05 },
+	{ STB0899_DACR1         	, 0x00 },
+	{ STB0899_DACR2         	, 0x00 },
+	{ STB0899_OUTCFG        	, 0x00 },
+	{ STB0899_MODECFG       	, 0x00 },
+	{ STB0899_IRQSTATUS_3		, 0xfe },
+	{ STB0899_IRQSTATUS_2		, 0x03 },
+	{ STB0899_IRQSTATUS_1		, 0x7c },
+	{ STB0899_IRQSTATUS_0		, 0xf4 },
+	{ STB0899_IRQMSK_3      	, 0xf3 },
+	{ STB0899_IRQMSK_2      	, 0xfc },
+	{ STB0899_IRQMSK_1      	, 0xff },
+	{ STB0899_IRQMSK_0		, 0xff },
+	{ STB0899_IRQCFG		, 0x00 },
+	{ STB0899_I2CCFG        	, 0x88 },
+	{ STB0899_I2CRPT        	, 0x58 },
+	{ STB0899_IOPVALUE5		, 0x00 },
+	{ STB0899_IOPVALUE4		, 0x33 },
+	{ STB0899_IOPVALUE3		, 0x6d },
+	{ STB0899_IOPVALUE2		, 0x90 },
+	{ STB0899_IOPVALUE1		, 0x60 },
+	{ STB0899_IOPVALUE0		, 0x00 },
+	{ STB0899_GPIO00CFG     	, 0x82 },
+	{ STB0899_GPIO01CFG     	, 0x82 },
+	{ STB0899_GPIO02CFG     	, 0x82 },
+	{ STB0899_GPIO03CFG     	, 0x82 },
+	{ STB0899_GPIO04CFG     	, 0x82 },
+	{ STB0899_GPIO05CFG     	, 0x82 },
+	{ STB0899_GPIO06CFG     	, 0x82 },
+	{ STB0899_GPIO07CFG     	, 0x82 },
+	{ STB0899_GPIO08CFG     	, 0x82 },
+	{ STB0899_GPIO09CFG     	, 0x82 },
+	{ STB0899_GPIO10CFG     	, 0x82 },
+	{ STB0899_GPIO11CFG     	, 0x82 },
+	{ STB0899_GPIO12CFG     	, 0x82 },
+	{ STB0899_GPIO13CFG     	, 0x82 },
+	{ STB0899_GPIO14CFG     	, 0x82 },
+	{ STB0899_GPIO15CFG     	, 0x82 },
+	{ STB0899_GPIO16CFG     	, 0x82 },
+	{ STB0899_GPIO17CFG     	, 0x82 },
+	{ STB0899_GPIO18CFG     	, 0x82 },
+	{ STB0899_GPIO19CFG     	, 0x82 },
+	{ STB0899_GPIO20CFG     	, 0x82 },
+	{ STB0899_SDATCFG       	, 0xb8 },
+	{ STB0899_SCLTCFG       	, 0xba },
+	{ STB0899_AGCRFCFG      	, 0x1c }, /* 0x11 */
+	{ STB0899_GPIO22        	, 0x82 }, /* AGCBB2CFG */
+	{ STB0899_GPIO21        	, 0x91 }, /* AGCBB1CFG */
+	{ STB0899_DIRCLKCFG     	, 0x82 },
+	{ STB0899_CLKOUT27CFG   	, 0x7e },
+	{ STB0899_STDBYCFG      	, 0x82 },
+	{ STB0899_CS0CFG        	, 0x82 },
+	{ STB0899_CS1CFG        	, 0x82 },
+	{ STB0899_DISEQCOCFG    	, 0x20 },
+	{ STB0899_GPIO32CFG		, 0x82 },
+	{ STB0899_GPIO33CFG		, 0x82 },
+	{ STB0899_GPIO34CFG		, 0x82 },
+	{ STB0899_GPIO35CFG		, 0x82 },
+	{ STB0899_GPIO36CFG		, 0x82 },
+	{ STB0899_GPIO37CFG		, 0x82 },
+	{ STB0899_GPIO38CFG		, 0x82 },
+	{ STB0899_GPIO39CFG		, 0x82 },
+	{ STB0899_NCOARSE       	, 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+	{ STB0899_SYNTCTRL      	, 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+	{ STB0899_FILTCTRL      	, 0x00 },
+	{ STB0899_SYSCTRL       	, 0x01 },
+	{ STB0899_STOPCLK1      	, 0x20 },
+	{ STB0899_STOPCLK2      	, 0x00 },
+	{ STB0899_INTBUFSTATUS		, 0x00 },
+	{ STB0899_INTBUFCTRL    	, 0x0a },
+	{ 0xffff			, 0xff },
+};
+
+static const struct stb0899_s1_reg az6027_stb0899_s1_init_3[] = {
+	{ STB0899_DEMOD         	, 0x00 },
+	{ STB0899_RCOMPC        	, 0xc9 },
+	{ STB0899_AGC1CN        	, 0x01 },
+	{ STB0899_AGC1REF       	, 0x10 },
+	{ STB0899_RTC	        	, 0x23 },
+	{ STB0899_TMGCFG        	, 0x4e },
+	{ STB0899_AGC2REF       	, 0x34 },
+	{ STB0899_TLSR          	, 0x84 },
+	{ STB0899_CFD           	, 0xf7 },
+	{ STB0899_ACLC	        	, 0x87 },
+	{ STB0899_BCLC          	, 0x94 },
+	{ STB0899_EQON          	, 0x41 },
+	{ STB0899_LDT           	, 0xf1 },
+	{ STB0899_LDT2          	, 0xe3 },
+	{ STB0899_EQUALREF      	, 0xb4 },
+	{ STB0899_TMGRAMP       	, 0x10 },
+	{ STB0899_TMGTHD        	, 0x30 },
+	{ STB0899_IDCCOMP		, 0xfd },
+	{ STB0899_QDCCOMP		, 0xff },
+	{ STB0899_POWERI		, 0x0c },
+	{ STB0899_POWERQ		, 0x0f },
+	{ STB0899_RCOMP			, 0x6c },
+	{ STB0899_AGCIQIN		, 0x80 },
+	{ STB0899_AGC2I1		, 0x06 },
+	{ STB0899_AGC2I2		, 0x00 },
+	{ STB0899_TLIR			, 0x30 },
+	{ STB0899_RTF			, 0x7f },
+	{ STB0899_DSTATUS		, 0x00 },
+	{ STB0899_LDI			, 0xbc },
+	{ STB0899_CFRM			, 0xea },
+	{ STB0899_CFRL			, 0x31 },
+	{ STB0899_NIRM			, 0x2b },
+	{ STB0899_NIRL			, 0x80 },
+	{ STB0899_ISYMB			, 0x1d },
+	{ STB0899_QSYMB			, 0xa6 },
+	{ STB0899_SFRH          	, 0x2f },
+	{ STB0899_SFRM          	, 0x68 },
+	{ STB0899_SFRL          	, 0x40 },
+	{ STB0899_SFRUPH        	, 0x2f },
+	{ STB0899_SFRUPM        	, 0x68 },
+	{ STB0899_SFRUPL        	, 0x40 },
+	{ STB0899_EQUAI1		, 0x02 },
+	{ STB0899_EQUAQ1		, 0xff },
+	{ STB0899_EQUAI2		, 0x04 },
+	{ STB0899_EQUAQ2		, 0x05 },
+	{ STB0899_EQUAI3		, 0x02 },
+	{ STB0899_EQUAQ3		, 0xfd },
+	{ STB0899_EQUAI4		, 0x03 },
+	{ STB0899_EQUAQ4		, 0x07 },
+	{ STB0899_EQUAI5		, 0x08 },
+	{ STB0899_EQUAQ5		, 0xf5 },
+	{ STB0899_DSTATUS2		, 0x00 },
+	{ STB0899_VSTATUS       	, 0x00 },
+	{ STB0899_VERROR		, 0x86 },
+	{ STB0899_IQSWAP		, 0x2a },
+	{ STB0899_ECNT1M		, 0x00 },
+	{ STB0899_ECNT1L		, 0x00 },
+	{ STB0899_ECNT2M		, 0x00 },
+	{ STB0899_ECNT2L		, 0x00 },
+	{ STB0899_ECNT3M		, 0x0a },
+	{ STB0899_ECNT3L		, 0xad },
+	{ STB0899_FECAUTO1      	, 0x06 },
+	{ STB0899_FECM	        	, 0x01 },
+	{ STB0899_VTH12         	, 0xb0 },
+	{ STB0899_VTH23         	, 0x7a },
+	{ STB0899_VTH34	        	, 0x58 },
+	{ STB0899_VTH56         	, 0x38 },
+	{ STB0899_VTH67         	, 0x34 },
+	{ STB0899_VTH78         	, 0x24 },
+	{ STB0899_PRVIT         	, 0xff },
+	{ STB0899_VITSYNC       	, 0x19 },
+	{ STB0899_RSULC         	, 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+	{ STB0899_TSULC         	, 0x42 },
+	{ STB0899_RSLLC         	, 0x41 },
+	{ STB0899_TSLPL	        	, 0x12 },
+	{ STB0899_TSCFGH        	, 0x0c },
+	{ STB0899_TSCFGM        	, 0x00 },
+	{ STB0899_TSCFGL        	, 0x00 },
+	{ STB0899_TSOUT			, 0x69 }, /* 0x0d for CAM */
+	{ STB0899_RSSYNCDEL     	, 0x00 },
+	{ STB0899_TSINHDELH     	, 0x02 },
+	{ STB0899_TSINHDELM		, 0x00 },
+	{ STB0899_TSINHDELL		, 0x00 },
+	{ STB0899_TSLLSTKM		, 0x1b },
+	{ STB0899_TSLLSTKL		, 0xb3 },
+	{ STB0899_TSULSTKM		, 0x00 },
+	{ STB0899_TSULSTKL		, 0x00 },
+	{ STB0899_PCKLENUL		, 0xbc },
+	{ STB0899_PCKLENLL		, 0xcc },
+	{ STB0899_RSPCKLEN		, 0xbd },
+	{ STB0899_TSSTATUS		, 0x90 },
+	{ STB0899_ERRCTRL1      	, 0xb6 },
+	{ STB0899_ERRCTRL2      	, 0x95 },
+	{ STB0899_ERRCTRL3      	, 0x8d },
+	{ STB0899_DMONMSK1		, 0x27 },
+	{ STB0899_DMONMSK0		, 0x03 },
+	{ STB0899_DEMAPVIT      	, 0x5c },
+	{ STB0899_PLPARM		, 0x19 },
+	{ STB0899_PDELCTRL      	, 0x48 },
+	{ STB0899_PDELCTRL2     	, 0x00 },
+	{ STB0899_BBHCTRL1      	, 0x00 },
+	{ STB0899_BBHCTRL2      	, 0x00 },
+	{ STB0899_HYSTTHRESH    	, 0x77 },
+	{ STB0899_MATCSTM		, 0x00 },
+	{ STB0899_MATCSTL		, 0x00 },
+	{ STB0899_UPLCSTM		, 0x00 },
+	{ STB0899_UPLCSTL		, 0x00 },
+	{ STB0899_DFLCSTM		, 0x00 },
+	{ STB0899_DFLCSTL		, 0x00 },
+	{ STB0899_SYNCCST		, 0x00 },
+	{ STB0899_SYNCDCSTM		, 0x00 },
+	{ STB0899_SYNCDCSTL		, 0x00 },
+	{ STB0899_ISI_ENTRY		, 0x00 },
+	{ STB0899_ISI_BIT_EN		, 0x00 },
+	{ STB0899_MATSTRM		, 0xf0 },
+	{ STB0899_MATSTRL		, 0x02 },
+	{ STB0899_UPLSTRM		, 0x45 },
+	{ STB0899_UPLSTRL		, 0x60 },
+	{ STB0899_DFLSTRM		, 0xe3 },
+	{ STB0899_DFLSTRL		, 0x00 },
+	{ STB0899_SYNCSTR		, 0x47 },
+	{ STB0899_SYNCDSTRM		, 0x05 },
+	{ STB0899_SYNCDSTRL		, 0x18 },
+	{ STB0899_CFGPDELSTATUS1	, 0x19 },
+	{ STB0899_CFGPDELSTATUS2	, 0x2b },
+	{ STB0899_BBFERRORM		, 0x00 },
+	{ STB0899_BBFERRORL		, 0x01 },
+	{ STB0899_UPKTERRORM		, 0x00 },
+	{ STB0899_UPKTERRORL		, 0x00 },
+	{ 0xffff			, 0xff },
+};
+
+
+
+struct stb0899_config az6027_stb0899_config = {
+	.init_dev		= az6027_stb0899_s1_init_1,
+	.init_s2_demod		= stb0899_s2_init_2,
+	.init_s1_demod		= az6027_stb0899_s1_init_3,
+	.init_s2_fec		= stb0899_s2_init_4,
+	.init_tst		= stb0899_s1_init_5,
+
+	.demod_address 		= 0xd0, /* 0x68, 0xd0 >> 1 */
+
+	.xtal_freq		= 27000000,
+	.inversion		= IQ_SWAP_ON, /* 1 */
+
+	.lo_clk			= 76500000,
+	.hi_clk			= 99000000,
+
+	.esno_ave		= STB0899_DVBS2_ESNO_AVE,
+	.esno_quant		= STB0899_DVBS2_ESNO_QUANT,
+	.avframes_coarse	= STB0899_DVBS2_AVFRAMES_COARSE,
+	.avframes_fine		= STB0899_DVBS2_AVFRAMES_FINE,
+	.miss_threshold		= STB0899_DVBS2_MISS_THRESHOLD,
+	.uwp_threshold_acq	= STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+	.uwp_threshold_track	= STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+	.uwp_threshold_sof	= STB0899_DVBS2_UWP_THRESHOLD_SOF,
+	.sof_search_timeout	= STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+	.btr_nco_bits		= STB0899_DVBS2_BTR_NCO_BITS,
+	.btr_gain_shift_offset	= STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+	.crl_nco_bits		= STB0899_DVBS2_CRL_NCO_BITS,
+	.ldpc_max_iter		= STB0899_DVBS2_LDPC_MAX_ITER,
+
+	.tuner_get_frequency	= stb6100_get_frequency,
+	.tuner_set_frequency	= stb6100_set_frequency,
+	.tuner_set_bandwidth	= stb6100_set_bandwidth,
+	.tuner_get_bandwidth	= stb6100_get_bandwidth,
+	.tuner_set_rfsiggain	= NULL,
+};
+
+struct stb6100_config az6027_stb6100_config = {
+	.tuner_address	= 0xc0,
+	.refclock	= 27000000,
+};
+
+
+/* check for mutex FIXME */
+int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+	int ret = -1;
+	if (mutex_lock_interruptible(&d->usb_mutex))
+		return -EAGAIN;
+
+	ret = usb_control_msg(d->udev,
+			      usb_rcvctrlpipe(d->udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_IN,
+			      value,
+			      index,
+			      b,
+			      blen,
+			      2000);
+
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
+	debug_dump(b, blen, deb_xfer);
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+static int az6027_usb_out_op(struct dvb_usb_device *d,
+			     u8 req,
+			     u16 value,
+			     u16 index,
+			     u8 *b,
+			     int blen)
+{
+	int ret;
+
+	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, index);
+	debug_dump(b, blen, deb_xfer);
+
+	if (mutex_lock_interruptible(&d->usb_mutex))
+		return -EAGAIN;
+
+	ret = usb_control_msg(d->udev,
+			      usb_sndctrlpipe(d->udev, 0),
+			      req,
+			      USB_TYPE_VENDOR | USB_DIR_OUT,
+			      value,
+			      index,
+			      b,
+			      blen,
+			      2000);
+
+	if (ret != blen) {
+		warn("usb out operation failed. (%d)", ret);
+		mutex_unlock(&d->usb_mutex);
+		return -EIO;
+	} else{
+		mutex_unlock(&d->usb_mutex);
+		return 0;
+	}
+}
+
+static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	deb_info("%s %d", __func__, onoff);
+
+	req = 0xBC;
+	value = onoff;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		warn("usb out operation failed. (%d)", ret);
+
+	return ret;
+}
+
+/* keys for the enclosed remote control */
+static struct dvb_usb_rc_key az6027_rc_keys[] = {
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+};
+
+/* remote control stuff (does not work with my box) */
+static int az6027_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	return 0;
+}
+
+/*
+int az6027_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 v = onoff;
+	return az6027_usb_out_op(d,0xBC,v,3,NULL,1);
+}
+*/
+
+static int az6027_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
+					int slot,
+					int address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 b[12];
+
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC1;
+	value = address;
+	index = 0;
+	blen = 1;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EINVAL;
+	} else {
+		ret = b[0];
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
+					 int slot,
+					 int address,
+					 u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	deb_info("%s %d", __func__, slot);
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC2;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
+	if (ret != 0)
+		warn("usb out operation failed. (%d)", ret);
+
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_read_cam_control(struct dvb_ca_en50221 *ca,
+				      int slot,
+				      u8 address)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 b[12];
+
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC3;
+	value = address;
+	index = 0;
+	blen = 2;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EINVAL;
+	} else {
+		if (b[0] == 0)
+			warn("Read CI IO error");
+
+		ret = b[1];
+		deb_info("read cam data = %x from 0x%x", b[1], value);
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_write_cam_control(struct dvb_ca_en50221 *ca,
+				       int slot,
+				       u8 address,
+				       u8 value)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value1;
+	u16 index;
+	int blen;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	mutex_lock(&state->ca_mutex);
+	req = 0xC4;
+	value1 = address;
+	index = value;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value1, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 b[12];
+
+	req = 0xC8;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else{
+		ret = b[0];
+	}
+	return ret;
+}
+
+static int az6027_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret, i;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC6;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+	msleep(500);
+	req = 0xC6;
+	value = 0;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+	for (i = 0; i < 15; i++) {
+		msleep(100);
+
+		if (CI_CamReady(ca, slot)) {
+			deb_info("CAM Ready");
+			break;
+		}
+	}
+	msleep(5000);
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	return 0;
+}
+
+static int az6027_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	deb_info("%s", __func__);
+	mutex_lock(&state->ca_mutex);
+	req = 0xC7;
+	value = 1;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(d, req, value, index, NULL, blen);
+	if (ret != 0) {
+		warn("usb out operation failed. (%d)", ret);
+		goto failed;
+	}
+
+failed:
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+static int az6027_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+	u8 b[12];
+
+	mutex_lock(&state->ca_mutex);
+
+	req = 0xC5;
+	value = 0;
+	index = 0;
+	blen = 1;
+
+	ret = az6027_usb_in_op(d, req, value, index, b, blen);
+	if (ret < 0) {
+		warn("usb in operation failed. (%d)", ret);
+		ret = -EIO;
+	} else
+		ret = 0;
+
+	if (b[0] == 0) {
+		ret = 0;
+
+	} else if (b[0] == 1) {
+		ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
+		      DVB_CA_EN50221_POLL_CAM_READY;
+	}
+
+	mutex_unlock(&state->ca_mutex);
+	return ret;
+}
+
+
+static void az6027_ci_uninit(struct dvb_usb_device *d)
+{
+	struct az6027_device_state *state;
+
+	deb_info("%s", __func__);
+
+	if (NULL == d)
+		return;
+
+	state = (struct az6027_device_state *)d->priv;
+	if (NULL == state)
+		return;
+
+	if (NULL == state->ca.data)
+		return;
+
+	dvb_ca_en50221_release(&state->ca);
+
+	memset(&state->ca, 0, sizeof(state->ca));
+}
+
+
+static int az6027_ci_init(struct dvb_usb_adapter *a)
+{
+	struct dvb_usb_device *d = a->dev;
+	struct az6027_device_state *state = (struct az6027_device_state *)d->priv;
+	int ret;
+
+	deb_info("%s", __func__);
+
+	mutex_init(&state->ca_mutex);
+
+	state->ca.owner			= THIS_MODULE;
+	state->ca.read_attribute_mem	= az6027_ci_read_attribute_mem;
+	state->ca.write_attribute_mem	= az6027_ci_write_attribute_mem;
+	state->ca.read_cam_control	= az6027_ci_read_cam_control;
+	state->ca.write_cam_control	= az6027_ci_write_cam_control;
+	state->ca.slot_reset		= az6027_ci_slot_reset;
+	state->ca.slot_shutdown		= az6027_ci_slot_shutdown;
+	state->ca.slot_ts_enable	= az6027_ci_slot_ts_enable;
+	state->ca.poll_slot_status	= az6027_ci_poll_slot_status;
+	state->ca.data			= d;
+
+	ret = dvb_ca_en50221_init(&a->dvb_adap,
+				  &state->ca,
+				  0, /* flags */
+				  1);/* n_slots */
+	if (ret != 0) {
+		err("Cannot initialize CI: Error %d.", ret);
+		memset(&state->ca, 0, sizeof(state->ca));
+		return ret;
+	}
+
+	deb_info("CI initialized.");
+
+	return 0;
+}
+
+/*
+static int az6027_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
+{
+	az6027_usb_in_op(d, 0xb7, 6, 0, &mac[0], 6);
+	return 0;
+}
+*/
+
+static int az6027_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+
+	u8 buf;
+	int ret;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+
+	struct i2c_msg i2c_msg = {
+		.addr	= 0x99,
+		.flags	= 0,
+		.buf	= &buf,
+		.len	= 1
+	};
+
+	/*
+	 * 2   --18v
+	 * 1   --13v
+	 * 0   --off
+	 */
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		buf = 1;
+		ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+		break;
+
+	case SEC_VOLTAGE_18:
+		buf = 2;
+		ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+		break;
+
+	case SEC_VOLTAGE_OFF:
+		buf = 0;
+		ret = i2c_transfer(&adap->dev->i2c_adap, &i2c_msg, 1);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static int az6027_frontend_poweron(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	req = 0xBC;
+	value = 1; /* power on */
+	index = 3;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	return 0;
+}
+static int az6027_frontend_reset(struct dvb_usb_adapter *adap)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	/* reset demodulator */
+	req = 0xC0;
+	value = 1; /* high */
+	index = 3;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	req = 0xC0;
+	value = 0; /* low */
+	index = 3;
+	blen = 0;
+	msleep_interruptible(200);
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	msleep_interruptible(200);
+
+	req = 0xC0;
+	value = 1; /*high */
+	index = 3;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	msleep_interruptible(200);
+	return 0;
+}
+
+static int az6027_frontend_tsbypass(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	u8 req;
+	u16 value;
+	u16 index;
+	int blen;
+
+	/* TS passthrough */
+	req = 0xC7;
+	value = onoff;
+	index = 0;
+	blen = 0;
+
+	ret = az6027_usb_out_op(adap->dev, req, value, index, NULL, blen);
+	if (ret != 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int az6027_frontend_attach(struct dvb_usb_adapter *adap)
+{
+
+	az6027_frontend_poweron(adap);
+	az6027_frontend_reset(adap);
+
+	deb_info("adap = %p, dev = %p\n", adap, adap->dev);
+	adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap);
+
+	if (adap->fe) {
+		deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address);
+		if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) {
+			deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address);
+			adap->fe->ops.set_voltage = az6027_set_voltage;
+			az6027_ci_init(adap);
+		} else {
+			adap->fe = NULL;
+		}
+	} else
+		warn("no front-end attached\n");
+
+	az6027_frontend_tsbypass(adap, 0);
+
+	return 0;
+}
+
+static struct dvb_usb_device_properties az6027_properties;
+
+static void az6027_usb_disconnect(struct usb_interface *intf)
+{
+	struct dvb_usb_device *d = usb_get_intfdata(intf);
+	az6027_ci_uninit(d);
+	dvb_usb_device_exit(intf);
+}
+
+
+static int az6027_usb_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf,
+				   &az6027_properties,
+				   THIS_MODULE,
+				   NULL,
+				   adapter_nr);
+}
+
+/* I2C */
+static int az6027_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i = 0, j = 0, len = 0;
+	int ret;
+	u16 index;
+	u16 value;
+	int length;
+	u8 req;
+	u8 data[256];
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+	for (i = 0; i < num; i++) {
+
+		if (msg[i].addr == 0x99) {
+			req = 0xBE;
+			index = 0;
+			value = msg[i].buf[0] & 0x00ff;
+			length = 1;
+			az6027_usb_out_op(d, req, value, index, data, length);
+		}
+
+		if (msg[i].addr == 0xd0) {
+			/* write/read request */
+			if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
+				req = 0xB9;
+				index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
+				value = msg[i].addr + (msg[i].len << 8);
+				length = msg[i + 1].len + 6;
+				ret = az6027_usb_in_op(d, req, value, index, data, length);
+				len = msg[i + 1].len;
+				for (j = 0; j < len; j++)
+					msg[i + 1].buf[j] = data[j + 5];
+
+				i++;
+			} else {
+
+				if (msg[i].addr == 0xd0) {
+					/* demod 16bit addr */
+					req = 0xBD;
+					index = (((msg[i].buf[0] << 8) & 0xff00) | (msg[i].buf[1] & 0x00ff));
+					value = msg[i].addr + (2 << 8);
+					length = msg[i].len - 2;
+					len = msg[i].len - 2;
+					for (j = 0; j < len; j++)
+						data[j] = msg[i].buf[j + 2];
+
+				}
+				az6027_usb_out_op(d, req, value, index, data, length);
+			}
+		}
+
+		if (msg[i].addr == 0xc0) {
+			if (msg[i].flags & I2C_M_RD) {
+
+				req = 0xB9;
+				index = 0x0;
+				value = msg[i].addr;
+				length = msg[i].len + 6;
+				ret = az6027_usb_in_op(d, req, value, index, data, length);
+				len = msg[i].len;
+				for (j = 0; j < len; j++)
+					msg[i].buf[j] = data[j + 5];
+
+			} else {
+
+				req = 0xBD;
+				index = msg[i].buf[0] & 0x00FF;
+				value = msg[i].addr + (1 << 8);
+				length = msg[i].len - 1;
+				len = msg[i].len - 1;
+
+				for (j = 0; j < len; j++)
+					data[j] = msg[i].buf[j + 1];
+
+				az6027_usb_out_op(d, req, value, index, data, length);
+			}
+		}
+	}
+	mutex_unlock(&d->i2c_mutex);
+
+	return i;
+}
+
+
+static u32 az6027_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm az6027_i2c_algo = {
+	.master_xfer   = az6027_i2c_xfer,
+	.functionality = az6027_i2c_func,
+};
+
+int az6027_identify_state(struct usb_device *udev,
+			  struct dvb_usb_device_properties *props,
+			  struct dvb_usb_device_description **desc,
+			  int *cold)
+{
+	u8 b[16];
+	s16 ret = usb_control_msg(udev,
+				  usb_rcvctrlpipe(udev, 0),
+				  0xb7,
+				  USB_TYPE_VENDOR | USB_DIR_IN,
+				  6,
+				  0,
+				  b,
+				  6,
+				  USB_CTRL_GET_TIMEOUT);
+
+	*cold = ret <= 0;
+
+	deb_info("cold: %d\n", *cold);
+	return 0;
+}
+
+
+static struct usb_device_id az6027_usb_table[] = {
+	{ USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) },
+	{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_DVBS2CI) },
+	{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI) },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(usb, az6027_usb_table);
+
+static struct dvb_usb_device_properties az6027_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware            = "dvb-usb-az6027-03.fw",
+	.no_reconnect        = 1,
+
+	.size_of_priv     = sizeof(struct az6027_device_state),
+	.identify_state		= az6027_identify_state,
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = az6027_streaming_ctrl,
+			.frontend_attach  = az6027_frontend_attach,
+
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}
+	},
+/*
+	.power_ctrl       = az6027_power_ctrl,
+	.read_mac_address = az6027_read_mac_addr,
+ */
+	.rc_key_map       = az6027_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(az6027_rc_keys),
+	.rc_interval      = 400,
+	.rc_query         = az6027_rc_query,
+	.i2c_algo         = &az6027_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{
+			.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
+			.cold_ids = { &az6027_usb_table[0], NULL },
+			.warm_ids = { NULL },
+		},
+		{ NULL },
+	}
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6027_usb_driver = {
+	.name		= "dvb_usb_az6027",
+	.probe 		= az6027_usb_probe,
+	.disconnect 	= az6027_usb_disconnect,
+	.id_table 	= az6027_usb_table,
+};
+
+/* module stuff */
+static int __init az6027_usb_module_init(void)
+{
+	int result;
+
+	result = usb_register(&az6027_usb_driver);
+	if (result) {
+		err("usb_register failed. (%d)", result);
+		return result;
+	}
+
+	return 0;
+}
+
+static void __exit az6027_usb_module_exit(void)
+{
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&az6027_usb_driver);
+}
+
+module_init(az6027_usb_module_init);
+module_exit(az6027_usb_module_exit);
+
+MODULE_AUTHOR("Adams Xu <Adams.xu@azwave.com.cn>");
+MODULE_DESCRIPTION("Driver for AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/az6027.h b/drivers/media/dvb/dvb-usb/az6027.h
new file mode 100644
index 000000000000..f3afe17f3f3d
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/az6027.h
@@ -0,0 +1,14 @@
+#ifndef _DVB_USB_VP6027_H_
+#define _DVB_USB_VP6027_H_
+
+#define DVB_USB_LOG_PREFIX "az6027"
+#include "dvb-usb.h"
+
+
+extern int dvb_usb_az6027_debug;
+#define deb_info(args...) dprintk(dvb_usb_az6027_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_az6027_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_az6027_debug, 0x04, args)
+#define deb_fe(args...)   dprintk(dvb_usb_az6027_debug, 0x08, args)
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 05fb28e9c69e..a7b8405c291e 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -1184,6 +1184,9 @@ static struct atbm8830_config mygica_d689_atbm8830_cfg = {
 	.osc_clk_freq = 30400, /* in kHz */
 	.if_freq = 0, /* zero IF */
 	.zif_swap_iq = 1,
+	.agc_min = 0x2E,
+	.agc_max = 0x90,
+	.agc_hold_loop = 0,
 };
 
 static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 495a90577c5f..83fc24a6c31a 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -42,7 +42,6 @@ struct dib0700_state {
 	u16 mt2060_if1[2];
 	u8 rc_toggle;
 	u8 rc_counter;
-	u8 rc_func_version;
 	u8 is_dib7000pc;
 	u8 fw_use_new_i2c_api;
 	u8 disable_streaming_master_mode;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 0d3c9a9a33be..4f961d2d1817 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -471,14 +471,209 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 	return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY_V1_20 10
+
+/* This is the structure of the RC response packet starting in firmware 1.20 */
+struct dib0700_rc_response {
+	u8 report_id;
+	u8 data_state;
+	u16 system;
+	u8 data;
+	u8 not_data;
+};
+#define RC_MSG_SIZE_V1_20 6
+
+static void dib0700_rc_urb_completion(struct urb *purb)
+{
+	struct dvb_usb_device *d = purb->context;
+	struct dvb_usb_rc_key *keymap;
+	struct dib0700_state *st;
+	struct dib0700_rc_response poll_reply;
+	u8 *buf;
+	int found = 0;
+	u32 event;
+	int state;
+	int i;
+
+	deb_info("%s()\n", __func__);
+	if (d == NULL)
+		return;
+
+	if (d->rc_input_dev == NULL) {
+		/* This will occur if disable_rc_polling=1 */
+		usb_free_urb(purb);
+		return;
+	}
+
+	keymap = d->props.rc_key_map;
+	st = d->priv;
+	buf = (u8 *)purb->transfer_buffer;
+
+	if (purb->status < 0) {
+		deb_info("discontinuing polling\n");
+		usb_free_urb(purb);
+		return;
+	}
+
+	if (purb->actual_length != RC_MSG_SIZE_V1_20) {
+		deb_info("malformed rc msg size=%d\n", purb->actual_length);
+		goto resubmit;
+	}
+
+	/* Set initial results in case we exit the function early */
+	event = 0;
+	state = REMOTE_NO_KEY_PRESSED;
+
+	deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
+		 buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
+
+	switch (dvb_usb_dib0700_ir_proto) {
+	case 0:
+		/* NEC Protocol */
+		poll_reply.report_id  = 0;
+		poll_reply.data_state = 1;
+		poll_reply.system     = buf[2];
+		poll_reply.data       = buf[4];
+		poll_reply.not_data   = buf[5];
+
+		/* NEC protocol sends repeat code as 0 0 0 FF */
+		if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
+		    && (poll_reply.not_data == 0xff)) {
+			poll_reply.data_state = 2;
+			break;
+		}
+		break;
+	default:
+		/* RC5 Protocol */
+		poll_reply.report_id  = buf[0];
+		poll_reply.data_state = buf[1];
+		poll_reply.system     = (buf[2] << 8) | buf[3];
+		poll_reply.data       = buf[4];
+		poll_reply.not_data   = buf[5];
+		break;
+	}
+
+	if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+		/* Key failed integrity check */
+		err("key failed integrity check: %04x %02x %02x",
+		    poll_reply.system,
+		    poll_reply.data, poll_reply.not_data);
+		goto resubmit;
+	}
+
+	deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
+		 poll_reply.report_id, poll_reply.data_state,
+		 poll_reply.system, poll_reply.data, poll_reply.not_data);
+
+	/* Find the key in the map */
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
+		    rc5_data(&keymap[i]) == poll_reply.data) {
+			event = keymap[i].event;
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0) {
+		err("Unknown remote controller key: %04x %02x %02x",
+		    poll_reply.system, poll_reply.data, poll_reply.not_data);
+		d->last_event = 0;
+		goto resubmit;
+	}
+
+	if (poll_reply.data_state == 1) {
+		/* New key hit */
+		st->rc_counter = 0;
+		event = keymap[i].event;
+		state = REMOTE_KEY_PRESSED;
+		d->last_event = keymap[i].event;
+	} else if (poll_reply.data_state == 2) {
+		/* Key repeated */
+		st->rc_counter++;
+
+		/* prevents unwanted double hits */
+		if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
+			event = d->last_event;
+			state = REMOTE_KEY_PRESSED;
+			st->rc_counter = RC_REPEAT_DELAY_V1_20;
+		}
+	} else {
+		err("Unknown data state [%d]", poll_reply.data_state);
+	}
+
+	switch (state) {
+	case REMOTE_NO_KEY_PRESSED:
+		break;
+	case REMOTE_KEY_PRESSED:
+		deb_info("key pressed\n");
+		d->last_event = event;
+	case REMOTE_KEY_REPEAT:
+		deb_info("key repeated\n");
+		input_event(d->rc_input_dev, EV_KEY, event, 1);
+		input_sync(d->rc_input_dev);
+		input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
+		input_sync(d->rc_input_dev);
+		break;
+	default:
+		break;
+	}
+
+resubmit:
+	/* Clean the buffer before we requeue */
+	memset(purb->transfer_buffer, 0, RC_MSG_SIZE_V1_20);
+
+	/* Requeue URB */
+	usb_submit_urb(purb, GFP_ATOMIC);
+}
+
 int dib0700_rc_setup(struct dvb_usb_device *d)
 {
+	struct dib0700_state *st = d->priv;
 	u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
-	int i = dib0700_ctrl_wr(d, rc_setup, 3);
+	struct urb *purb;
+	int ret;
+	int i;
+
+	if (d->props.rc_key_map == NULL)
+		return 0;
+
+	/* Set the IR mode */
+	i = dib0700_ctrl_wr(d, rc_setup, 3);
 	if (i<0) {
 		err("ir protocol setup failed");
 		return -1;
 	}
+
+	if (st->fw_version < 0x10200)
+		return 0;
+
+	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
+	purb = usb_alloc_urb(0, GFP_KERNEL);
+	if (purb == NULL) {
+		err("rc usb alloc urb failed\n");
+		return -1;
+	}
+
+	purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
+	if (purb->transfer_buffer == NULL) {
+		err("rc kzalloc failed\n");
+		usb_free_urb(purb);
+		return -1;
+	}
+
+	purb->status = -EINPROGRESS;
+	usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
+			  purb->transfer_buffer, RC_MSG_SIZE_V1_20,
+			  dib0700_rc_urb_completion, d);
+
+	ret = usb_submit_urb(purb, GFP_ATOMIC);
+	if (ret != 0) {
+		err("rc submit urb failed\n");
+		return -1;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 44972d01bbd0..34eab05afc6c 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -472,20 +472,25 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
 
 /* Number of keypresses to ignore before start repeating */
 #define RC_REPEAT_DELAY 6
-#define RC_REPEAT_DELAY_V1_20 10
 
-
-
-/* Used by firmware versions < 1.20 (deprecated) */
-static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
-				   int *state)
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	u8 key[4];
 	int i;
 	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
 	struct dib0700_state *st = d->priv;
+
 	*event = 0;
 	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (st->fw_version >= 0x10200) {
+		/* For 1.20 firmware , We need to keep the RC polling
+		   callback so we can reuse the input device setup in
+		   dvb-usb-remote.c.  However, the actual work is being done
+		   in the bulk URB completion handler. */
+		return 0;
+	}
+
 	i=dib0700_ctrl_rd(d,rc_request,2,key,4);
 	if (i<=0) {
 		err("RC Query Failed");
@@ -557,149 +562,6 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
 	return 0;
 }
 
-/* This is the structure of the RC response packet starting in firmware 1.20 */
-struct dib0700_rc_response {
-	u8 report_id;
-	u8 data_state;
-	u16 system;
-	u8 data;
-	u8 not_data;
-};
-
-/* This supports the new IR response format for firmware v1.20 */
-static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
-				  int *state)
-{
-	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
-	struct dib0700_state *st = d->priv;
-	struct dib0700_rc_response poll_reply;
-	u8 buf[6];
-	int i;
-	int status;
-	int actlen;
-	int found = 0;
-
-	/* Set initial results in case we exit the function early */
-	*event = 0;
-	*state = REMOTE_NO_KEY_PRESSED;
-
-	/* Firmware v1.20 provides RC data via bulk endpoint 1 */
-	status = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 1), buf,
-			      sizeof(buf), &actlen, 50);
-	if (status < 0) {
-		/* No data available (meaning no key press) */
-		return 0;
-	}
-
-
-	switch (dvb_usb_dib0700_ir_proto) {
-	case 0:
-		poll_reply.report_id  = 0;
-		poll_reply.data_state = 1;
-		poll_reply.system     = buf[2];
-		poll_reply.data       = buf[4];
-		poll_reply.not_data   = buf[5];
-
-		/* NEC protocol sends repeat code as 0 0 0 FF */
-		if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
-		    && (poll_reply.not_data == 0xff)) {
-			poll_reply.data_state = 2;
-			break;
-		}
-		break;
-	default:
-	if (actlen != sizeof(buf)) {
-		/* We didn't get back the 6 byte message we expected */
-		err("Unexpected RC response size [%d]", actlen);
-		return -1;
-	}
-
-	poll_reply.report_id  = buf[0];
-	poll_reply.data_state = buf[1];
-		poll_reply.system     = (buf[2] << 8) | buf[3];
-	poll_reply.data       = buf[4];
-	poll_reply.not_data   = buf[5];
-
-		break;
-	}
-
-	if ((poll_reply.data + poll_reply.not_data) != 0xff) {
-		/* Key failed integrity check */
-		err("key failed integrity check: %04x %02x %02x",
-		    poll_reply.system,
-		    poll_reply.data, poll_reply.not_data);
-		return -1;
-	}
-
-
-	/* Find the key in the map */
-	for (i = 0; i < d->props.rc_key_map_size; i++) {
-		if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
-			rc5_data(&keymap[i]) == poll_reply.data) {
-			*event = keymap[i].event;
-			found = 1;
-			break;
-		}
-	}
-
-	if (found == 0) {
-		err("Unknown remote controller key: %04x %02x %02x",
-			poll_reply.system,
-			poll_reply.data, poll_reply.not_data);
-		d->last_event = 0;
-		return 0;
-	}
-
-	if (poll_reply.data_state == 1) {
-		/* New key hit */
-		st->rc_counter = 0;
-		*event = keymap[i].event;
-		*state = REMOTE_KEY_PRESSED;
-		d->last_event = keymap[i].event;
-	} else if (poll_reply.data_state == 2) {
-		/* Key repeated */
-		st->rc_counter++;
-
-		/* prevents unwanted double hits */
-		if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
-			*event = d->last_event;
-			*state = REMOTE_KEY_PRESSED;
-			st->rc_counter = RC_REPEAT_DELAY_V1_20;
-		}
-	} else {
-		err("Unknown data state [%d]", poll_reply.data_state);
-	}
-
-	return 0;
-}
-
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
-{
-	struct dib0700_state *st = d->priv;
-
-	/* Because some people may have improperly named firmware files,
-	   let's figure out whether to use the new firmware call or the legacy
-	   call based on the firmware version embedded in the file */
-	if (st->rc_func_version == 0) {
-		u32 hwver, romver, ramver, fwtype;
-		int ret = dib0700_get_version(d, &hwver, &romver, &ramver,
-					      &fwtype);
-		if (ret < 0) {
-			err("Could not determine version info");
-			return -1;
-		}
-		if (ramver < 0x10200)
-			st->rc_func_version = 1;
-		else
-			st->rc_func_version = 2;
-	}
-
-	if (st->rc_func_version == 2)
-		return dib0700_rc_query_v1_20(d, event, state);
-	else
-		return dib0700_rc_query_legacy(d, event, state);
-}
-
 static struct dvb_usb_rc_key dib0700_rc_keys[] = {
 	/* Key codes for the tiny Pinnacle remote*/
 	{ 0x0700, KEY_MUTE },
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index bc3581d58ced..ae8b57acfe05 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -64,6 +64,8 @@
 #define USB_VID_HUMAX_COEX			0x10b9
 #define USB_VID_774				0x7a69
 #define USB_VID_EVOLUTEPC			0x1e59
+#define USB_VID_AZUREWAVE			0x13d3
+#define USB_VID_TECHNISAT			0x14f7
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
@@ -138,6 +140,7 @@
 #define USB_PID_TWINHAN_VP7021_COLD			0x3207
 #define USB_PID_TWINHAN_VP7021_WARM			0x3208
 #define USB_PID_TINYTWIN				0x3226
+#define USB_PID_TINYTWIN_2				0xe402
 #define USB_PID_DNTV_TINYUSB2_COLD			0x3223
 #define USB_PID_DNTV_TINYUSB2_WARM			0x3224
 #define USB_PID_ULTIMA_TVBOX_COLD			0x8105
@@ -209,6 +212,7 @@
 #define USB_PID_PINNACLE_PCTV71E			0x022b
 #define USB_PID_PINNACLE_PCTV72E			0x0236
 #define USB_PID_PINNACLE_PCTV73E			0x0237
+#define USB_PID_PINNACLE_PCTV310E			0x3211
 #define USB_PID_PINNACLE_PCTV801E			0x023a
 #define USB_PID_PINNACLE_PCTV801E_SE			0x023b
 #define USB_PID_PINNACLE_PCTV73A			0x0243
@@ -248,6 +252,7 @@
 #define USB_PID_DIGIVOX_MINI_SL_WARM			0xe361
 #define USB_PID_GRANDTEC_DVBT_USB2_COLD			0x0bc6
 #define USB_PID_GRANDTEC_DVBT_USB2_WARM			0x0bc7
+#define USB_PID_WINFAST_DTV2000DS			0x6a04
 #define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
@@ -290,5 +295,7 @@
 #define USB_PID_FRIIO_WHITE				0x0001
 #define USB_PID_TVWAY_PLUS				0x0002
 #define USB_PID_SVEON_STV20				0xe39d
-
+#define USB_PID_AZUREWAVE_AZ6027			0x3275
+#define USB_PID_TERRATEC_DVBS2CI			0x3275
+#define USB_PID_TECHNISAT_USB2_HDCI			0x0002
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index e331db8c77b2..5d91f70d2d2d 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -243,7 +243,7 @@ int dvb_usb_device_init(struct usb_interface *intf,
 		d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
 	if (d == NULL) {
 		err("no memory for 'struct dvb_usb_device'");
-		return ret;
+		return -ENOMEM;
 	}
 
 	d->udev = udev;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 6b5ded9e7d5d..a03ef7efec9a 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -107,6 +107,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
 		case REMOTE_KEY_REPEAT:
 			deb_rc("key repeated\n");
 			input_event(d->rc_input_dev, EV_KEY, event, 1);
+			input_sync(d->rc_input_dev);
 			input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
 			input_sync(d->rc_input_dev);
 			break;
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 64132c0cf80d..accc65509b07 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -1,6 +1,7 @@
 /* DVB USB framework compliant Linux driver for the
 *	DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
-*	TeVii S600, S630, S650 Cards
+*	TeVii S600, S630, S650,
+*	Prof 1100, 7500 Cards
 * Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
 *
 *	This program is free software; you can redistribute it and/or modify it
@@ -469,11 +470,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 								int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct usb_device *udev;
 	int ret = 0;
 	int len, i, j;
 
 	if (!d)
 		return -ENODEV;
+	udev = d->udev;
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
@@ -488,8 +491,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 		}
 		case (DW2102_VOLTAGE_CTRL): {
 			u8 obuf[2];
+
+			obuf[0] = 1;
+			obuf[1] = msg[j].buf[1];/* off-on */
+			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+					obuf, 2, DW210X_WRITE_MSG);
 			obuf[0] = 3;
-			obuf[1] = msg[j].buf[0];
+			obuf[1] = msg[j].buf[0];/* 13v-18v */
 			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
 					obuf, 2, DW210X_WRITE_MSG);
 			break;
@@ -527,6 +535,17 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 					i += 16;
 					len -= 16;
 				} while (len > 0);
+			} else if ((udev->descriptor.idProduct == 0x7500)
+					&& (j < (num - 1))) {
+				/* write register addr before read */
+				u8 obuf[msg[j].len + 2];
+				obuf[0] = msg[j + 1].len;
+				obuf[1] = (msg[j].addr << 1);
+				memcpy(obuf + 2, msg[j].buf, msg[j].len);
+				ret = dw210x_op_rw(d->udev, 0x92, 0, 0,
+						obuf, msg[j].len + 2,
+						DW210X_WRITE_MSG);
+				break;
 			} else {
 				/* write registers */
 				u8 obuf[msg[j].len + 2];
@@ -651,18 +670,25 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 
 static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
-	static u8 command_13v[1] = {0x00};
-	static u8 command_18v[1] = {0x01};
-	struct i2c_msg msg[] = {
-		{.addr = DW2102_VOLTAGE_CTRL, .flags = 0,
-			.buf = command_13v, .len = 1},
+	static u8 command_13v[] = {0x00, 0x01};
+	static u8 command_18v[] = {0x01, 0x01};
+	static u8 command_off[] = {0x00, 0x00};
+	struct i2c_msg msg = {
+		.addr = DW2102_VOLTAGE_CTRL,
+		.flags = 0,
+		.buf = command_off,
+		.len = 2,
 	};
 
 	struct dvb_usb_adapter *udev_adap =
 		(struct dvb_usb_adapter *)(fe->dvb->priv);
 	if (voltage == SEC_VOLTAGE_18)
-		msg[0].buf = command_18v;
-	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+		msg.buf = command_18v;
+	else if (voltage == SEC_VOLTAGE_13)
+		msg.buf = command_13v;
+
+	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
+
 	return 0;
 }
 
@@ -735,6 +761,18 @@ static struct stv6110_config dw2104_stv6110_config = {
 	.clk_div = 1,
 };
 
+static struct stv0900_config prof_7500_stv0900_config = {
+	.demod_address = 0x6a,
+	.demod_mode = 0,
+	.xtal = 27000000,
+	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+	.diseqc_mode = 2,/* 2/3 PWM */
+	.tun1_maddress = 0,/* 0x60 */
+	.tun1_adc = 0,/* 2 Vpp */
+	.path1_mode = 3,
+	.tun1_type = 3,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
 	struct dvb_tuner_ops *tuner_ops = NULL;
@@ -882,6 +920,19 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
 	return -EIO;
 }
 
+static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
+{
+	d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
+					&d->dev->i2c_adap, 0);
+	if (d->fe == NULL)
+		return -EIO;
+	d->fe->ops.set_voltage = dw210x_set_voltage;
+
+	info("Attached STV0900+STB6100A!\n");
+
+	return 0;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
 	dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -1073,6 +1124,7 @@ static struct usb_device_id dw2102_table[] = {
 	{USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
 	{USB_DEVICE(0x3011, USB_PID_PROF_1100)},
 	{USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
+	{USB_DEVICE(0x3034, 0x7500)},
 	{ }
 };
 
@@ -1387,9 +1439,30 @@ static struct dvb_usb_device_properties s6x0_properties = {
 	}
 };
 
+struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_description d7500 = {
+	"Prof 7500 USB DVB-S2",
+	{&dw2102_table[9], NULL},
+	{NULL},
+};
+
 static int dw2102_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
+
+	p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+	if (!p7500)
+		return -ENOMEM;
+	/* copy default structure */
+	memcpy(p7500, &s6x0_properties,
+			sizeof(struct dvb_usb_device_properties));
+	/* fill only different fields */
+	p7500->firmware = "dvb-usb-p7500.fw";
+	p7500->devices[0] = d7500;
+	p7500->rc_key_map = tbs_rc_keys;
+	p7500->rc_key_map_size = ARRAY_SIZE(tbs_rc_keys);
+	p7500->adapter->frontend_attach = prof_7500_frontend_attach;
+
 	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &dw2104_properties,
@@ -1397,6 +1470,8 @@ static int dw2102_probe(struct usb_interface *intf,
 	    0 == dvb_usb_device_init(intf, &dw3101_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &s6x0_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, p7500,
 			THIS_MODULE, NULL, adapter_nr))
 		return 0;
 
@@ -1431,6 +1506,6 @@ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
 MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
 				" DVB-C 3101 USB2.0,"
 				" TeVii S600, S630, S650, S660 USB2.0,"
-				" Prof 1100 USB2.0 devices");
+				" Prof 1100, 7500 USB2.0 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c
index ebb7b9fd115b..d14bd227b502 100644
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ b/drivers/media/dvb/dvb-usb/friio-fe.c
@@ -366,7 +366,7 @@ static u8 init_code[][2] = {
 	{0x76, 0x0C},
 };
 
-const static int init_code_len = sizeof(init_code) / sizeof(u8[2]);
+static const int init_code_len = sizeof(init_code) / sizeof(u8[2]);
 
 static int jdvbt90502_init(struct dvb_frontend *fe)
 {
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index ef9b7bed13ff..737ffa36ac9c 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -16,6 +16,9 @@
 #include "qt1010.h"
 #include "tda1004x.h"
 #include "tda827x.h"
+
+#include <media/tuner.h>
+#include "tuner-simple.h"
 #include <asm/unaligned.h>
 
 /* debug */
@@ -158,11 +161,14 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 
 			case 0x93:
 			case 0x92:
+			case 0x83: /* pinnacle PCTV310e */
+			case 0x82:
 				m->rep_count = 0;
 				*state = REMOTE_KEY_PRESSED;
 				goto unlock;
 
 			case 0x91:
+			case 0x81: /* pinnacle PCTV310e */
 				/* prevent immediate auto-repeat */
 				if (++m->rep_count > 2)
 					*state = REMOTE_KEY_REPEAT;
@@ -546,6 +552,14 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
+static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(simple_tuner_attach, adap->fe,
+		   &adap->dev->i2c_adap, 0x61,
+		   TUNER_PHILIPS_FMD1216ME_MK3);
+	return 0;
+}
+
 /* device-specific initialization */
 static struct m920x_inits megasky_rc_init [] = {
 	{ M9206_RC_INIT2, 0xa8 },
@@ -562,6 +576,18 @@ static struct m920x_inits tvwalkertwin_rc_init [] = {
 	{ } /* terminating entry */
 };
 
+static struct m920x_inits pinnacle310e_init[] = {
+	/* without these the tuner don't work */
+	{ 0xff20,         0x9b },
+	{ 0xff22,         0x70 },
+
+	/* rc settings */
+	{ 0xff50,         0x80 },
+	{ M9206_RC_INIT1, 0x00 },
+	{ M9206_RC_INIT2, 0xff },
+	{ } /* terminating entry */
+};
+
 /* ir keymaps */
 static struct dvb_usb_rc_key megasky_rc_keys [] = {
 	{ 0x0012, KEY_POWER },
@@ -602,11 +628,68 @@ static struct dvb_usb_rc_key tvwalkertwin_rc_keys [] = {
 	{ 0x001e, KEY_VOLUMEUP },
 };
 
+static struct dvb_usb_rc_key pinnacle310e_rc_keys[] = {
+	{ 0x16, KEY_POWER },
+	{ 0x17, KEY_FAVORITES },
+	{ 0x0f, KEY_TEXT },
+	{ 0x48, KEY_MEDIA },		/* preview */
+	{ 0x1c, KEY_EPG },
+	{ 0x04, KEY_LIST },			/* record list */
+	{ 0x03, KEY_1 },
+	{ 0x01, KEY_2 },
+	{ 0x06, KEY_3 },
+	{ 0x09, KEY_4 },
+	{ 0x1d, KEY_5 },
+	{ 0x1f, KEY_6 },
+	{ 0x0d, KEY_7 },
+	{ 0x19, KEY_8 },
+	{ 0x1b, KEY_9 },
+	{ 0x15, KEY_0 },
+	{ 0x0c, KEY_CANCEL },
+	{ 0x4a, KEY_CLEAR },
+	{ 0x13, KEY_BACK },
+	{ 0x00, KEY_TAB },
+	{ 0x4b, KEY_UP },
+	{ 0x4e, KEY_LEFT },
+	{ 0x52, KEY_RIGHT },
+	{ 0x51, KEY_DOWN },
+	{ 0x4f, KEY_ENTER },		/* could also be KEY_OK */
+	{ 0x1e, KEY_VOLUMEUP },
+	{ 0x0a, KEY_VOLUMEDOWN },
+	{ 0x05, KEY_CHANNELUP },
+	{ 0x02, KEY_CHANNELDOWN },
+	{ 0x11, KEY_RECORD },
+	{ 0x14, KEY_PLAY },
+	{ 0x4c, KEY_PAUSE },
+	{ 0x1a, KEY_STOP },
+	{ 0x40, KEY_REWIND },
+	{ 0x12, KEY_FASTFORWARD },
+	{ 0x41, KEY_PREVIOUSSONG },	/* Replay */
+	{ 0x42, KEY_NEXTSONG },		/* Skip */
+	{ 0x54, KEY_CAMERA },		/* Capture */
+/*	{ 0x50, KEY_SAP },	*/		/* Sap */
+	{ 0x47, KEY_CYCLEWINDOWS },	/* Pip */
+	{ 0x4d, KEY_SCREEN },		/* FullScreen */
+	{ 0x08, KEY_SUBTITLE },
+	{ 0x0e, KEY_MUTE },
+/*	{ 0x49, KEY_LR },	*/		/* L/R */
+	{ 0x07, KEY_SLEEP },		/* Hibernate */
+	{ 0x08, KEY_MEDIA },		/* A/V */
+	{ 0x0e, KEY_MENU },			/* Recall */
+	{ 0x45, KEY_ZOOMIN },
+	{ 0x46, KEY_ZOOMOUT },
+	{ 0x18, KEY_TV },			/* Red */
+	{ 0x53, KEY_VCR },			/* Green */
+	{ 0x5e, KEY_SAT },			/* Yellow */
+	{ 0x5f, KEY_PLAYER },		/* Blue */
+};
+
 /* DVB USB Driver stuff */
 static struct dvb_usb_device_properties megasky_properties;
 static struct dvb_usb_device_properties digivox_mini_ii_properties;
 static struct dvb_usb_device_properties tvwalkertwin_properties;
 static struct dvb_usb_device_properties dposh_properties;
+static struct dvb_usb_device_properties pinnacle_pctv310e_properties;
 
 static int m920x_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -652,6 +735,13 @@ static int m920x_probe(struct usb_interface *intf,
 			goto found;
 		}
 
+		ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties,
+					  THIS_MODULE, &d, adapter_nr);
+		if (ret == 0) {
+			rc_init_seq = pinnacle310e_init;
+			goto found;
+		}
+
 		return ret;
 	} else {
 		/* Another interface on a multi-tuner device */
@@ -682,6 +772,7 @@ static struct usb_device_id m920x_table [] = {
 			     USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) },
 		{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) },
 		{ USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) },
+		{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) },
 		{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, m920x_table);
@@ -895,6 +986,56 @@ static struct dvb_usb_device_properties dposh_properties = {
 	 }
 };
 
+static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.download_firmware = NULL,
+
+	.rc_interval      = 100,
+	.rc_key_map       = pinnacle310e_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(pinnacle310e_rc_keys),
+	.rc_query         = m920x_rc_query,
+
+	.size_of_priv     = sizeof(struct m920x_state),
+
+	.identify_state   = m920x_identify_state,
+	.num_adapters = 1,
+	.adapter = {{
+		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+		.pid_filter_count = 8,
+		.pid_filter       = m920x_pid_filter,
+		.pid_filter_ctrl  = m920x_pid_filter_ctrl,
+
+		.frontend_attach  = m920x_mt352_frontend_attach,
+		.tuner_attach     = m920x_fmd1216me_tuner_attach,
+
+		.stream = {
+			.type = USB_ISOC,
+			.count = 5,
+			.endpoint = 0x84,
+			.u = {
+				.isoc = {
+					.framesperurb = 128,
+					.framesize = 564,
+					.interval = 1,
+				}
+			}
+		},
+	} },
+	.i2c_algo         = &m920x_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "Pinnacle PCTV 310e",
+			{ &m920x_table[6], NULL },
+			{ NULL },
+		}
+	}
+};
+
 static struct usb_driver m920x_driver = {
 	.name		= "dvb_usb_m920x",
 	.probe		= m920x_probe,
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index 37532890accd..3c061518ffc1 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -18,7 +18,7 @@
 #define M9206_FW	0x30
 
 #define M9206_MAX_FILTERS 8
-#define M9206_MAX_ADAPTERS 2
+#define M9206_MAX_ADAPTERS 4
 
 /*
 sequences found in logs:
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index d4e230941679..830557696ae6 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -138,7 +138,7 @@ static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 					(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
 					msg[i].buf,
 					msg[i].len
-					)!= msg[i].len)) {
+					)) != msg[i].len) {
 			break;
 		}
 		if (dvb_usb_opera1_debug & 0x10)
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
index 7c5459c27b75..c3e0ec2dcfca 100644
--- a/drivers/media/dvb/firewire/firedtv-1394.c
+++ b/drivers/media/dvb/firewire/firedtv-1394.c
@@ -90,13 +90,14 @@ static inline struct node_entry *node_of(struct firedtv *fdtv)
 	return container_of(fdtv->device, struct unit_directory, device)->ne;
 }
 
-static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
 {
+	quadlet_t *d = data;
 	int ret;
 
-	ret = hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP,
-		(__force quadlet_t *)&data[1], (__force quadlet_t)data[0]);
-	data[0] = data[1];
+	ret = hpsb_node_lock(node_of(fdtv), addr,
+			     EXTCODE_COMPARE_SWAP, &d[1], d[0]);
+	d[0] = d[1];
 
 	return ret;
 }
@@ -192,9 +193,13 @@ static int node_probe(struct device *dev)
 	int kv_len, err;
 	void *kv_str;
 
-	kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
-	kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
-
+	if (ud->model_name_kv) {
+		kv_len = (ud->model_name_kv->value.leaf.len - 2) * 4;
+		kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
+	} else {
+		kv_len = 0;
+		kv_str = NULL;
+	}
 	fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
 	if (!fdtv)
 		return -ENOMEM;
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 50c42a4b972b..1b31bebc27d6 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -74,7 +74,6 @@
 #define EN50221_TAG_CA_INFO		0x9f8031
 
 struct avc_command_frame {
-	int length;
 	u8 ctype;
 	u8 subunit;
 	u8 opcode;
@@ -82,13 +81,27 @@ struct avc_command_frame {
 };
 
 struct avc_response_frame {
-	int length;
 	u8 response;
 	u8 subunit;
 	u8 opcode;
 	u8 operand[509];
 };
 
+#define LAST_OPERAND (509 - 1)
+
+static inline void clear_operands(struct avc_command_frame *c, int from, int to)
+{
+	memset(&c->operand[from], 0, to - from + 1);
+}
+
+static void pad_operands(struct avc_command_frame *c, int from)
+{
+	int to = ALIGN(from, 4);
+
+	if (from <= to && to <= LAST_OPERAND)
+		clear_operands(c, from, to);
+}
+
 #define AVC_DEBUG_READ_DESCRIPTOR              0x0001
 #define AVC_DEBUG_DSIT                         0x0002
 #define AVC_DEBUG_DSD                          0x0004
@@ -202,78 +215,65 @@ static void debug_pmt(char *msg, int length)
 		       16, 1, msg, length, false);
 }
 
-static int __avc_write(struct firedtv *fdtv,
-		const struct avc_command_frame *c, struct avc_response_frame *r)
+static int avc_write(struct firedtv *fdtv)
 {
 	int err, retry;
 
-	if (r)
-		fdtv->avc_reply_received = false;
+	fdtv->avc_reply_received = false;
 
 	for (retry = 0; retry < 6; retry++) {
 		if (unlikely(avc_debug))
-			debug_fcp(&c->ctype, c->length);
+			debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
 
 		err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
-					   (void *)&c->ctype, c->length);
+				fdtv->avc_data, fdtv->avc_data_length);
 		if (err) {
-			fdtv->avc_reply_received = true;
 			dev_err(fdtv->device, "FCP command write failed\n");
+
 			return err;
 		}
 
-		if (!r)
-			return 0;
-
 		/*
 		 * AV/C specs say that answers should be sent within 150 ms.
 		 * Time out after 200 ms.
 		 */
 		if (wait_event_timeout(fdtv->avc_wait,
 				       fdtv->avc_reply_received,
-				       msecs_to_jiffies(200)) != 0) {
-			r->length = fdtv->response_length;
-			memcpy(&r->response, fdtv->response, r->length);
-
+				       msecs_to_jiffies(200)) != 0)
 			return 0;
-		}
 	}
 	dev_err(fdtv->device, "FCP response timed out\n");
+
 	return -ETIMEDOUT;
 }
 
-static int avc_write(struct firedtv *fdtv,
-		const struct avc_command_frame *c, struct avc_response_frame *r)
+static bool is_register_rc(struct avc_response_frame *r)
 {
-	int ret;
-
-	if (mutex_lock_interruptible(&fdtv->avc_mutex))
-		return -EINTR;
-
-	ret = __avc_write(fdtv, c, r);
-
-	mutex_unlock(&fdtv->avc_mutex);
-	return ret;
+	return r->opcode     == AVC_OPCODE_VENDOR &&
+	       r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
+	       r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
+	       r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
+	       r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
 }
 
 int avc_recv(struct firedtv *fdtv, void *data, size_t length)
 {
-	struct avc_response_frame *r =
-			data - offsetof(struct avc_response_frame, response);
+	struct avc_response_frame *r = data;
 
 	if (unlikely(avc_debug))
 		debug_fcp(data, length);
 
-	if (length >= 8 &&
-	    r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
-	    r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
-	    r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
-	    r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
-		if (r->response == AVC_RESPONSE_CHANGED) {
-			fdtv_handle_rc(fdtv,
-			    r->operand[4] << 8 | r->operand[5]);
+	if (length >= 8 && is_register_rc(r)) {
+		switch (r->response) {
+		case AVC_RESPONSE_CHANGED:
+			fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
 			schedule_work(&fdtv->remote_ctrl_work);
-		} else if (r->response != AVC_RESPONSE_INTERIM) {
+			break;
+		case AVC_RESPONSE_INTERIM:
+			if (is_register_rc((void *)fdtv->avc_data))
+				goto wake;
+			break;
+		default:
 			dev_info(fdtv->device,
 				 "remote control result = %d\n", r->response);
 		}
@@ -285,9 +285,9 @@ int avc_recv(struct firedtv *fdtv, void *data, size_t length)
 		return -EIO;
 	}
 
-	memcpy(fdtv->response, data, length);
-	fdtv->response_length = length;
-
+	memcpy(fdtv->avc_data, data, length);
+	fdtv->avc_data_length = length;
+wake:
 	fdtv->avc_reply_received = true;
 	wake_up(&fdtv->avc_wait);
 
@@ -318,10 +318,11 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
  * tuning command for setting the relative LNB frequency
  * (not supported by the AVC standard)
  */
-static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
-			       struct dvb_frontend_parameters *params,
-			       struct avc_command_frame *c)
+static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
+			      struct dvb_frontend_parameters *params)
 {
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+
 	c->opcode = AVC_OPCODE_VENDOR;
 
 	c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
@@ -370,16 +371,18 @@ static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
 		c->operand[13] = 0x1;
 		c->operand[14] = 0xff;
 		c->operand[15] = 0xff;
-		c->length = 20;
+
+		return 16;
 	} else {
-		c->length = 16;
+		return 13;
 	}
 }
 
-static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
-				struct dvb_frontend_parameters *params,
-				struct avc_command_frame *c)
+static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
+			       struct dvb_frontend_parameters *params)
 {
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+
 	c->opcode = AVC_OPCODE_DSD;
 
 	c->operand[0] = 0;    /* source plug */
@@ -440,15 +443,14 @@ static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
 	c->operand[20] = 0x00;
 	c->operand[21] = 0x00;
 
-	/* Add PIDs to filter */
-	c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
+	return 22 + add_pid_filter(fdtv, &c->operand[22]);
 }
 
-static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
-				struct dvb_frontend_parameters *params,
-				struct avc_command_frame *c)
+static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
+			       struct dvb_frontend_parameters *params)
 {
 	struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
 
 	c->opcode = AVC_OPCODE_DSD;
 
@@ -543,55 +545,58 @@ static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
 	c->operand[15] = 0x00; /* network_ID[0] */
 	c->operand[16] = 0x00; /* network_ID[1] */
 
-	/* Add PIDs to filter */
-	c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
+	return 17 + add_pid_filter(fdtv, &c->operand[17]);
 }
 
 int avc_tuner_dsd(struct firedtv *fdtv,
 		  struct dvb_frontend_parameters *params)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int pos, ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
 
 	switch (fdtv->type) {
 	case FIREDTV_DVB_S:
-	case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
-	case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break;
-	case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break;
+	case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
+	case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
+	case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
 	default:
 		BUG();
 	}
+	pad_operands(c, pos);
 
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
-
-	msleep(500);
+	fdtv->avc_data_length = ALIGN(3 + pos, 4);
+	ret = avc_write(fdtv);
 #if 0
-	/* FIXME: */
-	/* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
+	/*
+	 * FIXME:
+	 * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
+	 * Check for AVC_RESPONSE_ACCEPTED here instead?
+	 */
 	if (status)
 		*status = r->operand[2];
 #endif
-	return 0;
+	mutex_unlock(&fdtv->avc_mutex);
+
+	if (ret == 0)
+		msleep(500);
+
+	return ret;
 }
 
 int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
-	int pos, k;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret, pos, k;
 
 	if (pidc > 16 && pidc != 0xff)
 		return -EINVAL;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -614,24 +619,27 @@ int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
 			c->operand[pos++] = 0x00; /* tableID */
 			c->operand[pos++] = 0x00; /* filter_length */
 		}
+	pad_operands(c, pos);
 
-	c->length = ALIGN(3 + pos, 4);
+	fdtv->avc_data_length = ALIGN(3 + pos, 4);
+	ret = avc_write(fdtv);
 
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	/* FIXME: check response code? */
 
-	msleep(50);
-	return 0;
+	mutex_unlock(&fdtv->avc_mutex);
+
+	if (ret == 0)
+		msleep(50);
+
+	return ret;
 }
 
 int avc_tuner_get_ts(struct firedtv *fdtv)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
-	int sl;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret, sl;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -646,26 +654,33 @@ int avc_tuner_get_ts(struct firedtv *fdtv)
 	c->operand[4] = 0x00;	/* antenna number */
 	c->operand[5] = 0x0; 	/* system_specific_search_flags */
 	c->operand[6] = sl;	/* system_specific_multiplex selection_length */
-	c->operand[7] = 0x00;	/* valid_flags [0] */
-	c->operand[8] = 0x00;	/* valid_flags [1] */
-	c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
+	/*
+	 * operand[7]: valid_flags[0]
+	 * operand[8]: valid_flags[1]
+	 * operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
+	 */
+	clear_operands(c, 7, 24);
 
-	c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+	fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+	ret = avc_write(fdtv);
 
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	/* FIXME: check response code? */
 
-	msleep(250);
-	return 0;
+	mutex_unlock(&fdtv->avc_mutex);
+
+	if (ret == 0)
+		msleep(250);
+
+	return ret;
 }
 
 int avc_identify_subunit(struct firedtv *fdtv)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -678,31 +693,34 @@ int avc_identify_subunit(struct firedtv *fdtv)
 	c->operand[4] = 0x08; /* length lowbyte  */
 	c->operand[5] = 0x00; /* offset highbyte */
 	c->operand[6] = 0x0d; /* offset lowbyte  */
+	clear_operands(c, 7, 8); /* padding */
 
-	c->length = 12;
-
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
 	if ((r->response != AVC_RESPONSE_STABLE &&
 	     r->response != AVC_RESPONSE_ACCEPTED) ||
 	    (r->operand[3] << 8) + r->operand[4] != 8) {
 		dev_err(fdtv->device, "cannot read subunit identifier\n");
-		return -EINVAL;
+		ret = -EINVAL;
 	}
-	return 0;
+out:
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
 }
 
 #define SIZEOF_ANTENNA_INPUT_INFO 22
 
 int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
-	int length;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int length, ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -710,27 +728,30 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
 
 	c->operand[0] = DESCRIPTOR_TUNER_STATUS;
 	c->operand[1] = 0xff;	/* read_result_status */
-	c->operand[2] = 0x00;	/* reserved */
-	c->operand[3] = 0;	/* SIZEOF_ANTENNA_INPUT_INFO >> 8; */
-	c->operand[4] = 0;	/* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */
-	c->operand[5] = 0x00;
-	c->operand[6] = 0x00;
-
-	c->length = 12;
-
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	/*
+	 * operand[2]: reserved
+	 * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
+	 * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
+	 */
+	clear_operands(c, 2, 31);
+
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
 	if (r->response != AVC_RESPONSE_STABLE &&
 	    r->response != AVC_RESPONSE_ACCEPTED) {
 		dev_err(fdtv->device, "cannot read tuner status\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	length = r->operand[9];
 	if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
 		dev_err(fdtv->device, "got invalid tuner status\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	stat->active_system		= r->operand[10];
@@ -766,20 +787,21 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
 	stat->ca_dvb_flag		= r->operand[31] >> 3 & 1;
 	stat->ca_error_flag		= r->operand[31] >> 2 & 1;
 	stat->ca_initialization_status	= r->operand[31] >> 1 & 1;
+out:
+	mutex_unlock(&fdtv->avc_mutex);
 
-	return 0;
+	return ret;
 }
 
 int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
 		    char conttone, char nrdiseq,
 		    struct dvb_diseqc_master_cmd *diseqcmd)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
-	int i, j, k;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int pos, j, k, ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -789,41 +811,41 @@ int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
 	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
 	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
 	c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
-
 	c->operand[4] = voltage;
 	c->operand[5] = nrdiseq;
 
-	i = 6;
-
+	pos = 6;
 	for (j = 0; j < nrdiseq; j++) {
-		c->operand[i++] = diseqcmd[j].msg_len;
+		c->operand[pos++] = diseqcmd[j].msg_len;
 
 		for (k = 0; k < diseqcmd[j].msg_len; k++)
-			c->operand[i++] = diseqcmd[j].msg[k];
+			c->operand[pos++] = diseqcmd[j].msg[k];
 	}
+	c->operand[pos++] = burst;
+	c->operand[pos++] = conttone;
+	pad_operands(c, pos);
 
-	c->operand[i++] = burst;
-	c->operand[i++] = conttone;
-
-	c->length = ALIGN(3 + i, 4);
-
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	fdtv->avc_data_length = ALIGN(3 + pos, 4);
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
 	if (r->response != AVC_RESPONSE_ACCEPTED) {
 		dev_err(fdtv->device, "LNB control failed\n");
-		return -EINVAL;
+		ret = -EINVAL;
 	}
+out:
+	mutex_unlock(&fdtv->avc_mutex);
 
-	return 0;
+	return ret;
 }
 
 int avc_register_remote_control(struct firedtv *fdtv)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_NOTIFY;
 	c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
@@ -833,10 +855,16 @@ int avc_register_remote_control(struct firedtv *fdtv)
 	c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
 	c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
 	c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
+	c->operand[4] = 0; /* padding */
+
+	fdtv->avc_data_length = 8;
+	ret = avc_write(fdtv);
 
-	c->length = 8;
+	/* FIXME: check response code? */
 
-	return avc_write(fdtv, c, NULL);
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
 }
 
 void avc_remote_ctrl_work(struct work_struct *work)
@@ -851,11 +879,10 @@ void avc_remote_ctrl_work(struct work_struct *work)
 #if 0 /* FIXME: unused */
 int avc_tuner_host2ca(struct firedtv *fdtv)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -867,15 +894,16 @@ int avc_tuner_host2ca(struct firedtv *fdtv)
 	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
 	c->operand[4] = 0; /* slot */
 	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
-	c->operand[6] = 0; /* more/last */
-	c->operand[7] = 0; /* length */
+	clear_operands(c, 6, 8);
 
-	c->length = 12;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
 
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	/* FIXME: check response code? */
 
-	return 0;
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
 }
 #endif
 
@@ -906,12 +934,11 @@ static int get_ca_object_length(struct avc_response_frame *r)
 
 int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
-	int pos;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int pos, ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_STATUS;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -923,11 +950,12 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
 	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
 	c->operand[4] = 0; /* slot */
 	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+	clear_operands(c, 6, LAST_OPERAND);
 
-	c->length = 12;
-
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
 	/* FIXME: check response code and validate response data */
 
@@ -939,18 +967,19 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
 	app_info[4] = 0x01;
 	memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
 	*len = app_info[3] + 4;
+out:
+	mutex_unlock(&fdtv->avc_mutex);
 
-	return 0;
+	return ret;
 }
 
 int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
-	int pos;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int pos, ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_STATUS;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -962,11 +991,14 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
 	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
 	c->operand[4] = 0; /* slot */
 	c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+	clear_operands(c, 6, LAST_OPERAND);
 
-	c->length = 12;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	/* FIXME: check response code and validate response data */
 
 	pos = get_ca_object_pos(r);
 	app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
@@ -976,17 +1008,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
 	app_info[4] = r->operand[pos + 0];
 	app_info[5] = r->operand[pos + 1];
 	*len = app_info[3] + 4;
+out:
+	mutex_unlock(&fdtv->avc_mutex);
 
-	return 0;
+	return ret;
 }
 
 int avc_ca_reset(struct firedtv *fdtv)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1002,19 +1035,20 @@ int avc_ca_reset(struct firedtv *fdtv)
 	c->operand[7] = 1; /* length */
 	c->operand[8] = 0; /* force hardware reset */
 
-	c->length = 12;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
 
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	/* FIXME: check response code? */
 
-	return 0;
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
 }
 
 int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
 	int list_management;
 	int program_info_length;
 	int pmt_cmd_id;
@@ -1022,11 +1056,12 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
 	int write_pos;
 	int es_info_length;
 	int crc32_csum;
+	int ret;
 
 	if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
 		debug_pmt(msg, length);
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_CONTROL;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1058,7 +1093,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
 
 	c->operand[12] = 0x02; /* Table id=2 */
 	c->operand[13] = 0x80; /* Section syntax + length */
-	/* c->operand[14] = XXXprogram_info_length + 12; */
+
 	c->operand[15] = msg[1]; /* Program number */
 	c->operand[16] = msg[2];
 	c->operand[17] = 0x01; /* Version number=0 + current/next=1 */
@@ -1106,12 +1141,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
 			write_pos += es_info_length;
 		}
 	}
-
-	/* CRC */
-	c->operand[write_pos++] = 0x00;
-	c->operand[write_pos++] = 0x00;
-	c->operand[write_pos++] = 0x00;
-	c->operand[write_pos++] = 0x00;
+	write_pos += 4; /* CRC */
 
 	c->operand[7] = 0x82;
 	c->operand[8] = (write_pos - 10) >> 8;
@@ -1123,28 +1153,31 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
 	c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
 	c->operand[write_pos - 2] = (crc32_csum >>  8) & 0xff;
 	c->operand[write_pos - 1] = (crc32_csum >>  0) & 0xff;
+	pad_operands(c, write_pos);
 
-	c->length = ALIGN(3 + write_pos, 4);
-
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
 	if (r->response != AVC_RESPONSE_ACCEPTED) {
 		dev_err(fdtv->device,
 			"CA PMT failed with response 0x%x\n", r->response);
-		return -EFAULT;
+		ret = -EFAULT;
 	}
+out:
+	mutex_unlock(&fdtv->avc_mutex);
 
-	return 0;
+	return ret;
 }
 
 int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_STATUS;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1156,28 +1189,28 @@ int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
 	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
 	c->operand[4] = 0; /* slot */
 	c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
-	c->operand[6] = 0; /* more/last */
-	c->operand[7] = 0; /* length */
+	clear_operands(c, 6, LAST_OPERAND);
 
-	c->length = 12;
-
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
 	/* FIXME: check response code and validate response data */
 
 	*interval = r->operand[get_ca_object_pos(r)];
+out:
+	mutex_unlock(&fdtv->avc_mutex);
 
-	return 0;
+	return ret;
 }
 
 int avc_ca_enter_menu(struct firedtv *fdtv)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	int ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_STATUS;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1189,24 +1222,25 @@ int avc_ca_enter_menu(struct firedtv *fdtv)
 	c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
 	c->operand[4] = 0; /* slot */
 	c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
-	c->operand[6] = 0; /* more/last */
-	c->operand[7] = 0; /* length */
+	clear_operands(c, 6, 8);
 
-	c->length = 12;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
 
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	/* FIXME: check response code? */
 
-	return 0;
+	mutex_unlock(&fdtv->avc_mutex);
+
+	return ret;
 }
 
 int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
 {
-	char buffer[sizeof(struct avc_command_frame)];
-	struct avc_command_frame *c = (void *)buffer;
-	struct avc_response_frame *r = (void *)buffer;
+	struct avc_command_frame *c = (void *)fdtv->avc_data;
+	struct avc_response_frame *r = (void *)fdtv->avc_data;
+	int ret;
 
-	memset(c, 0, sizeof(*c));
+	mutex_lock(&fdtv->avc_mutex);
 
 	c->ctype   = AVC_CTYPE_STATUS;
 	c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1218,20 +1252,21 @@ int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
 	c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
 	c->operand[4] = 0; /* slot */
 	c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
-	c->operand[6] = 0; /* more/last */
-	c->operand[7] = 0; /* length */
+	clear_operands(c, 6, LAST_OPERAND);
 
-	c->length = 12;
-
-	if (avc_write(fdtv, c, r) < 0)
-		return -EIO;
+	fdtv->avc_data_length = 12;
+	ret = avc_write(fdtv);
+	if (ret < 0)
+		goto out;
 
 	/* FIXME: check response code and validate response data */
 
 	*len = get_ca_object_length(r);
 	memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
+out:
+	mutex_unlock(&fdtv->avc_mutex);
 
-	return 0;
+	return ret;
 }
 
 #define CMP_OUTPUT_PLUG_CONTROL_REG_0	0xfffff0000904ULL
@@ -1240,14 +1275,14 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
 {
 	int ret;
 
-	if (mutex_lock_interruptible(&fdtv->avc_mutex))
-		return -EINTR;
+	mutex_lock(&fdtv->avc_mutex);
 
 	ret = fdtv->backend->read(fdtv, addr, data);
 	if (ret < 0)
 		dev_err(fdtv->device, "CMP: read I/O error\n");
 
 	mutex_unlock(&fdtv->avc_mutex);
+
 	return ret;
 }
 
@@ -1255,14 +1290,19 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
 {
 	int ret;
 
-	if (mutex_lock_interruptible(&fdtv->avc_mutex))
-		return -EINTR;
+	mutex_lock(&fdtv->avc_mutex);
+
+	/* data[] is stack-allocated and should not be DMA-mapped. */
+	memcpy(fdtv->avc_data, data, 8);
 
-	ret = fdtv->backend->lock(fdtv, addr, data);
+	ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data);
 	if (ret < 0)
 		dev_err(fdtv->device, "CMP: lock I/O error\n");
+	else
+		memcpy(data, fdtv->avc_data, 8);
 
 	mutex_unlock(&fdtv->avc_mutex);
+
 	return ret;
 }
 
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
index fc9996c13e13..079e8c5b0475 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -277,7 +277,6 @@ struct firedtv *fdtv_alloc(struct device *dev,
 
 	mutex_init(&fdtv->avc_mutex);
 	init_waitqueue_head(&fdtv->avc_wait);
-	fdtv->avc_reply_received = true;
 	mutex_init(&fdtv->demux_mutex);
 	INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
 
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 6223bf01efe9..7a3de16fba06 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -41,7 +41,7 @@ static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
 	return rcode != RCODE_COMPLETE ? -EIO : 0;
 }
 
-static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
 {
 	return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
 }
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
index 35080dbb3c66..78cc28f36914 100644
--- a/drivers/media/dvb/firewire/firedtv.h
+++ b/drivers/media/dvb/firewire/firedtv.h
@@ -73,7 +73,7 @@ struct input_dev;
 struct firedtv;
 
 struct firedtv_backend {
-	int (*lock)(struct firedtv *fdtv, u64 addr, __be32 data[]);
+	int (*lock)(struct firedtv *fdtv, u64 addr, void *data);
 	int (*read)(struct firedtv *fdtv, u64 addr, void *data);
 	int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
 	int (*start_iso)(struct firedtv *fdtv);
@@ -114,8 +114,8 @@ struct firedtv {
 	unsigned long		channel_active;
 	u16			channel_pid[16];
 
-	size_t			response_length;
-	u8			response[512];
+	int			avc_data_length;
+	u8			avc_data[512];
 };
 
 /* firedtv-1394.c */
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
index 28b90c91c766..e90fa92b1c1d 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -44,6 +44,7 @@ enum af9013_tuner {
 	AF9013_TUNER_MT2060_2   = 147, /* Microtune */
 	AF9013_TUNER_TDA18271   = 156, /* NXP */
 	AF9013_TUNER_QT1010A    = 162, /* Quantek */
+	AF9013_TUNER_TDA18218   = 179, /* NXP */
 };
 
 /* AF9013/5 GPIOs (mostly guessed)
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
index 59881a5944eb..43aac2f85c2e 100644
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ b/drivers/media/dvb/frontends/atbm8830.c
@@ -170,6 +170,19 @@ static int is_locked(struct atbm_state *priv, u8 *locked)
 	return 0;
 }
 
+static int set_agc_config(struct atbm_state *priv,
+	u8 min, u8 max, u8 hold_loop)
+{
+	/* no effect if both min and max are zero */
+	if (!min && !max)
+	    return 0;
+
+	atbm8830_write_reg(priv, REG_AGC_MIN, min);
+	atbm8830_write_reg(priv, REG_AGC_MAX, max);
+	atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
+
+	return 0;
+}
 
 static int set_static_channel_mode(struct atbm_state *priv)
 {
@@ -227,6 +240,9 @@ static int atbm8830_init(struct dvb_frontend *fe)
 	/*Set IF frequency*/
 	set_if_freq(priv, cfg->if_freq);
 
+	/*Set AGC Config*/
+	set_agc_config(priv, cfg->agc_min, cfg->agc_max,
+		cfg->agc_hold_loop);
 
 	/*Set static channel mode*/
 	set_static_channel_mode(priv);
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
index 614552709a6f..7eac178f57b2 100644
--- a/drivers/media/dvb/frontends/dib0090.c
+++ b/drivers/media/dvb/frontends/dib0090.c
@@ -283,7 +283,7 @@ static int dib0090_sleep(struct dvb_frontend *fe)
 	return 0;
 }
 
-extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
+void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
 {
 	struct dib0090_state *state = fe->tuner_priv;
 	if (fast)
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
index 6f6fa29d9ea4..2aa97dd6a8af 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb/frontends/dib8000.c
@@ -1999,6 +1999,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
 	struct dib8000_state *state = fe->demodulator_priv;
 	int time, ret;
 
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
 	dib8000_set_output_mode(state, OUTMODE_HIGH_Z);
 
 	if (fe->ops.tuner_ops.set_params)
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index e6f3d73db9d3..980e02f1575e 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -174,7 +174,7 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
 EXPORT_SYMBOL(dibx000_exit_i2c_master);
 
 
-u32 systime()
+u32 systime(void)
 {
     struct timespec t;
 
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
index b181bf023ada..13437259eeac 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -158,7 +158,8 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
 	/* override frontend ops */
 	fe->ops.set_voltage = lnbp21_set_voltage;
 	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-	fe->ops.set_tone = lnbp21_set_tone;
+	if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/
+		fe->ops.set_tone = lnbp21_set_tone;
 	printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
 
 	return fe;
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
index 9552a22ccffb..d21a327db629 100644
--- a/drivers/media/dvb/frontends/si21xx.c
+++ b/drivers/media/dvb/frontends/si21xx.c
@@ -97,8 +97,6 @@
 #define	LNB_SUPPLY_CTRL_REG_4		0xce
 #define	LNB_SUPPLY_STATUS_REG		0xcf
 
-#define FALSE	0
-#define TRUE	1
 #define FAIL	-1
 #define PASS	0
 
@@ -718,7 +716,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
 	int fine_tune_freq;
 	unsigned char sample_rate = 0;
 	/* boolean */
-	unsigned int inband_interferer_ind;
+	bool inband_interferer_ind;
 
 	/* INTERMEDIATE VALUES */
 	int icoarse_tune_freq; /* MHz */
@@ -728,15 +726,8 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
 	unsigned int x1;
 	unsigned int x2;
 	int i;
-	unsigned int inband_interferer_div2[ALLOWABLE_FS_COUNT] = {
-			FALSE, FALSE, FALSE, FALSE, FALSE,
-			FALSE, FALSE, FALSE, FALSE, FALSE
-	};
-	unsigned int inband_interferer_div4[ALLOWABLE_FS_COUNT] = {
-			FALSE, FALSE, FALSE, FALSE, FALSE,
-			FALSE, FALSE, FALSE, FALSE, FALSE
-	};
-
+	bool inband_interferer_div2[ALLOWABLE_FS_COUNT];
+	bool inband_interferer_div4[ALLOWABLE_FS_COUNT];
 	int status;
 
 	/* allowable sample rates for ADC in MHz */
@@ -762,7 +753,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
 	}
 
 	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
-		inband_interferer_div2[i] = inband_interferer_div4[i] = FALSE;
+		inband_interferer_div2[i] = inband_interferer_div4[i] = false;
 
 	if_limit_high = -700000;
 	if_limit_low = -100000;
@@ -798,7 +789,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
 
 		if (((band_low < x1) && (x1 < band_high)) ||
 					((band_low < x2) && (x2 < band_high)))
-					inband_interferer_div4[i] = TRUE;
+					inband_interferer_div4[i] = true;
 
 	}
 
@@ -811,25 +802,28 @@ static int si21xx_set_frontend(struct dvb_frontend *fe,
 
 		if (((band_low < x1) && (x1 < band_high)) ||
 					((band_low < x2) && (x2 < band_high)))
-					inband_interferer_div2[i] = TRUE;
+					inband_interferer_div2[i] = true;
 	}
 
-	inband_interferer_ind = TRUE;
-	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i)
-		inband_interferer_ind &= inband_interferer_div2[i] |
-						inband_interferer_div4[i];
+	inband_interferer_ind = true;
+	for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
+		if (inband_interferer_div2[i] || inband_interferer_div4[i]) {
+			inband_interferer_ind = false;
+			break;
+		}
+	}
 
 	if (inband_interferer_ind) {
 		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
-			if (inband_interferer_div2[i] == FALSE) {
+			if (!inband_interferer_div2[i]) {
 				sample_rate = (u8) afs[i];
 				break;
 			}
 		}
 	} else {
 		for (i = 0; i < ALLOWABLE_FS_COUNT; ++i) {
-			if ((inband_interferer_div2[i] |
-					inband_interferer_div4[i]) == FALSE) {
+			if ((inband_interferer_div2[i] ||
+			     !inband_interferer_div4[i])) {
 				sample_rate = (u8) afs[i];
 				break;
 			}
diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h
index 29c3fa85c227..e3e35d1ce838 100644
--- a/drivers/media/dvb/frontends/stv0900.h
+++ b/drivers/media/dvb/frontends/stv0900.h
@@ -49,6 +49,8 @@ struct stv0900_config {
 	u8 tun2_maddress;
 	u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
 	u8 tun2_adc;
+	u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
+	u8 tun2_type;
 	/* Set device param to start dma */
 	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
 };
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
index 8762c86044a5..01f8f1f802fd 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb/frontends/stv0900_core.c
@@ -177,7 +177,7 @@ u8 stv0900_read_reg(struct stv0900_internal *intp, u16 reg)
 	return buf;
 }
 
-void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
+static void extract_mask_pos(u32 label, u8 *mask, u8 *pos)
 {
 	u8 position = 0, i = 0;
 
@@ -218,7 +218,7 @@ u8 stv0900_get_bits(struct stv0900_internal *intp, u32 label)
 	return val;
 }
 
-enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
+static enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
 {
 	s32 i;
 
@@ -282,7 +282,7 @@ enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *intp)
 	return STV0900_NO_ERROR;
 }
 
-u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
+static u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
 {
 	u32 mclk = 90000000, div = 0, ad_div = 0;
 
@@ -296,7 +296,7 @@ u32 stv0900_get_mclk_freq(struct stv0900_internal *intp, u32 ext_clk)
 	return mclk;
 }
 
-enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
+static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
 {
 	u32 m_div, clk_sel;
 
@@ -334,7 +334,7 @@ enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 mclk)
 	return STV0900_NO_ERROR;
 }
 
-u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
+static u32 stv0900_get_err_count(struct stv0900_internal *intp, int cntr,
 					enum fe_stv0900_demod_num demod)
 {
 	u32 lsb, msb, hsb, err_val;
@@ -567,6 +567,46 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
 	}
 }
 
+u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
+{
+	u32 freq, round;
+	/*	Formulat :
+	Tuner_Frequency(MHz)	= Regs / 64
+	Tuner_granularity(MHz)	= Regs / 2048
+	real_Tuner_Frequency	= Tuner_Frequency(MHz) - Tuner_granularity(MHz)
+	*/
+	freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
+		(stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
+		stv0900_get_bits(intp, TUN_RFFREQ0);
+
+	freq = (freq * 1000) / 64;
+
+	round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
+		stv0900_get_bits(intp, TUN_RFRESTE0);
+
+	round = (round * 1000) / 2048;
+
+	return freq + round;
+}
+
+void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+						u32 Bandwidth, int demod)
+{
+	u32 tunerFrequency;
+	/* Formulat:
+	Tuner_frequency_reg= Frequency(MHz)*64
+	*/
+	tunerFrequency = (Frequency * 64) / 1000;
+
+	stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
+	stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
+	stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
+	/* Low Pass Filter = BW /2 (MHz)*/
+	stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
+	/* Tuner Write trig */
+	stv0900_write_reg(intp, TNRLD, 1);
+}
+
 static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
 				const struct stv0900_table *lookup,
 				enum fe_stv0900_demod_num demod)
@@ -1329,7 +1369,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
 	enum fe_stv0900_error error = STV0900_NO_ERROR;
 	enum fe_stv0900_error demodError = STV0900_NO_ERROR;
 	struct stv0900_internal *intp = NULL;
-
 	int selosci, i;
 
 	struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
@@ -1345,7 +1384,14 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
 	} else {
 		state->internal = kmalloc(sizeof(struct stv0900_internal),
 								GFP_KERNEL);
+		if (state->internal == NULL)
+			return STV0900_INVALID_HANDLE;
 		temp_int = append_internal(state->internal);
+		if (temp_int == NULL) {
+			kfree(state->internal);
+			state->internal = NULL;
+			return STV0900_INVALID_HANDLE;
+		}
 		state->internal->dmds_used = 1;
 		state->internal->i2c_adap = state->i2c_adap;
 		state->internal->i2c_addr = state->config->demod_address;
@@ -1371,11 +1417,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
 		return error;
 	}
 
-	if (state->internal == NULL) {
-		error = STV0900_INVALID_HANDLE;
-		return error;
-	}
-
 	intp = state->internal;
 
 	intp->demod_mode = p_init->demod_mode;
@@ -1404,6 +1445,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
 		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
 	}
 
+	intp->tuner_type[0] = p_init->tuner1_type;
+	intp->tuner_type[1] = p_init->tuner2_type;
+	/* tuner init */
+	switch (p_init->tuner1_type) {
+	case 3: /*FE_AUTO_STB6100:*/
+		stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
+		stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
+		stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
+		stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
+		stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
+		stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
+		stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
+		stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
+		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
+		break;
+	/* case FE_SW_TUNER: */
+	default:
+		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
+		break;
+	}
+
 	stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
 	switch (p_init->tuner1_adc) {
 	case 1:
@@ -1413,6 +1475,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
 		break;
 	}
 
+	stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */
+
+	/* tuner init */
+	switch (p_init->tuner2_type) {
+	case 3: /*FE_AUTO_STB6100:*/
+		stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
+		stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
+		stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
+		stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
+		stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
+		stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
+		stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
+		stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
+		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
+		break;
+	/* case FE_SW_TUNER: */
+	default:
+		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
+		break;
+	}
+
 	stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
 	switch (p_init->tuner2_adc) {
 	case 1:
@@ -1422,6 +1505,8 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
 		break;
 	}
 
+	stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */
+
 	stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
 	stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
 	stv0900_set_mclk(intp, 135000000);
@@ -1824,10 +1909,12 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
 		init_params.tun1_maddress	= config->tun1_maddress;
 		init_params.tun1_iq_inv		= STV0900_IQ_NORMAL;
 		init_params.tuner1_adc		= config->tun1_adc;
+		init_params.tuner1_type		= config->tun1_type;
 		init_params.path2_ts_clock	= config->path2_mode;
 		init_params.ts_config		= config->ts_config_regs;
 		init_params.tun2_maddress	= config->tun2_maddress;
 		init_params.tuner2_adc		= config->tun2_adc;
+		init_params.tuner2_type		= config->tun2_type;
 		init_params.tun2_iq_inv		= STV0900_IQ_SWAPPED;
 
 		err_stv0900 = stv0900_init_internal(&state->frontend,
diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h
index d8ba8a984abe..b62b0f0a4fef 100644
--- a/drivers/media/dvb/frontends/stv0900_priv.h
+++ b/drivers/media/dvb/frontends/stv0900_priv.h
@@ -247,6 +247,7 @@ struct stv0900_init_params{
 
 	u8	tun1_maddress;
 	int	tuner1_adc;
+	int 	tuner1_type;
 
 	/* IQ from the tuner1 to the demod */
 	enum stv0900_iq_inversion	tun1_iq_inv;
@@ -254,6 +255,7 @@ struct stv0900_init_params{
 
 	u8	tun2_maddress;
 	int	tuner2_adc;
+	int	tuner2_type;
 
 	/* IQ from the tuner2 to the demod */
 	enum stv0900_iq_inversion	tun2_iq_inv;
@@ -309,6 +311,8 @@ struct stv0900_internal{
 	s32	bw[2];
 	s32	symbol_rate[2];
 	s32	srch_range[2];
+	/* for software/auto tuner */
+	int	tuner_type[2];
 
 	/* algorithm for search Blind, Cold or Warm*/
 	enum fe_stv0900_search_algo	srch_algo[2];
@@ -394,4 +398,11 @@ extern enum
 fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
 				enum fe_stv0900_demod_num demod);
 
+extern u32
+stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);
+
+extern void
+stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+						u32 Bandwidth, int demod);
+
 #endif
diff --git a/drivers/media/dvb/frontends/stv0900_reg.h b/drivers/media/dvb/frontends/stv0900_reg.h
index 7b8edf192e97..731afe93a823 100644
--- a/drivers/media/dvb/frontends/stv0900_reg.h
+++ b/drivers/media/dvb/frontends/stv0900_reg.h
@@ -3174,17 +3174,21 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
 #define R0900_P1_TNRRF1 0xf4e9
 #define TNRRF1 REGx(R0900_P1_TNRRF1)
 #define F0900_P1_TUN_RFFREQ2 0xf4e900ff
+#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)
 
 /*P1_TNRRF0*/
 #define R0900_P1_TNRRF0 0xf4ea
 #define TNRRF0 REGx(R0900_P1_TNRRF0)
 #define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
+#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)
 
 /*P1_TNRBW*/
 #define R0900_P1_TNRBW 0xf4eb
 #define TNRBW REGx(R0900_P1_TNRBW)
 #define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
+#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
 #define F0900_P1_TUN_BW 0xf4eb003f
+#define TUN_BW FLDx(F0900_P1_TUN_BW)
 
 /*P1_TNRADJ*/
 #define R0900_P1_TNRADJ 0xf4ec
@@ -3234,11 +3238,13 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
 #define F0900_P1_TUN_I2CLOCKED 0xf4f60010
 #define F0900_P1_TUN_PROGDONE 0xf4f6000c
 #define F0900_P1_TUN_RFRESTE1 0xf4f60003
+#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)
 
 /*P1_TNRRESTE*/
 #define R0900_P1_TNRRESTE 0xf4f7
 #define TNRRESTE REGx(R0900_P1_TNRRESTE)
 #define F0900_P1_TUN_RFRESTE0 0xf4f700ff
+#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)
 
 /*P1_SMAPCOEF7*/
 #define R0900_P1_SMAPCOEF7 0xf500
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
index b8da87fa637f..ba0709b2d433 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb/frontends/stv0900_sw.c
@@ -193,7 +193,7 @@ static int stv0900_search_carr_sw_loop(struct stv0900_internal *intp,
 	return lock;
 }
 
-int stv0900_sw_algo(struct stv0900_internal *intp,
+static int stv0900_sw_algo(struct stv0900_internal *intp,
 				enum fe_stv0900_demod_num demod)
 {
 	int	lock = FALSE,
@@ -606,7 +606,12 @@ static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
 			tuner_freq -= (current_step * currier_step);
 
 		if (intp->chip_id <= 0x20) {
-			stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+			if (intp->tuner_type[d] == 3)
+				stv0900_set_tuner_auto(intp, tuner_freq,
+						intp->bw[d], demod);
+			else
+				stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+
 			stv0900_write_reg(intp, DMDISTATE, 0x1c);
 			stv0900_write_reg(intp, CFRINIT1, 0);
 			stv0900_write_reg(intp, CFRINIT0, 0);
@@ -790,7 +795,7 @@ static enum fe_stv0900_fec stv0900_get_vit_fec(struct stv0900_internal *intp,
 	return prate;
 }
 
-void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
+static void stv0900_set_dvbs1_track_car_loop(struct stv0900_internal *intp,
 					enum fe_stv0900_demod_num demod,
 					u32 srate)
 {
@@ -976,8 +981,16 @@ static void stv0900_track_optimization(struct dvb_frontend *fe)
 					intp->rolloff) + 10000000;
 
 		if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
-			if (intp->srch_algo[demod] != STV0900_WARM_START)
-				stv0900_set_bandwidth(fe, intp->bw[demod]);
+			if (intp->srch_algo[demod] != STV0900_WARM_START) {
+				if (intp->tuner_type[demod] == 3)
+					stv0900_set_tuner_auto(intp,
+							intp->freq[demod],
+							intp->bw[demod],
+							demod);
+				else
+					stv0900_set_bandwidth(fe,
+							intp->bw[demod]);
+			}
 		}
 
 		if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
@@ -1202,7 +1215,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
 	}
 
 	result->standard = stv0900_get_standard(fe, d);
-	result->frequency = stv0900_get_tuner_freq(fe);
+	if (intp->tuner_type[demod] == 3)
+		result->frequency = stv0900_get_freq_auto(intp, d);
+	else
+		result->frequency = stv0900_get_tuner_freq(fe);
+
 	offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
 	result->frequency += offsetFreq;
 	result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
@@ -1213,6 +1230,9 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
 	result->pilot = stv0900_get_bits(intp, DEMOD_TYPE) & 0x01;
 	result->frame_len = ((u32)stv0900_get_bits(intp, DEMOD_TYPE)) >> 1;
 	result->rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
+
+	dprintk("%s: modcode=0x%x \n", __func__, result->modcode);
+
 	switch (result->standard) {
 	case STV0900_DVBS2_STANDARD:
 		result->spectrum = stv0900_get_bits(intp, SPECINV_DEMOD);
@@ -1239,7 +1259,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
 	if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
 				(intp->symbol_rate[d] < 10000000)) {
 		offsetFreq = result->frequency - intp->freq[d];
-		intp->freq[d] = stv0900_get_tuner_freq(fe);
+		if (intp->tuner_type[demod] == 3)
+			intp->freq[d] = stv0900_get_freq_auto(intp, d);
+		else
+			intp->freq[d] = stv0900_get_tuner_freq(fe);
+
 		if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
 			range = STV0900_RANGEOK;
 		else if (ABS(offsetFreq) <=
@@ -1481,7 +1505,12 @@ static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
 			else
 				tuner_freq -= (current_step * currier_step);
 
-			stv0900_set_tuner(fe, tuner_freq, intp->bw[demod]);
+			if (intp->tuner_type[demod] == 3)
+				stv0900_set_tuner_auto(intp, tuner_freq,
+						intp->bw[demod], demod);
+			else
+				stv0900_set_tuner(fe, tuner_freq,
+						intp->bw[demod]);
 		}
 	}
 
@@ -1608,7 +1637,8 @@ static int stv0900_blind_search_algo(struct dvb_frontend *fe)
 
 	agc2_int = stv0900_blind_check_agc2_min_level(intp, demod);
 
-	if (agc2_int > STV0900_BLIND_SEARCH_AGC2_TH)
+	dprintk("%s agc2_int=%d agc2_th=%d \n", __func__, agc2_int, agc2_th);
+	if (agc2_int > agc2_th)
 		return FALSE;
 
 	if (intp->chip_id == 0x10)
@@ -1875,7 +1905,11 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
 
 	}
 
-	stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
+	if (intp->tuner_type[demod] == 3)
+		stv0900_set_tuner_auto(intp, intp->freq[demod],
+				intp->bw[demod], demod);
+	else
+		stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
 
 	agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
 				stv0900_get_bits(intp, AGCIQ_VALUE0));
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 1573466a5c74..c52c3357dc54 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -37,7 +37,82 @@
 static unsigned int verbose;
 module_param(verbose, int, 0644);
 
-struct mutex demod_lock;
+/* internal params node */
+struct stv090x_dev {
+	/* pointer for internal params, one for each pair of demods */
+	struct stv090x_internal		*internal;
+	struct stv090x_dev		*next_dev;
+};
+
+/* first internal params */
+static struct stv090x_dev *stv090x_first_dev;
+
+/* find chip by i2c adapter and i2c address */
+static struct stv090x_dev *find_dev(struct i2c_adapter *i2c_adap,
+					u8 i2c_addr)
+{
+	struct stv090x_dev *temp_dev = stv090x_first_dev;
+
+	/*
+	 Search of the last stv0900 chip or
+	 find it by i2c adapter and i2c address */
+	while ((temp_dev != NULL) &&
+		((temp_dev->internal->i2c_adap != i2c_adap) ||
+		(temp_dev->internal->i2c_addr != i2c_addr))) {
+
+		temp_dev = temp_dev->next_dev;
+	}
+
+	return temp_dev;
+}
+
+/* deallocating chip */
+static void remove_dev(struct stv090x_internal *internal)
+{
+	struct stv090x_dev *prev_dev = stv090x_first_dev;
+	struct stv090x_dev *del_dev = find_dev(internal->i2c_adap,
+						internal->i2c_addr);
+
+	if (del_dev != NULL) {
+		if (del_dev == stv090x_first_dev) {
+			stv090x_first_dev = del_dev->next_dev;
+		} else {
+			while (prev_dev->next_dev != del_dev)
+				prev_dev = prev_dev->next_dev;
+
+			prev_dev->next_dev = del_dev->next_dev;
+		}
+
+		kfree(del_dev);
+	}
+}
+
+/* allocating new chip */
+static struct stv090x_dev *append_internal(struct stv090x_internal *internal)
+{
+	struct stv090x_dev *new_dev;
+	struct stv090x_dev *temp_dev;
+
+	new_dev = kmalloc(sizeof(struct stv090x_dev), GFP_KERNEL);
+	if (new_dev != NULL) {
+		new_dev->internal = internal;
+		new_dev->next_dev = NULL;
+
+		/* append to list */
+		if (stv090x_first_dev == NULL) {
+			stv090x_first_dev = new_dev;
+		} else {
+			temp_dev = stv090x_first_dev;
+			while (temp_dev->next_dev != NULL)
+				temp_dev = temp_dev->next_dev;
+
+			temp_dev->next_dev = new_dev;
+		}
+	}
+
+	return new_dev;
+}
+
 
 /* DVBS1 and DSS C/N Lookup table */
 static const struct stv090x_tab stv090x_s1cn_tab[] = {
@@ -683,6 +758,9 @@ static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 	struct stv090x_state *state = fe->demodulator_priv;
 	u32 reg;
 
+	if (enable)
+		mutex_lock(&state->internal->tuner_lock);
+
 	reg = STV090x_READ_DEMOD(state, I2CRPT);
 	if (enable) {
 		dprintk(FE_DEBUG, 1, "Enable Gate");
@@ -696,9 +774,14 @@ static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 		if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0)
 			goto err;
 	}
+
+	if (!enable)
+		mutex_unlock(&state->internal->tuner_lock);
+
 	return 0;
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
+	mutex_unlock(&state->internal->tuner_lock);
 	return -1;
 }
 
@@ -755,13 +838,13 @@ static int stv090x_set_srate(struct stv090x_state *state, u32 srate)
 
 	if (srate > 60000000) {
 		sym  = (srate << 4); /* SR * 2^16 / master_clk */
-		sym /= (state->mclk >> 12);
+		sym /= (state->internal->mclk >> 12);
 	} else if (srate > 6000000) {
 		sym  = (srate << 6);
-		sym /= (state->mclk >> 10);
+		sym /= (state->internal->mclk >> 10);
 	} else {
 		sym  = (srate << 9);
-		sym /= (state->mclk >> 7);
+		sym /= (state->internal->mclk >> 7);
 	}
 
 	if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */
@@ -782,13 +865,13 @@ static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate
 	srate = 105 * (srate / 100);
 	if (srate > 60000000) {
 		sym  = (srate << 4); /* SR * 2^16 / master_clk */
-		sym /= (state->mclk >> 12);
+		sym /= (state->internal->mclk >> 12);
 	} else if (srate > 6000000) {
 		sym  = (srate << 6);
-		sym /= (state->mclk >> 10);
+		sym /= (state->internal->mclk >> 10);
 	} else {
 		sym  = (srate << 9);
-		sym /= (state->mclk >> 7);
+		sym /= (state->internal->mclk >> 7);
 	}
 
 	if (sym < 0x7fff) {
@@ -816,13 +899,13 @@ static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate
 	srate = 95 * (srate / 100);
 	if (srate > 60000000) {
 		sym  = (srate << 4); /* SR * 2^16 / master_clk */
-		sym /= (state->mclk >> 12);
+		sym /= (state->internal->mclk >> 12);
 	} else if (srate > 6000000) {
 		sym  = (srate << 6);
-		sym /= (state->mclk >> 10);
+		sym /= (state->internal->mclk >> 10);
 	} else {
 		sym  = (srate << 9);
-		sym /= (state->mclk >> 7);
+		sym /= (state->internal->mclk >> 7);
 	}
 
 	if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */
@@ -1103,21 +1186,21 @@ static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
 
 	switch (state->demod) {
 	case STV090x_DEMODULATOR_0:
-		mutex_lock(&demod_lock);
+		mutex_lock(&state->internal->demod_lock);
 		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
 		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable);
 		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
 			goto err;
-		mutex_unlock(&demod_lock);
+		mutex_unlock(&state->internal->demod_lock);
 		break;
 
 	case STV090x_DEMODULATOR_1:
-		mutex_lock(&demod_lock);
+		mutex_lock(&state->internal->demod_lock);
 		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
 		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable);
 		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
 			goto err;
-		mutex_unlock(&demod_lock);
+		mutex_unlock(&state->internal->demod_lock);
 		break;
 
 	default:
@@ -1126,14 +1209,14 @@ static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
 	}
 	return 0;
 err:
-	mutex_unlock(&demod_lock);
+	mutex_unlock(&state->internal->demod_lock);
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
 }
 
 static int stv090x_dvbs_track_crl(struct stv090x_state *state)
 {
-	if (state->dev_ver >= 0x30) {
+	if (state->internal->dev_ver >= 0x30) {
 		/* Set ACLC BCLC optimised value vs SR */
 		if (state->srate >= 15000000) {
 			if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0)
@@ -1215,7 +1298,7 @@ static int stv090x_delivery_search(struct stv090x_state *state)
 		if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
 			goto err;
 
-		if (state->dev_ver <= 0x20) {
+		if (state->internal->dev_ver <= 0x20) {
 			/* enable S2 carrier loop */
 			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
 				goto err;
@@ -1246,6 +1329,10 @@ static int stv090x_delivery_search(struct stv090x_state *state)
 	default:
 		/* enable DVB-S2 and DVB-S2 in Auto MODE */
 		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
 		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
 		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
 		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
@@ -1257,7 +1344,7 @@ static int stv090x_delivery_search(struct stv090x_state *state)
 		if (stv090x_dvbs_track_crl(state) < 0)
 			goto err;
 
-		if (state->dev_ver <= 0x20) {
+		if (state->internal->dev_ver <= 0x20) {
 			/* enable S2 carrier loop */
 			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
 				goto err;
@@ -1304,7 +1391,7 @@ static int stv090x_start_search(struct stv090x_state *state)
 	if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
 		goto err;
 
-	if (state->dev_ver <= 0x20) {
+	if (state->internal->dev_ver <= 0x20) {
 		if (state->srate <= 5000000) {
 			if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0)
 				goto err;
@@ -1348,7 +1435,7 @@ static int stv090x_start_search(struct stv090x_state *state)
 			 * CFR max = +1MHz
 			 */
 			freq_abs  = 1000 << 16;
-			freq_abs /= (state->mclk / 1000);
+			freq_abs /= (state->internal->mclk / 1000);
 			freq      = (s16) freq_abs;
 		} else {
 			/* COLD Start
@@ -1358,7 +1445,7 @@ static int stv090x_start_search(struct stv090x_state *state)
 			 */
 			freq_abs  = (state->search_range / 2000) + 600;
 			freq_abs  = freq_abs << 16;
-			freq_abs /= (state->mclk / 1000);
+			freq_abs /= (state->internal->mclk / 1000);
 			freq      = (s16) freq_abs;
 		}
 
@@ -1381,7 +1468,7 @@ static int stv090x_start_search(struct stv090x_state *state)
 	if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0)
 		goto err;
 
-	if (state->dev_ver >= 0x20) {
+	if (state->internal->dev_ver >= 0x20) {
 		if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
 			goto err;
 		if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
@@ -1418,10 +1505,10 @@ static int stv090x_start_search(struct stv090x_state *state)
 	if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0)
 		goto err;
 
-	if (state->dev_ver >= 0x20) {
+	if (state->internal->dev_ver >= 0x20) {
 		/*Frequency offset detector setting*/
 		if (state->srate < 2000000) {
-			if (state->dev_ver <= 0x20) {
+			if (state->internal->dev_ver <= 0x20) {
 				/* Cut 2 */
 				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
 					goto err;
@@ -1512,7 +1599,7 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
 		steps = 1;
 
 	dir = 1;
-	freq_step = (1000000 * 256) / (state->mclk / 256);
+	freq_step = (1000000 * 256) / (state->internal->mclk / 256);
 	freq_init = 0;
 
 	for (i = 0; i < steps; i++) {
@@ -1583,7 +1670,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 	u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
 	u32 agc2th;
 
-	if (state->dev_ver >= 0x30)
+	if (state->internal->dev_ver >= 0x30)
 		agc2th = 0x2e00;
 	else
 		agc2th = 0x1f00;
@@ -1619,13 +1706,13 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0)
 		goto err;
 
-	if (state->dev_ver >= 0x30) {
+	if (state->internal->dev_ver >= 0x30) {
 		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
 			goto err;
 		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0)
 			goto err;
 
-	} else if (state->dev_ver >= 0x20) {
+	} else if (state->internal->dev_ver >= 0x20) {
 		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0)
 			goto err;
 		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
@@ -1677,7 +1764,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 				STV090x_READ_DEMOD(state, AGC2I0);
 		}
 		agc2 /= 10;
-		srate_coarse = stv090x_get_srate(state, state->mclk);
+		srate_coarse = stv090x_get_srate(state, state->internal->mclk);
 		cur_step++;
 		dir *= -1;
 		if ((tmg_cpt >= 5) && (agc2 < agc2th) &&
@@ -1695,12 +1782,12 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 
 			if (state->config->tuner_set_frequency) {
 				if (state->config->tuner_set_frequency(fe, freq) < 0)
-					goto err;
+					goto err_gateoff;
 			}
 
 			if (state->config->tuner_set_bandwidth) {
 				if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-					goto err;
+					goto err_gateoff;
 			}
 
 			if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -1713,7 +1800,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 
 			if (state->config->tuner_get_status) {
 				if (state->config->tuner_get_status(fe, &reg) < 0)
-					goto err;
+					goto err_gateoff;
 			}
 
 			if (reg)
@@ -1729,9 +1816,12 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
 	if (!tmg_lock)
 		srate_coarse = 0;
 	else
-		srate_coarse = stv090x_get_srate(state, state->mclk);
+		srate_coarse = stv090x_get_srate(state, state->internal->mclk);
 
 	return srate_coarse;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(fe, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -1741,7 +1831,7 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
 {
 	u32 srate_coarse, freq_coarse, sym, reg;
 
-	srate_coarse = stv090x_get_srate(state, state->mclk);
+	srate_coarse = stv090x_get_srate(state, state->internal->mclk);
 	freq_coarse  = STV090x_READ_DEMOD(state, CFR2) << 8;
 	freq_coarse |= STV090x_READ_DEMOD(state, CFR1);
 	sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
@@ -1767,10 +1857,10 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
 		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
 			goto err;
 
-		if (state->dev_ver >= 0x30) {
+		if (state->internal->dev_ver >= 0x30) {
 			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
 				goto err;
-		} else if (state->dev_ver >= 0x20) {
+		} else if (state->internal->dev_ver >= 0x20) {
 			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
 				goto err;
 		}
@@ -1778,20 +1868,20 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
 		if (srate_coarse > 3000000) {
 			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
 			sym  = (sym / 1000) * 65536;
-			sym /= (state->mclk / 1000);
+			sym /= (state->internal->mclk / 1000);
 			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
 				goto err;
 			sym  = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */
 			sym  = (sym / 1000) * 65536;
-			sym /= (state->mclk / 1000);
+			sym /= (state->internal->mclk / 1000);
 			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
 				goto err;
 			sym  = (srate_coarse / 1000) * 65536;
-			sym /= (state->mclk / 1000);
+			sym /= (state->internal->mclk / 1000);
 			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
@@ -1799,20 +1889,20 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
 		} else {
 			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
 			sym  = (sym / 100) * 65536;
-			sym /= (state->mclk / 100);
+			sym /= (state->internal->mclk / 100);
 			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
 				goto err;
 			sym  = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */
 			sym  = (sym / 100) * 65536;
-			sym /= (state->mclk / 100);
+			sym /= (state->internal->mclk / 100);
 			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
 				goto err;
 			sym  = (srate_coarse / 100) * 65536;
-			sym /= (state->mclk / 100);
+			sym /= (state->internal->mclk / 100);
 			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
@@ -1874,18 +1964,19 @@ static int stv090x_blind_search(struct stv090x_state *state)
 	u32 agc2, reg, srate_coarse;
 	s32 cpt_fail, agc2_ovflw, i;
 	u8 k_ref, k_max, k_min;
-	int coarse_fail, lock;
+	int coarse_fail = 0;
+	int lock;
 
 	k_max = 110;
 	k_min = 10;
 
 	agc2 = stv090x_get_agc2_min_level(state);
 
-	if (agc2 > STV090x_SEARCH_AGC2_TH(state->dev_ver)) {
+	if (agc2 > STV090x_SEARCH_AGC2_TH(state->internal->dev_ver)) {
 		lock = 0;
 	} else {
 
-		if (state->dev_ver <= 0x20) {
+		if (state->internal->dev_ver <= 0x20) {
 			if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
 				goto err;
 		} else {
@@ -1897,7 +1988,7 @@ static int stv090x_blind_search(struct stv090x_state *state)
 		if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
 			goto err;
 
-		if (state->dev_ver >= 0x20) {
+		if (state->internal->dev_ver >= 0x20) {
 			if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
@@ -1956,7 +2047,7 @@ static int stv090x_chk_tmg(struct stv090x_state *state)
 	u32 reg;
 	s32 tmg_cpt = 0, i;
 	u8 freq, tmg_thh, tmg_thl;
-	int tmg_lock;
+	int tmg_lock = 0;
 
 	freq = STV090x_READ_DEMOD(state, CARFREQ);
 	tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE);
@@ -2080,12 +2171,12 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
 
 					if (state->config->tuner_set_frequency) {
 						if (state->config->tuner_set_frequency(fe, freq) < 0)
-							goto err;
+							goto err_gateoff;
 					}
 
 					if (state->config->tuner_set_bandwidth) {
 						if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-							goto err;
+							goto err_gateoff;
 					}
 
 					if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2098,7 +2189,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
 
 					if (state->config->tuner_get_status) {
 						if (state->config->tuner_get_status(fe, &reg) < 0)
-							goto err;
+							goto err_gateoff;
 					}
 
 					if (reg)
@@ -2129,6 +2220,8 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
 
 	return lock;
 
+err_gateoff:
+	stv090x_i2c_gate_ctrl(fe, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -2142,13 +2235,13 @@ static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s
 	car_max = state->search_range / 1000;
 	car_max += car_max / 10;
 	car_max  = 65536 * (car_max / 2);
-	car_max /= (state->mclk / 1000);
+	car_max /= (state->internal->mclk / 1000);
 
 	if (car_max > 0x4000)
 		car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */
 
 	inc  = srate;
-	inc /= state->mclk / 1000;
+	inc /= state->internal->mclk / 1000;
 	inc *= 256;
 	inc *= 256;
 	inc /= 1000;
@@ -2209,7 +2302,7 @@ static int stv090x_chk_signal(struct stv090x_state *state)
 
 	car_max += (car_max / 10); /* 10% margin */
 	car_max  = (65536 * car_max / 2);
-	car_max /= state->mclk / 1000;
+	car_max /= state->internal->mclk / 1000;
 
 	if (car_max > 0x4000)
 		car_max = 0x4000;
@@ -2234,7 +2327,7 @@ static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 tim
 	car_max  = state->search_range / 1000;
 	car_max += (car_max / 10);
 	car_max  = (65536 * car_max / 2);
-	car_max /= (state->mclk / 1000);
+	car_max /= (state->internal->mclk / 1000);
 	if (car_max > 0x4000)
 		car_max = 0x4000;
 
@@ -2304,7 +2397,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
 	case STV090x_SEARCH_DVBS1:
 	case STV090x_SEARCH_DSS:
 		/* accelerate the frequency detector */
-		if (state->dev_ver >= 0x20) {
+		if (state->internal->dev_ver >= 0x20) {
 			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0)
 				goto err;
 		}
@@ -2315,7 +2408,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
 		break;
 
 	case STV090x_SEARCH_DVBS2:
-		if (state->dev_ver >= 0x20) {
+		if (state->internal->dev_ver >= 0x20) {
 			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
 				goto err;
 		}
@@ -2328,7 +2421,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
 	case STV090x_SEARCH_AUTO:
 	default:
 		/* accelerate the frequency detector */
-		if (state->dev_ver >= 0x20) {
+		if (state->internal->dev_ver >= 0x20) {
 			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0)
 				goto err;
 			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
@@ -2350,7 +2443,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
 		/*run the SW search 2 times maximum*/
 		if (lock || no_signal || (trials == 2)) {
 			/*Check if the demod is not losing lock in DVBS2*/
-			if (state->dev_ver >= 0x20) {
+			if (state->internal->dev_ver >= 0x20) {
 				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
 					goto err;
 				if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
@@ -2372,7 +2465,7 @@ static int stv090x_sw_algo(struct stv090x_state *state)
 					/*FALSE lock, The demod is loosing lock */
 					lock = 0;
 					if (trials < 2) {
-						if (state->dev_ver >= 0x20) {
+						if (state->internal->dev_ver >= 0x20) {
 							if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
 								goto err;
 						}
@@ -2422,11 +2515,11 @@ static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
 	derot |= STV090x_READ_DEMOD(state, CFR0);
 
 	derot = comp2(derot, 24);
-	int_1 = state->mclk >> 12;
+	int_1 = mclk >> 12;
 	int_2 = derot >> 12;
 
 	/* carrier_frequency = MasterClock * Reg / 2^24 */
-	tmp_1 = state->mclk % 0x1000;
+	tmp_1 = mclk % 0x1000;
 	tmp_2 = derot % 0x1000;
 
 	derot = (int_1 * int_2) +
@@ -2502,13 +2595,13 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st
 
 	if (state->config->tuner_get_frequency) {
 		if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
-			goto err;
+			goto err_gateoff;
 	}
 
 	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
 		goto err;
 
-	offst_freq = stv090x_get_car_freq(state, state->mclk) / 1000;
+	offst_freq = stv090x_get_car_freq(state, state->internal->mclk) / 1000;
 	state->frequency += offst_freq;
 
 	if (stv090x_get_viterbi(state) < 0)
@@ -2530,7 +2623,7 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st
 
 		if (state->config->tuner_get_frequency) {
 			if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
-				goto err;
+				goto err_gateoff;
 		}
 
 		if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2550,6 +2643,9 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st
 	}
 
 	return STV090x_OUTOFRANGE;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(fe, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -2579,7 +2675,7 @@ static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_mod
 	s32 i;
 	struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low;
 
-	if (state->dev_ver == 0x20) {
+	if (state->internal->dev_ver == 0x20) {
 		car_loop		= stv090x_s2_crl_cut20;
 		car_loop_qpsk_low	= stv090x_s2_lowqpsk_crl_cut20;
 		car_loop_apsk_low	= stv090x_s2_apsk_crl_cut20;
@@ -2700,7 +2796,7 @@ static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
 		break;
 	}
 
-	if (state->dev_ver >= 0x30) {
+	if (state->internal->dev_ver >= 0x30) {
 		/* Cut 3.0 and up */
 		short_crl = stv090x_s2_short_crl_cut30;
 	} else {
@@ -2732,7 +2828,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 	s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
 	u32 reg;
 
-	srate  = stv090x_get_srate(state, state->mclk);
+	srate  = stv090x_get_srate(state, state->internal->mclk);
 	srate += stv090x_get_tmgoffst(state, srate);
 
 	switch (state->delsys) {
@@ -2751,7 +2847,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
 			goto err;
 
-		if (state->dev_ver >= 0x30) {
+		if (state->internal->dev_ver >= 0x30) {
 			if (stv090x_get_viterbi(state) < 0)
 				goto err;
 
@@ -2868,7 +2964,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 			goto err;
 	}
 
-	if (state->dev_ver >= 0x20) {
+	if (state->internal->dev_ver >= 0x20) {
 		if ((state->search_mode == STV090x_SEARCH_DVBS1)	||
 		    (state->search_mode == STV090x_SEARCH_DSS)		||
 		    (state->search_mode == STV090x_SEARCH_AUTO)) {
@@ -2890,7 +2986,8 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0)
 		goto err;
 
-	if ((state->dev_ver >= 0x20) || (blind_tune == 1) || (state->srate < 10000000)) {
+	if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1) ||
+	    (state->srate < 10000000)) {
 		/* update initial carrier freq with the found freq offset */
 		if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
 			goto err;
@@ -2898,7 +2995,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 			goto err;
 		state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000;
 
-		if ((state->dev_ver >= 0x20) || (blind_tune == 1)) {
+		if ((state->internal->dev_ver >= 0x20) || (blind_tune == 1)) {
 
 			if (state->algo != STV090x_WARM_SEARCH) {
 
@@ -2907,7 +3004,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 
 				if (state->config->tuner_set_bandwidth) {
 					if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-						goto err;
+						goto err_gateoff;
 				}
 
 				if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -2950,7 +3047,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 
 	}
 
-	if (state->dev_ver >= 0x20) {
+	if (state->internal->dev_ver >= 0x20) {
 		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
 			goto err;
 	}
@@ -2959,6 +3056,9 @@ static int stv090x_optimize_track(struct stv090x_state *state)
 		stv090x_set_vit_thtracq(state);
 
 	return 0;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(fe, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -3026,7 +3126,7 @@ static int stv090x_set_s2rolloff(struct stv090x_state *state)
 {
 	u32 reg;
 
-	if (state->dev_ver <= 0x20) {
+	if (state->internal->dev_ver <= 0x20) {
 		/* rolloff to auto mode if DVBS2 */
 		reg = STV090x_READ_DEMOD(state, DEMOD);
 		STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00);
@@ -3062,7 +3162,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */
 		goto err;
 
-	if (state->dev_ver >= 0x20) {
+	if (state->internal->dev_ver >= 0x20) {
 		if (state->srate > 5000000) {
 			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
 				goto err;
@@ -3102,7 +3202,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
 			goto err;
 
-		if (state->dev_ver >= 0x20) {
+		if (state->internal->dev_ver >= 0x20) {
 			if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0)
 				goto err;
 			if (state->algo == STV090x_COLD_SEARCH)
@@ -3120,9 +3220,11 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 		if (stv090x_set_srate(state, state->srate) < 0)
 			goto err;
 
-		if (stv090x_set_max_srate(state, state->mclk, state->srate) < 0)
+		if (stv090x_set_max_srate(state, state->internal->mclk,
+					  state->srate) < 0)
 			goto err;
-		if (stv090x_set_min_srate(state, state->mclk, state->srate) < 0)
+		if (stv090x_set_min_srate(state, state->internal->mclk,
+					  state->srate) < 0)
 			goto err;
 
 		if (state->srate >= 10000000)
@@ -3136,18 +3238,21 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 		goto err;
 
 	if (state->config->tuner_set_bbgain) {
-		if (state->config->tuner_set_bbgain(fe, 10) < 0) /* 10dB */
-			goto err;
+		reg = state->config->tuner_bbgain;
+		if (reg == 0)
+			reg = 10; /* default: 10dB */
+		if (state->config->tuner_set_bbgain(fe, reg) < 0)
+			goto err_gateoff;
 	}
 
 	if (state->config->tuner_set_frequency) {
 		if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
-			goto err;
+			goto err_gateoff;
 	}
 
 	if (state->config->tuner_set_bandwidth) {
 		if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
-			goto err;
+			goto err_gateoff;
 	}
 
 	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -3155,21 +3260,21 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 
 	msleep(50);
 
-	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
-		goto err;
-
 	if (state->config->tuner_get_status) {
+		if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+			goto err;
 		if (state->config->tuner_get_status(fe, &reg) < 0)
+			goto err_gateoff;
+		if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
 			goto err;
-	}
 
-	if (reg)
-		dprintk(FE_DEBUG, 1, "Tuner phase locked");
-	else
-		dprintk(FE_DEBUG, 1, "Tuner unlocked");
-
-	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
-		goto err;
+		if (reg)
+			dprintk(FE_DEBUG, 1, "Tuner phase locked");
+		else {
+			dprintk(FE_DEBUG, 1, "Tuner unlocked");
+			return STV090x_NOCARRIER;
+		}
+	}
 
 	msleep(10);
 	agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1),
@@ -3194,7 +3299,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 		reg = STV090x_READ_DEMOD(state, DEMOD);
 		STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
 
-		if (state->dev_ver <= 0x20) {
+		if (state->internal->dev_ver <= 0x20) {
 			/* rolloff to auto mode if DVBS2 */
 			STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1);
 		} else {
@@ -3238,7 +3343,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 	if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */
 		stv090x_optimize_track(state);
 
-		if (state->dev_ver >= 0x20) {
+		if (state->internal->dev_ver >= 0x20) {
 			/* >= Cut 2.0 :release TS reset after
 			 * demod lock and optimized Tracking
 			 */
@@ -3293,6 +3398,8 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 	}
 	return signal_state;
 
+err_gateoff:
+	stv090x_i2c_gate_ctrl(fe, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -3303,6 +3410,9 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
 	struct stv090x_state *state = fe->demodulator_priv;
 	struct dtv_frontend_properties *props = &fe->dtv_property_cache;
 
+	if (p->frequency == 0)
+		return DVBFE_ALGO_SEARCH_INVALID;
+
 	state->delsys = props->delivery_system;
 	state->frequency = p->frequency;
 	state->srate = p->u.qpsk.symbol_rate;
@@ -3353,7 +3463,8 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
 			if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) {
 				reg = STV090x_READ_DEMOD(state, TSSTATUS);
 				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
-					*status = FE_HAS_CARRIER |
+					*status = FE_HAS_SIGNAL |
+						  FE_HAS_CARRIER |
 						  FE_HAS_VITERBI |
 						  FE_HAS_SYNC |
 						  FE_HAS_LOCK;
@@ -3370,7 +3481,11 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
 			if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
 				reg = STV090x_READ_DEMOD(state, TSSTATUS);
 				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
-					*status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+					*status = FE_HAS_SIGNAL |
+						  FE_HAS_CARRIER |
+						  FE_HAS_VITERBI |
+						  FE_HAS_SYNC |
+						  FE_HAS_LOCK;
 				}
 			}
 		}
@@ -3770,6 +3885,15 @@ static void stv090x_release(struct dvb_frontend *fe)
 {
 	struct stv090x_state *state = fe->demodulator_priv;
 
+	state->internal->num_used--;
+	if (state->internal->num_used <= 0) {
+
+		dprintk(FE_ERROR, 1, "Actually removing");
+
+		remove_dev(state->internal);
+		kfree(state->internal);
+	}
+
 	kfree(state);
 }
 
@@ -3901,10 +4025,10 @@ static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk)
 	if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0)
 		goto err;
 
-	state->mclk = stv090x_get_mclk(state);
+	state->internal->mclk = stv090x_get_mclk(state);
 
 	/*Set the DiseqC frequency to 22KHz */
-	div = state->mclk / 704000;
+	div = state->internal->mclk / 704000;
 	if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0)
 		goto err;
 	if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0)
@@ -3920,7 +4044,7 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 {
 	u32 reg;
 
-	if (state->dev_ver >= 0x20) {
+	if (state->internal->dev_ver >= 0x20) {
 		switch (state->config->ts1_mode) {
 		case STV090x_TSMODE_PARALLEL_PUNCTURED:
 		case STV090x_TSMODE_DVBCI:
@@ -4092,6 +4216,71 @@ static int stv090x_set_tspath(struct stv090x_state *state)
 	default:
 		break;
 	}
+
+	if (state->config->ts1_clk > 0) {
+		u32 speed;
+
+		switch (state->config->ts1_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+		default:
+			speed = state->internal->mclk /
+				(state->config->ts1_clk / 4);
+			if (speed < 0x08)
+				speed = 0x08;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			speed = state->internal->mclk /
+				(state->config->ts1_clk / 32);
+			if (speed < 0x20)
+				speed = 0x20;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		}
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+		STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+			goto err;
+		if (stv090x_write_reg(state, STV090x_P1_TSSPEED, speed) < 0)
+			goto err;
+	}
+
+	if (state->config->ts2_clk > 0) {
+		u32 speed;
+
+		switch (state->config->ts2_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+		default:
+			speed = state->internal->mclk /
+				(state->config->ts2_clk / 4);
+			if (speed < 0x08)
+				speed = 0x08;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			speed = state->internal->mclk /
+				(state->config->ts2_clk / 32);
+			if (speed < 0x20)
+				speed = 0x20;
+			if (speed > 0xFF)
+				speed = 0xFF;
+			break;
+		}
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
+		STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
+			goto err;
+		if (stv090x_write_reg(state, STV090x_P2_TSSPEED, speed) < 0)
+			goto err;
+	}
+
 	reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
 	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
 	if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
@@ -4120,6 +4309,15 @@ static int stv090x_init(struct dvb_frontend *fe)
 	const struct stv090x_config *config = state->config;
 	u32 reg;
 
+	if (state->internal->mclk == 0) {
+		stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
+		msleep(5);
+		if (stv090x_write_reg(state, STV090x_SYNTCTRL,
+				      0x20 | config->clk_mode) < 0)
+			goto err;
+		stv090x_get_mclk(state);
+	}
+
 	if (stv090x_wakeup(fe) < 0) {
 		dprintk(FE_ERROR, 1, "Error waking device");
 		goto err;
@@ -4142,12 +4340,12 @@ static int stv090x_init(struct dvb_frontend *fe)
 
 	if (config->tuner_set_mode) {
 		if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
-			goto err;
+			goto err_gateoff;
 	}
 
 	if (config->tuner_init) {
 		if (config->tuner_init(fe) < 0)
-			goto err;
+			goto err_gateoff;
 	}
 
 	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
@@ -4157,6 +4355,9 @@ static int stv090x_init(struct dvb_frontend *fe)
 		goto err;
 
 	return 0;
+
+err_gateoff:
+	stv090x_i2c_gate_ctrl(fe, 0);
 err:
 	dprintk(FE_ERROR, 1, "I/O error");
 	return -1;
@@ -4188,16 +4389,26 @@ static int stv090x_setup(struct dvb_frontend *fe)
 	}
 
 	/* STV090x init */
-	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Stop Demod */
+
+	/* Stop Demod */
+	if (stv090x_write_reg(state, STV090x_P1_DMDISTATE, 0x5c) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_P2_DMDISTATE, 0x5c) < 0)
 		goto err;
 
 	msleep(5);
 
-	if (STV090x_WRITE_DEMOD(state, TNRCFG, 0x6c) < 0) /* check register ! (No Tuner Mode) */
+	/* Set No Tuner Mode */
+	if (stv090x_write_reg(state, STV090x_P1_TNRCFG, 0x6c) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_P2_TNRCFG, 0x6c) < 0)
 		goto err;
 
+	/* I2C repeater OFF */
 	STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
-	if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) /* repeater OFF */
+	if (stv090x_write_reg(state, STV090x_P1_I2CRPT, reg) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_P2_I2CRPT, reg) < 0)
 		goto err;
 
 	if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
@@ -4216,8 +4427,8 @@ static int stv090x_setup(struct dvb_frontend *fe)
 			goto err;
 	}
 
-	state->dev_ver = stv090x_read_reg(state, STV090x_MID);
-	if (state->dev_ver >= 0x20) {
+	state->internal->dev_ver = stv090x_read_reg(state, STV090x_MID);
+	if (state->internal->dev_ver >= 0x20) {
 		if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
 			goto err;
 
@@ -4228,27 +4439,35 @@ static int stv090x_setup(struct dvb_frontend *fe)
 				goto err;
 		}
 
-	} else if (state->dev_ver < 0x20) {
+	} else if (state->internal->dev_ver < 0x20) {
 		dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!",
-			state->dev_ver);
+			state->internal->dev_ver);
 
 		goto err;
-	} else if (state->dev_ver > 0x30) {
+	} else if (state->internal->dev_ver > 0x30) {
 		/* we shouldn't bail out from here */
 		dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!",
-			state->dev_ver);
+			state->internal->dev_ver);
 	}
 
-	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+	/* ADC1 range */
+	reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+	STV090x_SETFIELD(reg, ADC1_INMODE_FIELD,
+		(config->adc1_range == STV090x_ADC_1Vpp) ? 0 : 1);
+	if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
 		goto err;
-	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
+
+	/* ADC2 range */
+	reg = stv090x_read_reg(state, STV090x_TSTTNR3);
+	STV090x_SETFIELD(reg, ADC2_INMODE_FIELD,
+		(config->adc2_range == STV090x_ADC_1Vpp) ? 0 : 1);
+	if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
 		goto err;
 
-	stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
-	msleep(5);
-	if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0)
+	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
 		goto err;
-	stv090x_get_mclk(state);
 
 	return 0;
 err:
@@ -4299,6 +4518,7 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
 				    enum stv090x_demodulator demod)
 {
 	struct stv090x_state *state = NULL;
+	struct stv090x_dev *temp_int;
 
 	state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
 	if (state == NULL)
@@ -4314,8 +4534,32 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
 	state->device				= config->device;
 	state->rolloff				= STV090x_RO_35; /* default */
 
-	if (state->demod == STV090x_DEMODULATOR_0)
-		mutex_init(&demod_lock);
+	temp_int = find_dev(state->i2c,
+				state->config->address);
+
+	if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) {
+		state->internal = temp_int->internal;
+		state->internal->num_used++;
+		dprintk(FE_INFO, 1, "Found Internal Structure!");
+		dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
+			state->device == STV0900 ? "STV0900" : "STV0903",
+			demod,
+			state->internal->dev_ver);
+		return &state->frontend;
+	} else {
+		state->internal = kmalloc(sizeof(struct stv090x_internal),
+					  GFP_KERNEL);
+		temp_int = append_internal(state->internal);
+		state->internal->num_used = 1;
+		state->internal->mclk = 0;
+		state->internal->dev_ver = 0;
+		state->internal->i2c_adap = state->i2c;
+		state->internal->i2c_addr = state->config->address;
+		dprintk(FE_INFO, 1, "Create New Internal Structure!");
+	}
+
+	mutex_init(&state->internal->demod_lock);
+	mutex_init(&state->internal->tuner_lock);
 
 	if (stv090x_sleep(&state->frontend) < 0) {
 		dprintk(FE_ERROR, 1, "Error putting device to sleep");
@@ -4331,10 +4575,10 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
 		goto error;
 	}
 
-	dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x\n",
+	dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
 	       state->device == STV0900 ? "STV0900" : "STV0903",
 	       demod,
-	       state->dev_ver);
+	       state->internal->dev_ver);
 
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h
index b133807663ea..30f01a6902ac 100644
--- a/drivers/media/dvb/frontends/stv090x.h
+++ b/drivers/media/dvb/frontends/stv090x.h
@@ -60,6 +60,11 @@ enum stv090x_i2crpt {
 	STV090x_RPTLEVEL_2	= 7,
 };
 
+enum stv090x_adc_range {
+	STV090x_ADC_2Vpp	= 0,
+	STV090x_ADC_1Vpp	= 1
+};
+
 struct stv090x_config {
 	enum stv090x_device	device;
 	enum stv090x_mode	demod_mode;
@@ -68,13 +73,17 @@ struct stv090x_config {
 	u32 xtal; /* default: 8000000 */
 	u8 address; /* default: 0x68 */
 
-	u32 ref_clk; /* default: 16000000 FIXME to tuner config */
-
 	u8 ts1_mode;
 	u8 ts2_mode;
+	u32 ts1_clk;
+	u32 ts2_clk;
 
 	enum stv090x_i2crpt	repeater_level;
 
+	u8			tuner_bbgain; /* default: 10db */
+	enum stv090x_adc_range	adc1_range; /* default: 2Vpp */
+	enum stv090x_adc_range	adc2_range; /* default: 2Vpp */
+
 	bool diseqc_envelope_mode;
 
 	int (*tuner_init) (struct dvb_frontend *fe);
diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb/frontends/stv090x_priv.h
index 5921a8d6c89f..5b780c80d496 100644
--- a/drivers/media/dvb/frontends/stv090x_priv.h
+++ b/drivers/media/dvb/frontends/stv090x_priv.h
@@ -230,11 +230,23 @@ struct stv090x_tab {
 	s32 read;
 };
 
+struct stv090x_internal {
+	struct i2c_adapter 	*i2c_adap;
+	u8			i2c_addr;
+
+	struct mutex		demod_lock; /* Lock access to shared register */
+	struct mutex		tuner_lock; /* Lock access to tuners */
+	s32			mclk; /* Masterclock Divider factor */
+	u32			dev_ver;
+
+	int			num_used;
+};
+
 struct stv090x_state {
 	enum stv090x_device		device;
 	enum stv090x_demodulator	demod;
 	enum stv090x_mode		demod_mode;
-	u32				dev_ver;
+	struct stv090x_internal		*internal;
 
 	struct i2c_adapter		*i2c;
 	const struct stv090x_config	*config;
@@ -256,11 +268,8 @@ struct stv090x_state {
 	u32				frequency;
 	u32				srate;
 
-	s32				mclk; /* Masterclock Divider factor */
 	s32				tuner_bw;
 
-	u32				tuner_refclk;
-
 	s32				search_range;
 
 	s32				DemodTimeout;
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
index bcfcb652464c..f931ed07e92d 100644
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ b/drivers/media/dvb/frontends/stv6110x.c
@@ -35,8 +35,6 @@ static unsigned int verbose;
 module_param(verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "Set Verbosity level");
 
-static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
-
 static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
 {
 	int ret;
@@ -58,12 +56,23 @@ static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
 	return 0;
 }
 
-static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 data[], int len)
 {
 	int ret;
 	const struct stv6110x_config *config = stv6110x->config;
-	u8 buf[] = { reg, data };
-	struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 };
+	u8 buf[len + 1];
+	struct i2c_msg msg = {
+		.addr = config->addr,
+		.flags = 0,
+		.buf = buf,
+		.len = len + 1
+	};
+
+	if (start + len > 8)
+		return -EINVAL;
+
+	buf[0] = start;
+	memcpy(&buf[1], data, len);
 
 	ret = i2c_transfer(stv6110x->i2c, &msg, 1);
 	if (ret != 1) {
@@ -74,18 +83,21 @@ static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
 	return 0;
 }
 
+static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+{
+	return stv6110x_write_regs(stv6110x, reg, &data, 1);
+}
+
 static int stv6110x_init(struct dvb_frontend *fe)
 {
 	struct stv6110x_state *stv6110x = fe->tuner_priv;
 	int ret;
-	u8 i;
 
-	for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) {
-		ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]);
-		if (ret < 0) {
-			dprintk(FE_ERROR, 1, "Initialization failed");
-			return -1;
-		}
+	ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
+				  ARRAY_SIZE(stv6110x->regs));
+	if (ret < 0) {
+		dprintk(FE_ERROR, 1, "Initialization failed");
+		return -1;
 	}
 
 	return 0;
@@ -98,23 +110,23 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
 	s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000;
 	u8 i;
 
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
 
 	if (frequency <= 1023000) {
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
 		pVal = 40;
 	} else if (frequency <= 1300000) {
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
 		pVal = 40;
 	} else if (frequency <= 2046000) {
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
 		pVal = 20;
 	} else {
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
 		pVal = 20;
 	}
 
@@ -130,21 +142,21 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
 	divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
 	divider = (divider + 5) / 10;
 
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
 
 	/* VCO Auto calibration */
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
 
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
-	stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]);
-	stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]);
-	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
+	stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x->regs[STV6110x_TNG1]);
+	stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x->regs[STV6110x_TNG0]);
+	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
 
 	for (i = 0; i < TRIALS; i++) {
-		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
-		if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1]))
+		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
+		if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x->regs[STV6110x_STAT1]))
 				break;
 		msleep(1);
 	}
@@ -156,14 +168,14 @@ static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
 	struct stv6110x_state *stv6110x = fe->tuner_priv;
 
-	stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]);
-	stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]);
+	stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x->regs[STV6110x_TNG1]);
+	stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x->regs[STV6110x_TNG0]);
 
-	*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]),
-				 STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
+	*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x->regs[STV6110x_TNG1]),
+				 STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x->regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
 
-	*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) +
-			     STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1])));
+	*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x->regs[STV6110x_TNG1]) +
+			     STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x->regs[STV6110x_TNG1])));
 
 	*frequency >>= 2;
 
@@ -179,27 +191,27 @@ static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
 	halfbw = bandwidth >> 1;
 
 	if (halfbw > 36000000)
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
 	else if (halfbw < 5000000)
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
 	else
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
 
 
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
 
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
-	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
+	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x->regs[STV6110x_STAT1]);
 
 	for (i = 0; i < TRIALS; i++) {
-		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
-		if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1]))
+		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
+		if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x->regs[STV6110x_STAT1]))
 			break;
 		msleep(1);
 	}
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x->regs[STV6110x_CTRL3]);
 
 	return 0;
 }
@@ -208,8 +220,8 @@ static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 {
 	struct stv6110x_state *stv6110x = fe->tuner_priv;
 
-	stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]);
-	*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000;
+	stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x->regs[STV6110x_CTRL3]);
+	*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x->regs[STV6110x_CTRL3]) + 5) * 2000000;
 
 	return 0;
 }
@@ -222,20 +234,20 @@ static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
 	switch (refclock) {
 	default:
 	case 1:
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
 		break;
 	case 2:
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
 		break;
 	case 4:
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
 		break;
 	case 8:
 	case 0:
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
 		break;
 	}
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
 
 	return 0;
 }
@@ -244,8 +256,8 @@ static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
 {
 	struct stv6110x_state *stv6110x = fe->tuner_priv;
 
-	stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]);
-	*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]);
+	stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x->regs[STV6110x_CTRL2]);
+	*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x->regs[STV6110x_CTRL2]);
 
 	return 0;
 }
@@ -254,8 +266,8 @@ static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
 {
 	struct stv6110x_state *stv6110x = fe->tuner_priv;
 
-	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
-	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+	STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x->regs[STV6110x_CTRL2]);
 
 	return 0;
 }
@@ -267,19 +279,19 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
 
 	switch (mode) {
 	case TUNER_SLEEP:
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 0);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 0);
 		break;
 
 	case TUNER_WAKE:
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1);
-		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_SYN, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_RX, 1);
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL1], CTRL1_LPT, 1);
 		break;
 	}
 
-	ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+	ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x->regs[STV6110x_CTRL1]);
 	if (ret < 0) {
 		dprintk(FE_ERROR, 1, "I/O Error");
 		return -EIO;
@@ -297,9 +309,9 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
 {
 	struct stv6110x_state *stv6110x = fe->tuner_priv;
 
-	stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+	stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x->regs[STV6110x_STAT1]);
 
-	if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1]))
+	if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x->regs[STV6110x_STAT1]))
 		*status = TUNER_PHASELOCKED;
 	else
 		*status = 0;
@@ -349,6 +361,8 @@ struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
 					struct i2c_adapter *i2c)
 {
 	struct stv6110x_state *stv6110x;
+	u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
+	int ret;
 
 	stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
 	if (stv6110x == NULL)
@@ -357,6 +371,44 @@ struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
 	stv6110x->i2c		= i2c;
 	stv6110x->config	= config;
 	stv6110x->devctl	= &stv6110x_ctl;
+	memcpy(stv6110x->regs, default_regs, 8);
+
+	/* setup divider */
+	switch (stv6110x->config->clk_div) {
+	default:
+	case 1:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+		break;
+	case 2:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+		break;
+	case 4:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+		break;
+	case 8:
+	case 0:
+		STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+		break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl) {
+		ret = fe->ops.i2c_gate_ctrl(fe, 1);
+		if (ret < 0)
+			goto error;
+	}
+
+	ret = stv6110x_write_regs(stv6110x, 0, stv6110x->regs,
+				  ARRAY_SIZE(stv6110x->regs));
+	if (ret < 0) {
+		dprintk(FE_ERROR, 1, "Initialization failed");
+		goto error;
+	}
+
+	if (fe->ops.i2c_gate_ctrl) {
+		ret = fe->ops.i2c_gate_ctrl(fe, 0);
+		if (ret < 0)
+			goto error;
+	}
 
 	fe->tuner_priv		= stv6110x;
 	fe->ops.tuner_ops	= stv6110x_ops;
diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb/frontends/stv6110x.h
index a38257080e01..2429ae6d7847 100644
--- a/drivers/media/dvb/frontends/stv6110x.h
+++ b/drivers/media/dvb/frontends/stv6110x.h
@@ -26,6 +26,7 @@
 struct stv6110x_config {
 	u8	addr;
 	u32	refclk;
+	u8	clk_div; /* divisor value for the output clock */
 };
 
 enum tuner_mode {
diff --git a/drivers/media/dvb/frontends/stv6110x_priv.h b/drivers/media/dvb/frontends/stv6110x_priv.h
index 7260da633d49..0ec936a660a7 100644
--- a/drivers/media/dvb/frontends/stv6110x_priv.h
+++ b/drivers/media/dvb/frontends/stv6110x_priv.h
@@ -68,6 +68,7 @@
 struct stv6110x_state {
 	struct i2c_adapter		*i2c;
 	const struct stv6110x_config	*config;
+	u8 				regs[8];
 
 	struct stv6110x_devctl		*devctl;
 };
diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb/frontends/tda665x.c
index 87d52739c828..c44fefe92d97 100644
--- a/drivers/media/dvb/frontends/tda665x.c
+++ b/drivers/media/dvb/frontends/tda665x.c
@@ -133,7 +133,7 @@ static int tda665x_set_state(struct dvb_frontend *fe,
 		frequency += config->ref_divider >> 1;
 		frequency /= config->ref_divider;
 
-		buf[0] = (u8) (frequency & 0x7f00) >> 8;
+		buf[0] = (u8) ((frequency & 0x7f00) >> 8);
 		buf[1] = (u8) (frequency & 0x00ff) >> 0;
 		buf[2] = 0x80 | 0x40 | 0x02;
 		buf[3] = 0x00;
diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb/frontends/tda8261.c
index 320c3c36d8b2..614afcec05f1 100644
--- a/drivers/media/dvb/frontends/tda8261.c
+++ b/drivers/media/dvb/frontends/tda8261.c
@@ -39,7 +39,7 @@ static int tda8261_read(struct tda8261_state *state, u8 *buf)
 {
 	const struct tda8261_config *config = state->config;
 	int err = 0;
-	struct i2c_msg msg = { .addr	= config->addr, .flags = I2C_M_RD,.buf = buf,  .len = 2 };
+	struct i2c_msg msg = { .addr	= config->addr, .flags = I2C_M_RD,.buf = buf,  .len = 1 };
 
 	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
 		printk("%s: read error, err=%d\n", __func__, err);
diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c
index 4e814ff22b23..34c5de491d2b 100644
--- a/drivers/media/dvb/frontends/zl10036.c
+++ b/drivers/media/dvb/frontends/zl10036.c
@@ -411,7 +411,7 @@ static int zl10036_init_regs(struct zl10036_state *state)
 	state->bf = 0xff;
 
 	if (!state->config->rf_loop_enable)
-		zl10036_init_tab[1][2] |= 0x01;
+		zl10036_init_tab[1][0] |= 0x01;
 
 	deb_info("%s\n", __func__);
 
diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c
index 11b29cb883e6..c085e58a94bf 100644
--- a/drivers/media/dvb/frontends/zl10039.c
+++ b/drivers/media/dvb/frontends/zl10039.c
@@ -287,7 +287,6 @@ struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
 		break;
 	default:
 		dprintk("Chip ID=%x does not match a known type\n", state->id);
-		break;
 		goto error;
 	}
 
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c
index 7477dac628b4..5772ebb3a69e 100644
--- a/drivers/media/dvb/mantis/mantis_hif.c
+++ b/drivers/media/dvb/mantis/mantis_hif.c
@@ -22,8 +22,6 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 
-#include <linux/signal.h>
-#include <linux/sched.h>
 #include <linux/interrupt.h>
 
 #include "dmxdev.h"
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
index 6a9df779441f..4675a3b53c7d 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -126,7 +126,7 @@ int mantis_input_init(struct mantis_pci *mantis)
 	rc->id.version	= 1;
 	rc->dev		= mantis->pdev->dev;
 
-	err = ir_input_register(rc, &ir_mantis);
+	err = ir_input_register(rc, &ir_mantis, NULL);
 	if (err) {
 		dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
 		input_free_device(rc);
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c
index 6c7534af6b44..59feeb84aec7 100644
--- a/drivers/media/dvb/mantis/mantis_pci.c
+++ b/drivers/media/dvb/mantis/mantis_pci.c
@@ -41,11 +41,6 @@
 #include "dvb_frontend.h"
 #include "dvb_net.h"
 
-#include <asm/irq.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
 #include "mantis_common.h"
 #include "mantis_reg.h"
 #include "mantis_pci.h"
diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig
new file mode 100644
index 000000000000..3ec8e6fcbb1d
--- /dev/null
+++ b/drivers/media/dvb/ngene/Kconfig
@@ -0,0 +1,9 @@
+config DVB_NGENE
+	tristate "Micronas nGene support"
+	depends on DVB_CORE && PCI && I2C
+	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+	select DVB_STV6110x if !DVB_FE_CUSTOMISE
+	select DVB_STV090x if !DVB_FE_CUSTOMISE
+	---help---
+	  Support for Micronas PCI express cards with nGene bridge.
+
diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile
new file mode 100644
index 000000000000..40435cad4819
--- /dev/null
+++ b/drivers/media/dvb/ngene/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the nGene device driver
+#
+
+ngene-objs := ngene-core.o
+
+obj-$(CONFIG_DVB_NGENE) += ngene.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
+
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
new file mode 100644
index 000000000000..0150dfe7cfbb
--- /dev/null
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -0,0 +1,2024 @@
+/*
+ * ngene.c: nGene PCIe bridge driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
+ *                         Modifications for new nGene firmware,
+ *                         support for EEPROM-copying,
+ *                         support for new dual DVB-S2 card prototype
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <asm/div64.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/smp_lock.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/byteorder/generic.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include "ngene.h"
+
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+
+static int one_adapter = 1;
+module_param(one_adapter, int, 0444);
+MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
+
+
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Print debugging information.");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define COMMAND_TIMEOUT_WORKAROUND
+
+#define dprintk	if (debug) printk
+
+#define DEVICE_NAME "ngene"
+
+#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwritel(dat, adr)         writel((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr)         writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngreadl(adr)               readl(dev->iomem + (adr))
+#define ngreadb(adr)               readb(dev->iomem + (adr))
+#define ngcpyto(adr, src, count)   memcpy_toio((char *) \
+				   (dev->iomem + (adr)), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
+				   (dev->iomem + (adr)), (count))
+
+/****************************************************************************/
+/* nGene interrupt handler **************************************************/
+/****************************************************************************/
+
+static void event_tasklet(unsigned long data)
+{
+	struct ngene *dev = (struct ngene *)data;
+
+	while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
+		struct EVENT_BUFFER Event =
+			dev->EventQueue[dev->EventQueueReadIndex];
+		dev->EventQueueReadIndex =
+			(dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1);
+
+		if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify))
+			dev->TxEventNotify(dev, Event.TimeStamp);
+		if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify))
+			dev->RxEventNotify(dev, Event.TimeStamp,
+					   Event.RXCharacter);
+	}
+}
+
+static void demux_tasklet(unsigned long data)
+{
+	struct ngene_channel *chan = (struct ngene_channel *)data;
+	struct SBufferHeader *Cur = chan->nextBuffer;
+
+	spin_lock_irq(&chan->state_lock);
+
+	while (Cur->ngeneBuffer.SR.Flags & 0x80) {
+		if (chan->mode & NGENE_IO_TSOUT) {
+			u32 Flags = chan->DataFormatFlags;
+			if (Cur->ngeneBuffer.SR.Flags & 0x20)
+				Flags |= BEF_OVERFLOW;
+			if (chan->pBufferExchange) {
+				if (!chan->pBufferExchange(chan,
+							   Cur->Buffer1,
+							   chan->Capture1Length,
+							   Cur->ngeneBuffer.SR.
+							   Clock, Flags)) {
+					/*
+					   We didn't get data
+					   Clear in service flag to make sure we
+					   get called on next interrupt again.
+					   leave fill/empty (0x80) flag alone
+					   to avoid hardware running out of
+					   buffers during startup, we hold only
+					   in run state ( the source may be late
+					   delivering data )
+					*/
+
+					if (chan->HWState == HWSTATE_RUN) {
+						Cur->ngeneBuffer.SR.Flags &=
+							~0x40;
+						break;
+						/* Stop proccessing stream */
+					}
+				} else {
+					/* We got a valid buffer,
+					   so switch to run state */
+					chan->HWState = HWSTATE_RUN;
+				}
+			} else {
+				printk(KERN_ERR DEVICE_NAME ": OOPS\n");
+				if (chan->HWState == HWSTATE_RUN) {
+					Cur->ngeneBuffer.SR.Flags &= ~0x40;
+					break;	/* Stop proccessing stream */
+				}
+			}
+			if (chan->AudioDTOUpdated) {
+				printk(KERN_INFO DEVICE_NAME
+				       ": Update AudioDTO = %d\n",
+				       chan->AudioDTOValue);
+				Cur->ngeneBuffer.SR.DTOUpdate =
+					chan->AudioDTOValue;
+				chan->AudioDTOUpdated = 0;
+			}
+		} else {
+			if (chan->HWState == HWSTATE_RUN) {
+				u32 Flags = 0;
+				if (Cur->ngeneBuffer.SR.Flags & 0x01)
+					Flags |= BEF_EVEN_FIELD;
+				if (Cur->ngeneBuffer.SR.Flags & 0x20)
+					Flags |= BEF_OVERFLOW;
+				if (chan->pBufferExchange)
+					chan->pBufferExchange(chan,
+							      Cur->Buffer1,
+							      chan->
+							      Capture1Length,
+							      Cur->ngeneBuffer.
+							      SR.Clock, Flags);
+				if (chan->pBufferExchange2)
+					chan->pBufferExchange2(chan,
+							       Cur->Buffer2,
+							       chan->
+							       Capture2Length,
+							       Cur->ngeneBuffer.
+							       SR.Clock, Flags);
+			} else if (chan->HWState != HWSTATE_STOP)
+				chan->HWState = HWSTATE_RUN;
+		}
+		Cur->ngeneBuffer.SR.Flags = 0x00;
+		Cur = Cur->Next;
+	}
+	chan->nextBuffer = Cur;
+
+	spin_unlock_irq(&chan->state_lock);
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+	struct ngene *dev = (struct ngene *)dev_id;
+	u32 icounts = 0;
+	irqreturn_t rc = IRQ_NONE;
+	u32 i = MAX_STREAM;
+	u8 *tmpCmdDoneByte;
+
+	if (dev->BootFirmware) {
+		icounts = ngreadl(NGENE_INT_COUNTS);
+		if (icounts != dev->icounts) {
+			ngwritel(0, FORCE_NMI);
+			dev->cmd_done = 1;
+			wake_up(&dev->cmd_wq);
+			dev->icounts = icounts;
+			rc = IRQ_HANDLED;
+		}
+		return rc;
+	}
+
+	ngwritel(0, FORCE_NMI);
+
+	spin_lock(&dev->cmd_lock);
+	tmpCmdDoneByte = dev->CmdDoneByte;
+	if (tmpCmdDoneByte &&
+	    (*tmpCmdDoneByte ||
+	    (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) {
+		dev->CmdDoneByte = NULL;
+		dev->cmd_done = 1;
+		wake_up(&dev->cmd_wq);
+		rc = IRQ_HANDLED;
+	}
+	spin_unlock(&dev->cmd_lock);
+
+	if (dev->EventBuffer->EventStatus & 0x80) {
+		u8 nextWriteIndex =
+			(dev->EventQueueWriteIndex + 1) &
+			(EVENT_QUEUE_SIZE - 1);
+		if (nextWriteIndex != dev->EventQueueReadIndex) {
+			dev->EventQueue[dev->EventQueueWriteIndex] =
+				*(dev->EventBuffer);
+			dev->EventQueueWriteIndex = nextWriteIndex;
+		} else {
+			printk(KERN_ERR DEVICE_NAME ": event overflow\n");
+			dev->EventQueueOverflowCount += 1;
+			dev->EventQueueOverflowFlag = 1;
+		}
+		dev->EventBuffer->EventStatus &= ~0x80;
+		tasklet_schedule(&dev->event_tasklet);
+		rc = IRQ_HANDLED;
+	}
+
+	while (i > 0) {
+		i--;
+		spin_lock(&dev->channel[i].state_lock);
+		/* if (dev->channel[i].State>=KSSTATE_RUN) { */
+		if (dev->channel[i].nextBuffer) {
+			if ((dev->channel[i].nextBuffer->
+			     ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
+				dev->channel[i].nextBuffer->
+					ngeneBuffer.SR.Flags |= 0x40;
+				tasklet_schedule(
+					&dev->channel[i].demux_tasklet);
+				rc = IRQ_HANDLED;
+			}
+		}
+		spin_unlock(&dev->channel[i].state_lock);
+	}
+
+	/* Request might have been processed by a previous call. */
+	return IRQ_HANDLED;
+}
+
+/****************************************************************************/
+/* nGene command interface **************************************************/
+/****************************************************************************/
+
+static void dump_command_io(struct ngene *dev)
+{
+	u8 buf[8], *b;
+
+	ngcpyfrom(buf, HOST_TO_NGENE, 8);
+	printk(KERN_ERR "host_to_ngene (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		HOST_TO_NGENE, buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7]);
+
+	ngcpyfrom(buf, NGENE_TO_HOST, 8);
+	printk(KERN_ERR "ngene_to_host (%04x): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		NGENE_TO_HOST, buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7]);
+
+	b = dev->hosttongene;
+	printk(KERN_ERR "dev->hosttongene (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+
+	b = dev->ngenetohost;
+	printk(KERN_ERR "dev->ngenetohost (%p): %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		b, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+}
+
+static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
+{
+	int ret;
+	u8 *tmpCmdDoneByte;
+
+	dev->cmd_done = 0;
+
+	if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) {
+		dev->BootFirmware = 1;
+		dev->icounts = ngreadl(NGENE_INT_COUNTS);
+		ngwritel(0, NGENE_COMMAND);
+		ngwritel(0, NGENE_COMMAND_HI);
+		ngwritel(0, NGENE_STATUS);
+		ngwritel(0, NGENE_STATUS_HI);
+		ngwritel(0, NGENE_EVENT);
+		ngwritel(0, NGENE_EVENT_HI);
+	} else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) {
+		u64 fwio = dev->PAFWInterfaceBuffer;
+
+		ngwritel(fwio & 0xffffffff, NGENE_COMMAND);
+		ngwritel(fwio >> 32, NGENE_COMMAND_HI);
+		ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS);
+		ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI);
+		ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT);
+		ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI);
+	}
+
+	memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2);
+
+	if (dev->BootFirmware)
+		ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2);
+
+	spin_lock_irq(&dev->cmd_lock);
+	tmpCmdDoneByte = dev->ngenetohost + com->out_len;
+	if (!com->out_len)
+		tmpCmdDoneByte++;
+	*tmpCmdDoneByte = 0;
+	dev->ngenetohost[0] = 0;
+	dev->ngenetohost[1] = 0;
+	dev->CmdDoneByte = tmpCmdDoneByte;
+	spin_unlock_irq(&dev->cmd_lock);
+
+	/* Notify 8051. */
+	ngwritel(1, FORCE_INT);
+
+	ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ);
+	if (!ret) {
+		/*ngwritel(0, FORCE_NMI);*/
+
+		printk(KERN_ERR DEVICE_NAME
+		       ": Command timeout cmd=%02x prev=%02x\n",
+		       com->cmd.hdr.Opcode, dev->prev_cmd);
+		dump_command_io(dev);
+		return -1;
+	}
+	if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH)
+		dev->BootFirmware = 0;
+
+	dev->prev_cmd = com->cmd.hdr.Opcode;
+
+	if (!com->out_len)
+		return 0;
+
+	memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len);
+
+	return 0;
+}
+
+static int ngene_command(struct ngene *dev, struct ngene_command *com)
+{
+	int result;
+
+	down(&dev->cmd_mutex);
+	result = ngene_command_mutex(dev, com);
+	up(&dev->cmd_mutex);
+	return result;
+}
+
+
+static int ngene_command_i2c_read(struct ngene *dev, u8 adr,
+			   u8 *out, u8 outlen, u8 *in, u8 inlen, int flag)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_I2C_READ;
+	com.cmd.hdr.Length = outlen + 3;
+	com.cmd.I2CRead.Device = adr << 1;
+	memcpy(com.cmd.I2CRead.Data, out, outlen);
+	com.cmd.I2CRead.Data[outlen] = inlen;
+	com.cmd.I2CRead.Data[outlen + 1] = 0;
+	com.in_len = outlen + 3;
+	com.out_len = inlen + 1;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	if ((com.cmd.raw8[0] >> 1) != adr)
+		return -EIO;
+
+	if (flag)
+		memcpy(in, com.cmd.raw8, inlen + 1);
+	else
+		memcpy(in, com.cmd.raw8 + 1, inlen);
+	return 0;
+}
+
+static int ngene_command_i2c_write(struct ngene *dev, u8 adr,
+				   u8 *out, u8 outlen)
+{
+	struct ngene_command com;
+
+
+	com.cmd.hdr.Opcode = CMD_I2C_WRITE;
+	com.cmd.hdr.Length = outlen + 1;
+	com.cmd.I2CRead.Device = adr << 1;
+	memcpy(com.cmd.I2CRead.Data, out, outlen);
+	com.in_len = outlen + 1;
+	com.out_len = 1;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	if (com.cmd.raw8[0] == 1)
+		return -EIO;
+
+	return 0;
+}
+
+static int ngene_command_load_firmware(struct ngene *dev,
+				       u8 *ngene_fw, u32 size)
+{
+#define FIRSTCHUNK (1024)
+	u32 cleft;
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE;
+	com.cmd.hdr.Length = 0;
+	com.in_len = 0;
+	com.out_len = 0;
+
+	ngene_command(dev, &com);
+
+	cleft = (size + 3) & ~3;
+	if (cleft > FIRSTCHUNK) {
+		ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK,
+			cleft - FIRSTCHUNK);
+		cleft = FIRSTCHUNK;
+	}
+	ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft);
+
+	memset(&com, 0, sizeof(struct ngene_command));
+	com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH;
+	com.cmd.hdr.Length = 4;
+	com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA;
+	com.cmd.FWLoadFinish.Length = (unsigned short)cleft;
+	com.in_len = 4;
+	com.out_len = 0;
+
+	return ngene_command(dev, &com);
+}
+
+
+static int ngene_command_config_buf(struct ngene *dev, u8 config)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER;
+	com.cmd.hdr.Length = 1;
+	com.cmd.ConfigureBuffers.config = config;
+	com.in_len = 1;
+	com.out_len = 0;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+	return 0;
+}
+
+static int ngene_command_config_free_buf(struct ngene *dev, u8 *config)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
+	com.cmd.hdr.Length = 6;
+	memcpy(&com.cmd.ConfigureBuffers.config, config, 6);
+	com.in_len = 6;
+	com.out_len = 0;
+
+	if (ngene_command(dev, &com) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
+{
+	struct ngene_command com;
+
+	com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN;
+	com.cmd.hdr.Length = 1;
+	com.cmd.SetGpioPin.select = select | (level << 7);
+	com.in_len = 1;
+	com.out_len = 0;
+
+	return ngene_command(dev, &com);
+}
+
+
+/*
+ 02000640 is sample on rising edge.
+ 02000740 is sample on falling edge.
+ 02000040 is ignore "valid" signal
+
+ 0: FD_CTL1 Bit 7,6 must be 0,1
+    7   disable(fw controlled)
+    6   0-AUX,1-TS
+    5   0-par,1-ser
+    4   0-lsb/1-msb
+    3,2 reserved
+    1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both
+ 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge
+ 2: FD_STA is read-only. 0-sync
+ 3: FD_INSYNC is number of 47s to trigger "in sync".
+ 4: FD_OUTSYNC is number of 47s to trigger "out of sync".
+ 5: FD_MAXBYTE1 is low-order of bytes per packet.
+ 6: FD_MAXBYTE2 is high-order of bytes per packet.
+ 7: Top byte is unused.
+*/
+
+/****************************************************************************/
+
+static u8 TSFeatureDecoderSetup[8 * 4] = {
+	0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
+	0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXH */
+	0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* DRXHser */
+	0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,	/* S2ser */
+};
+
+/* Set NGENE I2S Config to 16 bit packed */
+static u8 I2SConfiguration[] = {
+	0x00, 0x10, 0x00, 0x00,
+	0x80, 0x10, 0x00, 0x00,
+};
+
+static u8 SPDIFConfiguration[10] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* Set NGENE I2S Config to transport stream compatible mode */
+
+static u8 TS_I2SConfiguration[4] = { 0x3E, 0x1A, 0x00, 0x00 }; /*3e 18 00 00 ?*/
+
+static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x20, 0x00, 0x00 };
+
+static u8 ITUDecoderSetup[4][16] = {
+	{0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20,  /* SDTV */
+	 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00},
+	{0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,
+	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+	{0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00,  /* HDTV 1080i50 */
+	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+	{0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,  /* HDTV 1080i60 */
+	 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
+};
+
+/*
+ * 50 48 60 gleich
+ * 27p50 9f 00 22 80 42 69 18 ...
+ * 27p60 93 00 22 80 82 69 1c ...
+ */
+
+/* Maxbyte to 1144 (for raw data) */
+static u8 ITUFeatureDecoderSetup[8] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
+};
+
+static void FillTSBuffer(void *Buffer, int Length, u32 Flags)
+{
+	u32 *ptr = Buffer;
+
+	memset(Buffer, 0xff, Length);
+	while (Length > 0) {
+		if (Flags & DF_SWAP32)
+			*ptr = 0x471FFF10;
+		else
+			*ptr = 0x10FF1F47;
+		ptr += (188 / 4);
+		Length -= 188;
+	}
+}
+
+
+static void flush_buffers(struct ngene_channel *chan)
+{
+	u8 val;
+
+	do {
+		msleep(1);
+		spin_lock_irq(&chan->state_lock);
+		val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80;
+		spin_unlock_irq(&chan->state_lock);
+	} while (val);
+}
+
+static void clear_buffers(struct ngene_channel *chan)
+{
+	struct SBufferHeader *Cur = chan->nextBuffer;
+
+	do {
+		memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR));
+		if (chan->mode & NGENE_IO_TSOUT)
+			FillTSBuffer(Cur->Buffer1,
+				     chan->Capture1Length,
+				     chan->DataFormatFlags);
+		Cur = Cur->Next;
+	} while (Cur != chan->nextBuffer);
+
+	if (chan->mode & NGENE_IO_TSOUT) {
+		chan->nextBuffer->ngeneBuffer.SR.DTOUpdate =
+			chan->AudioDTOValue;
+		chan->AudioDTOUpdated = 0;
+
+		Cur = chan->TSIdleBuffer.Head;
+
+		do {
+			memset(&Cur->ngeneBuffer.SR, 0,
+			       sizeof(Cur->ngeneBuffer.SR));
+			FillTSBuffer(Cur->Buffer1,
+				     chan->Capture1Length,
+				     chan->DataFormatFlags);
+			Cur = Cur->Next;
+		} while (Cur != chan->TSIdleBuffer.Head);
+	}
+}
+
+static int ngene_command_stream_control(struct ngene *dev, u8 stream,
+					u8 control, u8 mode, u8 flags)
+{
+	struct ngene_channel *chan = &dev->channel[stream];
+	struct ngene_command com;
+	u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
+	u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500);
+	u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
+	u16 BsSDO = 0x9B00;
+
+	/* down(&dev->stream_mutex); */
+	while (down_trylock(&dev->stream_mutex)) {
+		printk(KERN_INFO DEVICE_NAME ": SC locked\n");
+		msleep(1);
+	}
+	memset(&com, 0, sizeof(com));
+	com.cmd.hdr.Opcode = CMD_CONTROL;
+	com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
+	com.cmd.StreamControl.Stream = stream | (control ? 8 : 0);
+	if (chan->mode & NGENE_IO_TSOUT)
+		com.cmd.StreamControl.Stream |= 0x07;
+	com.cmd.StreamControl.Control = control |
+		(flags & SFLAG_ORDER_LUMA_CHROMA);
+	com.cmd.StreamControl.Mode = mode;
+	com.in_len = sizeof(struct FW_STREAM_CONTROL);
+	com.out_len = 0;
+
+	dprintk(KERN_INFO DEVICE_NAME
+		": Stream=%02x, Control=%02x, Mode=%02x\n",
+		com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
+		com.cmd.StreamControl.Mode);
+
+	chan->Mode = mode;
+
+	if (!(control & 0x80)) {
+		spin_lock_irq(&chan->state_lock);
+		if (chan->State == KSSTATE_RUN) {
+			chan->State = KSSTATE_ACQUIRE;
+			chan->HWState = HWSTATE_STOP;
+			spin_unlock_irq(&chan->state_lock);
+			if (ngene_command(dev, &com) < 0) {
+				up(&dev->stream_mutex);
+				return -1;
+			}
+			/* clear_buffers(chan); */
+			flush_buffers(chan);
+			up(&dev->stream_mutex);
+			return 0;
+		}
+		spin_unlock_irq(&chan->state_lock);
+		up(&dev->stream_mutex);
+		return 0;
+	}
+
+	if (mode & SMODE_AUDIO_CAPTURE) {
+		com.cmd.StreamControl.CaptureBlockCount =
+			chan->Capture1Length / AUDIO_BLOCK_SIZE;
+		com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+	} else if (mode & SMODE_TRANSPORT_STREAM) {
+		com.cmd.StreamControl.CaptureBlockCount =
+			chan->Capture1Length / TS_BLOCK_SIZE;
+		com.cmd.StreamControl.MaxLinesPerField =
+			chan->Capture1Length / TS_BLOCK_SIZE;
+		com.cmd.StreamControl.Buffer_Address =
+			chan->TSRingBuffer.PAHead;
+		if (chan->mode & NGENE_IO_TSOUT) {
+			com.cmd.StreamControl.BytesPerVBILine =
+				chan->Capture1Length / TS_BLOCK_SIZE;
+			com.cmd.StreamControl.Stream |= 0x07;
+		}
+	} else {
+		com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine;
+		com.cmd.StreamControl.MaxLinesPerField = chan->nLines;
+		com.cmd.StreamControl.MinLinesPerField = 100;
+		com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
+
+		if (mode & SMODE_VBI_CAPTURE) {
+			com.cmd.StreamControl.MaxVBILinesPerField =
+				chan->nVBILines;
+			com.cmd.StreamControl.MinVBILinesPerField = 0;
+			com.cmd.StreamControl.BytesPerVBILine =
+				chan->nBytesPerVBILine;
+		}
+		if (flags & SFLAG_COLORBAR)
+			com.cmd.StreamControl.Stream |= 0x04;
+	}
+
+	spin_lock_irq(&chan->state_lock);
+	if (mode & SMODE_AUDIO_CAPTURE) {
+		chan->nextBuffer = chan->RingBuffer.Head;
+		if (mode & SMODE_AUDIO_SPDIF) {
+			com.cmd.StreamControl.SetupDataLen =
+				sizeof(SPDIFConfiguration);
+			com.cmd.StreamControl.SetupDataAddr = BsSPI;
+			memcpy(com.cmd.StreamControl.SetupData,
+			       SPDIFConfiguration, sizeof(SPDIFConfiguration));
+		} else {
+			com.cmd.StreamControl.SetupDataLen = 4;
+			com.cmd.StreamControl.SetupDataAddr = BsSDI;
+			memcpy(com.cmd.StreamControl.SetupData,
+			       I2SConfiguration +
+			       4 * dev->card_info->i2s[stream], 4);
+		}
+	} else if (mode & SMODE_TRANSPORT_STREAM) {
+		chan->nextBuffer = chan->TSRingBuffer.Head;
+		if (stream >= STREAM_AUDIOIN1) {
+			if (chan->mode & NGENE_IO_TSOUT) {
+				com.cmd.StreamControl.SetupDataLen =
+					sizeof(TS_I2SOutConfiguration);
+				com.cmd.StreamControl.SetupDataAddr = BsSDO;
+				memcpy(com.cmd.StreamControl.SetupData,
+				       TS_I2SOutConfiguration,
+				       sizeof(TS_I2SOutConfiguration));
+			} else {
+				com.cmd.StreamControl.SetupDataLen =
+					sizeof(TS_I2SConfiguration);
+				com.cmd.StreamControl.SetupDataAddr = BsSDI;
+				memcpy(com.cmd.StreamControl.SetupData,
+				       TS_I2SConfiguration,
+				       sizeof(TS_I2SConfiguration));
+			}
+		} else {
+			com.cmd.StreamControl.SetupDataLen = 8;
+			com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10;
+			memcpy(com.cmd.StreamControl.SetupData,
+			       TSFeatureDecoderSetup +
+			       8 * dev->card_info->tsf[stream], 8);
+		}
+	} else {
+		chan->nextBuffer = chan->RingBuffer.Head;
+		com.cmd.StreamControl.SetupDataLen =
+			16 + sizeof(ITUFeatureDecoderSetup);
+		com.cmd.StreamControl.SetupDataAddr = BsUVI;
+		memcpy(com.cmd.StreamControl.SetupData,
+		       ITUDecoderSetup[chan->itumode], 16);
+		memcpy(com.cmd.StreamControl.SetupData + 16,
+		       ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup));
+	}
+	clear_buffers(chan);
+	chan->State = KSSTATE_RUN;
+	if (mode & SMODE_TRANSPORT_STREAM)
+		chan->HWState = HWSTATE_RUN;
+	else
+		chan->HWState = HWSTATE_STARTUP;
+	spin_unlock_irq(&chan->state_lock);
+
+	if (ngene_command(dev, &com) < 0) {
+		up(&dev->stream_mutex);
+		return -1;
+	}
+	up(&dev->stream_mutex);
+	return 0;
+}
+
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static void ngene_i2c_set_bus(struct ngene *dev, int bus)
+{
+	if (!(dev->card_info->i2c_access & 2))
+		return;
+	if (dev->i2c_current_bus == bus)
+		return;
+
+	switch (bus) {
+	case 0:
+		ngene_command_gpio_set(dev, 3, 0);
+		ngene_command_gpio_set(dev, 2, 1);
+		break;
+
+	case 1:
+		ngene_command_gpio_set(dev, 2, 0);
+		ngene_command_gpio_set(dev, 3, 1);
+		break;
+	}
+	dev->i2c_current_bus = bus;
+}
+
+static int ngene_i2c_master_xfer(struct i2c_adapter *adapter,
+				 struct i2c_msg msg[], int num)
+{
+	struct ngene_channel *chan =
+		(struct ngene_channel *)i2c_get_adapdata(adapter);
+	struct ngene *dev = chan->dev;
+
+	down(&dev->i2c_switch_mutex);
+	ngene_i2c_set_bus(dev, chan->number);
+
+	if (num == 2 && msg[1].flags & I2C_M_RD && !(msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_read(dev, msg[0].addr,
+					    msg[0].buf, msg[0].len,
+					    msg[1].buf, msg[1].len, 0))
+			goto done;
+
+	if (num == 1 && !(msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_write(dev, msg[0].addr,
+					     msg[0].buf, msg[0].len))
+			goto done;
+	if (num == 1 && (msg[0].flags & I2C_M_RD))
+		if (!ngene_command_i2c_read(dev, msg[0].addr, 0, 0,
+					    msg[0].buf, msg[0].len, 0))
+			goto done;
+
+	up(&dev->i2c_switch_mutex);
+	return -EIO;
+
+done:
+	up(&dev->i2c_switch_mutex);
+	return num;
+}
+
+
+static u32 ngene_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ngene_i2c_algo = {
+	.master_xfer = ngene_i2c_master_xfer,
+	.functionality = ngene_i2c_functionality,
+};
+
+static int ngene_i2c_init(struct ngene *dev, int dev_nr)
+{
+	struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
+
+	i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
+	adap->class = I2C_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
+
+	strcpy(adap->name, "nGene");
+
+	adap->algo = &ngene_i2c_algo;
+	adap->algo_data = (void *)&(dev->channel[dev_nr]);
+	adap->dev.parent = &dev->pci_dev->dev;
+
+	return i2c_add_adapter(adap);
+}
+
+
+/****************************************************************************/
+/* DVB functions and API interface ******************************************/
+/****************************************************************************/
+
+static void swap_buffer(u32 *p, u32 len)
+{
+	while (len) {
+		*p = swab32(*p);
+		p++;
+		len -= 4;
+	}
+}
+
+
+static void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
+{
+	struct ngene_channel *chan = priv;
+
+
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+	if (chan->users > 0)
+#endif
+		dvb_dmx_swfilter(&chan->demux, buf, len);
+	return 0;
+}
+
+u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 };
+
+static void *tsout_exchange(void *priv, void *buf, u32 len,
+			    u32 clock, u32 flags)
+{
+	struct ngene_channel *chan = priv;
+	struct ngene *dev = chan->dev;
+	u32 alen;
+
+	alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
+	alen -= alen % 188;
+
+	if (alen < len)
+		FillTSBuffer(buf + alen, len - alen, flags);
+	else
+		alen = len;
+	dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
+	if (flags & DF_SWAP32)
+		swap_buffer((u32 *)buf, alen);
+	wake_up_interruptible(&dev->tsout_rbuf.queue);
+	return buf;
+}
+
+
+static void set_transfer(struct ngene_channel *chan, int state)
+{
+	u8 control = 0, mode = 0, flags = 0;
+	struct ngene *dev = chan->dev;
+	int ret;
+
+	/*
+	printk(KERN_INFO DEVICE_NAME ": st %d\n", state);
+	msleep(100);
+	*/
+
+	if (state) {
+		if (chan->running) {
+			printk(KERN_INFO DEVICE_NAME ": already running\n");
+			return;
+		}
+	} else {
+		if (!chan->running) {
+			printk(KERN_INFO DEVICE_NAME ": already stopped\n");
+			return;
+		}
+	}
+
+	if (dev->card_info->switch_ctrl)
+		dev->card_info->switch_ctrl(chan, 1, state ^ 1);
+
+	if (state) {
+		spin_lock_irq(&chan->state_lock);
+
+		/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+			  ngreadl(0x9310)); */
+		dvb_ringbuffer_flush(&dev->tsout_rbuf);
+		control = 0x80;
+		if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+			chan->Capture1Length = 512 * 188;
+			mode = SMODE_TRANSPORT_STREAM;
+		}
+		if (chan->mode & NGENE_IO_TSOUT) {
+			chan->pBufferExchange = tsout_exchange;
+			/* 0x66666666 = 50MHz *2^33 /250MHz */
+			chan->AudioDTOValue = 0x66666666;
+			/* set_dto(chan, 38810700+1000); */
+			/* set_dto(chan, 19392658); */
+		}
+		if (chan->mode & NGENE_IO_TSIN)
+			chan->pBufferExchange = tsin_exchange;
+		/* ngwritel(0, 0x9310); */
+		spin_unlock_irq(&chan->state_lock);
+	} else
+		;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n",
+			   ngreadl(0x9310)); */
+
+	ret = ngene_command_stream_control(dev, chan->number,
+					   control, mode, flags);
+	if (!ret)
+		chan->running = state;
+	else
+		printk(KERN_ERR DEVICE_NAME ": set_transfer %d failed\n",
+		       state);
+	if (!state) {
+		spin_lock_irq(&chan->state_lock);
+		chan->pBufferExchange = 0;
+		dvb_ringbuffer_flush(&dev->tsout_rbuf);
+		spin_unlock_irq(&chan->state_lock);
+	}
+}
+
+static int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ngene_channel *chan = dvbdmx->priv;
+
+	if (chan->users == 0) {
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+		if (!chan->running)
+#endif
+			set_transfer(chan, 1);
+		/* msleep(10); */
+	}
+
+	return ++chan->users;
+}
+
+static int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+	struct ngene_channel *chan = dvbdmx->priv;
+
+	if (--chan->users)
+		return chan->users;
+
+#ifndef COMMAND_TIMEOUT_WORKAROUND
+	set_transfer(chan, 0);
+#endif
+
+	return 0;
+}
+
+
+
+static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+				   int (*start_feed)(struct dvb_demux_feed *),
+				   int (*stop_feed)(struct dvb_demux_feed *),
+				   void *priv)
+{
+	dvbdemux->priv = priv;
+
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = start_feed;
+	dvbdemux->stop_feed = stop_feed;
+	dvbdemux->write_to_decoder = 0;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+				      DMX_SECTION_FILTERING |
+				      DMX_MEMORY_BASED_FILTERING);
+	return dvb_dmx_init(dvbdemux);
+}
+
+static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+				      struct dvb_demux *dvbdemux,
+				      struct dmx_frontend *hw_frontend,
+				      struct dmx_frontend *mem_frontend,
+				      struct dvb_adapter *dvb_adapter)
+{
+	int ret;
+
+	dmxdev->filternum = 256;
+	dmxdev->demux = &dvbdemux->dmx;
+	dmxdev->capabilities = 0;
+	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+	if (ret < 0)
+		return ret;
+
+	hw_frontend->source = DMX_FRONTEND_0;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+	mem_frontend->source = DMX_MEMORY_FE;
+	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
+
+
+/****************************************************************************/
+/* nGene hardware init and release functions ********************************/
+/****************************************************************************/
+
+static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb)
+{
+	struct SBufferHeader *Cur = rb->Head;
+	u32 j;
+
+	if (!Cur)
+		return;
+
+	for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) {
+		if (Cur->Buffer1)
+			pci_free_consistent(dev->pci_dev,
+					    rb->Buffer1Length,
+					    Cur->Buffer1,
+					    Cur->scList1->Address);
+
+		if (Cur->Buffer2)
+			pci_free_consistent(dev->pci_dev,
+					    rb->Buffer2Length,
+					    Cur->Buffer2,
+					    Cur->scList2->Address);
+	}
+
+	if (rb->SCListMem)
+		pci_free_consistent(dev->pci_dev, rb->SCListMemSize,
+				    rb->SCListMem, rb->PASCListMem);
+
+	pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead);
+}
+
+static void free_idlebuffer(struct ngene *dev,
+		     struct SRingBufferDescriptor *rb,
+		     struct SRingBufferDescriptor *tb)
+{
+	int j;
+	struct SBufferHeader *Cur = tb->Head;
+
+	if (!rb->Head)
+		return;
+	free_ringbuffer(dev, rb);
+	for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
+		Cur->Buffer2 = 0;
+		Cur->scList2 = 0;
+		Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
+		Cur->ngeneBuffer.Number_of_entries_2 = 0;
+	}
+}
+
+static void free_common_buffers(struct ngene *dev)
+{
+	u32 i;
+	struct ngene_channel *chan;
+
+	for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+		chan = &dev->channel[i];
+		free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer);
+		free_ringbuffer(dev, &chan->RingBuffer);
+		free_ringbuffer(dev, &chan->TSRingBuffer);
+	}
+
+	if (dev->OverflowBuffer)
+		pci_free_consistent(dev->pci_dev,
+				    OVERFLOW_BUFFER_SIZE,
+				    dev->OverflowBuffer, dev->PAOverflowBuffer);
+
+	if (dev->FWInterfaceBuffer)
+		pci_free_consistent(dev->pci_dev,
+				    4096,
+				    dev->FWInterfaceBuffer,
+				    dev->PAFWInterfaceBuffer);
+}
+
+/****************************************************************************/
+/* Ring buffer handling *****************************************************/
+/****************************************************************************/
+
+static int create_ring_buffer(struct pci_dev *pci_dev,
+		       struct SRingBufferDescriptor *descr, u32 NumBuffers)
+{
+	dma_addr_t tmp;
+	struct SBufferHeader *Head;
+	u32 i;
+	u32 MemSize = SIZEOF_SBufferHeader * NumBuffers;
+	u64 PARingBufferHead;
+	u64 PARingBufferCur;
+	u64 PARingBufferNext;
+	struct SBufferHeader *Cur, *Next;
+
+	descr->Head = 0;
+	descr->MemSize = 0;
+	descr->PAHead = 0;
+	descr->NumBuffers = 0;
+
+	if (MemSize < 4096)
+		MemSize = 4096;
+
+	Head = pci_alloc_consistent(pci_dev, MemSize, &tmp);
+	PARingBufferHead = tmp;
+
+	if (!Head)
+		return -ENOMEM;
+
+	memset(Head, 0, MemSize);
+
+	PARingBufferCur = PARingBufferHead;
+	Cur = Head;
+
+	for (i = 0; i < NumBuffers - 1; i++) {
+		Next = (struct SBufferHeader *)
+			(((u8 *) Cur) + SIZEOF_SBufferHeader);
+		PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader;
+		Cur->Next = Next;
+		Cur->ngeneBuffer.Next = PARingBufferNext;
+		Cur = Next;
+		PARingBufferCur = PARingBufferNext;
+	}
+	/* Last Buffer points back to first one */
+	Cur->Next = Head;
+	Cur->ngeneBuffer.Next = PARingBufferHead;
+
+	descr->Head       = Head;
+	descr->MemSize    = MemSize;
+	descr->PAHead     = PARingBufferHead;
+	descr->NumBuffers = NumBuffers;
+
+	return 0;
+}
+
+static int AllocateRingBuffers(struct pci_dev *pci_dev,
+			       dma_addr_t of,
+			       struct SRingBufferDescriptor *pRingBuffer,
+			       u32 Buffer1Length, u32 Buffer2Length)
+{
+	dma_addr_t tmp;
+	u32 i, j;
+	int status = 0;
+	u32 SCListMemSize = pRingBuffer->NumBuffers
+		* ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
+		    NUM_SCATTER_GATHER_ENTRIES)
+		* sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+	u64 PASCListMem;
+	struct HW_SCATTER_GATHER_ELEMENT *SCListEntry;
+	u64 PASCListEntry;
+	struct SBufferHeader *Cur;
+	void *SCListMem;
+
+	if (SCListMemSize < 4096)
+		SCListMemSize = 4096;
+
+	SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp);
+
+	PASCListMem = tmp;
+	if (SCListMem == NULL)
+		return -ENOMEM;
+
+	memset(SCListMem, 0, SCListMemSize);
+
+	pRingBuffer->SCListMem = SCListMem;
+	pRingBuffer->PASCListMem = PASCListMem;
+	pRingBuffer->SCListMemSize = SCListMemSize;
+	pRingBuffer->Buffer1Length = Buffer1Length;
+	pRingBuffer->Buffer2Length = Buffer2Length;
+
+	SCListEntry = SCListMem;
+	PASCListEntry = PASCListMem;
+	Cur = pRingBuffer->Head;
+
+	for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) {
+		u64 PABuffer;
+
+		void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length,
+						    &tmp);
+		PABuffer = tmp;
+
+		if (Buffer == NULL)
+			return -ENOMEM;
+
+		Cur->Buffer1 = Buffer;
+
+		SCListEntry->Address = PABuffer;
+		SCListEntry->Length  = Buffer1Length;
+
+		Cur->scList1 = SCListEntry;
+		Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry;
+		Cur->ngeneBuffer.Number_of_entries_1 =
+			NUM_SCATTER_GATHER_ENTRIES;
+
+		SCListEntry += 1;
+		PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+		for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) {
+			SCListEntry->Address = of;
+			SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+			SCListEntry += 1;
+			PASCListEntry +=
+				sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+		}
+#endif
+
+		if (!Buffer2Length)
+			continue;
+
+		Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp);
+		PABuffer = tmp;
+
+		if (Buffer == NULL)
+			return -ENOMEM;
+
+		Cur->Buffer2 = Buffer;
+
+		SCListEntry->Address = PABuffer;
+		SCListEntry->Length  = Buffer2Length;
+
+		Cur->scList2 = SCListEntry;
+		Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry;
+		Cur->ngeneBuffer.Number_of_entries_2 =
+			NUM_SCATTER_GATHER_ENTRIES;
+
+		SCListEntry   += 1;
+		PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+
+#if NUM_SCATTER_GATHER_ENTRIES > 1
+		for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) {
+			SCListEntry->Address = of;
+			SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
+			SCListEntry += 1;
+			PASCListEntry +=
+				sizeof(struct HW_SCATTER_GATHER_ELEMENT);
+		}
+#endif
+
+	}
+
+	return status;
+}
+
+static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
+			    struct SRingBufferDescriptor *pRingBuffer)
+{
+	int status = 0;
+
+	/* Copy pointer to scatter gather list in TSRingbuffer
+	   structure for buffer 2
+	   Load number of buffer
+	*/
+	u32 n = pRingBuffer->NumBuffers;
+
+	/* Point to first buffer entry */
+	struct SBufferHeader *Cur = pRingBuffer->Head;
+	int i;
+	/* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */
+	for (i = 0; i < n; i++) {
+		Cur->Buffer2 = pIdleBuffer->Head->Buffer1;
+		Cur->scList2 = pIdleBuffer->Head->scList1;
+		Cur->ngeneBuffer.Address_of_first_entry_2 =
+			pIdleBuffer->Head->ngeneBuffer.
+			Address_of_first_entry_1;
+		Cur->ngeneBuffer.Number_of_entries_2 =
+			pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
+		Cur = Cur->Next;
+	}
+	return status;
+}
+
+static u32 RingBufferSizes[MAX_STREAM] = {
+	RING_SIZE_VIDEO,
+	RING_SIZE_VIDEO,
+	RING_SIZE_AUDIO,
+	RING_SIZE_AUDIO,
+	RING_SIZE_AUDIO,
+};
+
+static u32 Buffer1Sizes[MAX_STREAM] = {
+	MAX_VIDEO_BUFFER_SIZE,
+	MAX_VIDEO_BUFFER_SIZE,
+	MAX_AUDIO_BUFFER_SIZE,
+	MAX_AUDIO_BUFFER_SIZE,
+	MAX_AUDIO_BUFFER_SIZE
+};
+
+static u32 Buffer2Sizes[MAX_STREAM] = {
+	MAX_VBI_BUFFER_SIZE,
+	MAX_VBI_BUFFER_SIZE,
+	0,
+	0,
+	0
+};
+
+
+static int AllocCommonBuffers(struct ngene *dev)
+{
+	int status = 0, i;
+
+	dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096,
+						     &dev->PAFWInterfaceBuffer);
+	if (!dev->FWInterfaceBuffer)
+		return -ENOMEM;
+	dev->hosttongene = dev->FWInterfaceBuffer;
+	dev->ngenetohost = dev->FWInterfaceBuffer + 256;
+	dev->EventBuffer = dev->FWInterfaceBuffer + 512;
+
+	dev->OverflowBuffer = pci_alloc_consistent(dev->pci_dev,
+						   OVERFLOW_BUFFER_SIZE,
+						   &dev->PAOverflowBuffer);
+	if (!dev->OverflowBuffer)
+		return -ENOMEM;
+	memset(dev->OverflowBuffer, 0, OVERFLOW_BUFFER_SIZE);
+
+	for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
+		int type = dev->card_info->io_type[i];
+
+		dev->channel[i].State = KSSTATE_STOP;
+
+		if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) {
+			status = create_ring_buffer(dev->pci_dev,
+						    &dev->channel[i].RingBuffer,
+						    RingBufferSizes[i]);
+			if (status < 0)
+				break;
+
+			if (type & (NGENE_IO_TV | NGENE_IO_AIN)) {
+				status = AllocateRingBuffers(dev->pci_dev,
+							     dev->
+							     PAOverflowBuffer,
+							     &dev->channel[i].
+							     RingBuffer,
+							     Buffer1Sizes[i],
+							     Buffer2Sizes[i]);
+				if (status < 0)
+					break;
+			} else if (type & NGENE_IO_HDTV) {
+				status = AllocateRingBuffers(dev->pci_dev,
+							     dev->
+							     PAOverflowBuffer,
+							     &dev->channel[i].
+							     RingBuffer,
+							   MAX_HDTV_BUFFER_SIZE,
+							     0);
+				if (status < 0)
+					break;
+			}
+		}
+
+		if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+
+			status = create_ring_buffer(dev->pci_dev,
+						    &dev->channel[i].
+						    TSRingBuffer, RING_SIZE_TS);
+			if (status < 0)
+				break;
+
+			status = AllocateRingBuffers(dev->pci_dev,
+						     dev->PAOverflowBuffer,
+						     &dev->channel[i].
+						     TSRingBuffer,
+						     MAX_TS_BUFFER_SIZE, 0);
+			if (status)
+				break;
+		}
+
+		if (type & NGENE_IO_TSOUT) {
+			status = create_ring_buffer(dev->pci_dev,
+						    &dev->channel[i].
+						    TSIdleBuffer, 1);
+			if (status < 0)
+				break;
+			status = AllocateRingBuffers(dev->pci_dev,
+						     dev->PAOverflowBuffer,
+						     &dev->channel[i].
+						     TSIdleBuffer,
+						     MAX_TS_BUFFER_SIZE, 0);
+			if (status)
+				break;
+			FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer,
+					 &dev->channel[i].TSRingBuffer);
+		}
+	}
+	return status;
+}
+
+static void ngene_release_buffers(struct ngene *dev)
+{
+	if (dev->iomem)
+		iounmap(dev->iomem);
+	free_common_buffers(dev);
+	vfree(dev->tsout_buf);
+	vfree(dev->ain_buf);
+	vfree(dev->vin_buf);
+	vfree(dev);
+}
+
+static int ngene_get_buffers(struct ngene *dev)
+{
+	if (AllocCommonBuffers(dev))
+		return -ENOMEM;
+	if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) {
+		dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE);
+		if (!dev->tsout_buf)
+			return -ENOMEM;
+		dvb_ringbuffer_init(&dev->tsout_rbuf,
+				    dev->tsout_buf, TSOUT_BUF_SIZE);
+	}
+	if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
+		dev->ain_buf = vmalloc(AIN_BUF_SIZE);
+		if (!dev->ain_buf)
+			return -ENOMEM;
+		dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE);
+	}
+	if (dev->card_info->io_type[0] & NGENE_IO_HDTV) {
+		dev->vin_buf = vmalloc(VIN_BUF_SIZE);
+		if (!dev->vin_buf)
+			return -ENOMEM;
+		dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE);
+	}
+	dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0),
+			     pci_resource_len(dev->pci_dev, 0));
+	if (!dev->iomem)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void ngene_init(struct ngene *dev)
+{
+	int i;
+
+	tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
+
+	memset_io(dev->iomem + 0xc000, 0x00, 0x220);
+	memset_io(dev->iomem + 0xc400, 0x00, 0x100);
+
+	for (i = 0; i < MAX_STREAM; i++) {
+		dev->channel[i].dev = dev;
+		dev->channel[i].number = i;
+	}
+
+	dev->fw_interface_version = 0;
+
+	ngwritel(0, NGENE_INT_ENABLE);
+
+	dev->icounts = ngreadl(NGENE_INT_COUNTS);
+
+	dev->device_version = ngreadl(DEV_VER) & 0x0f;
+	printk(KERN_INFO DEVICE_NAME ": Device version %d\n",
+	       dev->device_version);
+}
+
+static int ngene_load_firm(struct ngene *dev)
+{
+	u32 size;
+	const struct firmware *fw = NULL;
+	u8 *ngene_fw;
+	char *fw_name;
+	int err, version;
+
+	version = dev->card_info->fw_version;
+
+	switch (version) {
+	default:
+	case 15:
+		version = 15;
+		size = 23466;
+		fw_name = "ngene_15.fw";
+		break;
+	case 16:
+		size = 23498;
+		fw_name = "ngene_16.fw";
+		break;
+	case 17:
+		size = 24446;
+		fw_name = "ngene_17.fw";
+		break;
+	}
+
+	if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
+		printk(KERN_ERR DEVICE_NAME
+			": Could not load firmware file %s.\n", fw_name);
+		printk(KERN_INFO DEVICE_NAME
+			": Copy %s to your hotplug directory!\n", fw_name);
+		return -1;
+	}
+	if (size != fw->size) {
+		printk(KERN_ERR DEVICE_NAME
+			": Firmware %s has invalid size!", fw_name);
+		err = -1;
+	} else {
+		printk(KERN_INFO DEVICE_NAME
+			": Loading firmware file %s.\n", fw_name);
+		ngene_fw = (u8 *) fw->data;
+		err = ngene_command_load_firmware(dev, ngene_fw, size);
+	}
+
+	release_firmware(fw);
+
+	return err;
+}
+
+static void ngene_stop(struct ngene *dev)
+{
+	down(&dev->cmd_mutex);
+	i2c_del_adapter(&(dev->channel[0].i2c_adapter));
+	i2c_del_adapter(&(dev->channel[1].i2c_adapter));
+	ngwritel(0, NGENE_INT_ENABLE);
+	ngwritel(0, NGENE_COMMAND);
+	ngwritel(0, NGENE_COMMAND_HI);
+	ngwritel(0, NGENE_STATUS);
+	ngwritel(0, NGENE_STATUS_HI);
+	ngwritel(0, NGENE_EVENT);
+	ngwritel(0, NGENE_EVENT_HI);
+	free_irq(dev->pci_dev->irq, dev);
+}
+
+static int ngene_start(struct ngene *dev)
+{
+	int stat;
+	int i;
+
+	pci_set_master(dev->pci_dev);
+	ngene_init(dev);
+
+	stat = request_irq(dev->pci_dev->irq, irq_handler,
+			   IRQF_SHARED, "nGene",
+			   (void *)dev);
+	if (stat < 0)
+		return stat;
+
+	init_waitqueue_head(&dev->cmd_wq);
+	init_waitqueue_head(&dev->tx_wq);
+	init_waitqueue_head(&dev->rx_wq);
+	sema_init(&dev->cmd_mutex, 1);
+	sema_init(&dev->stream_mutex, 1);
+	sema_init(&dev->pll_mutex, 1);
+	sema_init(&dev->i2c_switch_mutex, 1);
+	spin_lock_init(&dev->cmd_lock);
+	for (i = 0; i < MAX_STREAM; i++)
+		spin_lock_init(&dev->channel[i].state_lock);
+	ngwritel(1, TIMESTAMPS);
+
+	ngwritel(1, NGENE_INT_ENABLE);
+
+	stat = ngene_load_firm(dev);
+	if (stat < 0)
+		goto fail;
+
+	stat = ngene_i2c_init(dev, 0);
+	if (stat < 0)
+		goto fail;
+
+	stat = ngene_i2c_init(dev, 1);
+	if (stat < 0)
+		goto fail;
+
+	if (dev->card_info->fw_version == 17) {
+		u8 tsin4_config[6] = {
+			3072 / 64, 3072 / 64, 0, 3072 / 64, 3072 / 64, 0};
+		u8 default_config[6] = {
+			4096 / 64, 4096 / 64, 0, 2048 / 64, 2048 / 64, 0};
+		u8 *bconf = default_config;
+
+		if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
+			bconf = tsin4_config;
+		dprintk(KERN_DEBUG DEVICE_NAME ": FW 17 buffer config\n");
+		stat = ngene_command_config_free_buf(dev, bconf);
+	} else {
+		int bconf = BUFFER_CONFIG_4422;
+		if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
+			bconf = BUFFER_CONFIG_3333;
+		stat = ngene_command_config_buf(dev, bconf);
+	}
+	return stat;
+fail:
+	ngwritel(0, NGENE_INT_ENABLE);
+	free_irq(dev->pci_dev->irq, dev);
+	return stat;
+}
+
+
+
+/****************************************************************************/
+/* Switch control (I2C gates, etc.) *****************************************/
+/****************************************************************************/
+
+
+/****************************************************************************/
+/* Demod/tuner attachment ***************************************************/
+/****************************************************************************/
+
+static int tuner_attach_stv6110(struct ngene_channel *chan)
+{
+	struct stv090x_config *feconf = (struct stv090x_config *)
+		chan->dev->card_info->fe_config[chan->number];
+	struct stv6110x_config *tunerconf = (struct stv6110x_config *)
+		chan->dev->card_info->tuner_config[chan->number];
+	struct stv6110x_devctl *ctl;
+
+	ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf,
+			 &chan->i2c_adapter);
+	if (ctl == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No STV6110X found!\n");
+		return -ENODEV;
+	}
+
+	feconf->tuner_init          = ctl->tuner_init;
+	feconf->tuner_set_mode      = ctl->tuner_set_mode;
+	feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+	feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+	feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+	feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+	feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
+	feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
+	feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
+	feconf->tuner_get_status    = ctl->tuner_get_status;
+
+	return 0;
+}
+
+
+static int demod_attach_stv0900(struct ngene_channel *chan)
+{
+	struct stv090x_config *feconf = (struct stv090x_config *)
+		chan->dev->card_info->fe_config[chan->number];
+
+	chan->fe = dvb_attach(stv090x_attach,
+			feconf,
+			&chan->i2c_adapter,
+			chan->number == 0 ? STV090x_DEMODULATOR_0 :
+					    STV090x_DEMODULATOR_1);
+	if (chan->fe == NULL) {
+		printk(KERN_ERR	DEVICE_NAME ": No STV0900 found!\n");
+		return -ENODEV;
+	}
+
+	if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0,
+			0, chan->dev->card_info->lnb[chan->number])) {
+		printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n");
+		dvb_frontend_detach(chan->fe);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void release_channel(struct ngene_channel *chan)
+{
+	struct dvb_demux *dvbdemux = &chan->demux;
+	struct ngene *dev = chan->dev;
+	struct ngene_info *ni = dev->card_info;
+	int io = ni->io_type[chan->number];
+
+#ifdef COMMAND_TIMEOUT_WORKAROUND
+	if (chan->running)
+		set_transfer(chan, 0);
+#endif
+
+	tasklet_kill(&chan->demux_tasklet);
+
+	if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+		if (chan->fe) {
+			dvb_unregister_frontend(chan->fe);
+			dvb_frontend_detach(chan->fe);
+			chan->fe = 0;
+		}
+		dvbdemux->dmx.close(&dvbdemux->dmx);
+		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+					      &chan->hw_frontend);
+		dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+					      &chan->mem_frontend);
+		dvb_dmxdev_release(&chan->dmxdev);
+		dvb_dmx_release(&chan->demux);
+
+		if (chan->number == 0 || !one_adapter)
+			dvb_unregister_adapter(&dev->adapter[chan->number]);
+	}
+}
+
+static int init_channel(struct ngene_channel *chan)
+{
+	int ret = 0, nr = chan->number;
+	struct dvb_adapter *adapter = NULL;
+	struct dvb_demux *dvbdemux = &chan->demux;
+	struct ngene *dev = chan->dev;
+	struct ngene_info *ni = dev->card_info;
+	int io = ni->io_type[nr];
+
+	tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan);
+	chan->users = 0;
+	chan->type = io;
+	chan->mode = chan->type;	/* for now only one mode */
+
+	if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
+		if (nr >= STREAM_AUDIOIN1)
+			chan->DataFormatFlags = DF_SWAP32;
+		if (nr == 0 || !one_adapter) {
+			adapter = &dev->adapter[nr];
+			ret = dvb_register_adapter(adapter, "nGene",
+						   THIS_MODULE,
+						   &chan->dev->pci_dev->dev,
+						   adapter_nr);
+			if (ret < 0)
+				return ret;
+		} else {
+			adapter = &dev->adapter[0];
+		}
+
+		ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+					      ngene_start_feed,
+					      ngene_stop_feed, chan);
+		ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
+						 &chan->hw_frontend,
+						 &chan->mem_frontend, adapter);
+	}
+
+	if (io & NGENE_IO_TSIN) {
+		chan->fe = NULL;
+		if (ni->demod_attach[nr])
+			ni->demod_attach[nr](chan);
+		if (chan->fe) {
+			if (dvb_register_frontend(adapter, chan->fe) < 0) {
+				if (chan->fe->ops.release)
+					chan->fe->ops.release(chan->fe);
+				chan->fe = NULL;
+			}
+		}
+		if (chan->fe && ni->tuner_attach[nr])
+			if (ni->tuner_attach[nr] (chan) < 0) {
+				printk(KERN_ERR DEVICE_NAME
+				       ": Tuner attach failed on channel %d!\n",
+				       nr);
+			}
+	}
+	return ret;
+}
+
+static int init_channels(struct ngene *dev)
+{
+	int i, j;
+
+	for (i = 0; i < MAX_STREAM; i++) {
+		if (init_channel(&dev->channel[i]) < 0) {
+			for (j = i - 1; j >= 0; j--)
+				release_channel(&dev->channel[j]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/****************************************************************************/
+/* device probe/remove calls ************************************************/
+/****************************************************************************/
+
+static void __devexit ngene_remove(struct pci_dev *pdev)
+{
+	struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+	int i;
+
+	tasklet_kill(&dev->event_tasklet);
+	for (i = MAX_STREAM - 1; i >= 0; i--)
+		release_channel(&dev->channel[i]);
+	ngene_stop(dev);
+	ngene_release_buffers(dev);
+	pci_set_drvdata(pdev, 0);
+	pci_disable_device(pdev);
+}
+
+static int __devinit ngene_probe(struct pci_dev *pci_dev,
+				 const struct pci_device_id *id)
+{
+	struct ngene *dev;
+	int stat = 0;
+
+	if (pci_enable_device(pci_dev) < 0)
+		return -ENODEV;
+
+	dev = vmalloc(sizeof(struct ngene));
+	if (dev == NULL) {
+		stat = -ENOMEM;
+		goto fail0;
+	}
+	memset(dev, 0, sizeof(struct ngene));
+
+	dev->pci_dev = pci_dev;
+	dev->card_info = (struct ngene_info *)id->driver_data;
+	printk(KERN_INFO DEVICE_NAME ": Found %s\n", dev->card_info->name);
+
+	pci_set_drvdata(pci_dev, dev);
+
+	/* Alloc buffers and start nGene */
+	stat = ngene_get_buffers(dev);
+	if (stat < 0)
+		goto fail1;
+	stat = ngene_start(dev);
+	if (stat < 0)
+		goto fail1;
+
+	dev->i2c_current_bus = -1;
+
+	/* Register DVB adapters and devices for both channels */
+	if (init_channels(dev) < 0)
+		goto fail2;
+
+	return 0;
+
+fail2:
+	ngene_stop(dev);
+fail1:
+	ngene_release_buffers(dev);
+fail0:
+	pci_disable_device(pci_dev);
+	pci_set_drvdata(pci_dev, 0);
+	return stat;
+}
+
+/****************************************************************************/
+/* Card configs *************************************************************/
+/****************************************************************************/
+
+static struct stv090x_config fe_cineS2 = {
+	.device         = STV0900,
+	.demod_mode     = STV090x_DUAL,
+	.clk_mode       = STV090x_CLK_EXT,
+
+	.xtal           = 27000000,
+	.address        = 0x68,
+
+	.ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+	.ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+	.repeater_level = STV090x_RPTLEVEL_16,
+
+	.adc1_range	= STV090x_ADC_1Vpp,
+	.adc2_range	= STV090x_ADC_1Vpp,
+
+	.diseqc_envelope_mode = true,
+};
+
+static struct stv6110x_config tuner_cineS2_0 = {
+	.addr	= 0x60,
+	.refclk	= 27000000,
+	.clk_div = 1,
+};
+
+static struct stv6110x_config tuner_cineS2_1 = {
+	.addr	= 0x63,
+	.refclk	= 27000000,
+	.clk_div = 1,
+};
+
+static struct ngene_info ngene_info_cineS2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Linux4Media cineS2 DVB-S2 Twin Tuner",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0b, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 15,
+};
+
+static struct ngene_info ngene_info_satixs2 = {
+	.type		= NGENE_SIDEWINDER,
+	.name		= "Mystique SaTiX-S2 Dual",
+	.io_type	= {NGENE_IO_TSIN, NGENE_IO_TSIN},
+	.demod_attach	= {demod_attach_stv0900, demod_attach_stv0900},
+	.tuner_attach	= {tuner_attach_stv6110, tuner_attach_stv6110},
+	.fe_config	= {&fe_cineS2, &fe_cineS2},
+	.tuner_config	= {&tuner_cineS2_0, &tuner_cineS2_1},
+	.lnb		= {0x0b, 0x08},
+	.tsf		= {3, 3},
+	.fw_version	= 15,
+};
+
+/****************************************************************************/
+
+
+
+/****************************************************************************/
+/* PCI Subsystem ID *********************************************************/
+/****************************************************************************/
+
+#define NGENE_ID(_subvend, _subdev, _driverdata) { \
+	.vendor = NGENE_VID, .device = NGENE_PID, \
+	.subvendor = _subvend, .subdevice = _subdev, \
+	.driver_data = (unsigned long) &_driverdata }
+
+/****************************************************************************/
+
+static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
+	NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
+	NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
+	NGENE_ID(0x18c3, 0xdb01, ngene_info_satixs2),
+	{0}
+};
+MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
+
+/****************************************************************************/
+/* Init/Exit ****************************************************************/
+/****************************************************************************/
+
+static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
+					     enum pci_channel_state state)
+{
+	printk(KERN_ERR DEVICE_NAME ": PCI error\n");
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+	if (state == pci_channel_io_frozen)
+		return PCI_ERS_RESULT_NEED_RESET;
+	return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": link reset\n");
+	return 0;
+}
+
+static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": slot reset\n");
+	return 0;
+}
+
+static void ngene_resume(struct pci_dev *dev)
+{
+	printk(KERN_INFO DEVICE_NAME ": resume\n");
+}
+
+static struct pci_error_handlers ngene_errors = {
+	.error_detected = ngene_error_detected,
+	.link_reset = ngene_link_reset,
+	.slot_reset = ngene_slot_reset,
+	.resume = ngene_resume,
+};
+
+static struct pci_driver ngene_pci_driver = {
+	.name        = "ngene",
+	.id_table    = ngene_id_tbl,
+	.probe       = ngene_probe,
+	.remove      = __devexit_p(ngene_remove),
+	.err_handler = &ngene_errors,
+};
+
+static __init int module_init_ngene(void)
+{
+	printk(KERN_INFO
+	       "nGene PCIE bridge driver, Copyright (C) 2005-2007 Micronas\n");
+	return pci_register_driver(&ngene_pci_driver);
+}
+
+static __exit void module_exit_ngene(void)
+{
+	pci_unregister_driver(&ngene_pci_driver);
+}
+
+module_init(module_init_ngene);
+module_exit(module_exit_ngene);
+
+MODULE_DESCRIPTION("nGene");
+MODULE_AUTHOR("Micronas, Ralph Metzler, Manfred Voelkel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h
new file mode 100644
index 000000000000..a7eb29846310
--- /dev/null
+++ b/drivers/media/dvb/ngene/ngene.h
@@ -0,0 +1,859 @@
+/*
+ * ngene.h: nGene PCIe bridge driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _NGENE_H_
+#define _NGENE_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <asm/dma.h>
+#include <linux/scatterlist.h>
+
+#include <linux/dvb/frontend.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_ringbuffer.h"
+
+#define NGENE_VID       0x18c3
+#define NGENE_PID       0x0720
+
+#ifndef VIDEO_CAP_VC1
+#define VIDEO_CAP_AVC   128
+#define VIDEO_CAP_H264  128
+#define VIDEO_CAP_VC1   256
+#define VIDEO_CAP_WMV9  256
+#define VIDEO_CAP_MPEG4 512
+#endif
+
+enum STREAM {
+	STREAM_VIDEOIN1 = 0,        /* ITU656 or TS Input */
+	STREAM_VIDEOIN2,
+	STREAM_AUDIOIN1,            /* I2S or SPI Input */
+	STREAM_AUDIOIN2,
+	STREAM_AUDIOOUT,
+	MAX_STREAM
+};
+
+enum SMODE_BITS {
+	SMODE_AUDIO_SPDIF = 0x20,
+	SMODE_AVSYNC = 0x10,
+	SMODE_TRANSPORT_STREAM = 0x08,
+	SMODE_AUDIO_CAPTURE = 0x04,
+	SMODE_VBI_CAPTURE = 0x02,
+	SMODE_VIDEO_CAPTURE = 0x01
+};
+
+enum STREAM_FLAG_BITS {
+	SFLAG_CHROMA_FORMAT_2COMP  = 0x01, /* Chroma Format : 2's complement */
+	SFLAG_CHROMA_FORMAT_OFFSET = 0x00, /* Chroma Format : Binary offset */
+	SFLAG_ORDER_LUMA_CHROMA    = 0x02, /* Byte order: Y,Cb,Y,Cr */
+	SFLAG_ORDER_CHROMA_LUMA    = 0x00, /* Byte order: Cb,Y,Cr,Y */
+	SFLAG_COLORBAR             = 0x04, /* Select colorbar */
+};
+
+#define PROGRAM_ROM     0x0000
+#define PROGRAM_SRAM    0x1000
+#define PERIPHERALS0    0x8000
+#define PERIPHERALS1    0x9000
+#define SHARED_BUFFER   0xC000
+
+#define HOST_TO_NGENE    (SHARED_BUFFER+0x0000)
+#define NGENE_TO_HOST    (SHARED_BUFFER+0x0100)
+#define NGENE_COMMAND    (SHARED_BUFFER+0x0200)
+#define NGENE_COMMAND_HI (SHARED_BUFFER+0x0204)
+#define NGENE_STATUS     (SHARED_BUFFER+0x0208)
+#define NGENE_STATUS_HI  (SHARED_BUFFER+0x020C)
+#define NGENE_EVENT      (SHARED_BUFFER+0x0210)
+#define NGENE_EVENT_HI   (SHARED_BUFFER+0x0214)
+#define VARIABLES        (SHARED_BUFFER+0x0210)
+
+#define NGENE_INT_COUNTS       (SHARED_BUFFER+0x0260)
+#define NGENE_INT_ENABLE       (SHARED_BUFFER+0x0264)
+#define NGENE_VBI_LINE_COUNT   (SHARED_BUFFER+0x0268)
+
+#define BUFFER_GP_XMIT  (SHARED_BUFFER+0x0800)
+#define BUFFER_GP_RECV  (SHARED_BUFFER+0x0900)
+#define EEPROM_AREA     (SHARED_BUFFER+0x0A00)
+
+#define SG_V_IN_1       (SHARED_BUFFER+0x0A80)
+#define SG_VBI_1        (SHARED_BUFFER+0x0B00)
+#define SG_A_IN_1       (SHARED_BUFFER+0x0B80)
+#define SG_V_IN_2       (SHARED_BUFFER+0x0C00)
+#define SG_VBI_2        (SHARED_BUFFER+0x0C80)
+#define SG_A_IN_2       (SHARED_BUFFER+0x0D00)
+#define SG_V_OUT        (SHARED_BUFFER+0x0D80)
+#define SG_A_OUT2       (SHARED_BUFFER+0x0E00)
+
+#define DATA_A_IN_1     (SHARED_BUFFER+0x0E80)
+#define DATA_A_IN_2     (SHARED_BUFFER+0x0F00)
+#define DATA_A_OUT      (SHARED_BUFFER+0x0F80)
+#define DATA_V_IN_1     (SHARED_BUFFER+0x1000)
+#define DATA_V_IN_2     (SHARED_BUFFER+0x2000)
+#define DATA_V_OUT      (SHARED_BUFFER+0x3000)
+
+#define DATA_FIFO_AREA  (SHARED_BUFFER+0x1000)
+
+#define TIMESTAMPS      0xA000
+#define SCRATCHPAD      0xA080
+#define FORCE_INT       0xA088
+#define FORCE_NMI       0xA090
+#define INT_STATUS      0xA0A0
+
+#define DEV_VER         0x9004
+
+#define FW_DEBUG_DEFAULT (PROGRAM_SRAM+0x00FF)
+
+struct SG_ADDR {
+	u64 start;
+	u64 curr;
+	u16 curr_ptr;
+	u16 elements;
+	u32 pad[3];
+} __attribute__ ((__packed__));
+
+struct SHARED_MEMORY {
+	/* C000 */
+	u32 HostToNgene[64];
+
+	/* C100 */
+	u32 NgeneToHost[64];
+
+	/* C200 */
+	u64 NgeneCommand;
+	u64 NgeneStatus;
+	u64 NgeneEvent;
+
+	/* C210 */
+	u8 pad1[0xc260 - 0xc218];
+
+	/* C260 */
+	u32 IntCounts;
+	u32 IntEnable;
+
+	/* C268 */
+	u8 pad2[0xd000 - 0xc268];
+
+} __attribute__ ((__packed__));
+
+struct BUFFER_STREAM_RESULTS {
+	u32 Clock;           /* Stream time in 100ns units */
+	u16 RemainingLines;  /* Remaining lines in this field.
+				0 for complete field */
+	u8  FieldCount;      /* Video field number */
+	u8  Flags;           /* Bit 7 = Done, Bit 6 = seen, Bit 5 = overflow,
+				Bit 0 = FieldID */
+	u16 BlockCount;      /* Audio block count (unused) */
+	u8  Reserved[2];
+	u32 DTOUpdate;
+} __attribute__ ((__packed__));
+
+struct HW_SCATTER_GATHER_ELEMENT {
+	u64 Address;
+	u32 Length;
+	u32 Reserved;
+} __attribute__ ((__packed__));
+
+struct BUFFER_HEADER {
+	u64    Next;
+	struct BUFFER_STREAM_RESULTS SR;
+
+	u32    Number_of_entries_1;
+	u32    Reserved5;
+	u64    Address_of_first_entry_1;
+
+	u32    Number_of_entries_2;
+	u32    Reserved7;
+	u64    Address_of_first_entry_2;
+} __attribute__ ((__packed__));
+
+struct EVENT_BUFFER {
+	u32    TimeStamp;
+	u8     GPIOStatus;
+	u8     UARTStatus;
+	u8     RXCharacter;
+	u8     EventStatus;
+	u32    Reserved[2];
+} __attribute__ ((__packed__));
+
+/* Firmware commands. */
+
+enum OPCODES {
+	CMD_NOP = 0,
+	CMD_FWLOAD_PREPARE  = 0x01,
+	CMD_FWLOAD_FINISH   = 0x02,
+	CMD_I2C_READ        = 0x03,
+	CMD_I2C_WRITE       = 0x04,
+
+	CMD_I2C_WRITE_NOSTOP = 0x05,
+	CMD_I2C_CONTINUE_WRITE = 0x06,
+	CMD_I2C_CONTINUE_WRITE_NOSTOP = 0x07,
+
+	CMD_DEBUG_OUTPUT    = 0x09,
+
+	CMD_CONTROL         = 0x10,
+	CMD_CONFIGURE_BUFFER = 0x11,
+	CMD_CONFIGURE_FREE_BUFFER = 0x12,
+
+	CMD_SPI_READ        = 0x13,
+	CMD_SPI_WRITE       = 0x14,
+
+	CMD_MEM_READ        = 0x20,
+	CMD_MEM_WRITE	    = 0x21,
+	CMD_SFR_READ	    = 0x22,
+	CMD_SFR_WRITE	    = 0x23,
+	CMD_IRAM_READ	    = 0x24,
+	CMD_IRAM_WRITE	    = 0x25,
+	CMD_SET_GPIO_PIN    = 0x26,
+	CMD_SET_GPIO_INT    = 0x27,
+	CMD_CONFIGURE_UART  = 0x28,
+	CMD_WRITE_UART      = 0x29,
+	MAX_CMD
+};
+
+enum RESPONSES {
+	OK = 0,
+	ERROR = 1
+};
+
+struct FW_HEADER {
+	u8 Opcode;
+	u8 Length;
+} __attribute__ ((__packed__));
+
+struct FW_I2C_WRITE {
+	struct FW_HEADER hdr;
+	u8 Device;
+	u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_I2C_CONTINUE_WRITE {
+	struct FW_HEADER hdr;
+	u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_I2C_READ {
+	struct FW_HEADER hdr;
+	u8 Device;
+	u8 Data[252];    /* followed by two bytes of read data count */
+} __attribute__ ((__packed__));
+
+struct FW_SPI_WRITE {
+	struct FW_HEADER hdr;
+	u8 ModeSelect;
+	u8 Data[250];
+} __attribute__ ((__packed__));
+
+struct FW_SPI_READ {
+	struct FW_HEADER hdr;
+	u8 ModeSelect;
+	u8 Data[252];    /* followed by two bytes of read data count */
+} __attribute__ ((__packed__));
+
+struct FW_FWLOAD_PREPARE {
+	struct FW_HEADER hdr;
+} __attribute__ ((__packed__));
+
+struct FW_FWLOAD_FINISH {
+	struct FW_HEADER hdr;
+	u16 Address;     /* address of final block */
+	u16 Length;
+} __attribute__ ((__packed__));
+
+/*
+ * Meaning of FW_STREAM_CONTROL::Mode bits:
+ *  Bit 7: Loopback PEXin to PEXout using TVOut channel
+ *  Bit 6: AVLOOP
+ *  Bit 5: Audio select; 0=I2S, 1=SPDIF
+ *  Bit 4: AVSYNC
+ *  Bit 3: Enable transport stream
+ *  Bit 2: Enable audio capture
+ *  Bit 1: Enable ITU-Video VBI capture
+ *  Bit 0: Enable ITU-Video capture
+ *
+ * Meaning of FW_STREAM_CONTROL::Control bits (see UVI1_CTL)
+ *  Bit 7: continuous capture
+ *  Bit 6: capture one field
+ *  Bit 5: capture one frame
+ *  Bit 4: unused
+ *  Bit 3: starting field; 0=odd, 1=even
+ *  Bit 2: sample size; 0=8-bit, 1=10-bit
+ *  Bit 1: data format; 0=UYVY, 1=YUY2
+ *  Bit 0: resets buffer pointers
+*/
+
+enum FSC_MODE_BITS {
+	SMODE_LOOPBACK          = 0x80,
+	SMODE_AVLOOP            = 0x40,
+	_SMODE_AUDIO_SPDIF      = 0x20,
+	_SMODE_AVSYNC           = 0x10,
+	_SMODE_TRANSPORT_STREAM = 0x08,
+	_SMODE_AUDIO_CAPTURE    = 0x04,
+	_SMODE_VBI_CAPTURE      = 0x02,
+	_SMODE_VIDEO_CAPTURE    = 0x01
+};
+
+
+/* Meaning of FW_STREAM_CONTROL::Stream bits:
+ * Bit 3: Audio sample count:  0 = relative, 1 = absolute
+ * Bit 2: color bar select; 1=color bars, 0=CV3 decoder
+ * Bits 1-0: stream select, UVI1, UVI2, TVOUT
+ */
+
+struct FW_STREAM_CONTROL {
+	struct FW_HEADER hdr;
+	u8     Stream;             /* Stream number (UVI1, UVI2, TVOUT) */
+	u8     Control;            /* Value written to UVI1_CTL */
+	u8     Mode;               /* Controls clock source */
+	u8     SetupDataLen;	   /* Length of setup data, MSB=1 write
+				      backwards */
+	u16    CaptureBlockCount;  /* Blocks (a 256 Bytes) to capture per buffer
+				      for TS and Audio */
+	u64    Buffer_Address;	   /* Address of first buffer header */
+	u16    BytesPerVideoLine;
+	u16    MaxLinesPerField;
+	u16    MinLinesPerField;
+	u16    Reserved_1;
+	u16    BytesPerVBILine;
+	u16    MaxVBILinesPerField;
+	u16    MinVBILinesPerField;
+	u16    SetupDataAddr;      /* ngene relative address of setup data */
+	u8     SetupData[32];      /* setup data */
+} __attribute__((__packed__));
+
+#define AUDIO_BLOCK_SIZE    256
+#define TS_BLOCK_SIZE       256
+
+struct FW_MEM_READ {
+	struct FW_HEADER hdr;
+	u16   address;
+} __attribute__ ((__packed__));
+
+struct FW_MEM_WRITE {
+	struct FW_HEADER hdr;
+	u16   address;
+	u8    data;
+} __attribute__ ((__packed__));
+
+struct FW_SFR_IRAM_READ {
+	struct FW_HEADER hdr;
+	u8    address;
+} __attribute__ ((__packed__));
+
+struct FW_SFR_IRAM_WRITE {
+	struct FW_HEADER hdr;
+	u8    address;
+	u8    data;
+} __attribute__ ((__packed__));
+
+struct FW_SET_GPIO_PIN {
+	struct FW_HEADER hdr;
+	u8    select;
+} __attribute__ ((__packed__));
+
+struct FW_SET_GPIO_INT {
+	struct FW_HEADER hdr;
+	u8    select;
+} __attribute__ ((__packed__));
+
+struct FW_SET_DEBUGMODE {
+	struct FW_HEADER hdr;
+	u8   debug_flags;
+} __attribute__ ((__packed__));
+
+struct FW_CONFIGURE_BUFFERS {
+	struct FW_HEADER hdr;
+	u8   config;
+} __attribute__ ((__packed__));
+
+enum _BUFFER_CONFIGS {
+	/* 4k UVI1, 4k UVI2, 2k AUD1, 2k AUD2  (standard usage) */
+	BUFFER_CONFIG_4422 = 0,
+	/* 3k UVI1, 3k UVI2, 3k AUD1, 3k AUD2  (4x TS input usage) */
+	BUFFER_CONFIG_3333 = 1,
+	/* 8k UVI1, 0k UVI2, 2k AUD1, 2k I2SOut  (HDTV decoder usage) */
+	BUFFER_CONFIG_8022 = 2,
+	BUFFER_CONFIG_FW17 = 255, /* Use new FW 17 command */
+};
+
+struct FW_CONFIGURE_FREE_BUFFERS {
+	struct FW_HEADER hdr;
+	u8   UVI1_BufferLength;
+	u8   UVI2_BufferLength;
+	u8   TVO_BufferLength;
+	u8   AUD1_BufferLength;
+	u8   AUD2_BufferLength;
+	u8   TVA_BufferLength;
+} __attribute__ ((__packed__));
+
+struct FW_CONFIGURE_UART {
+	struct FW_HEADER hdr;
+	u8 UartControl;
+} __attribute__ ((__packed__));
+
+enum _UART_CONFIG {
+	_UART_BAUDRATE_19200 = 0,
+	_UART_BAUDRATE_9600  = 1,
+	_UART_BAUDRATE_4800  = 2,
+	_UART_BAUDRATE_2400  = 3,
+	_UART_RX_ENABLE      = 0x40,
+	_UART_TX_ENABLE      = 0x80,
+};
+
+struct FW_WRITE_UART {
+	struct FW_HEADER hdr;
+	u8 Data[252];
+} __attribute__ ((__packed__));
+
+
+struct ngene_command {
+	u32 in_len;
+	u32 out_len;
+	union {
+		u32                              raw[64];
+		u8                               raw8[256];
+		struct FW_HEADER                 hdr;
+		struct FW_I2C_WRITE              I2CWrite;
+		struct FW_I2C_CONTINUE_WRITE     I2CContinueWrite;
+		struct FW_I2C_READ               I2CRead;
+		struct FW_STREAM_CONTROL         StreamControl;
+		struct FW_FWLOAD_PREPARE         FWLoadPrepare;
+		struct FW_FWLOAD_FINISH          FWLoadFinish;
+		struct FW_MEM_READ		 MemoryRead;
+		struct FW_MEM_WRITE		 MemoryWrite;
+		struct FW_SFR_IRAM_READ		 SfrIramRead;
+		struct FW_SFR_IRAM_WRITE         SfrIramWrite;
+		struct FW_SPI_WRITE              SPIWrite;
+		struct FW_SPI_READ               SPIRead;
+		struct FW_SET_GPIO_PIN           SetGpioPin;
+		struct FW_SET_GPIO_INT           SetGpioInt;
+		struct FW_SET_DEBUGMODE          SetDebugMode;
+		struct FW_CONFIGURE_BUFFERS      ConfigureBuffers;
+		struct FW_CONFIGURE_FREE_BUFFERS ConfigureFreeBuffers;
+		struct FW_CONFIGURE_UART         ConfigureUart;
+		struct FW_WRITE_UART             WriteUart;
+	} cmd;
+} __attribute__ ((__packed__));
+
+#define NGENE_INTERFACE_VERSION 0x103
+#define MAX_VIDEO_BUFFER_SIZE   (417792) /* 288*1440 rounded up to next page */
+#define MAX_AUDIO_BUFFER_SIZE     (8192) /* Gives room for about 23msec@48KHz */
+#define MAX_VBI_BUFFER_SIZE      (28672) /* 1144*18 rounded up to next page */
+#define MAX_TS_BUFFER_SIZE       (98304) /* 512*188 rounded up to next page */
+#define MAX_HDTV_BUFFER_SIZE   (2080768) /* 541*1920*2 rounded up to next page
+					    Max: (1920x1080i60) */
+
+#define OVERFLOW_BUFFER_SIZE    (8192)
+
+#define RING_SIZE_VIDEO     4
+#define RING_SIZE_AUDIO     8
+#define RING_SIZE_TS        8
+
+#define NUM_SCATTER_GATHER_ENTRIES  8
+
+#define MAX_DMA_LENGTH (((MAX_VIDEO_BUFFER_SIZE + MAX_VBI_BUFFER_SIZE) * \
+			RING_SIZE_VIDEO * 2) + \
+			(MAX_AUDIO_BUFFER_SIZE * RING_SIZE_AUDIO * 2) + \
+			(MAX_TS_BUFFER_SIZE * RING_SIZE_TS * 4) + \
+			(RING_SIZE_VIDEO * PAGE_SIZE * 2) + \
+			(RING_SIZE_AUDIO * PAGE_SIZE * 2) + \
+			(RING_SIZE_TS    * PAGE_SIZE * 4) + \
+			 8 * PAGE_SIZE + OVERFLOW_BUFFER_SIZE + PAGE_SIZE)
+
+#define EVENT_QUEUE_SIZE    16
+
+/* Gathers the current state of a single channel. */
+
+struct SBufferHeader {
+	struct BUFFER_HEADER   ngeneBuffer; /* Physical descriptor */
+	struct SBufferHeader  *Next;
+	void                  *Buffer1;
+	struct HW_SCATTER_GATHER_ELEMENT *scList1;
+	void                  *Buffer2;
+	struct HW_SCATTER_GATHER_ELEMENT *scList2;
+};
+
+/* Sizeof SBufferHeader aligned to next 64 Bit boundary (hw restriction) */
+#define SIZEOF_SBufferHeader ((sizeof(struct SBufferHeader) + 63) & ~63)
+
+enum HWSTATE {
+	HWSTATE_STOP,
+	HWSTATE_STARTUP,
+	HWSTATE_RUN,
+	HWSTATE_PAUSE,
+};
+
+enum KSSTATE {
+	KSSTATE_STOP,
+	KSSTATE_ACQUIRE,
+	KSSTATE_PAUSE,
+	KSSTATE_RUN,
+};
+
+struct SRingBufferDescriptor {
+	struct SBufferHeader *Head; /* Points to first buffer in ring buffer
+				       structure*/
+	u64   PAHead;         /* Physical address of first buffer */
+	u32   MemSize;        /* Memory size of allocated ring buffers
+				 (needed for freeing) */
+	u32   NumBuffers;     /* Number of buffers in the ring */
+	u32   Buffer1Length;  /* Allocated length of Buffer 1 */
+	u32   Buffer2Length;  /* Allocated length of Buffer 2 */
+	void *SCListMem;      /* Memory to hold scatter gather lists for this
+				 ring */
+	u64   PASCListMem;    /* Physical address  .. */
+	u32   SCListMemSize;  /* Size of this memory */
+};
+
+enum STREAMMODEFLAGS {
+	StreamMode_NONE   = 0, /* Stream not used */
+	StreamMode_ANALOG = 1, /* Analog: Stream 0,1 = Video, 2,3 = Audio */
+	StreamMode_TSIN   = 2, /* Transport stream input (all) */
+	StreamMode_HDTV   = 4, /* HDTV: Maximum 1920x1080p30,1920x1080i60
+				  (only stream 0) */
+	StreamMode_TSOUT  = 8, /* Transport stream output (only stream 3) */
+};
+
+
+enum BufferExchangeFlags {
+	BEF_EVEN_FIELD   = 0x00000001,
+	BEF_CONTINUATION = 0x00000002,
+	BEF_MORE_DATA    = 0x00000004,
+	BEF_OVERFLOW     = 0x00000008,
+	DF_SWAP32        = 0x00010000,
+};
+
+typedef void *(IBufferExchange)(void *, void *, u32, u32, u32);
+
+struct MICI_STREAMINFO {
+	IBufferExchange    *pExchange;
+	IBufferExchange    *pExchangeVBI;     /* Secondary (VBI, ancillary) */
+	u8  Stream;
+	u8  Flags;
+	u8  Mode;
+	u8  Reserved;
+	u16 nLinesVideo;
+	u16 nBytesPerLineVideo;
+	u16 nLinesVBI;
+	u16 nBytesPerLineVBI;
+	u32 CaptureLength;    /* Used for audio and transport stream */
+};
+
+/****************************************************************************/
+/* STRUCTS ******************************************************************/
+/****************************************************************************/
+
+/* sound hardware definition */
+#define MIXER_ADDR_TVTUNER      0
+#define MIXER_ADDR_LAST         0
+
+struct ngene_channel;
+
+/*struct sound chip*/
+
+struct mychip {
+	struct ngene_channel *chan;
+	struct snd_card *card;
+	struct pci_dev *pci;
+	struct snd_pcm_substream *substream;
+	struct snd_pcm *pcm;
+	unsigned long port;
+	int irq;
+	spinlock_t mixer_lock;
+	spinlock_t lock;
+	int mixer_volume[MIXER_ADDR_LAST + 1][2];
+	int capture_source[MIXER_ADDR_LAST + 1][2];
+};
+
+#ifdef NGENE_V4L
+struct ngene_overlay {
+	int                    tvnorm;
+	struct v4l2_rect       w;
+	enum v4l2_field        field;
+	struct v4l2_clip       *clips;
+	int                    nclips;
+	int                    setup_ok;
+};
+
+struct ngene_tvnorm {
+	int   v4l2_id;
+	char  *name;
+	u16   swidth, sheight; /* scaled standard width, height */
+	int   tuner_norm;
+	int   soundstd;
+};
+
+struct ngene_vopen {
+	struct ngene_channel      *ch;
+	enum v4l2_priority         prio;
+	int                        width;
+	int                        height;
+	int                        depth;
+	struct videobuf_queue      vbuf_q;
+	struct videobuf_queue      vbi;
+	int                        fourcc;
+	int                        picxcount;
+	int                        resources;
+	enum v4l2_buf_type         type;
+	const struct ngene_format *fmt;
+
+	const struct ngene_format *ovfmt;
+	struct ngene_overlay       ov;
+};
+#endif
+
+struct ngene_channel {
+	struct device         device;
+	struct i2c_adapter    i2c_adapter;
+
+	struct ngene         *dev;
+	int                   number;
+	int                   type;
+	int                   mode;
+
+	struct dvb_frontend  *fe;
+	struct dmxdev         dmxdev;
+	struct dvb_demux      demux;
+	struct dmx_frontend   hw_frontend;
+	struct dmx_frontend   mem_frontend;
+	int                   users;
+	struct video_device  *v4l_dev;
+	struct tasklet_struct demux_tasklet;
+
+	struct SBufferHeader *nextBuffer;
+	enum KSSTATE          State;
+	enum HWSTATE          HWState;
+	u8                    Stream;
+	u8                    Flags;
+	u8                    Mode;
+	IBufferExchange      *pBufferExchange;
+	IBufferExchange      *pBufferExchange2;
+
+	spinlock_t            state_lock;
+	u16                   nLines;
+	u16                   nBytesPerLine;
+	u16                   nVBILines;
+	u16                   nBytesPerVBILine;
+	u16                   itumode;
+	u32                   Capture1Length;
+	u32                   Capture2Length;
+	struct SRingBufferDescriptor RingBuffer;
+	struct SRingBufferDescriptor TSRingBuffer;
+	struct SRingBufferDescriptor TSIdleBuffer;
+
+	u32                   DataFormatFlags;
+
+	int                   AudioDTOUpdated;
+	u32                   AudioDTOValue;
+
+	int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t);
+	u8 lnbh;
+
+	/* stuff from analog driver */
+
+	int minor;
+	struct mychip        *mychip;
+	struct snd_card      *soundcard;
+	u8                   *evenbuffer;
+	u8                    dma_on;
+	int                   soundstreamon;
+	int                   audiomute;
+	int                   soundbuffisallocated;
+	int                   sndbuffflag;
+	int                   tun_rdy;
+	int                   dec_rdy;
+	int                   tun_dec_rdy;
+	int                   lastbufferflag;
+
+	struct ngene_tvnorm  *tvnorms;
+	int                   tvnorm_num;
+	int                   tvnorm;
+
+#ifdef NGENE_V4L
+	int                   videousers;
+	struct v4l2_prio_state prio;
+	struct ngene_vopen    init;
+	int                   resources;
+	struct v4l2_framebuffer fbuf;
+	struct ngene_buffer  *screen;     /* overlay             */
+	struct list_head      capture;    /* video capture queue */
+	spinlock_t s_lock;
+	struct semaphore reslock;
+#endif
+
+	int running;
+};
+
+struct ngene;
+
+typedef void (rx_cb_t)(struct ngene *, u32, u8);
+typedef void (tx_cb_t)(struct ngene *, u32);
+
+struct ngene {
+	int                   nr;
+	struct pci_dev       *pci_dev;
+	unsigned char        *iomem;
+
+	/*struct i2c_adapter  i2c_adapter;*/
+
+	u32                   device_version;
+	u32                   fw_interface_version;
+	u32                   icounts;
+
+	u8                   *CmdDoneByte;
+	int                   BootFirmware;
+	void                 *OverflowBuffer;
+	dma_addr_t            PAOverflowBuffer;
+	void                 *FWInterfaceBuffer;
+	dma_addr_t            PAFWInterfaceBuffer;
+	u8                   *ngenetohost;
+	u8                   *hosttongene;
+
+	struct EVENT_BUFFER   EventQueue[EVENT_QUEUE_SIZE];
+	int                   EventQueueOverflowCount;
+	int                   EventQueueOverflowFlag;
+	struct tasklet_struct event_tasklet;
+	struct EVENT_BUFFER  *EventBuffer;
+	int                   EventQueueWriteIndex;
+	int                   EventQueueReadIndex;
+
+	wait_queue_head_t     cmd_wq;
+	int                   cmd_done;
+	struct semaphore      cmd_mutex;
+	struct semaphore      stream_mutex;
+	struct semaphore      pll_mutex;
+	struct semaphore      i2c_switch_mutex;
+	int                   i2c_current_channel;
+	int                   i2c_current_bus;
+	spinlock_t            cmd_lock;
+
+	struct dvb_adapter    adapter[MAX_STREAM];
+	struct ngene_channel  channel[MAX_STREAM];
+
+	struct ngene_info    *card_info;
+
+	tx_cb_t              *TxEventNotify;
+	rx_cb_t              *RxEventNotify;
+	int                   tx_busy;
+	wait_queue_head_t     tx_wq;
+	wait_queue_head_t     rx_wq;
+#define UART_RBUF_LEN 4096
+	u8                    uart_rbuf[UART_RBUF_LEN];
+	int                   uart_rp, uart_wp;
+
+	u8                   *tsout_buf;
+#define TSOUT_BUF_SIZE (512*188*8)
+	struct dvb_ringbuffer tsout_rbuf;
+
+	u8                   *ain_buf;
+#define AIN_BUF_SIZE (128*1024)
+	struct dvb_ringbuffer ain_rbuf;
+
+
+	u8                   *vin_buf;
+#define VIN_BUF_SIZE (4*1920*1080)
+	struct dvb_ringbuffer vin_rbuf;
+
+	unsigned long         exp_val;
+	int prev_cmd;
+};
+
+struct ngene_info {
+	int   type;
+#define NGENE_APP        0
+#define NGENE_TERRATEC   1
+#define NGENE_SIDEWINDER 2
+#define NGENE_RACER      3
+#define NGENE_VIPER      4
+#define NGENE_PYTHON     5
+#define NGENE_VBOX_V1	 6
+#define NGENE_VBOX_V2	 7
+
+	int   fw_version;
+	char *name;
+
+	int   io_type[MAX_STREAM];
+#define NGENE_IO_NONE    0
+#define NGENE_IO_TV      1
+#define NGENE_IO_HDTV    2
+#define NGENE_IO_TSIN    4
+#define NGENE_IO_TSOUT   8
+#define NGENE_IO_AIN     16
+
+	void *fe_config[4];
+	void *tuner_config[4];
+
+	int (*demod_attach[4])(struct ngene_channel *);
+	int (*tuner_attach[4])(struct ngene_channel *);
+
+	u8    avf[4];
+	u8    msp[4];
+	u8    demoda[4];
+	u8    lnb[4];
+	int   i2c_access;
+	u8    ntsc;
+	u8    tsf[4];
+	u8    i2s[4];
+
+	int (*gate_ctrl)(struct dvb_frontend *, int);
+	int (*switch_ctrl)(struct ngene_channel *, int, int);
+};
+
+#ifdef NGENE_V4L
+struct ngene_format{
+	char *name;
+	int   fourcc;          /* video4linux 2      */
+	int   btformat;        /* BT848_COLOR_FMT_*  */
+	int   format;
+	int   btswap;          /* BT848_COLOR_CTL_*  */
+	int   depth;           /* bit/pixel          */
+	int   flags;
+	int   hshift, vshift;  /* for planar modes   */
+	int   palette;
+};
+
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
+
+struct ngene_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer     vb;
+
+	/* ngene specific */
+	const struct ngene_format *fmt;
+	int                        tvnorm;
+	int                        btformat;
+	int                        btswap;
+};
+#endif
+
+
+#endif
+
+/*  LocalWords:  Endif
+ */
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index 1067b22eb0c6..cff77e2eb557 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -62,6 +62,7 @@ static struct sms_board sms_boards[] = {
 	[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
 		.name	= "Hauppauge WinTV MiniStick",
 		.type	= SMS_NOVA_B0,
+		.fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
 		.board_cfg.leds_power = 26,
 		.board_cfg.led0 = 27,
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index ca758bcb48c9..4bfd3451b568 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -1459,8 +1459,10 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
 	if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
 		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
 		if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
-				&groupCfg) != 0)
-			return -EINVAL;
+				&groupCfg) != 0) {
+			rc = -EINVAL;
+			goto free;
+		}
 
 		pMsg->msgData[1] = TranslatedPinNum;
 		pMsg->msgData[2] = GroupNum;
@@ -1490,6 +1492,7 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
 		else
 			sms_err("smscore_gpio_configure error");
 	}
+free:
 	kfree(buffer);
 
 	return rc;
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
index eec18aaf5512..8ecadecaa9d0 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -212,6 +212,8 @@ struct smscore_device_t {
 #define MSG_SMS_DAB_CHANNEL				607
 #define MSG_SMS_GET_PID_FILTER_LIST_REQ			608
 #define MSG_SMS_GET_PID_FILTER_LIST_RES			609
+#define MSG_SMS_GET_STATISTICS_RES			616
+#define MSG_SMS_GET_STATISTICS_REQ			615
 #define MSG_SMS_HO_PER_SLICES_IND			630
 #define MSG_SMS_SET_ANTENNA_CONFIG_REQ			651
 #define MSG_SMS_SET_ANTENNA_CONFIG_RES			652
@@ -339,7 +341,7 @@ struct SmsFirmware_ST {
 
 /* Statistics information returned as response for
  * SmsHostApiGetStatistics_Req */
-struct SMSHOSTLIB_STATISTICS_S {
+struct SMSHOSTLIB_STATISTICS_ST {
 	u32 Reserved;		/* Reserved */
 
 	/* Common parameters */
@@ -424,6 +426,79 @@ struct SMSHOSTLIB_STATISTICS_S {
 	u32 ReservedFields[10];	/* Reserved */
 };
 
+struct SmsMsgStatisticsInfo_ST {
+	u32 RequestResult;
+
+	struct SMSHOSTLIB_STATISTICS_ST Stat;
+
+	/* Split the calc of the SNR in DAB */
+	u32 Signal; /* dB */
+	u32 Noise; /* dB */
+
+};
+
+struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
+	/* Per-layer information */
+	u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+		       * 255 means layer does not exist */
+	u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
+			    * 255 means layer does not exist */
+	u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+	u32 BERErrorCount; /* Post Viterbi Error Bits Count */
+	u32 BERBitCount; /* Post Viterbi Total Bits Count */
+	u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+	u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
+	u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
+	u32 TotalTSPackets; /* Total number of transport-stream packets */
+	u32 TILdepthI; /* Time interleaver depth I parameter,
+			* 255 means layer does not exist */
+	u32 NumberOfSegments; /* Number of segments in layer A,
+			       * 255 means layer does not exist */
+	u32 TMCCErrors; /* TMCC errors */
+};
+
+struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
+	u32 StatisticsType; /* Enumerator identifying the type of the
+				* structure.  Values are the same as
+				* SMSHOSTLIB_DEVICE_MODES_E
+				*
+				* This field MUST always be first in any
+				* statistics structure */
+
+	u32 FullSize; /* Total size of the structure returned by the modem.
+		       * If the size requested by the host is smaller than
+		       * FullSize, the struct will be truncated */
+
+	/* Common parameters */
+	u32 IsRfLocked; /* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+
+	/* Reception quality */
+	s32  SNR; /* dB */
+	s32  RSSI; /* dBm */
+	s32  InBandPwr; /* In band power in dBM */
+	s32  CarrierOffset; /* Carrier Offset in Hz */
+
+	/* Transmission parameters */
+	u32 Frequency; /* Frequency in Hz */
+	u32 Bandwidth; /* Bandwidth in MHz */
+	u32 TransmissionMode; /* ISDB-T transmission mode */
+	u32 ModemState; /* 0 - Acquisition, 1 - Locked */
+	u32 GuardInterval; /* Guard Interval, 1 divided by value */
+	u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+	u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
+	u32 NumOfLayers; /* Number of ISDB-T layers in the network */
+
+	/* Per-layer information */
+	/* Layers A, B and C */
+	struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST	LayerInfo[3];
+	/* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
+
+	/* Interface information */
+	u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+};
+
 struct PID_STATISTICS_DATA_S {
 	struct PID_BURST_S {
 		u32 size;
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 68bf9fbd8fed..5f3939821ca3 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -116,6 +116,118 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client,
 	}
 }
 
+
+static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+				   struct SMSHOSTLIB_STATISTICS_ST *p)
+{
+	if (sms_dbg & 2) {
+		printk(KERN_DEBUG "Reserved = %d", p->Reserved);
+		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+		printk(KERN_DEBUG "SNR = %d", p->SNR);
+		printk(KERN_DEBUG "BER = %d", p->BER);
+		printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
+		printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
+		printk(KERN_DEBUG "MFER = %d", p->MFER);
+		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+		printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
+		printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
+		printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
+		printk(KERN_DEBUG "Constellation = %d", p->Constellation);
+		printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
+		printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
+		printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
+		printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
+		printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
+		printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
+		printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
+		printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
+		printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
+		printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
+		printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
+		printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
+		printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
+		printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
+		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+		printk(KERN_DEBUG "PreBER = %d", p->PreBER);
+		printk(KERN_DEBUG "CellId = %d", p->CellId);
+		printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
+		printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
+		printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
+	}
+
+	pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+	pReceptionData->SNR = p->SNR;
+	pReceptionData->BER = p->BER;
+	pReceptionData->BERErrorCount = p->BERErrorCount;
+	pReceptionData->InBandPwr = p->InBandPwr;
+	pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
+};
+
+
+static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+				    struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
+{
+	int i;
+
+	if (sms_dbg & 2) {
+		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+		printk(KERN_DEBUG "SNR = %d", p->SNR);
+		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+		printk(KERN_DEBUG "SystemType = %d", p->SystemType);
+		printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
+		printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
+		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+
+		for (i = 0; i < 3; i++) {
+			printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
+			printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
+			printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
+			printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
+			printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
+			printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
+			printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
+			printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
+			printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
+			printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
+			printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
+			printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
+		}
+	}
+
+	pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+	pReceptionData->SNR = p->SNR;
+	pReceptionData->InBandPwr = p->InBandPwr;
+
+	pReceptionData->ErrorTSPackets = 0;
+	pReceptionData->BER = 0;
+	pReceptionData->BERErrorCount = 0;
+	for (i = 0; i < 3; i++) {
+		pReceptionData->BER += p->LayerInfo[i].BER;
+		pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
+		pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
+	}
+}
+
 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 {
 	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
@@ -134,6 +246,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 		break;
 
 	case MSG_SMS_RF_TUNE_RES:
+	case MSG_SMS_ISDBT_TUNE_RES:
 		complete(&client->tune_done);
 		break;
 
@@ -217,6 +330,40 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 		is_status_update = true;
 		break;
 	}
+	case MSG_SMS_GET_STATISTICS_RES: {
+		union {
+			struct SMSHOSTLIB_STATISTICS_ISDBT_ST  isdbt;
+			struct SmsMsgStatisticsInfo_ST         dvb;
+		} *p = (void *) (phdr + 1);
+		struct RECEPTION_STATISTICS_S *pReceptionData =
+				&client->sms_stat_dvb.ReceptionData;
+
+		sms_info("MSG_SMS_GET_STATISTICS_RES");
+
+		is_status_update = true;
+
+		switch (smscore_get_device_mode(client->coredev)) {
+		case DEVICE_MODE_ISDBT:
+		case DEVICE_MODE_ISDBT_BDA:
+			smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
+			break;
+		default:
+			smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
+		}
+		if (!pReceptionData->IsDemodLocked) {
+			pReceptionData->SNR = 0;
+			pReceptionData->BER = 0;
+			pReceptionData->BERErrorCount = 0;
+			pReceptionData->InBandPwr = 0;
+			pReceptionData->ErrorTSPackets = 0;
+		}
+
+		complete(&client->tune_done);
+		break;
+	}
+	default:
+		sms_info("Unhandled message %d", phdr->msgType);
+
 	}
 	smscore_putbuffer(client->coredev, cb);
 
@@ -233,10 +380,10 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 						DVB3_EVENT_UNC_ERR);
 
 		} else {
-			/*client->fe_status =
-				(phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
-				0 : FE_HAS_SIGNAL;*/
-			client->fe_status = 0;
+			if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
+				client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+			else
+				client->fe_status = 0;
 			sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
 		}
 	}
@@ -325,6 +472,20 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
 						0 : -ETIME;
 }
 
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+	int rc;
+	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
+				    DVBT_BDA_CONTROL_MSG_ID,
+				    HIF_TASK,
+				    sizeof(struct SmsMsgHdr_ST), 0 };
+
+	rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					  &client->tune_done);
+
+	return rc;
+}
+
 static inline int led_feedback(struct smsdvb_client_t *client)
 {
 	if (client->fe_status & FE_HAS_LOCK)
@@ -337,33 +498,43 @@ static inline int led_feedback(struct smsdvb_client_t *client)
 
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 {
+	int rc;
 	struct smsdvb_client_t *client;
 	client = container_of(fe, struct smsdvb_client_t, frontend);
 
+	rc = smsdvb_send_statistics_request(client);
+
 	*stat = client->fe_status;
 
 	led_feedback(client);
 
-	return 0;
+	return rc;
 }
 
 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
+	int rc;
 	struct smsdvb_client_t *client;
 	client = container_of(fe, struct smsdvb_client_t, frontend);
 
+	rc = smsdvb_send_statistics_request(client);
+
 	*ber = client->sms_stat_dvb.ReceptionData.BER;
 
 	led_feedback(client);
 
-	return 0;
+	return rc;
 }
 
 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
+	int rc;
+
 	struct smsdvb_client_t *client;
 	client = container_of(fe, struct smsdvb_client_t, frontend);
 
+	rc = smsdvb_send_statistics_request(client);
+
 	if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
 		*strength = 0;
 		else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
@@ -375,31 +546,37 @@ static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 
 	led_feedback(client);
 
-	return 0;
+	return rc;
 }
 
 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
+	int rc;
 	struct smsdvb_client_t *client;
 	client = container_of(fe, struct smsdvb_client_t, frontend);
 
+	rc = smsdvb_send_statistics_request(client);
+
 	*snr = client->sms_stat_dvb.ReceptionData.SNR;
 
 	led_feedback(client);
 
-	return 0;
+	return rc;
 }
 
 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
+	int rc;
 	struct smsdvb_client_t *client;
 	client = container_of(fe, struct smsdvb_client_t, frontend);
 
+	rc = smsdvb_send_statistics_request(client);
+
 	*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
 
 	led_feedback(client);
 
-	return 0;
+	return rc;
 }
 
 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@@ -413,9 +590,10 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
 	return 0;
 }
 
-static int smsdvb_set_frontend(struct dvb_frontend *fe,
-			       struct dvb_frontend_parameters *fep)
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
+				    struct dvb_frontend_parameters *p)
 {
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 	struct smsdvb_client_t *client =
 		container_of(fe, struct smsdvb_client_t, frontend);
 
@@ -429,24 +607,33 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
 	client->fe_status = FE_HAS_SIGNAL;
 	client->event_fe_state = -1;
 	client->event_unc_state = -1;
+	fe->dtv_property_cache.delivery_system = SYS_DVBT;
 
 	Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
 	Msg.Msg.msgDstId = HIF_TASK;
 	Msg.Msg.msgFlags = 0;
 	Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
 	Msg.Msg.msgLength = sizeof(Msg);
-	Msg.Data[0] = fep->frequency;
+	Msg.Data[0] = c->frequency;
 	Msg.Data[2] = 12000000;
 
-	sms_debug("freq %d band %d",
-		  fep->frequency, fep->u.ofdm.bandwidth);
+	sms_info("%s: freq %d band %d", __func__, c->frequency,
+		 c->bandwidth_hz);
 
-	switch (fep->u.ofdm.bandwidth) {
-	case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
-	case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
-	case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
-	case BANDWIDTH_AUTO: return -EOPNOTSUPP;
-	default: return -EINVAL;
+	switch (c->bandwidth_hz / 1000000) {
+	case 8:
+		Msg.Data[1] = BW_8_MHZ;
+		break;
+	case 7:
+		Msg.Data[1] = BW_7_MHZ;
+		break;
+	case 6:
+		Msg.Data[1] = BW_6_MHZ;
+		break;
+	case 0:
+		return -EOPNOTSUPP;
+	default:
+		return -EINVAL;
 	}
 	/* Disable LNA, if any. An error is returned if no LNA is present */
 	ret = sms_board_lna_control(client->coredev, 0);
@@ -470,6 +657,90 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
 					   &client->tune_done);
 }
 
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
+				     struct dvb_frontend_parameters *p)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+
+	struct {
+		struct SmsMsgHdr_ST	Msg;
+		u32		Data[4];
+	} Msg;
+
+	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
+	Msg.Msg.msgDstId  = HIF_TASK;
+	Msg.Msg.msgFlags  = 0;
+	Msg.Msg.msgType   = MSG_SMS_ISDBT_TUNE_REQ;
+	Msg.Msg.msgLength = sizeof(Msg);
+
+	if (c->isdbt_sb_segment_idx == -1)
+		c->isdbt_sb_segment_idx = 0;
+
+	switch (c->isdbt_sb_segment_count) {
+	case 3:
+		Msg.Data[1] = BW_ISDBT_3SEG;
+		break;
+	case 1:
+		Msg.Data[1] = BW_ISDBT_1SEG;
+		break;
+	case 0:	/* AUTO */
+		switch (c->bandwidth_hz / 1000000) {
+		case 8:
+		case 7:
+			c->isdbt_sb_segment_count = 3;
+			Msg.Data[1] = BW_ISDBT_3SEG;
+			break;
+		case 6:
+			c->isdbt_sb_segment_count = 1;
+			Msg.Data[1] = BW_ISDBT_1SEG;
+			break;
+		default: /* Assumes 6 MHZ bw */
+			c->isdbt_sb_segment_count = 1;
+			c->bandwidth_hz = 6000;
+			Msg.Data[1] = BW_ISDBT_1SEG;
+			break;
+		}
+		break;
+	default:
+		sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
+		return -EINVAL;
+	}
+
+	Msg.Data[0] = c->frequency;
+	Msg.Data[2] = 12000000;
+	Msg.Data[3] = c->isdbt_sb_segment_idx;
+
+	sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
+		 c->frequency, c->isdbt_sb_segment_count,
+		 c->isdbt_sb_segment_idx);
+
+	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+					   &client->tune_done);
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *fep)
+{
+	struct smsdvb_client_t *client =
+		container_of(fe, struct smsdvb_client_t, frontend);
+	struct smscore_device_t *coredev = client->coredev;
+
+	switch (smscore_get_device_mode(coredev)) {
+	case DEVICE_MODE_DVBT:
+	case DEVICE_MODE_DVBT_BDA:
+		return smsdvb_dvbt_set_frontend(fe, fep);
+	case DEVICE_MODE_ISDBT:
+	case DEVICE_MODE_ISDBT_BDA:
+		return smsdvb_isdbt_set_frontend(fe, fep);
+	default:
+		return -EINVAL;
+	}
+}
+
 static int smsdvb_get_frontend(struct dvb_frontend *fe,
 			       struct dvb_frontend_parameters *fep)
 {
@@ -557,13 +828,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
 	/* device removal handled by onremove callback */
 	if (!arrival)
 		return 0;
-
-	if (smscore_get_device_mode(coredev) != DEVICE_MODE_DVBT_BDA) {
-		sms_err("SMS Device mode is not set for "
-			"DVB operation.");
-		return 0;
-	}
-
 	client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
 	if (!client) {
 		sms_err("kmalloc() failed");
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index e3d776feeaca..a56eac76e0f0 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -85,9 +85,9 @@ static struct keyboard_layout_map_t keyboard_layout_maps[] = {
 		{ } /* Terminating entry */
 };
 
-u32 ir_pos;
-u32	ir_word;
-u32 ir_toggle;
+static u32 ir_pos;
+static u32 ir_word;
+static u32 ir_toggle;
 
 #define RC5_PUSH_BIT(dst, bit, pos)	\
 	{ dst <<= 1; dst |= bit; pos++; }
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index 23a1c6380d3f..b070e88d8c6b 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -268,8 +268,8 @@ int av7110_check_ir_config(struct av7110 *av7110, int force)
 
 
 /* /proc/av7110_ir interface */
-static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
-				unsigned long count, void *data)
+static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer,
+				    size_t count, loff_t *pos)
 {
 	char *page;
 	u32 ir_config;
@@ -309,6 +309,10 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
 	return count;
 }
 
+static const struct file_operations av7110_ir_proc_fops = {
+	.owner		= THIS_MODULE,
+	.write		= av7110_ir_proc_write,
+};
 
 /* interrupt handler */
 static void ir_handler(struct av7110 *av7110, u32 ircom)
@@ -368,11 +372,9 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
 	input_dev->timer.data = (unsigned long) &av7110->ir;
 
 	if (av_cnt == 1) {
-		e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
-		if (e) {
-			e->write_proc = av7110_ir_write_proc;
+		e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
+		if (e)
 			e->size = 4 + 256 * sizeof(u16);
-		}
 	}
 
 	tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 9782e0593733..49c2a817a06f 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -254,7 +254,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
 	budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
 	budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
 	budget_ci->ir.last_raw = 0xffff; /* An impossible value */
-	error = ir_input_register(input_dev, ir_codes);
+	error = ir_input_register(input_dev, ir_codes, NULL);
 	if (error) {
 		printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
 		return error;
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index e48380c48990..9fdf26cc6998 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -433,9 +433,8 @@ static struct stv090x_config tt1600_stv090x_config = {
 	.demod_mode		= STV090x_SINGLE,
 	.clk_mode		= STV090x_CLK_EXT,
 
-	.xtal			= 27000000,
+	.xtal			= 13500000,
 	.address		= 0x68,
-	.ref_clk		= 27000000,
 
 	.ts1_mode		= STV090x_TSMODE_DVBCI,
 	.ts2_mode		= STV090x_TSMODE_SERIAL_CONTINUOUS,
@@ -457,6 +456,7 @@ static struct stv090x_config tt1600_stv090x_config = {
 static struct stv6110x_config tt1600_stv6110x_config = {
 	.addr			= 0x60,
 	.refclk			= 27000000,
+	.clk_div		= 2,
 };
 
 static struct isl6423_config tt1600_isl6423_config = {