Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] New tda10045h patch



Hi, attached is a new tda10045h patch. It fixes the memory leak I described.

I've had some time to test it. I multicasted three streams round my network 
with vls. Normally, it was perfect, but there was the occasional problem.....

Occasionally, vls would report that it encountered a discontinuity in the SI 
information. I'd usually say this was just corruption, but it happens much 
more frequently than normal... say about 4 events in 5 minutes. I usually see 
about one event every few hours.

Anyone else get this? Up to now, I've been using a much older revision of the 
dvb-kernel driver.... this isn't a slight issue with the new code is it? Or 
maybe its some issue with the i2c... vls does poll the frontend status quite 
frequently.

I only have access to the UK DVB-T signals, so I know that tuning to a 8MHz, 
2K transmission mode signal is OK (apart from the issue above).

Robert says his windows code definitely tunes to 7MHz signals.. can someone 
try the linux driver on one of these signals please?
diff -Naur -X diffignore dvb-kernel.orig/build-2.4/Makefile dvb-kernel/build-2.4/Makefile
--- dvb-kernel.orig/build-2.4/Makefile	2003-06-16 10:26:45.000000000 +0100
+++ dvb-kernel/build-2.4/Makefile	2003-06-16 10:05:58.000000000 +0100
@@ -25,7 +25,7 @@
 
 obj-saa7146	:= saa7146.o saa7146_vv.o video-buf.o videodev.o v4l2-common.o v4l1-compat.o
 obj-dvb 	:= dvb-core.o \
- 			stv0299.o  alps_bsrv2.o alps_tdlb7.o alps_tdmb7.o \
+ 			stv0299.o  alps_bsrv2.o alps_tdlb7.o alps_tdmb7.o tda10045h.o \
 			at76c651.o cx24110.o grundig_29504-401.o grundig_29504-491.o \
 			ves1820.o nxt6000.o dvb_dummy_fe.o  \
 			dvb-ttpci-budget.o dvb-ttpci-budget-ci.o dvb-ttpci-budget-av.o \
diff -Naur -X diffignore dvb-kernel.orig/linux/drivers/media/dvb/frontends/Kconfig dvb-kernel/linux/drivers/media/dvb/frontends/Kconfig
--- dvb-kernel.orig/linux/drivers/media/dvb/frontends/Kconfig	2003-04-20 09:15:32.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/frontends/Kconfig	2003-06-12 22:41:13.000000000 +0100
@@ -105,3 +105,12 @@
 	  DVB adapter simply enable all supported frontends, the 
 	  right one will get autodetected.
 
+config DVB_TDA10045H
+	tristate "Frontends with external TDA10045H demodulator (OFDM)"
+	depends on DVB_CORE
+	help
+	  A DVB-T tuner module. Say Y when you want to support this frontend.
+
+	  If you don't know what tuner module is soldered on your 
+	  DVB adapter simply enable all supported frontends, the 
+	  right one will get autodetected.
diff -Naur -X diffignore dvb-kernel.orig/linux/drivers/media/dvb/frontends/Makefile dvb-kernel/linux/drivers/media/dvb/frontends/Makefile
--- dvb-kernel.orig/linux/drivers/media/dvb/frontends/Makefile	2003-04-20 09:15:32.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/frontends/Makefile	2003-06-13 16:49:26.000000000 +0100
@@ -13,3 +13,4 @@
 obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o
 obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o
 obj-$(CONFIG_DVB_VES1820) += ves1820.o
+obj-$(CONFIG_DVB_TDA10045H) += tda10045h.o
diff -Naur -X diffignore dvb-kernel.orig/linux/drivers/media/dvb/frontends/tda10045h.c dvb-kernel/linux/drivers/media/dvb/frontends/tda10045h.c
--- dvb-kernel.orig/linux/drivers/media/dvb/frontends/tda10045h.c	1970-01-01 01:00:00.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/frontends/tda10045h.c	2003-06-14 11:56:16.000000000 +0100
@@ -0,0 +1,1220 @@
+  /*
+     Driver for Philips TDA10045H OFDM Frontend
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published by
+     the Free Software Foundation; either version 2 of the License, or
+     (at your option) any later version.
+
+     This program is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+
+     GNU General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   */
+
+/*
+    This driver needs a copy of the DLL "ttlcdacc.dll" from the Haupauge or Technotrend
+    windows driver saved as '/usr/lib/DVB/driver/frontends/tda10045h.mc'.
+    You can also pass the complete file name with the module parameter 'tda10045h_firmware'.
+  
+    Currently the DLL from v2.15a of the technotrend driver is supported. Other versions can
+    be added reasonably painlessly.
+ 
+    Windows driver URL: http://www.technotrend.de/
+ */
+
+
+#define __KERNEL_SYSCALLS__
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/unistd.h>
+#include <linux/fcntl.h>
+#include <linux/errno.h>
+#include "dvb_frontend.h"
+#include "dvb_functions.h"
+
+static int tda10045h_debug = 0;
+static char *tda10045h_firmware =
+    "/usr/lib/DVB/driver/frontends/tda10045h.mc";
+
+
+#define TDA10045H_ADDRESS           0x08
+#define TDA10045H_TUNERA_ADDRESS    0x61
+#define TDA10045H_TDM1316L_ADDRESS  0x63
+#define TDA10045H_MC44BC374_ADDRESS 0x65
+
+#define TDA10045H_CHIPID        0x00
+#define TDA10045H_AUTO          0x01
+#define TDA10045H_IN_CONF1      0x02
+#define TDA10045H_IN_CONF2      0x03
+#define TDA10045H_OUT_CONF1     0x04
+#define TDA10045H_OUT_CONF2     0x05
+#define TDA10045H_STATUS_CD     0x06
+#define TDA10045H_CONFC4        0x07
+#define TDA10045H_REG0C         0x0C
+#define TDA10045H_CODE_IN       0x0D
+#define TDA10045H_FWPAGE        0x0E
+#define TDA10045H_SCAN_CPT      0x10
+#define TDA10045H_DSP_CMD       0x11
+#define TDA10045H_DSP_ARG       0x12
+#define TDA10045H_DSP_DATA1     0x13
+#define TDA10045H_DSP_DATA2     0x14
+#define TDA10045H_CONFADC1      0x15
+#define TDA10045H_CONFC1        0x16
+#define TDA10045H_SNR           0x1c
+#define TDA10045H_REG1E         0x1e
+#define TDA10045H_REG1F         0x1f
+#define TDA10045H_CBER_MSB      0x21
+#define TDA10045H_CBER_LSB      0x22
+#define TDA10045H_CVBER_LUT     0x23
+#define TDA10045H_VBER_MSB      0x24
+#define TDA10045H_VBER_MID      0x25
+#define TDA10045H_VBER_LSB      0x26
+#define TDA10045H_UNCOR         0x27
+#define TDA10045H_CONFPLL_P     0x2D
+#define TDA10045H_CONFPLL_M_MSB 0x2E
+#define TDA10045H_CONFPLL_M_LSB 0x2F
+#define TDA10045H_CONFPLL_N     0x30
+#define TDA10045H_UNSURW_MSB    0x31
+#define TDA10045H_UNSURW_LSB    0x32
+#define TDA10045H_WREF_MSB      0x33
+#define TDA10045H_WREF_MID      0x34
+#define TDA10045H_WREF_LSB      0x35
+#define TDA10045H_MUXOUT        0x36
+#define TDA10045H_CONFADC2      0x37
+#define TDA10045H_IOFFSET       0x38
+
+
+#define dprintk if (tda10045h_debug) printk
+
+static struct dvb_frontend_info tda10045h_info = {
+	.name = "Philips TDA10045H",
+	.type = FE_OFDM,
+	.frequency_min = 87000000,
+	.frequency_max = 895000000,
+	.frequency_stepsize = 166667,
+	.caps = FE_CAN_INVERSION_AUTO |
+	    FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+	    FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+	    FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+	    FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+};
+
+#pragma pack(1)
+struct tda10045h_state {
+	u8 tuner_address;
+	u8 initialised;
+};
+#pragma pack()
+
+struct fwinfo {
+	int file_size;
+	int fw_offset;
+	int fw_size;
+};
+static struct fwinfo tda10045h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x34cc5,.fw_size = 30555},	/* 2.15a */
+};
+static int tda10045h_fwinfo_count =
+    sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);
+
+
+static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+static u8 bandwidth_8mhz[] =
+    { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 };
+static u8 bandwidth_7mhz[] =
+    { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb };
+static u8 bandwidth_6mhz[] =
+    { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f };
+static u8 tuner_data[] = { 0x0b, 0xf5, 0x88, 0xab, 0x00 };
+static int errno;
+
+static
+int tda10045h_write_byte(struct dvb_i2c_bus *i2c, int reg, int data)
+{
+	int ret;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = {.addr = TDA10045H_ADDRESS,.flags = 0,.buf =
+		    buf,.len = 2
+	};
+
+	dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data);
+
+	ret = i2c->xfer(i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+		       __FUNCTION__, reg, data, ret);
+
+	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
+		reg, data, ret);
+	return (ret != 1) ? -1 : 0;
+}
+
+static
+int tda10045h_read_byte(struct dvb_i2c_bus *i2c, int reg)
+{
+	int ret;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = { {.addr = TDA10045H_ADDRESS,.flags =
+				  0,.buf = b0,.len = 1},
+	{.addr = TDA10045H_ADDRESS,.flags = I2C_M_RD,.buf = b1,.len = 1}
+	};
+
+	dprintk("%s: reg=0x%x\n", __FUNCTION__, reg);
+
+	ret = i2c->xfer(i2c, msg, 2);
+
+	if (ret != 2) {
+		printk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
+		       ret);
+		return -1;
+	}
+
+	dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__,
+		reg, b1[0], ret);
+	return b1[0];
+}
+
+static
+int tda10045h_write_mask(struct dvb_i2c_bus *i2c, int reg, int mask,
+			 int data)
+{
+
+	dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
+		mask, data);
+
+	// read a byte and check
+	int val = tda10045h_read_byte(i2c, reg);
+	if (val < 0)
+		return val;
+
+	// mask if off
+	val = val & ~mask;
+	val |= data & 0xff;
+
+	// write it out again
+	return tda10045h_write_byte(i2c, reg, val);
+}
+
+static
+int tda10045h_write_buf(struct dvb_i2c_bus *i2c, int reg,
+			unsigned char *buf, int len)
+{
+	int i;
+	int result;
+
+	dprintk("%s: reg=0x%x, len=0x%x\n", __FUNCTION__, reg, len);
+
+	result = 0;
+	for (i = 0; i < len; i++) {
+		result = tda10045h_write_byte(i2c, reg + i, buf[i]);
+		if (result != 0)
+			break;
+	}
+
+	return result;
+}
+
+static
+int tda10045h_enable_tuner_i2c(struct dvb_i2c_bus *i2c)
+{
+
+	dprintk("%s\n", __FUNCTION__);
+
+	int result = tda10045h_write_mask(i2c, TDA10045H_CONFC4, 2, 2);
+	dvb_delay(1);
+	return result;
+}
+
+static
+int tda10045h_disable_tuner_i2c(struct dvb_i2c_bus *i2c)
+{
+
+	dprintk("%s\n", __FUNCTION__);
+
+	return tda10045h_write_mask(i2c, TDA10045H_CONFC4, 2, 0);
+}
+
+static
+int tda10045h_dsp_command(struct dvb_i2c_bus *i2c, int cmd, int arg)
+{
+	int counter;
+	int data1;
+	int data2;
+
+	dprintk("%s: cmd=0x%x, arg=0x%x\n", __FUNCTION__, cmd, arg);
+
+	// send command and argument
+	if (tda10045h_write_byte(i2c, TDA10045H_DSP_ARG, arg) < 0)
+		return -1;
+	if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, cmd) < 0)
+		return -1;
+
+	// command retry loop
+	counter = 0;
+	while (counter++ < 5) {
+
+		// read in the two data bytes
+		data1 = tda10045h_read_byte(i2c, TDA10045H_DSP_DATA1);
+		data2 = tda10045h_read_byte(i2c, TDA10045H_DSP_DATA2);
+		if ((data1 < 0) || (data2 < 0))
+			return -1;
+
+		// finshed yet?
+		if (data1 == cmd)
+			continue;
+		if (data2 == arg)
+			continue;
+
+		// OK, resend command
+		if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, cmd) < 0)
+			return -1;
+	}
+
+	// OK, did it work?
+	if (data1 != cmd)
+		return -1;
+	if (data2 != arg)
+		return -1;
+
+	// success
+	return 0;
+}
+
+
+static
+int tda10045h_init(struct dvb_i2c_bus *i2c)
+{
+	int fw_pos;
+	int tx_size;
+	int counter;
+	u8 fw_buf[65];
+	struct i2c_msg fw_msg = {.addr = TDA10045H_ADDRESS,.flags =
+		    0,.buf = fw_buf,.len = 0
+	};
+	struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0
+	};
+	unsigned char *firmware = NULL;
+	int filesize;
+	int fw_size = 0;
+	int fd;
+	int data1;
+	int fwinfo_idx;
+	mm_segment_t fs = get_fs();
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// Load the firmware
+	set_fs(get_ds());
+	fd = open(tda10045h_firmware, 0, 0);
+	if (fd < 0) {
+		printk("%s: Unable to open firmware %s\n", __FUNCTION__,
+		       tda10045h_firmware);
+		return -EIO;
+	}
+	filesize = lseek(fd, 0L, 2);
+	if (filesize <= 0) {
+		printk("%s: Firmware %s is empty\n", __FUNCTION__,
+		       tda10045h_firmware);
+		sys_close(fd);
+		return -EIO;
+	}
+	// find extraction parameters
+	for (fwinfo_idx = 0; fwinfo_idx < tda10045h_fwinfo_count;
+	     fwinfo_idx++) {
+		if (tda10045h_fwinfo[fwinfo_idx].file_size == filesize)
+			break;
+	}
+	if (fwinfo_idx >= tda10045h_fwinfo_count) {
+		printk("%s: Unsupported firmware %s\n", __FUNCTION__,
+		       tda10045h_firmware);
+		sys_close(fd);
+		return -EIO;
+	}
+	fw_size = tda10045h_fwinfo[fwinfo_idx].fw_size;
+
+	// allocate buffer for it
+	firmware = vmalloc(fw_size);
+	if (firmware == NULL) {
+		printk("%s: Out of memory loading firmware\n",
+		       __FUNCTION__);
+		sys_close(fd);
+		return -EIO;
+	}
+	// read it!
+	lseek(fd, tda10045h_fwinfo[fwinfo_idx].fw_offset, 0);
+	if (read(fd, firmware, fw_size) != fw_size) {
+		printk("%s: Failed to read firmware\n", __FUNCTION__);
+		vfree(firmware);
+		sys_close(fd);
+		return -EIO;
+	}
+	sys_close(fd);
+	set_fs(fs);
+
+	// Disable the MC44BC374C
+	tda10045h_enable_tuner_i2c(i2c);
+	tuner_msg.addr = TDA10045H_MC44BC374_ADDRESS;
+	tuner_msg.buf = disable_mc44BC374c;
+	tuner_msg.len = sizeof(disable_mc44BC374c);
+	if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+		if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+			if (firmware)
+				vfree(firmware);
+			return -EIO;
+		}
+	}
+	tda10045h_disable_tuner_i2c(i2c);
+
+	// setup for firmware upload
+	tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P, bandwidth_8mhz,
+			    sizeof(bandwidth_8mhz));
+	tda10045h_write_byte(i2c, TDA10045H_IOFFSET, 0);
+	dvb_delay(500);
+
+	// do the firmware upload
+	tda10045h_write_byte(i2c, TDA10045H_FWPAGE, 0);
+	fw_pos = 0;
+	while (fw_pos != fw_size) {
+		// work out how much to send this time
+		tx_size = fw_size - fw_pos;
+		if (tx_size > 64) {
+			tx_size = 64;
+		}
+		// send the chunk
+		fw_buf[0] = TDA10045H_CODE_IN;
+		memcpy(fw_buf + 1, firmware + fw_pos, tx_size);
+		fw_msg.len = tx_size + 1;
+		if (i2c->xfer(i2c, &fw_msg, 1) != 1) {
+			vfree(firmware);
+			return -EIO;
+		}
+		fw_pos += tx_size;
+
+		dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, fw_pos);
+	}
+	dvb_delay(100);
+	vfree(firmware);
+
+	// Initialise the DSP and check upload was OK
+	tda10045h_write_mask(i2c, TDA10045H_CONFC4, 0x10, 0);
+	tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, 0x67);
+	if ((tda10045h_read_byte(i2c, TDA10045H_DSP_DATA1) != 0x67) ||
+	    (tda10045h_read_byte(i2c, TDA10045H_DSP_DATA2) != 0x2c)) {
+		printk("%s: firmware upload failed!\n", __FUNCTION__);
+		return -EIO;
+	}
+	// tda setup
+	tda10045h_write_byte(i2c, TDA10045H_CONFADC1, 0x2e);
+	tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x40, 0);
+	tda10045h_write_mask(i2c, TDA10045H_CONFC4, 0x20, 0);
+	tda10045h_write_mask(i2c, TDA10045H_VBER_MSB, 0xe0, 0xa0);
+	tda10045h_write_byte(i2c, TDA10045H_REG1F, 0);
+	tda10045h_write_byte(i2c, TDA10045H_REG1E, 0);
+	tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x80, 0x80);
+
+	// DSP init
+	tda10045h_write_mask(i2c, TDA10045H_CONFC4, 0x10, 0);
+	if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, 0x61) < 0)
+		return -1;
+
+	// command retry loop
+	counter = 0;
+	while (counter++ < 5) {
+
+		// read in the data byte
+		data1 = tda10045h_read_byte(i2c, TDA10045H_DSP_DATA1);
+		if (data1 < 0)
+			return data1;
+
+		// finshed yet?
+		if (data1 & 1)
+			continue;
+
+		// OK, resend command
+		if (tda10045h_write_byte(i2c, TDA10045H_DSP_CMD, 0x61) < 0)
+			return -1;
+	}
+	tda10045h_write_byte(i2c, TDA10045H_DSP_DATA1, 0x01);
+	tda10045h_write_byte(i2c, TDA10045H_DSP_DATA2, 0x0e);
+	tda10045h_dsp_command(i2c, 0x69, 0);
+	tda10045h_write_byte(i2c, TDA10045H_DSP_DATA2, 0x01);
+	tda10045h_dsp_command(i2c, 0x69, 1);
+	tda10045h_write_byte(i2c, TDA10045H_DSP_DATA2, 0x03);
+	tda10045h_dsp_command(i2c, 0x69, 2);
+
+	// tda setup
+	tda10045h_write_mask(i2c, TDA10045H_CONFADC2, 0x20, 0x20);
+	tda10045h_write_mask(i2c, TDA10045H_CONFADC1, 0x80, 0);
+	tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x10, 0);
+	tda10045h_write_mask(i2c, TDA10045H_AUTO, 0x10, 0x10);
+	tda10045h_write_mask(i2c, TDA10045H_IN_CONF2, 0xC0, 0x0);
+	tda10045h_write_mask(i2c, TDA10045H_AUTO, 8, 0);
+
+	// done
+	return 0;
+}
+
+static
+int tda10045h_encode_fec(int fec)
+{
+	// convert known FEC values
+	switch (fec) {
+	case FEC_1_2:
+		return 0;
+	case FEC_2_3:
+		return 1;
+	case FEC_3_4:
+		return 2;
+	case FEC_5_6:
+		return 3;
+	case FEC_7_8:
+		return 4;
+	}
+
+	// unsupported
+	return -EINVAL;
+}
+
+static
+int tda10045h_decode_fec(int tdafec)
+{
+	// convert known FEC values
+	switch (tdafec) {
+	case 0:
+		return FEC_1_2;
+	case 1:
+		return FEC_2_3;
+	case 2:
+		return FEC_3_4;
+	case 3:
+		return FEC_5_6;
+	case 4:
+		return FEC_7_8;
+	}
+
+	// unsupported
+	return -1;
+}
+
+static
+int tda10045h_set_frequency(struct dvb_i2c_bus *i2c,
+			    struct tda10045h_state *tda_state,
+			    struct dvb_frontend_parameters *fe_params)
+{
+	int counter, counter2;
+	u8 tuner_buf[5];
+	u8 v1, v2, v3;
+	struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf =
+		    tuner_buf,.len = sizeof(tuner_buf)
+	};
+	int tuner_frequency;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// setup the frequency buffer
+	switch (tda_state->tuner_address) {
+	case TDA10045H_TUNERA_ADDRESS:
+
+		// setup tuner buffer
+		tuner_frequency =
+		    ((fe_params->frequency * 6) + 217502000) / 1000000;
+		tuner_buf[0] = tuner_frequency >> 8;
+		tuner_buf[1] = tuner_frequency & 0xff;
+		tuner_buf[2] = 0x88;
+		if (fe_params->frequency < 550000000) {
+			tuner_buf[3] = 0xab;
+		} else {
+			tuner_buf[3] = 0xeb;
+		}
+
+		// tune it
+		tda10045h_enable_tuner_i2c(i2c);
+		tuner_msg.addr = tda_state->tuner_address;
+		tuner_msg.len = 4;
+		i2c->xfer(i2c, &tuner_msg, 1);
+
+		// wait for it to finish
+		tuner_msg.len = 1;
+		tuner_msg.flags = I2C_M_RD;
+		counter = 0;
+		counter2 = 0;
+		while (counter++ < 100) {
+			if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+				if (tuner_buf[0] & 0x40) {
+					counter2++;
+				} else {
+					counter2 = 0;
+				}
+			}
+
+			if (counter2 > 10) {
+				break;
+			}
+		}
+		tda10045h_disable_tuner_i2c(i2c);
+		break;
+
+	case TDA10045H_TDM1316L_ADDRESS:
+		// determine settings
+		tuner_frequency = fe_params->frequency + 36167000;
+		dprintk("tuner_freq: %i\n", tuner_frequency);
+		if (tuner_frequency < 87000000) {
+			return -EINVAL;
+		} else if (tuner_frequency < 130000000) {
+			v1 = 1;
+			v2 = 3;
+		} else if (tuner_frequency < 160000000) {
+			v1 = 1;
+			v2 = 5;
+		} else if (tuner_frequency < 200000000) {
+			v1 = 1;
+			v2 = 6;
+		} else if (tuner_frequency < 290000000) {
+			v1 = 2;
+			v2 = 3;
+		} else if (tuner_frequency < 420000000) {
+			v1 = 2;
+			v2 = 5;
+		} else if (tuner_frequency < 480000000) {
+			v1 = 2;
+			v2 = 6;
+		} else if (tuner_frequency < 620000000) {
+			v1 = 4;
+			v2 = 3;
+		} else if (tuner_frequency < 830000000) {
+			v1 = 4;
+			v2 = 5;
+		} else if (tuner_frequency < 895000000) {
+			v1 = 4;
+			v2 = 7;
+		} else {
+			return -EINVAL;
+		}
+
+		// work out v3
+		switch (fe_params->u.ofdm.bandwidth) {
+		case BANDWIDTH_6_MHZ:	// FIXME: IS THIS CORRECT???????
+			if (fe_params->frequency <= 300000000) {
+				v3 = 0;
+			} else {
+				v3 = 1;
+			}
+			break;
+
+		case BANDWIDTH_7_MHZ:
+			v3 = 0;
+			break;
+
+		case BANDWIDTH_8_MHZ:
+			v3 = 1;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		// calculate tuner parameters
+		tuner_frequency =
+		    ((fe_params->frequency * 6) + 217502000) / 1000000;
+		tuner_buf[0] = tuner_frequency >> 8;
+		tuner_buf[1] = tuner_frequency & 0xff;
+		tuner_buf[2] = 0xca;
+		tuner_buf[3] = (3 << 5) | (v3 << 3) | v1;
+		tuner_buf[4] = 0x85;
+
+		// tune it
+		tda10045h_enable_tuner_i2c(i2c);
+		tuner_msg.addr = tda_state->tuner_address;
+		tuner_msg.len = 5;
+		if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+			return -EIO;
+		}
+		dvb_delay(50);
+		tuner_buf[3] = (v2 << 5) | (v3 << 3) | v1;
+		if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {
+			return -EIO;
+		}
+		dvb_delay(1);
+		tda10045h_disable_tuner_i2c(i2c);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	dprintk("%s: success\n", __FUNCTION__);
+
+	// done
+	return 0;
+}
+
+static
+int tda10045h_set_fe(struct dvb_i2c_bus *i2c,
+		     struct tda10045h_state *tda_state,
+		     struct dvb_frontend_parameters *fe_params)
+{
+	int tmp;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// set frequency
+	tmp = tda10045h_set_frequency(i2c, tda_state, fe_params);
+	if (tmp < 0)
+		return tmp;
+
+	// Set standard params.. or put them to auto
+	if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) ||
+	    (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) ||
+	    (fe_params->u.ofdm.constellation == QAM_AUTO) ||
+	    (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) {
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 1, 1);	// enable auto
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x03, 0);	// turn off constellation bits
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x60, 0);	// turn off hierarchy bits
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF2, 0x3f, 0);	// turn off FEC bits
+	} else {
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 1, 0);	// disable auto
+
+		// set HP FEC
+		tmp = tda10045h_encode_fec(fe_params->u.ofdm.code_rate_HP);
+		if (tmp < 0)
+			return tmp;
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF2, 7, tmp);
+
+		// set LP FEC
+		if (fe_params->u.ofdm.code_rate_LP != FEC_NONE) {
+			tmp =
+			    tda10045h_encode_fec(fe_params->u.ofdm.
+						 code_rate_LP);
+			if (tmp < 0)
+				return tmp;
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF2,
+					     0x38, tmp << 3);
+		}
+		// set constellation
+		switch (fe_params->u.ofdm.constellation) {
+		case QPSK:
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+					     3, 0);
+			break;
+
+		case QAM_16:
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+					     3, 1);
+			break;
+
+		case QAM_64:
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+					     3, 2);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		// set hierarchy
+		switch (fe_params->u.ofdm.hierarchy_information) {
+		case HIERARCHY_NONE:
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+					     0x60, 0 << 5);
+			break;
+
+		case HIERARCHY_1:
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+					     0x60, 1 << 5);
+			break;
+
+		case HIERARCHY_2:
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+					     0x60, 2 << 5);
+			break;
+
+		case HIERARCHY_4:
+			tda10045h_write_mask(i2c, TDA10045H_IN_CONF1,
+					     0x60, 3 << 5);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	// set bandwidth
+	switch (fe_params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		tda10045h_write_byte(i2c, TDA10045H_REG0C, 0x14);
+		tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P,
+				    bandwidth_6mhz,
+				    sizeof(bandwidth_6mhz));
+		break;
+
+	case BANDWIDTH_7_MHZ:
+		tda10045h_write_byte(i2c, TDA10045H_REG0C, 0x80);
+		tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P,
+				    bandwidth_7mhz,
+				    sizeof(bandwidth_7mhz));
+		break;
+
+	case BANDWIDTH_8_MHZ:
+		tda10045h_write_byte(i2c, TDA10045H_REG0C, 0x14);
+		tda10045h_write_buf(i2c, TDA10045H_CONFPLL_P,
+				    bandwidth_8mhz,
+				    sizeof(bandwidth_8mhz));
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// set inversion
+	switch (fe_params->inversion) {
+	case INVERSION_OFF:
+		tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x20, 0);
+		break;
+
+	case INVERSION_ON:
+		tda10045h_write_mask(i2c, TDA10045H_CONFC1, 0x20, 0x20);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// set guard interval
+	switch (fe_params->u.ofdm.guard_interval) {
+	case GUARD_INTERVAL_1_32:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+				     0 << 2);
+		break;
+
+	case GUARD_INTERVAL_1_16:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+				     1 << 2);
+		break;
+
+	case GUARD_INTERVAL_1_8:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+				     2 << 2);
+		break;
+
+	case GUARD_INTERVAL_1_4:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 0);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+				     3 << 2);
+		break;
+
+	case GUARD_INTERVAL_AUTO:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 2, 2);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x0c,
+				     0 << 2);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// set transmission mode
+	switch (fe_params->u.ofdm.transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 4, 0);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x10,
+				     0 << 4);
+		break;
+
+	case TRANSMISSION_MODE_8K:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 4, 0);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x10,
+				     1 << 4);
+		break;
+
+	case TRANSMISSION_MODE_AUTO:
+		tda10045h_write_mask(i2c, TDA10045H_AUTO, 4, 4);
+		tda10045h_write_mask(i2c, TDA10045H_IN_CONF1, 0x10, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	// reset DSP
+	tda10045h_write_mask(i2c, TDA10045H_CONFC4, 8, 8);
+	tda10045h_write_mask(i2c, TDA10045H_CONFC4, 8, 0);
+	dvb_delay(10);
+
+	// done
+	return 0;
+}
+
+
+static
+int tda10045h_get_fe(struct dvb_i2c_bus *i2c,
+		     struct dvb_frontend_parameters *fe_params)
+{
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// inversion status
+	fe_params->inversion = INVERSION_OFF;
+	if (tda10045h_read_byte(i2c, TDA10045H_CONFC1) & 0x20) {
+		fe_params->inversion = INVERSION_ON;
+	}
+	// bandwidth
+	switch (tda10045h_read_byte(i2c, TDA10045H_WREF_LSB)) {
+	case 0x14:
+		fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+		break;
+	case 0xdb:
+		fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+		break;
+	case 0x4f:
+		fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+		break;
+	}
+
+	// FEC
+	fe_params->u.ofdm.code_rate_HP =
+	    tda10045h_decode_fec(tda10045h_read_byte
+				 (i2c, TDA10045H_OUT_CONF2) & 7);
+	fe_params->u.ofdm.code_rate_LP =
+	    tda10045h_decode_fec((tda10045h_read_byte
+				  (i2c, TDA10045H_OUT_CONF2) >> 3) & 7);
+
+	// constellation
+	switch (tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 3) {
+	case 0:
+		fe_params->u.ofdm.constellation = QPSK;
+		break;
+	case 1:
+		fe_params->u.ofdm.constellation = QAM_16;
+		break;
+	case 2:
+		fe_params->u.ofdm.constellation = QAM_64;
+		break;
+	}
+
+	// transmission mode
+	fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+	if (tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 0x10) {
+		fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+	}
+	// guard interval
+	switch ((tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 0x0c) >>
+		2) {
+	case 0:
+		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	}
+
+	// hierarchy
+	switch ((tda10045h_read_byte(i2c, TDA10045H_OUT_CONF1) & 0x60) >>
+		5) {
+	case 0:
+		fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+		break;
+	case 1:
+		fe_params->u.ofdm.hierarchy_information = HIERARCHY_1;
+		break;
+	case 2:
+		fe_params->u.ofdm.hierarchy_information = HIERARCHY_2;
+		break;
+	case 3:
+		fe_params->u.ofdm.hierarchy_information = HIERARCHY_4;
+		break;
+	}
+
+	// done
+	return 0;
+}
+
+
+static
+int tda10045h_read_status(struct dvb_i2c_bus *i2c, fe_status_t * fe_status)
+{
+	int status;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// read status
+	status = tda10045h_read_byte(i2c, TDA10045H_STATUS_CD);
+	if (status == -1) {
+		return -EIO;
+	}
+	// decode
+	*fe_status = 0;
+	if (status == 0x2f) {
+		*fe_status =
+		    FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+		    FE_HAS_SYNC | FE_HAS_LOCK;
+	}
+	// FIXME: decode statuses better
+
+	dprintk("%s: ------------------ raw_status=0x%x\n", __FUNCTION__, status);
+
+	// success
+	dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status);
+	return 0;
+}
+
+static
+int tda10045h_read_snr(struct dvb_i2c_bus *i2c, u16 * snr)
+{
+	int tmp;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// read it
+	tmp = tda10045h_read_byte(i2c, TDA10045H_SNR);
+	if (tmp < 0)
+		return -EIO;
+
+	// done
+	*snr = tmp;
+	dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr);
+	return 0;
+}
+
+static
+int tda10045h_read_ucblocks(struct dvb_i2c_bus *i2c, u32 * ucblocks)
+{
+	int tmp;
+	int tmp2;
+	int counter;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// read the UCBLOCKS and reset
+	counter = 0;
+	tmp = tda10045h_read_byte(i2c, TDA10045H_UNCOR) & 0x7f;
+	if (tmp < 0)
+		return -EIO;
+	while (counter++ < 5) {
+		tda10045h_write_mask(i2c, TDA10045H_UNCOR, 0x80, 0);
+		tda10045h_write_mask(i2c, TDA10045H_UNCOR, 0x80, 0);
+		tda10045h_write_mask(i2c, TDA10045H_UNCOR, 0x80, 0);
+
+		tmp2 = tda10045h_read_byte(i2c, TDA10045H_UNCOR);
+		if (tmp2 < 0)
+			return -EIO;
+		tmp2 &= 0x7f;
+		if ((tmp2 < tmp) || (tmp2 == 0))
+			break;
+	}
+
+	// done
+	if (tmp != 0x7f) {
+		*ucblocks = tmp;
+	} else {
+		*ucblocks = 0xffffffff;
+	}
+	dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks);
+	return 0;
+}
+
+static
+int tda10045h_read_vber(struct dvb_i2c_bus *i2c, u32 * vber)
+{
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// read it in
+	*vber = 0;
+	*vber |= tda10045h_read_byte(i2c, TDA10045H_VBER_LSB);
+	*vber |= tda10045h_read_byte(i2c, TDA10045H_VBER_MID) << 8;
+	*vber |=
+	    (tda10045h_read_byte(i2c, TDA10045H_VBER_MSB) & 0x0f) << 16;
+
+	// reset counter
+	tda10045h_read_byte(i2c, TDA10045H_CVBER_LUT);
+
+	// done
+	dprintk("%s: vber=0x%x\n", __FUNCTION__, *vber);
+	return 0;
+}
+
+static
+int tda10045h_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+	int status;
+	struct dvb_i2c_bus *i2c = fe->i2c;
+	struct tda10045h_state *tda_state = (struct tda10045h_state *) &(fe->data);
+
+	dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd);
+
+	switch (cmd) {
+	case FE_GET_INFO:
+		memcpy(arg, &tda10045h_info,
+		       sizeof(struct dvb_frontend_info));
+		break;
+
+	case FE_READ_STATUS:
+		return tda10045h_read_status(i2c, (fe_status_t *) arg);
+
+	case FE_READ_BER:
+		return tda10045h_read_vber(i2c, (u32 *) arg);
+
+	case FE_READ_SIGNAL_STRENGTH:
+		// FIXME: implement
+		break;
+
+	case FE_READ_SNR:
+		return tda10045h_read_snr(i2c, (u16 *) arg);
+
+	case FE_READ_UNCORRECTED_BLOCKS:
+		return tda10045h_read_ucblocks(i2c, (u32 *) arg);
+
+	case FE_SET_FRONTEND:
+		return tda10045h_set_fe(i2c, tda_state,
+					(struct dvb_frontend_parameters
+					 *) arg);
+
+	case FE_GET_FRONTEND:
+		return tda10045h_get_fe(i2c,
+					(struct dvb_frontend_parameters
+					 *) arg);
+
+	case FE_SLEEP:
+		break;
+
+	case FE_INIT:
+		// don't bother reinitialising
+		if (tda_state->initialised)
+			return 0;
+
+		// OK, perform initialisation
+		status = tda10045h_init(i2c);
+		if (status == 0)
+			tda_state->initialised = 1;
+		return status;
+
+	case FE_RESET:
+		// reset DSP
+		tda10045h_write_mask(i2c, TDA10045H_CONFC4, 8, 8);
+		tda10045h_write_mask(i2c, TDA10045H_CONFC4, 8, 0);
+		dvb_delay(10);
+
+		// reinitialise
+		tda_state->initialised = 0;
+		status = tda10045h_init(i2c);
+		if (status == 0)
+			tda_state->initialised = 1;
+		return status;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+
+static
+int tda10045h_attach(struct dvb_i2c_bus *i2c)
+{
+	int tuner_address = -1;
+	struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0
+	};
+	struct tda10045h_state tda_state;
+
+	dprintk("%s\n", __FUNCTION__);
+
+	// supported frontend?
+	if (tda10045h_read_byte(i2c, TDA10045H_CHIPID) != 0x25)
+		return -ENODEV;
+
+	// supported tuner?
+	tda10045h_enable_tuner_i2c(i2c);
+	tuner_msg.addr = TDA10045H_TUNERA_ADDRESS;
+	tuner_msg.buf = tuner_data;
+	tuner_msg.len = 4;
+	if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+		tuner_address = TDA10045H_TUNERA_ADDRESS;
+		printk("tda10045h: Detected, tuner type A.\n");
+	} else {
+		tuner_msg.addr = TDA10045H_TDM1316L_ADDRESS;
+		tuner_msg.buf = tuner_data;
+		tuner_msg.len = 5;
+		if (i2c->xfer(i2c, &tuner_msg, 1) == 1) {
+			tuner_address = TDA10045H_TDM1316L_ADDRESS;
+			printk
+			    ("tda10045h: Detected Philips TDM1316L tuner.\n");
+		}
+	}
+	tda10045h_disable_tuner_i2c(i2c);
+
+	// did we find a tuner?
+	if (tuner_address == -1) {
+		printk("tda10045h: Detected, but with unknown tuner.\n");
+		return -ENODEV;
+	}
+	// create state
+	tda_state.tuner_address = tuner_address;
+	tda_state.initialised = 0;
+
+	// register
+	dvb_register_frontend(tda10045h_ioctl, i2c, (void *)(*((u32*) &tda_state)),
+			      &tda10045h_info);
+
+	// success
+	return 0;
+}
+
+
+static
+void tda10045h_detach(struct dvb_i2c_bus *i2c)
+{
+	dprintk("%s\n", __FUNCTION__);
+
+	dvb_unregister_frontend(tda10045h_ioctl, i2c);
+}
+
+
+static
+int __init init_tda10045h(void)
+{
+	return dvb_register_i2c_device(THIS_MODULE, tda10045h_attach,
+				       tda10045h_detach);
+}
+
+
+static
+void __exit exit_tda10045h(void)
+{
+	dvb_unregister_i2c_device(tda10045h_attach);
+}
+
+module_init(init_tda10045h);
+module_exit(exit_tda10045h);
+
+MODULE_DESCRIPTION("Philips TDA10045H DVB-T Frontend");
+MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(tda10045h_debug, "i");
+MODULE_PARM_DESC(tda10045h_debug, "enable verbose debug messages");
+
+MODULE_PARM(tda10045h_firmware, "s");
+MODULE_PARM_DESC(tda10045h_firmware, "where to find the firmware file");
diff -Naur -X diffignore dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget.c dvb-kernel/linux/drivers/media/dvb/ttpci/budget.c
--- dvb-kernel.orig/linux/drivers/media/dvb/ttpci/budget.c	2003-05-20 12:28:54.000000000 +0100
+++ dvb-kernel/linux/drivers/media/dvb/ttpci/budget.c	2003-06-04 18:23:52.000000000 +0100
@@ -198,6 +198,7 @@
 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(ttbt2,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
 /* Uncomment for Budget Patch */
 /*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/
@@ -209,6 +210,7 @@
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
 	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
 	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
+	MAKE_EXTENSION_PCI(ttbt2,  0x13c2, 0x1011),	
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
 	{
 		.vendor    = 0,

Home | Main Index | Thread Index