>> 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 <[EMAIL PROTECTED]>
        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 <[EMAIL PROTECTED]>
        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 <[EMAIL PROTECTED]>
        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, &reg);
        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, &reg);
        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, &reg);
        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, &reg);
        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, &reg);
        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, &reg);
                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, &reg);
                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, &reg);
        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, &reg); /* 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, &reg);
                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, &reg); /* 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, &reg);
        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, &reg); /* 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, &reg);
                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, &reg);
        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, &reg);
                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, &reg);
                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, &reg);
                AF901x_SETFIELD(MP2IF_3_EN, reg, 0); /* disable MP2IF */
                af9015_write(v_bus, AF901x_MP2IF_3, reg);
        }
        af9015_read(v_bus, AF901x_MP2IF_2, &reg);
        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, &reg);
        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, &reg);
                /* change output bit to Data 7, for the AF9013 */
                if (!(AF901x_GETFIELD(MP2IF_USB20_MODE, reg))) {
                        af9015_read(v_bus, AF901x_MP2IF_0, &reg);
                        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, &reg);
                AF901x_SETFIELD(MP2IF_3_HALF_PSB, reg, 1);
                af9015_write(v_bus, AF901x_MP2IF_3, reg);

                af9015_read(v_bus, AF901x_TSPARAM, &reg);
                AF901x_SETFIELD(TSPARAM_STOP_EN, reg, 1);
                af9015_write(v_bus, AF901x_TSPARAM, reg);

                af9015_read(v_bus, AF901x_MPEG_FULL_SPEED, &reg);
                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, &reg);
        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, &reg);
        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, &reg);
        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, &reg);
        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, &reg); /* 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, &reg);
        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, &reg);
        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, &reg); /* 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, &reg); /* 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, &reg);
        AF901x_SETFIELD(MP2IF_3_EN, reg, 1); /* enable MP2IF */
        af9015_write(v_bus, AF901x_MP2IF_3, reg);

        af9015_read(v_bus, AF901x_MP2IF_3, &reg);
        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 <[email protected]>\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 <[EMAIL PROTECTED]>");
MODULE_DESCRIPTION("AF9015 DVB-T");
MODULE_LICENSE("GPL");
/*
        AF-9015 Bus Interface Unit driver

        Copyright (c) Manu Abraham <[EMAIL PROTECTED]>
        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 <[EMAIL PROTECTED]>
        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
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

Reply via email to