qemu/hw/misc/i2c-echo.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include "qemu/timer.h"
   3#include "qemu/main-loop.h"
   4#include "block/aio.h"
   5#include "hw/i2c/i2c.h"
   6
   7#define TYPE_I2C_ECHO "i2c-echo"
   8OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO)
   9
  10enum i2c_echo_state {
  11    I2C_ECHO_STATE_IDLE,
  12    I2C_ECHO_STATE_START_SEND,
  13    I2C_ECHO_STATE_ACK,
  14};
  15
  16typedef struct I2CEchoState {
  17    I2CSlave parent_obj;
  18
  19    I2CBus *bus;
  20
  21    enum i2c_echo_state state;
  22    QEMUBH *bh;
  23
  24    unsigned int pos;
  25    uint8_t data[3];
  26} I2CEchoState;
  27
  28static void i2c_echo_bh(void *opaque)
  29{
  30    I2CEchoState *state = opaque;
  31
  32    switch (state->state) {
  33    case I2C_ECHO_STATE_IDLE:
  34        return;
  35
  36    case I2C_ECHO_STATE_START_SEND:
  37        if (i2c_start_send_async(state->bus, state->data[0])) {
  38            goto release_bus;
  39        }
  40
  41        state->pos++;
  42        state->state = I2C_ECHO_STATE_ACK;
  43        return;
  44
  45    case I2C_ECHO_STATE_ACK:
  46        if (state->pos > 2) {
  47            break;
  48        }
  49
  50        if (i2c_send_async(state->bus, state->data[state->pos++])) {
  51            break;
  52        }
  53
  54        return;
  55    }
  56
  57
  58    i2c_end_transfer(state->bus);
  59release_bus:
  60    i2c_bus_release(state->bus);
  61
  62    state->state = I2C_ECHO_STATE_IDLE;
  63}
  64
  65static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
  66{
  67    I2CEchoState *state = I2C_ECHO(s);
  68
  69    switch (event) {
  70    case I2C_START_RECV:
  71        state->pos = 0;
  72
  73        break;
  74
  75    case I2C_START_SEND:
  76        state->pos = 0;
  77
  78        break;
  79
  80    case I2C_FINISH:
  81        state->pos = 0;
  82        state->state = I2C_ECHO_STATE_START_SEND;
  83        i2c_bus_master(state->bus, state->bh);
  84
  85        break;
  86
  87    case I2C_NACK:
  88        break;
  89
  90    default:
  91        return -1;
  92    }
  93
  94    return 0;
  95}
  96
  97static uint8_t i2c_echo_recv(I2CSlave *s)
  98{
  99    I2CEchoState *state = I2C_ECHO(s);
 100
 101    if (state->pos > 2) {
 102        return 0xff;
 103    }
 104
 105    return state->data[state->pos++];
 106}
 107
 108static int i2c_echo_send(I2CSlave *s, uint8_t data)
 109{
 110    I2CEchoState *state = I2C_ECHO(s);
 111
 112    if (state->pos > 2) {
 113        return -1;
 114    }
 115
 116    state->data[state->pos++] = data;
 117
 118    return 0;
 119}
 120
 121static void i2c_echo_realize(DeviceState *dev, Error **errp)
 122{
 123    I2CEchoState *state = I2C_ECHO(dev);
 124    BusState *bus = qdev_get_parent_bus(dev);
 125
 126    state->bus = I2C_BUS(bus);
 127    state->bh = qemu_bh_new(i2c_echo_bh, state);
 128
 129    return;
 130}
 131
 132static void i2c_echo_class_init(ObjectClass *oc, void *data)
 133{
 134    I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc);
 135    DeviceClass *dc = DEVICE_CLASS(oc);
 136
 137    dc->realize = i2c_echo_realize;
 138
 139    sc->event = i2c_echo_event;
 140    sc->recv = i2c_echo_recv;
 141    sc->send = i2c_echo_send;
 142}
 143
 144static const TypeInfo i2c_echo = {
 145    .name = TYPE_I2C_ECHO,
 146    .parent = TYPE_I2C_SLAVE,
 147    .instance_size = sizeof(I2CEchoState),
 148    .class_init = i2c_echo_class_init,
 149};
 150
 151static void register_types(void)
 152{
 153    type_register_static(&i2c_echo);
 154}
 155
 156type_init(register_types);
 157