
From: Michael Hunold <hunold@linuxtv.org>

- [DVB] dvb-ttpci, budget: updated to fix problems with some CAMs on KNC1
  cards

- [DVB] dvb-ttpci, budget: make needlessly global code static, whitespace
  and newline cleanups, thanks to Adrian Bunk <bunk@stusta.de>

- [DVB] dvb-ttpci, budget: follow frontend changes in driver

- [DVB] dvb-ttpci, budget: fix drivers to use new
  wait_for_debi_done(...,nobusywait) routine.

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

 25-akpm/drivers/media/dvb/ttpci/av7110.c       |  691 ++++++++++++++++++++----
 25-akpm/drivers/media/dvb/ttpci/av7110.h       |   18 
 25-akpm/drivers/media/dvb/ttpci/av7110_av.c    |    4 
 25-akpm/drivers/media/dvb/ttpci/av7110_ca.c    |    8 
 25-akpm/drivers/media/dvb/ttpci/av7110_hw.c    |   30 -
 25-akpm/drivers/media/dvb/ttpci/av7110_v4l.c   |   10 
 25-akpm/drivers/media/dvb/ttpci/budget-av.c    |  709 +++++++++++++++++++++++--
 25-akpm/drivers/media/dvb/ttpci/budget-ci.c    |  601 +++++++++++++++++----
 25-akpm/drivers/media/dvb/ttpci/budget-core.c  |  139 +++-
 25-akpm/drivers/media/dvb/ttpci/budget-patch.c |  248 +++++++-
 25-akpm/drivers/media/dvb/ttpci/budget.c       |  395 +++++++++++--
 25-akpm/drivers/media/dvb/ttpci/budget.h       |   23 
 12 files changed, 2457 insertions(+), 419 deletions(-)

diff -puN drivers/media/dvb/ttpci/av7110_av.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/av7110_av.c
--- 25/drivers/media/dvb/ttpci/av7110_av.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/av7110_av.c	Thu Nov 18 15:18:09 2004
@@ -674,7 +674,7 @@ void av7110_p2t_write(u8 const *buf, lon
 }
 
 
-int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length)
+static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length)
 {
 	int i;
 	int c = 0;
@@ -936,7 +936,7 @@ static ssize_t dvb_audio_write(struct fi
 	return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
 }
 
-u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
+static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
 
 #define MIN_IFRAME 400000
 
diff -puN drivers/media/dvb/ttpci/av7110.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/av7110.c
--- 25/drivers/media/dvb/ttpci/av7110.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/av7110.c	Thu Nov 18 15:18:09 2004
@@ -94,7 +94,16 @@ MODULE_PARM_DESC(volume, "initial volume
 
 static void restart_feeds(struct av7110 *av7110);
 
-int av7110_num = 0;
+static int av7110_num = 0;
+
+#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \
+{\
+	if (fe_func != NULL) { \
+		av7110_copy = fe_func; \
+	   	fe_func = av7110_func; \
+	} \
+}
+
 
 static void init_av7110_av(struct av7110 *av7110)
 {
@@ -259,15 +268,15 @@ void av7110_unregister_irc_handler(void 
         irc_handler = NULL;
 }
 
-void run_handlers(unsigned long ircom) 
+static void run_handlers(unsigned long ircom)
 {
         if (irc_handler != NULL)
                 (*irc_handler)((u32) ircom);
 }
 
-DECLARE_TASKLET(irtask,run_handlers,0);
+static DECLARE_TASKLET(irtask, run_handlers, 0);
 
-void IR_handle(struct av7110 *av7110, u32 ircom)
+static void IR_handle(struct av7110 *av7110, u32 ircom)
 {
 	dprintk(4, "ircommand = %08x\n", ircom);
         irtask.data = (unsigned long) ircom;
@@ -572,7 +581,7 @@ static void gpioirq (unsigned long data)
                 wake_up(&cibuf->queue);
                 iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
                 iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-		saa7146_wait_for_debi_done(av7110->dev);
+		saa7146_wait_for_debi_done(av7110->dev, 0);
                 saa7146_write(av7110->dev, IER, 
                               saa7146_read(av7110->dev, IER) | MASK_19 );
 		if (len < 5)
@@ -610,7 +619,7 @@ static void gpioirq (unsigned long data)
 		dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len);
                 iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
                 iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
-		saa7146_wait_for_debi_done(av7110->dev);
+		saa7146_wait_for_debi_done(av7110->dev, 0);
                 saa7146_write(av7110->dev, IER, 
                               saa7146_read(av7110->dev, IER) | MASK_19 );
 
@@ -637,7 +646,7 @@ static void gpioirq (unsigned long data)
                 memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
                 av7110->bmpp+=len;
                 av7110->bmplen-=len;
-		saa7146_wait_for_debi_done(av7110->dev);
+		saa7146_wait_for_debi_done(av7110->dev, 0);
                 saa7146_write(av7110->dev, IER, 
                               saa7146_read(av7110->dev, IER) | MASK_19 );
 		if (len < 5)
@@ -659,7 +668,7 @@ static void gpioirq (unsigned long data)
 
         case DATA_TS_RECORD:
         case DATA_PES_RECORD:
-		saa7146_wait_for_debi_done(av7110->dev);
+		saa7146_wait_for_debi_done(av7110->dev, 0);
                 saa7146_write(av7110->dev, IER, 
                               saa7146_read(av7110->dev, IER) | MASK_19);
                 irdebi(av7110, DEBISWAB, DPRAM_BASE+rxbuf, 0, len);
@@ -667,7 +676,7 @@ static void gpioirq (unsigned long data)
                 return;
 
         case DATA_DEBUG_MESSAGE:
-		saa7146_wait_for_debi_done(av7110->dev);
+		saa7146_wait_for_debi_done(av7110->dev, 0);
                 if (!len || len>0xff) {
                         iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
                         break;
@@ -1090,71 +1099,42 @@ static int dvb_get_stc(struct dmx_demux 
  * SEC device file operations
  ******************************************************************************/
 
-static int av7110_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
-	struct av7110 *av7110 = fe->before_after_data;
 
-	dprintk(4, "%p\n", av7110);
+static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
 
-	switch (cmd) {
-	case FE_SET_TONE:
-		switch ((fe_sec_tone_mode_t) arg) {
+	switch (tone) {
 		case SEC_TONE_ON:
 			Set22K(av7110, 1);
 			break;
 		case SEC_TONE_OFF:
 			Set22K(av7110, 0);
 			break;
+
 		default:
 			return -EINVAL;
-};
-		break;
-
-	case FE_DISEQC_SEND_MASTER_CMD:
-	{
-		struct dvb_diseqc_master_cmd *cmd = arg;
-		av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
-		break;
 	}
 
-	case FE_DISEQC_SEND_BURST:
-		av7110_diseqc_send(av7110, 0, NULL, (unsigned long) arg);
-		break;
-
-	default:
-		return -EOPNOTSUPP;
-};
-
 	return 0;
 }
 
-
-static void av7110_before_after_tune (fe_status_t s, void *data)
+static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
 {
-	struct av7110 *av7110 = data;
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
 
-	dprintk(4, "%p\n", av7110);
+	av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
 
-        av7110->fe_synced = (s & FE_HAS_LOCK) ? 1 : 0;
+	return 0;
+}
 
-        if (av7110->playing)
-                return;
+static int av7110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
 
-        if (down_interruptible(&av7110->pid_mutex))
-                return;
+	av7110_diseqc_send(av7110, 0, NULL, minicmd);
 
-	if (av7110->fe_synced) {
-                SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], 
-                        av7110->pids[DMX_PES_AUDIO], 
-                        av7110->pids[DMX_PES_TELETEXT], 0, 
-                        av7110->pids[DMX_PES_PCR]);
-		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
-	} else {
-		SetPIDs(av7110, 0, 0, 0, 0, 0);
-		av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0);
-	}
-
-        up(&av7110->pid_mutex);
+	return 0;
 }
 
 
@@ -1170,15 +1150,6 @@ static int av7110_register(struct av7110
 
         av7110->registered=1;
 
-	dvb_add_frontend_notifier (av7110->dvb_adapter,
-				   av7110_before_after_tune, av7110);
-
-	/**
-	 *   init DiSEqC stuff
-	 */
-	dvb_add_frontend_ioctls (av7110->dvb_adapter,
-				 av7110_diseqc_ioctl, NULL, av7110);
-
         dvbdemux->priv = (void *) av7110;
 
 	for (i=0; i<32; i++)
@@ -1252,12 +1223,7 @@ static void dvb_unregister(struct av7110
         dvb_dmxdev_release(&av7110->dmxdev);
         dvb_dmx_release(&av7110->demux);
 
-	dvb_remove_frontend_notifier (av7110->dvb_adapter,
-				      av7110_before_after_tune);
-
-	dvb_remove_frontend_ioctls (av7110->dvb_adapter,
-				    av7110_diseqc_ioctl, NULL);
-
+	if (av7110->fe != NULL) dvb_unregister_frontend(av7110->fe);
 	dvb_unregister_device(av7110->osd_dev);
 	av7110_av_unregister(av7110);
 	av7110_ca_unregister(av7110);
@@ -1280,6 +1246,7 @@ int i2c_writereg(struct av7110 *av7110, 
 	return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
 }
 
+#if 0
 u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
 {
 	u8 mm1[] = {0x00};
@@ -1296,6 +1263,7 @@ u8 i2c_readreg(struct av7110 *av7110, u8
 
 	return mm2[0];
 }
+#endif
 
 /****************************************************************************
  * INITIALIZATION
@@ -1408,28 +1376,532 @@ static int get_firmware(struct av7110* a
 #endif
 
 
-static int client_register(struct i2c_client *client)
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
-	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
-	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	u8 pwr = 0;
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	u32 div = (params->frequency + 479500) / 125;
+
+	if (params->frequency > 2000000) pwr = 3;
+	else if (params->frequency > 1800000) pwr = 2;
+	else if (params->frequency > 1600000) pwr = 1;
+	else if (params->frequency > 1200000) pwr = 0;
+	else if (params->frequency >= 1100000) pwr = 1;
+	else pwr = 2;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = ((div & 0x18000) >> 10) | 0x95;
+	buf[3] = (pwr << 6) | 0x30;
 
-	/* fixme: check for "type" (ie. frontend type) */
-	if (client->driver->command)
-		return client->driver->command(client, FE_REGISTER, av7110->dvb_adapter);
+        // NOTE: since we're using a prescaler of 2, we set the
+	// divisor frequency to 62.5kHz and divide by 125 above
+
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
 	return 0;
 }
 
-static int client_unregister(struct i2c_client *client)
+static struct ves1x93_config alps_bsrv2_config = {
+	.demod_address = 0x08,
+	.xin = 90100000UL,
+	.invert_pwm = 0,
+	.pll_set = alps_bsrv2_pll_set,
+};
+
+
+static u8 alps_bsru6_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   // AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x15, 0xc9,   // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,  // 1/2 threshold
+	0x2a, 0x14,  // 2/3 threshold
+	0x2b, 0x0f,  // 3/4 threshold
+	0x2c, 0x09,  // 5/6 threshold
+	0x2d, 0x05,  // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,  // test all FECs
+	0x32, 0x19,  // viterbi and synchro search
+	0x33, 0xfc,  // rs control
+	0x34, 0x93,  // error control
+	0x0f, 0x52,
+	0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
 {
-	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
-	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+	u8 aclk = 0;
+	u8 bclk = 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);
+
+	return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	int ret;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125; // round correctly
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	data[3] = 0xC4;
+
+	if (params->frequency > 1530000) data[3] = 0xc0;
+
+	ret = i2c_transfer (&av7110->i2c_adap, &msg, 1);
+	if (ret != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+	.pll_set = alps_bsru6_pll_set,
+};
+
+
+
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (params->frequency + 35937500 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85 | ((div >> 10) & 0x60);
+	data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+	.demod_address = 0x09,
+	.xin = 57840000UL,
+	.invert = 1,
+	.selagc = VES1820_SELAGC_SIGNAMPERR,
+	.pll_set = alps_tdbe2_pll_set,
+};
+
+
+
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = params->frequency / 125;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = 0x00;
+
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+	.demod_address = 0x68,
+	.pll_set = grundig_29504_451_pll_set,
+};
+
+
+
+static int philips_cd1516_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+        struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	u32 div;
+	u32 f = params->frequency;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (f + 36125000 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
+
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct ves1820_config philips_cd1516_config = {
+	.demod_address = 0x09,
+	.xin = 57840000UL,
+	.invert = 1,
+	.selagc = VES1820_SELAGC_SIGNAMPERR,
+	.pll_set = philips_cd1516_pll_set,
+};
+
+
+
+static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	u32 div, pwr;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (params->frequency + 36200000) / 166666;
+
+	if (params->frequency <= 782000000)
+		pwr = 1;
+	else
+		pwr = 2;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85;
+	data[3] = pwr << 6;
+
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	return request_firmware(fw, name, &av7110->dev->pci->dev);
+}
+
+static struct sp8870_config alps_tdlb7_config = {
+
+	.demod_address = 0x71,
+	.pll_set = alps_tdlb7_pll_set,
+	.request_firmware = alps_tdlb7_request_firmware,
+};
+
+
+
+static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) };
+	struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 };
+	int i;
+
+	// this calculation does not match the TDA6405TS datasheet!
+	div = (params->frequency + 36150000 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0xce; // this value does not match the TDA6405TS datasheet!
+
+	if (params->frequency < 45000000)
+		return -EINVAL;
+	else if (params->frequency < 137000000)
+		data[3] = 0x01;
+	else if (params->frequency < 403000000)
+		data[3] = 0x02;
+	else if (params->frequency < 860000000)
+		data[3] = 0x04;
+	else
+		return -EINVAL;
+
+	stv0297_enable_plli2c(fe);
+	if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) {
+		printk("nexusca: pll transfer failed!\n");
+		return -EIO;
+	}
+
+	// wait for PLL lock
+	for(i=0; i< 20; i++) {
+
+		stv0297_enable_plli2c(fe);
+		if (i2c_transfer (&av7110->i2c_adap, &readmsg, 1) == 1)
+			if (data[0] & 0x40) break;
+		msleep(10);
+	}
+
+	return 0;
+}
+
+static struct stv0297_config nexusca_stv0297_config = {
+
+	.demod_address = 0x1C,
+	.pll_set = nexusca_stv0297_pll_set,
+};
+
+
+static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
+{
+	msleep (50);
+
+	av7110->fe_synced = (status & FE_HAS_LOCK) ? 1 : 0;
+
+	if (av7110->playing)
+		return;
+
+	if (down_interruptible(&av7110->pid_mutex))
+		return;
+
+	if (av7110->fe_synced) {
+		SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+			av7110->pids[DMX_PES_AUDIO],
+			av7110->pids[DMX_PES_TELETEXT], 0,
+			av7110->pids[DMX_PES_PCR]);
+	                av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+	} else {
+			SetPIDs(av7110, 0, 0, 0, 0, 0);
+	                av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0);
+	}
+
+	av7110->fe_status = status;
+	up(&av7110->pid_mutex);
+}
+
+static int av7110_fe_init(struct dvb_frontend* fe)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	av7110_fe_lock_fix(av7110, 0);
+	return av7110->fe_init(fe);
+}
+
+static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+	int ret;
+
+	/* call the real implementation */
+	ret = av7110->fe_read_status(fe, status);
+	if (ret)
+		return ret;
+
+	if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) {
+		av7110_fe_lock_fix(av7110, *status);
+	}
 
