]> git.proxmox.com Git - mirror_qemu.git/blame - hw/i2c/smbus_slave.c
Revert "vl: Fix to create migration object before block backends again"
[mirror_qemu.git] / hw / i2c / smbus_slave.c
CommitLineData
5fafdf24 1/*
0ff596d0
PB
2 * QEMU SMBus device emulation.
3 *
93198b6c
CM
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 *
0ff596d0
PB
8 * Copyright (c) 2007 CodeSourcery.
9 * Written by Paul Brook
10 *
8e31bf38 11 * This code is licensed under the LGPL.
0ff596d0
PB
12 */
13
14/* TODO: Implement PEC. */
15
0430891c 16#include "qemu/osdep.h"
83c9f4ca 17#include "hw/hw.h"
0d09e41a 18#include "hw/i2c/i2c.h"
93198b6c 19#include "hw/i2c/smbus_slave.h"
0ff596d0
PB
20
21//#define DEBUG_SMBUS 1
22
23#ifdef DEBUG_SMBUS
001faf32
BS
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)
0ff596d0 28#else
001faf32
BS
29#define DPRINTF(fmt, ...) do {} while(0)
30#define BADF(fmt, ...) \
31do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
0ff596d0
PB
32#endif
33
34enum {
35 SMBUS_IDLE,
36 SMBUS_WRITE_DATA,
0ff596d0
PB
37 SMBUS_READ_DATA,
38 SMBUS_DONE,
39 SMBUS_CONFUSED = -1
40};
41
42static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
43{
b5ea9327 44 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
1ea96673 45
0ff596d0 46 DPRINTF("Quick Command %d\n", recv);
b5ea9327
AL
47 if (sc->quick_cmd) {
48 sc->quick_cmd(dev, recv);
49 }
0ff596d0
PB
50}
51
52static void smbus_do_write(SMBusDevice *dev)
53{
b5ea9327 54 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
1ea96673 55
9cf27d74
CM
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);
0ff596d0
PB
59 }
60}
61
d307c28c 62static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
0ff596d0 63{
b5ea9327 64 SMBusDevice *dev = SMBUS_DEVICE(s);
1ea96673 65
0ff596d0
PB
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;
8b38e532 73
0ff596d0
PB
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");
031ac498 85 dev->mode = SMBUS_READ_DATA;
0ff596d0 86 break;
8b38e532 87
0ff596d0
PB
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 {
9cf27d74 93 smbus_do_write(dev);
0ff596d0 94 DPRINTF("Read mode\n");
0ff596d0
PB
95 dev->mode = SMBUS_READ_DATA;
96 }
97 break;
8b38e532 98
0ff596d0
PB
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:
905cec6d
CM
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 }
0ff596d0
PB
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;
8b38e532 135
0ff596d0
PB
136 case SMBUS_READ_DATA:
137 dev->mode = SMBUS_DONE;
138 break;
8b38e532 139
0ff596d0
PB
140 default:
141 BADF("Unexpected NACK in state %d\n", dev->mode);
142 dev->mode = SMBUS_CONFUSED;
143 break;
144 }
145 }
d307c28c
CM
146
147 return 0;
0ff596d0
PB
148}
149
2ac4c5f4 150static uint8_t smbus_i2c_recv(I2CSlave *s)
0ff596d0 151{
b5ea9327
AL
152 SMBusDevice *dev = SMBUS_DEVICE(s);
153 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
031ac498 154 uint8_t ret = 0xff;
0ff596d0
PB
155
156 switch (dev->mode) {
031ac498 157 case SMBUS_READ_DATA:
b5ea9327
AL
158 if (sc->receive_byte) {
159 ret = sc->receive_byte(dev);
0ff596d0
PB
160 }
161 DPRINTF("Read data %02x\n", ret);
162 break;
8b38e532 163
0ff596d0
PB
164 default:
165 BADF("Unexpected read in state %d\n", dev->mode);
166 dev->mode = SMBUS_CONFUSED;
0ff596d0
PB
167 break;
168 }
8b38e532 169
0ff596d0
PB
170 return ret;
171}
172
9e07bdf8 173static int smbus_i2c_send(I2CSlave *s, uint8_t data)
0ff596d0 174{
b5ea9327 175 SMBusDevice *dev = SMBUS_DEVICE(s);
1ea96673 176
0ff596d0
PB
177 switch (dev->mode) {
178 case SMBUS_WRITE_DATA:
179 DPRINTF("Write data %02x\n", data);
629457a1
CM
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 }
0ff596d0 185 break;
8b38e532 186
0ff596d0
PB
187 default:
188 BADF("Unexpected write in state %d\n", dev->mode);
189 break;
190 }
8b38e532 191
0ff596d0
PB
192 return 0;
193}
194
b5ea9327
AL
195static void smbus_device_class_init(ObjectClass *klass, void *data)
196{
197 I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
198
b5ea9327
AL
199 sc->event = smbus_i2c_event;
200 sc->recv = smbus_i2c_recv;
201 sc->send = smbus_i2c_send;
202}
203
547db24a
CM
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
8c43a6f0 222static const TypeInfo smbus_device_type_info = {
b5ea9327
AL
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
83f7d43a 231static void smbus_device_register_types(void)
b5ea9327
AL
232{
233 type_register_static(&smbus_device_type_info);
234}
235
83f7d43a 236type_init(smbus_device_register_types)