/* 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/README.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 */
bool 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_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 = dvb_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
|