From: Michael Hunold <hunold@linuxtv.org>

- [DVB] dvb-ttusb-dec, dvb-ttusb-budget, skystar2, bt878 + dvb-bt8xx: follow
  frontend changes in driver

- [DVB] DST isn't a real frontend, it's an interface to a frontend
  microcontroller, so move the hardware dependend stuff to the right place

Signed-off-by: Michael Hunold <hunold@linuxtv.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 /dev/null                                                      | 1293 ----------
 25-akpm/drivers/media/dvb/b2c2/skystar2.c                      |  289 +-
 25-akpm/drivers/media/dvb/bt8xx/bt878.c                        |   23 
 25-akpm/drivers/media/dvb/bt8xx/dst.c                          | 1089 ++++++++
 25-akpm/drivers/media/dvb/bt8xx/dst.h                          |   40 
 25-akpm/drivers/media/dvb/bt8xx/dst_priv.h                     |   37 
 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.c                    |  312 ++
 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.h                    |    5 
 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c      |  230 +
 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h |    2 
 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c                |  349 --
 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.c               |  255 +
 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.h               |   38 
 13 files changed, 2203 insertions(+), 1759 deletions(-)

diff -puN drivers/media/dvb/b2c2/skystar2.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/b2c2/skystar2.c
--- 25/drivers/media/dvb/b2c2/skystar2.c~dvb-follow-frontend-changes-in-drivers	Thu Nov 18 15:18:02 2004
+++ 25-akpm/drivers/media/dvb/b2c2/skystar2.c	Thu Nov 18 15:18:02 2004
@@ -50,6 +50,8 @@
 #include "dvbdev.h"
 #include "demux.h"
 #include "dvb_net.h"
+#include "stv0299.h"
+#include "mt352.h"
 
 
 static int debug;
@@ -77,6 +79,9 @@ struct dmaq {
 	u8 *buffer;
 };
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#define __iomem
+#endif
 
 struct adapter {
 	struct pci_dev *pdev;
@@ -118,6 +123,9 @@ struct adapter {
 	int pid_count;
 	int whole_bandwidth_count;
 	u32 mac_filter;
+
+	struct dvb_frontend* fe;
+	int (*fe_sleep)(struct dvb_frontend* fe);
 };
 
 #define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg)
@@ -297,13 +305,6 @@ static int master_xfer(struct i2c_adapte
 		for (i = 0; i < num; i++) {
 		ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
 			 msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
-	
-		/* allow only the mt312, mt352 and stv0299 frontends to access the bus */
-		if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) &&
-		    (msgs[i].addr != 0x61) && (msgs[i].addr != 0x0f)) {
-		up(&tmp->i2c_sem);
-		return -EREMOTEIO;
-	}
 	}
 
 	// read command
@@ -785,7 +786,7 @@ static int eeprom_read(struct adapter *a
 	return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len);
 }
 
-u8 calc_lrc(u8 *buf, int len)
+static u8 calc_lrc(u8 *buf, int len)
 {
 	int i;
 	u8 sum;
@@ -1773,6 +1774,7 @@ static void free_adapter_object(struct a
 	if (adapter->io_mem)
 		iounmap(adapter->io_mem);
 
+	if (adapter != 0)
 	kfree(adapter);
 }
 
@@ -2024,6 +2026,7 @@ static int dvb_stop_feed(struct dvb_demu
 	return 0;
 }
 
+#if 0
 /* lnb control */
 static void set_tuner_tone(struct adapter *adapter, u8 tone)
 {
@@ -2058,6 +2061,7 @@ static void set_tuner_tone(struct adapte
 		write_reg_dw(adapter, 0x200, 0x40ff8000);
 	}
 }
+#endif
 
 static void set_tuner_polarity(struct adapter *adapter, u8 polarity)
 {
@@ -2085,6 +2089,7 @@ static void set_tuner_polarity(struct ad
 	write_reg_dw(adapter, 0x204, var);
 }
 
+#if 0
 static void diseqc_send_bit(struct adapter *adapter, int data)
 {
 	set_tuner_tone(adapter, 1);
@@ -2135,7 +2140,7 @@ static int send_diseqc_msg(struct adapte
 }
 
 
-int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg)
+static int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg)
 {
 	switch (cmd) {
 	case FE_SET_TONE:
@@ -2169,107 +2174,252 @@ int soft_diseqc(struct adapter *adapter,
 
 	return 0;
 }
+#endif
 
-static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 		{
-	struct adapter *adapter = fe->before_after_data;
-
-	struct dvb_frontend_info info;
+	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
 
-	fe->ioctl(fe, FE_GET_INFO, &info);
+	dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
 
-	// we must use different DiSEqC hw
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
+		set_tuner_polarity(adapter, 1);
+		return 0;
 
-	if (strcmp(info.name, "Zarlink MT312") == 0) {
-		//VP310 using mt312 driver for tuning only: diseqc not wired
-		//use FCII instead
-		if (!soft_diseqc(adapter, cmd, arg))
+	case SEC_VOLTAGE_18:
+		dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
+		set_tuner_polarity(adapter, 2);
 			return 0;
+
+	default:
+		return -EINVAL;
+	}
 	}
 
-	switch (cmd) {
-	case FE_SLEEP:
+static int flexcop_sleep(struct dvb_frontend* fe)
 		{
-			dprintk("%s: FE_SLEEP\n", __FUNCTION__);
+	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
 
+	dprintk("%s: FE_SLEEP\n", __FUNCTION__);
 			set_tuner_polarity(adapter, 0);
 
-			// return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend.
-			return -EOPNOTSUPP;
+	if (adapter->fe_sleep) return adapter->fe_sleep(fe);
+	return 0;
 		}
 
-	case FE_SET_VOLTAGE:
+static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
 		{
-			dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
-
-			switch ((fe_sec_voltage_t) arg) {
-			case SEC_VOLTAGE_13:
+	printk("flexcop_i2c_func\n");
 
-				dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
+	return I2C_FUNC_I2C;
+}
 
-				set_tuner_polarity(adapter, 1);
+static struct i2c_algorithm    flexcop_algo = {
+	.name		= "flexcop i2c algorithm",
+	.id		= I2C_ALGO_BIT,
+	.master_xfer	= master_xfer,
+	.functionality	= flexcop_i2c_func,
+};
 
-				return 0;
 
-			case SEC_VOLTAGE_18:
 
-				dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
 
-				set_tuner_polarity(adapter, 2);
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
 
-				return 0;
+	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+	stv0299_writereg (fe, 0x13, aclk);
+	stv0299_writereg (fe, 0x14, bclk);
+	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
+	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
 
-			default:
+	return 0;
+}
 
-				return -EINVAL;
-			};
-		}
+static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	struct adapter* adapter = (struct adapter*) fe->dvb->priv;
 
+	div = params->frequency / 125;
 
-	default:
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x84;  // 0xC4
+	buf[3] = 0x08;
 
-		return -EOPNOTSUPP;
-	};
+	if (params->frequency < 1500000) buf[3] |= 0x10;
 
+	if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
+static u8 samsung_tbmu24112_inittab[] = {
+	     0x01, 0x15,
+	     0x02, 0x30,
+	     0x03, 0x00,
+	     0x04, 0x7D,
+	     0x05, 0x35,
+	     0x06, 0x02,
+	     0x07, 0x00,
+	     0x08, 0xC3,
+	     0x0C, 0x00,
+	     0x0D, 0x81,
+	     0x0E, 0x23,
+	     0x0F, 0x12,
+	     0x10, 0x7E,
+	     0x11, 0x84,
+	     0x12, 0xB9,
+	     0x13, 0x88,
+	     0x14, 0x89,
+	     0x15, 0xC9,
+	     0x16, 0x00,
+	     0x17, 0x5C,
+	     0x18, 0x00,
+	     0x19, 0x00,
+	     0x1A, 0x00,
+	     0x1C, 0x00,
+	     0x1D, 0x00,
+	     0x1E, 0x00,
+	     0x1F, 0x3A,
+	     0x20, 0x2E,
+	     0x21, 0x80,
+	     0x22, 0xFF,
+	     0x23, 0xC1,
+	     0x28, 0x00,
+	     0x29, 0x1E,
+	     0x2A, 0x14,
+	     0x2B, 0x0F,
+	     0x2C, 0x09,
+	     0x2D, 0x05,
+	     0x31, 0x1F,
+	     0x32, 0x19,
+	     0x33, 0xFE,
+	     0x34, 0x93,
+	     0xff, 0xff,
+			};
+
+static struct stv0299_config samsung_tbmu24112_config = {
+	.demod_address = 0x68,
+	.inittab = samsung_tbmu24112_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_LK,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
+   	.pll_set = samsung_tbmu24112_pll_set,
+};
+
+
+
+
 
-static int client_register(struct i2c_client *client)
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
 {
-	struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
+	static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d };
+	static u8 mt352_reset [] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
 
-	dprintk("client_register\n");
+	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
 
-	if (client->driver->command)
-		return client->driver->command(client, FE_REGISTER, adapter->dvb_adapter);
 	return 0;
 }
 
-static int client_unregister(struct i2c_client *client)
+int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
 {
-	struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter);
+	u32 div;
+	unsigned char bs = 0;
 
-	dprintk("client_unregister\n");
+	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+	if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
+	if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
+	if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
+
+	pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+	pllbuf[1] = div >> 8;
+   	pllbuf[2] = div & 0xff;
+   	pllbuf[3] = 0xcc;
+   	pllbuf[4] = bs;
 
-	if (client->driver->command)
-		return client->driver->command(client, FE_UNREGISTER, adapter->dvb_adapter);
 	return 0;
 }
 
-u32 flexcop_i2c_func(struct i2c_adapter *adapter)
+static struct mt352_config samsung_tdtc9251dh0_config = {
+
+	.demod_address = 0x0f,
+	.demod_init = samsung_tdtc9251dh0_demod_init,
+   	.pll_set = samsung_tdtc9251dh0_pll_set,
+};
+
+
+
+
+
+static void frontend_init(struct adapter *skystar2)
 {
-	printk("flexcop_i2c_func\n");
+	switch(skystar2->pdev->device) {
+	case 0x2103: // Technisat Skystar2 OR Technisat Airstar2
 
-	return I2C_FUNC_I2C;
+		// try the skystar2 first (stv0299/Samsung tbmu24112(sl1935))
+		skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap);
+		if (skystar2->fe != NULL) {
+			skystar2->fe->ops->set_voltage = flexcop_set_voltage;
+			skystar2->fe_sleep = skystar2->fe->ops->sleep;
+			skystar2->fe->ops->sleep = flexcop_sleep;
+			break;
 }
 
-static struct i2c_algorithm    flexcop_algo = {
-	.name		= "flexcop i2c algorithm",
-	.id		= I2C_ALGO_BIT,
-	.master_xfer	= master_xfer,
-	.functionality	= flexcop_i2c_func,
-};
+		// try the airstar2 (mt352/Samsung tdtc9251dh0(??))
+		skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap);
+		if (skystar2->fe != NULL) {
+			skystar2->fe->ops->info.frequency_min = 474000000;
+			skystar2->fe->ops->info.frequency_max = 858000000;
+			break;
+		}
+		break;
+	}
+
+	if (skystar2->fe == NULL) {
+		printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		       skystar2->pdev->vendor,
+		       skystar2->pdev->device,
+		       skystar2->pdev->subsystem_vendor,
+		       skystar2->pdev->subsystem_device);
+	} else {
+		if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) {
+			printk("skystar2: Frontend registration failed!\n");
+			if (skystar2->fe->ops->release)
+				skystar2->fe->ops->release(skystar2->fe);
+			skystar2->fe = NULL;
+		}
+	}
+}
 
 
 static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -2298,8 +2448,10 @@ static int skystar2_probe(struct pci_dev
 
 	adapter = (struct adapter *) pci_get_drvdata(pdev);
 
+	dvb_adapter->priv = adapter;
 	adapter->dvb_adapter = dvb_adapter;
 
+
 	init_MUTEX(&adapter->i2c_sem);
 
 
@@ -2316,16 +2468,12 @@ static int skystar2_probe(struct pci_dev
 	adapter->i2c_adap.algo              = &flexcop_algo;
 	adapter->i2c_adap.algo_data         = NULL;
 	adapter->i2c_adap.id                = I2C_ALGO_BIT;
-	adapter->i2c_adap.client_register   = client_register;
-	adapter->i2c_adap.client_unregister = client_unregister;
 
 	if (i2c_add_adapter(&adapter->i2c_adap) < 0) {
 		dvb_unregister_adapter (adapter->dvb_adapter);
 		return -ENOMEM;
 	}
 
-	dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter);
-
 	dvbdemux = &adapter->demux;
 
 	dvbdemux->priv = (void *) adapter;
@@ -2361,6 +2509,9 @@ static int skystar2_probe(struct pci_dev
 		return ret;
 
 	dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
+
+	frontend_init(adapter);
+
 	return 0;
 }
 
@@ -2385,9 +2536,9 @@ static void skystar2_remove(struct pci_d
 		dvb_dmxdev_release(&adapter->dmxdev);
 		dvb_dmx_release(&adapter->demux);
 
-		if (adapter->dvb_adapter != NULL) {
-			dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL);
+		if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe);
 
+		if (adapter->dvb_adapter != NULL) {
 			i2c_del_adapter(&adapter->i2c_adap);
 
 			dvb_unregister_adapter(adapter->dvb_adapter);
@@ -2398,7 +2549,7 @@ static void skystar2_remove(struct pci_d
 
 static struct pci_device_id skystar2_pci_tbl[] = {
 	{0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
-	{0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},	//FCIII
+/*	{0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */	//FCIII
 	{0,},
 };
 
diff -puN drivers/media/dvb/bt8xx/bt878.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/bt8xx/bt878.c
--- 25/drivers/media/dvb/bt8xx/bt878.c~dvb-follow-frontend-changes-in-drivers	Thu Nov 18 15:18:02 2004
+++ 25-akpm/drivers/media/dvb/bt8xx/bt878.c	Thu Nov 18 15:18:02 2004
@@ -44,7 +44,7 @@
 #include "dmxdev.h"
 #include "dvbdev.h"
 #include "bt878.h"
-#include "dst-bt878.h"
+#include "dst_priv.h"
 
 
 /**************************************/
@@ -559,22 +559,11 @@ static struct pci_driver bt878_pci_drive
 
 static int bt878_pci_driver_registered = 0;
 
-/* This will be used later by dvb-bt8xx to only use the audio
- * dma of certain cards */
-int bt878_find_audio_dma(void)
-{
-	// pci_register_driver(&bt878_pci_driver);
-	bt878_pci_driver_registered = 1;
-	return 0;
-}
-
-EXPORT_SYMBOL(bt878_find_audio_dma);
-
 /*******************************/
 /* Module management functions */
 /*******************************/
 
-int bt878_init_module(void)
+static int bt878_init_module(void)
 {
 	bt878_num = 0;
 	bt878_pci_driver_registered = 0;
@@ -586,13 +575,13 @@ int bt878_init_module(void)
 /*
         bt878_check_chipset();
 */
-	/* later we register inside of bt878_find_audio_dma
+	/* later we register inside of bt878_find_audio_dma()
 	 * because we may want to ignore certain cards */
 	bt878_pci_driver_registered = 1;
 	return pci_module_init(&bt878_pci_driver);
 }
 
-void bt878_cleanup_module(void)
+static void bt878_cleanup_module(void)
 {
 	if (bt878_pci_driver_registered) {
 		bt878_pci_driver_registered = 0;
@@ -601,12 +590,10 @@ void bt878_cleanup_module(void)
 	return;
 }
 
-EXPORT_SYMBOL(bt878_init_module);
-EXPORT_SYMBOL(bt878_cleanup_module);
 module_init(bt878_init_module);
 module_exit(bt878_cleanup_module);
 
-
+//MODULE_AUTHOR("XXX");
 MODULE_LICENSE("GPL");
 
 /*
diff -puN /dev/null drivers/media/dvb/bt8xx/dst.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/bt8xx/dst.c	Thu Nov 18 15:18:02 2004
@@ -0,0 +1,1089 @@
+/*
+    Frontend-driver for TwinHan DST Frontend
+
+    Copyright (C) 2003 Jamie Honan
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "dst_priv.h"
+#include "dst.h"
+
+struct dst_state {
+
+	struct i2c_adapter* i2c;
+
+	struct bt878* bt;
+
+	struct dvb_frontend_ops ops;
+
+	/* configuration settings */
+	const struct dst_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* private demodulator data */
+	u8 tx_tuna[10];
+	u8 rx_tuna[10];
+	u8 rxbuffer[10];
+	u8 diseq_flags;
+	u8 dst_type;
+	u32 type_flags;
+	u32 frequency;		/* intermediate frequency in kHz for QPSK */
+	fe_spectral_inversion_t inversion;
+	u32 symbol_rate;	/* symbol rate in Symbols per second */
+	fe_code_rate_t fec;
+	fe_sec_voltage_t voltage;
+	fe_sec_tone_mode_t tone;
+	u32 decode_freq;
+	u8 decode_lock;
+	u16 decode_strength;
+	u16 decode_snr;
+	unsigned long cur_jiff;
+	u8 k22;
+	fe_bandwidth_t bandwidth;
+};
+
+static unsigned int dst_verbose = 0;
+module_param(dst_verbose, int, 0644);
+MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
+static unsigned int dst_debug = 0;
+module_param(dst_debug, int, 0644);
+MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
+
+#define dprintk	if (dst_debug) printk
+
+#define DST_TYPE_IS_SAT		0
+#define DST_TYPE_IS_TERR	1
+#define DST_TYPE_IS_CABLE	2
+
+#define DST_TYPE_HAS_NEWTUNE	1
+#define DST_TYPE_HAS_TS204	2
+#define DST_TYPE_HAS_SYMDIV	4
+
+#define HAS_LOCK	1
+#define ATTEMPT_TUNE	2
+#define HAS_POWER	4
+
+static void dst_packsize(struct dst_state* state, int psize)
+{
+	union dst_gpio_packet bits;
+
+	bits.psize = psize;
+	bt878_device_control(state->bt, DST_IG_TS, &bits);
+}
+
+static int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh)
+{
+	union dst_gpio_packet enb;
+	union dst_gpio_packet bits;
+	int err;
+
+	enb.enb.mask = mask;
+	enb.enb.enable = enbb;
+	if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) {
+		dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb);
+		return -EREMOTEIO;
+	}
+
+	/* because complete disabling means no output, no need to do output packet */
+	if (enbb == 0)
+		return 0;
+
+	bits.outp.mask = enbb;
+	bits.outp.highvals = outhigh;
+
+	if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) {
+		dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int dst_gpio_inb(struct dst_state *state, u8 * result)
+{
+	union dst_gpio_packet rd_packet;
+	int err;
+
+	*result = 0;
+
+	if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
+		dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err);
+		return -EREMOTEIO;
+	}
+
+	*result = (u8) rd_packet.rd.value;
+	return 0;
+}
+
+#define DST_I2C_ENABLE	1
+#define DST_8820  	2
+
+static int dst_reset8820(struct dst_state *state)
+{
+	int retval;
+	/* pull 8820 gpio pin low, wait, high, wait, then low */
+	// dprintk ("%s: reset 8820\n", __FUNCTION__);
+	retval = dst_gpio_outb(state, DST_8820, DST_8820, 0);
+	if (retval < 0)
+		return retval;
+	msleep(10);
+	retval = dst_gpio_outb(state, DST_8820, DST_8820, DST_8820);
+	if (retval < 0)
+		return retval;
+	/* wait for more feedback on what works here *
+	   msleep(10);
+	   retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
+	   if (retval < 0)
+	   return retval;
+	 */
+	return 0;
+}
+
+static int dst_i2c_enable(struct dst_state *state)
+{
+	int retval;
+	/* pull I2C enable gpio pin low, wait */
+	// dprintk ("%s: i2c enable\n", __FUNCTION__);
+	retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0);
+	if (retval < 0)
+		return retval;
+	// dprintk ("%s: i2c enable delay\n", __FUNCTION__);
+	msleep(33);
+	return 0;
+}
+
+static int dst_i2c_disable(struct dst_state *state)
+{
+	int retval;
+	/* release I2C enable gpio pin, wait */
+	// dprintk ("%s: i2c disable\n", __FUNCTION__);
+	retval = dst_gpio_outb(state, ~0, 0, 0);
+	if (retval < 0)
+		return retval;
+	// dprintk ("%s: i2c disable delay\n", __FUNCTION__);
+	msleep(33);
+	return 0;
+}
+
+static int dst_wait_dst_ready(struct dst_state *state)
+{
+	u8 reply;
+	int retval;
+	int i;
+	for (i = 0; i < 200; i++) {
+		retval = dst_gpio_inb(state, &reply);
+		if (retval < 0)
+			return retval;
+		if ((reply & DST_I2C_ENABLE) == 0) {
+			dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
+			return 1;
+		}
+		msleep(10);
+	}
+	dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
+	return 0;
+}
+
+static int write_dst(struct dst_state *state, u8 * data, u8 len)
+{
+	struct i2c_msg msg = {
+		.addr = state->config->demod_address,.flags = 0,.buf = data,.len = len
+	};
+	int err;
+	int cnt;
+
+	if (dst_debug && dst_verbose) {
+		u8 i;
+		dprintk("%s writing", __FUNCTION__);
+		for (i = 0; i < len; i++) {
+			dprintk(" 0x%02x", data[i]);
+		}
+		dprintk("\n");
+	}
+	msleep(30);
+	for (cnt = 0; cnt < 4; cnt++) {
+		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+			dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
+			dst_i2c_disable(state);
+			msleep(500);
+			dst_i2c_enable(state);
+			msleep(500);
+			continue;
+		} else
+			break;
+	}
+	if (cnt >= 4)
+		return -EREMOTEIO;
+	return 0;
+}
+
+static int read_dst(struct dst_state *state, u8 * ret, u8 len)
+{
+	struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len };
+	int err;
+	int cnt;
+
+	for (cnt = 0; cnt < 4; cnt++) {
+		if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) {
+			dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]);
+			dst_i2c_disable(state);
+			dst_i2c_enable(state);
+			continue;
+		} else
+			break;
+	}
+	if (cnt >= 4)
+		return -EREMOTEIO;
+	dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]);
+	if (dst_debug && dst_verbose) {
+		for (err = 1; err < len; err++)
+			dprintk(" 0x%x", ret[err]);
+		if (err > 1)
+			dprintk("\n");
+	}
+	return 0;
+}
+
+static int dst_set_freq(struct dst_state *state, u32 freq)
+{
+	u8 *val;
+
+	state->frequency = freq;
+
+	// dprintk("%s: set frequency %u\n", __FUNCTION__, freq);
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		freq = freq / 1000;
+		if (freq < 950 || freq > 2150)
+			return -EINVAL;
+		val = &state->tx_tuna[0];
+		val[2] = (freq >> 8) & 0x7f;
+		val[3] = (u8) freq;
+		val[4] = 1;
+		val[8] &= ~4;
+		if (freq < 1531)
+			val[8] |= 4;
+	} else if (state->dst_type == DST_TYPE_IS_TERR) {
+		freq = freq / 1000;
+		if (freq < 137000 || freq > 858000)
+			return -EINVAL;
+		val = &state->tx_tuna[0];
+		val[2] = (freq >> 16) & 0xff;
+		val[3] = (freq >> 8) & 0xff;
+		val[4] = (u8) freq;
+		val[5] = 0;
+		switch (state->bandwidth) {
+		case BANDWIDTH_6_MHZ:
+			val[6] = 6;
+			break;
+
+		case BANDWIDTH_7_MHZ:
+		case BANDWIDTH_AUTO:
+			val[6] = 7;
+			break;
+
+		case BANDWIDTH_8_MHZ:
+			val[6] = 8;
+			break;
+		}
+
+		val[7] = 0;
+		val[8] = 0;
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		/* guess till will get one */
+		freq = freq / 1000;
+		val = &state->tx_tuna[0];
+		val[2] = (freq >> 16) & 0xff;
+		val[3] = (freq >> 8) & 0xff;
+		val[4] = (u8) freq;
+	} else
+		return -EINVAL;
+	return 0;
+}
+
+static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth)
+{
+	u8 *val;
+
+	state->bandwidth = bandwidth;
+
+	if (state->dst_type != DST_TYPE_IS_TERR)
+		return 0;
+
+	val = &state->tx_tuna[0];
+	switch (bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		val[6] = 6;
+		break;
+
+	case BANDWIDTH_7_MHZ:
+		val[6] = 7;
+		break;
+
+	case BANDWIDTH_8_MHZ:
+		val[6] = 8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion)
+{
+	u8 *val;
+
+	state->inversion = inversion;
+
+	val = &state->tx_tuna[0];
+
+	val[8] &= ~0x80;
+
+	switch (inversion) {
+	case INVERSION_OFF:
+		break;
+	case INVERSION_ON:
+		val[8] |= 0x80;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec)
+{
+	state->fec = fec;
+	return 0;
+}
+
+static fe_code_rate_t dst_get_fec(struct dst_state* state)
+{
+	return state->fec;
+}
+
+static int dst_set_symbolrate(struct dst_state* state, u32 srate)
+{
+	u8 *val;
+	u32 symcalc;
+	u64 sval;
+
+	state->symbol_rate = srate;
+
+	if (state->dst_type == DST_TYPE_IS_TERR) {
+		return 0;
+	}
+	// dprintk("%s: set srate %u\n", __FUNCTION__, srate);
+	srate /= 1000;
+	val = &state->tx_tuna[0];
+
+	if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+		sval = srate;
+		sval <<= 20;
+		do_div(sval, 88000);
+		symcalc = (u32) sval;
+		// dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc);
+		val[5] = (u8) (symcalc >> 12);
+		val[6] = (u8) (symcalc >> 4);
+		val[7] = (u8) (symcalc << 4);
+	} else {
+		val[5] = (u8) (srate >> 16) & 0x7f;
+		val[6] = (u8) (srate >> 8);
+		val[7] = (u8) srate;
+	}
+	val[8] &= ~0x20;
+	if (srate > 8000)
+		val[8] |= 0x20;
+	return 0;
+}
+
+static u8 dst_check_sum(u8 * buf, u32 len)
+{
+	u32 i;
+	u8 val = 0;
+	if (!len)
+		return 0;
+	for (i = 0; i < len; i++) {
+		val += buf[i];
+	}
+	return ((~val) + 1);
+}
+
+struct dst_types {
+	char *mstr;
+	int offs;
+	u8 dst_type;
+	u32 type_flags;
+};
+
+static struct dst_types dst_tlist[] = {
+	{"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
+	{"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
+	{"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204},
+	{"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
+	{"DST-CI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
+	{"DSTMCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
+	{"DSTFCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
+	{"DCTNEW",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE},
+	{"DCT-CI",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
+	{"DTTDIG",  1, DST_TYPE_IS_TERR, 0}
+};
+
+/* DCTNEW and DCT-CI are guesses */
+
+static void dst_type_flags_print(u32 type_flags)
+{
+	printk("DST type flags :");
+	if (type_flags & DST_TYPE_HAS_NEWTUNE)
+		printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+	if (type_flags & DST_TYPE_HAS_TS204)
+		printk(" 0x%x ts204", DST_TYPE_HAS_TS204);
+	if (type_flags & DST_TYPE_HAS_SYMDIV)
+		printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
+	printk("\n");
+}
+
+static int dst_type_print(u8 type)
+{
+	char *otype;
+	switch (type) {
+	case DST_TYPE_IS_SAT:
+		otype = "satellite";
+		break;
+	case DST_TYPE_IS_TERR:
+		otype = "terrestial TV";
+		break;
+	case DST_TYPE_IS_CABLE:
+		otype = "terrestial TV";
+		break;
+	default:
+		printk("%s: invalid dst type %d\n", __FUNCTION__, type);
+		return -EINVAL;
+	}
+	printk("DST type : %s\n", otype);
+	return 0;
+}
+
+static int dst_check_ci(struct dst_state *state)
+{
+	u8 txbuf[8];
+	u8 rxbuf[8];
+	int retval;
+	int i;
+	struct dst_types *dsp;
+	u8 use_dst_type;
+	u32 use_type_flags;
+
+	memset(txbuf, 0, sizeof(txbuf));
+	txbuf[1] = 6;
+	txbuf[7] = dst_check_sum(txbuf, 7);
+
+	dst_i2c_enable(state);
+	dst_reset8820(state);
+	retval = write_dst(state, txbuf, 8);
+	if (retval < 0) {
+		dst_i2c_disable(state);
+		dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
+		return retval;
+	}
+	msleep(3);
+	retval = read_dst(state, rxbuf, 1);
+	dst_i2c_disable(state);
+	if (retval < 0) {
+		dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__);
+		return retval;
+	}
+	if (rxbuf[0] != 0xff) {
+		dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]);
+		return retval;
+	}
+	if (!dst_wait_dst_ready(state))
+		return 0;
+	// dst_i2c_enable(i2c); Dimitri
+	retval = read_dst(state, rxbuf, 8);
+	dst_i2c_disable(state);
+	if (retval < 0) {
+		dprintk("%s: read not successful\n", __FUNCTION__);
+		return retval;
+	}
+	if (rxbuf[7] != dst_check_sum(rxbuf, 7)) {
+		dprintk("%s: checksum failure\n", __FUNCTION__);
+		return retval;
+	}
+	rxbuf[7] = '\0';
+	for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) {
+		if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) {
+			use_type_flags = dsp->type_flags;
+			use_dst_type = dsp->dst_type;
+			printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr);
+			break;
+		}
+	}
+	if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) {
+		printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]);
+		printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__);
+		use_dst_type = DST_TYPE_IS_SAT;
+		use_type_flags = DST_TYPE_HAS_SYMDIV;
+	}
+	dst_type_print(use_dst_type);
+
+	state->type_flags = use_type_flags;
+	state->dst_type = use_dst_type;
+	dst_type_flags_print(state->type_flags);
+
+	if (state->type_flags & DST_TYPE_HAS_TS204) {
+		dst_packsize(state, 204);
+	}
+	return 0;
+}
+
+static int dst_command(struct dst_state* state, u8 * data, u8 len)
+{
+	int retval;
+	u8 reply;
+
+	dst_i2c_enable(state);
+	dst_reset8820(state);
+	retval = write_dst(state, data, len);
+	if (retval < 0) {
+		dst_i2c_disable(state);
+		dprintk("%s: write not successful\n", __FUNCTION__);
+		return retval;
+	}
+	msleep(33);
+	retval = read_dst(state, &reply, 1);
+	dst_i2c_disable(state);
+	if (retval < 0) {
+		dprintk("%s: read verify  not successful\n", __FUNCTION__);
+		return retval;
+	}
+	if (reply != 0xff) {
+		dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
+		return 0;
+	}
+	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
+		return 0;
+	if (!dst_wait_dst_ready(state))
+		return 0;
+	// dst_i2c_enable(i2c); Per dimitri
+	retval = read_dst(state, state->rxbuffer, 8);
+	dst_i2c_disable(state);
+	if (retval < 0) {
+		dprintk("%s: read not successful\n", __FUNCTION__);
+		return 0;
+	}
+	if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
+		dprintk("%s: checksum failure\n", __FUNCTION__);
+		return 0;
+	}
+	return 0;
+}
+
+static int dst_get_signal(struct dst_state* state)
+{
+	int retval;
+	u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
+
+	if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
+		state->decode_lock = state->decode_strength = state->decode_snr = 0;
+		return 0;
+	}
+	if (0 == (state->diseq_flags & HAS_LOCK)) {
+		state->decode_lock = state->decode_strength = state->decode_snr = 0;
+		return 0;
+	}
+	if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) {
+		retval = dst_command(state, get_signal, 8);
+		if (retval < 0)
+			return retval;
+		if (state->dst_type == DST_TYPE_IS_SAT) {
+			state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
+			state->decode_strength = state->rxbuffer[5] << 8;
+			state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
+		} else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) {
+			state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
+			state->decode_strength = state->rxbuffer[4] << 8;
+			state->decode_snr = state->rxbuffer[3] << 8;
+		}
+		state->cur_jiff = jiffies;
+	}
+	return 0;
+}
+
+static int dst_tone_power_cmd(struct dst_state* state)
+{
+	u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
+
+	if (state->dst_type == DST_TYPE_IS_TERR)
+		return 0;
+
+	if (state->voltage == SEC_VOLTAGE_OFF)
+		paket[4] = 0;
+	else
+		paket[4] = 1;
+	if (state->tone == SEC_TONE_ON)
+		paket[2] = state->k22;
+	else
+		paket[2] = 0;
+	paket[7] = dst_check_sum(&paket[0], 7);
+	dst_command(state, paket, 8);
+	return 0;
+}
+
+static int dst_get_tuna(struct dst_state* state)
+{
+	int retval;
+	if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
+		return 0;
+	state->diseq_flags &= ~(HAS_LOCK);
+	if (!dst_wait_dst_ready(state))
+		return 0;
+	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+		/* how to get variable length reply ???? */
+		retval = read_dst(state, state->rx_tuna, 10);
+	} else {
+		retval = read_dst(state, &state->rx_tuna[2], 8);
+	}
+	if (retval < 0) {
+		dprintk("%s: read not successful\n", __FUNCTION__);
+		return 0;
+	}
+	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
+			dprintk("%s: checksum failure?\n", __FUNCTION__);
+			return 0;
+		}
+	} else {
+		if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
+			dprintk("%s: checksum failure?\n", __FUNCTION__);
+			return 0;
+		}
+	}
+	if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
+		return 0;
+	state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+
+	state->decode_lock = 1;
+	/*
+	   dst->decode_n1 = (dst->rx_tuna[4] << 8) +
+	   (dst->rx_tuna[5]);
+
+	   dst->decode_n2 = (dst->rx_tuna[8] << 8) +
+	   (dst->rx_tuna[7]);
+	 */
+	state->diseq_flags |= HAS_LOCK;
+	/* dst->cur_jiff = jiffies; */
+	return 1;
+}
+
+static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+
+static int dst_write_tuna(struct dvb_frontend* fe)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	int retval;
+	u8 reply;
+
+	dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags);
+	state->decode_freq = 0;
+	state->decode_lock = state->decode_strength = state->decode_snr = 0;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		if (!(state->diseq_flags & HAS_POWER))
+			dst_set_voltage(fe, SEC_VOLTAGE_13);
+	}
+	state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
+	dst_i2c_enable(state);
+	if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+		dst_reset8820(state);
+		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
+		retval = write_dst(state, &state->tx_tuna[0], 10);
+	} else {
+		state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
+		retval = write_dst(state, &state->tx_tuna[2], 8);
+	}
+	if (retval < 0) {
+		dst_i2c_disable(state);
+		dprintk("%s: write not successful\n", __FUNCTION__);
+		return retval;
+	}
+	msleep(3);
+	retval = read_dst(state, &reply, 1);
+	dst_i2c_disable(state);
+	if (retval < 0) {
+		dprintk("%s: read verify  not successful\n", __FUNCTION__);
+		return retval;
+	}
+	if (reply != 0xff) {
+		dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
+		return 0;
+	}
+	state->diseq_flags |= ATTEMPT_TUNE;
+	return dst_get_tuna(state);
+}
+
+/*
+ * line22k0    0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k1    0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
+ * line22k2    0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
+ * tone        0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
+ * data        0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
+ * power_off   0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
+ * power_on    0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
+ * Diseqc 1    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
+ * Diseqc 2    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
+ * Diseqc 3    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
+ * Diseqc 4    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
+ */
+
+static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
+
+	if (state->dst_type == DST_TYPE_IS_TERR)
+		return 0;
+
+	if (cmd->msg_len == 0 || cmd->msg_len > 4)
+		return -EINVAL;
+	memcpy(&paket[3], cmd->msg, cmd->msg_len);
+	paket[7] = dst_check_sum(&paket[0], 7);
+	dst_command(state, paket, 8);
+	return 0;
+}
+
+static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	u8 *val;
+	int need_cmd;
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+	state->voltage = voltage;
+
+	if (state->dst_type == DST_TYPE_IS_TERR)
+		return 0;
+
+	need_cmd = 0;
+	val = &state->tx_tuna[0];
+	val[8] &= ~0x40;
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		if ((state->diseq_flags & HAS_POWER) == 0)
+			need_cmd = 1;
+		state->diseq_flags |= HAS_POWER;
+		break;
+	case SEC_VOLTAGE_18:
+		if ((state->diseq_flags & HAS_POWER) == 0)
+			need_cmd = 1;
+		state->diseq_flags |= HAS_POWER;
+		val[8] |= 0x40;
+		break;
+	case SEC_VOLTAGE_OFF:
+		need_cmd = 1;
+		state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (need_cmd) {
+		dst_tone_power_cmd(state);
+	}
+	return 0;
+}
+
+static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	u8 *val;
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+	state->tone = tone;
+
+	if (state->dst_type == DST_TYPE_IS_TERR)
+		return 0;
+
+	val = &state->tx_tuna[0];
+
+	val[8] &= ~0x1;
+
+	switch (tone) {
+	case SEC_TONE_OFF:
+		break;
+	case SEC_TONE_ON:
+		val[8] |= 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	dst_tone_power_cmd(state);
+	return 0;
+}
+
+static int dst_init(struct dvb_frontend* fe)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
+	static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
+	static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+	static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+	static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+	static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
+	state->inversion = INVERSION_ON;
+	state->voltage = SEC_VOLTAGE_13;
+	state->tone = SEC_TONE_OFF;
+	state->symbol_rate = 29473000;
+	state->fec = FEC_AUTO;
+	state->diseq_flags = 0;
+	state->k22 = 0x02;
+	state->bandwidth = BANDWIDTH_7_MHZ;
+	state->cur_jiff = jiffies;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		state->frequency = 950000;
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna));
+	} else if (state->dst_type == DST_TYPE_IS_TERR) {
+		state->frequency = 137000000;
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna));
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		state->frequency = 51000000;
+		memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna));
+	}
+
+	return 0;
+}
+
+static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+	*status = 0;
+	if (state->diseq_flags & HAS_LOCK) {
+		dst_get_signal(state);
+		if (state->decode_lock)
+			*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
+	}
+
+	return 0;
+}
+
+static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+	dst_get_signal(state);
+	*strength = state->decode_strength;
+
+	return 0;
+}
+
+static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+	dst_get_signal(state);
+	*snr = state->decode_snr;
+
+	return 0;
+}
+
+static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+	dst_set_freq(state, p->frequency);
+	dst_set_inversion(state, p->inversion);
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		dst_set_fec(state, p->u.qpsk.fec_inner);
+		dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+	} else if (state->dst_type == DST_TYPE_IS_TERR) {
+		dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		dst_set_fec(state, p->u.qam.fec_inner);
+		dst_set_symbolrate(state, p->u.qam.symbol_rate);
+	}
+	dst_write_tuna(fe);
+
+	return 0;
+}
+
+static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+
+	p->frequency = state->decode_freq;
+	p->inversion = state->inversion;
+	if (state->dst_type == DST_TYPE_IS_SAT) {
+		p->u.qpsk.symbol_rate = state->symbol_rate;
+		p->u.qpsk.fec_inner = dst_get_fec(state);
+	} else if (state->dst_type == DST_TYPE_IS_TERR) {
+		p->u.ofdm.bandwidth = state->bandwidth;
+	} else if (state->dst_type == DST_TYPE_IS_CABLE) {
+		p->u.qam.symbol_rate = state->symbol_rate;
+		p->u.qam.fec_inner = dst_get_fec(state);
+		p->u.qam.modulation = QAM_AUTO;
+	}
+
+	return 0;
+}
+
+static void dst_release(struct dvb_frontend* fe)
+{
+	struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops dst_dvbt_ops;
+static struct dvb_frontend_ops dst_dvbs_ops;
+static struct dvb_frontend_ops dst_dvbc_ops;
+
+struct dvb_frontend* dst_attach(const struct dst_config* config,
+				struct i2c_adapter* i2c,
+				struct bt878 *bt)
+{
+	struct dst_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->bt = bt;
+
+	/* check if the demod is there */
+	if (dst_check_ci(state) < 0) goto error;
+
+	/* determine settings based on type */
+	switch (state->dst_type) {
+	case DST_TYPE_IS_TERR:
+		memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case DST_TYPE_IS_CABLE:
+		memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	case DST_TYPE_IS_SAT:
+		memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+		break;
+	default:
+		printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
+		goto error;
+	}
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	if (state) kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops dst_dvbt_ops = {
+
+	.info = {
+		.name = "DST DVB-T",
+		.type = FE_OFDM,
+		.frequency_min = 137000000,
+		.frequency_max = 858000000,
+		.frequency_stepsize = 166667,
+		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+	},
+
+	.release = dst_release,
+
+	.init = dst_init,
+
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_dvbs_ops = {
+
+	.info = {
+		.name = "DST DVB-S",
+		.type = FE_QPSK,
+		.frequency_min = 950000,
+		.frequency_max = 2150000,
+		.frequency_stepsize = 1000,	/* kHz for QPSK frontends */
+		.frequency_tolerance = 29500,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+	/*     . symbol_rate_tolerance	= 	???,*/
+		.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
+	},
+
+	.release = dst_release,
+
+	.init = dst_init,
+
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+
+	.diseqc_send_master_cmd = dst_set_diseqc,
+	.set_voltage = dst_set_voltage,
+	.set_tone = dst_set_tone,
+};
+
+static struct dvb_frontend_ops dst_dvbc_ops = {
+
+	.info = {
+		.name = "DST DVB-C",
+		.type = FE_QAM,
+		.frequency_stepsize = 62500,
+		.frequency_min = 51000000,
+		.frequency_max = 858000000,
+		.symbol_rate_min = 1000000,
+		.symbol_rate_max = 45000000,
+	/*     . symbol_rate_tolerance	= 	???,*/
+		.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
+	},
+
+	.release = dst_release,
+
+	.init = dst_init,
+
+	.set_frontend = dst_set_frontend,
+	.get_frontend = dst_get_frontend,
+
+	.read_status = dst_read_status,
+	.read_signal_strength = dst_read_signal_strength,
+	.read_snr = dst_read_snr,
+};
+
+MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_AUTHOR("Jamie Honan");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(dst_attach);
diff -puN /dev/null drivers/media/dvb/bt8xx/dst.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/bt8xx/dst.h	Thu Nov 18 15:18:02 2004
@@ -0,0 +1,40 @@
+/*
+    Frontend-driver for TwinHan DST Frontend
+
+    Copyright (C) 2003 Jamie Honan
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef DST_H
+#define DST_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/device.h>
+#include "bt878.h"
+
+struct dst_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+};
+
+extern struct dvb_frontend* dst_attach(const struct dst_config* config,
+				       struct i2c_adapter* i2c,
+				       struct bt878 *bt);
+
+#endif // DST_H
diff -puN /dev/null drivers/media/dvb/bt8xx/dst_priv.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/bt8xx/dst_priv.h	Thu Nov 18 15:18:02 2004
@@ -0,0 +1,37 @@
+/*
+ * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
+ *
+ * Copyright (C) 2003 Jamie Honan
+ */
+
+struct dst_gpio_enable {
+	u32	mask;
+	u32	enable;
+};
+
+struct dst_gpio_output {
+	u32	mask;
+	u32	highvals;
+};
+
+struct dst_gpio_read {
+	unsigned long value;
+};
+
+union dst_gpio_packet {
+	struct dst_gpio_enable enb;
+	struct dst_gpio_output outp;
+	struct dst_gpio_read rd;
+	int    psize;
+};
+
+#define DST_IG_ENABLE	0
+#define DST_IG_WRITE	1
+#define DST_IG_READ	2
+#define DST_IG_TS       3
+
+struct bt878;
+
+int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
+
+struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap);
diff -puN drivers/media/dvb/bt8xx/dvb-bt8xx.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/bt8xx/dvb-bt8xx.c
--- 25/drivers/media/dvb/bt8xx/dvb-bt8xx.c~dvb-follow-frontend-changes-in-drivers	Thu Nov 18 15:18:02 2004
+++ 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.c	Thu Nov 18 15:18:02 2004
@@ -126,7 +126,286 @@ static struct bt878 __init *dvb_bt8xx_87
 	return NULL;
 }
 
-static int __init dvb_bt8xx_load_card( struct dvb_bt8xx_card *card)
+
+static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
+{
+	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
+	static u8 mt352_reset [] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
+	static u8 mt352_gpp_ctl_cfg [] = { 0x75, 0x33 };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+        mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+	return 0;
+}
+
+static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+	u32 div;
+	unsigned char bs = 0;
+	unsigned char cp = 0;
+
+	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+	if (params->frequency < 542000000) cp = 0xb4;
+	else if (params->frequency < 771000000) cp = 0xbc;
+	else cp = 0xf4;
+
+        if (params->frequency == 0) bs = 0x03;
+	else if (params->frequency < 443250000) bs = 0x02;
+	else bs = 0x08;
+
+	pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+	pllbuf[1] = div >> 8;
+   	pllbuf[2] = div & 0xff;
+   	pllbuf[3] = cp;
+   	pllbuf[4] = bs;
+
+	return 0;
+}
+
+static struct mt352_config thomson_dtt7579_config = {
+
+	.demod_address = 0x0f,
+	.demod_init = thomson_dtt7579_demod_init,
+	.pll_set = thomson_dtt7579_pll_set,
+};
+
+
+
+static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+	u8 cfg, cpump, band_select;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (36000000 + params->frequency + 83333) / 166666;
+	cfg = 0x88;
+
+	if (params->frequency < 175000000) cpump = 2;
+	else if (params->frequency < 390000000) cpump = 1;
+	else if (params->frequency < 470000000) cpump = 2;
+	else if (params->frequency < 750000000) cpump = 2;
+	else cpump = 3;
+
+	if (params->frequency < 175000000) band_select = 0x0e;
+	else if (params->frequency < 470000000) band_select = 0x05;
+	else band_select = 0x03;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = ((div >> 10) & 0x60) | cfg;
+	data[3] = cpump | band_select;
+
+	i2c_transfer(card->i2c_adapter, &msg, 1);
+	return (div * 166666 - 36000000);
+}
+
+static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
+
+	return request_firmware(fw, name, &bt->bt->dev->dev);
+}
+
+struct sp887x_config microtune_mt7202dtf_config = {
+
+	.demod_address = 0x70,
+	.pll_set = microtune_mt7202dtf_pll_set,
+	.request_firmware = microtune_mt7202dtf_request_firmware,
+};
+
+
+
+static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+{
+	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
+	static u8 mt352_reset [] = { 0x50, 0x80 };
+	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+	static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+	                               0x00, 0xFF, 0x00, 0x40, 0x40 };
+	static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
+	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
+
+
+	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+	udelay(2000);
+	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+
+	mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
+	udelay(2000);
+	mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
+	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
+
+	return 0;
+}
+
+static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+{
+	u32 div;
+	unsigned char bs = 0;
+	unsigned char cp = 0;
+
+	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
+
+	if (params->frequency < 150000000) cp = 0xB4;
+	else if (params->frequency < 173000000) cp = 0xBC;
+	else if (params->frequency < 250000000) cp = 0xB4;
+	else if (params->frequency < 400000000) cp = 0xBC;
+	else if (params->frequency < 420000000) cp = 0xF4;
+	else if (params->frequency < 470000000) cp = 0xFC;
+	else if (params->frequency < 600000000) cp = 0xBC;
+	else if (params->frequency < 730000000) cp = 0xF4;
+	else cp = 0xFC;
+
+	if (params->frequency < 150000000) bs = 0x01;
+	else if (params->frequency < 173000000) bs = 0x01;
+	else if (params->frequency < 250000000) bs = 0x02;
+	else if (params->frequency < 400000000) bs = 0x02;
+	else if (params->frequency < 420000000) bs = 0x02;
+	else if (params->frequency < 470000000) bs = 0x02;
+	else if (params->frequency < 600000000) bs = 0x08;
+	else if (params->frequency < 730000000) bs = 0x08;
+	else bs = 0x08;
+
+	pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+	pllbuf[1] = div >> 8;
+   	pllbuf[2] = div & 0xff;
+   	pllbuf[3] = cp;
+   	pllbuf[4] = bs;
+
+	return 0;
+}
+
+static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
+
+	.demod_address = 0x0f,
+	.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
+	.pll_set = advbt771_samsung_tdtc9251dh0_pll_set,
+};
+
+
+static struct dst_config dst_config = {
+
+	.demod_address = 0x55,
+};
+
+
+static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+	div = (params->frequency + 36166667) / 166667;
+
+	buf[0] = (div >> 8) & 0x7F;
+	buf[1] = div & 0xFF;
+	buf[2] = 0x85;
+	if ((params->frequency >= 47000000) && (params->frequency < 153000000))
+		buf[3] = 0x01;
+	else if ((params->frequency >= 153000000) && (params->frequency < 430000000))
+		buf[3] = 0x02;
+	else if ((params->frequency >= 430000000) && (params->frequency < 824000000))
+		buf[3] = 0x0C;
+	else if ((params->frequency >= 824000000) && (params->frequency < 863000000))
+		buf[3] = 0x8C;
+	else
+		return -EINVAL;
+
+	i2c_transfer(card->i2c_adapter, &msg, 1);
+	return 0;
+}
+
+static struct nxt6000_config vp3021_alps_tded4_config = {
+
+	.demod_address = 0x0a,
+	.clock_inversion = 1,
+	.pll_set = vp3021_alps_tded4_pll_set,
+};
+
+
+static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
+{
+	switch(type) {
+#ifdef BTTV_DVICO_DVBT_LITE
+	case BTTV_DVICO_DVBT_LITE:
+		card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			card->fe->ops->info.frequency_min = 174000000;
+			card->fe->ops->info.frequency_max = 862000000;
+			break;
+		}
+		break;
+#endif
+
+#ifdef BTTV_TWINHAN_VP3021
+	case BTTV_TWINHAN_VP3021:
+#else
+	case BTTV_NEBULA_DIGITV:
+#endif
+		card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			break;
+		}
+		break;
+
+	case BTTV_AVDVBT_761:
+		card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			break;
+		}
+		break;
+
+	case BTTV_AVDVBT_771:
+		card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
+		if (card->fe != NULL) {
+			card->fe->ops->info.frequency_min = 174000000;
+			card->fe->ops->info.frequency_max = 862000000;
+			break;
+		}
+		break;
+
+	case BTTV_TWINHAN_DST:
+		card->fe = dst_attach(&dst_config, card->i2c_adapter, card->bt);
+		if (card->fe != NULL) {
+			break;
+		}
+		break;
+	}
+
+	if (card->fe == NULL) {
+		printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		       card->bt->dev->vendor,
+		       card->bt->dev->device,
+		       card->bt->dev->subsystem_vendor,
+		       card->bt->dev->subsystem_device);
+	} else {
+		if (dvb_register_frontend(card->dvb_adapter, card->fe)) {
+			printk("dvb-bt8xx: Frontend registration failed!\n");
+			if (card->fe->ops->release)
+				card->fe->ops->release(card->fe);
+			card->fe = NULL;
+		}
+	}
+}
+
+static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
 {
 	int result;
 
@@ -136,6 +415,7 @@ static int __init dvb_bt8xx_load_card( s
 		return result;
 		
 	}
+	card->dvb_adapter->priv = card;
 
 	card->bt->adapter = card->i2c_adapter;
 
@@ -207,6 +487,8 @@ static int __init dvb_bt8xx_load_card( s
 
 	tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
 	
+	frontend_init(card, type);
+
 	return 0;
 }
 
@@ -228,7 +510,7 @@ static int dvb_bt8xx_probe(struct device
 
 	switch(sub->core->type)
 	{
-	case BTTV_PINNACLESAT:
+/*	case BTTV_PINNACLESAT: UNDEFINED HARDWARE */
 #ifdef BTTV_DVICO_DVBT_LITE
 	case BTTV_DVICO_DVBT_LITE:
 #endif
@@ -240,7 +522,11 @@ static int dvb_bt8xx_probe(struct device
 				 * DA_APP(parallel) */
 				break;
 
+#ifdef BTTV_TWINHAN_VP3021
+	case BTTV_TWINHAN_VP3021:
+#else
 	case BTTV_NEBULA_DIGITV:
+#endif
 	case BTTV_AVDVBT_761:
 		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
 		card->op_sync_orin = 0;
@@ -302,7 +588,7 @@ static int dvb_bt8xx_probe(struct device
 	init_MUTEX(&card->bt->gpio_lock);
 	card->bt->bttv_nr = sub->core->nr;
 
-	if ( (ret = dvb_bt8xx_load_card(card)) ) {
+	if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
 		kfree(card);
 		return ret;
 	}
@@ -324,6 +610,7 @@ static int dvb_bt8xx_remove(struct devic
 		card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
 		dvb_dmxdev_release(&card->dmxdev);
 		dvb_dmx_release(&card->demux);
+	if (card->fe) dvb_unregister_frontend(card->fe);
 		dvb_unregister_adapter(card->dvb_adapter);
 		
 		kfree(card);
@@ -331,24 +618,6 @@ static int dvb_bt8xx_remove(struct devic
 	return 0;
 	}
 
-static void dvb_bt8xx_i2c_info(struct bttv_sub_device *sub,
-			       struct i2c_client *client, int attach)
-{
-	struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
-
-	if (attach) {
-		printk("xxx attach\n");
-		if (client->driver->command)
-			client->driver->command(client, FE_REGISTER,
-						card->dvb_adapter);
-	} else {
-		printk("xxx detach\n");
-		if (client->driver->command)
-			client->driver->command(client, FE_UNREGISTER,
-						card->dvb_adapter);
-	}
-}
-
 static struct bttv_sub_driver driver = {
 	.drv = {
 		.name		= "dvb-bt8xx",
@@ -360,7 +629,6 @@ static struct bttv_sub_driver driver = {
 		 * .resume	= dvb_bt8xx_resume,
 		 */
 	},
-	.i2c_info = dvb_bt8xx_i2c_info,
 };
 
 static int __init dvb_bt8xx_init(void)
diff -puN drivers/media/dvb/bt8xx/dvb-bt8xx.h~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/bt8xx/dvb-bt8xx.h
--- 25/drivers/media/dvb/bt8xx/dvb-bt8xx.h~dvb-follow-frontend-changes-in-drivers	Thu Nov 18 15:18:02 2004
+++ 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.h	Thu Nov 18 15:18:02 2004
@@ -26,6 +26,10 @@
 #include "dvbdev.h"
 #include "dvb_net.h"
 #include "bttv.h"
+#include "mt352.h"
+#include "sp887x.h"
+#include "dst.h"
+#include "nxt6000.h"
 
 struct dvb_bt8xx_card {
 	struct semaphore lock;
@@ -44,4 +48,5 @@ struct dvb_bt8xx_card {
 	struct i2c_adapter *i2c_adapter;
 	struct dvb_net dvbnet;
 				
+	struct dvb_frontend* fe;
 };
diff -L drivers/media/dvb/frontends/dst-bt878.h -puN drivers/media/dvb/frontends/dst-bt878.h~dvb-follow-frontend-changes-in-drivers /dev/null
--- 25/drivers/media/dvb/frontends/dst-bt878.h
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,37 +0,0 @@
-/*
- * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
- *
- * Copyright (C) 2003 Jamie Honan
- */
-
-struct dst_gpio_enable {
-	u32	mask;
-	u32	enable;
-};
-
-struct dst_gpio_output {
-	u32	mask;
-	u32	highvals;
-};
-
-struct dst_gpio_read {
-	unsigned long value;
-};
-
-union dst_gpio_packet {
-	struct dst_gpio_enable enb;
-	struct dst_gpio_output outp;
-	struct dst_gpio_read rd;
-	int    psize;
-};
-
-#define DST_IG_ENABLE	0
-#define DST_IG_WRITE	1
-#define DST_IG_READ	2
-#define DST_IG_TS       3
-
-struct bt878 ;
-
-int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
-
-struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap);
diff -L drivers/media/dvb/frontends/dst.c -puN drivers/media/dvb/frontends/dst.c~dvb-follow-frontend-changes-in-drivers /dev/null
--- 25/drivers/media/dvb/frontends/dst.c
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,1256 +0,0 @@
-/* 
-    Frontend-driver for TwinHan DST Frontend
-
-    Copyright (C) 2003 Jamie Honan
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "dst-bt878.h"
-
-unsigned int dst_verbose = 0;
-MODULE_PARM(dst_verbose, "i");
-MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
-unsigned int dst_debug = 0;
-MODULE_PARM(dst_debug, "i");
-MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
-
-#define dprintk	if (dst_debug) printk
-
-#define DST_I2C_ADDR 0x55
-
-#define DST_TYPE_IS_SAT		0
-#define DST_TYPE_IS_TERR	1
-#define DST_TYPE_IS_CABLE	2
-
-#define DST_TYPE_HAS_NEWTUNE	1
-#define DST_TYPE_HAS_TS204	2
-#define DST_TYPE_HAS_SYMDIV	4
-
-#define HAS_LOCK	1
-#define ATTEMPT_TUNE	2
-#define HAS_POWER	4
-
-struct dst_data {
-	u8 tx_tuna[10];
-	u8 rx_tuna[10];
-	u8 rxbuffer[10];
-	u8 diseq_flags;
-	u8 dst_type;
-	u32 type_flags;
-	u32 frequency;		/* intermediate frequency in kHz for QPSK */
-	fe_spectral_inversion_t inversion;
-	u32 symbol_rate;	/* symbol rate in Symbols per second */
-	fe_code_rate_t fec;
-	fe_sec_voltage_t voltage;
-	fe_sec_tone_mode_t tone;
-	u32 decode_freq;
-	u8 decode_lock;
-	u16 decode_strength;
-	u16 decode_snr;
-	unsigned long cur_jiff;
-	u8 k22;
-	fe_bandwidth_t bandwidth;
-
-	struct bt878 *bt;
-	struct i2c_adapter *i2c;
-	struct dvb_adapter *dvb;
-};
-
-static struct dvb_frontend_info dst_info_sat = {
-	.name = "DST SAT",
-	.type = FE_QPSK,
-	.frequency_min = 950000,
-	.frequency_max = 2150000,
-	.frequency_stepsize = 1000,	/* kHz for QPSK frontends */
-	.frequency_tolerance = 29500,
-	.symbol_rate_min = 1000000,
-	.symbol_rate_max = 45000000,
-/*     . symbol_rate_tolerance	= 	???,*/
-	.notifier_delay = 50,	/* 1/20 s */
-	.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
-};
-
-static struct dvb_frontend_info dst_info_cable = {
-	.name = "DST CABLE",
-	.type = FE_QAM,
-	.frequency_stepsize = 62500,
-	.frequency_min = 51000000,
-	.frequency_max = 858000000,
-	.symbol_rate_min = 1000000,
-	.symbol_rate_max = 45000000,
-/*     . symbol_rate_tolerance	= 	???,*/
-	.notifier_delay = 50,	/* 1/20 s */
-	.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
-};
-
-static struct dvb_frontend_info dst_info_terr = {
-	.name = "DST TERR",
-	.type = FE_OFDM,
-	.frequency_min = 137000000,
-	.frequency_max = 858000000,
-	.frequency_stepsize = 166667,
-	.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
-};
-
-static void dst_packsize(struct dst_data *dst, int psize)
-{
-	union dst_gpio_packet bits;
-
-	bits.psize = psize;
-	bt878_device_control(dst->bt, DST_IG_TS, &bits);
-}
-
-static int dst_gpio_outb(struct dst_data *dst, u32 mask, u32 enbb, u32 outhigh)
-{
-	union dst_gpio_packet enb;
-	union dst_gpio_packet bits;
-	int err;
-
-	enb.enb.mask = mask;
-	enb.enb.enable = enbb;
-	if ((err = bt878_device_control(dst->bt, DST_IG_ENABLE, &enb)) < 0) {
-		dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb);
-		return -EREMOTEIO;
-	}
-
-	/* because complete disabling means no output, no need to do output packet */
-	if (enbb == 0)
-		return 0;
-
-	bits.outp.mask = enbb;
-	bits.outp.highvals = outhigh;
-
-	if ((err = bt878_device_control(dst->bt, DST_IG_WRITE, &bits)) < 0) {
-		dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int dst_gpio_inb(struct dst_data *dst, u8 * result)
-{
-	union dst_gpio_packet rd_packet;
-	int err;
-
-	*result = 0;
-
-	if ((err = bt878_device_control(dst->bt, DST_IG_READ, &rd_packet)) < 0) {
-		dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err);
-		return -EREMOTEIO;
-	}
-	*result = (u8) rd_packet.rd.value;
-	return 0;
-}
-
-#define DST_I2C_ENABLE	1
-#define DST_8820  	2
-
-static int dst_reset8820(struct dst_data *dst)
-{
-	int retval;
-	/* pull 8820 gpio pin low, wait, high, wait, then low */
-	// dprintk ("%s: reset 8820\n", __FUNCTION__);
-	retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
-	if (retval < 0)
-		return retval;
-	msleep(10);
-	retval = dst_gpio_outb(dst, DST_8820, DST_8820, DST_8820);
-	if (retval < 0)
-		return retval;
-	/* wait for more feedback on what works here *
-	   msleep(10);
-	   retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
-	   if (retval < 0)
-	   return retval;
-	 */
-	return 0;
-}
-
-static int dst_i2c_enable(struct dst_data *dst)
-{
-	int retval;
-	/* pull I2C enable gpio pin low, wait */
-	// dprintk ("%s: i2c enable\n", __FUNCTION__);
-	retval = dst_gpio_outb(dst, ~0, DST_I2C_ENABLE, 0);
-	if (retval < 0)
-		return retval;
-	// dprintk ("%s: i2c enable delay\n", __FUNCTION__);
-	msleep(33);
-	return 0;
-}
-
-static int dst_i2c_disable(struct dst_data *dst)
-{
-	int retval;
-	/* release I2C enable gpio pin, wait */
-	// dprintk ("%s: i2c disable\n", __FUNCTION__);
-	retval = dst_gpio_outb(dst, ~0, 0, 0);
-	if (retval < 0)
-		return retval;
-	// dprintk ("%s: i2c disable delay\n", __FUNCTION__);
-	msleep(33);
-	return 0;
-}
-
-static int dst_wait_dst_ready(struct dst_data *dst)
-{
-	u8 reply;
-	int retval;
-	int i;
-	for (i = 0; i < 200; i++) {
-		retval = dst_gpio_inb(dst, &reply);
-		if (retval < 0)
-			return retval;
-		if ((reply & DST_I2C_ENABLE) == 0) {
-			dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
-			return 1;
-		}
-		msleep(5);
-	}
-	dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
-	return 0;
-}
-
-static int write_dst(struct dst_data *dst, u8 * data, u8 len)
-{
-	struct i2c_msg msg = {
-		.addr = DST_I2C_ADDR,.flags = 0,.buf = data,.len = len
-	};
-	int err;
-	int cnt;
-
-	if (dst_debug && dst_verbose) {
-		u8 i;
-		dprintk("%s writing", __FUNCTION__);
-		for (i = 0; i < len; i++) {
-			dprintk(" 0x%02x", data[i]);
-		}
-		dprintk("\n");
-	}
-	msleep(30);
-	for (cnt = 0; cnt < 4; cnt++) {
-		if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) {
-			dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]);
-			dst_i2c_disable(dst);
-			msleep(500);
-			dst_i2c_enable(dst);
-			msleep(500);
-			continue;
-		} else
-			break;
-	}
-	if (cnt >= 4)
-		return -EREMOTEIO;
-	return 0;
-}
-
-static int read_dst(struct dst_data *dst, u8 * ret, u8 len)
-{
-	struct i2c_msg msg = {.addr = DST_I2C_ADDR,.flags = I2C_M_RD,.buf = ret,.len = len };
-	int err;
-	int cnt;
-
-	for (cnt = 0; cnt < 4; cnt++) {
-		if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) {
-			dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]);
-			dst_i2c_disable(dst);
-			dst_i2c_enable(dst);
-			continue;
-		} else
-			break;
-	}
-	if (cnt >= 4)
-		return -EREMOTEIO;
-	dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]);
-	if (dst_debug && dst_verbose) {
-		for (err = 1; err < len; err++)
-			dprintk(" 0x%x", ret[err]);
-		if (err > 1)
-			dprintk("\n");
-	}
-	return 0;
-}
-
-static int dst_set_freq(struct dst_data *dst, u32 freq)
-{
-	u8 *val;
-
-	dst->frequency = freq;
-
-	// dprintk("%s: set frequency %u\n", __FUNCTION__, freq);
-	if (dst->dst_type == DST_TYPE_IS_SAT) {
-		freq = freq / 1000;
-		if (freq < 950 || freq > 2150)
-			return -EINVAL;
-		val = &dst->tx_tuna[0];
-		val[2] = (freq >> 8) & 0x7f;
-		val[3] = (u8) freq;
-		val[4] = 1;
-		val[8] &= ~4;
-		if (freq < 1531)
-			val[8] |= 4;
-	} else if (dst->dst_type == DST_TYPE_IS_TERR) {
-		freq = freq / 1000;
-		if (freq < 137000 || freq > 858000)
-			return -EINVAL;
-		val = &dst->tx_tuna[0];
-		val[2] = (freq >> 16) & 0xff;
-		val[3] = (freq >> 8) & 0xff;
-		val[4] = (u8) freq;
-		val[5] = 0;
-		switch (dst->bandwidth) {
-		case BANDWIDTH_6_MHZ:
-			val[6] = 6;
-			break;
-
-		case BANDWIDTH_7_MHZ:
-		case BANDWIDTH_AUTO:
-			val[6] = 7;
-			break;
-
-		case BANDWIDTH_8_MHZ:
-			val[6] = 8;
-			break;
-		}
-
-		val[7] = 0;
-		val[8] = 0;
-	} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
-		/* guess till will get one */
-		freq = freq / 1000;
-		val = &dst->tx_tuna[0];
-		val[2] = (freq >> 16) & 0xff;
-		val[3] = (freq >> 8) & 0xff;
-		val[4] = (u8) freq;
-	} else
-		return -EINVAL;
-	return 0;
-}
-
-static int dst_set_bandwidth(struct dst_data *dst, fe_bandwidth_t bandwidth)
-{
-	u8 *val;
-
-	dst->bandwidth = bandwidth;
-
-	if (dst->dst_type != DST_TYPE_IS_TERR)
-		return 0;
-
-	val = &dst->tx_tuna[0];
-	switch (bandwidth) {
-	case BANDWIDTH_6_MHZ:
-		val[6] = 6;
-		break;
-
-	case BANDWIDTH_7_MHZ:
-		val[6] = 7;
-		break;
-
-	case BANDWIDTH_8_MHZ:
-		val[6] = 8;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int dst_set_inversion(struct dst_data *dst, fe_spectral_inversion_t inversion)
-{
-	u8 *val;
-
-	dst->inversion = inversion;
-
-	val = &dst->tx_tuna[0];
-
-	val[8] &= ~0x80;
-
-	switch (inversion) {
-	case INVERSION_OFF:
-		break;
-	case INVERSION_ON:
-		val[8] |= 0x80;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-
-static int dst_set_fec(struct dst_data *dst, fe_code_rate_t fec)
-{
-	dst->fec = fec;
-	return 0;
-}
-
-static fe_code_rate_t dst_get_fec(struct dst_data *dst)
-{
-	return dst->fec;
-}
-
-static int dst_set_symbolrate(struct dst_data *dst, u32 srate)
-{
-	u8 *val;
-	u32 symcalc;
-	u64 sval;
-
-	dst->symbol_rate = srate;
-
-	if (dst->dst_type == DST_TYPE_IS_TERR) {
-		return 0;
-	}
-	// dprintk("%s: set srate %u\n", __FUNCTION__, srate);
-	srate /= 1000;
-	val = &dst->tx_tuna[0];
-
-	if (dst->type_flags & DST_TYPE_HAS_SYMDIV) {
-		sval = srate;
-		sval <<= 20;
-		do_div(sval, 88000);
-		symcalc = (u32) sval;
-		// dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc);
-		val[5] = (u8) (symcalc >> 12);
-		val[6] = (u8) (symcalc >> 4);
-		val[7] = (u8) (symcalc << 4);
-	} else {
-		val[5] = (u8) (srate >> 16) & 0x7f;
-		val[6] = (u8) (srate >> 8);
-		val[7] = (u8) srate;
-	}
-	val[8] &= ~0x20;
-	if (srate > 8000)
-		val[8] |= 0x20;
-	return 0;
-}
-
-
-static u8 dst_check_sum(u8 * buf, u32 len)
-{
-	u32 i;
-	u8 val = 0;
-	if (!len)
-		return 0;
-	for (i = 0; i < len; i++) {
-		val += buf[i];
-	}
-	return ((~val) + 1);
-}
-
-typedef struct dst_types {
-	char *mstr;
-	int offs;
-	u8 dst_type;
-	u32 type_flags;
-} DST_TYPES;
-
-struct dst_types dst_tlist[] = {
-	{"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
-	{"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
-	{"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204},
-	{"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV},
-	{"DST-CI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE},
-	{"DSTMCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
-	{"DSTFCI",  1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
-	{"DCTNEW",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE},
-	{"DCT_CI",  1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
-	{"DTTDIG",  1, DST_TYPE_IS_TERR, 0}
-};
-
-/* DCTNEW and DCT-CI are guesses */
-
-static void dst_type_flags_print(u32 type_flags)
-{
-	printk("DST type flags :");
-	if (type_flags & DST_TYPE_HAS_NEWTUNE)
-		printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
-	if (type_flags & DST_TYPE_HAS_TS204)
-		printk(" 0x%x ts204", DST_TYPE_HAS_TS204);
-	if (type_flags & DST_TYPE_HAS_SYMDIV)
-		printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
-	printk("\n");
-}
-
-static int dst_type_print(u8 type)
-{
-	char *otype;
-	switch (type) {
-	case DST_TYPE_IS_SAT:
-		otype = "satellite";
-		break;
-	case DST_TYPE_IS_TERR:
-		otype = "terrestial TV";
-		break;
-	case DST_TYPE_IS_CABLE:
-		otype = "terrestial TV";
-		break;
-	default:
-		printk("%s: invalid dst type %d\n", __FUNCTION__, type);
-		return -EINVAL;
-	}
-	printk("DST type : %s\n", otype);
-	return 0;
-}
-
-static int dst_check_ci(struct dst_data *dst)
-{
-	u8 txbuf[8];
-	u8 rxbuf[8];
-	int retval;
-	int i;
-	struct dst_types *dsp;
-	u8 use_dst_type;
-	u32 use_type_flags;
-
-	memset(txbuf, 0, sizeof(txbuf));
-	txbuf[1] = 6;
-	txbuf[7] = dst_check_sum(txbuf, 7);
-
-	dst_i2c_enable(dst);
-	dst_reset8820(dst);
-	retval = write_dst(dst, txbuf, 8);
-	if (retval < 0) {
-		dst_i2c_disable(dst);
-		dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
-		return retval;
-	}
-	msleep(3);
-	retval = read_dst(dst, rxbuf, 1);
-	dst_i2c_disable(dst);
-	if (retval < 0) {
-		dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__);
-		return retval;
-	}
-	if (rxbuf[0] != 0xff) {
-		dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]);
-		return retval;
-	}
-	if (!dst_wait_dst_ready(dst))
-		return 0;
-	// dst_i2c_enable(i2c); Dimitri
-	retval = read_dst(dst, rxbuf, 8);
-	dst_i2c_disable(dst);
-	if (retval < 0) {
-		dprintk("%s: read not successful\n", __FUNCTION__);
-		return retval;
-	}
-	if (rxbuf[7] != dst_check_sum(rxbuf, 7)) {
-		dprintk("%s: checksum failure\n", __FUNCTION__);
-		return retval;
-	}
-	rxbuf[7] = '\0';
-	for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) {
-		if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) {
-			use_type_flags = dsp->type_flags;
-			use_dst_type = dsp->dst_type;
-			printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr);
-			break;
-		}
-	}
-	if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) {
-		printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]);
-		printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__);
-		use_dst_type = DST_TYPE_IS_SAT;
-		use_type_flags = DST_TYPE_HAS_SYMDIV;
-	}
-	dst_type_print(use_dst_type);
-
-	dst->type_flags = use_type_flags;
-	dst->dst_type = use_dst_type;
-	dst_type_flags_print(dst->type_flags);
-
-	if (dst->type_flags & DST_TYPE_HAS_TS204) {
-		dst_packsize(dst, 204);
-	}
-	return 0;
-}
-
-static int dst_command(struct dst_data *dst, u8 * data, u8 len)
-{
-	int retval;
-	u8 reply;
-
-	dst_i2c_enable(dst);
-	dst_reset8820(dst);
-	retval = write_dst(dst, data, len);
-	if (retval < 0) {
-		dst_i2c_disable(dst);
-		dprintk("%s: write not successful\n", __FUNCTION__);
-		return retval;
-	}
-	msleep(33);
-	retval = read_dst(dst, &reply, 1);
-	dst_i2c_disable(dst);
-	if (retval < 0) {
-		dprintk("%s: read verify  not successful\n", __FUNCTION__);
-		return retval;
-	}
-	if (reply != 0xff) {
-		dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
-		return 0;
-	}
-	if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
-		return 0;
-	if (!dst_wait_dst_ready(dst))
-		return 0;
-	// dst_i2c_enable(i2c); Per dimitri
-	retval = read_dst(dst, dst->rxbuffer, 8);
-	dst_i2c_disable(dst);
-	if (retval < 0) {
-		dprintk("%s: read not successful\n", __FUNCTION__);
-		return 0;
-	}
-	if (dst->rxbuffer[7] != dst_check_sum(dst->rxbuffer, 7)) {
-		dprintk("%s: checksum failure\n", __FUNCTION__);
-		return 0;
-	}
-	return 0;
-}
-
-static int dst_get_signal(struct dst_data *dst)
-{
-	int retval;
-	u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
-
-	if ((dst->diseq_flags & ATTEMPT_TUNE) == 0) {
-		dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
-		return 0;
-	}
-	if (0 == (dst->diseq_flags & HAS_LOCK)) {
-		dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
-		return 0;
-	}
-	if (time_after_eq(jiffies, dst->cur_jiff + (HZ / 5))) {
-		retval = dst_command(dst, get_signal, 8);
-		if (retval < 0)
-			return retval;
-		if (dst->dst_type == DST_TYPE_IS_SAT) {
-			dst->decode_lock = ((dst->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
-			dst->decode_strength = dst->rxbuffer[5] << 8;
-			dst->decode_snr = dst->rxbuffer[2] << 8 | dst->rxbuffer[3];
-		} else if ((dst->dst_type == DST_TYPE_IS_TERR) || (dst->dst_type == DST_TYPE_IS_CABLE)) {
-			dst->decode_lock = (dst->rxbuffer[1]) ? 1 : 0;
-			dst->decode_strength = dst->rxbuffer[4] << 8;
-			dst->decode_snr = dst->rxbuffer[3] << 8;
-		}
-		dst->cur_jiff = jiffies;
-	}
-	return 0;
-}
-
-/*
- * line22k0    0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
- * line22k1    0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
- * line22k2    0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
- * tone        0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
- * data        0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
- * power_off   0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
- * power_on    0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
- * Diseqc 1    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
- * Diseqc 2    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 
- * Diseqc 3    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 
- * Diseqc 4    0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 
- */
-
-static int dst_set_diseqc(struct dst_data *dst, u8 * cmd, u8 len)
-{
-	u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
-
-	if (dst->dst_type == DST_TYPE_IS_TERR)
-		return 0;
-
-	if (len == 0 || len > 4)
-		return -EINVAL;
-	memcpy(&paket[3], cmd, len);
-	paket[7] = dst_check_sum(&paket[0], 7);
-	dst_command(dst, paket, 8);
-	return 0;
-}
-
-static int dst_tone_power_cmd(struct dst_data *dst)
-{
-	u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
-
-	if (dst->dst_type == DST_TYPE_IS_TERR)
-		return 0;
-
-	if (dst->voltage == SEC_VOLTAGE_OFF)
-		paket[4] = 0;
-	else
-		paket[4] = 1;
-	if (dst->tone == SEC_TONE_ON)
-		paket[2] = dst->k22;
-	else
-		paket[2] = 0;
-	paket[7] = dst_check_sum(&paket[0], 7);
-	dst_command(dst, paket, 8);
-	return 0;
-}
-
-static int dst_set_voltage(struct dst_data *dst, fe_sec_voltage_t voltage)
-{
-	u8 *val;
-	int need_cmd;
-
-	dst->voltage = voltage;
-
-	if (dst->dst_type == DST_TYPE_IS_TERR)
-		return 0;
-
-	need_cmd = 0;
-	val = &dst->tx_tuna[0];
-	val[8] &= ~0x40;
-	switch (voltage) {
-	case SEC_VOLTAGE_13:
-		if ((dst->diseq_flags & HAS_POWER) == 0)
-			need_cmd = 1;
-		dst->diseq_flags |= HAS_POWER;
-		break;
-	case SEC_VOLTAGE_18:
-		if ((dst->diseq_flags & HAS_POWER) == 0)
-			need_cmd = 1;
-		dst->diseq_flags |= HAS_POWER;
-		val[8] |= 0x40;
-		break;
-	case SEC_VOLTAGE_OFF:
-		need_cmd = 1;
-		dst->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
-		break;
-	default:
-		return -EINVAL;
-	}
-	if (need_cmd) {
-		dst_tone_power_cmd(dst);
-	}
-	return 0;
-}
-
-
-static int dst_set_tone(struct dst_data *dst, fe_sec_tone_mode_t tone)
-{
-	u8 *val;
-
-	dst->tone = tone;
-
-	if (dst->dst_type == DST_TYPE_IS_TERR)
-		return 0;
-
-	val = &dst->tx_tuna[0];
-
-	val[8] &= ~0x1;
-
-	switch (tone) {
-	case SEC_TONE_OFF:
-		break;
-	case SEC_TONE_ON:
-		val[8] |= 1;
-		break;
-	default:
-		return -EINVAL;
-	}
-	dst_tone_power_cmd(dst);
-	return 0;
-}
-
-static int dst_get_tuna(struct dst_data *dst)
-{
-	int retval;
-	if ((dst->diseq_flags & ATTEMPT_TUNE) == 0)
-		return 0;
-	dst->diseq_flags &= ~(HAS_LOCK);
-	if (!dst_wait_dst_ready(dst))
-		return 0;
-	if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
-		/* how to get variable length reply ???? */
-		retval = read_dst(dst, dst->rx_tuna, 10);
-	} else {
-		retval = read_dst(dst, &dst->rx_tuna[2], 8);
-	}
-	if (retval < 0) {
-		dprintk("%s: read not successful\n", __FUNCTION__);
-		return 0;
-	}
-	if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
-		if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[0], 9)) {
-			dprintk("%s: checksum failure?\n", __FUNCTION__);
-			return 0;
-		}
-	} else {
-		if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[2], 7)) {
-			dprintk("%s: checksum failure?\n", __FUNCTION__);
-			return 0;
-		}
-	}
-	if (dst->rx_tuna[2] == 0 && dst->rx_tuna[3] == 0)
-		return 0;
-	dst->decode_freq = ((dst->rx_tuna[2] & 0x7f) << 8) + dst->rx_tuna[3];
-
-	dst->decode_lock = 1;
-	/*
-	   dst->decode_n1 = (dst->rx_tuna[4] << 8) +
-	   (dst->rx_tuna[5]);
-
-	   dst->decode_n2 = (dst->rx_tuna[8] << 8) +
-	   (dst->rx_tuna[7]);
-	 */
-	dst->diseq_flags |= HAS_LOCK;
-	/* dst->cur_jiff = jiffies; */
-	return 1;
-}
-
-static int dst_write_tuna(struct dst_data *dst)
-{
-	int retval;
-	u8 reply;
-
-	dprintk("%s: type_flags 0x%x \n", __FUNCTION__, dst->type_flags);
-	dst->decode_freq = 0;
-	dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
-	if (dst->dst_type == DST_TYPE_IS_SAT) {
-		if (!(dst->diseq_flags & HAS_POWER))
-			dst_set_voltage(dst, SEC_VOLTAGE_13);
-	}
-	dst->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-	dst_i2c_enable(dst);
-	if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
-		dst_reset8820(dst);
-		dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[0], 9);
-		retval = write_dst(dst, &dst->tx_tuna[0], 10);
-	} else {
-		dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[2], 7);
-		retval = write_dst(dst, &dst->tx_tuna[2], 8);
-	}
-	if (retval < 0) {
-		dst_i2c_disable(dst);
-		dprintk("%s: write not successful\n", __FUNCTION__);
-		return retval;
-	}
-	msleep(3);
-	retval = read_dst(dst, &reply, 1);
-	dst_i2c_disable(dst);
-	if (retval < 0) {
-		dprintk("%s: read verify  not successful\n", __FUNCTION__);
-		return retval;
-	}
-	if (reply != 0xff) {
-		dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
-		return 0;
-	}
-	dst->diseq_flags |= ATTEMPT_TUNE;
-	return dst_get_tuna(dst);
-}
-
-static void dst_init(struct dst_data *dst)
-{
-	static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
-	static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
-	static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
-	static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
-	static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
-	static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
-	dst->inversion = INVERSION_ON;
-	dst->voltage = SEC_VOLTAGE_13;
-	dst->tone = SEC_TONE_OFF;
-	dst->symbol_rate = 29473000;
-	dst->fec = FEC_AUTO;
-	dst->diseq_flags = 0;
-	dst->k22 = 0x02;
-	dst->bandwidth = BANDWIDTH_7_MHZ;
-	dst->cur_jiff = jiffies;
-	if (dst->dst_type == DST_TYPE_IS_SAT) {
-		dst->frequency = 950000;
-		memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna));
-	} else if (dst->dst_type == DST_TYPE_IS_TERR) {
-		dst->frequency = 137000000;
-		memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna));
-	} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
-		dst->frequency = 51000000;
-		memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna));
-	}
-}
-
-struct lkup {
-	unsigned int cmd;
-	char *desc;
-} looker[] = {
-	{
-	FE_GET_INFO, "FE_GET_INFO:"}, {
-	FE_READ_STATUS, "FE_READ_STATUS:"}, {
-	FE_READ_BER, "FE_READ_BER:"}, {
-	FE_READ_SIGNAL_STRENGTH, "FE_READ_SIGNAL_STRENGTH:"}, {
-	FE_READ_SNR, "FE_READ_SNR:"}, {
-	FE_READ_UNCORRECTED_BLOCKS, "FE_READ_UNCORRECTED_BLOCKS:"}, {
-	FE_SET_FRONTEND, "FE_SET_FRONTEND:"}, {
-	FE_GET_FRONTEND, "FE_GET_FRONTEND:"}, {
-	FE_SLEEP, "FE_SLEEP:"}, {
-	FE_INIT, "FE_INIT:"}, {
-	FE_SET_TONE, "FE_SET_TONE:"}, {
-FE_SET_VOLTAGE, "FE_SET_VOLTAGE:"},};
-
-static int dst_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
-	struct dst_data *dst = fe->data;
-	int retval;
-	/*
-	   char  *cc;
-
-	   cc = "FE_UNSUPP:";
-	   for(retval = 0; retval < sizeof(looker) / sizeof(looker[0]); retval++) {
-	   if (looker[retval].cmd == cmd) {
-	   cc = looker[retval].desc;
-	   break;
-	   }
-	   }
-	   dprintk("%s cmd %s (0x%x)\n",__FUNCTION__, cc, cmd);
-	 */
-	// printk("%s: dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, dst, dst->bt, dst->i2c);
-	/* should be set by attach, but just in case */
-
-	switch (cmd) {
-	case FE_GET_INFO:
-		{
-			struct dvb_frontend_info *info;
-			info = &dst_info_sat;
-			if (dst->dst_type == DST_TYPE_IS_TERR)
-				info = &dst_info_terr;
-			else if (dst->dst_type == DST_TYPE_IS_CABLE)
-				info = &dst_info_cable;
-			memcpy(arg, info, sizeof(struct dvb_frontend_info));
-			break;
-		}
-	case FE_READ_STATUS:
-		{
-			fe_status_t *status = arg;
-
-			*status = 0;
-			if (dst->diseq_flags & HAS_LOCK) {
-				dst_get_signal(dst);
-				if (dst->decode_lock)
-					*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
-			}
-			break;
-		}
-
-	case FE_READ_BER:
-		{
-			/* guess */
-			// *(u32*) arg = dst->decode_n1;
-			*(u32 *) arg = 0;
-			return -EOPNOTSUPP;
-		}
-
-	case FE_READ_SIGNAL_STRENGTH:
-		{
-			dst_get_signal(dst);
-			*((u16 *) arg) = dst->decode_strength;
-			break;
-		}
-
-	case FE_READ_SNR:
-		{
-			dst_get_signal(dst);
-			*((u16 *) arg) = dst->decode_snr;
-			break;
-		}
-
-	case FE_READ_UNCORRECTED_BLOCKS:
-		{
-			*((u32 *) arg) = 0;	/* the stv0299 can't measure BER and */
-			return -EOPNOTSUPP;	/* errors at the same time.... */
-		}
-
-	case FE_SET_FRONTEND:
-		{
-			struct dvb_frontend_parameters *p = arg;
-
-			dst_set_freq(dst, p->frequency);
-			dst_set_inversion(dst, p->inversion);
-			if (dst->dst_type == DST_TYPE_IS_SAT) {
-				dst_set_fec(dst, p->u.qpsk.fec_inner);
-				dst_set_symbolrate(dst, p->u.qpsk.symbol_rate);
-			} else if (dst->dst_type == DST_TYPE_IS_TERR) {
-				dst_set_bandwidth(dst, p->u.ofdm.bandwidth);
-			} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
-				dst_set_fec(dst, p->u.qam.fec_inner);
-				dst_set_symbolrate(dst, p->u.qam.symbol_rate);
-			}
-			dst_write_tuna(dst);
-
-			break;
-		}
-
-	case FE_GET_FRONTEND:
-		{
-			struct dvb_frontend_parameters *p = arg;
-
-
-			p->frequency = dst->decode_freq;
-			p->inversion = dst->inversion;
-			if (dst->dst_type == DST_TYPE_IS_SAT) {
-				p->u.qpsk.symbol_rate = dst->symbol_rate;
-				p->u.qpsk.fec_inner = dst_get_fec(dst);
-			} else if (dst->dst_type == DST_TYPE_IS_TERR) {
-				p->u.ofdm.bandwidth = dst->bandwidth;
-			} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
-				p->u.qam.symbol_rate = dst->symbol_rate;
-				p->u.qam.fec_inner = dst_get_fec(dst);
-				p->u.qam.modulation = QAM_AUTO;
-			}
-			break;
-		}
-
-	case FE_SLEEP:
-		return 0;
-
-	case FE_INIT:
-		dst_init(dst);
-		break;
-
-	case FE_DISEQC_SEND_MASTER_CMD:
-		{
-			struct dvb_diseqc_master_cmd *cmd = (struct dvb_diseqc_master_cmd *) arg;
-			retval = dst_set_diseqc(dst, cmd->msg, cmd->msg_len);
-			if (retval < 0)
-				return retval;
-			break;
-		}
-	case FE_SET_TONE:
-		retval = dst_set_tone(dst, (fe_sec_tone_mode_t) arg);
-		if (retval < 0)
-			return retval;
-		break;
-	case FE_SET_VOLTAGE:
-		retval = dst_set_voltage(dst, (fe_sec_voltage_t) arg);
-		if (retval < 0)
-			return retval;
-		break;
-	default:
-		return -EOPNOTSUPP;
-	};
-
-	return 0;
-}
-
-static ssize_t attr_read_type(struct device *dev, char *buf)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
-	return sprintf(buf, "0x%02x\n", dst->dst_type);
-}
-
-static ssize_t attr_write_type(struct device *dev, const char *buf, size_t count)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
-	unsigned long type;
-	type = simple_strtoul(buf, NULL, 0);
-	dst->dst_type = type & 0xff;
-	return strlen(buf) + 1;
-}
-
-/* dst_type, "Type of DST card, 0 Satellite, 1 terrestial, 2 Cable, default driver determined"); */
-static struct device_attribute dev_attr_client_type = {
-	.attr = {.name = "type",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
-	.show = &attr_read_type,
-	.store = &attr_write_type,
-};
-
-static ssize_t attr_read_flags(struct device *dev, char *buf)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
-	return sprintf(buf, "0x%02x\n", dst->type_flags);
-}
-
-static ssize_t attr_write_flags(struct device *dev, const char *buf, size_t count)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client);
-	unsigned long flags;
-	flags = simple_strtoul(buf, NULL, 0);
-	dst->type_flags = flags & 0xffffffff;
-	return strlen(buf) + 1;
-}
-
-/* dst_type_flags, "Type flags of DST card, bitfield 1=10 byte tuner, 2=TS is 204, 4=symdiv"); */
-static struct device_attribute dev_attr_client_flags = {
-	.attr = {.name = "flags",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
-	.show = &attr_read_flags,
-	.store = &attr_write_flags,
-};
-
-static struct i2c_client client_template;
-
-static int attach_adapter(struct i2c_adapter *adapter)
-{
-	struct i2c_client *client;
-	struct dst_data *dst;
-	struct bt878 *bt;
-	struct dvb_frontend_info *info;
-	int ret;
-
-	bt = bt878_find_by_i2c_adap(adapter);
-	if (!bt)
-		return -ENODEV;
-
-	dst = kmalloc(sizeof(struct dst_data), GFP_KERNEL);
-	if (dst == NULL) {
-		printk(KERN_INFO "%s: Out of memory.\n", __FUNCTION__);
-		return -ENOMEM;
-	}
-
-	memset(dst, 0, sizeof(*dst));
-	dst->bt = bt;
-	dst->i2c = adapter;
-	if (dst_check_ci(dst) < 0) {
-		kfree(dst);
-		return -ENODEV;
-	}
-	dst_init(dst);
-
-	dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, (u32) dst, (u32) (dst->bt), (u32) (dst->i2c));
-
-	switch (dst->dst_type) {
-	case DST_TYPE_IS_TERR:
-		info = &dst_info_terr;
-		break;
-	case DST_TYPE_IS_CABLE:
-		info = &dst_info_cable;
-		break;
-	case DST_TYPE_IS_SAT:
-		info = &dst_info_sat;
-		break;
-	default:
-		printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
-		kfree(dst);
-		return -ENODEV;
-	}
-
-	if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
-		kfree(dst);
-		return -ENOMEM;
-	}
-
-	memcpy(client, &client_template, sizeof(struct i2c_client));
-	client->adapter = adapter;
-	client->addr = DST_I2C_ADDR;
-
-	i2c_set_clientdata(client, (void *) dst);
-
-	ret = i2c_attach_client(client);
-	if (ret) {
-		kfree(client);
-		kfree(dst);
-		return -EFAULT;
-	}
-
-	BUG_ON(!dst->dvb);
-
-	device_create_file(&client->dev, &dev_attr_client_type);
-	device_create_file(&client->dev, &dev_attr_client_flags);
-
-	ret = dvb_register_frontend(dst_ioctl, dst->dvb, dst, info, THIS_MODULE);
-	if (ret) {
-		i2c_detach_client(client);
-		kfree(client);
-		kfree(dst);
-		return -EFAULT;
-	}
-
-	return 0;
-}
-
-static int detach_client(struct i2c_client *client)
-{
-	struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
-
-	dvb_unregister_frontend(dst_ioctl, state->dvb);
-
-	device_remove_file(&client->dev, &dev_attr_client_type);
-	device_remove_file(&client->dev, &dev_attr_client_flags);
-
-	i2c_detach_client(client);
-	BUG_ON(state->dvb);
-
-	kfree(client);
-	kfree(state);
-
-	return 0;
-}
-
-static int command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-	struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
-
-	switch (cmd) {
-	case FE_REGISTER:
-		state->dvb = (struct dvb_adapter *) arg;
-		break;
-	case FE_UNREGISTER:
-		state->dvb = NULL;
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-	return 0;
-}
-
-static struct i2c_driver driver = {
-	.owner = THIS_MODULE,
-	.name = "dst",
-	.id = I2C_DRIVERID_DVBFE_DST,
-	.flags = I2C_DF_NOTIFY,
-	.attach_adapter = attach_adapter,
-	.detach_client = detach_client,
-	.command = command,
-};
-
-static struct i2c_client client_template = {
-	I2C_DEVNAME("dst"),
-	.flags = I2C_CLIENT_ALLOW_USE,
-	.driver = &driver,
-};
-
-static int __init init_dst(void)
-{
-	return i2c_add_driver(&driver);
-}
-
-static void __exit exit_dst(void)
-{
-	if (i2c_del_driver(&driver))
-		printk("dst: driver deregistration failed\n");
-}
-
-module_init(init_dst);
-module_exit(exit_dst);
-
-MODULE_DESCRIPTION("DST DVB-S Frontend");
-MODULE_AUTHOR("Jamie Honan");
-MODULE_LICENSE("GPL");
diff -puN drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
--- 25/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c~dvb-follow-frontend-changes-in-drivers	Thu Nov 18 15:18:02 2004
+++ 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c	Thu Nov 18 15:18:02 2004
@@ -24,6 +24,8 @@
 #include "dmxdev.h"
 #include "dvb_demux.h"
 #include "dvb_net.h"
+#include "cx22700.h"
+#include "tda1004x.h"
 
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/dmx.h>
@@ -132,6 +134,8 @@ struct ttusb {
 #if 0
 	devfs_handle_t stc_devfs_handle;
 #endif
+
+	struct dvb_frontend* fe;
 };
 
 /* ugly workaround ... don't know why it's neccessary to read */
@@ -461,9 +465,10 @@ static int ttusb_init_controller(struct 
 }
 
 #ifdef TTUSB_DISEQC
-static int ttusb_send_diseqc(struct ttusb *ttusb,
+static int ttusb_send_diseqc(struct dvb_frontend* fe,
 		      const struct dvb_diseqc_master_cmd *cmd)
 {
+	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
 	u8 b[12] = { 0xaa, ++ttusb->c, 0x18 };
 
 	int err;
@@ -484,6 +489,7 @@ static int ttusb_send_diseqc(struct ttus
 }
 #endif
 
+#if 0
 static int ttusb_update_lnb(struct ttusb *ttusb)
 {
 	u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
@@ -501,41 +507,25 @@ static int ttusb_update_lnb(struct ttusb
 	return err;
 }
 
-static int ttusb_set_voltage(struct ttusb *ttusb, fe_sec_voltage_t voltage)
+static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
 {
+	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+
 	ttusb->voltage = voltage;
 	return ttusb_update_lnb(ttusb);
 }
 
 #ifdef TTUSB_TONE
-static int ttusb_set_tone(struct ttusb *ttusb, fe_sec_tone_mode_t tone)
+static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
+	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+
 	ttusb->tone = tone;
 	return ttusb_update_lnb(ttusb);
 }
 #endif
-
-static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
-	struct ttusb *ttusb = fe->before_after_data;
-
-	switch (cmd) {
-	case FE_SET_VOLTAGE:
-		return ttusb_set_voltage(ttusb, (fe_sec_voltage_t) arg);
-#ifdef TTUSB_TONE
-	case FE_SET_TONE:
-		return ttusb_set_tone(ttusb, (fe_sec_tone_mode_t) arg);
-#endif
-#ifdef TTUSB_DISEQC
-	case FE_DISEQC_SEND_MASTER_CMD:
-		return ttusb_send_diseqc(ttusb,
-					 (struct dvb_diseqc_master_cmd *)
-					 arg);
 #endif
-	default:
-		return -EOPNOTSUPP;
-	};
-}
+
 
 #if 0
 static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq)
@@ -560,7 +550,7 @@ static void ttusb_handle_sec_data(struct
 				  const u8 * data, int len);
 #endif
 
-int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid;
+static int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid;
 
 static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
 			   int len)
@@ -1071,38 +1061,183 @@ static struct file_operations stc_fops =
 };
 #endif
 
-u32 functionality(struct i2c_adapter *adapter)
+static u32 functionality(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C;
 }
 
-static struct i2c_algorithm ttusb_dec_algo = {
-	.name		= "ttusb dec i2c algorithm",
-	.id		= I2C_ALGO_BIT,
-	.master_xfer	= master_xfer,
-	.functionality	= functionality,
-};
 
-static int client_register(struct i2c_client *client)
+
+static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
-	struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
+	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+	u8 data[4];
+	struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) };
+	u32 div;
+
+	div = (params->frequency + 36166667) / 166667;
 
-	if (client->driver->command)
-		return client->driver->command(client, FE_REGISTER, ttusb->adapter);
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = ((div >> 10) & 0x60) | 0x85;
+	data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
 
+	if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
-static int client_unregister(struct i2c_client *client)
+struct cx22700_config alps_tdmb7_config = {
+	.demod_address = 0x43,
+	.pll_set = alps_tdmb7_pll_set,
+};
+
+
+
+
+
+static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
 {
-	struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
+	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+	static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+	static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+	struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
+
+	// setup PLL configuration
+	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+	msleep(1);
+
+	// disable the mc44BC374c (do not check for errors)
+	tuner_msg.addr = 0x65;
+	tuner_msg.buf = disable_mc44BC374c;
+	tuner_msg.len = sizeof(disable_mc44BC374c);
+	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+		i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
+	}
 