-	/* fixme: check for "type" (ie. frontend type) */
-	if (client->driver->command)
-		return client->driver->command(client, FE_UNREGISTER, av7110->dvb_adapter);
 	return 0;
 }
 
+static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	av7110_fe_lock_fix(av7110, 0);
+	return av7110->fe_diseqc_reset_overload(fe);
+}
+
+static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	av7110_fe_lock_fix(av7110, 0);
+	return av7110->fe_diseqc_send_master_cmd(fe, cmd);
+}
+
+static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	av7110_fe_lock_fix(av7110, 0);
+	return av7110->fe_diseqc_send_burst(fe, minicmd);
+}
+
+static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	av7110_fe_lock_fix(av7110, 0);
+	return av7110->fe_set_tone(fe, tone);
+}
+
+static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	av7110_fe_lock_fix(av7110, 0);
+	return av7110->fe_set_voltage(fe, voltage);
+}
+
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
+{
+   	struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+	av7110_fe_lock_fix(av7110, 0);
+	return av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+}
+
+static u8 read_pwm(struct av7110* av7110)
+{
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+				 { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+        if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+static void frontend_init(struct av7110 *av7110)
+{
+	if (av7110->dev->pci->subsystem_vendor == 0x110a) {
+		switch(av7110->dev->pci->subsystem_device) {
+		case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
+			av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110));
+			if (av7110->fe)
+				break;
+			break;
+		}
+
+	} else if (av7110->dev->pci->subsystem_vendor == 0x13c2) {
+		switch(av7110->dev->pci->subsystem_device) {
+		case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+		case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X
+		case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
+
+			// try the ALPS BSRV2 first of all
+			av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops->set_tone = av7110_set_tone;
+				break;
+			}
+
+			// try the ALPS BSRU6 now
+			av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops->set_tone = av7110_set_tone;
+				break;
+			}
+
+			// Try the grundig 29504-451
+                        av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+			if (av7110->fe) {
+				av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+				av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+				av7110->fe->ops->set_tone = av7110_set_tone;
+				break;
+			}
+			break;
+
+		case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
+
+			// ALPS TDLB7
+                        av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+			if (av7110->fe)
+				break;
+			break;
+
+		case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
+
+                        av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+			if (av7110->fe)
+				break;
+			break;
+
+		case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
+
+			av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b);
+			if (av7110->fe) {
+				/* tuner on this needs a slower i2c bus speed */
+				av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
+				break;
+			}
+		}
+	}
+
+	if (av7110->fe == NULL) {
+		printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		       av7110->dev->pci->vendor,
+		       av7110->dev->pci->device,
+		       av7110->dev->pci->subsystem_vendor,
+		       av7110->dev->pci->subsystem_device);
+	} else {
+		FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
+		FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
+		FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+		FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+		FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+		FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+		FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+		FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+		if (dvb_register_frontend(av7110->dvb_adapter, av7110->fe)) {
+			printk("av7110: Frontend registration failed!\n");
+			if (av7110->fe->ops->release)
+				av7110->fe->ops->release(av7110->fe);
+			av7110->fe = NULL;
+		}
+	}
+}
+
 static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
 {
 	struct av7110 *av7110 = NULL;
@@ -1446,7 +1918,7 @@ static int av7110_attach(struct saa7146_
 	memset(av7110, 0, sizeof(struct av7110));
 	
 	av7110->card_name = (char*)pci_ext->ext_priv;
-	av7110->dev=(struct saa7146_dev *)dev;
+	av7110->dev = dev;
 	dev->ext_priv = av7110;
 
 	if ((ret = get_firmware(av7110))) {
@@ -1460,15 +1932,11 @@ static int av7110_attach(struct saa7146_
 	   get recognized before the main driver is fully loaded */
 	saa7146_write(dev, GPIO_CTRL, 0x500000);
 
-	av7110->i2c_adap = (struct i2c_adapter) {
-		.client_register = client_register,
-		.client_unregister = client_unregister,
 #ifdef I2C_ADAP_CLASS_TV_DIGITAL
-		.class = I2C_ADAP_CLASS_TV_DIGITAL,
+	av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
 #else
-		.class = I2C_CLASS_TV_DIGITAL,
+	av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
 #endif
-	};
 	strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
 
 	saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -1567,6 +2035,9 @@ static int av7110_attach(struct saa7146_
 	if (ret)
 		goto err3;
 
+	av7110->dvb_adapter->priv = av7110;
+	frontend_init(av7110);
+
 	printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
 	av7110->device_initialized = 1;
 	av7110_num++;
@@ -1663,33 +2134,29 @@ static struct saa7146_pci_extension_data
 	.ext_priv = x_name, \
 	.ext = &av7110_extension }
 
-MAKE_AV7110_INFO(fs_1_5, "Siemens cable card PCI rev1.5");
-MAKE_AV7110_INFO(fs_1_3, "Siemens/Technotrend/Hauppauge PCI rev1.3");
-MAKE_AV7110_INFO(tt_1_6, "Technotrend/Hauppauge PCI rev1.3 or 1.6");
-MAKE_AV7110_INFO(tt_2_1, "Technotrend/Hauppauge PCI rev2.1 or 2.2");
-MAKE_AV7110_INFO(tt_t,	 "Technotrend/Hauppauge PCI DVB-T");
-MAKE_AV7110_INFO(unkwn0, "Technotrend/Hauppauge PCI rev?(unknown0)?");
-MAKE_AV7110_INFO(unkwn1, "Technotrend/Hauppauge PCI rev?(unknown1)?");
-MAKE_AV7110_INFO(unkwn2, "Technotrend/Hauppauge PCI rev?(unknown2)?");
-MAKE_AV7110_INFO(nexus,  "Technotrend/Hauppauge Nexus PCI DVB-S");
-MAKE_AV7110_INFO(dvboc11,"Octal/Technotrend DVB-C for iTV");
+MAKE_AV7110_INFO(tts_1_X,    "Technotrend/Hauppauge WinTV DVB-S rev1.X");
+MAKE_AV7110_INFO(ttt_1_X,    "Technotrend/Hauppauge WinTV DVB-T rev1.X");
+MAKE_AV7110_INFO(ttc_1_X,    "Technotrend/Hauppauge WinTV Nexus-CA rev1.X");
+MAKE_AV7110_INFO(ttc_2_X,    "Technotrend/Hauppauge WinTV DVB-C rev2.X");
+MAKE_AV7110_INFO(tts_2_X,    "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
+MAKE_AV7110_INFO(tts_1_3se,  "Technotrend/Hauppauge WinTV Nexus-S rev1.3");
+MAKE_AV7110_INFO(fsc,        "Fujitsu Siemens DVB-C");
 
 static struct pci_device_id pci_tbl[] = {
-	MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0xffff),
-	MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0x0000),
-	MAKE_EXTENSION_PCI(fs_1_3, 0x13c2, 0x0000),
-	MAKE_EXTENSION_PCI(unkwn0, 0x13c2, 0x1002),
-	MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0001),
-	MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0002),
-	MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0003),
-	MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0004),
-	MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0006),
-	MAKE_EXTENSION_PCI(tt_t,   0x13c2, 0x0008),
-	MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x1102),
-	MAKE_EXTENSION_PCI(unkwn1, 0xffc2, 0x0000),
-	MAKE_EXTENSION_PCI(unkwn2, 0x00a1, 0x00a1),
-	MAKE_EXTENSION_PCI(nexus,  0x00a1, 0xa1a0),
-	MAKE_EXTENSION_PCI(dvboc11,0x13c2, 0x000a),
+	MAKE_EXTENSION_PCI(tts_1_X,   0x13c2, 0x0000),
+	MAKE_EXTENSION_PCI(ttt_1_X,   0x13c2, 0x0001),
+	MAKE_EXTENSION_PCI(ttc_2_X,   0x13c2, 0x0002),
+	MAKE_EXTENSION_PCI(tts_2_X,   0x13c2, 0x0003),
+	MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002),
+	MAKE_EXTENSION_PCI(fsc,       0x110a, 0x0000),
+	MAKE_EXTENSION_PCI(ttc_1_X,   0x13c2, 0x000a),
+
+/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte
+/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
+/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0006), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-S v????
+/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v????
+/*	MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
+
 	{
 		.vendor    = 0,
 	}
diff -puN drivers/media/dvb/ttpci/av7110_ca.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/av7110_ca.c
--- 25/drivers/media/dvb/ttpci/av7110_ca.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/av7110_ca.c	Thu Nov 18 15:18:09 2004
@@ -89,20 +89,20 @@ void ci_get_data(struct dvb_ringbuffer *
  * CI link layer file ops
  ******************************************************************************/
 
-int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size)
+static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size)
 {
 	dvb_ringbuffer_init(cirbuf, vmalloc(size), size);
 	dvb_ringbuffer_init(ciwbuf, vmalloc(size), size);
 	return 0;
 }
 
-void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
+static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
 {
 	dvb_ringbuffer_flush_spinlock_wakeup(cirbuf);
 	dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf);
 }
 
-void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
+static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf)
 {
 	vfree(cirbuf->data);
 	cirbuf->data = NULL;
@@ -110,7 +110,7 @@ void ci_ll_release(struct dvb_ringbuffer
 	ciwbuf->data = NULL;
 }
 
-int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
+static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file,
 		int slots, ca_slot_info_t *slot)
 {
 	int i;
diff -puN drivers/media/dvb/ttpci/av7110.h~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/av7110.h
--- 25/drivers/media/dvb/ttpci/av7110.h~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/av7110.h	Thu Nov 18 15:18:09 2004
@@ -24,6 +24,13 @@
 #include "dvb_filter.h"
 #include "dvb_net.h"
 #include "dvb_ringbuffer.h"
+#include "dvb_frontend.h"
+#include "ves1820.h"
+#include "ves1x93.h"
+#include "stv0299.h"
+#include "tda8083.h"
+#include "sp8870.h"
+#include "stv0297.h"
 
 #include <media/saa7146_vv.h>
 
@@ -217,6 +224,17 @@ struct av7110 {
 
 	unsigned char *bin_root;
 	unsigned long size_root;
+
+	struct dvb_frontend* fe;
+	fe_status_t fe_status;
+	int (*fe_init)(struct dvb_frontend* fe);
+	int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
+	int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
+	int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+	int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+	int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+	int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+	int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
 };
 
 
diff -puN drivers/media/dvb/ttpci/av7110_hw.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/av7110_hw.c
--- 25/drivers/media/dvb/ttpci/av7110_hw.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/av7110_hw.c	Thu Nov 18 15:18:09 2004
@@ -53,10 +53,14 @@ int av7110_debiwrite(struct av7110 *av71
 {
 	struct saa7146_dev *dev = av7110->dev;
 
-	if (count <= 0 || count > 32764)
+	if (count <= 0 || count > 32764) {
+		printk("%s: invalid count %d\n", __FUNCTION__, count);
 		return -1;
-	if (saa7146_wait_for_debi_done(av7110->dev) < 0)
+	}
+	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+		printk("%s: wait_for_debi_done failed\n", __FUNCTION__);
 		return -1;
+	}
 	saa7146_write(dev, DEBI_CONFIG, config);
 	if (count <= 4)		/* immediate transfer */
 		saa7146_write(dev, DEBI_AD, val);
@@ -72,10 +76,14 @@ u32 av7110_debiread(struct av7110 *av711
 	struct saa7146_dev *dev = av7110->dev;
 	u32 result = 0;
 
-	if (count > 32764 || count <= 0)
+	if (count > 32764 || count <= 0) {
+		printk("%s: invalid count %d\n", __FUNCTION__, count);
 		return 0;
-	if (saa7146_wait_for_debi_done(av7110->dev) < 0)
+	}
+	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+		printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__);
 		return 0;
+	}
 	saa7146_write(dev, DEBI_AD, av7110->debi_bus);
 	saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
 
@@ -83,7 +91,11 @@ u32 av7110_debiread(struct av7110 *av711
 	saa7146_write(dev, MC2, (2 << 16) | 2);
 	if (count > 4)
 		return count;
-	saa7146_wait_for_debi_done(av7110->dev);
+	if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
+		printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__);
+		return 0;
+	}
+
 	result = saa7146_read(dev, DEBI_AD);
 	result &= (0xffffffffUL >> ((4 - count) * 8));
 	return result;
@@ -240,7 +252,7 @@ int av7110_bootarm(struct av7110 *av7110
 	mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode));
 	iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
 
-	if (saa7146_wait_for_debi_done(av7110->dev)) {
+	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
 		       "saa7146_wait_for_debi_done() timed out\n");
 		return -1;
@@ -258,7 +270,7 @@ int av7110_bootarm(struct av7110 *av7110
 	dprintk(1, "load dpram code\n");
 	mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
 
-	if (saa7146_wait_for_debi_done(av7110->dev)) {
+	if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
 		printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
 		       "saa7146_wait_for_debi_done() timed out after loading DRAM\n");
 		return -1;
@@ -305,6 +317,8 @@ int __av7110_send_fw_cmd(struct av7110 *
 		}
 	}
 
+	wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
+
 #ifndef _NOHANDSHAKE
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
@@ -334,6 +348,8 @@ int __av7110_send_fw_cmd(struct av7110 *
 
 	wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
 
+	wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
+
 #ifdef COM_DEBUG
 	start = jiffies;
 	while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
diff -puN drivers/media/dvb/ttpci/av7110_v4l.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/av7110_v4l.c
--- 25/drivers/media/dvb/ttpci/av7110_v4l.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/av7110_v4l.c	Thu Nov 18 15:18:09 2004
@@ -162,7 +162,7 @@ static struct v4l2_audio msp3400_v4l2_au
 	.capability = V4L2_AUDCAP_STEREO
 };
 
-int av7110_dvb_c_switch(struct saa7146_fh *fh)
+static int av7110_dvb_c_switch(struct saa7146_fh *fh)
 {
 	struct saa7146_dev *dev = fh->dev;
 	struct saa7146_vv *vv = dev->vv_data;
@@ -227,7 +227,7 @@ int av7110_dvb_c_switch(struct saa7146_f
 	return 0;
 }
 
-int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 {
 	struct saa7146_dev *dev = fh->dev;
 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
@@ -424,7 +424,7 @@ int av7110_ioctl(struct saa7146_fh *fh, 
  * INITIALIZATION
  ****************************************************************************/
 
-struct saa7146_extension_ioctls ioctls[] = {
+static struct saa7146_extension_ioctls ioctls[] = {
 	{ VIDIOC_ENUMINPUT,	SAA7146_EXCLUSIVE },
 	{ VIDIOC_G_INPUT,	SAA7146_EXCLUSIVE },
 	{ VIDIOC_S_INPUT,	SAA7146_EXCLUSIVE },
@@ -684,7 +684,7 @@ static struct saa7146_ext_vv av7110_vv_d
 	.flags		= 0,
 
 	.stds		= &standard[0],
-	.num_stds	= sizeof(standard) / sizeof(struct saa7146_standard),
+	.num_stds	= ARRAY_SIZE(standard),
 	.std_callback	= &std_callback,
 
 	.ioctls		= &ioctls[0],
@@ -698,7 +698,7 @@ static struct saa7146_ext_vv av7110_vv_d
 	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
 
 	.stds		= &standard[0],
-	.num_stds	= sizeof(standard) / sizeof(struct saa7146_standard),
+	.num_stds	= ARRAY_SIZE(standard),
 	.std_callback	= &std_callback,
 
 	.ioctls		= &ioctls[0],
diff -puN drivers/media/dvb/ttpci/budget-av.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/budget-av.c
--- 25/drivers/media/dvb/ttpci/budget-av.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/budget-av.c	Thu Nov 18 15:18:09 2004
@@ -4,6 +4,9 @@
  *
  * Compiled from various sources by Michael Hunold <michael@mihu.de> 
  *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ *                               Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
  * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
  *
  * Copyright (C) 1999-2002 Ralph  Metzler 
@@ -31,15 +34,34 @@
  */
 
 #include "budget.h"
+#include "stv0299.h"
+#include "tda10021.h"
+#include "tda1004x.h"
 #include <media/saa7146_vv.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/spinlock.h>
+
+#include "dvb_ca_en50221.h"
+
+#define DEBICICAM		0x02420000
 
 struct budget_av {
 	struct budget budget;
 	struct video_device *vd;
 	int cur_input;
 	int has_saa7113;
+	struct tasklet_struct ciintf_irq_tasklet;
+	int slot_status;
+	struct dvb_ca_en50221 ca;
 };
 
+int enable_ci = 0;
+
+
 /****************************************************************************
  * INITIALIZATION
  ****************************************************************************/
@@ -55,8 +77,10 @@ static u8 i2c_readreg (struct i2c_adapte
 	msgs[1].flags = I2C_M_RD;
 	msgs[0].addr = msgs[1].addr=id/2;
 	mm1[0] = reg;
-	msgs[0].len = 1; msgs[1].len = 1;
-	msgs[0].buf = mm1; msgs[1].buf = mm2;
+	msgs[0].len = 1;
+	msgs[1].len = 1;
+	msgs[0].buf = mm1;
+	msgs[1].buf = mm2;
 
 	i2c_transfer(i2c, msgs, 2);
 
@@ -90,6 +114,211 @@ static int i2c_writereg (struct i2c_adap
         return i2c_transfer(i2c, &msgs, 1);
 }
 
+static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0);
+
+	if (result == -ETIMEDOUT)
+		budget_av->slot_status = 0;
+	return result;
+}
+
+static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
+	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0);
+
+	if (result == -ETIMEDOUT)
+		budget_av->slot_status = 0;
+	return result;
+}
+
+static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+	result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
+
+	if (result == -ETIMEDOUT)
+		budget_av->slot_status = 0;
+	return result;
+}
+
+static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	int result;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+	result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
+
+	if (result == -ETIMEDOUT)
+		budget_av->slot_status = 0;
+	return result;
+}
+
+static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	dprintk(1, "ciintf_slot_reset\n");
+
+	/* reset the card */
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
+	msleep(100);
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+	msleep(2000);		/* horrendous I know, but its the only way to be absolutely sure without an IRQ line! */
+
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	return 0;
+}
+
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	dprintk(1, "ciintf_slot_shutdown\n");
+
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+	budget_av->slot_status = 0;
+	return 0;
+}
+
+static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
+
+	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+	return 0;
+}
+
+static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+	struct budget_av *budget_av = (struct budget_av *) ca->data;
+	struct saa7146_dev *saa = budget_av->budget.dev;
+	int cam = 0;
+
+	if (slot != 0)
+		return -EINVAL;
+
+	if (!budget_av->slot_status) {
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+		udelay(1);
+		cam = saa7146_read(saa, PSR) & MASK_06;
+		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+		if (cam)
+			budget_av->slot_status = 1;
+	} else if (!open) {
+		saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+		if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
+			budget_av->slot_status = 0;
+	}
+
+	if (budget_av->slot_status == 1)
+		return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+
+	return 0;
+}
+
+static int ciintf_init(struct budget_av *budget_av)
+{
+	struct saa7146_dev *saa = budget_av->budget.dev;
+	int result;
+
+	memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));
+
+	/* setup GPIOs */
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);
+	saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+
+	/* Reset the card */
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
+	msleep(50);
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+	msleep(100);
+
+	/* Enable DEBI pins */
+	saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
+
+	/* register CI interface */
+	budget_av->ca.owner = THIS_MODULE;
+	budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem;
+	budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem;
+	budget_av->ca.read_cam_control = ciintf_read_cam_control;
+	budget_av->ca.write_cam_control = ciintf_write_cam_control;
+	budget_av->ca.slot_reset = ciintf_slot_reset;
+	budget_av->ca.slot_shutdown = ciintf_slot_shutdown;
+	budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
+	budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
+	budget_av->ca.data = budget_av;
+	if ((result = dvb_ca_en50221_init(budget_av->budget.dvb_adapter,
+					  &budget_av->ca, 0, 1)) != 0) {
+		printk("budget_av: CI interface detected, but initialisation failed.\n");
+		goto error;
+	}
+	// success!
+	printk("ciintf_init: CI interface initialised\n");
+	budget_av->budget.ci_present = 1;
+	return 0;
+
+error:
+	saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+	return result;
+}
+
+static void ciintf_deinit(struct budget_av *budget_av)
+{
+	struct saa7146_dev *saa = budget_av->budget.dev;
+
+	saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
+	saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
+	saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
+	saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
+
+	/* release the CA device */
+	dvb_ca_en50221_release(&budget_av->ca);
+
+	/* disable DEBI pins */
+	saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
+}
+
 
 static const u8 saa7113_tab[] = {
 	0x01, 0x08,
@@ -165,6 +394,397 @@ static int saa7113_setinput (struct budg
 }
 
 
+static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
+	u8 m1;
+
+	aclk = 0xb5;
+	if (srate < 2000000)
+		bclk = 0x86;
+	else if (srate < 5000000)
+		bclk = 0x89;
+	else if (srate < 15000000)
+		bclk = 0x8f;
+	else if (srate < 45000000)
+		bclk = 0x95;
+
+	m1 = 0x14;
+	if (srate < 4000000)
+		m1 = 0x10;
+
+	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);
+	stv0299_writereg(fe, 0x0f, 0x80 | m1);
+
+	return 0;
+}
+
+static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
+					struct dvb_frontend_parameters *params)
+{
+	struct budget_av *budget_av = (struct budget_av *) fe->dvb->priv;
+	u32 div;
+	u8 buf[4];
+	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125;	// round correctly
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	buf[3] = 0x20;
+
+	if (params->u.qpsk.symbol_rate < 4000000)
+		buf[3] |= 1;
+
+	if (params->frequency < 1250000)
+		buf[3] |= 0;
+	else if (params->frequency < 1550000)
+		buf[3] |= 0x40;
+	else if (params->frequency < 2050000)
+		buf[3] |= 0x80;
+	else if (params->frequency < 2150000)
+		buf[3] |= 0xC0;
+
+	if (i2c_transfer(&budget_av->budget.i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static u8 typhoon_cinergy1200s_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,		/* DAC not used, set to high impendance mode */
+	0x07, 0x00,		/* DAC LSB */
+	0x08, 0x40,		/* DiSEqC off */
+	0x09, 0x00,		/* FIFO */
+	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,		// AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb5,		// Lock detect: -64  Carrier freq detect:on
+	0x15, 0xc9,		// lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,		// 1/2 threshold
+	0x2a, 0x14,		// 2/3 threshold
+	0x2b, 0x0f,		// 3/4 threshold
+	0x2c, 0x09,		// 5/6 threshold
+	0x2d, 0x05,		// 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,		// test all FECs
+	0x32, 0x19,		// viterbi and synchro search
+	0x33, 0xfc,		// rs control
+	0x34, 0x93,		// error control
+	0x0f, 0x92,
+	0xff, 0xff
+};
+
+static struct stv0299_config typhoon_config = {
+	.demod_address = 0x68,
+	.inittab = typhoon_cinergy1200s_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+	.pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static struct stv0299_config cinergy_1200s_config = {
+	.demod_address = 0x68,
+	.inittab = typhoon_cinergy1200s_inittab,
+	.mclk = 88000000UL,
+	.invert = 0,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_0,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.min_delay_ms = 100,
+	.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+	.pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+	u8 buf[4];
+	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+#define TUNER_MUL 62500
+
+	u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x8e;
+	buf[3] = (params->frequency < 174500000 ? 0xa1 :
+		  params->frequency < 454000000 ? 0x92 : 0x34);
+
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct tda10021_config philips_cu1216_config = {
+	.demod_address = 0x0c,
+	.pll_set = philips_cu1216_pll_set,
+};
+
+
+
+
+static int philips_tu1216_pll_init(struct dvb_frontend *fe)
+{
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+	static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len =
+			sizeof(tu1216_init) };
+
+	// setup PLL configuration
+	if (i2c_transfer(&budget->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(&budget->i2c_adap, &tuner_msg, 1) != 1) {
+		i2c_transfer(&budget->i2c_adap, &tuner_msg, 1);
+	}
+
+	return 0;
+}
+
+static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct budget *budget = (struct budget *) 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(&budget->i2c_adap, &tuner_msg, 1) != 1)
+		return -EIO;
+
+	msleep(1);
+	return 0;
+}
+
+static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
+					   const struct firmware **fw, char *name)
+{
+	struct budget *budget = (struct budget *) fe->dvb->priv;
+
+	return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
+struct tda1004x_config philips_tu1216_config = {
+
+	.demod_address = 0x8,
+	.invert = 1,
+	.pll_init = philips_tu1216_pll_init,
+	.pll_set = philips_tu1216_pll_set,
+	.request_firmware = philips_tu1216_request_firmware,
+};
+
+
+
+
+static u8 read_pwm(struct budget_av *budget_av)
+{
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
+	{.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
+	};
+
+	if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)
+	    || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+
+static void frontend_init(struct budget_av *budget_av)
+{
+	switch (budget_av->budget.dev->pci->subsystem_device) {
+	case 0x4f56:		// Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059))
+		budget_av->budget.dvb_frontend =
+			stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap);
+		if (budget_av->budget.dvb_frontend != NULL) {
+			break;
+		}
+		break;
+
+	case 0x0020:		// KNC1 DVB-C budget (tda10021/Philips CU1216(tua6034))
+		budget_av->budget.dvb_frontend =
+			tda10021_attach(&philips_cu1216_config,
+					&budget_av->budget.i2c_adap, read_pwm(budget_av));
+		if (budget_av->budget.dvb_frontend != NULL) {
+			break;
+		}
+		break;
+
+	case 0x0030:		// KNC1 DVB-T budget (tda10046/Philips TU1216(tda6651tt))
+		budget_av->budget.dvb_frontend =
+			tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
+		if (budget_av->budget.dvb_frontend != NULL) {
+			break;
+		}
+		break;
+
+	case 0x1154:		// TerraTec Cinergy 1200 DVB-S (stv0299/Philips SU1278(tsa5059))
+		budget_av->budget.dvb_frontend =
+			stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap);
+		if (budget_av->budget.dvb_frontend != NULL) {
+			break;
+		}
+		break;
+
+	case 0x1156:		// Terratec Cinergy 1200 DVB-C (tda10021/Philips CU1216(tua6034))
+		budget_av->budget.dvb_frontend =
+			tda10021_attach(&philips_cu1216_config,
+					&budget_av->budget.i2c_adap, read_pwm(budget_av));
+		if (budget_av->budget.dvb_frontend) {
+			break;
+		}
+		break;
+
+	case 0x1157:		// Terratec Cinergy 1200 DVB-T (tda10046/Philips TU1216(tda6651tt))
+		budget_av->budget.dvb_frontend =
+			tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
+		if (budget_av->budget.dvb_frontend) {
+			break;
+		}
+		break;
+	}
+
+	if (budget_av->budget.dvb_frontend == NULL) {
+		printk("budget_av: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		       budget_av->budget.dev->pci->vendor,
+		       budget_av->budget.dev->pci->device,
+		       budget_av->budget.dev->pci->subsystem_vendor,
+		       budget_av->budget.dev->pci->subsystem_device);
+	} else {
+		if (dvb_register_frontend
+		    (budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) {
+			printk("budget-av: Frontend registration failed!\n");
+			if (budget_av->budget.dvb_frontend->ops->release)
+				budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+			budget_av->budget.dvb_frontend = NULL;
+		}
+	}
+}
+
+
+static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)
+{
+	struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
+
+	dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);
+
+	if (*isr & MASK_10)
+		ttpci_budget_irq10_handler(dev, isr);
+}
+
 static int budget_av_detach (struct saa7146_dev *dev)
 {
 	struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
@@ -180,6 +800,11 @@ static int budget_av_detach (struct saa7
 	saa7146_unregister_device (&budget_av->vd, dev);
 	}
 
+	if (budget_av->budget.ci_present)
+		ciintf_deinit(budget_av);
+
+	if (budget_av->budget.dvb_frontend != NULL)
+		dvb_unregister_frontend(budget_av->budget.dvb_frontend);
 	err = ttpci_budget_deinit (&budget_av->budget);
 
 	kfree (budget_av);
@@ -189,28 +814,24 @@ static int budget_av_detach (struct saa7
 
 static struct saa7146_ext_vv vv_data;
 
-static int budget_av_attach (struct saa7146_dev* dev,
-		      struct saa7146_pci_extension_data *info)
+static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
 	struct budget_av *budget_av;
-	struct budget_info *bi = info->ext_priv;
 	u8 *mac;
 	int err;
 
 	dprintk(2, "dev: %p\n", dev);
 
-	if (bi->type != BUDGET_KNC1 && bi->type != BUDGET_CIN1200) {
-		return -ENODEV;
-	}
-
 	if (!(budget_av = kmalloc(sizeof(struct budget_av), GFP_KERNEL)))
 		return -ENOMEM;
 
 	memset(budget_av, 0, sizeof(struct budget_av));
 
+	budget_av->budget.ci_present = 0;
+
 	dev->ext_priv = budget_av;
 
-	if ((err = ttpci_budget_init(&budget_av->budget, dev, info))) {
+	if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
 		kfree(budget_av);
 		return err;
 	}
@@ -220,8 +841,6 @@ static int budget_av_attach (struct saa7
 	saa7146_write(dev, DD1_INIT, 0x07000600);
 	saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
 
-	//test_knc_ci(av7110);
-
 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
 	msleep(500);
 
@@ -234,9 +853,7 @@ static int budget_av_attach (struct saa7
 		return err;
 	}
 
-	if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1",
-					   VFL_TYPE_GRABBER)))
-	{
+		if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
 		/* fixme: proper cleanup here */
 		ERR(("cannot register capture v4l2 device.\n"));
 		return err;
@@ -261,15 +878,20 @@ static int budget_av_attach (struct saa7
 		printk("KNC1-%d: Could not read MAC from KNC1 card\n",
 				budget_av->budget.dvb_adapter->num);
 		memset(mac, 0, 6);
-	}
-	else
+	} else {
 		printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
 				budget_av->budget.dvb_adapter->num,
 				mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-	return 0;
 }
 
+	budget_av->budget.dvb_adapter->priv = budget_av;
+	frontend_init(budget_av);
+
+	if (enable_ci)
+		ciintf_init(budget_av);
 
+	return 0;
+}
 
 #define KNC1_INPUTS 2
 static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
