]> git.proxmox.com Git - mirror_qemu.git/blame - hw/misc/i2c-echo.c
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into...
[mirror_qemu.git] / hw / misc / i2c-echo.c
CommitLineData
b14037f3
KJ
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);