qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

smbus_slave.c (5939B)


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