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

📄 nxt200x.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *    Support for NXT2002 and NXT2004 - VSB/QAM * *    Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com) *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net> *    and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.com) * *    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. **//* *                      NOTES ABOUT THIS DRIVER * * This Linux driver supports: *   B2C2/BBTI Technisat Air2PC - ATSC (NXT2002) *   AverTVHD MCE A180 (NXT2004) *   ATI HDTV Wonder (NXT2004) * * This driver needs external firmware. Please use the command * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to * download/extract the appropriate firmware, and then copy it to * /usr/lib/hotplug/firmware/ or /lib/firmware/ * (depending on configuration of firmware hotplug). */#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"#define CRC_CCIT_MASK 0x1021#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/string.h>#include "dvb_frontend.h"#include "dvb-pll.h"#include "nxt200x.h"struct nxt200x_state {	struct i2c_adapter* i2c;	struct dvb_frontend_ops ops;	const struct nxt200x_config* config;	struct dvb_frontend frontend;	/* demodulator private data */	nxt_chip_type demod_chip;	u8 initialised:1;};static int debug;#define dprintk(args...) \	do { \		if (debug) printk(KERN_DEBUG "nxt200x: " args); \	} while (0)static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len){	int err;	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",			__FUNCTION__, addr, err);		return -EREMOTEIO;	}	return 0;}static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len){	int err;	struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",			__FUNCTION__, addr, err);		return -EREMOTEIO;	}	return 0;}static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, u8 *buf, u8 len){	u8 buf2 [len+1];	int err;	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };	buf2[0] = reg;	memcpy(&buf2[1], buf, len);	if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {		printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",			__FUNCTION__, state->config->demod_address, err);		return -EREMOTEIO;	}	return 0;}static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len){	u8 reg2 [] = { reg };	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },			{ .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };	int err;	if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {		printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",			__FUNCTION__, state->config->demod_address, err);		return -EREMOTEIO;	}	return 0;}static u16 nxt200x_crc(u16 crc, u8 c){	u8 i;	u16 input = (u16) c & 0xFF;	input<<=8;	for(i=0; i<8; i++) {		if((crc^input) & 0x8000)			crc=(crc<<1)^CRC_CCIT_MASK;		else			crc<<=1;		input<<=1;	}	return crc;}static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len){	u8 attr, len2, buf;	dprintk("%s\n", __FUNCTION__);	/* set mutli register register */	nxt200x_writebytes(state, 0x35, &reg, 1);	/* send the actual data */	nxt200x_writebytes(state, 0x36, data, len);	switch (state->demod_chip) {		case NXT2002:			len2 = len;			buf = 0x02;			break;		case NXT2004:			/* probably not right, but gives correct values */			attr = 0x02;			if (reg & 0x80) {				attr = attr << 1;				if (reg & 0x04)					attr = attr >> 1;			}			/* set write bit */			len2 = ((attr << 4) | 0x10) | len;			buf = 0x80;			break;		default:			return -EINVAL;			break;	}	/* set multi register length */	nxt200x_writebytes(state, 0x34, &len2, 1);	/* toggle the multireg write bit */	nxt200x_writebytes(state, 0x21, &buf, 1);	nxt200x_readbytes(state, 0x21, &buf, 1);	switch (state->demod_chip) {		case NXT2002:			if ((buf & 0x02) == 0)				return 0;			break;		case NXT2004:			if (buf == 0)				return 0;			break;		default:			return -EINVAL;			break;	}	printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg);	return 0;}static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len){	int i;	u8 buf, len2, attr;	dprintk("%s\n", __FUNCTION__);	/* set mutli register register */	nxt200x_writebytes(state, 0x35, &reg, 1);	switch (state->demod_chip) {		case NXT2002:			/* set multi register length */			len2 = len & 0x80;			nxt200x_writebytes(state, 0x34, &len2, 1);			/* read the actual data */			nxt200x_readbytes(state, reg, data, len);			return 0;			break;		case NXT2004:			/* probably not right, but gives correct values */			attr = 0x02;			if (reg & 0x80) {				attr = attr << 1;				if (reg & 0x04)					attr = attr >> 1;			}			/* set multi register length */			len2 = (attr << 4) | len;			nxt200x_writebytes(state, 0x34, &len2, 1);			/* toggle the multireg bit*/			buf = 0x80;			nxt200x_writebytes(state, 0x21, &buf, 1);			/* read the actual data */			for(i = 0; i < len; i++) {				nxt200x_readbytes(state, 0x36 + i, &data[i], 1);			}			return 0;			break;		default:			return -EINVAL;			break;	}}static void nxt200x_microcontroller_stop (struct nxt200x_state* state){	u8 buf, stopval, counter = 0;	dprintk("%s\n", __FUNCTION__);	/* set correct stop value */	switch (state->demod_chip) {		case NXT2002:			stopval = 0x40;			break;		case NXT2004:			stopval = 0x10;			break;		default:			stopval = 0;			break;	}	buf = 0x80;	nxt200x_writebytes(state, 0x22, &buf, 1);	while (counter < 20) {		nxt200x_readbytes(state, 0x31, &buf, 1);		if (buf & stopval)			return;		msleep(10);		counter++;	}	printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n");	return;}static void nxt200x_microcontroller_start (struct nxt200x_state* state){	u8 buf;	dprintk("%s\n", __FUNCTION__);	buf = 0x00;	nxt200x_writebytes(state, 0x22, &buf, 1);}static void nxt2004_microcontroller_init (struct nxt200x_state* state){	u8 buf[9];	u8 counter = 0;	dprintk("%s\n", __FUNCTION__);	buf[0] = 0x00;	nxt200x_writebytes(state, 0x2b, buf, 1);	buf[0] = 0x70;	nxt200x_writebytes(state, 0x34, buf, 1);	buf[0] = 0x04;	nxt200x_writebytes(state, 0x35, buf, 1);	buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;	buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;	nxt200x_writebytes(state, 0x36, buf, 9);	buf[0] = 0x80;	nxt200x_writebytes(state, 0x21, buf, 1);	while (counter < 20) {		nxt200x_readbytes(state, 0x21, buf, 1);		if (buf[0] == 0)			return;		msleep(10);		counter++;	}	printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n");	return;}static int nxt200x_writetuner (struct nxt200x_state* state, u8* data){	u8 buf, count = 0;	dprintk("%s\n", __FUNCTION__);	dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);	/* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.	 * direct write is required for Philips TUV1236D and ALPS TDHU2 */	switch (state->demod_chip) {		case NXT2004:			if (i2c_writebytes(state, state->config->pll_address, data, 4))				printk(KERN_WARNING "nxt200x: error writing to tuner\n");			/* wait until we have a lock */			while (count < 20) {				i2c_readbytes(state, state->config->pll_address, &buf, 1);				if (buf & 0x40)					return 0;				msleep(100);				count++;			}			printk("nxt2004: timeout waiting for tuner lock\n");			break;		case NXT2002:			/* set the i2c transfer speed to the tuner */			buf = 0x03;			nxt200x_writebytes(state, 0x20, &buf, 1);			/* setup to transfer 4 bytes via i2c */			buf = 0x04;			nxt200x_writebytes(state, 0x34, &buf, 1);			/* write actual tuner bytes */			nxt200x_writebytes(state, 0x36, data, 4);			/* set tuner i2c address */			buf = state->config->pll_address;			nxt200x_writebytes(state, 0x35, &buf, 1);			/* write UC Opmode to begin transfer */			buf = 0x80;			nxt200x_writebytes(state, 0x21, &buf, 1);			while (count < 20) {				nxt200x_readbytes(state, 0x21, &buf, 1);				if ((buf & 0x80)== 0x00)					return 0;				msleep(100);				count++;			}			printk("nxt2002: timeout error writing tuner\n");			break;		default:			return -EINVAL;			break;	}	return 0;}static void nxt200x_agc_reset(struct nxt200x_state* state){	u8 buf;	dprintk("%s\n", __FUNCTION__);	switch (state->demod_chip) {		case NXT2002:			buf = 0x08;			nxt200x_writebytes(state, 0x08, &buf, 1);			buf = 0x00;			nxt200x_writebytes(state, 0x08, &buf, 1);			break;		case NXT2004:			nxt200x_readreg_multibyte(state, 0x08, &buf, 1);			buf = 0x08;			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);			buf = 0x00;			nxt200x_writereg_multibyte(state, 0x08, &buf, 1);			break;		default:			break;	}	return;}static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw){	struct nxt200x_state* state = fe->demodulator_priv;	u8 buf[3], written = 0, chunkpos = 0;	u16 rambase, position, crc = 0;	dprintk("%s\n", __FUNCTION__);	dprintk("Firmware is %zu bytes\n", fw->size);	/* Get the RAM base for this nxt2002 */	nxt200x_readbytes(state, 0x10, buf, 1);	if (buf[0] & 0x10)		rambase = 0x1000;	else		rambase = 0x0000;	dprintk("rambase on this nxt2002 is %04X\n", rambase);	/* Hold the micro in reset while loading firmware */	buf[0] = 0x80;	nxt200x_writebytes(state, 0x2B, buf, 1);	for (position = 0; position < fw->size; position++) {		if (written == 0) {			crc = 0;			chunkpos = 0x28;			buf[0] = ((rambase + position) >> 8);			buf[1] = (rambase + position) & 0xFF;			buf[2] = 0x81;			/* write starting address */			nxt200x_writebytes(state, 0x29, buf, 3);		}		written++;		chunkpos++;		if ((written % 4) == 0)			nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);		crc = nxt200x_crc(crc, fw->data[position]);		if ((written == 255) || (position+1 == fw->size)) {			/* write remaining bytes of firmware */			nxt200x_writebytes(state, chunkpos+4-(written %4),				&fw->data[position-(written %4) + 1],				written %4);			buf[0] = crc << 8;			buf[1] = crc & 0xFF;			/* write crc */			nxt200x_writebytes(state, 0x2C, buf, 2);			/* do a read to stop things */			nxt200x_readbytes(state, 0x2A, buf, 1);			/* set transfer mode to complete */			buf[0] = 0x80;			nxt200x_writebytes(state, 0x2B, buf, 1);			written = 0;		}	}	return 0;};static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw){	struct nxt200x_state* state = fe->demodulator_priv;	u8 buf[3];	u16 rambase, position, crc=0;	dprintk("%s\n", __FUNCTION__);	dprintk("Firmware is %zu bytes\n", fw->size);	/* set rambase */	rambase = 0x1000;	/* hold the micro in reset while loading firmware */	buf[0] = 0x80;	nxt200x_writebytes(state, 0x2B, buf,1);	/* calculate firmware CRC */	for (position = 0; position < fw->size; position++) {		crc = nxt200x_crc(crc, fw->data[position]);	}	buf[0] = rambase >> 8;	buf[1] = rambase & 0xFF;	buf[2] = 0x81;	/* write starting address */	nxt200x_writebytes(state,0x29,buf,3);	for (position = 0; position < fw->size;) {		nxt200x_writebytes(state, 0x2C, &fw->data[position],			fw->size-position > 255 ? 255 : fw->size-position);		position += (fw->size-position > 255 ? 255 : fw->size-position);	}	buf[0] = crc >> 8;	buf[1] = crc & 0xFF;	dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);	/* write crc */	nxt200x_writebytes(state, 0x2C, buf,2);	/* do a read to stop things */	nxt200x_readbytes(state, 0x2C, buf, 1);	/* set transfer mode to complete */	buf[0] = 0x80;	nxt200x_writebytes(state, 0x2B, buf,1);	return 0;};static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,					     struct dvb_frontend_parameters *p){	struct nxt200x_state* state = fe->demodulator_priv;	u8 buf[4];	/* stop the micro first */	nxt200x_microcontroller_stop(state);	if (state->demod_chip == NXT2004) {		/* make sure demod is set to digital */		buf[0] = 0x04;		nxt200x_writebytes(state, 0x14, buf, 1);		buf[0] = 0x00;		nxt200x_writebytes(state, 0x17, buf, 1);	}	/* get tuning information */	dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);	/* set additional params */	switch (p->u.vsb.modulation) {		case QAM_64:		case QAM_256:			/* Set punctured clock for QAM */			/* This is just a guess since I am unable to test it */			if (state->config->set_ts_params)				state->config->set_ts_params(fe, 1);			/* set input */			if (state->config->set_pll_input)				state->config->set_pll_input(buf, 1);			break;		case VSB_8:			/* Set non-punctured clock for VSB */			if (state->config->set_ts_params)				state->config->set_ts_params(fe, 0);			/* set input */			if (state->config->set_pll_input)				state->config->set_pll_input(buf, 0);			break;		default:			return -EINVAL;			break;	}	/* write frequency information */	nxt200x_writetuner(state, buf);	/* reset the agc now that tuning has been completed */	nxt200x_agc_reset(state);	/* set target power level */	switch (p->u.vsb.modulation) {		case QAM_64:		case QAM_256:			buf[0] = 0x74;			break;		case VSB_8:			buf[0] = 0x70;			break;		default:			return -EINVAL;			break;	}	nxt200x_writebytes(state, 0x42, buf, 1);	/* configure sdm */	switch (state->demod_chip) {		case NXT2002:			buf[0] = 0x87;			break;

⌨️ 快捷键说明

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