📄 tda1004x.c
字号:
/* Driver for Philips tda1004xh OFDM Frontend (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach 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/hotplug/firmware/tda1004x.bin'. You can also pass the complete file name with the module parameter 'tda1004x_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"#ifndef DVB_TDA1004X_FIRMWARE_FILE#define DVB_TDA1004X_FIRMWARE_FILE "/usr/lib/hotplug/firmware/tda1004x.bin"#endifstatic int tda1004x_debug = 0;static char *tda1004x_firmware = DVB_TDA1004X_FIRMWARE_FILE;#define MC44BC374_ADDRESS 0x65#define TDA1004X_CHIPID 0x00#define TDA1004X_AUTO 0x01#define TDA1004X_IN_CONF1 0x02#define TDA1004X_IN_CONF2 0x03#define TDA1004X_OUT_CONF1 0x04#define TDA1004X_OUT_CONF2 0x05#define TDA1004X_STATUS_CD 0x06#define TDA1004X_CONFC4 0x07#define TDA1004X_DSSPARE2 0x0C#define TDA10045H_CODE_IN 0x0D#define TDA10045H_FWPAGE 0x0E#define TDA1004X_SCAN_CPT 0x10#define TDA1004X_DSP_CMD 0x11#define TDA1004X_DSP_ARG 0x12#define TDA1004X_DSP_DATA1 0x13#define TDA1004X_DSP_DATA2 0x14#define TDA1004X_CONFADC1 0x15#define TDA1004X_CONFC1 0x16#define TDA10045H_S_AGC 0x1a#define TDA10046H_AGC_TUN_LEVEL 0x1a#define TDA1004X_SNR 0x1c#define TDA1004X_CONF_TS1 0x1e#define TDA1004X_CONF_TS2 0x1f#define TDA1004X_CBER_RESET 0x20#define TDA1004X_CBER_MSB 0x21#define TDA1004X_CBER_LSB 0x22#define TDA1004X_CVBER_LUT 0x23#define TDA1004X_VBER_MSB 0x24#define TDA1004X_VBER_MID 0x25#define TDA1004X_VBER_LSB 0x26#define TDA1004X_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 TDA10046H_CONFPLL1 0x2D#define TDA10046H_CONFPLL2 0x2F#define TDA10046H_CONFPLL3 0x30#define TDA10046H_TIME_WREF1 0x31#define TDA10046H_TIME_WREF2 0x32#define TDA10046H_TIME_WREF3 0x33#define TDA10046H_TIME_WREF4 0x34#define TDA10046H_TIME_WREF5 0x35#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 TDA1004X_CONFADC2 0x37#define TDA10045H_IOFFSET 0x38#define TDA10046H_CONF_TRISTATE1 0x3B#define TDA10046H_CONF_TRISTATE2 0x3C#define TDA10046H_CONF_POLARITY 0x3D#define TDA10046H_FREQ_OFFSET 0x3E#define TDA10046H_GPIO_OUT_SEL 0x41#define TDA10046H_GPIO_SELECT 0x42#define TDA10046H_AGC_CONF 0x43#define TDA10046H_AGC_GAINS 0x46#define TDA10046H_AGC_TUN_MIN 0x47#define TDA10046H_AGC_TUN_MAX 0x48#define TDA10046H_AGC_IF_MIN 0x49#define TDA10046H_AGC_IF_MAX 0x4A#define TDA10046H_FREQ_PHY2_MSB 0x4D#define TDA10046H_FREQ_PHY2_LSB 0x4E#define TDA10046H_CVBER_CTRL 0x4F#define TDA10046H_AGC_IF_LEVEL 0x52#define TDA10046H_CODE_CPT 0x57#define TDA10046H_CODE_IN 0x58#define FE_TYPE_TDA10045H 0#define FE_TYPE_TDA10046H 1#define TUNER_TYPE_TD1344 0#define TUNER_TYPE_TD1316 1#define dprintk if (tda1004x_debug) printkstatic struct dvb_frontend_info tda10045h_info = { .name = "Philips TDA10045H", .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO};static struct dvb_frontend_info tda10046h_info = { .name = "Philips TDA10046H", .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_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 tda1004x_state { u8 tda1004x_address; u8 tuner_address; u8 initialised:1; u8 tuner_type:2; u8 fe_type:2;};#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} };static int tda10045h_fwinfo_count = sizeof(tda10045h_fwinfo) / sizeof(struct fwinfo);static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} };static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo);static int errno;static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data){ int ret; u8 buf[] = { reg, data }; struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 }; dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data); msg.addr = tda_state->tda1004x_address; 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 tda1004x_read_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg){ int ret; u8 b0[] = { reg }; u8 b1[] = { 0 }; struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1}, { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}}; dprintk("%s: reg=0x%x\n", __FUNCTION__, reg); msg[0].addr = tda_state->tda1004x_address; msg[1].addr = tda_state->tda1004x_address; 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 tda1004x_write_mask(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, 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 = tda1004x_read_byte(i2c, tda_state, reg); if (val < 0) return val; // mask if off val = val & ~mask; val |= data & 0xff; // write it out again return tda1004x_write_byte(i2c, tda_state, reg, val);}static int tda1004x_write_buf(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, 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 = tda1004x_write_byte(i2c, tda_state, reg + i, buf[i]); if (result != 0) break; } return result;}static int tda1004x_enable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state){ int result; dprintk("%s\n", __FUNCTION__); result = tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 2); dvb_delay(1); return result;}static int tda1004x_disable_tuner_i2c(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state){ dprintk("%s\n", __FUNCTION__); return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0);}static int tda10045h_set_bandwidth(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, fe_bandwidth_t bandwidth){ static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; switch (bandwidth) { case BANDWIDTH_6_MHZ: tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14); tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); break; case BANDWIDTH_7_MHZ: tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x80); tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); break; case BANDWIDTH_8_MHZ: tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14); tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); break; default: return -EINVAL; } tda1004x_write_byte(i2c, tda_state, TDA10045H_IOFFSET, 0); // done return 0;}static int tda10046h_set_bandwidth(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, fe_bandwidth_t bandwidth){ static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e }; static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 }; static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd }; switch (bandwidth) { case BANDWIDTH_6_MHZ: tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0); break; case BANDWIDTH_7_MHZ: tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0); break; case BANDWIDTH_8_MHZ: tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0xFF); break; default: return -EINVAL; } // done return 0;}static int tda1004x_fwupload(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state){ u8 fw_buf[65]; struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = fw_buf,.len = 0 }; unsigned char *firmware = NULL; int filesize; int fd; int fwinfo_idx; int fw_size = 0; int fw_pos, fw_offset; int tx_size; mm_segment_t fs = get_fs(); int dspCodeCounterReg=0, dspCodeInReg=0, dspVersion=0; int fwInfoCount=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -