qemu

Форк
0
/
adb.c 
325 строк · 8.7 Кб
1
/*
2
 * QEMU ADB support
3
 *
4
 * Copyright (c) 2004 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

25
#include "qemu/osdep.h"
26
#include "hw/input/adb.h"
27
#include "hw/qdev-properties.h"
28
#include "migration/vmstate.h"
29
#include "qemu/module.h"
30
#include "qemu/timer.h"
31
#include "adb-internal.h"
32
#include "trace.h"
33

34
/* error codes */
35
#define ADB_RET_NOTPRESENT (-2)
36

37
static const char *adb_commands[] = {
38
    "RESET", "FLUSH", "(Reserved 0x2)", "(Reserved 0x3)",
39
    "Reserved (0x4)", "(Reserved 0x5)", "(Reserved 0x6)", "(Reserved 0x7)",
40
    "LISTEN r0", "LISTEN r1", "LISTEN r2", "LISTEN r3",
41
    "TALK r0", "TALK r1", "TALK r2", "TALK r3",
42
};
43

44
static void adb_device_reset(ADBDevice *d)
45
{
46
    device_cold_reset(DEVICE(d));
47
}
48

49
static int do_adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf,
50
                          int len)
51
{
52
    ADBDevice *d;
53
    ADBDeviceClass *adc;
54
    int devaddr, cmd, olen, i;
55

56
    cmd = buf[0] & 0xf;
57
    if (cmd == ADB_BUSRESET) {
58
        for (i = 0; i < s->nb_devices; i++) {
59
            d = s->devices[i];
60
            adb_device_reset(d);
61
        }
62
        s->status = 0;
63
        return 0;
64
    }
65

66
    s->pending = 0;
67
    for (i = 0; i < s->nb_devices; i++) {
68
        d = s->devices[i];
69
        adc = ADB_DEVICE_GET_CLASS(d);
70

71
        if (adc->devhasdata(d)) {
72
            s->pending |= (1 << d->devaddr);
73
        }
74
    }
75

76
    s->status = 0;
77
    devaddr = buf[0] >> 4;
78
    for (i = 0; i < s->nb_devices; i++) {
79
        d = s->devices[i];
80
        adc = ADB_DEVICE_GET_CLASS(d);
81

82
        if (d->devaddr == devaddr) {
83
            olen = adc->devreq(d, obuf, buf, len);
84
            if (!olen) {
85
                s->status |= ADB_STATUS_BUSTIMEOUT;
86
            }
87
            return olen;
88
        }
89
    }
90

91
    s->status |= ADB_STATUS_BUSTIMEOUT;
92
    return ADB_RET_NOTPRESENT;
93
}
94

95
int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
96
{
97
    int ret;
98

99
    trace_adb_bus_request(buf[0] >> 4, adb_commands[buf[0] & 0xf], len);
100

101
    assert(s->autopoll_blocked);
102

103
    ret = do_adb_request(s, obuf, buf, len);
104

105
    trace_adb_bus_request_done(buf[0] >> 4, adb_commands[buf[0] & 0xf], ret);
106
    return ret;
107
}
108

109
int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
110
{
111
    ADBDevice *d;
112
    int olen, i;
113
    uint8_t buf[1];
114

115
    olen = 0;
116
    for (i = 0; i < s->nb_devices; i++) {
117
        if (s->poll_index >= s->nb_devices) {
118
            s->poll_index = 0;
119
        }
120
        d = s->devices[s->poll_index];
121
        if ((1 << d->devaddr) & poll_mask) {
122
            buf[0] = ADB_READREG | (d->devaddr << 4);
123
            olen = do_adb_request(s, obuf + 1, buf, 1);
124
            /* if there is data, we poll again the same device */
125
            if (olen > 0) {
126
                s->status |= ADB_STATUS_POLLREPLY;
127
                obuf[0] = buf[0];
128
                olen++;
129
                return olen;
130
            }
131
        }
132
        s->poll_index++;
133
    }
134
    return olen;
135
}
136

137
void adb_set_autopoll_enabled(ADBBusState *s, bool enabled)
138
{
139
    if (s->autopoll_enabled != enabled) {
140
        s->autopoll_enabled = enabled;
141
        if (s->autopoll_enabled) {
142
            timer_mod(s->autopoll_timer,
143
                      qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
144
                      s->autopoll_rate_ms);
145
        } else {
146
            timer_del(s->autopoll_timer);
147
        }
148
    }
149
}
150

151
void adb_set_autopoll_rate_ms(ADBBusState *s, int rate_ms)
152
{
153
    s->autopoll_rate_ms = rate_ms;
154

155
    if (s->autopoll_enabled) {
156
        timer_mod(s->autopoll_timer,
157
                  qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
158
                  s->autopoll_rate_ms);
159
    }
160
}
161

162
void adb_set_autopoll_mask(ADBBusState *s, uint16_t mask)
163
{
164
    if (s->autopoll_mask != mask) {
165
        s->autopoll_mask = mask;
166
        if (s->autopoll_enabled && s->autopoll_mask) {
167
            timer_mod(s->autopoll_timer,
168
                      qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
169
                      s->autopoll_rate_ms);
170
        } else {
171
            timer_del(s->autopoll_timer);
172
        }
173
    }
174
}
175

