/* hardware interface struct
 * functions are defined in target tree
 */
struct i2c_struct
{
    int  (*i2c_start)(void);
    void (*i2c_stop)(void);
    int  (*i2c_outb)(unsigned char byte)
    int  (*i2c_inb)(bool ack);
    void (*i2c_hw_init)(void);
}

/* arbitrary choosen */
#define  MAX_I2C_INTERFACES 5
/* global array which holds ptrs to struct with lowlevel,
 * platform specific i2c functions
 */
static const struct i2c_struct *i2c_if[MAX_I2C_INTERFACES];

int i2c_write (int bus_index,
               unsigned char i2c_addr,
               int address,
               const unsigned char *buf,
               int count)
{
    int i;
    int ret = 0;
    const struct i2c_struct *iface = i2c_if[bus_index];

    iface->i2c_start();
    if (!iface->i2c_outb(i2c_address & 0xfe))
    {
        ret = -2;
        goto end;
    }

    if (address != -1)
    {
        if (!iface->i2c_outb(address))
        {
            ret = -3;
            goto end;
        }
    }

    for(i = 0;i < count;i++)
    {
        if (!iface->i2c_outb(buf[i]))
        {
            ret = -4;
            break;
        }
    }

end:
    iface->i2c_stop();
    return ret;
}

int i2c_write (int bus_index,
               unsigned char i2c_addr,
               int address,
               const unsigned char *buf,
               int count)
{  
    int i;
    int ret = 0;
    const struct i2c_struct *iface = i2c_if[bus_index];

    if (address != -1)
    {
        iface->i2c_start();
        if (!iface->i2c_outb(bus_address & 0xfe))
        {
            ret = -2;
            goto end;
        }
        if (!iface->i2c_outb(address))
        {
            ret = -3;
            goto end;
        }
    }

    iface->i2c_start();
    if (!iface->i2c_outb(bus_address | 1))
    {
        ret = -4;
        goto end;
    }

    for(i = 0;i < count-1;i++)
        buf[i] = iface->i2c_inb(true);

    buf[i] = iface->i2c_inb(false);

end:
    iface->i2c_stop();
    return ret;
}

int i2c_register_interface(int bus_index
                           struct i2c_struct *iface)
{
    static unsigned char i2c_num_ifs = 0;

    if ( bus_index < 0 )
    {
        /* assign next free index */
        if (i2c_num_ifs == MAX_I2C_INTERFACES)
            return -1;

        bus_index = i2c_num_ifs++;
    }

    i2c_if[bus_index] = iface;
}

void i2c_init(void)
{
    int i;
    struct i2c_struct *iface;

    for (i=0; i < MAX_I2C_INTERFACES; i++)
    {
        if (i2c_if[i] != NULL)
        {
            iface = i2c_if[i];
            i2c_if->i2c_hw_init();
        }
    }
}