xref: /qemu/hw/input/adb.c (revision e5dffaa5b19b284718b40a4aba01abf0bcdabf7a)
1267002cdSbellard /*
2267002cdSbellard  * QEMU ADB support
3267002cdSbellard  *
4267002cdSbellard  * Copyright (c) 2004 Fabrice Bellard
5267002cdSbellard  *
6267002cdSbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7267002cdSbellard  * of this software and associated documentation files (the "Software"), to deal
8267002cdSbellard  * in the Software without restriction, including without limitation the rights
9267002cdSbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10267002cdSbellard  * copies of the Software, and to permit persons to whom the Software is
11267002cdSbellard  * furnished to do so, subject to the following conditions:
12267002cdSbellard  *
13267002cdSbellard  * The above copyright notice and this permission notice shall be included in
14267002cdSbellard  * all copies or substantial portions of the Software.
15267002cdSbellard  *
16267002cdSbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17267002cdSbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18267002cdSbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19267002cdSbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20267002cdSbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21267002cdSbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22267002cdSbellard  * THE SOFTWARE.
23267002cdSbellard  */
2483c9f4caSPaolo Bonzini #include "hw/hw.h"
250d09e41aSPaolo Bonzini #include "hw/input/adb.h"
2628ecbaeeSPaolo Bonzini #include "ui/console.h"
27267002cdSbellard 
28ea026b2fSblueswir1 /* debug ADB */
29ea026b2fSblueswir1 //#define DEBUG_ADB
30ea026b2fSblueswir1 
31ea026b2fSblueswir1 #ifdef DEBUG_ADB
32001faf32SBlue Swirl #define ADB_DPRINTF(fmt, ...) \
33001faf32SBlue Swirl do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
34ea026b2fSblueswir1 #else
35001faf32SBlue Swirl #define ADB_DPRINTF(fmt, ...)
36ea026b2fSblueswir1 #endif
37ea026b2fSblueswir1 
38267002cdSbellard /* ADB commands */
39267002cdSbellard #define ADB_BUSRESET		0x00
40267002cdSbellard #define ADB_FLUSH               0x01
41267002cdSbellard #define ADB_WRITEREG		0x08
42267002cdSbellard #define ADB_READREG		0x0c
43267002cdSbellard 
44267002cdSbellard /* ADB device commands */
45267002cdSbellard #define ADB_CMD_SELF_TEST		0xff
46267002cdSbellard #define ADB_CMD_CHANGE_ID		0xfe
47267002cdSbellard #define ADB_CMD_CHANGE_ID_AND_ACT	0xfd
48267002cdSbellard #define ADB_CMD_CHANGE_ID_AND_ENABLE	0x00
49267002cdSbellard 
50267002cdSbellard /* ADB default device IDs (upper 4 bits of ADB command byte) */
512e4a7c9cSAndreas Färber #define ADB_DEVID_DONGLE   1
522e4a7c9cSAndreas Färber #define ADB_DEVID_KEYBOARD 2
532e4a7c9cSAndreas Färber #define ADB_DEVID_MOUSE    3
542e4a7c9cSAndreas Färber #define ADB_DEVID_TABLET   4
552e4a7c9cSAndreas Färber #define ADB_DEVID_MODEM    5
562e4a7c9cSAndreas Färber #define ADB_DEVID_MISC     7
57267002cdSbellard 
58bec9d989Sbellard /* error codes */
59bec9d989Sbellard #define ADB_RET_NOTPRESENT (-2)
60bec9d989Sbellard 
612e4a7c9cSAndreas Färber static void adb_device_reset(ADBDevice *d)
622e4a7c9cSAndreas Färber {
632e4a7c9cSAndreas Färber     qdev_reset_all(DEVICE(d));
642e4a7c9cSAndreas Färber }
652e4a7c9cSAndreas Färber 
66e2733d20Sbellard int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
67267002cdSbellard {
68267002cdSbellard     ADBDevice *d;
69267002cdSbellard     int devaddr, cmd, i;
70267002cdSbellard 
71819e712bSbellard     cmd = buf[0] & 0xf;
72bec9d989Sbellard     if (cmd == ADB_BUSRESET) {
73bec9d989Sbellard         for(i = 0; i < s->nb_devices; i++) {
742e4a7c9cSAndreas Färber             d = s->devices[i];
752e4a7c9cSAndreas Färber             adb_device_reset(d);
76bec9d989Sbellard         }
77bec9d989Sbellard         return 0;
78bec9d989Sbellard     }
79819e712bSbellard     devaddr = buf[0] >> 4;
80267002cdSbellard     for(i = 0; i < s->nb_devices; i++) {
812e4a7c9cSAndreas Färber         d = s->devices[i];
82267002cdSbellard         if (d->devaddr == devaddr) {
832e4a7c9cSAndreas Färber             ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d);
842e4a7c9cSAndreas Färber             return adc->devreq(d, obuf, buf, len);
85267002cdSbellard         }
86267002cdSbellard     }
87bec9d989Sbellard     return ADB_RET_NOTPRESENT;
88e2733d20Sbellard }
89e2733d20Sbellard 
90bec9d989Sbellard /* XXX: move that to cuda ? */
91e2733d20Sbellard int adb_poll(ADBBusState *s, uint8_t *obuf)
92e2733d20Sbellard {
93e2733d20Sbellard     ADBDevice *d;
94e2733d20Sbellard     int olen, i;
95bec9d989Sbellard     uint8_t buf[1];
96e2733d20Sbellard 
97e2733d20Sbellard     olen = 0;
98e2733d20Sbellard     for(i = 0; i < s->nb_devices; i++) {
99e2733d20Sbellard         if (s->poll_index >= s->nb_devices)
100e2733d20Sbellard             s->poll_index = 0;
1012e4a7c9cSAndreas Färber         d = s->devices[s->poll_index];
102bec9d989Sbellard         buf[0] = ADB_READREG | (d->devaddr << 4);
103bec9d989Sbellard         olen = adb_request(s, obuf + 1, buf, 1);
104bec9d989Sbellard         /* if there is data, we poll again the same device */
105bec9d989Sbellard         if (olen > 0) {
106bec9d989Sbellard             obuf[0] = buf[0];
107bec9d989Sbellard             olen++;
108e2733d20Sbellard             break;
109e2733d20Sbellard         }
110bec9d989Sbellard         s->poll_index++;
111bec9d989Sbellard     }
112e2733d20Sbellard     return olen;
113267002cdSbellard }
114267002cdSbellard 
11584ede329SAndreas Färber static const TypeInfo adb_bus_type_info = {
11684ede329SAndreas Färber     .name = TYPE_ADB_BUS,
11784ede329SAndreas Färber     .parent = TYPE_BUS,
11884ede329SAndreas Färber     .instance_size = sizeof(ADBBusState),
11984ede329SAndreas Färber };
12084ede329SAndreas Färber 
121*e5dffaa5SMark Cave-Ayland static const VMStateDescription vmstate_adb_device = {
122*e5dffaa5SMark Cave-Ayland     .name = "adb_device",
123*e5dffaa5SMark Cave-Ayland     .version_id = 0,
124*e5dffaa5SMark Cave-Ayland     .minimum_version_id = 0,
125*e5dffaa5SMark Cave-Ayland     .fields = (VMStateField[]) {
126*e5dffaa5SMark Cave-Ayland         VMSTATE_INT32(devaddr, ADBDevice),
127*e5dffaa5SMark Cave-Ayland         VMSTATE_INT32(handler, ADBDevice),
128*e5dffaa5SMark Cave-Ayland         VMSTATE_END_OF_LIST()
129*e5dffaa5SMark Cave-Ayland     }
130*e5dffaa5SMark Cave-Ayland };
131*e5dffaa5SMark Cave-Ayland 
1322e4a7c9cSAndreas Färber static void adb_device_realizefn(DeviceState *dev, Error **errp)
1332e4a7c9cSAndreas Färber {
1342e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
1352e4a7c9cSAndreas Färber     ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev));
1362e4a7c9cSAndreas Färber 
1372e4a7c9cSAndreas Färber     if (bus->nb_devices >= MAX_ADB_DEVICES) {
1382e4a7c9cSAndreas Färber         return;
1392e4a7c9cSAndreas Färber     }
1402e4a7c9cSAndreas Färber 
1412e4a7c9cSAndreas Färber     bus->devices[bus->nb_devices++] = d;
1422e4a7c9cSAndreas Färber }
1432e4a7c9cSAndreas Färber 
1442e4a7c9cSAndreas Färber static void adb_device_class_init(ObjectClass *oc, void *data)
1452e4a7c9cSAndreas Färber {
1462e4a7c9cSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
1472e4a7c9cSAndreas Färber 
1482e4a7c9cSAndreas Färber     dc->realize = adb_device_realizefn;
1492e4a7c9cSAndreas Färber     dc->bus_type = TYPE_ADB_BUS;
1502e4a7c9cSAndreas Färber }
1512e4a7c9cSAndreas Färber 
1522e4a7c9cSAndreas Färber static const TypeInfo adb_device_type_info = {
1532e4a7c9cSAndreas Färber     .name = TYPE_ADB_DEVICE,
1542e4a7c9cSAndreas Färber     .parent = TYPE_DEVICE,
1552e4a7c9cSAndreas Färber     .instance_size = sizeof(ADBDevice),
1562e4a7c9cSAndreas Färber     .abstract = true,
1572e4a7c9cSAndreas Färber     .class_init = adb_device_class_init,
1582e4a7c9cSAndreas Färber };
1592e4a7c9cSAndreas Färber 
160267002cdSbellard /***************************************************************/
161267002cdSbellard /* Keyboard ADB device */
162267002cdSbellard 
1632e4a7c9cSAndreas Färber #define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD)
1642e4a7c9cSAndreas Färber 
165e2733d20Sbellard typedef struct KBDState {
1662e4a7c9cSAndreas Färber     /*< private >*/
1672e4a7c9cSAndreas Färber     ADBDevice parent_obj;
1682e4a7c9cSAndreas Färber     /*< public >*/
1692e4a7c9cSAndreas Färber 
170e2733d20Sbellard     uint8_t data[128];
171e2733d20Sbellard     int rptr, wptr, count;
172e2733d20Sbellard } KBDState;
173e2733d20Sbellard 
1742e4a7c9cSAndreas Färber #define ADB_KEYBOARD_CLASS(class) \
1752e4a7c9cSAndreas Färber     OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD)
1762e4a7c9cSAndreas Färber #define ADB_KEYBOARD_GET_CLASS(obj) \
1772e4a7c9cSAndreas Färber     OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD)
1782e4a7c9cSAndreas Färber 
1792e4a7c9cSAndreas Färber typedef struct ADBKeyboardClass {
1802e4a7c9cSAndreas Färber     /*< private >*/
1812e4a7c9cSAndreas Färber     ADBDeviceClass parent_class;
1822e4a7c9cSAndreas Färber     /*< public >*/
1832e4a7c9cSAndreas Färber 
1842e4a7c9cSAndreas Färber     DeviceRealize parent_realize;
1852e4a7c9cSAndreas Färber } ADBKeyboardClass;
1862e4a7c9cSAndreas Färber 
187267002cdSbellard static const uint8_t pc_to_adb_keycode[256] = {
188267002cdSbellard   0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
189267002cdSbellard  12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
190267002cdSbellard   2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
191267002cdSbellard  11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
192267002cdSbellard  97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
193e2733d20Sbellard  84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
194267002cdSbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
195267002cdSbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
196e2733d20Sbellard   0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
197e2733d20Sbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
198e2733d20Sbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
199e2733d20Sbellard   0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
200e2733d20Sbellard   0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
201e2733d20Sbellard  61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
202267002cdSbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
203e2733d20Sbellard   0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
204267002cdSbellard };
205267002cdSbellard 
206267002cdSbellard static void adb_kbd_put_keycode(void *opaque, int keycode)
207267002cdSbellard {
2082e4a7c9cSAndreas Färber     KBDState *s = opaque;
209e2733d20Sbellard 
210e2733d20Sbellard     if (s->count < sizeof(s->data)) {
211e2733d20Sbellard         s->data[s->wptr] = keycode;
212e2733d20Sbellard         if (++s->wptr == sizeof(s->data))
213e2733d20Sbellard             s->wptr = 0;
214e2733d20Sbellard         s->count++;
215e2733d20Sbellard     }
216e2733d20Sbellard }
217e2733d20Sbellard 
218e2733d20Sbellard static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
219e2733d20Sbellard {
220e2733d20Sbellard     static int ext_keycode;
2212e4a7c9cSAndreas Färber     KBDState *s = ADB_KEYBOARD(d);
222e2733d20Sbellard     int adb_keycode, keycode;
223e2733d20Sbellard     int olen;
224e2733d20Sbellard 
225e2733d20Sbellard     olen = 0;
226e2733d20Sbellard     for(;;) {
227e2733d20Sbellard         if (s->count == 0)
228e2733d20Sbellard             break;
229e2733d20Sbellard         keycode = s->data[s->rptr];
230e2733d20Sbellard         if (++s->rptr == sizeof(s->data))
231e2733d20Sbellard             s->rptr = 0;
232e2733d20Sbellard         s->count--;
233267002cdSbellard 
234267002cdSbellard         if (keycode == 0xe0) {
235267002cdSbellard             ext_keycode = 1;
236267002cdSbellard         } else {
237267002cdSbellard             if (ext_keycode)
238267002cdSbellard                 adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
239267002cdSbellard             else
240267002cdSbellard                 adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
241bec9d989Sbellard             obuf[0] = adb_keycode | (keycode & 0x80);
242bec9d989Sbellard             /* NOTE: could put a second keycode if needed */
243bec9d989Sbellard             obuf[1] = 0xff;
244bec9d989Sbellard             olen = 2;
245267002cdSbellard             ext_keycode = 0;
246e2733d20Sbellard             break;
247267002cdSbellard         }
248267002cdSbellard     }
249e2733d20Sbellard     return olen;
250e2733d20Sbellard }
251267002cdSbellard 
252e2733d20Sbellard static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
253e2733d20Sbellard                            const uint8_t *buf, int len)
254267002cdSbellard {
2552e4a7c9cSAndreas Färber     KBDState *s = ADB_KEYBOARD(d);
256e2733d20Sbellard     int cmd, reg, olen;
257e2733d20Sbellard 
258bec9d989Sbellard     if ((buf[0] & 0x0f) == ADB_FLUSH) {
259bec9d989Sbellard         /* flush keyboard fifo */
260bec9d989Sbellard         s->wptr = s->rptr = s->count = 0;
261bec9d989Sbellard         return 0;
262e2733d20Sbellard     }
263267002cdSbellard 
264267002cdSbellard     cmd = buf[0] & 0xc;
265267002cdSbellard     reg = buf[0] & 0x3;
266e2733d20Sbellard     olen = 0;
267267002cdSbellard     switch(cmd) {
268267002cdSbellard     case ADB_WRITEREG:
269267002cdSbellard         switch(reg) {
270267002cdSbellard         case 2:
271267002cdSbellard             /* LED status */
272267002cdSbellard             break;
273267002cdSbellard         case 3:
274267002cdSbellard             switch(buf[2]) {
275267002cdSbellard             case ADB_CMD_SELF_TEST:
276267002cdSbellard                 break;
277267002cdSbellard             case ADB_CMD_CHANGE_ID:
278267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ACT:
279267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ENABLE:
280267002cdSbellard                 d->devaddr = buf[1] & 0xf;
281267002cdSbellard                 break;
282267002cdSbellard             default:
283267002cdSbellard                 /* XXX: check this */
284267002cdSbellard                 d->devaddr = buf[1] & 0xf;
285267002cdSbellard                 d->handler = buf[2];
286267002cdSbellard                 break;
287267002cdSbellard             }
288267002cdSbellard         }
289267002cdSbellard         break;
290267002cdSbellard     case ADB_READREG:
291267002cdSbellard         switch(reg) {
292bec9d989Sbellard         case 0:
293bec9d989Sbellard             olen = adb_kbd_poll(d, obuf);
294bec9d989Sbellard             break;
295267002cdSbellard         case 1:
296267002cdSbellard             break;
297267002cdSbellard         case 2:
298e2733d20Sbellard             obuf[0] = 0x00; /* XXX: check this */
299e2733d20Sbellard             obuf[1] = 0x07; /* led status */
300e2733d20Sbellard             olen = 2;
301267002cdSbellard             break;
302267002cdSbellard         case 3:
303e2733d20Sbellard             obuf[0] = d->handler;
304e2733d20Sbellard             obuf[1] = d->devaddr;
305e2733d20Sbellard             olen = 2;
306267002cdSbellard             break;
307267002cdSbellard         }
308267002cdSbellard         break;
309267002cdSbellard     }
310e2733d20Sbellard     return olen;
311267002cdSbellard }
312267002cdSbellard 
3131f1f0600SJuan Quintela static const VMStateDescription vmstate_adb_kbd = {
3141f1f0600SJuan Quintela     .name = "adb_kbd",
315*e5dffaa5SMark Cave-Ayland     .version_id = 2,
316*e5dffaa5SMark Cave-Ayland     .minimum_version_id = 2,
3171f1f0600SJuan Quintela     .fields = (VMStateField[]) {
318*e5dffaa5SMark Cave-Ayland         VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice),
3191f1f0600SJuan Quintela         VMSTATE_BUFFER(data, KBDState),
3201f1f0600SJuan Quintela         VMSTATE_INT32(rptr, KBDState),
3211f1f0600SJuan Quintela         VMSTATE_INT32(wptr, KBDState),
3221f1f0600SJuan Quintela         VMSTATE_INT32(count, KBDState),
3231f1f0600SJuan Quintela         VMSTATE_END_OF_LIST()
3249b64997fSblueswir1     }
3251f1f0600SJuan Quintela };
3269b64997fSblueswir1 
3272e4a7c9cSAndreas Färber static void adb_kbd_reset(DeviceState *dev)
3283988e897Sbellard {
3292e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
3302e4a7c9cSAndreas Färber     KBDState *s = ADB_KEYBOARD(dev);
3313988e897Sbellard 
3323988e897Sbellard     d->handler = 1;
3332e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_KEYBOARD;
3342e4a7c9cSAndreas Färber     memset(s->data, 0, sizeof(s->data));
3352e4a7c9cSAndreas Färber     s->rptr = 0;
3362e4a7c9cSAndreas Färber     s->wptr = 0;
3372e4a7c9cSAndreas Färber     s->count = 0;
3383988e897Sbellard }
3393988e897Sbellard 
3402e4a7c9cSAndreas Färber static void adb_kbd_realizefn(DeviceState *dev, Error **errp)
341267002cdSbellard {
3422e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
3432e4a7c9cSAndreas Färber     ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev);
3442e4a7c9cSAndreas Färber 
3452e4a7c9cSAndreas Färber     akc->parent_realize(dev, errp);
3462e4a7c9cSAndreas Färber 
347267002cdSbellard     qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
348267002cdSbellard }
349267002cdSbellard 
3502e4a7c9cSAndreas Färber static void adb_kbd_initfn(Object *obj)
3512e4a7c9cSAndreas Färber {
3522e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(obj);
3532e4a7c9cSAndreas Färber 
3542e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_KEYBOARD;
3552e4a7c9cSAndreas Färber }
3562e4a7c9cSAndreas Färber 
3572e4a7c9cSAndreas Färber static void adb_kbd_class_init(ObjectClass *oc, void *data)
3582e4a7c9cSAndreas Färber {
3592e4a7c9cSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
3602e4a7c9cSAndreas Färber     ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
3612e4a7c9cSAndreas Färber     ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc);
3622e4a7c9cSAndreas Färber 
3632e4a7c9cSAndreas Färber     akc->parent_realize = dc->realize;
3642e4a7c9cSAndreas Färber     dc->realize = adb_kbd_realizefn;
3652e4a7c9cSAndreas Färber 
3662e4a7c9cSAndreas Färber     adc->devreq = adb_kbd_request;
3672e4a7c9cSAndreas Färber     dc->reset = adb_kbd_reset;
3682e4a7c9cSAndreas Färber     dc->vmsd = &vmstate_adb_kbd;
3692e4a7c9cSAndreas Färber }
3702e4a7c9cSAndreas Färber 
3712e4a7c9cSAndreas Färber static const TypeInfo adb_kbd_type_info = {
3722e4a7c9cSAndreas Färber     .name = TYPE_ADB_KEYBOARD,
3732e4a7c9cSAndreas Färber     .parent = TYPE_ADB_DEVICE,
3742e4a7c9cSAndreas Färber     .instance_size = sizeof(KBDState),
3752e4a7c9cSAndreas Färber     .instance_init = adb_kbd_initfn,
3762e4a7c9cSAndreas Färber     .class_init = adb_kbd_class_init,
3772e4a7c9cSAndreas Färber     .class_size = sizeof(ADBKeyboardClass),
3782e4a7c9cSAndreas Färber };
3792e4a7c9cSAndreas Färber 
380267002cdSbellard /***************************************************************/
381267002cdSbellard /* Mouse ADB device */
382267002cdSbellard 
3832e4a7c9cSAndreas Färber #define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
3842e4a7c9cSAndreas Färber 
385e2733d20Sbellard typedef struct MouseState {
3862e4a7c9cSAndreas Färber     /*< public >*/
3872e4a7c9cSAndreas Färber     ADBDevice parent_obj;
3882e4a7c9cSAndreas Färber     /*< private >*/
3892e4a7c9cSAndreas Färber 
390e2733d20Sbellard     int buttons_state, last_buttons_state;
391e2733d20Sbellard     int dx, dy, dz;
392e2733d20Sbellard } MouseState;
393e2733d20Sbellard 
3942e4a7c9cSAndreas Färber #define ADB_MOUSE_CLASS(class) \
3952e4a7c9cSAndreas Färber     OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
3962e4a7c9cSAndreas Färber #define ADB_MOUSE_GET_CLASS(obj) \
3972e4a7c9cSAndreas Färber     OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
3982e4a7c9cSAndreas Färber 
3992e4a7c9cSAndreas Färber typedef struct ADBMouseClass {
4002e4a7c9cSAndreas Färber     /*< public >*/
4012e4a7c9cSAndreas Färber     ADBDeviceClass parent_class;
4022e4a7c9cSAndreas Färber     /*< private >*/
4032e4a7c9cSAndreas Färber 
4042e4a7c9cSAndreas Färber     DeviceRealize parent_realize;
4052e4a7c9cSAndreas Färber } ADBMouseClass;
4062e4a7c9cSAndreas Färber 
407267002cdSbellard static void adb_mouse_event(void *opaque,
408267002cdSbellard                             int dx1, int dy1, int dz1, int buttons_state)
409267002cdSbellard {
4102e4a7c9cSAndreas Färber     MouseState *s = opaque;
411e2733d20Sbellard 
412e2733d20Sbellard     s->dx += dx1;
413e2733d20Sbellard     s->dy += dy1;
414e2733d20Sbellard     s->dz += dz1;
415e2733d20Sbellard     s->buttons_state = buttons_state;
416e2733d20Sbellard }
417e2733d20Sbellard 
418e2733d20Sbellard 
419e2733d20Sbellard static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
420e2733d20Sbellard {
4212e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(d);
422267002cdSbellard     int dx, dy;
423267002cdSbellard 
424e2733d20Sbellard     if (s->last_buttons_state == s->buttons_state &&
425e2733d20Sbellard         s->dx == 0 && s->dy == 0)
426e2733d20Sbellard         return 0;
427e2733d20Sbellard 
428e2733d20Sbellard     dx = s->dx;
429267002cdSbellard     if (dx < -63)
430267002cdSbellard         dx = -63;
431267002cdSbellard     else if (dx > 63)
432267002cdSbellard         dx = 63;
433267002cdSbellard 
434e2733d20Sbellard     dy = s->dy;
435267002cdSbellard     if (dy < -63)
436267002cdSbellard         dy = -63;
437267002cdSbellard     else if (dy > 63)
438267002cdSbellard         dy = 63;
439267002cdSbellard 
440e2733d20Sbellard     s->dx -= dx;
441e2733d20Sbellard     s->dy -= dy;
442e2733d20Sbellard     s->last_buttons_state = s->buttons_state;
443e2733d20Sbellard 
444267002cdSbellard     dx &= 0x7f;
445267002cdSbellard     dy &= 0x7f;
446267002cdSbellard 
447bec9d989Sbellard     if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
448267002cdSbellard         dy |= 0x80;
449bec9d989Sbellard     if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
450267002cdSbellard         dx |= 0x80;
451267002cdSbellard 
452bec9d989Sbellard     obuf[0] = dy;
453bec9d989Sbellard     obuf[1] = dx;
454bec9d989Sbellard     return 2;
455267002cdSbellard }
456267002cdSbellard 
457e2733d20Sbellard static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
458e2733d20Sbellard                              const uint8_t *buf, int len)
459267002cdSbellard {
4602e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(d);
461e2733d20Sbellard     int cmd, reg, olen;
462e2733d20Sbellard 
463bec9d989Sbellard     if ((buf[0] & 0x0f) == ADB_FLUSH) {
464bec9d989Sbellard         /* flush mouse fifo */
465bec9d989Sbellard         s->buttons_state = s->last_buttons_state;
466bec9d989Sbellard         s->dx = 0;
467bec9d989Sbellard         s->dy = 0;
468bec9d989Sbellard         s->dz = 0;
469bec9d989Sbellard         return 0;
470e2733d20Sbellard     }
471267002cdSbellard 
472267002cdSbellard     cmd = buf[0] & 0xc;
473267002cdSbellard     reg = buf[0] & 0x3;
474e2733d20Sbellard     olen = 0;
475267002cdSbellard     switch(cmd) {
476267002cdSbellard     case ADB_WRITEREG:
477ea026b2fSblueswir1         ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
478267002cdSbellard         switch(reg) {
479267002cdSbellard         case 2:
480267002cdSbellard             break;
481267002cdSbellard         case 3:
482267002cdSbellard             switch(buf[2]) {
483267002cdSbellard             case ADB_CMD_SELF_TEST:
484267002cdSbellard                 break;
485267002cdSbellard             case ADB_CMD_CHANGE_ID:
486267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ACT:
487267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ENABLE:
488267002cdSbellard                 d->devaddr = buf[1] & 0xf;
489267002cdSbellard                 break;
490267002cdSbellard             default:
491267002cdSbellard                 /* XXX: check this */
492267002cdSbellard                 d->devaddr = buf[1] & 0xf;
493267002cdSbellard                 break;
494267002cdSbellard             }
495267002cdSbellard         }
496267002cdSbellard         break;
497267002cdSbellard     case ADB_READREG:
498267002cdSbellard         switch(reg) {
499bec9d989Sbellard         case 0:
500bec9d989Sbellard             olen = adb_mouse_poll(d, obuf);
501bec9d989Sbellard             break;
502267002cdSbellard         case 1:
503267002cdSbellard             break;
504267002cdSbellard         case 3:
505e2733d20Sbellard             obuf[0] = d->handler;
506e2733d20Sbellard             obuf[1] = d->devaddr;
507e2733d20Sbellard             olen = 2;
508267002cdSbellard             break;
509267002cdSbellard         }
510ea026b2fSblueswir1         ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
511ea026b2fSblueswir1                     obuf[0], obuf[1]);
512267002cdSbellard         break;
513267002cdSbellard     }
514e2733d20Sbellard     return olen;
515267002cdSbellard }
516267002cdSbellard 
5172e4a7c9cSAndreas Färber static void adb_mouse_reset(DeviceState *dev)
5183988e897Sbellard {
5192e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
5202e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(dev);
5213988e897Sbellard 
5223988e897Sbellard     d->handler = 2;
5232e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_MOUSE;
5242e4a7c9cSAndreas Färber     s->last_buttons_state = s->buttons_state = 0;
5252e4a7c9cSAndreas Färber     s->dx = s->dy = s->dz = 0;
5263988e897Sbellard }
5273988e897Sbellard 
5282b2cd592SJuan Quintela static const VMStateDescription vmstate_adb_mouse = {
5292b2cd592SJuan Quintela     .name = "adb_mouse",
530*e5dffaa5SMark Cave-Ayland     .version_id = 2,
531*e5dffaa5SMark Cave-Ayland     .minimum_version_id = 2,
5322b2cd592SJuan Quintela     .fields = (VMStateField[]) {
533*e5dffaa5SMark Cave-Ayland         VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
534*e5dffaa5SMark Cave-Ayland                        ADBDevice),
5352b2cd592SJuan Quintela         VMSTATE_INT32(buttons_state, MouseState),
5362b2cd592SJuan Quintela         VMSTATE_INT32(last_buttons_state, MouseState),
5372b2cd592SJuan Quintela         VMSTATE_INT32(dx, MouseState),
5382b2cd592SJuan Quintela         VMSTATE_INT32(dy, MouseState),
5392b2cd592SJuan Quintela         VMSTATE_INT32(dz, MouseState),
5402b2cd592SJuan Quintela         VMSTATE_END_OF_LIST()
5419b64997fSblueswir1     }
5422b2cd592SJuan Quintela };
5439b64997fSblueswir1 
5442e4a7c9cSAndreas Färber static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
545267002cdSbellard {
5462e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(dev);
5472e4a7c9cSAndreas Färber     ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
548267002cdSbellard 
5492e4a7c9cSAndreas Färber     amc->parent_realize(dev, errp);
5502e4a7c9cSAndreas Färber 
5512e4a7c9cSAndreas Färber     qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
552267002cdSbellard }
55384ede329SAndreas Färber 
5542e4a7c9cSAndreas Färber static void adb_mouse_initfn(Object *obj)
5552e4a7c9cSAndreas Färber {
5562e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(obj);
5572e4a7c9cSAndreas Färber 
5582e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_MOUSE;
5592e4a7c9cSAndreas Färber }
5602e4a7c9cSAndreas Färber 
5612e4a7c9cSAndreas Färber static void adb_mouse_class_init(ObjectClass *oc, void *data)
5622e4a7c9cSAndreas Färber {
5632e4a7c9cSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
5642e4a7c9cSAndreas Färber     ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
5652e4a7c9cSAndreas Färber     ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
5662e4a7c9cSAndreas Färber 
5672e4a7c9cSAndreas Färber     amc->parent_realize = dc->realize;
5682e4a7c9cSAndreas Färber     dc->realize = adb_mouse_realizefn;
5692e4a7c9cSAndreas Färber 
5702e4a7c9cSAndreas Färber     adc->devreq = adb_mouse_request;
5712e4a7c9cSAndreas Färber     dc->reset = adb_mouse_reset;
5722e4a7c9cSAndreas Färber     dc->vmsd = &vmstate_adb_mouse;
5732e4a7c9cSAndreas Färber }
5742e4a7c9cSAndreas Färber 
5752e4a7c9cSAndreas Färber static const TypeInfo adb_mouse_type_info = {
5762e4a7c9cSAndreas Färber     .name = TYPE_ADB_MOUSE,
5772e4a7c9cSAndreas Färber     .parent = TYPE_ADB_DEVICE,
5782e4a7c9cSAndreas Färber     .instance_size = sizeof(MouseState),
5792e4a7c9cSAndreas Färber     .instance_init = adb_mouse_initfn,
5802e4a7c9cSAndreas Färber     .class_init = adb_mouse_class_init,
5812e4a7c9cSAndreas Färber     .class_size = sizeof(ADBMouseClass),
5822e4a7c9cSAndreas Färber };
5832e4a7c9cSAndreas Färber 
58484ede329SAndreas Färber 
58584ede329SAndreas Färber static void adb_register_types(void)
58684ede329SAndreas Färber {
58784ede329SAndreas Färber     type_register_static(&adb_bus_type_info);
5882e4a7c9cSAndreas Färber     type_register_static(&adb_device_type_info);
5892e4a7c9cSAndreas Färber     type_register_static(&adb_kbd_type_info);
5902e4a7c9cSAndreas Färber     type_register_static(&adb_mouse_type_info);
59184ede329SAndreas Färber }
59284ede329SAndreas Färber 
59384ede329SAndreas Färber type_init(adb_register_types)
594