176
void adb_autopoll_block(ADBBusState *s)
177
{
178
    s->autopoll_blocked = true;
179
    trace_adb_bus_autopoll_block(s->autopoll_blocked);
180

181
    if (s->autopoll_enabled) {
182
        timer_del(s->autopoll_timer);
183
    }
184
}
185

186
void adb_autopoll_unblock(ADBBusState *s)
187
{
188
    s->autopoll_blocked = false;
189
    trace_adb_bus_autopoll_block(s->autopoll_blocked);
190

191
    if (s->autopoll_enabled) {
192
        timer_mod(s->autopoll_timer,
193
                  qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
194
                  s->autopoll_rate_ms);
195
    }
196
}
197

198
static void adb_autopoll(void *opaque)
199
{
200
    ADBBusState *s = opaque;
201

202
    if (!s->autopoll_blocked) {
203
        trace_adb_bus_autopoll_cb(s->autopoll_mask);
204
        s->autopoll_cb(s->autopoll_cb_opaque);
205
        trace_adb_bus_autopoll_cb_done(s->autopoll_mask);
206
    }
207

208
    timer_mod(s->autopoll_timer,
209
              qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
210
              s->autopoll_rate_ms);
211
}
212

213
void adb_register_autopoll_callback(ADBBusState *s, void (*cb)(void *opaque),
214
                                    void *opaque)
215
{
216
    s->autopoll_cb = cb;
217
    s->autopoll_cb_opaque = opaque;
218
}
219

220
static const VMStateDescription vmstate_adb_bus = {
221
    .name = "adb_bus",
222
    .version_id = 0,
223
    .minimum_version_id = 0,
224
    .fields = (const VMStateField[]) {
225
        VMSTATE_TIMER_PTR(autopoll_timer, ADBBusState),
226
        VMSTATE_BOOL(autopoll_enabled, ADBBusState),
227
        VMSTATE_UINT8(autopoll_rate_ms, ADBBusState),
228
        VMSTATE_UINT16(autopoll_mask, ADBBusState),
229
        VMSTATE_BOOL(autopoll_blocked, ADBBusState),
230
        VMSTATE_END_OF_LIST()
231
    }
232
};
233

234
static void adb_bus_reset_hold(Object *obj, ResetType type)
235
{
236
    ADBBusState *adb_bus = ADB_BUS(obj);
237

238
    adb_bus->autopoll_enabled = false;
239
    adb_bus->autopoll_mask = 0xffff;
240
    adb_bus->autopoll_rate_ms = 20;
241
}
242

243
static void adb_bus_realize(BusState *qbus, Error **errp)
244
{
245
    ADBBusState *adb_bus = ADB_BUS(qbus);
246

247
    adb_bus->autopoll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, adb_autopoll,
248
                                           adb_bus);
249

250
    vmstate_register_any(NULL, &vmstate_adb_bus, adb_bus);
251
}
252

253
static void adb_bus_unrealize(BusState *qbus)
254
{
255
    ADBBusState *adb_bus = ADB_BUS(qbus);
256

257
    timer_del(adb_bus->autopoll_timer);
258

259
    vmstate_unregister(NULL, &vmstate_adb_bus, adb_bus);
260
}
261

262
static void adb_bus_class_init(ObjectClass *klass, void *data)
263
{
264
    BusClass *k = BUS_CLASS(klass);
265
    ResettableClass *rc = RESETTABLE_CLASS(klass);
266

267
    k->realize = adb_bus_realize;
268
    k->unrealize = adb_bus_unrealize;
269
    rc->phases.hold = adb_bus_reset_hold;
270
}
271

272
static const TypeInfo adb_bus_type_info = {
273
    .name = TYPE_ADB_BUS,
274
    .parent = TYPE_BUS,
275
    .instance_size = sizeof(ADBBusState),
276
    .class_init = adb_bus_class_init,
277
};
278

279
const VMStateDescription vmstate_adb_device = {
280
    .name = "adb_device",
281
    .version_id = 0,
282
    .minimum_version_id = 0,
283
    .fields = (const VMStateField[]) {
284
        VMSTATE_INT32(devaddr, ADBDevice),
285
        VMSTATE_INT32(handler, ADBDevice),
286
        VMSTATE_END_OF_LIST()
287
    }
288
};
289

290
static void adb_device_realizefn(DeviceState *dev, Error **errp)
291
{
292
    ADBDevice *d = ADB_DEVICE(dev);
293
    ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev));
294

295
    if (bus->nb_devices >= MAX_ADB_DEVICES) {
296
        return;
297
    }
298

299
    bus->devices[bus->nb_devices++] = d;
300
}
301

302
static void adb_device_class_init(ObjectClass *oc, void *data)
303
{
304
    DeviceClass *dc = DEVICE_CLASS(oc);
305

306
    dc->realize = adb_device_realizefn;
307
    dc->bus_type = TYPE_ADB_BUS;
308
}
309

310
static const TypeInfo adb_device_type_info = {
311
    .name = TYPE_ADB_DEVICE,
312
    .parent = TYPE_DEVICE,
313
    .class_size = sizeof(ADBDeviceClass),
314
    .instance_size = sizeof(ADBDevice),
315
    .abstract = true,
316
    .class_init = adb_device_class_init,
317
};
318

319
static void adb_register_types(void)
320
{
321
    type_register_static(&adb_bus_type_info);
322
    type_register_static(&adb_device_type_info);
323
}
324

325
type_init(adb_register_types)
326

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

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

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

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