]> git.proxmox.com Git - mirror_qemu.git/blame - hw/input/adb.c
hw/input: Constify VMState
[mirror_qemu.git] / hw / input / adb.c
CommitLineData
267002cd
FB
1/*
2 * QEMU ADB support
5fafdf24 3 *
267002cd 4 * Copyright (c) 2004 Fabrice Bellard
5fafdf24 5 *
267002cd
FB
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 */
0b8fa32f 24
0430891c 25#include "qemu/osdep.h"
0d09e41a 26#include "hw/input/adb.h"
a27bd6c7 27#include "hw/qdev-properties.h"
d6454270 28#include "migration/vmstate.h"
0b8fa32f 29#include "qemu/module.h"
da52c083 30#include "qemu/timer.h"
77cb0f5a 31#include "adb-internal.h"
e590e7f0 32#include "trace.h"
267002cd 33
bec9d989
FB
34/* error codes */
35#define ADB_RET_NOTPRESENT (-2)
36
e590e7f0
MCA
37static 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
2e4a7c9c
AF
44static void adb_device_reset(ADBDevice *d)
45{
dfa6ba6b 46 device_cold_reset(DEVICE(d));
2e4a7c9c
AF
47}
48
d2288b75
MCA
49static int do_adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf,
50 int len)
267002cd
FB
51{
52 ADBDevice *d;
244a0ee9 53 ADBDeviceClass *adc;
3fe02cc8 54 int devaddr, cmd, olen, i;
267002cd 55
819e712b 56 cmd = buf[0] & 0xf;
bec9d989 57 if (cmd == ADB_BUSRESET) {
bcaaefdb 58 for (i = 0; i < s->nb_devices; i++) {
2e4a7c9c
AF
59 d = s->devices[i];
60 adb_device_reset(d);
bec9d989 61 }
3fe02cc8 62 s->status = 0;
bec9d989 63 return 0;
267002cd 64 }
244a0ee9
MCA
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
3fe02cc8 76 s->status = 0;
bec9d989 77 devaddr = buf[0] >> 4;
bcaaefdb 78 for (i = 0; i < s->nb_devices; i++) {
2e4a7c9c 79 d = s->devices[i];
244a0ee9
MCA
80 adc = ADB_DEVICE_GET_CLASS(d);
81
267002cd 82 if (d->devaddr == devaddr) {
3fe02cc8
MCA
83 olen = adc->devreq(d, obuf, buf, len);
84 if (!olen) {
85 s->status |= ADB_STATUS_BUSTIMEOUT;
86 }
87 return olen;
267002cd
FB
88 }
89 }
244a0ee9 90
3fe02cc8 91 s->status |= ADB_STATUS_BUSTIMEOUT;
bec9d989 92 return ADB_RET_NOTPRESENT;
e2733d20
FB
93}
94
d2288b75
MCA
95int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
96{
e590e7f0
MCA
97 int ret;
98
99 trace_adb_bus_request(buf[0] >> 4, adb_commands[buf[0] & 0xf], len);
100
913f47ef
MCA
101 assert(s->autopoll_blocked);
102
e590e7f0
MCA
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;
d2288b75
MCA
107}
108
216c906e 109int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
e2733d20
FB
110{
111 ADBDevice *d;
112 int olen, i;
bec9d989 113 uint8_t buf[1];
e2733d20
FB
114
115 olen = 0;
bcaaefdb
MCA
116 for (i = 0; i < s->nb_devices; i++) {
117 if (s->poll_index >= s->nb_devices) {
e2733d20 118 s->poll_index = 0;
bcaaefdb 119 }
2e4a7c9c 120 d = s->devices[s->poll_index];
216c906e
HP
121 if ((1 << d->devaddr) & poll_mask) {
122 buf[0] = ADB_READREG | (d->devaddr << 4);
d2288b75 123 olen = do_adb_request(s, obuf + 1, buf, 1);
216c906e
HP
124 /* if there is data, we poll again the same device */
125 if (olen > 0) {
3fe02cc8 126 s->status |= ADB_STATUS_POLLREPLY;
216c906e
HP
127 obuf[0] = buf[0];
128 olen++;
3fe02cc8 129 return olen;
216c906e 130 }
bec9d989
FB
131 }
132 s->poll_index++;
e2733d20
FB
133 }
134 return olen;
267002cd
FB
135}
136
da52c083
MCA
137void 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
151void 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
162void 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
4e5df036
MCA
176void adb_autopoll_block(ADBBusState *s)
177{
178 s->autopoll_blocked = true;
e590e7f0 179 trace_adb_bus_autopoll_block(s->autopoll_blocked);
4e5df036
MCA
180
181 if (s->autopoll_enabled) {
182 timer_del(s->autopoll_timer);
183 }
184}
185
186void adb_autopoll_unblock(ADBBusState *s)
187{
188 s->autopoll_blocked = false;
e590e7f0 189 trace_adb_bus_autopoll_block(s->autopoll_blocked);
4e5df036
MCA
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
da52c083
MCA
198static void adb_autopoll(void *opaque)
199{
200 ADBBusState *s = opaque;
201
913f47ef 202 if (!s->autopoll_blocked) {
e590e7f0 203 trace_adb_bus_autopoll_cb(s->autopoll_mask);
913f47ef 204 s->autopoll_cb(s->autopoll_cb_opaque);
e590e7f0 205 trace_adb_bus_autopoll_cb_done(s->autopoll_mask);
913f47ef 206 }
da52c083
MCA
207
208 timer_mod(s->autopoll_timer,
209 qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
210 s->autopoll_rate_ms);
211}
212
213void 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
0606b288
MCA
220static const VMStateDescription vmstate_adb_bus = {
221 .name = "adb_bus",
222 .version_id = 0,
223 .minimum_version_id = 0,
af0f07df 224 .fields = (const VMStateField[]) {
da52c083
MCA
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),
4e5df036 229 VMSTATE_BOOL(autopoll_blocked, ADBBusState),
0606b288
MCA
230 VMSTATE_END_OF_LIST()
231 }
232};
233
da52c083
MCA
234static void adb_bus_reset(BusState *qbus)
235{
236 ADBBusState *adb_bus = ADB_BUS(qbus);
237
238 adb_bus->autopoll_enabled = false;
239 adb_bus->autopoll_mask = 0xffff;
240 adb_bus->autopoll_rate_ms = 20;
241}
242
0606b288
MCA
243static void adb_bus_realize(BusState *qbus, Error **errp)
244{
245 ADBBusState *adb_bus = ADB_BUS(qbus);
246
da52c083
MCA
247 adb_bus->autopoll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, adb_autopoll,
248 adb_bus);
249
99b16e8e 250 vmstate_register_any(NULL, &vmstate_adb_bus, adb_bus);
0606b288
MCA
251}
252
253static void adb_bus_unrealize(BusState *qbus)
254{
255 ADBBusState *adb_bus = ADB_BUS(qbus);
256
da52c083
MCA
257 timer_del(adb_bus->autopoll_timer);
258
0606b288
MCA
259 vmstate_unregister(NULL, &vmstate_adb_bus, adb_bus);
260}
261
262static void adb_bus_class_init(ObjectClass *klass, void *data)
263{
264 BusClass *k = BUS_CLASS(klass);
265
266 k->realize = adb_bus_realize;
267 k->unrealize = adb_bus_unrealize;
da52c083 268 k->reset = adb_bus_reset;
0606b288
MCA
269}
270
84ede329
AF
271static const TypeInfo adb_bus_type_info = {
272 .name = TYPE_ADB_BUS,
273 .parent = TYPE_BUS,
274 .instance_size = sizeof(ADBBusState),
0606b288 275 .class_init = adb_bus_class_init,
84ede329
AF
276};
277
77cb0f5a 278const VMStateDescription vmstate_adb_device = {
e5dffaa5
MCA
279 .name = "adb_device",
280 .version_id = 0,
281 .minimum_version_id = 0,
af0f07df 282 .fields = (const VMStateField[]) {
e5dffaa5
MCA
283 VMSTATE_INT32(devaddr, ADBDevice),
284 VMSTATE_INT32(handler, ADBDevice),
285 VMSTATE_END_OF_LIST()
286 }
287};
288
2e4a7c9c
AF
289static void adb_device_realizefn(DeviceState *dev, Error **errp)
290{
291 ADBDevice *d = ADB_DEVICE(dev);
292 ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev));
293
294 if (bus->nb_devices >= MAX_ADB_DEVICES) {
295 return;
296 }
297
298 bus->devices[bus->nb_devices++] = d;
299}
300
301static void adb_device_class_init(ObjectClass *oc, void *data)
302{
303 DeviceClass *dc = DEVICE_CLASS(oc);
304
305 dc->realize = adb_device_realizefn;
306 dc->bus_type = TYPE_ADB_BUS;
307}
308
309static const TypeInfo adb_device_type_info = {
310 .name = TYPE_ADB_DEVICE,
311 .parent = TYPE_DEVICE,
7e26c92b 312 .class_size = sizeof(ADBDeviceClass),
2e4a7c9c
AF
313 .instance_size = sizeof(ADBDevice),
314 .abstract = true,
315 .class_init = adb_device_class_init,
316};
317
84ede329
AF
318static void adb_register_types(void)
319{
320 type_register_static(&adb_bus_type_info);
2e4a7c9c 321 type_register_static(&adb_device_type_info);
84ede329
AF
322}
323
324type_init(adb_register_types)