-	if (client->driver->command)
-		return client->driver->command(client, FE_UNREGISTER, ttusb->adapter);
+	return 0;
+}
+
+static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+	u8 tuner_buf[4];
+	struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+	int tuner_frequency = 0;
+	u8 band, cp, filter;
+
+	// determine charge pump
+	tuner_frequency = params->frequency + 36130000;
+	if (tuner_frequency < 87000000) return -EINVAL;
+	else if (tuner_frequency < 130000000) cp = 3;
+	else if (tuner_frequency < 160000000) cp = 5;
+	else if (tuner_frequency < 200000000) cp = 6;
+	else if (tuner_frequency < 290000000) cp = 3;
+	else if (tuner_frequency < 420000000) cp = 5;
+	else if (tuner_frequency < 480000000) cp = 6;
+	else if (tuner_frequency < 620000000) cp = 3;
+	else if (tuner_frequency < 830000000) cp = 5;
+	else if (tuner_frequency < 895000000) cp = 7;
+	else return -EINVAL;
+
+	// determine band
+	if (params->frequency < 49000000) return -EINVAL;
+	else if (params->frequency < 159000000) band = 1;
+	else if (params->frequency < 444000000) band = 2;
+	else if (params->frequency < 861000000) band = 4;
+	else return -EINVAL;
+
+	// setup PLL filter
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		tda1004x_write_byte(fe, 0x0C, 0);
+		filter = 0;
+		break;
+
+	case BANDWIDTH_7_MHZ:
+		tda1004x_write_byte(fe, 0x0C, 0);
+		filter = 0;
+		break;
+
+	case BANDWIDTH_8_MHZ:
+		tda1004x_write_byte(fe, 0x0C, 0xFF);
+		filter = 1;
+		break;
 
