qemu

Форк
0
/
smbus_slave.c 
245 строк · 6.0 Кб
1
/*
2
 * QEMU SMBus device emulation.
3
 *
4
 * This code is a helper for SMBus device emulation.  It implements an
5
 * I2C device interface 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 { g_autofree char *qom_path = object_get_canonical_path(OBJECT(dev));  \
29
    fprintf(stderr, "%s: smbus: error: " fmt , qom_path, ## __VA_ARGS__); \
30
            exit(1); } while (0)
31
#else
32
#define DPRINTF(fmt, ...) do {} while(0)
33
#define BADF(fmt, ...) \
34
do { g_autofree char *qom_path = object_get_canonical_path(OBJECT(dev));  \
35
    fprintf(stderr, "%s: smbus: error: " fmt , qom_path, ## __VA_ARGS__); \
36
             } while (0)
37
#endif
38

39
enum {
40
    SMBUS_IDLE,
41
    SMBUS_WRITE_DATA,
42
    SMBUS_READ_DATA,
43
    SMBUS_DONE,
44
    SMBUS_CONFUSED = -1
45
};
46

47
static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
48
{
49
    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
50

51
    DPRINTF("Quick Command %d\n", recv);
52
    if (sc->quick_cmd) {
53
        sc->quick_cmd(dev, recv);
54
    }
55
}
56

57
static void smbus_do_write(SMBusDevice *dev)
58
{
59
    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
60

61
    DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
62
    if (sc->write_data) {
63
        sc->write_data(dev, dev->data_buf, dev->data_len);
64
    }
65
}
66

67
static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
68
{
69
    SMBusDevice *dev = SMBUS_DEVICE(s);
70

71
    switch (event) {
72
    case I2C_START_SEND:
73
        switch (dev->mode) {
74
        case SMBUS_IDLE:
75
            DPRINTF("Incoming data\n");
76
            dev->mode = SMBUS_WRITE_DATA;
77
            break;
78

79
        default:
80
            BADF("Unexpected send start condition in state %d\n", dev->mode);
81
            dev->mode = SMBUS_CONFUSED;
82
            break;
83
        }
84
        break;
85

86
    case I2C_START_RECV:
87
        switch (dev->mode) {
88
        case SMBUS_IDLE:
89
            DPRINTF("Read mode\n");
90
            dev->mode = SMBUS_READ_DATA;
91
            break;
92

93
        case SMBUS_WRITE_DATA:
94
            if (dev->data_len == 0) {
95
                BADF("Read after write with no data\n");
96
                dev->mode = SMBUS_CONFUSED;
97
            } else {
98
                smbus_do_write(dev);
99
                DPRINTF("Read mode\n");
100
                dev->mode = SMBUS_READ_DATA;
101
            }
102
            break;
103

104
        default:
105
            BADF("Unexpected recv start condition in state %d\n", dev->mode);
106
            dev->mode = SMBUS_CONFUSED;
107
            break;
108
        }
109
        break;
110

111
    case I2C_FINISH:
112
        if (dev->data_len == 0) {
113
            if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
114
                smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
115
            }
116
        } else {
117
            switch (dev->mode) {
118
            case SMBUS_WRITE_DATA:
119
                smbus_do_write(dev);
120
                break;
121

122
            case SMBUS_READ_DATA:
123
                BADF("Unexpected stop during receive\n");
124
                break;
125

126
            default:
127
                /* Nothing to do.  */
128
                break;
129
            }
130
        }
131
        dev->mode = SMBUS_IDLE;
132
        dev->data_len = 0;
133
        break;
134

135
    case I2C_NACK:
136
        switch (dev->mode) {
137
        case SMBUS_DONE:
138
            /* Nothing to do.  */
139
            break;
140

141
        case SMBUS_READ_DATA:
142
            dev->mode = SMBUS_DONE;
143
            break;
144

145
        default:
146
            BADF("Unexpected NACK in state %d\n", dev->mode);
147
            dev->mode = SMBUS_CONFUSED;
148
            break;
149
        }
150
        break;
151

152
    default:
153
        return -1;
154
    }
155

156
    return 0;
157
}
158

159
static uint8_t smbus_i2c_recv(I2CSlave *s)
160
{
161
    SMBusDevice *dev = SMBUS_DEVICE(s);
162
    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
163
    uint8_t ret = 0xff;
164

165
    switch (dev->mode) {
166
    case SMBUS_READ_DATA:
167
        if (sc->receive_byte) {
168
            ret = sc->receive_byte(dev);
169
        }
170
        DPRINTF("Read data %02x\n", ret);
171
        break;
172

173
    default:
174
        BADF("Unexpected read in state %d\n", dev->mode);
175
        dev->mode = SMBUS_CONFUSED;
176
        break;
177
    }
178

179
    return ret;
180
}
181

182
static int smbus_i2c_send(I2CSlave *s, uint8_t data)
183
{
184
    SMBusDevice *dev = SMBUS_DEVICE(s);
185

186
    switch (dev->mode) {
187
    case SMBUS_WRITE_DATA:
188
        DPRINTF("Write data %02x\n", data);
189
        if (dev->data_len >= sizeof(dev->data_buf)) {
190
            BADF("Too many bytes sent\n");
191
        } else {
192
            dev->data_buf[dev->data_len++] = data;
193
        }
194
        break;
195

196
    default:
197
        BADF("Unexpected write in state %d\n", dev->mode);
198
        break;
199
    }
200

201
    return 0;
202
}
203

204
static void smbus_device_class_init(ObjectClass *klass, void *data)
205
{
206
    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
207

208
    sc->event = smbus_i2c_event;
209
    sc->recv = smbus_i2c_recv;
210
    sc->send = smbus_i2c_send;
211
}
212

213
bool smbus_vmstate_needed(SMBusDevice *dev)
214
{
215
    return dev->mode != SMBUS_IDLE;
216
}
217

218
const VMStateDescription vmstate_smbus_device = {
219
    .name = TYPE_SMBUS_DEVICE,
220
    .version_id = 1,
221
    .minimum_version_id = 1,
222
    .fields = (const VMStateField[]) {
223
        VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
224
        VMSTATE_INT32(mode, SMBusDevice),
225
        VMSTATE_INT32(data_len, SMBusDevice),
226
        VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
227
        VMSTATE_END_OF_LIST()
228
    }
229
};
230

231
static const TypeInfo smbus_device_type_info = {
232
    .name = TYPE_SMBUS_DEVICE,
233
    .parent = TYPE_I2C_SLAVE,
234
    .instance_size = sizeof(SMBusDevice),
235
    .abstract = true,
236
    .class_size = sizeof(SMBusDeviceClass),
237
    .class_init = smbus_device_class_init,
238
};
239

240
static void smbus_device_register_types(void)
241
{
242
    type_register_static(&smbus_device_type_info);
243
}
244

245
type_init(smbus_device_register_types)
246

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.