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

📄 af9005.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* DVB USB compliant Linux driver for the Afatech 9005 * USB1.1 DVB-T receiver. * * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) * * Thanks to Afatech who kindly provided information. * * 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. * * see Documentation/dvb/REDME.dvb-usb for more information */#include "af9005.h"/* debug */int dvb_usb_af9005_debug;module_param_named(debug, dvb_usb_af9005_debug, int, 0644);MODULE_PARM_DESC(debug,		 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."		 DVB_USB_DEBUG_STATUS);/* enable obnoxious led */int dvb_usb_af9005_led = 1;module_param_named(led, dvb_usb_af9005_led, bool, 0644);MODULE_PARM_DESC(led, "enable led (default: 1).");/* eeprom dump */static int dvb_usb_af9005_dump_eeprom;module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);/* remote control decoder */static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len,		u32 *event, int *state);static void *rc_keys;static int *rc_keys_size;u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };struct af9005_device_state {	u8 sequence;	int led_state;};static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,			  u8 *rbuf, u16 rlen, int delay_ms){	int actlen, ret = -ENOMEM;	if (wbuf == NULL || wlen == 0)		return -EINVAL;	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))		return ret;	deb_xfer(">>> ");	debug_dump(wbuf, wlen, deb_xfer);	ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,						    2), wbuf, wlen,			   &actlen, 2000);	if (ret)		err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);	else		ret = actlen != wlen ? -1 : 0;	/* an answer is expected, and no error before */	if (!ret && rbuf && rlen) {		if (delay_ms)			msleep(delay_ms);		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,							    0x01), rbuf,				   rlen, &actlen, 2000);		if (ret)			err("recv bulk message failed: %d", ret);		else {			deb_xfer("<<< ");			debug_dump(rbuf, actlen, deb_xfer);		}	}	mutex_unlock(&d->usb_mutex);	return ret;}static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,			      int readwrite, int type, u8 * values, int len){	struct af9005_device_state *st = d->priv;	u8 obuf[16] = { 0 };	u8 ibuf[17] = { 0 };	u8 command;	int i;	int ret;	if (len < 1) {		err("generic read/write, less than 1 byte. Makes no sense.");		return -EINVAL;	}	if (len > 8) {		err("generic read/write, more than 8 bytes. Not supported.");		return -EINVAL;	}	obuf[0] = 14;		/* rest of buffer length low */	obuf[1] = 0;		/* rest of buffer length high */	obuf[2] = AF9005_REGISTER_RW;	/* register operation */	obuf[3] = 12;		/* rest of buffer length */	obuf[4] = st->sequence++;	/* sequence number */	obuf[5] = (u8) (reg >> 8);	/* register address */	obuf[6] = (u8) (reg & 0xff);	if (type == AF9005_OFDM_REG) {		command = AF9005_CMD_OFDM_REG;	} else {		command = AF9005_CMD_TUNER;	}	if (len > 1)		command |=		    AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;	command |= readwrite;	if (readwrite == AF9005_CMD_WRITE)		for (i = 0; i < len; i++)			obuf[8 + i] = values[i];	else if (type == AF9005_TUNER_REG)		/* read command for tuner, the first byte contains the i2c address */		obuf[8] = values[0];	obuf[7] = command;	ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);	if (ret)		return ret;	/* sanity check */	if (ibuf[2] != AF9005_REGISTER_RW_ACK) {		err("generic read/write, wrong reply code.");		return -EIO;	}	if (ibuf[3] != 0x0d) {		err("generic read/write, wrong length in reply.");		return -EIO;	}	if (ibuf[4] != obuf[4]) {		err("generic read/write, wrong sequence in reply.");		return -EIO;	}	/*	   Windows driver doesn't check these fields, in fact sometimes	   the register in the reply is different that what has been sent	   if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {	   err("generic read/write, wrong register in reply.");	   return -EIO;	   }	   if (ibuf[7] != command) {	   err("generic read/write wrong command in reply.");	   return -EIO;	   }	 */	if (ibuf[16] != 0x01) {		err("generic read/write wrong status code in reply.");		return -EIO;	}	if (readwrite == AF9005_CMD_READ)		for (i = 0; i < len; i++)			values[i] = ibuf[8 + i];	return 0;}int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value){	int ret;	deb_reg("read register %x ", reg);	ret = af9005_generic_read_write(d, reg,					AF9005_CMD_READ, AF9005_OFDM_REG,					value, 1);	if (ret)		deb_reg("failed\n");	else		deb_reg("value %x\n", *value);	return ret;}int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,			       u8 * values, int len){	int ret;	deb_reg("read %d registers %x ", len, reg);	ret = af9005_generic_read_write(d, reg,					AF9005_CMD_READ, AF9005_OFDM_REG,					values, len);	if (ret)		deb_reg("failed\n");	else		debug_dump(values, len, deb_reg);	return ret;}int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value){	int ret;	u8 temp = value;	deb_reg("write register %x value %x ", reg, value);	ret = af9005_generic_read_write(d, reg,					AF9005_CMD_WRITE, AF9005_OFDM_REG,					&temp, 1);	if (ret)		deb_reg("failed\n");	else		deb_reg("ok\n");	return ret;}int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,				u8 * values, int len){	int ret;	deb_reg("write %d registers %x values ", len, reg);	debug_dump(values, len, deb_reg);	ret = af9005_generic_read_write(d, reg,					AF9005_CMD_WRITE, AF9005_OFDM_REG,					values, len);	if (ret)		deb_reg("failed\n");	else		deb_reg("ok\n");	return ret;}int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,			      u8 len, u8 * value){	u8 temp;	int ret;	deb_reg("read bits %x %x %x", reg, pos, len);	ret = af9005_read_ofdm_register(d, reg, &temp);	if (ret) {		deb_reg(" failed\n");		return ret;	}	*value = (temp >> pos) & regmask[len - 1];	deb_reg(" value %x\n", *value);	return 0;}int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,			       u8 len, u8 value){	u8 temp, mask;	int ret;	deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);	if (pos == 0 && len == 8)		return af9005_write_ofdm_register(d, reg, value);	ret = af9005_read_ofdm_register(d, reg, &temp);	if (ret)		return ret;	mask = regmask[len - 1] << pos;	temp = (temp & ~mask) | ((value << pos) & mask);	return af9005_write_ofdm_register(d, reg, temp);}static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,					   u16 reg, u8 * values, int len){	return af9005_generic_read_write(d, reg,					 AF9005_CMD_READ, AF9005_TUNER_REG,					 values, len);}static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,					    u16 reg, u8 * values, int len){	return af9005_generic_read_write(d, reg,					 AF9005_CMD_WRITE,					 AF9005_TUNER_REG, values, len);}int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,				 u8 * values, int len){	/* don't let the name of this function mislead you: it's just used	   as an interface from the firmware to the i2c bus. The actual	   i2c addresses are contained in the data */	int ret, i, done = 0, fail = 0;	u8 temp;	ret = af9005_usb_write_tuner_registers(d, reg, values, len);	if (ret)		return ret;	if (reg != 0xffff) {		/* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */		for (i = 0; i < 200; i++) {			ret =			    af9005_read_ofdm_register(d,						      xd_I2C_i2c_m_status_wdat_done,						      &temp);			if (ret)				return ret;			done = temp & (regmask[i2c_m_status_wdat_done_len - 1]				       << i2c_m_status_wdat_done_pos);			if (done)				break;			fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]				       << i2c_m_status_wdat_fail_pos);			if (fail)				break;			msleep(50);		}		if (i == 200)			return -ETIMEDOUT;		if (fail) {			/* clear write fail bit */			af9005_write_register_bits(d,						   xd_I2C_i2c_m_status_wdat_fail,						   i2c_m_status_wdat_fail_pos,						   i2c_m_status_wdat_fail_len,						   1);			return -EIO;		}		/* clear write done bit */		ret =		    af9005_write_register_bits(d,					       xd_I2C_i2c_m_status_wdat_fail,					       i2c_m_status_wdat_done_pos,					       i2c_m_status_wdat_done_len, 1);		if (ret)			return ret;	}	return 0;}int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,				u8 * values, int len){	/* don't let the name of this function mislead you: it's just used	   as an interface from the firmware to the i2c bus. The actual	   i2c addresses are contained in the data */	int ret, i;	u8 temp, buf[2];	buf[0] = addr;		/* tuner i2c address */	buf[1] = values[0];	/* tuner register */	values[0] = addr + 0x01;	/* i2c read address */	if (reg == APO_REG_I2C_RW_SILICON_TUNER) {		/* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */		ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);		if (ret)			return ret;	}	/* send read command to ofsm */	ret = af9005_usb_read_tuner_registers(d, reg, values, 1);	if (ret)		return ret;	/* check if read done */	for (i = 0; i < 200; i++) {		ret = af9005_read_ofdm_register(d, 0xa408, &temp);		if (ret)			return ret;		if (temp & 0x01)			break;		msleep(50);	}	if (i == 200)		return -ETIMEDOUT;	/* clear read done bit (by writing 1) */	ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);	if (ret)		return ret;	/* get read data (available from 0xa400) */	for (i = 0; i < len; i++) {		ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);		if (ret)			return ret;		values[i] = temp;	}	return 0;}static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,			    u8 * data, int len){	int ret, i;	u8 buf[3];	deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,		reg, len);	debug_dump(data, len, deb_i2c);	for (i = 0; i < len; i++) {		buf[0] = i2caddr;		buf[1] = reg + (u8) i;		buf[2] = data[i];		ret =		    af9005_write_tuner_registers(d,						 APO_REG_I2C_RW_SILICON_TUNER,						 buf, 3);		if (ret) {			deb_i2c("i2c_write failed\n");			return ret;		}	}	deb_i2c("i2c_write ok\n");	return 0;}static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,			   u8 * data, int len){	int ret, i;	u8 temp;	deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);	for (i = 0; i < len; i++) {		temp = reg + i;		ret =		    af9005_read_tuner_registers(d,						APO_REG_I2C_RW_SILICON_TUNER,						i2caddr, &temp, 1);		if (ret) {			deb_i2c("i2c_read failed\n");			return ret;		}		data[i] = temp;	}	deb_i2c("i2c data read: ");	debug_dump(data, len, deb_i2c);	return 0;}static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],			   int num){	/* only implements what the mt2060 module does, don't know how	   to make it really generic */	struct dvb_usb_device *d = i2c_get_adapdata(adap);	int ret;	u8 reg, addr;	u8 *value;	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)		return -EAGAIN;	if (num > 2)		warn("more than 2 i2c messages at a time is not handled yet. TODO.");	if (num == 2) {		/* reads a single register */		reg = *msg[0].buf;		addr = msg[0].addr;		value = msg[1].buf;		ret = af9005_i2c_read(d, addr, reg, value, 1);		if (ret == 0)			ret = 2;	} else {		/* write one or more registers */		reg = msg[0].buf[0];		addr = msg[0].addr;		value = &msg[0].buf[1];		ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);		if (ret == 0)			ret = 1;	}	mutex_unlock(&d->i2c_mutex);	return ret;}static u32 af9005_i2c_func(struct i2c_adapter *adapter){	return I2C_FUNC_I2C;}static struct i2c_algorithm af9005_i2c_algo = {	.master_xfer = af9005_i2c_xfer,	.functionality = af9005_i2c_func,};int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,			int wlen, u8 * rbuf, int rlen){	struct af9005_device_state *st = d->priv;	int ret, i, packet_len;	u8 buf[64];	u8 ibuf[64];	if (wlen < 0) {		err("send command, wlen less than 0 bytes. Makes no sense.");		return -EINVAL;	}	if (wlen > 54) {		err("send command, wlen more than 54 bytes. Not supported.");		return -EINVAL;	}	if (rlen > 54) {		err("send command, rlen more than 54 bytes. Not supported.");		return -EINVAL;	}	packet_len = wlen + 5;	buf[0] = (u8) (packet_len & 0xff);	buf[1] = (u8) ((packet_len & 0xff00) >> 8);	buf[2] = 0x26;		/* packet type */	buf[3] = wlen + 3;	buf[4] = st->sequence++;	buf[5] = command;	buf[6] = wlen;	for (i = 0; i < wlen; i++)		buf[7 + i] = wbuf[i];	ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);	if (ret)		return ret;	if (ibuf[2] != 0x27) {		err("send command, wrong reply code.");		return -EIO;	}	if (ibuf[4] != buf[4]) {		err("send command, wrong sequence in reply.");		return -EIO;	}	if (ibuf[5] != 0x01) {		err("send command, wrong status code in reply.");		return -EIO;	}	if (ibuf[6] != rlen) {		err("send command, invalid data length in reply.");		return -EIO;	}	for (i = 0; i < rlen; i++)		rbuf[i] = ibuf[i + 7];	return 0;}int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,		       int len){	struct af9005_device_state *st = d->priv;	u8 obuf[16], ibuf[14];	int ret, i;	memset(obuf, 0, sizeof(obuf));	memset(ibuf, 0, sizeof(ibuf));	obuf[0] = 14;		/* length of rest of packet low */	obuf[1] = 0;		/* length of rest of packer high */

⌨️ 快捷键说明

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