+	default:
+		return -EINVAL;
+	}
+
+	// calculate divisor
+	// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+	tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+
+	// setup tuner buffer
+	tuner_buf[0] = tuner_frequency >> 8;
+	tuner_buf[1] = tuner_frequency & 0xff;
+	tuner_buf[2] = 0xca;
+	tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+	if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+
+	msleep(1);
 	return 0;
 }
 
+static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
+
+	return request_firmware(fw, name, &ttusb->dev->dev);
+}
+
+struct tda1004x_config philips_tdm1316l_config = {
+
+	.demod_address = 0x8,
+	.invert = 1,
+	.pll_init = philips_tdm1316l_pll_init,
+	.pll_set = philips_tdm1316l_pll_set,
+	.request_firmware = philips_tdm1316l_request_firmware,
+};
+
+
+
+static void frontend_init(struct ttusb* ttusb)
+{
+	switch(ttusb->dev->descriptor.idProduct) {
+	case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
+		// try the ALPS TDMB7 first
+		ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
+		if (ttusb->fe != NULL) break;
+
+		// Philips td1316
+		ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
+		if (ttusb->fe != NULL) break;
+		break;
+	}
+
+	if (ttusb->fe == NULL) {
+		printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n",
+		       ttusb->dev->descriptor.idVendor,
+		       ttusb->dev->descriptor.idProduct);
+	} else {
+		if (dvb_register_frontend(ttusb->adapter, ttusb->fe)) {
+			printk("dvb-ttusb-budget: Frontend registration failed!\n");
+			if (ttusb->fe->ops->release)
+				ttusb->fe->ops->release(ttusb->fe);
+			ttusb->fe = NULL;
+		}
+	}
+}
+
+
+
+static struct i2c_algorithm ttusb_dec_algo = {
+	.name		= "ttusb dec i2c algorithm",
+	.id		= I2C_ALGO_BIT,
+	.master_xfer	= master_xfer,
+	.functionality	= functionality,
+};
+
 static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *udev;
@@ -1140,6 +1275,7 @@ static int ttusb_probe(struct usb_interf
 	up(&ttusb->sem);
 
 	dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
+	ttusb->adapter->priv = ttusb;
 
 	/* i2c */
 	memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
@@ -1155,8 +1291,6 @@ static int ttusb_probe(struct usb_interf
 	ttusb->i2c_adap.algo              = &ttusb_dec_algo;
 	ttusb->i2c_adap.algo_data         = NULL;
 	ttusb->i2c_adap.id                = I2C_ALGO_BIT;
-	ttusb->i2c_adap.client_register   = client_register;
-	ttusb->i2c_adap.client_unregister = client_unregister;
 
 	result = i2c_add_adapter(&ttusb->i2c_adap);
 	if (result) {
@@ -1164,9 +1298,6 @@ static int ttusb_probe(struct usb_interf
 		return result;
 	}
 
-	dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL,
-				ttusb);
-
 	memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
 
 	ttusb->dvb_demux.dmx.capabilities =
@@ -1218,9 +1349,10 @@ static int ttusb_probe(struct usb_interf
 			   S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
 			   | S_IROTH | S_IWOTH, &stc_fops, ttusb);
 #endif
-
 	usb_set_intfdata(intf, (void *) ttusb);
 
+	frontend_init(ttusb);
+
 	return 0;
 }
 
@@ -1238,7 +1370,7 @@ static void ttusb_disconnect(struct usb_
 	dvb_net_release(&ttusb->dvbnet);
 	dvb_dmxdev_release(&ttusb->dmxdev);
 	dvb_dmx_release(&ttusb->dvb_demux);
-
+	if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe);
 	i2c_del_adapter(&ttusb->i2c_adap);
 	dvb_unregister_adapter(ttusb->adapter);
 
@@ -1250,8 +1382,8 @@ static void ttusb_disconnect(struct usb_
 }
 
 static struct usb_device_id ttusb_table[] = {
-	{USB_DEVICE(0xb48, 0x1003)},
-	{USB_DEVICE(0xb48, 0x1004)},	/* to be confirmed ????  */
+/*	{USB_DEVICE(0xb48, 0x1003)},UNDEFINED HARDWARE - mail linuxtv.org list */
+/*	{USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/	/* to be confirmed ????  */
 	{USB_DEVICE(0xb48, 0x1005)},
 	{}
 };
diff -puN drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h
--- 25/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h~dvb-follow-frontend-changes-in-drivers	Thu Nov 18 15:18:02 2004
+++ 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h	Thu Nov 18 15:18:02 2004
@@ -1,7 +1,7 @@
 
 #include <asm/types.h>
 
-u8 dsp_bootcode [] = {
+static u8 dsp_bootcode [] = {
 	0x08, 0xaa, 0x00, 0x18, 0x00, 0x03, 0x08, 0x00, 
 	0x00, 0x10, 0x00, 0x00, 0x01, 0x80, 0x18, 0x5f, 
 	0x00, 0x00, 0x01, 0x80, 0x77, 0x18, 0x2a, 0xeb, 
diff -puN drivers/media/dvb/ttusb-dec/ttusb_dec.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/ttusb-dec/ttusb_dec.c
--- 25/drivers/media/dvb/ttusb-dec/ttusb_dec.c~dvb-follow-frontend-changes-in-drivers	Thu Nov 18 15:18:02 2004
+++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c	Thu Nov 18 15:18:02 2004
@@ -30,11 +30,7 @@
 #include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/firmware.h>
-#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
 #include <linux/crc32.h>
-#else
-#warning "CRC checking of firmware not available"
-#endif
 #include <linux/init.h>
 
 #include "dmxdev.h"
@@ -42,6 +38,7 @@
 #include "dvb_filter.h"
 #include "dvb_frontend.h"
 #include "dvb_net.h"
+#include "ttusbdecfe.h"
 
 static int debug;
 static int output_pva;
@@ -69,9 +66,6 @@ MODULE_PARM_DESC(output_pva, "Output PVA
 
 #define	MAX_PVA_LENGTH		6144
 
-#define LOF_HI			10600000
-#define LOF_LO			9750000
-
 enum ttusb_dec_model {
 	TTUSB_DEC2000T,
 	TTUSB_DEC2540T,
@@ -102,12 +96,9 @@ struct ttusb_dec {
 	struct dvb_demux		demux;
 	struct dmx_frontend		frontend;
 	struct dvb_net			dvb_net;
-	struct dvb_frontend_info	*frontend_info;
-	int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);
+	struct dvb_frontend*		fe;
 
 	u16			pid[DMX_PES_OTHER];
-	int			hi_band;
-	int			voltage;
 
 	/* USB bits */
 	struct usb_device	*udev;
@@ -166,32 +157,6 @@ struct filter_info {
 	struct list_head	filter_info_list;
 };
 
-static struct dvb_frontend_info dec2000t_frontend_info = {
-	.name			= "TechnoTrend/Hauppauge DEC2000-t Frontend",
-	.type			= FE_OFDM,
-	.frequency_min		= 51000000,
-	.frequency_max		= 858000000,
-	.frequency_stepsize	= 62500,
-	.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		FE_CAN_HIERARCHY_AUTO,
-};
-
-static struct dvb_frontend_info dec3000s_frontend_info = {
-	.name			= "TechnoTrend/Hauppauge DEC3000-s Frontend",
-	.type			= FE_QPSK,
-	.frequency_min		= 950000,
-	.frequency_max		= 2150000,
-	.frequency_stepsize	= 125,
-	.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-		FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
-		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
-		FE_CAN_HIERARCHY_AUTO,
-};
-
 static void ttusb_dec_set_model(struct ttusb_dec *dec,
 				enum ttusb_dec_model model);
 
@@ -1170,10 +1135,9 @@ static int ttusb_dec_boot_dsp(struct ttu
 	u16 firmware_csum = 0;
 	u16 firmware_csum_ns;
 	u32 firmware_size_nl;
-#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
 	u32 crc32_csum, crc32_check, tmp;
-#endif
 	const struct firmware *fw_entry = NULL;
+
 	dprintk("%s\n", __FUNCTION__);
 
 	if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
@@ -1194,7 +1158,6 @@ static int ttusb_dec_boot_dsp(struct ttu
 	/* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
 	   at offset 56 of file, so use it to check if the firmware file is
 	   valid. */
-#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
 	crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
 	memcpy(&tmp, &firmware[56], 4);
 	crc32_check = htonl(tmp);
@@ -1204,7 +1167,6 @@ static int ttusb_dec_boot_dsp(struct ttu
 			__FUNCTION__, crc32_csum, crc32_check);
 		return -1;
 	}
-#endif
 	memcpy(idstring, &firmware[36], 20);
 	idstring[20] = '\0';
 	printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring);
@@ -1404,6 +1366,7 @@ static void ttusb_dec_exit_dvb(struct tt
 	dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
 	dvb_dmxdev_release(&dec->dmxdev);
 	dvb_dmx_release(&dec->demux);
+	if (dec->fe) dvb_unregister_frontend(dec->fe);
 	dvb_unregister_adapter(dec->adapter);
 }
 
@@ -1435,264 +1398,6 @@ static void ttusb_dec_exit_tasklet(struc
 	}
 }
 
-static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd,
-				  void *arg)
-{
-	struct ttusb_dec *dec = fe->data;
-
-	dprintk("%s\n", __FUNCTION__);
-
-	switch (cmd) {
-
-	case FE_GET_INFO:
-		dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
-		memcpy(arg, dec->frontend_info,
-		       sizeof (struct dvb_frontend_info));
-		break;
-
-	case FE_READ_STATUS: {
-			fe_status_t *status = (fe_status_t *)arg;
-			dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
-			*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-				  FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
-			break;
-		}
-
-	case FE_READ_BER: {
-			u32 *ber = (u32 *)arg;
-			dprintk("%s: FE_READ_BER\n", __FUNCTION__);
-			*ber = 0;
-			return -ENOSYS;
-			break;
-		}
-
-	case FE_READ_SIGNAL_STRENGTH: {
-			dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
-			*(s32 *)arg = 0xFF;
-			return -ENOSYS;
-			break;
-		}
-
-	case FE_READ_SNR:
-		dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
-		*(s32 *)arg = 0;
-		return -ENOSYS;
-		break;
-
-	case FE_READ_UNCORRECTED_BLOCKS:
-		dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
-		*(u32 *)arg = 0;
-		return -ENOSYS;
-		break;
-
-	case FE_SET_FRONTEND: {
-			struct dvb_frontend_parameters *p =
-				(struct dvb_frontend_parameters *)arg;
-		u8 b[] = { 0x00, 0x00, 0x00, 0x03,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x01,
-			   0x00, 0x00, 0x00, 0xff,
-			   0x00, 0x00, 0x00, 0xff };
-			u32 freq;
-
-			dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
-
-			dprintk("            frequency->%d\n", p->frequency);
-			dprintk("            symbol_rate->%d\n",
-				p->u.qam.symbol_rate);
-			dprintk("            inversion->%d\n", p->inversion);
-
-			freq = htonl(p->frequency / 1000);
-			memcpy(&b[4], &freq, sizeof (u32));
-			ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
-
-			break;
-		}
-
-	case FE_GET_FRONTEND:
-		dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
-		break;
-
-	case FE_SLEEP:
-		dprintk("%s: FE_SLEEP\n", __FUNCTION__);
-		return -ENOSYS;
-		break;
-
-	case FE_INIT:
-		dprintk("%s: FE_INIT\n", __FUNCTION__);
-		break;
-
-	default:
-		dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
-		return -EINVAL;
-
-	}
-
-	return 0;
-}
-
-static int ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe,
-					  unsigned int cmd, void *arg)
-{
-	struct ttusb_dec *dec = fe->data;
-
-	dprintk("%s\n", __FUNCTION__);
-
-	switch (cmd) {
-
-	case FE_GET_INFO:
-		dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
-		memcpy(arg, dec->frontend_info,
-		       sizeof (struct dvb_frontend_info));
-		break;
-
-	case FE_READ_STATUS: {
-			fe_status_t *status = (fe_status_t *)arg;
-			dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
-			*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
-				  FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
-			break;
-		}
-
-	case FE_READ_BER: {
-			u32 *ber = (u32 *)arg;
-			dprintk("%s: FE_READ_BER\n", __FUNCTION__);
-			*ber = 0;
-			return -ENOSYS;
-			break;
-		}
-
-	case FE_READ_SIGNAL_STRENGTH: {
-			dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
-			*(s32 *)arg = 0xFF;
-			return -ENOSYS;
-			break;
-		}
-
-	case FE_READ_SNR:
-		dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
-		*(s32 *)arg = 0;
-		return -ENOSYS;
-		break;
-
-	case FE_READ_UNCORRECTED_BLOCKS:
-		dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
-		*(u32 *)arg = 0;
-		return -ENOSYS;
-		break;
-
-	case FE_SET_FRONTEND: {
-			struct dvb_frontend_parameters *p =
-				(struct dvb_frontend_parameters *)arg;
-		u8 b[] = { 0x00, 0x00, 0x00, 0x01,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x01,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x00 };
-			u32 freq;
-			u32 sym_rate;
-			u32 band;
-		u32 lnb_voltage;
-
-			dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
-
-			dprintk("            frequency->%d\n", p->frequency);
-			dprintk("            symbol_rate->%d\n",
-				p->u.qam.symbol_rate);
-			dprintk("            inversion->%d\n", p->inversion);
-
-		freq = htonl(p->frequency +
-		       (dec->hi_band ? LOF_HI : LOF_LO));
-			memcpy(&b[4], &freq, sizeof(u32));
-			sym_rate = htonl(p->u.qam.symbol_rate);
-			memcpy(&b[12], &sym_rate, sizeof(u32));
-			band = htonl(dec->hi_band ? LOF_HI : LOF_LO);
-			memcpy(&b[24], &band, sizeof(u32));
-		lnb_voltage = htonl(dec->voltage);
-		memcpy(&b[28], &lnb_voltage, sizeof(u32));
-
-			ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
-
-			break;
-		}
-
-	case FE_GET_FRONTEND:
-		dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
-		break;
-
-	case FE_SLEEP:
-		dprintk("%s: FE_SLEEP\n", __FUNCTION__);
-		return -ENOSYS;
-		break;
-
-	case FE_INIT:
-		dprintk("%s: FE_INIT\n", __FUNCTION__);
-		break;
-
-	case FE_DISEQC_SEND_MASTER_CMD: {
-		u8 b[] = { 0x00, 0xff, 0x00, 0x00,
-			   0x00, 0x00, 0x00, 0x00,
-			   0x00, 0x00 };
-		struct dvb_diseqc_master_cmd *cmd = arg;
-		memcpy(&b[4], cmd->msg, cmd->msg_len);
-		dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__);
-		ttusb_dec_send_command(dec, 0x72,
-				       sizeof(b) - (6 - cmd->msg_len), b,
-				       NULL, NULL);
-		break;
-	}
-
-	case FE_DISEQC_SEND_BURST:
-		dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__);
-		break;
-
-	case FE_SET_TONE: {
-			fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg;
-			dprintk("%s: FE_SET_TONE\n", __FUNCTION__);
-			dec->hi_band = (SEC_TONE_ON == tone);
-			break;
-		}
-
-	case FE_SET_VOLTAGE:
-		dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
-		switch ((fe_sec_voltage_t) arg) {
-		case SEC_VOLTAGE_13:
-			dec->voltage = 13;
-			break;
-		case SEC_VOLTAGE_18:
-			dec->voltage = 18;
-			break;
-		default:
-			return -EINVAL;
-			break;
-		}
-		break;
-
-	default:
-		dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
-		return -EINVAL;
-
-	}
-
-	return 0;
-}
-
-static void ttusb_dec_init_frontend(struct ttusb_dec *dec)
-{
-	int ret;
-	ret = dvb_register_frontend(dec->frontend_ioctl, dec->adapter, dec, dec->frontend_info, THIS_MODULE);
-}
-
-static void ttusb_dec_exit_frontend(struct ttusb_dec *dec)
-{
-	dvb_unregister_frontend(dec->frontend_ioctl, dec->adapter);
-}
-
 static void ttusb_dec_init_filters(struct ttusb_dec *dec)
 {
 	INIT_LIST_HEAD(&dec->filter_info_list);
@@ -1711,6 +1416,18 @@ static void ttusb_dec_exit_filters(struc
 	}
 }
 