@@ -290,12 +912,9 @@ static int av_ioctl(struct saa7146_fh *f
 {
 	struct saa7146_dev *dev = fh->dev;
 	struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
-/*
-	struct saa7146_vv *vv = dev->vv_data; 
-*/	
+
 	switch(cmd) {
-	case VIDIOC_ENUMINPUT:
-	{
+	case VIDIOC_ENUMINPUT:{
 		struct v4l2_input *i = arg;
 		
 		dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
@@ -305,8 +924,7 @@ static int av_ioctl(struct saa7146_fh *f
 		memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
 		return 0;
 	}
-	case VIDIOC_G_INPUT:
-	{
+	case VIDIOC_G_INPUT:{
 		int *input = (int *)arg;
 
 		*input = budget_av->cur_input;
@@ -314,8 +932,7 @@ static int av_ioctl(struct saa7146_fh *f
 		dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
 		return 0;		
 	}	
-	case VIDIOC_S_INPUT:
-	{
+	case VIDIOC_S_INPUT:{
 		int input = *(int *)arg;
 		dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
 		return saa7113_setinput (budget_av, input);
@@ -327,17 +944,15 @@ static int av_ioctl(struct saa7146_fh *f
 }
 
 static struct saa7146_standard standard[] = {
-	{
-		.name	= "PAL", 	.id	= V4L2_STD_PAL,
+	{.name = "PAL",.id = V4L2_STD_PAL,
 		.v_offset	= 0x17,	.v_field 	= 288,
 		.h_offset	= 0x14,	.h_pixels 	= 680,  	      
-		.v_max_out	= 576,	.h_max_out	= 768
-	}, {
-		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
+	 .v_max_out = 576,.h_max_out = 768 },
+
+	{.name = "NTSC",.id = V4L2_STD_NTSC,
 		.v_offset	= 0x16,	.v_field 	= 240,
 		.h_offset	= 0x06,	.h_pixels 	= 708,
-		.v_max_out	= 480,	.h_max_out	= 640,
-	}
+	 .v_max_out = 480,.h_max_out = 640, },
 };
 
 static struct saa7146_ext_vv vv_data = {
@@ -350,17 +965,22 @@ static struct saa7146_ext_vv vv_data = {
 	.ioctl		= av_ioctl,
 };
 
-
-
 static struct saa7146_extension budget_extension;
 
-
-MAKE_BUDGET_INFO(knc1, "KNC1 DVB-S", BUDGET_KNC1);
-MAKE_BUDGET_INFO(cin1200, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200);
+MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
+MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
+MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
+MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
+MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
 
 static struct pci_device_id pci_tbl [] = {
-	MAKE_EXTENSION_PCI(knc1, 0x1131, 0x4f56),
-	MAKE_EXTENSION_PCI(cin1200, 0x153b, 0x1154),
+	MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
+	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
+	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
+	MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
+	MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
+	MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
 	{
 		.vendor    = 0,
 	}
@@ -377,7 +997,7 @@ static struct saa7146_extension budget_e
 	.detach		= budget_av_detach,
 
 	.irq_mask	= MASK_10,
-	.irq_func	= ttpci_budget_irq10_handler,
+	.irq_func = budget_av_irq,
 };	
 
 static int __init budget_av_init(void) 
@@ -396,5 +1016,6 @@ module_exit(budget_av_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
 MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
-		   "budget PCI DVB w/ analog input (e.g. the KNC cards)");
-
+		   "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");
+module_param_named(enable_ci, enable_ci, int, 0644);
+MODULE_PARM_DESC(enable_ci, "Turn on/off CI module (default:off).");
diff -puN drivers/media/dvb/ttpci/budget.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/budget.c
--- 25/drivers/media/dvb/ttpci/budget.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/budget.c	Thu Nov 18 15:18:09 2004
@@ -35,6 +35,11 @@
  */
 
 #include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "ves1820.h"
+#include "l64781.h"
+#include "tda8083.h"
 
 static void Set22K (struct budget *budget, int state)
 {
@@ -105,89 +110,368 @@ static int SendDiSEqCMsg (struct budget 
 	return 0;
 }
 
-
-int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+/*
+ *   Routines for the Fujitsu Siemens Activy budget card
+ *   22 kHz tone and DiSEqC are handled by the frontend.
+ *   Voltage must be set here.
+ */
+static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
 {
-       struct budget *budget = fe->before_after_data;
+	struct saa7146_dev *dev=budget->dev;
 
        dprintk(2, "budget: %p\n", budget);
 
-       switch (cmd) {
-       case FE_SET_TONE:
-               switch ((fe_sec_tone_mode_t) arg) {
+	switch (voltage) {
+		case SEC_VOLTAGE_13:
+			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
+			break;
+		case SEC_VOLTAGE_18:
+			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	return SetVoltage_Activy (budget, voltage);
+}
+
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	switch (tone) {
                case SEC_TONE_ON:
                        Set22K (budget, 1);
                        break;
                case SEC_TONE_OFF:
                        Set22K (budget, 0);
                        break;
+
                default:
                        return -EINVAL;
-               };
-               break;
+	}
+
+	return 0;
+}
 
-       case FE_DISEQC_SEND_MASTER_CMD:
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
        {
-               struct dvb_diseqc_master_cmd *cmd = arg;
+	struct budget* budget = (struct budget*) fe->dvb->priv;
 
                SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
-               break;
+
+	return 0;
        }
 
-       case FE_DISEQC_SEND_BURST:
-               SendDiSEqCMsg (budget, 0, NULL, (unsigned long)arg);
-               break;
-
-       default:
-               return -EOPNOTSUPP;
-       };
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+
+	SendDiSEqCMsg (budget, 0, NULL, minicmd);
 
        return 0;
 }
 
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u8 pwr = 0;
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	u32 div = (params->frequency + 479500) / 125;
+
+	if (params->frequency > 2000000) pwr = 3;
+	else if (params->frequency > 1800000) pwr = 2;
+	else if (params->frequency > 1600000) pwr = 1;
+	else if (params->frequency > 1200000) pwr = 0;
+	else if (params->frequency >= 1100000) pwr = 1;
+	else pwr = 2;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = ((div & 0x18000) >> 10) | 0x95;
+	buf[3] = (pwr << 6) | 0x30;
 
-/*
- *   Routines for the Fujitsu Siemens Activy budget card
- *   22 kHz tone and DiSEqC are handled by the frontend.
- *   Voltage must be set here.
- */
-static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
+        // NOTE: since we're using a prescaler of 2, we set the
+	// divisor frequency to 62.5kHz and divide by 125 above
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config =
 {
-	struct saa7146_dev *dev=budget->dev;
+	.demod_address = 0x08,
+	.xin = 90100000UL,
+	.invert_pwm = 0,
+	.pll_set = alps_bsrv2_pll_set,
+};
+
+static u8 alps_bsru6_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x00,
+	0x03, 0x00,
+        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   // AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x15, 0xc9,   // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,  // 1/2 threshold
+	0x2a, 0x14,  // 2/3 threshold
+	0x2b, 0x0f,  // 3/4 threshold
+	0x2c, 0x09,  // 5/6 threshold
+	0x2d, 0x05,  // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,  // test all FECs
+	0x32, 0x19,  // viterbi and synchro search
+	0x33, 0xfc,  // rs control
+	0x34, 0x93,  // error control
+	0x0f, 0x52,
+	0xff, 0xff
+};
 
-	dprintk(2, "budget: %p\n", budget);
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 0;
 
-	switch (voltage) {
-		case SEC_VOLTAGE_13:
-			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
-			break;
-		case SEC_VOLTAGE_18:
-			saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
-			break;
-		default:
-			return -EINVAL;
+	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);
+
+	return 0;
 	}
 
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125; // round correctly
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	data[3] = 0xC4;
+
+	if (params->frequency > 1530000) data[3] = 0xc0;
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
+static struct stv0299_config alps_bsru6_config = {
 
-static int budget_ioctl_activy (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+	.pll_set = alps_bsru6_pll_set,
+};
+
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
-	struct budget *budget = fe->before_after_data;
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (params->frequency + 35937500 + 31250) / 62500;
+
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x85 | ((div >> 10) & 0x60);
+	data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
 
-	dprintk(2, "budget: %p\n", budget);
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
 
-	switch (cmd) {
-		case FE_SET_VOLTAGE:
-			return SetVoltage_Activy (budget, (fe_sec_voltage_t) arg);
-		default:
-			return -EOPNOTSUPP;
+static struct ves1820_config alps_tdbe2_config = {
+	.demod_address = 0x09,
+	.xin = 57840000UL,
+	.invert = 1,
+	.selagc = VES1820_SELAGC_SIGNAMPERR,
+	.pll_set = alps_tdbe2_pll_set,
+};
+
+static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u32 div;
+	u8 cfg, cpump, band_select;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = (36125000 + params->frequency) / 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 = 1;
+	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 << 6) | band_select;
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
 	}
 
+static struct l64781_config grundig_29504_401_config = {
+	.demod_address = 0x55,
+	.pll_set = grundig_29504_401_pll_set,
+};
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct budget* budget = (struct budget*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = params->frequency / 125;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = 0x00;
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
 	return 0;
 }
 
+static struct tda8083_config grundig_29504_451_config = {
+	.demod_address = 0x68,
+	.pll_set = grundig_29504_451_pll_set,
+};
+
+static u8 read_pwm(struct budget* budget)
+{
+	u8 b = 0xff;
+	u8 pwm;
+	struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+				 { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+        if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+		pwm = 0x48;
+
+	return pwm;
+}
+
+static void frontend_init(struct budget *budget)
+{
+	switch(budget->dev->pci->subsystem_device) {
+	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
+
+		// try the ALPS BSRV2 first of all
+		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+		        budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops->set_tone = budget_set_tone;
+			break;
+		}
+
+		// try the ALPS BSRU6 now
+		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+			budget->dvb_frontend->ops->set_tone = budget_set_tone;
+			break;
+		}
+		break;
+
+   	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+
+		budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+		if (budget->dvb_frontend) break;
+		break;
+
+   	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+
+		budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) break;
+		break;
+
+	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI (tda8083/Grundig 29504-451(tsa5522))
+
+		// grundig 29504-451
+                budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
+			break;
+		}
+		break;
+	}
+
+	if (budget->dvb_frontend == NULL) {
+		printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		       budget->dev->pci->vendor,
+		       budget->dev->pci->device,
+		       budget->dev->pci->subsystem_vendor,
+		       budget->dev->pci->subsystem_device);
+	} else {
+		if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+			printk("budget: Frontend registration failed!\n");
+			if (budget->dvb_frontend->ops->release)
+				budget->dvb_frontend->ops->release(budget->dvb_frontend);
+			budget->dvb_frontend = NULL;
+		}
+	}
+}
 
 static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
@@ -203,18 +487,14 @@ static int budget_attach (struct saa7146
 
 	dev->ext_priv = budget;
 
-	if ((err = ttpci_budget_init (budget, dev, info))) {
+	if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
 		printk("==> failed\n");
 		kfree (budget);
 		return err;
 	}
 
-	if (budget->card->type == BUDGET_FS_ACTIVY)
-		dvb_add_frontend_ioctls (budget->dvb_adapter,
-				 budget_ioctl_activy, NULL, budget);
-	else
-	dvb_add_frontend_ioctls (budget->dvb_adapter,
-				 budget_diseqc_ioctl, NULL, budget);
+	budget->dvb_adapter->priv = budget;
+	frontend_init(budget);
 
 	return 0;
 }
@@ -225,12 +505,7 @@ static int budget_detach (struct saa7146
 	struct budget *budget = (struct budget*) dev->ext_priv;
 	int err;
 
-	if (budget->card->type == BUDGET_FS_ACTIVY)
-		dvb_remove_frontend_ioctls (budget->dvb_adapter,
-				    budget_ioctl_activy, NULL);
-	else
-	dvb_remove_frontend_ioctls (budget->dvb_adapter,
-				    budget_diseqc_ioctl, NULL);
+	if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
 
 	err = ttpci_budget_deinit (budget);
 
@@ -247,18 +522,14 @@ static struct saa7146_extension budget_e
 MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
-MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
+/* MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC); UNDEFINED HARDWARE - mail linuxtv.org list */
 MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
-/* Uncomment for Budget Patch */
-/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/
 
 static struct pci_device_id pci_tbl[] = {
-	/* Uncomment for Budget Patch */
-	/*MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000),*/
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
 	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
-	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+/*	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */
 	MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
 	{
 		.vendor    = 0,
diff -puN drivers/media/dvb/ttpci/budget-ci.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/budget-ci.c
--- 25/drivers/media/dvb/ttpci/budget-ci.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/budget-ci.c	Thu Nov 18 15:18:09 2004
@@ -39,6 +39,8 @@
 #include <linux/spinlock.h>
 
 #include "dvb_ca_en50221.h"
+#include "stv0299.h"
+#include "tda1004x.h"
 
 #define DEBIADDR_IR		0x1234
 #define DEBIADDR_CICONTROL	0x0000
@@ -64,72 +66,11 @@ struct budget_ci {
 	struct input_dev input_dev;
 	struct tasklet_struct msp430_irq_tasklet;
 	struct tasklet_struct ciintf_irq_tasklet;
-	spinlock_t debilock;
 	int slot_status;
 	struct dvb_ca_en50221 ca;
 	char ir_dev_name[50];
 };
 
-static u32 budget_debiread (struct budget_ci* budget_ci, u32 config, int addr, int count)
-{
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-	u32 result = 0;
-        unsigned long flags;
-
-	if (count > 4 || count <= 0)
-		return 0;
-
-	spin_lock_irqsave(&budget_ci->debilock, flags);
-
-	if (saa7146_wait_for_debi_done(saa) < 0) {
-		spin_unlock_irqrestore(&budget_ci->debilock, flags);
-		return 0;
-	}
-
-	saa7146_write (saa, DEBI_COMMAND,
-		       (count << 17) | 0x10000 | (addr & 0xffff));
-	saa7146_write(saa, DEBI_CONFIG, config);
-	saa7146_write(saa, DEBI_PAGE, 0);
-	saa7146_write(saa, MC2, (2 << 16) | 2);
-
-	saa7146_wait_for_debi_done(saa);
-
-	result = saa7146_read(saa, 0x88);
-	result &= (0xffffffffUL >> ((4 - count) * 8));
-
-	spin_unlock_irqrestore(&budget_ci->debilock, flags);
-	return result;
-}
-
-static u8 budget_debiwrite (struct budget_ci* budget_ci, u32 config, int addr, int count, u32 value)
-{
-	struct saa7146_dev *saa = budget_ci->budget.dev;
-        unsigned long flags;
-
-	if (count > 4 || count <= 0)
-		return 0;
-
-	spin_lock_irqsave(&budget_ci->debilock, flags);
-
-	if (saa7146_wait_for_debi_done(saa) < 0) {
-		spin_unlock_irqrestore(&budget_ci->debilock, flags);
-		return 0;
-	}
-
-	saa7146_write (saa, DEBI_COMMAND,
-		       (count << 17) | 0x00000 | (addr & 0xffff));
-	saa7146_write(saa, DEBI_CONFIG, config);
-	saa7146_write(saa, DEBI_PAGE, 0);
-	saa7146_write(saa, DEBI_AD, value);
-	saa7146_write(saa, MC2, (2 << 16) | 2);
-
-	saa7146_wait_for_debi_done(saa);
-
-	spin_unlock_irqrestore(&budget_ci->debilock, flags);
-	return 0;
-}
-
-
 /* from reading the following remotes:
    Zenith Universal 7 / TV Mode 807 / VCR Mode 837
    Hauppauge (from NOVA-CI-s box product)
@@ -206,7 +147,8 @@ static void msp430_ir_interrupt (unsigne
 {
 	struct budget_ci *budget_ci = (struct budget_ci*) data;
 	struct input_dev *dev = &budget_ci->input_dev;
-	unsigned int code = budget_debiread(budget_ci, DEBINOSWAP, DEBIADDR_IR, 2) >> 8;
+	unsigned int code =
+		ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
 
 	if (code & 0x40) {
 	        code &= 0x3f;
@@ -221,8 +163,7 @@ static void msp430_ir_interrupt (unsigne
 		}
 
 		if (!key_map[code]) {
-        	        printk ("DVB (%s): no key for %02x!\n",
-				__FUNCTION__, code);
+			printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
 		        return;
        		}
 
@@ -281,79 +222,98 @@ static void msp430_ir_deinit (struct bud
 	input_unregister_device(dev);
 }
 
-static int ciintf_read_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address) {
+static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
+{
 	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-	if (slot != 0) return -EINVAL;
+	if (slot != 0)
+		return -EINVAL;
 
-	return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1);
+	return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
+				     DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
 }
 
-static int ciintf_write_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address, u8 value) {
+static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
+{
 	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-	if (slot != 0) return -EINVAL;
+	if (slot != 0)
+		return -EINVAL;
 
-	return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1, value);
+	return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
+				      DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
 }
 
-static int ciintf_read_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address) {
+static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
+{
 	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-	if (slot != 0) return -EINVAL;
+	if (slot != 0)
+		return -EINVAL;
 
-	return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1);
+	return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
+				     DEBIADDR_IO | (address & 3), 1, 1, 0);
 }
 
-static int ciintf_write_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value) {
+static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
+{
 	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 
-	if (slot != 0) return -EINVAL;
+	if (slot != 0)
+		return -EINVAL;
 
-	return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1, value);
+	return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
+				      DEBIADDR_IO | (address & 3), 1, value, 1, 0);
 }
 
-static int ciintf_slot_reset(struct dvb_ca_en50221* ca, int slot) {
+static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
 	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 
-	if (slot != 0) return -EINVAL;
+	if (slot != 0)
+		return -EINVAL;
 
 	// trigger on RISING edge during reset so we know when READY is re-asserted
 	saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
 	budget_ci->slot_status = SLOTSTATUS_RESET;
-	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
 	msleep(1);
-	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       CICONTROL_RESET, 1, 0);
 
 	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
    	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
 	return 0;
 }
 
-static int ciintf_slot_shutdown(struct dvb_ca_en50221* ca, int slot) {
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
    	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 
-	if (slot != 0) return -EINVAL;
+	if (slot != 0)
+		return -EINVAL;
 
 	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
 	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
 	return 0;
 }
 
-static int ciintf_slot_ts_enable(struct dvb_ca_en50221* ca, int slot) {
+static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
 	struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	int tmp;
 
-	if (slot != 0) return -EINVAL;
-
+	if (slot != 0)
+		return -EINVAL;
 
 	saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
 
-	tmp = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
-	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, tmp | CICONTROL_ENABLETS);
+	tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       tmp | CICONTROL_ENABLETS, 1, 0);
 
    	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
 	return 0;
@@ -367,10 +327,11 @@ static void ciintf_interrupt (unsigned l
 	unsigned int flags;
 
 	// ensure we don't get spurious IRQs during initialisation
-	if (!budget_ci->budget.ci_present) return;
+	if (!budget_ci->budget.ci_present)
+		return;
 
 	// read the CAM status
-	flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
+	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
 	if (flags & CICONTROL_CAMDETECT) {
 
 		// GPIO should be set to trigger on falling edge if a CAM is present
@@ -379,7 +340,8 @@ static void ciintf_interrupt (unsigned l
 		if (budget_ci->slot_status & SLOTSTATUS_NONE) {
 			// CAM insertion IRQ
 			budget_ci->slot_status = SLOTSTATUS_PRESENT;
-			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_INSERTED);
+			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
+						     DVB_CA_EN50221_CAMCHANGE_INSERTED);
 
 		} else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
 			// CAM ready (reset completed)
@@ -401,7 +363,8 @@ static void ciintf_interrupt (unsigned l
 		if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
 			// CAM removal IRQ
 			budget_ci->slot_status = SLOTSTATUS_NONE;
-			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_REMOVED);
+			dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
+						     DVB_CA_EN50221_CAMCHANGE_REMOVED);
 		}
 	}
 }
@@ -418,18 +381,18 @@ static int ciintf_init(struct budget_ci*
 	saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
 
 	// test if it is there
-	if ((budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CIVERSION, 1) & 0xa0) != 0xa0) {
+	if ((ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0) & 0xa0) != 0xa0) {
 		result = -ENODEV;
 		goto error;
 	}
-
 	// determine whether a CAM is present or not
-	flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
+	flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
 	budget_ci->slot_status = SLOTSTATUS_NONE;
-	if (flags & CICONTROL_CAMDETECT) budget_ci->slot_status = SLOTSTATUS_PRESENT;
-
+	if (flags & CICONTROL_CAMDETECT)
+		budget_ci->slot_status = SLOTSTATUS_PRESENT;
 
 	// register CI interface
+	budget_ci->ca.owner = THIS_MODULE;
 	budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
 	budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
 	budget_ci->ca.read_cam_control = ciintf_read_cam_control;
@@ -442,8 +405,7 @@ static int ciintf_init(struct budget_ci*
 					  &budget_ci->ca,
 					  DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
 					  DVB_CA_EN50221_FLAG_IRQ_FR |
-					  DVB_CA_EN50221_FLAG_IRQ_DA,
-				  1)) != 0) {
+					  DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) {
 		printk("budget_ci: CI interface detected, but initialisation failed.\n");
 		goto error;
 	}
@@ -456,7 +418,8 @@ static int ciintf_init(struct budget_ci*
 		saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
 	}
 	saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
-	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       CICONTROL_RESET, 1, 0);
 
 	// success!
 	printk("budget_ci: CI interface initialised\n");
@@ -464,7 +427,8 @@ static int ciintf_init(struct budget_ci*
 
 	// forge a fake CI IRQ so the CAM state is setup correctly
 	flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-	if (budget_ci->slot_status != SLOTSTATUS_NONE) flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+	if (budget_ci->slot_status != SLOTSTATUS_NONE)
+		flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
 	dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
 
 	return 0;
@@ -482,9 +446,10 @@ static void ciintf_deinit(struct budget_
 	saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
 	saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
 	tasklet_kill(&budget_ci->ciintf_irq_tasklet);
-	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
 	msleep(1);
-	budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
+	ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
+			       CICONTROL_RESET, 1, 0);
 
 	// disable TS data stream to CI interface
 	saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
@@ -513,9 +478,425 @@ static void budget_ci_irq (struct saa714
 }
 
 
+static u8 alps_bsru6_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x00,
+	0x03, 0x00,
+	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,		/* DAC not used, set to high impendance mode */
+	0x07, 0x00,		/* DAC LSB */
+	0x08, 0x40,		/* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,		/* FIFO */
+	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,		// AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb5,		// Lock detect: -64  Carrier freq detect:on
+	0x15, 0xc9,		// lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,		// 1/2 threshold
+	0x2a, 0x14,		// 2/3 threshold
+	0x2b, 0x0f,		// 3/4 threshold
+	0x2c, 0x09,		// 5/6 threshold
+	0x2d, 0x05,		// 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,		// test all FECs
+	0x32, 0x19,		// viterbi and synchro search
+	0x33, 0xfc,		// rs control
+	0x34, 0x93,		// error control
+	0x0f, 0x52,
+	0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 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);
+
+	return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+	u8 buf[4];
+	u32 div;
+	struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125;	// round correctly
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	buf[3] = 0xC4;
+
+	if (params->frequency > 1530000)
+		buf[3] = 0xc0;
+
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+	.pll_set = alps_bsru6_pll_set,
+};
+
+
+
+
+static u8 philips_su1278_tt_inittab[] = {
+	0x01, 0x0f,
+	0x02, 0x30,
+	0x03, 0x00,
+	0x04, 0x5b,
+	0x05, 0x85,
+	0x06, 0x02,
+	0x07, 0x00,
+	0x08, 0x02,
+	0x09, 0x00,
+	0x0C, 0x01,
+	0x0D, 0x81,
+	0x0E, 0x44,
+	0x0f, 0x14,
+	0x10, 0x3c,
+	0x11, 0x84,
+	0x12, 0xda,
+	0x13, 0x97,
+	0x14, 0x95,
+	0x15, 0xc9,
+	0x16, 0x19,
+	0x17, 0x8c,
+	0x18, 0x59,
+	0x19, 0xf8,
+	0x1a, 0xfe,
+	0x1c, 0x7f,
+	0x1d, 0x00,
+	0x1e, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,
+	0x29, 0x28,
+	0x2a, 0x14,
+	0x2b, 0x0f,
+	0x2c, 0x09,
+	0x2d, 0x09,
+	0x31, 0x1f,
+	0x32, 0x19,
+	0x33, 0xfc,
+	0x34, 0x93,
+	0xff, 0xff
+};
 
-static int budget_ci_attach (struct saa7146_dev* dev,
-		      struct saa7146_pci_extension_data *info)
+static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
+{
+	stv0299_writereg(fe, 0x0e, 0x44);
+	if (srate >= 10000000) {
+		stv0299_writereg(fe, 0x13, 0x97);
+		stv0299_writereg(fe, 0x14, 0x95);
+		stv0299_writereg(fe, 0x15, 0xc9);
+		stv0299_writereg(fe, 0x17, 0x8c);
+		stv0299_writereg(fe, 0x1a, 0xfe);
+		stv0299_writereg(fe, 0x1c, 0x7f);
+		stv0299_writereg(fe, 0x2d, 0x09);
+	} else {
+		stv0299_writereg(fe, 0x13, 0x99);
+		stv0299_writereg(fe, 0x14, 0x8d);
+		stv0299_writereg(fe, 0x15, 0xce);
+		stv0299_writereg(fe, 0x17, 0x43);
+		stv0299_writereg(fe, 0x1a, 0x1d);
+		stv0299_writereg(fe, 0x1c, 0x12);
+		stv0299_writereg(fe, 0x2d, 0x05);
+	}
+	stv0299_writereg(fe, 0x0e, 0x23);
+	stv0299_writereg(fe, 0x0f, 0x94);
+	stv0299_writereg(fe, 0x10, 0x39);
+	stv0299_writereg(fe, 0x15, 0xc9);
+
+	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+
+	return 0;
+}
+
+static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
+				     struct dvb_frontend_parameters *params)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+	u32 div;
+	u8 buf[4];
+	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000))
+		return -EINVAL;
+
+	div = (params->frequency + (500 - 1)) / 500;	// round correctly
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
+	buf[3] = 0x20;
+
+	if (params->u.qpsk.symbol_rate < 4000000)
+		buf[3] |= 1;
+
+	if (params->frequency < 1250000)
+		buf[3] |= 0;
+	else if (params->frequency < 1550000)
+		buf[3] |= 0x40;
+	else if (params->frequency < 2050000)
+		buf[3] |= 0x80;
+	else if (params->frequency < 2150000)
+		buf[3] |= 0xC0;
+
+	if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+static struct stv0299_config philips_su1278_tt_config = {
+
+	.demod_address = 0x68,
+	.inittab = philips_su1278_tt_inittab,
+	.mclk = 64000000UL,
+	.invert = 0,
+	.enhanced_tuning = 1,
+	.skip_reinit = 1,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 50,
+	.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
+	.pll_set = philips_su1278_tt_pll_set,
+};
+
+
+
+static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) 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 = 0x63,.flags = 0,.buf = td1316_init,.len =
+			sizeof(td1316_init) };
+
+	// setup PLL configuration
+	if (i2c_transfer(&budget_ci->budget.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(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+		i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
+	}
+
+	return 0;
+}
+
+static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+	u8 tuner_buf[4];
+	struct i2c_msg tuner_msg = {.addr = 0x63,.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 and TDA9889
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		tda1004x_write_byte(fe, 0x0C, 0x14);
+		filter = 0;
+		break;
+
+	case BANDWIDTH_7_MHZ:
+		tda1004x_write_byte(fe, 0x0C, 0x80);
+		filter = 0;
+		break;
+
+	case BANDWIDTH_8_MHZ:
+		tda1004x_write_byte(fe, 0x0C, 0x14);
+		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(&budget_ci->budget.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 budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
+
+	return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
+}
+
+struct tda1004x_config philips_tdm1316l_config = {
+
+	.demod_address = 0x8,
+	.invert = 0,
+	.pll_init = philips_tdm1316l_pll_init,
+	.pll_set = philips_tdm1316l_pll_set,
+	.request_firmware = philips_tdm1316l_request_firmware,
+};
+
+
+
+static void frontend_init(struct budget_ci *budget_ci)
+{
+	switch (budget_ci->budget.dev->pci->subsystem_device) {
+	case 0x100c:		// Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
+		budget_ci->budget.dvb_frontend =
+			stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			break;
+		}
+		break;
+
+	case 0x100f:		// Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
+		budget_ci->budget.dvb_frontend =
+			stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			break;
+		}
+		break;
+
+	case 0x1011:		// Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+		budget_ci->budget.dvb_frontend =
+			tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+		if (budget_ci->budget.dvb_frontend) {
+			break;
+		}
+		break;
+	}
+
+	if (budget_ci->budget.dvb_frontend == NULL) {
+		printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		       budget_ci->budget.dev->pci->vendor,
+		       budget_ci->budget.dev->pci->device,
+		       budget_ci->budget.dev->pci->subsystem_vendor,
+		       budget_ci->budget.dev->pci->subsystem_device);
+	} else {
+		if (dvb_register_frontend
+		    (budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
+			printk("budget-ci: Frontend registration failed!\n");
+			if (budget_ci->budget.dvb_frontend->ops->release)
+				budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+			budget_ci->budget.dvb_frontend = NULL;
+		}
+	}
+}
+
+static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 {
 	struct budget_ci *budget_ci;
 	int err;
@@ -525,12 +906,11 @@ static int budget_ci_attach (struct saa7
 
 	dprintk(2, "budget_ci: %p\n", budget_ci);
 
-	spin_lock_init(&budget_ci->debilock);
 	budget_ci->budget.ci_present = 0;
 
 	dev->ext_priv = budget_ci;
 
-	if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) {
+	if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
 		kfree (budget_ci);
 		return err;
 	}
@@ -542,6 +922,9 @@ static int budget_ci_attach (struct saa7
 
 	ciintf_init(budget_ci);
 
+	budget_ci->budget.dvb_adapter->priv = budget_ci;
+	frontend_init(budget_ci);
+
 	return 0;
 }
 
@@ -553,8 +936,10 @@ static int budget_ci_detach (struct saa7
 	struct saa7146_dev *saa = budget_ci->budget.dev;
 	int err;
 
-	if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci);
-
+	if (budget_ci->budget.ci_present)
+		ciintf_deinit(budget_ci);
+	if (budget_ci->budget.dvb_frontend)
+		dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
 	err = ttpci_budget_deinit (&budget_ci->budget);
 
 	tasklet_kill (&budget_ci->msp430_irq_tasklet);
diff -puN drivers/media/dvb/ttpci/budget-core.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/budget-core.c
--- 25/drivers/media/dvb/ttpci/budget-core.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/budget-core.c	Thu Nov 18 15:18:09 2004
@@ -74,8 +74,7 @@ static int start_ts_capture (struct budg
 
         memset(budget->grabbing, 0x00, TS_HEIGHT*TS_WIDTH);
 
-        saa7146_write(dev, PCI_BT_V1, 0x001c0000 |
-            (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
+	saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
 
         budget->tsf=0xff;
         budget->ttbp=0;
@@ -150,14 +149,87 @@ static void vpeirq (unsigned long data)
 		return;
 
         if (newdma > olddma) { /* no wraparound, dump olddma..newdma */
-                        dvb_dmx_swfilter_packets(&budget->demux, 
-        	                mem+olddma, (newdma-olddma) / 188);
+		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (newdma - olddma) / 188);
         } else { /* wraparound, dump olddma..buflen and 0..newdma */
-	                dvb_dmx_swfilter_packets(&budget->demux,
-        	                mem+olddma, (TS_BUFLEN-olddma) / 188);
-                        dvb_dmx_swfilter_packets(&budget->demux,
-                                mem, newdma / 188);
+		dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
+		dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
+	}
         }
+
+
+int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
+			  int uselocks, int nobusyloop)
+{
+	struct saa7146_dev *saa = budget->dev;
+	int result = 0;
+	unsigned long flags = 0;
+
+	if (count > 4 || count <= 0)
+		return 0;
+
+	if (uselocks)
+		spin_lock_irqsave(&budget->debilock, flags);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
+	saa7146_write(saa, DEBI_CONFIG, config);
+	saa7146_write(saa, DEBI_PAGE, 0);
+	saa7146_write(saa, MC2, (2 << 16) | 2);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	result = saa7146_read(saa, DEBI_AD);
+	result &= (0xffffffffUL >> ((4 - count) * 8));
+
+	if (uselocks)
+		spin_unlock_irqrestore(&budget->debilock, flags);
+
+	return result;
+}
+
+int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
+			   int count, u32 value, int uselocks, int nobusyloop)
+{
+	struct saa7146_dev *saa = budget->dev;
+	unsigned long flags = 0;
+	int result;
+
+	if (count > 4 || count <= 0)
+		return 0;
+
+	if (uselocks)
+		spin_lock_irqsave(&budget->debilock, flags);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
+	saa7146_write(saa, DEBI_CONFIG, config);
+	saa7146_write(saa, DEBI_PAGE, 0);
+	saa7146_write(saa, DEBI_AD, value);
+	saa7146_write(saa, MC2, (2 << 16) | 2);
+
+	if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
+		if (uselocks)
+			spin_unlock_irqrestore(&budget->debilock, flags);
+		return result;
+	}
+
+	if (uselocks)
+		spin_unlock_irqrestore(&budget->debilock, flags);
+	return 0;
 }
 
 
@@ -231,13 +303,11 @@ static int budget_register(struct budget
                 return ret;
         
         budget->mem_frontend.source = DMX_MEMORY_FE;
-        ret=dvbdemux->dmx.add_frontend (&dvbdemux->dmx, 
-                                        &budget->mem_frontend);
+	ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
         if (ret<0)
                 return ret;
         
-        ret=dvbdemux->dmx.connect_frontend (&dvbdemux->dmx, 
-                                            &budget->hw_frontend);
+	ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
         if (ret < 0)
                 return ret;
 
@@ -263,30 +333,9 @@ static void budget_unregister(struct bud
         dvb_dmx_release(&budget->demux);
 }
 
-/* fixme: can this be unified among all saa7146 based dvb cards? */
-static int client_register(struct i2c_client *client)
-{
-	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
-	struct budget *budget = (struct budget*)dev->ext_priv;
-
-	if (client->driver->command)
-		return client->driver->command(client, FE_REGISTER, budget->dvb_adapter);
-	return 0;
-}
-
-static int client_unregister(struct i2c_client *client)
-{
-	struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
-	struct budget *budget = (struct budget*)dev->ext_priv;
-
-	if (client->driver->command)
-		return client->driver->command(client, FE_UNREGISTER, budget->dvb_adapter);
-	return 0;
-}
-
-int ttpci_budget_init (struct budget *budget,
-		       struct saa7146_dev* dev,
-		       struct saa7146_pci_extension_data *info)
+int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
+		      struct saa7146_pci_extension_data *info,
+		      struct module *owner)
 {
 	int length = TS_WIDTH*TS_HEIGHT;
 	int ret = 0;
@@ -299,7 +348,7 @@ int ttpci_budget_init (struct budget *bu
 	budget->card = bi;
 	budget->dev = (struct saa7146_dev *) dev;
 
-	dvb_register_adapter(&budget->dvb_adapter, budget->card->name, THIS_MODULE);
+	dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
 
 	/* set dd1 stream a & b */
       	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
@@ -313,21 +362,18 @@ int ttpci_budget_init (struct budget *bu
 	else
 		budget->video_port = BUDGET_VIDEO_PORTA;
 	spin_lock_init(&budget->feedlock);
+	spin_lock_init(&budget->debilock);
 
 	/* the Siemens DVB needs this if you want to have the i2c chips
            get recognized before the main driver is loaded */
 	if (bi->type != BUDGET_FS_ACTIVY)
 		saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
 	
-	budget->i2c_adap = (struct i2c_adapter) {
-		.client_register = client_register,
-		.client_unregister = client_unregister,
 #ifdef I2C_ADAP_CLASS_TV_DIGITAL
-		.class = I2C_ADAP_CLASS_TV_DIGITAL,
+	budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
 #else
-		.class = I2C_CLASS_TV_DIGITAL,
+	budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
 #endif
-	};
 
 	strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
 
@@ -341,7 +387,8 @@ int ttpci_budget_init (struct budget *bu
 
 	ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter->proposed_mac);
 
-	if( NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci,length,&budget->pt))) {
+	if (NULL ==
+	    (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) {
 		ret = -ENOMEM;
 		goto err;
 	}
@@ -420,8 +467,8 @@ void ttpci_budget_set_video_port(struct 
    	spin_unlock(&budget->feedlock);
 }
 
-
-
+EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
+EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
 EXPORT_SYMBOL_GPL(ttpci_budget_init);
 EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
 EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
diff -puN drivers/media/dvb/ttpci/budget.h~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/budget.h
--- 25/drivers/media/dvb/ttpci/budget.h~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/budget.h	Thu Nov 18 15:18:09 2004
@@ -9,6 +9,7 @@
 #include "dvb_filter.h"
 #include "dvb_net.h"
 
+#include <linux/module.h>
 #include <media/saa7146.h>
 
 extern int budget_debug;
@@ -61,7 +62,10 @@ struct budget {
 
 	spinlock_t feedlock;
 
+	spinlock_t debilock;
+
         struct dvb_adapter       *dvb_adapter;
+	struct dvb_frontend *dvb_frontend;
 	void			 *priv;
 };
 
@@ -82,20 +86,27 @@ static struct saa7146_pci_extension_data
 
 #define BUDGET_TT		   0
 #define BUDGET_TT_HW_DISEQC	   1
-#define BUDGET_KNC1		   2
 #define BUDGET_PATCH		   3
 #define BUDGET_FS_ACTIVY	   4
-#define BUDGET_CIN1200		   5
+#define BUDGET_CIN1200S		   5
+#define BUDGET_CIN1200C		   6
+#define BUDGET_CIN1200T		   7
+#define BUDGET_KNC1S		   8
+#define BUDGET_KNC1C		   9
+#define BUDGET_KNC1T		   10
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
 
-extern int ttpci_budget_init (struct budget *budget,
-			      struct saa7146_dev* dev,
-			      struct saa7146_pci_extension_data *info);
+extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
+			     struct saa7146_pci_extension_data *info,
+			     struct module *owner);
 extern int ttpci_budget_deinit (struct budget *budget);
 extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr);
 extern void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port);
+extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
+				 int uselocks, int nobusyloop);
+extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value,
+				  int uselocks, int nobusyloop);
 
 #endif
-
diff -puN drivers/media/dvb/ttpci/budget-patch.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers drivers/media/dvb/ttpci/budget-patch.c
--- 25/drivers/media/dvb/ttpci/budget-patch.c~dvb-follow-changes-in-dvb-ttpci-and-budget-drivers	Thu Nov 18 15:18:09 2004
+++ 25-akpm/drivers/media/dvb/ttpci/budget-patch.c	Thu Nov 18 15:18:09 2004
@@ -33,6 +33,9 @@
 #include "av7110.h"
 #include "av7110_hw.h"
 #include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "tda8083.h"
 
 #define budget_patch budget
 
@@ -121,16 +124,11 @@ static int av7110_send_diseqc_msg(struct
         return 0;
 }
 
-
-int budget_patch_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
 {
-        struct budget_patch *budget = fe->before_after_data;
-
-        dprintk(2, "budget: %p\n", budget);
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 
-        switch (cmd) {
-        case FE_SET_TONE:
-                switch ((fe_sec_tone_mode_t) arg) {
+	switch (tone) {
                 case SEC_TONE_ON:
                         av7110_set22k (budget, 1);
                         break;
@@ -140,27 +138,232 @@ int budget_patch_diseqc_ioctl (struct dv
                 default:
                         return -EINVAL;
                 }
-                break;
 
-        case FE_DISEQC_SEND_MASTER_CMD:
+	return 0;
+}
+
+static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
         {
-                struct dvb_diseqc_master_cmd *cmd = arg;
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
 
                 av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
-                break;
+
+	return 0;
         }
 
-        case FE_DISEQC_SEND_BURST:
-                av7110_send_diseqc_msg (budget, 0, NULL, (int) (long) arg);
-                break;
+static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+
+	av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
 
-        default:
-                return -EOPNOTSUPP;
+	return 0;
         }
 
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+	u8 pwr = 0;
+	u8 buf[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+	u32 div = (params->frequency + 479500) / 125;
+
+	if (params->frequency > 2000000) pwr = 3;
+	else if (params->frequency > 1800000) pwr = 2;
+	else if (params->frequency > 1600000) pwr = 1;
+	else if (params->frequency > 1200000) pwr = 0;
+	else if (params->frequency >= 1100000) pwr = 1;
+	else pwr = 2;
+
+	buf[0] = (div >> 8) & 0x7f;
+	buf[1] = div & 0xff;
+	buf[2] = ((div & 0x18000) >> 10) | 0x95;
+	buf[3] = (pwr << 6) | 0x30;
+
+        // NOTE: since we're using a prescaler of 2, we set the
+	// divisor frequency to 62.5kHz and divide by 125 above
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+	.demod_address = 0x08,
+	.xin = 90100000UL,
+	.invert_pwm = 0,
+	.pll_set = alps_bsrv2_pll_set,
+};
+
+static u8 alps_bsru6_inittab[] = {
+	0x01, 0x15,
+	0x02, 0x00,
+	0x03, 0x00,
+        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
+	0x06, 0x40,   /* DAC not used, set to high impendance mode */
+	0x07, 0x00,   /* DAC LSB */
+	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
+	0x09, 0x00,   /* FIFO */
+	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
+	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
+	0x10, 0x3f,   // AGC2  0x3d
+	0x11, 0x84,
+	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+	0x15, 0xc9,   // lock detector threshold
+	0x16, 0x00,
+	0x17, 0x00,
+	0x18, 0x00,
+	0x19, 0x00,
+	0x1a, 0x00,
+	0x1f, 0x50,
+	0x20, 0x00,
+	0x21, 0x00,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
+	0x29, 0x1e,  // 1/2 threshold
+	0x2a, 0x14,  // 2/3 threshold
+	0x2b, 0x0f,  // 3/4 threshold
+	0x2c, 0x09,  // 5/6 threshold
+	0x2d, 0x05,  // 7/8 threshold
+	0x2e, 0x01,
+	0x31, 0x1f,  // test all FECs
+	0x32, 0x19,  // viterbi and synchro search
+	0x33, 0xfc,  // rs control
+	0x34, 0x93,  // error control
+	0x0f, 0x52,
+	0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+	u8 aclk = 0;
+	u8 bclk = 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);
+
         return 0;
 }
 
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+	u8 data[4];
+	u32 div;
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+	div = (params->frequency + (125 - 1)) / 125; // round correctly
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+	data[3] = 0xC4;
+
+	if (params->frequency > 1530000) data[3] = 0xc0;
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+	.demod_address = 0x68,
+	.inittab = alps_bsru6_inittab,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.enhanced_tuning = 0,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_1,
+	.volt13_op0_op1 = STV0299_VOLT13_OP1,
+	.min_delay_ms = 100,
+	.set_symbol_rate = alps_bsru6_set_symbol_rate,
+	.pll_set = alps_bsru6_pll_set,
+};
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+	u32 div;
+	u8 data[4];
+	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+	div = params->frequency / 125;
+	data[0] = (div >> 8) & 0x7f;
+	data[1] = div & 0xff;
+	data[2] = 0x8e;
+	data[3] = 0x00;
+
+	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+	return 0;
+}
+
+struct tda8083_config grundig_29504_451_config = {
+	.demod_address = 0x68,
+	.pll_set = grundig_29504_451_pll_set,
+};
+
+static void frontend_init(struct budget_patch* budget)
+{
+	switch(budget->dev->pci->subsystem_device) {
+	case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+
+		// try the ALPS BSRV2 first of all
+		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+			budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+			break;
+		}
+
+		// try the ALPS BSRU6 now
+		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+			budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+			break;
+		}
+
+		// Try the grundig 29504-451
+		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+		if (budget->dvb_frontend) {
+			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+			budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+			budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+			break;
+		}
+		break;
+	}
+
+	if (budget->dvb_frontend == NULL) {
+		printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+		       budget->dev->pci->vendor,
+		       budget->dev->pci->device,
+		       budget->dev->pci->subsystem_vendor,
+		       budget->dev->pci->subsystem_device);
+	} else {
+		if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+			printk("budget-av: Frontend registration failed!\n");
+			if (budget->dvb_frontend->ops->release)
+				budget->dvb_frontend->ops->release(budget->dvb_frontend);
+			budget->dvb_frontend = NULL;
+		}
+	}
+}
 
 static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
 {
@@ -173,7 +376,7 @@ static int budget_patch_attach (struct s
 
         dprintk(2, "budget: %p\n", budget);
 
-        if ((err = ttpci_budget_init (budget, dev, info))) {
+        if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
                 kfree (budget);
                 return err;
         }
@@ -221,11 +424,11 @@ static int budget_patch_attach (struct s
         // Enable RPS1                                                  (rFC p33)
         saa7146_write(dev, MC1, (MASK_13 | MASK_29));
 
-        dvb_add_frontend_ioctls (budget->dvb_adapter,
-                budget_patch_diseqc_ioctl, NULL, budget);
-
         dev->ext_priv = budget;
 
+	budget->dvb_adapter->priv = budget;
+	frontend_init(budget);
+
         return 0;
 }
 
@@ -235,8 +438,7 @@ static int budget_patch_detach (struct s
         struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
         int err;
 
-        dvb_remove_frontend_ioctls (budget->dvb_adapter,
-                budget_patch_diseqc_ioctl, NULL);
+	if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
 
         err = ttpci_budget_deinit (budget);
 
_
