qemu/hw/i2c/smbus_slave.c
<<
>>
Prefs
   1/*
   2 * QEMU SMBus device emulation.
   3 *
   4 * This code is a helper for SMBus device emulation.  It implements an
   5 * I2C device inteface and runs the SMBus protocol from the device
   6 * point of view and maps those to simple calls to emulate.
   7 *
   8 * Copyright (c) 2007 CodeSourcery.
   9 * Written by Paul Brook
  10 *
  11 * This code is licensed under the LGPL.
  12 */
  13
  14/* TODO: Implement PEC.  */
  15
  16#include "qemu/osdep.h"
  17#include "hw/hw.h"
  18#include "hw/i2c/i2c.h"
  19#include "hw/i2c/smbus_slave.h"
  20
  21//#define DEBUG_SMBUS 1
  22
  23#ifdef DEBUG_SMBUS
  24#define DPRINTF(fmt, ...) \
  25do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
  26#define BADF(fmt, ...) \
  27do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
  28#else
  29#define DPRINTF(fmt, ...) do {} while(0)
  30#define BADF(fmt, ...) \
  31do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
  32#endif
  33
  34enum {
  35    SMBUS_IDLE,
  36    SMBUS_WRITE_DATA,
  37    SMBUS_READ_DATA,
  38    SMBUS_DONE,
  39    SMBUS_CONFUSED = -1
  40};
  41
  42static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
  43{
  44    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
  45
  46    DPRINTF("Quick Command %d\n", recv);
  47    if (sc->quick_cmd) {
  48        sc->quick_cmd(dev, recv);
  49    }
  50}
  51
  52static void smbus_do_write(SMBusDevice *dev)
  53{
  54    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
  55
  56    DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
  57    if (sc->write_data) {
  58        sc->write_data(dev, dev->data_buf, dev->data_len);
  59    }
  60}
  61
  62static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
  63{
  64    SMBusDevice *dev = SMBUS_DEVICE(s);
  65
  66    switch (event) {
  67    case I2C_START_SEND:
  68        switch (dev->mode) {
  69        case SMBUS_IDLE:
  70            DPRINTF("Incoming data\n");
  71            dev->mode = SMBUS_WRITE_DATA;
  72            break;
  73
  74        default:
  75            BADF("Unexpected send start condition in state %d\n", dev->mode);
  76            dev->mode = SMBUS_CONFUSED;
  77            break;
  78        }
  79        break;
  80
  81    case I2C_START_RECV:
  82        switch (dev->mode) {
  83        case SMBUS_IDLE:
  84            DPRINTF("Read mode\n");
  85            dev->mode = SMBUS_READ_DATA;
  86            break;
  87
  88        case SMBUS_WRITE_DATA:
  89            if (dev->data_len == 0) {
  90                BADF("Read after write with no data\n");
  91                dev->mode = SMBUS_CONFUSED;
  92            } else {
  93                smbus_do_write(dev);
  94                DPRINTF("Read mode\n");
  95                dev->mode = SMBUS_READ_DATA;
  96            }
  97            break;
  98
  99        default:
 100            BADF("Unexpected recv start condition in state %d\n", dev->mode);
 101            dev->mode = SMBUS_CONFUSED;
 102            break;
 103        }
 104        break;
 105
 106    case I2C_FINISH:
 107        if (dev->data_len == 0) {
 108            if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
 109                smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
 110            }
 111        } else {
 112            switch (dev->mode) {
 113            case SMBUS_WRITE_DATA:
 114                smbus_do_write(dev);
 115                break;
 116
 117            case SMBUS_READ_DATA:
 118                BADF("Unexpected stop during receive\n");
 119                break;
 120
 121            default:
 122                /* Nothing to do.  */
 123                break;
 124            }
 125        }
 126        dev->mode = SMBUS_IDLE;
 127        dev->data_len = 0;
 128        break;
 129
 130    case I2C_NACK:
 131        switch (dev->mode) {
 132        case SMBUS_DONE:
 133            /* Nothing to do.  */
 134            break;
 135
 136        case SMBUS_READ_DATA:
 137            dev->mode = SMBUS_DONE;
 138            break;
 139
 140        default:
 141            BADF("Unexpected NACK in state %d\n", dev->mode);
 142            dev->mode = SMBUS_CONFUSED;
 143            break;
 144        }
 145    }
 146
 147    return 0;
 148}
 149
 150static uint8_t smbus_i2c_recv(I2CSlave *s)
 151{
 152    SMBusDevice *dev = SMBUS_DEVICE(s);
 153    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
 154    uint8_t ret = 0xff;
 155
 156    switch (dev->mode) {
 157    case SMBUS_READ_DATA:
 158        if (sc->receive_byte) {
 159            ret = sc->receive_byte(dev);
 160        }
 161        DPRINTF("Read data %02x\n", ret);
 162        break;
 163
 164    default:
 165        BADF("Unexpected read in state %d\n", dev->mode);
 166        dev->mode = SMBUS_CONFUSED;
 167        break;
 168    }
 169
 170    return ret;
 171}
 172
 173static int smbus_i2c_send(I2CSlave *s, uint8_t data)
 174{
 175    SMBusDevice *dev = SMBUS_DEVICE(s);
 176
 177    switch (dev->mode) {
 178    case SMBUS_WRITE_DATA:
 179        DPRINTF("Write data %02x\n", data);
 180        if (dev->data_len >= sizeof(dev->data_buf)) {
 181            BADF("Too many bytes sent\n");
 182        } else {
 183            dev->data_buf[dev->data_len++] = data;
 184        }
 185        break;
 186
 187    default:
 188        BADF("Unexpected write in state %d\n", dev->mode);
 189        break;
 190    }
 191
 192    return 0;
 193}
 194
 195static void smbus_device_class_init(ObjectClass *klass, void *data)
 196{
 197    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
 198
 199    sc->event = smbus_i2c_event;
 200    sc->recv = smbus_i2c_recv;
 201    sc->send = smbus_i2c_send;
 202}
 203
 204bool smbus_vmstate_needed(SMBusDevice *dev)
 205{
 206    return dev->mode != SMBUS_IDLE;
 207}
 208
 209const VMStateDescription vmstate_smbus_device = {
 210    .name = TYPE_SMBUS_DEVICE,
 211    .version_id = 1,
 212    .minimum_version_id = 1,
 213    .fields      = (VMStateField[]) {
 214        VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
 215        VMSTATE_INT32(mode, SMBusDevice),
 216        VMSTATE_INT32(data_len, SMBusDevice),
 217        VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
 218        VMSTATE_END_OF_LIST()
 219    }
 220};
 221
 222static const TypeInfo smbus_device_type_info = {
 223    .name = TYPE_SMBUS_DEVICE,
 224    .parent = TYPE_I2C_SLAVE,
 225    .instance_size = sizeof(SMBusDevice),
 226    .abstract = true,
 227    .class_size = sizeof(SMBusDeviceClass),
 228    .class_init = smbus_device_class_init,
 229};
 230
 231static void smbus_device_register_types(void)
 232{
 233    type_register_static(&smbus_device_type_info);
 234}
 235
 236type_init(smbus_device_register_types)
 237