+int fe_send_command(struct dvb_frontend* fe, const u8 command,
+		    int param_length, const u8 params[],
+		    int *result_length, u8 cmd_result[])
+{
+	struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv;
+	return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
+}
+
+struct ttusbdecfe_config fe_config = {
+	.send_command = fe_send_command
+};
+
 static int ttusb_dec_probe(struct usb_interface *intf,
 			   const struct usb_device_id *id)
 {
@@ -1752,7 +1469,32 @@ static int ttusb_dec_probe(struct usb_in
 		return 0;
 	}
 	ttusb_dec_init_dvb(dec);
-	ttusb_dec_init_frontend(dec);
+
+	dec->adapter->priv = dec;
+	switch (id->idProduct) {
+	case 0x1006:
+		dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
+		break;
+
+	case 0x1008:
+	case 0x1009:
+		dec->fe = ttusbdecfe_dvbt_attach(&fe_config);
+		break;
+	}
+
+	if (dec->fe == NULL) {
+		printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",
+		       dec->udev->descriptor.idVendor,
+		       dec->udev->descriptor.idProduct);
+	} else {
+		if (dvb_register_frontend(dec->adapter, dec->fe)) {
+			printk("budget-ci: Frontend registration failed!\n");
+			if (dec->fe->ops->release)
+				dec->fe->ops->release(dec->fe);
+			dec->fe = NULL;
+		}
+	}
+
 	ttusb_dec_init_v_pes(dec);
 	ttusb_dec_init_filters(dec);
 	ttusb_dec_init_tasklet(dec);
@@ -1776,7 +1518,6 @@ static void ttusb_dec_disconnect(struct 
 	ttusb_dec_exit_tasklet(dec);
 		ttusb_dec_exit_filters(dec);
 	ttusb_dec_exit_usb(dec);
-		ttusb_dec_exit_frontend(dec);
 	ttusb_dec_exit_dvb(dec);
 	}
 
@@ -1792,22 +1533,16 @@ static void ttusb_dec_set_model(struct t
 	case TTUSB_DEC2000T:
 		dec->model_name = "DEC2000-t";
 		dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
-		dec->frontend_info = &dec2000t_frontend_info;
-		dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
 		break;
 
 	case TTUSB_DEC2540T:
 		dec->model_name = "DEC2540-t";
 		dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
-		dec->frontend_info = &dec2000t_frontend_info;
-		dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
 		break;
 
 	case TTUSB_DEC3000S:
 		dec->model_name = "DEC3000-s";
 		dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
-		dec->frontend_info = &dec3000s_frontend_info;
-		dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl;
 		break;
 	}
 }
diff -puN /dev/null drivers/media/dvb/ttusb-dec/ttusbdecfe.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.c	Thu Nov 18 15:18:02 2004
@@ -0,0 +1,255 @@
+/*
+ * TTUSB DEC Frontend Driver
+ *
+ * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "dvb_frontend.h"
+#include "ttusbdecfe.h"
+
+
+#define LOF_HI			10600000
+#define LOF_LO			9750000
+
+struct ttusbdecfe_state {
+
+	struct dvb_frontend_ops ops;
+
+	/* configuration settings */
+	const struct ttusbdecfe_config* config;
+
+	struct dvb_frontend frontend;
+
+	u8 hi_band;
+	u8 voltage;
+};
+
+
+static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+		  FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+	u8 b[] = { 0x00, 0x00, 0x00, 0x03,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x01,
+		   0x00, 0x00, 0x00, 0xff,
+		   0x00, 0x00, 0x00, 0xff };
+
+	u32 freq = htonl(p->frequency / 1000);
+	memcpy(&b[4], &freq, sizeof (u32));
+	state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
+
+	return 0;
+}
+
+static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+	u8 b[] = { 0x00, 0x00, 0x00, 0x01,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x01,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00 };
+	u32 freq;
+	u32 sym_rate;
+	u32 band;
+	u32 lnb_voltage;
+
+	freq = htonl(p->frequency +
+	       (state->hi_band ? LOF_HI : LOF_LO));
+	memcpy(&b[4], &freq, sizeof(u32));
+	sym_rate = htonl(p->u.qam.symbol_rate);
+	memcpy(&b[12], &sym_rate, sizeof(u32));
+	band = htonl(state->hi_band ? LOF_HI : LOF_LO);
+	memcpy(&b[24], &band, sizeof(u32));
+	lnb_voltage = htonl(state->voltage);
+	memcpy(&b[28], &lnb_voltage, sizeof(u32));
+
+	state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
+
+	return 0;
+}
+
+static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
+{
+	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+	u8 b[] = { 0x00, 0xff, 0x00, 0x00,
+		   0x00, 0x00, 0x00, 0x00,
+		   0x00, 0x00 };
+
+	memcpy(&b[4], cmd->msg, cmd->msg_len);
+
+	state->config->send_command(fe, 0x72,
+				    sizeof(b) - (6 - cmd->msg_len), b,
+				    NULL, NULL);
+
+	return 0;
+}
+
+
+static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+	state->hi_band = (SEC_TONE_ON == tone);
+
+	return 0;
+}
+
+
+static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_13:
+		state->voltage = 13;
+		break;
+	case SEC_VOLTAGE_18:
+		state->voltage = 18;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ttusbdecfe_release(struct dvb_frontend* fe)
+{
+	struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbt_ops;
+
+struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config)
+{
+	struct ttusbdecfe_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	if (state) kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
+
+struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config)
+{
+	struct ttusbdecfe_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->voltage = 0;
+	state->hi_band = 0;
+	memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
+
+	/* create dvb_frontend */
+	state->frontend.ops = &state->ops;
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	if (state) kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
+
+	.info = {
+		.name			= "TechnoTrend/Hauppauge DEC2000-t Frontend",
+		.type			= FE_OFDM,
+		.frequency_min		= 51000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = ttusbdecfe_release,
+
+	.set_frontend = ttusbdecfe_dvbt_set_frontend,
+
+	.read_status = ttusbdecfe_read_status,
+};
+
+static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
+
+	.info = {
+		.name			= "TechnoTrend/Hauppauge DEC3000-s Frontend",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 125,
+		.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.release = ttusbdecfe_release,
+
+	.set_frontend = ttusbdecfe_dvbs_set_frontend,
+
+	.read_status = ttusbdecfe_read_status,
+
+	.diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd,
+	.set_voltage = ttusbdecfe_dvbs_set_voltage,
+	.set_tone = ttusbdecfe_dvbs_set_tone,
+};
+
+MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver");
+MODULE_AUTHOR("Alex Woods/Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ttusbdecfe_dvbt_attach);
+EXPORT_SYMBOL(ttusbdecfe_dvbs_attach);
diff -puN /dev/null drivers/media/dvb/ttusb-dec/ttusbdecfe.h
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.h	Thu Nov 18 15:18:02 2004
@@ -0,0 +1,38 @@
+/*
+ * TTUSB DEC Driver
+ *
+ * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef TTUSBDECFE_H
+#define TTUSBDECFE_H
+
+#include <linux/dvb/frontend.h>
+
+struct ttusbdecfe_config
+{
+	int (*send_command)(struct dvb_frontend* fe, const u8 command,
+			    int param_length, const u8 params[],
+			    int *result_length, u8 cmd_result[]);
+};
+
+extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config);
+
+extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config);
+
+#endif // TTUSBDECFE_H
_