123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- #include "qemu/osdep.h"
- #include "qemu/timer.h"
- #include "qemu/main-loop.h"
- #include "block/aio.h"
- #include "hw/i2c/i2c.h"
- #define TYPE_I2C_ECHO "i2c-echo"
- OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO)
- enum i2c_echo_state {
- I2C_ECHO_STATE_IDLE,
- I2C_ECHO_STATE_START_SEND,
- I2C_ECHO_STATE_ACK,
- };
- typedef struct I2CEchoState {
- I2CSlave parent_obj;
- I2CBus *bus;
- enum i2c_echo_state state;
- QEMUBH *bh;
- unsigned int pos;
- uint8_t data[3];
- } I2CEchoState;
- static void i2c_echo_bh(void *opaque)
- {
- I2CEchoState *state = opaque;
- switch (state->state) {
- case I2C_ECHO_STATE_IDLE:
- return;
- case I2C_ECHO_STATE_START_SEND:
- if (i2c_start_send_async(state->bus, state->data[0])) {
- goto release_bus;
- }
- state->pos++;
- state->state = I2C_ECHO_STATE_ACK;
- return;
- case I2C_ECHO_STATE_ACK:
- if (state->pos > 2) {
- break;
- }
- if (i2c_send_async(state->bus, state->data[state->pos++])) {
- break;
- }
- return;
- }
- i2c_end_transfer(state->bus);
- release_bus:
- i2c_bus_release(state->bus);
- state->state = I2C_ECHO_STATE_IDLE;
- }
- static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
- {
- I2CEchoState *state = I2C_ECHO(s);
- switch (event) {
- case I2C_START_RECV:
- state->pos = 0;
- break;
- case I2C_START_SEND:
- state->pos = 0;
- break;
- case I2C_FINISH:
- state->pos = 0;
- state->state = I2C_ECHO_STATE_START_SEND;
- i2c_bus_master(state->bus, state->bh);
- break;
- case I2C_NACK:
- break;
- default:
- return -1;
- }
- return 0;
- }
- static uint8_t i2c_echo_recv(I2CSlave *s)
- {
- I2CEchoState *state = I2C_ECHO(s);
- if (state->pos > 2) {
- return 0xff;
- }
- return state->data[state->pos++];
- }
- static int i2c_echo_send(I2CSlave *s, uint8_t data)
- {
- I2CEchoState *state = I2C_ECHO(s);
- if (state->pos > 2) {
- return -1;
- }
- state->data[state->pos++] = data;
- return 0;
- }
- static void i2c_echo_realize(DeviceState *dev, Error **errp)
- {
- I2CEchoState *state = I2C_ECHO(dev);
- BusState *bus = qdev_get_parent_bus(dev);
- state->bus = I2C_BUS(bus);
- state->bh = qemu_bh_new(i2c_echo_bh, state);
- return;
- }
- static void i2c_echo_class_init(ObjectClass *oc, void *data)
- {
- I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
- dc->realize = i2c_echo_realize;
- sc->event = i2c_echo_event;
- sc->recv = i2c_echo_recv;
- sc->send = i2c_echo_send;
- }
- static const TypeInfo i2c_echo = {
- .name = TYPE_I2C_ECHO,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(I2CEchoState),
- .class_init = i2c_echo_class_init,
- };
- static void register_types(void)
- {
- type_register_static(&i2c_echo);
- }
- type_init(register_types);
|