>> My plan goes this way. >> >> * dvb-usb provides the real I2C bus. >> * the Host BIU is registered, which registers Virtual Bus #0 and #1 >> * the MASTER demod get's attached to VBus #0 - 0 >> * the MASTER tuner get's attached as a SLAVE on to the MASTER demod on >> VBus #0 - 1 >> * the SLAVE demod get's attached to VBus #1 >> * the SLAVE tuner get's attached as a SLAVE on to the SLAVE demod on VBus #1 - 0 >> * firmware is downloaded via VBus #0 to the Host After some efforts, i got to a stage where most things are done, except for some small issues that i find a bit nasty. Most of the nastiness can be seen in af901x_biu.c (i have added in the comments near the relative areas) The major issue that i face is that dvb-usb sees the Bus Interface as 2 objects (in the dual demod configuration), since there are 2 frontend's being attached. (I don't see any clean way where i can do the BIU config and or BIU specific access, which in fact happens only once) Since i got a bit stuck up with frontend attach itself, temporarily left out the firmware copy part. Comments and thoughts would be interesting. Thanks, Manu
/* AF-901x DVB-T demodulator driver Copyright (c) Manu Abraham <abraham.manu@xxxxxxxxx> Copyright (c) AFA Technologies 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. */ #ifndef __AF901x_PRIV_H #define __AF901x_PRIV_H /** * For the USB devices, the i2c_adapter is just virtual * but on the PCIe devices, it is in fact a real bus */ struct af901x_state { struct i2c_adapter *i2c_adapter; struct af901x_config *config; enum fe_status stat; u32 ber; u32 unc; u16 abort_count; struct dvb_frontend frontend; enum fe_modulation constellation; u32 fcw; u8 unplug_th; }; #endif //__AF901x_PRIV_H
/* AF-901x DVB-T demodulator driver Copyright (c) Manu Abraham <abraham.manu@xxxxxxxxx> Copyright (c) AFA Technologies 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. */ #ifndef __AF9015_H #define __AF9015_H #include <linux/dvb/frontend.h> #define AF9015_DEFAULT_TS_PACKT_LEN 64 #define AF9015_DEFAULT_TS_FRAME_SIZE (64 * 188) enum af901x_ts_mode { AF901x_MPEG_PARALLEL = 0, AF901x_MPEG_SERIAL, AF901x_USB, }; enum af901x_f_sample { AF901x_FSAMPLE_28800 = 28800, /* 28.800 MHz */ AF901x_FSAMPLE_20480 = 20480, /* 20.480 MHz */ AF901x_FSAMPLE_28000 = 28000, /* 28.000 MHz */ AF901x_FSAMPLE_25000 = 25000, /* 25.000 MHz */ }; struct af901x_config { u8 addr; u8 slave; u8 eeprom_addr; u8 tuner_addr; // interface setting u32 frame_size; u16 packt_size; /* Initial settings*/ enum fe_bandwidth bandwidth; u32 inversion; // convert to enum enum af901x_ts_mode ts_mode; enum af901x_f_sample f_sample; /* nyquist sampling */ u32 i_freq_0; /* IF 1 */ u32 i_freq_1; /* IF 2 */ // u32 osc_freq; /* OSC freq = nyquist freq */ }; #endif //__AF9015_H
/* AF-9015 Bus Interface Unit driver Copyright (c) Manu Abraham <abraham.manu@xxxxxxxxx> Copyright (c) AFA Technologies 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. */ #include "dvb-usb.h" #include "af9015.h" #include "af9015_fw.h" #include "af9015_priv.h" #include "af901x_reg.h" #include "af901x_priv.h" #include "af9015_rom.h" static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbosity level"); u8 ucSN = 0; /** * NOTE! Currently we do bulk transfers for Control messages * not very sure, whether this is the best approach we should * take. Need to address this thought, once we have settled * with the basic functionality. */ int af9015_biu_read(struct usb_device *udev, struct af9015_biu_msg *msg) { int i, err, length; u8 buf[64]; /* EP 1 IN */ /** * TODO! Probably it might make more sense to replace * the hardcoded length of 255 with the length in the * sent message, ie, msg->len */ err = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, 255, &length, 1000); if (err == 0) { if (length == 0) { printk("%s: Transaction error! length=%d\n", __func__, length); goto exit; } if (buf[0] != (ucSN - 1)) { printk("%s: Sequence error! Seq RD=0x%02x, Expect=0x%02x\n", __func__, buf[0], ucSN); err = -EINVAL; goto exit; } if (buf[1] != 0) { printk("%s: Status check failed! Status=0x%02x\n", __func__, buf[1]); err = -EINVAL; goto exit; } } printk("%s: Data=[", __func__); for (i = 0; i < (msg->length + 2); i++) printk(" 0x%02x ", buf[i]); printk("]\n"); memcpy(msg->data, &buf[2], msg->length); // printk("%s: Data=[0x%02x]\n", __func__, msg->data[0]); return 0; exit: printk("%s: Read Error\n", __func__); return err; } /** * NOTE! Currently we do bulk transfers for Control messages. * not very sure, whether this is the best approach we should * take. Need to address this thought, once we have settled * with the basic functionality. */ int af9015_biu_write(struct usb_device *udev, struct af9015_biu_msg *msg) { int i, err, act_len; u8 biu_msg[64] = {0}; u8 length = 0; biu_msg[0] = msg->biu_cmd; biu_msg[1] = ucSN; biu_msg[2] = msg->addr; biu_msg[3] = msg->reg_addr_msb; /* Register Address (MSB) */ biu_msg[4] = msg->reg_addr_lsb; /* Register Address (LSB) */ biu_msg[5] = 0; /* what to do with MAILBOX[5] commands ? */ biu_msg[6] = msg->addr_length; /* Reg addr bytes = 3, means SLAVE, So what to do ? */ biu_msg[7] = msg->length; /* TODO! Checksum */ // printk("%s: Header = [ ", __func__); // for (i = 0; i < 8; i++) // printk("0x%02x ", biu_msg[i]); // printk("]\n"); switch (msg->biu_cmd) { case AF9015_REQ_FWDOWNLOAD: if (msg->length) /* There are cases with no data */ memcpy(&biu_msg[8], &msg->data[0], msg->length); /* Copy data */ length = 8 + msg->length; break; default: length = 8; break; } printk("%s: Message = [ ", __func__); for (i = 0; i < length; i++) printk("0x%02x ", biu_msg[i]); printk("]\n"); /* EP 2 OUT */ err = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), biu_msg, length, &act_len, 1000); ucSN += 1; return err; } /** * NOTE! This is the BIU protocol what we use. In fact this is not * the default hardware protocol that's defined by the vendor, We * try to make it look a bit nicer, by wrapping it around etc. * Since there is no other documentation other than this, it * is better to have it documented for reference purposes. * Such a rework has been done,such that SLAVE demodulators * are easily separable from Bus Interface Unit (BIU) integrated * demodulators, which brings code reusability, without duplication. * * struct af9015_biu_msg { * u16 addr; // Slave address * enum af9015_biu_cmd biu_cmd; // BIU Command * u16 flags; * #define BIU_RD 0x01 * u8 *data; // Data * u8 length; // Length of data * }; * * Where BIU Commands are defined thus: * * enum af9015_biu_cmd { * AF9015_REQ_CURCONFIG = 0x10, // 1a) Get current config * AF9015_REQ_FWDOWNLOAD = 0x11, // 2a) Download Firmware control messages * AF9015_REQ_CHKSUMCOMPUTE = 0x12, // 3a) Calculate Checksum control messages * AF9015_REQ_BOOTCONTROL = 0x13, // 4a) Boot control messages * AF9015_REQ_BIUMMIO_RD = 0x20, // 5a) USB Memory RD control messages * AF9015_REQ_BIUMMIO_WR = 0x21, // 6a) USB Memory WR control messages * AF9015_REQ_GENERIC_I2C = 0x22, // 7a) General I2C control messages * AF9015_REQ_FWCOPY = 0x23, // 8a) Copy Firmware control messages * AF9015_REQ_SWRESET = 0x25, // 9) Software reset control messages * AF9015_REQ_CMDCTL = 0x26, // 10a) Control unit command conrtol messages * }; * * Where Data is defined thus: * * Byte 0: Register Address (MSB) * Byte 1: Register Address (LSB) * Byte 2: Embedded MailBox Command * Byte 3:+ * --- | * --- | * Byte n:+ Data for internal Memory Mapped Registers */ int af9015_biu_xfer(struct usb_device *udev, struct af9015_biu_msg *msgs, int num) { int ret = 0, i; for (i = 0; i < num; i++) { // printk("%s: Msgs [%d of %d]\n", __func__, i, num); if (msgs[i].flags & BIU_RD) ret = af9015_biu_read(udev, &msgs[i]); else ret = af9015_biu_write(udev, &msgs[i]); if (ret < 0) { printk("%s: Transaction failure\n", __func__); return ret; } } return num; } static int af901x_fw_download(struct usb_device *udev, const struct firmware *fw) { int i, err; u8 config, *fw_array = packetArr; u32 length, blocks, remainder; struct af9015_biu_msg biu_config[] = { { .addr = 0x3a, .biu_cmd = AF9015_REQ_CURCONFIG, .reg_addr_msb = 0, .reg_addr_lsb = 0, .flags = 0, .data = NULL, .length = 0 },{ /* Current configuration */ .addr = 0x3a, .biu_cmd = AF9015_REQ_CURCONFIG, .flags = BIU_RD, .data = &config, .length = 1 } }; struct af9015_biu_msg fw_download = { /* Firmware download */ .addr = 0x3a, .biu_cmd = AF9015_REQ_FWDOWNLOAD, .flags = 0, }; struct af9015_biu_msg boot = { /* Boot demodulator */ .addr = 0x3a, .biu_cmd = AF9015_REQ_BOOTCONTROL, .flags = 0, .data = NULL, .length = 0 }; /* [STEP #1] Read current configuration */ printk("%s: Read current configuration\n", __func__); if ((err = af9015_biu_xfer(udev, biu_config, 2)) != 2) goto exit; if (biu_config[1].data[0] != 1) goto exit; length = sizeof (packetArr) / sizeof (u8); blocks = length / 63; remainder = length % 63; printk("%s: Array length=%d, Blocks=%d, Remainder=%d\n", __func__, length, blocks, remainder); /* [STEP #2] USB firmware download */ fw_download.reg_addr_msb = *(fw_array + 3); fw_download.reg_addr_lsb = *(fw_array + 4); fw_download.length = *(fw_array + 7); fw_download.data = fw_array + 8; for (i = 0; i < blocks; i++) { printk("%s: Transferring FW Blocks [%d of %d]\n", __func__, i, blocks); if ((err = af9015_biu_xfer(udev, &fw_download, 1)) != 1) goto exit; fw_array += 63; fw_download.reg_addr_msb = *(fw_array + 3); fw_download.reg_addr_lsb = *(fw_array + 4); fw_download.length = *(fw_array + 7); fw_download.data = fw_array + 8; } if (remainder) { fw_download.reg_addr_msb = *(fw_array + 3); fw_download.reg_addr_lsb = *(fw_array + 4); fw_download.length = *(fw_array + 7); fw_download.data = fw_array + 8; if ((err = af9015_biu_xfer(udev, &fw_download, 1)) != 1) goto exit; } /* [STEP #3] Boot */ printk("%s: Booting the DSP core\n", __func__); if ((err = af9015_biu_xfer(udev, &boot, 1)) != 1) goto exit; /* [STEP #4] Wait */ msleep(10); /* [STEP #5] Read current configuration */ printk("%s: Read current configuration\n", __func__); if ((err = af9015_biu_xfer(udev, biu_config, 2)) != 2) goto exit; if (biu_config[1].data[0] != 2) { if (biu_config[1].data[0] == 1) printk("%s: DSP Boot Code running still!, :-(\n", __func__); goto exit; } if (biu_config[1].data[0] == 2) printk("%s: DSP Firmware running, we made it through! :)\n", __func__); return 0; exit: printk("%s: ERROR=%d\n", __func__, err); return err; } #define MERC_EEPROM_I2C_ADDR 0x9A50 static int af9015_read_eeprom(struct usb_device *udev, u16 reg, u8 *data) { int err; u8 r_data, addr_len; u8 eeprom_reg[] = { ((reg >> 8) & 0xff), (reg & 0xff), 0x00 }; struct af9015_biu_msg mem_read[] = { { /* Memory read */ .addr = 0x2a, .biu_cmd = AF9015_REQ_BIUMMIO_RD, .reg_addr_msb = ((MERC_EEPROM_I2C_ADDR >> 8) & 0xff), .reg_addr_lsb = (MERC_EEPROM_I2C_ADDR & 0xff), .flags = 0, .data = NULL, .length = 1 },{ .flags = BIU_RD, .data = &r_data, .length = 1 } }; struct af9015_biu_msg eeprom_read[] = { { /* EEPROM read */ .addr = 0xa1, /* EEPROM = 0x50 */ .biu_cmd = AF9015_REQ_GENERIC_I2C, .reg_addr_msb = ((reg >> 8) & 0xff), .reg_addr_lsb = (reg & 0xff), .flags = 0, .data = NULL, .length = 1 },{ .flags = BIU_RD, .data = data, .length = 1 } }; /* [STEP #1] Issue Memory Read Request */ // printk("%s: Memory Read Request @ 0x%02x Reg(MSB)=0x%02x (LSB)=0x%02x\n", // __func__, // 0x2a, // ((MERC_EEPROM_I2C_ADDR >> 8) & 0xff), // (MERC_EEPROM_I2C_ADDR & 0xff)); if ((err = af9015_biu_xfer(udev, mem_read, 2)) != 2) { printk("%s: Memory Read request failed\n", __func__); goto exit; } if (r_data == 0) { printk("%s: Data=0, Unexpected\n", __func__); err = -EIO; goto exit; } if (r_data < 0xa8) { addr_len = 1; } else { addr_len = 2; } eeprom_read[0].addr_length = addr_len; /* [STEP #2] Issue Eeprom Read Request */ // printk("%s: EEPROM Read Request @ 0x%02x Reg (MSB)=0x%02x (LSB)=0x%02x\n", // __func__, eeprom_read[0].addr, ((reg >> 8) & 0xff), (reg & 0xff)); if ((err = af9015_biu_xfer(udev, eeprom_read, 2)) != 2) { printk("%s: EEPROM Read request failed\n", __func__); goto exit; } *data = data[0]; // printk("%s: Data=[0x%02x]\n", __func__, *data); return 0; exit: return err; } static int af9015_get_biu_config(struct af901x_biu *biu, struct af901x_config *dmd_config) { int err; u16 shift = 0; u8 slave = 0; u8 tmp[4]; struct af901x_biu_config *biu_config = &biu->biu_config; biu->dmd_config = dmd_config; #if 0 if (slave) shift = EEPROM_SHIFT; #endif /* IR Table download */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IRMODE, tmp))) { biu_config->ir_mode = tmp[0]; switch (biu_config->ir_mode) { case AF9015_IRMODE_HID: case AF9015_IRMODE_RLC: case AF9015_IRMODE_RC6: if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IRREMOTE, tmp))) { biu_config->ir_type = tmp[0]; switch (biu_config->ir_type) { case AF9015_IR_NEC: printk("%s: IR/HID Mode=(NEC)\n", __func__); break; case AF9015_IR_RC6: printk("%s: IR/HID Mode=(RC6)\n", __func__); break; default: printk("%s: Unknown IR mode\n", __func__); err = -EINVAL; } } break; case AF9015_IRMODE_DISABLED: default: printk("%s: IR mode disabled\n", __func__); break; } } /* Dual TS option */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_TSMODE, tmp))) { biu_config->ts_mode = tmp[0]; printk("%s: Dual TS Mode = 0x%02X\n", __func__, biu_config->ts_mode); } /* MPEG2 I2C addr */ if ((err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_2WIREADDR, tmp))) { biu_config->addr = AF901x_SLAVE_DEMOD_ADDR; printk("%s: EEPROM_2WIREADDR Fail\n", __func__); } biu_config->addr = tmp[0]; printk("%s: 2 wire address = 0x%02x\n", __func__, biu_config->addr); /* SAW filter bandwidth */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_SAWBW1, tmp))) { biu_config->saw_bw = tmp[0]; printk("%s: SAW filter bandwidth = %d Mhz\n", __func__, biu_config->saw_bw); } if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_XTALTYP1, tmp))) { biu_config->osc_type = tmp[0]; switch (biu_config->osc_type) { case 0: dmd_config->f_sample = AF901x_FSAMPLE_28800; break; case 1: dmd_config->f_sample = AF901x_FSAMPLE_20480; break; case 2: dmd_config->f_sample = AF901x_FSAMPLE_28000; break; case 3: dmd_config->f_sample = AF901x_FSAMPLE_25000; break; default: err = -EINVAL; }; printk("%s: Found Xtal Oscillator with freq = %d kHz,\n will use the same frequency for the sampling rate as well.\n", __func__, biu_config->osc_freq); } /* Tuner type */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_TUNERID1, tmp))) { biu_config->tuner = tmp[0]; printk("%s: Tuner type = 0x%02X\n", __func__, biu_config->tuner); switch (biu_config->tuner) { case AF9015_TUNER_MT2060D: printk("%s: Found a MT2060 digital tuner\n", __func__); break; case AF9015_TUNER_MXL5003D: printk("%s: Found a MXL5003 digital tuner\n", __func__); break; case AF9015_TUNER_MXL5005H: printk("%s: Found a MXL5005 Hybrid tuner\n", __func__); break; default: printk("%s: Unknown tuner %d, please report\n", __func__, biu_config->tuner); err = -EINVAL; } } /* IF0 */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF1H, tmp))) biu_config->i_freq_0 = tmp[0]; if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF1L, tmp))) { dmd_config->i_freq_0 <<= 8; dmd_config->i_freq_0 |= tmp[0]; printk("%s: IF0 = %d\n",__func__, dmd_config->i_freq_0); } /* IF1 */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF2H, tmp))) biu_config->i_freq_1 = tmp[0]; if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IF2L, tmp))) { biu_config->i_freq_1 <<= 8; biu_config->i_freq_1 |= tmp[0]; printk("%s: IF1 = %d\n", __func__, biu_config->i_freq_1); } /* MT2060 IF0 */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_MT2060_IF1H, tmp))) biu_config->i_freq_0 = tmp[0]; if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_MT2060_IF1L, tmp))) { biu_config->i_freq_0 <<= 8; biu_config->i_freq_0 |= tmp[0]; printk("%s: MT2060 IF0 = %d\n",__func__, biu_config->i_freq_0); } /* MT2060 IF1 */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_MT2060_IF2H, tmp))) biu_config->i_freq_1 = tmp[0]; if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_MT2060_IF2L, tmp))) { biu_config->i_freq_1 <<= 8; biu_config->i_freq_1 |= tmp[0]; printk("%s: MT2060 IF1 = %d\n", __func__, biu_config->i_freq_1); } /* Spectral inversion */ if (!(err = af9015_read_eeprom(biu->udev->udev, AF9015_CONFIG_ROM_IQINV1, tmp))) { dmd_config->inversion = tmp[0]; printk("%s: Spectral Inversion = 0x%02X\n", __func__, tmp[0]); } return 0; exit: printk("%s: BIU EEPROM read failed err=%d\n", __func__, err); return err; } static int af9015_read(struct i2c_adapter *v_bus, u16 reg, u8 *data) { return 0; } static int af9015_write(struct i2c_adapter *v_bus, u16 reg, u8 data) { return 0; } /* Mode 15 + 13 init config mode */ static int af9015_epconfig_mode_15(struct af901x_biu *biu) { struct i2c_adapter *v_bus = biu->adapter; /* Adapter 0 */ u8 reg, dual = 0; /* TODO! Must move out end point configuration from in here */ // if (state->config->usb_11) { /** NOTE BIU config */ // /** // * We need to put frame sizes and packet sizes // * based on USB mode, ie 1.1/2.0 // */ // } /* TS init */ af9015_read(v_bus, AF901x_MP2IF_2, ®); AF901x_SETFIELD(MP2IF_2_SW_RESET, reg, 1); /* 0xd507 assert EP4 Reset */ af9015_write(v_bus, AF901x_MP2IF_2, reg); af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_SWRST, reg, 1); /* 0xd50b assert EP5 reset */ af9015_write(v_bus, AF901x_MP2IF_3, reg); af9015_read(v_bus, AF901x_TX_ENABLE, ®); AF901x_SETFIELD(TX_ENABLE_EP4, reg, 0); /* 0xdd11 disable EP4 */ af9015_write(v_bus, AF901x_TX_ENABLE, reg); af9015_read(v_bus, AF901x_TX_ENABLE, ®); AF901x_SETFIELD(TX_ENABLE_EP5, reg, 0); /* 0xdd11 disable EP5 */ af9015_write(v_bus, AF901x_TX_ENABLE, reg); af9015_read(v_bus, AF901x_TX_ENABLE, ®); AF901x_SETFIELD(TX_ENABLE_EP4, reg, 1); /* 0xdd11 enable EP4 */ af9015_write(v_bus, AF901x_TX_ENABLE, reg); if (dual) { af9015_read(v_bus, AF901x_TX_ENABLE, ®); AF901x_SETFIELD(TX_ENABLE_EP5, reg, 1); /* 0xdd11 enable EP5 */ af9015_write(v_bus, AF901x_TX_ENABLE, reg); }else { af9015_read(v_bus, AF901x_TX_ENABLE, ®); AF901x_SETFIELD(TX_ENABLE_EP5, reg, 0); /* 0xdd11 disable EP5 */ af9015_write(v_bus, AF901x_TX_ENABLE, reg); } af9015_read(v_bus, AF901x_TX_NAK, ®); AF901x_SETFIELD(TX_NAK_EP4, reg, 0); /* disable EP4 NAK */ if (dual) AF901x_SETFIELD(TX_NAK_EP5, reg, 0); /* disable EP5 NAK */ af9015_write(v_bus, AF901x_TX_NAK, reg); af9015_read(v_bus, AF901x_MP2IF_0, ®); /* 0xd500 */ AF901x_SETFIELD(MP2IF_0_MPEG_PARALLEL, reg, 0); /* disable Parallel mode */ AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL, reg, 0); /* disable Serial mode */ af9015_write(v_bus, AF901x_MP2IF_0, reg); if (dual) { af9015_read(v_bus, AF901x_MP2IF_0, ®); AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL, reg, 1); af9015_write(v_bus, AF901x_MP2IF_0, reg); } af9015_read(v_bus, AF901x_TX_LEN_EP4_LSB, ®); /* EP4 transfer length */ AF901x_SETFIELD(TX_LEN_EP4_LSB, reg, (BYTE0(TX_LEN_EP4_LSB, AF9015_DEFAULT_TS_FRAME_SIZE))); af9015_write(v_bus, AF901x_TX_LEN_EP4_LSB, reg); af9015_read(v_bus, AF901x_TX_LEN_EP4_MSB, ®); AF901x_SETFIELD(TX_LEN_EP4_MSB, reg, (BYTE1(TX_LEN_EP4_MSB, AF9015_DEFAULT_TS_FRAME_SIZE))); af9015_write(v_bus, AF901x_TX_LEN_EP4_MSB, reg); if (dual) { af9015_read(v_bus, AF901x_TX_LEN_EP5_LSB, ®); /* EP5 transfer length */ AF901x_SETFIELD(TX_LEN_EP5_LSB, reg, (BYTE0(TX_LEN_EP5_LSB, AF9015_DEFAULT_TS_FRAME_SIZE))); af9015_write(v_bus, AF901x_TX_LEN_EP5_LSB, reg); af9015_read(v_bus, AF901x_TX_LEN_EP5_MSB, ®); AF901x_SETFIELD(TX_LEN_EP4_MSB, reg, (BYTE1(TX_LEN_EP5_MSB, AF9015_DEFAULT_TS_FRAME_SIZE))); af9015_write(v_bus, AF901x_TX_LEN_EP5_MSB, reg); } af9015_read(v_bus, AF901x_MAX_PACKET_EP4, ®); AF901x_SETFIELD(MAX_PACKET_EP4, reg, AF9015_DEFAULT_TS_PACKT_LEN); af9015_write(v_bus, AF901x_MAX_PACKET_EP4, reg); if (dual) { af9015_read(v_bus, AF901x_MAX_PACKET_EP5, ®); AF901x_SETFIELD(MAX_PACKET_EP5, reg, AF9015_DEFAULT_TS_PACKT_LEN); af9015_write(v_bus, AF901x_MAX_PACKET_EP5, reg); } if (dual) { /* enable MP2IF */ af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_EN, reg, 1); /* enable MP2IF */ af9015_write(v_bus, AF901x_MP2IF_3, reg); } else { af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_EN, reg, 0); /* disable MP2IF */ af9015_write(v_bus, AF901x_MP2IF_3, reg); } af9015_read(v_bus, AF901x_MP2IF_2, ®); AF901x_SETFIELD(MP2IF_2_SW_RESET, reg, 0); /* negate EP4 reset */ af9015_write(v_bus, AF901x_MP2IF_2, reg); af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_SWRST, reg, 0); /* negate EP5 reset */ af9015_write(v_bus, AF901x_MP2IF_3, reg); if (dual) { /* Set Serial output pin of 13 (data7) */ af9015_read(v_bus, AF901x_MP2IF_USB20, ®); /* change output bit to Data 7, for the AF9013 */ if (!(AF901x_GETFIELD(MP2IF_USB20_MODE, reg))) { af9015_read(v_bus, AF901x_MP2IF_0, ®); AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL7, reg, 1); af9015_write(v_bus, AF901x_MP2IF_0, reg); } /* Split 9015 PSB to 1.5k + 0.5k, enable Flow Control */ af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_HALF_PSB, reg, 1); af9015_write(v_bus, AF901x_MP2IF_3, reg); af9015_read(v_bus, AF901x_TSPARAM, ®); AF901x_SETFIELD(TSPARAM_STOP_EN, reg, 1); af9015_write(v_bus, AF901x_TSPARAM, reg); af9015_read(v_bus, AF901x_MPEG_FULL_SPEED, ®); AF901x_SETFIELD(MPEG_FULL_SPEED, reg, 1); af9015_write(v_bus, AF901x_MPEG_FULL_SPEED, reg); } return 0; } /** * NOTE! Mode 17 config * * We don't use this mode on any PC based devices * For a specific consumer handheld device with a * MPEG2 decoder */ static int af9015_epconfig_mode_17(struct af901x_biu *biu) { struct i2c_adapter *v_bus = biu->adapter; /* Adapter 0 */ u8 reg; // if (state->config->usb_11) { /** NOTE BIU config */ // /** // * We need to put frame sizes and packet sizes // * based on USB mode, ie 1.1/2.0 // */ // } af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_SWRST, reg, 1); /* 0xd50b assert EP5 reset */ af9015_write(v_bus, AF901x_MP2IF_3, reg); af9015_read(v_bus, AF901x_TX_ENABLE, ®); AF901x_SETFIELD(TX_ENABLE_EP5, reg, 0); /* 0xdd11 disable EP5 */ af9015_write(v_bus, AF901x_TX_ENABLE, reg); af9015_read(v_bus, AF901x_TX_ENABLE, ®); AF901x_SETFIELD(TX_ENABLE_EP5, reg, 1); /* 0xdd11 enable EP5 */ af9015_write(v_bus, AF901x_TX_ENABLE, reg); af9015_read(v_bus, AF901x_TX_NAK, ®); AF901x_SETFIELD(TX_NAK_EP5, reg, 0); /* disable EP5 NAK */ af9015_write(v_bus, AF901x_TX_NAK, reg); af9015_read(v_bus, AF901x_TX_LEN_EP5_LSB, ®); /* EP5 transfer length */ AF901x_SETFIELD(TX_LEN_EP5_LSB, reg, (BYTE0(TX_LEN_EP5_LSB, AF9015_DEFAULT_TS_FRAME_SIZE))); af9015_write(v_bus, AF901x_TX_LEN_EP5_LSB, reg); af9015_read(v_bus, AF901x_TX_LEN_EP5_MSB, ®); AF901x_SETFIELD(TX_LEN_EP4_MSB, reg, (BYTE1(TX_LEN_EP5_MSB, AF9015_DEFAULT_TS_FRAME_SIZE))); af9015_write(v_bus, AF901x_TX_LEN_EP5_MSB, reg); af9015_read(v_bus, AF901x_MAX_PACKET_EP5, ®); AF901x_SETFIELD(MAX_PACKET_EP5, reg, AF9015_DEFAULT_TS_PACKT_LEN); af9015_write(v_bus, AF901x_MAX_PACKET_EP5, reg); af9015_read(v_bus, AF901x_MP2IF_0, ®); /* 0xd500 */ AF901x_SETFIELD(MP2IF_0_MPEG_SERIAL, reg, 1); /* enable Serial mode */ af9015_write(v_bus, AF901x_MP2IF_0, reg); af9015_read(v_bus, AF901x_MP2IF_0, ®); /* 0xd500 */ AF901x_SETFIELD(MP2IF_0_MPEG_PARALLEL, reg, 0); /* disable Parallel mode */ af9015_write(v_bus, AF901x_MP2IF_0, reg); /* enable MP2IF */ af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_EN, reg, 1); /* enable MP2IF */ af9015_write(v_bus, AF901x_MP2IF_3, reg); af9015_read(v_bus, AF901x_MP2IF_3, ®); AF901x_SETFIELD(MP2IF_3_SWRST, reg, 0); /* negate EP5 reset */ af9015_write(v_bus, AF901x_MP2IF_3, reg); return 0; } extern struct dvb_frontend *af901x_attach(struct i2c_adapter *i2c_adapter, struct af901x_config *config); static int af9015_frontend_attach(struct dvb_usb_adapter *adap) { int err = 0; struct af901x_biu *biu = adap->dev->priv; struct i2c_adapter *i2c = biu->adapter; struct af901x_config demod_config; biu->udev = adap->dev; /** * TODO! Loading defaults, depends on the config * no hardcoded values please */ demod_config.bandwidth = BANDWIDTH_6_MHZ; /** * TODO! *Bloody Hell !* It sucks to do like this * Need to do it in a better way, this is _crap_ */ //------------------------ printk("%s: Initializing I2C\n", __func__); af9015_i2c_init(biu); printk("%s: Retrieving BIU config\n", __func__); af9015_get_biu_config(biu, &demod_config); //------------------------ printk("%s: Attaching Master demodulator\n", __func__); if (!(adap->fe = af901x_attach(i2c, &demod_config))) { printk("%s: AF9015 MASTER demodulator attach failed. :-(\n\n \ This is a very unlikely case, so surely there is a bug\n \ some place. All the singing happens on the\n \ Linux DVB Mailing List <linux-dvb@xxxxxxxxxxx>\n \ Please join the chorus at Linux DVB. ;-)\n", __func__); err = -EIO; goto exit; } printk("%s: AF9015 Master demodulator successfully attached\n", __func__); /** * TODO! How do we attach multiple frontends in our circumstance ? * A bit lost in thoughts, atm. Ever thought about circles ? */ return 0; exit: printk("%s: Quite nasty indeed!\n", __func__); return err; } static int af901x_frontend_attach(struct dvb_usb_adapter *adap) { int err = 0; struct af901x_biu *biu = adap->dev->priv; struct i2c_adapter *i2c = biu->adapter; struct af901x_config demod_config; i2c++; /* Virtual world 1 */ /** * We already initialized I2C and as well * read the BIU config. What to do now ? */ printk("%s: Attaching Slave demodulator\n", __func__); if (!(adap->fe = af901x_attach(i2c, &demod_config))) { printk("%s: AF9015 SLAVE demodulator attach failed.\n", __func__); err = -EIO; goto exit; } printk("%s: AF901x SLAVE demodulator successfully attached\n", __func__); return 0; exit: printk("%s: Quite nasty indeed!\n", __func__); return err; } static struct dvb_usb_device_properties af9015_properties; static struct af9015_biuconfig_mode af9015_ref_pcusb_dev = { .biu_mode = AF9015_BIU_MODE_15, .usb_mode = AF9015_USB_MODE_20 /* TODO! add in demod and tuner I2C addresses */ }; // static struct af9015_biuconfig_mode af9015_azurewave_vp704j = { // .biu_mode = AF9015_BIU_MODE_15, // .usb_mode = AF9015_USB_MODE_20 // /* TODO! add in demod and tuner I2C addresses */ // }; static int af9015_biu_epconfig(struct af901x_biu *biu) { int err = 0; struct af9015_biuconfig_mode *biuconfig_mode = &biu->config_mode; /* TODO! Need to do this conditionally for each device based on ID's */ memcpy(&biuconfig_mode, &af9015_ref_pcusb_dev, sizeof (struct af9015_biuconfig_mode)); switch (biuconfig_mode->biu_mode) { case AF9015_BIU_MODE_15: printk("%s: Using MODE 15\n", __func__); af9015_epconfig_mode_15(biu); break; case AF9015_BIU_MODE_17: printk("%s: Using MODE 17\n", __func__); af9015_epconfig_mode_17(biu); break; default: err = -EINVAL; break; } return err; } static int af9015_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { int err; struct dvb_usb_device *dev; struct af901x_biu *biu; printk("%s: probing for a AF9015\n", __func__); if ((err = dvb_usb_device_init(intf, &af9015_properties, THIS_MODULE, &dev))) printk("%s error %d\n", __FUNCTION__, err); dev = usb_get_intfdata(intf); // biu = dev->priv; // biu->udev = dev; // // printk("%s: Initializing I2C\n", __func__); // af9015_i2c_init(biu); // printk("%s: Retrieving BIU config\n", __func__); // af9015_get_biu_config(biu); // printk("%s: Initializing BIU\n", __func__); // af9015_biu_epconfig(biu); return err; } static void af9015_usb_device_exit(struct usb_interface *intf) { struct af901x_biu *biu; struct dvb_usb_device *dev = usb_get_intfdata(intf); biu = dev->priv; biu->udev = dev; af9015_i2c_exit(biu); dvb_usb_device_exit(intf); } static struct usb_device_id af9015_usb_table[] = { { USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015) }, { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_VP704J) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); static struct dvb_usb_device_properties af9015_properties = { .firmware = "dvb-usb-af9015.fw", .download_firmware = af901x_fw_download, .size_of_priv = sizeof (struct af901x_biu), .no_reconnect = 1, .num_adapters = 1, .adapter = { { .frontend_attach = af9015_frontend_attach, .stream = { .type = USB_BULK, .count = 4, .endpoint = 0x84, .u = { .bulk = { .buffersize = 4096, /* actual size seen is 3948 */ } } }, } }, .num_device_descs = 1, .devices = { { .name = "Afatech 9015 DVB-T", .cold_ids = { af9015_usb_table, NULL }, .warm_ids = { NULL }, },{ NULL }, } }; static struct usb_driver af9015_driver = { #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) .owner = THIS_MODULE, #endif .name = "dvb-usb-af9015", .probe = af9015_usb_probe, .disconnect = af9015_usb_device_exit, .id_table = af9015_usb_table, }; static int __init af9015_init(void) { int result; printk("%s: Initializing AF9015\n", __func__); if ((result = usb_register(&af9015_driver))) { err("usb_register failed. (%d)", result); return result; } return 0; } static void __exit af9015_exit(void) { printk("%s: AF9015 exiting\n", __func__); usb_deregister(&af9015_driver); } module_init(af9015_init); module_exit(af9015_exit); MODULE_AUTHOR("Manu Abraham <abraham.manu@xxxxxxxxx>"); MODULE_DESCRIPTION("AF9015 DVB-T"); MODULE_LICENSE("GPL");
/* AF-9015 Bus Interface Unit driver Copyright (c) Manu Abraham <abraham.manu@xxxxxxxxx> Copyright (c) AFA Technologies 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. */ #include <linux/kernel.h> #include <linux/device.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/i2c.h> #include "af9015_priv.h" #include "dvb-usb.h" #include <linux/mutex.h> /** * NOTE! This is the BIU protocol what we use. In fact this is not * the default hardware protocol that's defined by the vendor, We * try to make it look a bit nicer, by wrapping it around etc. * Since there is no other documentation other than this, it * is better to have it documented for reference purposes. * Such a rework has been done,such that SLAVE demodulators * are easily separable from Bus Interface Unit (BIU) integrated * demodulators, which brings code reusability, without duplication. * * struct af9015_biu_msg { * u16 addr; // Slave address * enum af9015_biu_cmd biu_cmd; // BIU Command * u16 flags; * #define BIU_RD 0x01 * u8 *data; // Data * u8 length; // Length of data * }; * * Where BIU Commands are defined thus: * * enum af9015_biu_cmd { * AF9015_REQ_CURCONFIG = 0x10, // 1a) Get current config * AF9015_REQ_FWDOWNLOAD = 0x11, // 2a) Download Firmware control messages * AF9015_REQ_CHKSUMCOMPUTE = 0x12, // 3a) Calculate Checksum control messages * AF9015_REQ_BOOTCONTROL = 0x13, // 4a) Boot control messages * AF9015_REQ_BIUMMIO_RD = 0x20, // 5a) USB Memory RD control messages * AF9015_REQ_BIUMMIO_WR = 0x21, // 6a) USB Memory WR control messages * AF9015_REQ_GENERIC_I2C = 0x22, // 7a) General I2C control messages * AF9015_REQ_FWCOPY = 0x23, // 8a) Copy Firmware control messages * AF9015_REQ_SWRESET = 0x25, // 9) Software reset control messages * AF9015_REQ_CMDCTL = 0x26, // 10a) Control unit command conrtol messages * }; * * Where Data is defined thus: * * //Byte 0: Bus Interface Unit (BIU) Command * //Byte 1: Register Address (MSB) * //Byte 2: Register Address (LSB) * //Byte 3: Embedded MailBox Command * Byte 0: Register Address (MSB) * Byte 1: Register Address (LSB) * Byte 2: Embedded MailBox Command * Byte 3:+ * --- | * --- | * Byte n:+ Data for internal Memory Mapped Registers */ /** * NOTE! We will ignore the EEPROM for now. Technically it is not * on an I2C bus, but a 2 wire bus, memory mapped. Thus virtual. * Transactions with the EEPROM at the earliest stage where there * wouldn't be any other transactions. In fact the firmware * download would happen much later after the EEPROM transactions. * This is in contradiction to what we do currently. */ static int af9015_read_regs(struct af901x_biu *biu, struct i2c_msg *msgs) { int err = 0; struct af9015_biu_msg msg = { .flags = BIU_RD, .data = msgs[1].buf, .length = msgs[1].len }; if ((err = af9015_biu_read(biu->udev->udev, &msg) < 0)) { printk("%s: Read error\n", __func__); err = -EIO; goto exit; } return 0; exit: return err; } static int af9015_write_regs(struct af901x_biu *biu, struct i2c_msg *msgs, int flags) { int err = 0; u16 reg_addr = 0; struct af9015_biu_msg msg = { .addr = 0x3a, .reg_addr_msb = msgs->buf[0], .reg_addr_lsb = msgs->buf[1], .flags = 0, .data = &msgs->buf[2], .length = msgs->len }; reg_addr |= msgs->buf[0]; reg_addr <<= 8; reg_addr |= msgs->buf[1]; if ((reg_addr == 0xff00) || (reg_addr == 0xae00)) { msg.biu_cmd = AF9015_REQ_CMDCTL; /* looks incorrect */ } else { /** * Any better methods possibles for identification ? * Or can this be made better somehow */ if (flags) msg.biu_cmd = AF9015_REQ_BIUMMIO_RD; else msg.biu_cmd = AF9015_REQ_BIUMMIO_WR; } if ((err = af9015_biu_write(biu->udev->udev, &msg) < 0)) { printk("%s: Write Error\n", __func__); err = -EIO; goto exit; } return 0; exit: return err; } static int af9015_virt_0_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs, int num) { struct af901x_biu *biu; int i, ret = 0; biu = i2c_get_adapdata(i2c); if (mutex_lock_interruptible(&biu->biu_lock)) { printk("%s: Physical Bus in use, will try later\n", __func__); return -ERESTARTSYS; } for (i = 0; i < num; i++) { printk("%s: Msgs [%d of %d]\n", __func__, i, num); if (msgs[i].flags & BIU_RD) ret = af9015_read_regs(biu, msgs); else /** * NOTE! Doubting Thomas * * Internally write needs to know whether we are writing * for a pure write or a partial write for a read * in case of read, we identify the operation as a write * operation for a read. * Write (Flags = 0), Read (Flags = 1) * Also we do not have the READ flag in the first message * First message always contains the partial write and * hence therefore i + 1 */ ret = af9015_write_regs(biu, msgs, msgs[i + 1].flags); if (ret < 0) { printk("%s: Transaction failure\n", __func__); return ret; } } mutex_unlock(&biu->biu_lock); return num; } static int af9015_virt_1_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { return 0; } static int af9015_virt_2_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { return 0; } static u32 af9015_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; } static struct i2c_algorithm af9015_algo[] = { { .master_xfer = af9015_virt_0_xfer, .functionality = af9015_i2c_func, },{ .master_xfer = af9015_virt_1_xfer, .functionality = af9015_i2c_func, },{ .master_xfer = af9015_virt_2_xfer, .functionality = af9015_i2c_func, } }; #define I2C_HW_B_AF9015 0x30 static struct i2c_adapter af9015_i2c_adapter[] = { { .owner = THIS_MODULE, .name = "AF9015 Virual Adapter-0", .id = I2C_HW_B_AF9015, .class = I2C_CLASS_TV_DIGITAL, .algo = &af9015_algo[0], },{ .owner = THIS_MODULE, .name = "AF9015 Virual Adapter-1", .id = I2C_HW_B_AF9015, .class = I2C_CLASS_TV_DIGITAL, .algo = &af9015_algo[1], },{ .owner = THIS_MODULE, .name = "AF9015 Virual Adapter-2", .id = I2C_HW_B_AF9015, .class = I2C_CLASS_TV_DIGITAL, .algo = &af9015_algo[2], } }; #define AF9015_MAX_VIRTUAL_ADAPTERS 3 int __devinit af9015_i2c_init(struct af901x_biu *biu) { struct i2c_adapter *i2c = biu->adapter; int i, err; for (i = 0; i < AF9015_MAX_VIRTUAL_ADAPTERS; i++) { printk("%s: Initializing adapter %d\n", __func__, i); mutex_init(&biu->biu_lock); memcpy(i2c, &af9015_i2c_adapter[i], sizeof (struct i2c_adapter)); i2c_set_adapdata(i2c, biu); i2c->dev.parent = &biu->udev->udev->dev; if ((err = i2c_add_adapter(i2c)) < 0) { printk("%s: Adapter %d init failed\n", __func__, i); goto exit; } i2c++; } printk("%s: Initializing Virtual adapters\n", __func__); return 0; exit: return err; } int __devexit af9015_i2c_exit(struct af901x_biu *biu) { struct i2c_adapter *i2c = biu->adapter; int i, err; for (i = 0; i < AF9015_MAX_VIRTUAL_ADAPTERS; i++) { err = i2c_del_adapter(i2c); i2c++; } return 0; }
/* AF-9015 Bus Interface Unit driver Copyright (c) Manu Abraham <abraham.manu@xxxxxxxxx> Copyright (c) AFA Technologies 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. */ #ifndef __AF9015_PRIV_H #define __AF9015_PRIV_H #include <linux/usb.h> #include "af9015.h" enum af9015_tuner_types { AF9015_TUNER_MT2060D = 130, AF9015_TUNER_MXL5003D = 3, AF9015_TUNER_MXL5005H = 13, #if 0 AF9015_TUNER_QT1010 = xxx AF9015_TUNER_MC44S802 = xxx AF9015_TUNER_MC44S803 = xxx #endif }; enum af9015_ir_types { AF9015_IR_NEC = 0, AF9015_IR_RC6, }; enum af9015_ir_mode { AF9015_IRMODE_DISABLED = 0, AF9015_IRMODE_HID, AF9015_IRMODE_RLC, AF9015_IRMODE_RC6 }; /** * Mode 15: Used normally in PC applications * either USB mode or SERIAL mode * Mode 17: Used in consumer devices with a MPEG decoder * USB mode alongwith a SERIAL mode */ enum af9015_biu_mode { AF9015_BIU_MODE_15 = 1, AF9015_BIU_MODE_17 }; /** * Mode 11: USB 1.1 mode application * Mode 20: USB 2.0 mode application */ enum af9015_usb_mode { AF9015_USB_MODE_11 = 1, AF9015_USB_MODE_20 }; struct af901x_biu_config { // will change it state (biu_state) struct af901x_state *state; // u8 ir_mode; /* from EEPROM, must go out */ enum af9015_ir_mode ir_mode; u8 ts_mode; /* from EEPROM, must go out */ u8 addr; u8 saw_bw; /* from EEPROM, must go out */ u8 osc_type; /*from EEPROM, must go out */ enum af9015_tuner_types tuner; /* from EEPROM, must go out */ enum af9015_ir_types ir_type; /* from EEPROM, must go out */ u32 osc_freq; /* from EEPROM, must go out */ u16 i_freq_0; /* IF 1 */ /* from EEPROM, must go out */ u16 i_freq_1; /* IF 2 */ /* from EEPROM, must go out */ u8 inversion; /* from EEPROM, must go out */ // u8 usb_11; // This is static }; struct af9015_biuconfig_mode { enum af9015_biu_mode biu_mode; enum af9015_usb_mode usb_mode; }; struct af901x_biu { struct dvb_usb_adapter *usb_adapter; struct dvb_usb_device *udev; struct i2c_adapter *i2c; /* we are in the real world */ struct mutex biu_lock; struct i2c_adapter adapter[2]; /* explore virtual worlds */ struct af901x_state *state; struct af901x_config *dmd_config; struct af901x_biu_config biu_config; struct af9015_biuconfig_mode config_mode; u8 biu_seq; }; enum af9015_biu_cmd { AF9015_REQ_CURCONFIG = 0x10, /* 1a) Get current config */ AF9015_REQ_FWDOWNLOAD = 0x11, /* 2a) Download Firmware control messages */ AF9015_REQ_CHKSUMCOMPUTE = 0x12, /* 3a) Calculate Checksum control messages */ AF9015_REQ_BOOTCONTROL = 0x13, /* 4a) Boot control messages */ AF9015_REQ_BIUMMIO_RD = 0x20, /* 5a) USB Memory RD control messages */ AF9015_REQ_BIUMMIO_WR = 0x21, /* 6a) USB Memory WR control messages */ AF9015_REQ_GENERIC_I2C = 0x22, /* 7a) General I2C control messages */ AF9015_REQ_FWCOPY = 0x23, /* 8a) Copy Firmware control messages */ AF9015_REQ_FWVERSION = 0x24, AF9015_REQ_SWRESET = 0x25, /* 9) Software reset control messages */ AF9015_REQ_CMDCTL = 0x26, /* 10a) Control unit command conrtol messages */ AF9015_REQ_PROPRIETARY_IR = 0x27, AF9015_REQ_FWRELINK = 0x5a }; struct af9015_biu_msg { u16 addr; /* Slave address */ enum af9015_biu_cmd biu_cmd; /* Command */ // u8 sequence; // for read u8 reg_addr_msb; // Temporary u8 reg_addr_lsb; // Temporary u8 addr_length; /* page offset */ u16 flags; #define BIU_RD 0x01 u8 *data; /* Data */ u16 length; /* Length of data */ }; #define AF9015_ERROR 0 #define AF9015_NOTICE 1 #define AF9015_INFO 2 #define AF9015_DEBUG 3 #define dprint(x, y, z, format, arg...) do { \ if (z) { \ if ((x > AF9015_ERROR) && (x > y)) \ printk(AF9015_ERR "%s (%d): " format "\n", __func__, state->num, ##arg);\ else if ((x > AF9015_NOTICE) && (x > y)) \ printk(AF9015_ERR "%s (%d): " format "\n", __func__, state->num, ##arg);\ else if ((x > AF9015_INFO) && (x > y)) \ printk(AF9015_ERR "%s (%d): " format "\n", __func__, state->num, ##arg);\ else if ((x > AF9015_DEBUG) && (x > y)) \ printk(AF9015_ERR "%s (%d): " format "\n", __func__, state->num, ##arg);\ } else { \ if (x > y) \ printk(format, ##arg); \ } \ } while (0); #define AF901x_GETFIELD(bitf, val) ((val >> AF901x_OFFST_##bitf) & \ ((1 << AF901x_WIDTH_##bitf) - 1)) #define AF901x_SETFIELD(bitf, mask, val)(mask = (mask & (~(((1 << AF901x_WIDTH_##bitf) - 1)<< \ AF901x_OFFST_##bitf))) | (val << AF901x_OFFST_##bitf)) struct af901x_reg { u16 reg_addr; u8 pos; u8 len; u8 val; }; #define AF901x_SLAVE_DEMOD_ADDR 0x3a #define MERC_ADDR_FW_VER 0x5103 #define MERC_IR_TABLE_BASE_ADDR 0x9A56 #define MERC_ADDR_HW_VER 0x116B #define AF901X_API_VER_0 0 #define AF901X_API_VER_1 1 #define AF901X_API_VER_2 9 #define AF901X_API_VER_3 0 extern int af9015_biu_xfer(struct usb_device *udev, struct af9015_biu_msg *msgs, int num); extern int af9015_i2c_exit(struct af901x_biu *biu); extern int af9015_i2c_init(struct af901x_biu *biu); extern int af9015_biu_read(struct usb_device *udev, struct af9015_biu_msg *msg); extern int af9015_biu_write(struct usb_device *udev, struct af9015_biu_msg *msg); #endif//__AF9015_PRIV_H
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb