xref: /qemu/hw/input/adb.c (revision 0430891ce162b986c6e02a7729a942ecd2a32ca4)
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  */
24*0430891cSPeter Maydell #include "qemu/osdep.h"
2583c9f4caSPaolo Bonzini #include "hw/hw.h"
260d09e41aSPaolo Bonzini #include "hw/input/adb.h"
2728ecbaeeSPaolo Bonzini #include "ui/console.h"
28267002cdSbellard 
29ea026b2fSblueswir1 /* debug ADB */
30ea026b2fSblueswir1 //#define DEBUG_ADB
31ea026b2fSblueswir1 
32ea026b2fSblueswir1 #ifdef DEBUG_ADB
33001faf32SBlue Swirl #define ADB_DPRINTF(fmt, ...) \
34001faf32SBlue Swirl do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
35ea026b2fSblueswir1 #else
36001faf32SBlue Swirl #define ADB_DPRINTF(fmt, ...)
37ea026b2fSblueswir1 #endif
38ea026b2fSblueswir1 
39267002cdSbellard /* ADB commands */
40267002cdSbellard #define ADB_BUSRESET		0x00
41267002cdSbellard #define ADB_FLUSH               0x01
42267002cdSbellard #define ADB_WRITEREG		0x08
43267002cdSbellard #define ADB_READREG		0x0c
44267002cdSbellard 
45267002cdSbellard /* ADB device commands */
46267002cdSbellard #define ADB_CMD_SELF_TEST		0xff
47267002cdSbellard #define ADB_CMD_CHANGE_ID		0xfe
48267002cdSbellard #define ADB_CMD_CHANGE_ID_AND_ACT	0xfd
49267002cdSbellard #define ADB_CMD_CHANGE_ID_AND_ENABLE	0x00
50267002cdSbellard 
51267002cdSbellard /* ADB default device IDs (upper 4 bits of ADB command byte) */
522e4a7c9cSAndreas Färber #define ADB_DEVID_DONGLE   1
532e4a7c9cSAndreas Färber #define ADB_DEVID_KEYBOARD 2
542e4a7c9cSAndreas Färber #define ADB_DEVID_MOUSE    3
552e4a7c9cSAndreas Färber #define ADB_DEVID_TABLET   4
562e4a7c9cSAndreas Färber #define ADB_DEVID_MODEM    5
572e4a7c9cSAndreas Färber #define ADB_DEVID_MISC     7
58267002cdSbellard 
59bec9d989Sbellard /* error codes */
60bec9d989Sbellard #define ADB_RET_NOTPRESENT (-2)
61bec9d989Sbellard 
622e4a7c9cSAndreas Färber static void adb_device_reset(ADBDevice *d)
632e4a7c9cSAndreas Färber {
642e4a7c9cSAndreas Färber     qdev_reset_all(DEVICE(d));
652e4a7c9cSAndreas Färber }
662e4a7c9cSAndreas Färber 
67e2733d20Sbellard int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
68267002cdSbellard {
69267002cdSbellard     ADBDevice *d;
70267002cdSbellard     int devaddr, cmd, i;
71267002cdSbellard 
72819e712bSbellard     cmd = buf[0] & 0xf;
73bec9d989Sbellard     if (cmd == ADB_BUSRESET) {
74bec9d989Sbellard         for(i = 0; i < s->nb_devices; i++) {
752e4a7c9cSAndreas Färber             d = s->devices[i];
762e4a7c9cSAndreas Färber             adb_device_reset(d);
77bec9d989Sbellard         }
78bec9d989Sbellard         return 0;
79bec9d989Sbellard     }
80819e712bSbellard     devaddr = buf[0] >> 4;
81267002cdSbellard     for(i = 0; i < s->nb_devices; i++) {
822e4a7c9cSAndreas Färber         d = s->devices[i];
83267002cdSbellard         if (d->devaddr == devaddr) {
842e4a7c9cSAndreas Färber             ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d);
852e4a7c9cSAndreas Färber             return adc->devreq(d, obuf, buf, len);
86267002cdSbellard         }
87267002cdSbellard     }
88bec9d989Sbellard     return ADB_RET_NOTPRESENT;
89e2733d20Sbellard }
90e2733d20Sbellard 
91bec9d989Sbellard /* XXX: move that to cuda ? */
92e2733d20Sbellard int adb_poll(ADBBusState *s, uint8_t *obuf)
93e2733d20Sbellard {
94e2733d20Sbellard     ADBDevice *d;
95e2733d20Sbellard     int olen, i;
96bec9d989Sbellard     uint8_t buf[1];
97e2733d20Sbellard 
98e2733d20Sbellard     olen = 0;
99e2733d20Sbellard     for(i = 0; i < s->nb_devices; i++) {
100e2733d20Sbellard         if (s->poll_index >= s->nb_devices)
101e2733d20Sbellard             s->poll_index = 0;
1022e4a7c9cSAndreas Färber         d = s->devices[s->poll_index];
103bec9d989Sbellard         buf[0] = ADB_READREG | (d->devaddr << 4);
104bec9d989Sbellard         olen = adb_request(s, obuf + 1, buf, 1);
105bec9d989Sbellard         /* if there is data, we poll again the same device */
106bec9d989Sbellard         if (olen > 0) {
107bec9d989Sbellard             obuf[0] = buf[0];
108bec9d989Sbellard             olen++;
109e2733d20Sbellard             break;
110e2733d20Sbellard         }
111bec9d989Sbellard         s->poll_index++;
112bec9d989Sbellard     }
113e2733d20Sbellard     return olen;
114267002cdSbellard }
115267002cdSbellard 
11684ede329SAndreas Färber static const TypeInfo adb_bus_type_info = {
11784ede329SAndreas Färber     .name = TYPE_ADB_BUS,
11884ede329SAndreas Färber     .parent = TYPE_BUS,
11984ede329SAndreas Färber     .instance_size = sizeof(ADBBusState),
12084ede329SAndreas Färber };
12184ede329SAndreas Färber 
122e5dffaa5SMark Cave-Ayland static const VMStateDescription vmstate_adb_device = {
123e5dffaa5SMark Cave-Ayland     .name = "adb_device",
124e5dffaa5SMark Cave-Ayland     .version_id = 0,
125e5dffaa5SMark Cave-Ayland     .minimum_version_id = 0,
126e5dffaa5SMark Cave-Ayland     .fields = (VMStateField[]) {
127e5dffaa5SMark Cave-Ayland         VMSTATE_INT32(devaddr, ADBDevice),
128e5dffaa5SMark Cave-Ayland         VMSTATE_INT32(handler, ADBDevice),
129e5dffaa5SMark Cave-Ayland         VMSTATE_END_OF_LIST()
130e5dffaa5SMark Cave-Ayland     }
131e5dffaa5SMark Cave-Ayland };
132e5dffaa5SMark Cave-Ayland 
1332e4a7c9cSAndreas Färber static void adb_device_realizefn(DeviceState *dev, Error **errp)
1342e4a7c9cSAndreas Färber {
1352e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
1362e4a7c9cSAndreas Färber     ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev));
1372e4a7c9cSAndreas Färber 
1382e4a7c9cSAndreas Färber     if (bus->nb_devices >= MAX_ADB_DEVICES) {
1392e4a7c9cSAndreas Färber         return;
1402e4a7c9cSAndreas Färber     }
1412e4a7c9cSAndreas Färber 
1422e4a7c9cSAndreas Färber     bus->devices[bus->nb_devices++] = d;
1432e4a7c9cSAndreas Färber }
1442e4a7c9cSAndreas Färber 
1452e4a7c9cSAndreas Färber static void adb_device_class_init(ObjectClass *oc, void *data)
1462e4a7c9cSAndreas Färber {
1472e4a7c9cSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
1482e4a7c9cSAndreas Färber 
1492e4a7c9cSAndreas Färber     dc->realize = adb_device_realizefn;
1502e4a7c9cSAndreas Färber     dc->bus_type = TYPE_ADB_BUS;
1512e4a7c9cSAndreas Färber }
1522e4a7c9cSAndreas Färber 
1532e4a7c9cSAndreas Färber static const TypeInfo adb_device_type_info = {
1542e4a7c9cSAndreas Färber     .name = TYPE_ADB_DEVICE,
1552e4a7c9cSAndreas Färber     .parent = TYPE_DEVICE,
1562e4a7c9cSAndreas Färber     .instance_size = sizeof(ADBDevice),
1572e4a7c9cSAndreas Färber     .abstract = true,
1582e4a7c9cSAndreas Färber     .class_init = adb_device_class_init,
1592e4a7c9cSAndreas Färber };
1602e4a7c9cSAndreas Färber 
161267002cdSbellard /***************************************************************/
162267002cdSbellard /* Keyboard ADB device */
163267002cdSbellard 
1642e4a7c9cSAndreas Färber #define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD)
1652e4a7c9cSAndreas Färber 
166e2733d20Sbellard typedef struct KBDState {
1672e4a7c9cSAndreas Färber     /*< private >*/
1682e4a7c9cSAndreas Färber     ADBDevice parent_obj;
1692e4a7c9cSAndreas Färber     /*< public >*/
1702e4a7c9cSAndreas Färber 
171e2733d20Sbellard     uint8_t data[128];
172e2733d20Sbellard     int rptr, wptr, count;
173e2733d20Sbellard } KBDState;
174e2733d20Sbellard 
1752e4a7c9cSAndreas Färber #define ADB_KEYBOARD_CLASS(class) \
1762e4a7c9cSAndreas Färber     OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD)
1772e4a7c9cSAndreas Färber #define ADB_KEYBOARD_GET_CLASS(obj) \
1782e4a7c9cSAndreas Färber     OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD)
1792e4a7c9cSAndreas Färber 
1802e4a7c9cSAndreas Färber typedef struct ADBKeyboardClass {
1812e4a7c9cSAndreas Färber     /*< private >*/
1822e4a7c9cSAndreas Färber     ADBDeviceClass parent_class;
1832e4a7c9cSAndreas Färber     /*< public >*/
1842e4a7c9cSAndreas Färber 
1852e4a7c9cSAndreas Färber     DeviceRealize parent_realize;
1862e4a7c9cSAndreas Färber } ADBKeyboardClass;
1872e4a7c9cSAndreas Färber 
188267002cdSbellard static const uint8_t pc_to_adb_keycode[256] = {
189267002cdSbellard   0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
190267002cdSbellard  12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
191267002cdSbellard   2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
192267002cdSbellard  11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
193267002cdSbellard  97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
194e2733d20Sbellard  84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
195267002cdSbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
196267002cdSbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
197e2733d20Sbellard   0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
198e2733d20Sbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
199e2733d20Sbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
200e2733d20Sbellard   0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
201e2733d20Sbellard   0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
202e2733d20Sbellard  61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
203267002cdSbellard   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
204e2733d20Sbellard   0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
205267002cdSbellard };
206267002cdSbellard 
207267002cdSbellard static void adb_kbd_put_keycode(void *opaque, int keycode)
208267002cdSbellard {
2092e4a7c9cSAndreas Färber     KBDState *s = opaque;
210e2733d20Sbellard 
211e2733d20Sbellard     if (s->count < sizeof(s->data)) {
212e2733d20Sbellard         s->data[s->wptr] = keycode;
213e2733d20Sbellard         if (++s->wptr == sizeof(s->data))
214e2733d20Sbellard             s->wptr = 0;
215e2733d20Sbellard         s->count++;
216e2733d20Sbellard     }
217e2733d20Sbellard }
218e2733d20Sbellard 
219e2733d20Sbellard static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
220e2733d20Sbellard {
221e2733d20Sbellard     static int ext_keycode;
2222e4a7c9cSAndreas Färber     KBDState *s = ADB_KEYBOARD(d);
223e2733d20Sbellard     int adb_keycode, keycode;
224e2733d20Sbellard     int olen;
225e2733d20Sbellard 
226e2733d20Sbellard     olen = 0;
227e2733d20Sbellard     for(;;) {
228e2733d20Sbellard         if (s->count == 0)
229e2733d20Sbellard             break;
230e2733d20Sbellard         keycode = s->data[s->rptr];
231e2733d20Sbellard         if (++s->rptr == sizeof(s->data))
232e2733d20Sbellard             s->rptr = 0;
233e2733d20Sbellard         s->count--;
234267002cdSbellard 
235267002cdSbellard         if (keycode == 0xe0) {
236267002cdSbellard             ext_keycode = 1;
237267002cdSbellard         } else {
238267002cdSbellard             if (ext_keycode)
239267002cdSbellard                 adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
240267002cdSbellard             else
241267002cdSbellard                 adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
242bec9d989Sbellard             obuf[0] = adb_keycode | (keycode & 0x80);
243bec9d989Sbellard             /* NOTE: could put a second keycode if needed */
244bec9d989Sbellard             obuf[1] = 0xff;
245bec9d989Sbellard             olen = 2;
246267002cdSbellard             ext_keycode = 0;
247e2733d20Sbellard             break;
248267002cdSbellard         }
249267002cdSbellard     }
250e2733d20Sbellard     return olen;
251e2733d20Sbellard }
252267002cdSbellard 
253e2733d20Sbellard static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
254e2733d20Sbellard                            const uint8_t *buf, int len)
255267002cdSbellard {
2562e4a7c9cSAndreas Färber     KBDState *s = ADB_KEYBOARD(d);
257e2733d20Sbellard     int cmd, reg, olen;
258e2733d20Sbellard 
259bec9d989Sbellard     if ((buf[0] & 0x0f) == ADB_FLUSH) {
260bec9d989Sbellard         /* flush keyboard fifo */
261bec9d989Sbellard         s->wptr = s->rptr = s->count = 0;
262bec9d989Sbellard         return 0;
263e2733d20Sbellard     }
264267002cdSbellard 
265267002cdSbellard     cmd = buf[0] & 0xc;
266267002cdSbellard     reg = buf[0] & 0x3;
267e2733d20Sbellard     olen = 0;
268267002cdSbellard     switch(cmd) {
269267002cdSbellard     case ADB_WRITEREG:
270267002cdSbellard         switch(reg) {
271267002cdSbellard         case 2:
272267002cdSbellard             /* LED status */
273267002cdSbellard             break;
274267002cdSbellard         case 3:
275267002cdSbellard             switch(buf[2]) {
276267002cdSbellard             case ADB_CMD_SELF_TEST:
277267002cdSbellard                 break;
278267002cdSbellard             case ADB_CMD_CHANGE_ID:
279267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ACT:
280267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ENABLE:
281267002cdSbellard                 d->devaddr = buf[1] & 0xf;
282267002cdSbellard                 break;
283267002cdSbellard             default:
284267002cdSbellard                 /* XXX: check this */
285267002cdSbellard                 d->devaddr = buf[1] & 0xf;
286267002cdSbellard                 d->handler = buf[2];
287267002cdSbellard                 break;
288267002cdSbellard             }
289267002cdSbellard         }
290267002cdSbellard         break;
291267002cdSbellard     case ADB_READREG:
292267002cdSbellard         switch(reg) {
293bec9d989Sbellard         case 0:
294bec9d989Sbellard             olen = adb_kbd_poll(d, obuf);
295bec9d989Sbellard             break;
296267002cdSbellard         case 1:
297267002cdSbellard             break;
298267002cdSbellard         case 2:
299e2733d20Sbellard             obuf[0] = 0x00; /* XXX: check this */
300e2733d20Sbellard             obuf[1] = 0x07; /* led status */
301e2733d20Sbellard             olen = 2;
302267002cdSbellard             break;
303267002cdSbellard         case 3:
304e2733d20Sbellard             obuf[0] = d->handler;
305e2733d20Sbellard             obuf[1] = d->devaddr;
306e2733d20Sbellard             olen = 2;
307267002cdSbellard             break;
308267002cdSbellard         }
309267002cdSbellard         break;
310267002cdSbellard     }
311e2733d20Sbellard     return olen;
312267002cdSbellard }
313267002cdSbellard 
3141f1f0600SJuan Quintela static const VMStateDescription vmstate_adb_kbd = {
3151f1f0600SJuan Quintela     .name = "adb_kbd",
316e5dffaa5SMark Cave-Ayland     .version_id = 2,
317e5dffaa5SMark Cave-Ayland     .minimum_version_id = 2,
3181f1f0600SJuan Quintela     .fields = (VMStateField[]) {
319e5dffaa5SMark Cave-Ayland         VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice),
3201f1f0600SJuan Quintela         VMSTATE_BUFFER(data, KBDState),
3211f1f0600SJuan Quintela         VMSTATE_INT32(rptr, KBDState),
3221f1f0600SJuan Quintela         VMSTATE_INT32(wptr, KBDState),
3231f1f0600SJuan Quintela         VMSTATE_INT32(count, KBDState),
3241f1f0600SJuan Quintela         VMSTATE_END_OF_LIST()
3259b64997fSblueswir1     }
3261f1f0600SJuan Quintela };
3279b64997fSblueswir1 
3282e4a7c9cSAndreas Färber static void adb_kbd_reset(DeviceState *dev)
3293988e897Sbellard {
3302e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
3312e4a7c9cSAndreas Färber     KBDState *s = ADB_KEYBOARD(dev);
3323988e897Sbellard 
3333988e897Sbellard     d->handler = 1;
3342e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_KEYBOARD;
3352e4a7c9cSAndreas Färber     memset(s->data, 0, sizeof(s->data));
3362e4a7c9cSAndreas Färber     s->rptr = 0;
3372e4a7c9cSAndreas Färber     s->wptr = 0;
3382e4a7c9cSAndreas Färber     s->count = 0;
3393988e897Sbellard }
3403988e897Sbellard 
3412e4a7c9cSAndreas Färber static void adb_kbd_realizefn(DeviceState *dev, Error **errp)
342267002cdSbellard {
3432e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
3442e4a7c9cSAndreas Färber     ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev);
3452e4a7c9cSAndreas Färber 
3462e4a7c9cSAndreas Färber     akc->parent_realize(dev, errp);
3472e4a7c9cSAndreas Färber 
348267002cdSbellard     qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
349267002cdSbellard }
350267002cdSbellard 
3512e4a7c9cSAndreas Färber static void adb_kbd_initfn(Object *obj)
3522e4a7c9cSAndreas Färber {
3532e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(obj);
3542e4a7c9cSAndreas Färber 
3552e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_KEYBOARD;
3562e4a7c9cSAndreas Färber }
3572e4a7c9cSAndreas Färber 
3582e4a7c9cSAndreas Färber static void adb_kbd_class_init(ObjectClass *oc, void *data)
3592e4a7c9cSAndreas Färber {
3602e4a7c9cSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
3612e4a7c9cSAndreas Färber     ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
3622e4a7c9cSAndreas Färber     ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc);
3632e4a7c9cSAndreas Färber 
3642e4a7c9cSAndreas Färber     akc->parent_realize = dc->realize;
3652e4a7c9cSAndreas Färber     dc->realize = adb_kbd_realizefn;
36632f3a899SLaurent Vivier     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
3672e4a7c9cSAndreas Färber 
3682e4a7c9cSAndreas Färber     adc->devreq = adb_kbd_request;
3692e4a7c9cSAndreas Färber     dc->reset = adb_kbd_reset;
3702e4a7c9cSAndreas Färber     dc->vmsd = &vmstate_adb_kbd;
3712e4a7c9cSAndreas Färber }
3722e4a7c9cSAndreas Färber 
3732e4a7c9cSAndreas Färber static const TypeInfo adb_kbd_type_info = {
3742e4a7c9cSAndreas Färber     .name = TYPE_ADB_KEYBOARD,
3752e4a7c9cSAndreas Färber     .parent = TYPE_ADB_DEVICE,
3762e4a7c9cSAndreas Färber     .instance_size = sizeof(KBDState),
3772e4a7c9cSAndreas Färber     .instance_init = adb_kbd_initfn,
3782e4a7c9cSAndreas Färber     .class_init = adb_kbd_class_init,
3792e4a7c9cSAndreas Färber     .class_size = sizeof(ADBKeyboardClass),
3802e4a7c9cSAndreas Färber };
3812e4a7c9cSAndreas Färber 
382267002cdSbellard /***************************************************************/
383267002cdSbellard /* Mouse ADB device */
384267002cdSbellard 
3852e4a7c9cSAndreas Färber #define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
3862e4a7c9cSAndreas Färber 
387e2733d20Sbellard typedef struct MouseState {
3882e4a7c9cSAndreas Färber     /*< public >*/
3892e4a7c9cSAndreas Färber     ADBDevice parent_obj;
3902e4a7c9cSAndreas Färber     /*< private >*/
3912e4a7c9cSAndreas Färber 
392e2733d20Sbellard     int buttons_state, last_buttons_state;
393e2733d20Sbellard     int dx, dy, dz;
394e2733d20Sbellard } MouseState;
395e2733d20Sbellard 
3962e4a7c9cSAndreas Färber #define ADB_MOUSE_CLASS(class) \
3972e4a7c9cSAndreas Färber     OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
3982e4a7c9cSAndreas Färber #define ADB_MOUSE_GET_CLASS(obj) \
3992e4a7c9cSAndreas Färber     OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
4002e4a7c9cSAndreas Färber 
4012e4a7c9cSAndreas Färber typedef struct ADBMouseClass {
4022e4a7c9cSAndreas Färber     /*< public >*/
4032e4a7c9cSAndreas Färber     ADBDeviceClass parent_class;
4042e4a7c9cSAndreas Färber     /*< private >*/
4052e4a7c9cSAndreas Färber 
4062e4a7c9cSAndreas Färber     DeviceRealize parent_realize;
4072e4a7c9cSAndreas Färber } ADBMouseClass;
4082e4a7c9cSAndreas Färber 
409267002cdSbellard static void adb_mouse_event(void *opaque,
410267002cdSbellard                             int dx1, int dy1, int dz1, int buttons_state)
411267002cdSbellard {
4122e4a7c9cSAndreas Färber     MouseState *s = opaque;
413e2733d20Sbellard 
414e2733d20Sbellard     s->dx += dx1;
415e2733d20Sbellard     s->dy += dy1;
416e2733d20Sbellard     s->dz += dz1;
417e2733d20Sbellard     s->buttons_state = buttons_state;
418e2733d20Sbellard }
419e2733d20Sbellard 
420e2733d20Sbellard 
421e2733d20Sbellard static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
422e2733d20Sbellard {
4232e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(d);
424267002cdSbellard     int dx, dy;
425267002cdSbellard 
426e2733d20Sbellard     if (s->last_buttons_state == s->buttons_state &&
427e2733d20Sbellard         s->dx == 0 && s->dy == 0)
428e2733d20Sbellard         return 0;
429e2733d20Sbellard 
430e2733d20Sbellard     dx = s->dx;
431267002cdSbellard     if (dx < -63)
432267002cdSbellard         dx = -63;
433267002cdSbellard     else if (dx > 63)
434267002cdSbellard         dx = 63;
435267002cdSbellard 
436e2733d20Sbellard     dy = s->dy;
437267002cdSbellard     if (dy < -63)
438267002cdSbellard         dy = -63;
439267002cdSbellard     else if (dy > 63)
440267002cdSbellard         dy = 63;
441267002cdSbellard 
442e2733d20Sbellard     s->dx -= dx;
443e2733d20Sbellard     s->dy -= dy;
444e2733d20Sbellard     s->last_buttons_state = s->buttons_state;
445e2733d20Sbellard 
446267002cdSbellard     dx &= 0x7f;
447267002cdSbellard     dy &= 0x7f;
448267002cdSbellard 
449bec9d989Sbellard     if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
450267002cdSbellard         dy |= 0x80;
451bec9d989Sbellard     if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
452267002cdSbellard         dx |= 0x80;
453267002cdSbellard 
454bec9d989Sbellard     obuf[0] = dy;
455bec9d989Sbellard     obuf[1] = dx;
456bec9d989Sbellard     return 2;
457267002cdSbellard }
458267002cdSbellard 
459e2733d20Sbellard static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
460e2733d20Sbellard                              const uint8_t *buf, int len)
461267002cdSbellard {
4622e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(d);
463e2733d20Sbellard     int cmd, reg, olen;
464e2733d20Sbellard 
465bec9d989Sbellard     if ((buf[0] & 0x0f) == ADB_FLUSH) {
466bec9d989Sbellard         /* flush mouse fifo */
467bec9d989Sbellard         s->buttons_state = s->last_buttons_state;
468bec9d989Sbellard         s->dx = 0;
469bec9d989Sbellard         s->dy = 0;
470bec9d989Sbellard         s->dz = 0;
471bec9d989Sbellard         return 0;
472e2733d20Sbellard     }
473267002cdSbellard 
474267002cdSbellard     cmd = buf[0] & 0xc;
475267002cdSbellard     reg = buf[0] & 0x3;
476e2733d20Sbellard     olen = 0;
477267002cdSbellard     switch(cmd) {
478267002cdSbellard     case ADB_WRITEREG:
479ea026b2fSblueswir1         ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
480267002cdSbellard         switch(reg) {
481267002cdSbellard         case 2:
482267002cdSbellard             break;
483267002cdSbellard         case 3:
484267002cdSbellard             switch(buf[2]) {
485267002cdSbellard             case ADB_CMD_SELF_TEST:
486267002cdSbellard                 break;
487267002cdSbellard             case ADB_CMD_CHANGE_ID:
488267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ACT:
489267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ENABLE:
490267002cdSbellard                 d->devaddr = buf[1] & 0xf;
491267002cdSbellard                 break;
492267002cdSbellard             default:
493267002cdSbellard                 /* XXX: check this */
494267002cdSbellard                 d->devaddr = buf[1] & 0xf;
495267002cdSbellard                 break;
496267002cdSbellard             }
497267002cdSbellard         }
498267002cdSbellard         break;
499267002cdSbellard     case ADB_READREG:
500267002cdSbellard         switch(reg) {
501bec9d989Sbellard         case 0:
502bec9d989Sbellard             olen = adb_mouse_poll(d, obuf);
503bec9d989Sbellard             break;
504267002cdSbellard         case 1:
505267002cdSbellard             break;
506267002cdSbellard         case 3:
507e2733d20Sbellard             obuf[0] = d->handler;
508e2733d20Sbellard             obuf[1] = d->devaddr;
509e2733d20Sbellard             olen = 2;
510267002cdSbellard             break;
511267002cdSbellard         }
512ea026b2fSblueswir1         ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
513ea026b2fSblueswir1                     obuf[0], obuf[1]);
514267002cdSbellard         break;
515267002cdSbellard     }
516e2733d20Sbellard     return olen;
517267002cdSbellard }
518267002cdSbellard 
5192e4a7c9cSAndreas Färber static void adb_mouse_reset(DeviceState *dev)
5203988e897Sbellard {
5212e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
5222e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(dev);
5233988e897Sbellard 
5243988e897Sbellard     d->handler = 2;
5252e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_MOUSE;
5262e4a7c9cSAndreas Färber     s->last_buttons_state = s->buttons_state = 0;
5272e4a7c9cSAndreas Färber     s->dx = s->dy = s->dz = 0;
5283988e897Sbellard }
5293988e897Sbellard 
5302b2cd592SJuan Quintela static const VMStateDescription vmstate_adb_mouse = {
5312b2cd592SJuan Quintela     .name = "adb_mouse",
532e5dffaa5SMark Cave-Ayland     .version_id = 2,
533e5dffaa5SMark Cave-Ayland     .minimum_version_id = 2,
5342b2cd592SJuan Quintela     .fields = (VMStateField[]) {
535e5dffaa5SMark Cave-Ayland         VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
536e5dffaa5SMark Cave-Ayland                        ADBDevice),
5372b2cd592SJuan Quintela         VMSTATE_INT32(buttons_state, MouseState),
5382b2cd592SJuan Quintela         VMSTATE_INT32(last_buttons_state, MouseState),
5392b2cd592SJuan Quintela         VMSTATE_INT32(dx, MouseState),
5402b2cd592SJuan Quintela         VMSTATE_INT32(dy, MouseState),
5412b2cd592SJuan Quintela         VMSTATE_INT32(dz, MouseState),
5422b2cd592SJuan Quintela         VMSTATE_END_OF_LIST()
5439b64997fSblueswir1     }
5442b2cd592SJuan Quintela };
5459b64997fSblueswir1 
5462e4a7c9cSAndreas Färber static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
547267002cdSbellard {
5482e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(dev);
5492e4a7c9cSAndreas Färber     ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
550267002cdSbellard 
5512e4a7c9cSAndreas Färber     amc->parent_realize(dev, errp);
5522e4a7c9cSAndreas Färber 
5532e4a7c9cSAndreas Färber     qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
554267002cdSbellard }
55584ede329SAndreas Färber 
5562e4a7c9cSAndreas Färber static void adb_mouse_initfn(Object *obj)
5572e4a7c9cSAndreas Färber {
5582e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(obj);
5592e4a7c9cSAndreas Färber 
5602e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_MOUSE;
5612e4a7c9cSAndreas Färber }
5622e4a7c9cSAndreas Färber 
5632e4a7c9cSAndreas Färber static void adb_mouse_class_init(ObjectClass *oc, void *data)
5642e4a7c9cSAndreas Färber {
5652e4a7c9cSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
5662e4a7c9cSAndreas Färber     ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
5672e4a7c9cSAndreas Färber     ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
5682e4a7c9cSAndreas Färber 
5692e4a7c9cSAndreas Färber     amc->parent_realize = dc->realize;
5702e4a7c9cSAndreas Färber     dc->realize = adb_mouse_realizefn;
57132f3a899SLaurent Vivier     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
5722e4a7c9cSAndreas Färber 
5732e4a7c9cSAndreas Färber     adc->devreq = adb_mouse_request;
5742e4a7c9cSAndreas Färber     dc->reset = adb_mouse_reset;
5752e4a7c9cSAndreas Färber     dc->vmsd = &vmstate_adb_mouse;
5762e4a7c9cSAndreas Färber }
5772e4a7c9cSAndreas Färber 
5782e4a7c9cSAndreas Färber static const TypeInfo adb_mouse_type_info = {
5792e4a7c9cSAndreas Färber     .name = TYPE_ADB_MOUSE,
5802e4a7c9cSAndreas Färber     .parent = TYPE_ADB_DEVICE,
5812e4a7c9cSAndreas Färber     .instance_size = sizeof(MouseState),
5822e4a7c9cSAndreas Färber     .instance_init = adb_mouse_initfn,
5832e4a7c9cSAndreas Färber     .class_init = adb_mouse_class_init,
5842e4a7c9cSAndreas Färber     .class_size = sizeof(ADBMouseClass),
5852e4a7c9cSAndreas Färber };
5862e4a7c9cSAndreas Färber 
58784ede329SAndreas Färber 
58884ede329SAndreas Färber static void adb_register_types(void)
58984ede329SAndreas Färber {
59084ede329SAndreas Färber     type_register_static(&adb_bus_type_info);
5912e4a7c9cSAndreas Färber     type_register_static(&adb_device_type_info);
5922e4a7c9cSAndreas Färber     type_register_static(&adb_kbd_type_info);
5932e4a7c9cSAndreas Färber     type_register_static(&adb_mouse_type_info);
59484ede329SAndreas Färber }
59584ede329SAndreas Färber 
59684ede329SAndreas Färber type_init(adb_register_types)
597