⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tda1004x.c

📁 linux TV 源码
💻 C
📖 第 1 页 / 共 3 页
字号:
  /*     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 '/etc/dvb/tda1004x.mc'.    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"/** *  a sleeping delay function, waits i ms * */static inlinevoid dvb_delay(int i){	current->state=TASK_INTERRUPTIBLE;	schedule_timeout((HZ*i)/1000);}#ifndef CONFIG_TDA1004X_MC_LOCATION#define CONFIG_TDA1004X_MC_LOCATION "/etc/dvb/tda1004x.mc"#endifstatic int tda1004x_debug = 0;static char *tda1004x_firmware = CONFIG_TDA1004X_MC_LOCATION;#define TDA10045H_ADDRESS        0x08#define TD1344_ADDRESS           0x61#define TDM1316L_ADDRESS         0x63#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 TDA1004X_CODE_IN         0x0D#define TDA1004X_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 TDA1004X_SIGNAL_STRENGTH 0x1a#define TDA1004X_SNR             0x1c#define TDA1004X_REG1E           0x1e#define TDA1004X_REG1F           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 TDA1004X_CONFPLL_P       0x2D#define TDA1004X_CONFPLL_M_MSB   0x2E#define TDA1004X_CONFPLL_M_LSB   0x2F#define TDA1004X_CONFPLL_N       0x30#define TDA1004X_UNSURW_MSB      0x31#define TDA1004X_UNSURW_LSB      0x32#define TDA1004X_WREF_MSB        0x33#define TDA1004X_WREF_MID        0x34#define TDA1004X_WREF_LSB        0x35#define TDA1004X_MUXOUT          0x36#define TDA1004X_CONFADC2        0x37#define TDA1004X_IOFFSET         0x38#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_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 tda1004x_state {	u8 tda1004x_address;	u8 tuner_address;	u8 initialised:1;};#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 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, TDA1004X_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, TDA1004X_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, TDA1004X_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz));		break;	default:		return -EINVAL;	}	tda1004x_write_byte(i2c, tda_state, TDA1004X_IOFFSET, 0);        // done        return 0;}static int tda1004x_init(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 };	struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = 0,.len = 0 };	unsigned char *firmware = NULL;	int filesize;	int fd;	int fwinfo_idx;	int fw_size = 0;	int fw_pos;	int tx_size;        static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };	mm_segment_t fs = get_fs();	dprintk("%s\n", __FUNCTION__);	// Load the firmware	set_fs(get_ds());	fd = open(tda1004x_firmware, 0, 0);	if (fd < 0) {		printk("%s: Unable to open firmware %s\n", __FUNCTION__,		       tda1004x_firmware);		return -EIO;	}	filesize = lseek(fd, 0L, 2);	if (filesize <= 0) {		printk("%s: Firmware %s is empty\n", __FUNCTION__,		       tda1004x_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__, tda1004x_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	tda1004x_enable_tuner_i2c(i2c, tda_state);	tuner_msg.addr = MC44BC374_ADDRESS;	tuner_msg.buf = disable_mc44BC374c;	tuner_msg.len = sizeof(disable_mc44BC374c);	if (i2c->xfer(i2c, &tuner_msg, 1) != 1) {		i2c->xfer(i2c, &tuner_msg, 1);	}	tda1004x_disable_tuner_i2c(i2c, tda_state);	// set some valid bandwith parameters        switch(tda_state->tda1004x_address) {        case TDA10045H_ADDRESS:                tda10045h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ);                break;        }	dvb_delay(500);	// do the firmware upload	tda1004x_write_byte(i2c, tda_state, TDA1004X_FWPAGE, 0);        fw_msg.addr = tda_state->tda1004x_address;	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] = TDA1004X_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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -