Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[linux-dvb] Improved tda10045h patch
Hi, more improvements:
1) Now tunes properly! Previously it could only tune to certain frequencies
'cos of a rounding bug in the calculations.
2) Made it less noisy so it doesn't print disturbing messages when probing for
a tda10045h fails.
3) Added FIXME comments in appropriate unfinished places.
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-16 14:21:48.000000000 +0100
@@ -0,0 +1,1223 @@
+ /*
+ 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)
+ dprintk("%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) {
+ dprintk("%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)
+{
+ int val;
+ dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg,
+ mask, data);
+
+ // read a byte and check
+ 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)
+{
+ int result;
+ dprintk("%s\n", __FUNCTION__);
+
+ 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 / 1000) * 6) + 217502) / 1000;
+ 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 / 1000) * 6) + 217502) / 1000;
+ 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
+
+ printk("%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;
+ // FIXME: calculate this properly
+
+ // 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;
+ }
+ // FIXME: calculate this properly
+
+ // 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);
+ // FIXME: calculate this properly
+
+ // 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