xref: /qemu/hw/input/adb.c (revision 32f3a8992ea28a194678832eec1e1ffc09cbb7b1)
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 
121e5dffaa5SMark Cave-Ayland static const VMStateDescription vmstate_adb_device = {
122e5dffaa5SMark Cave-Ayland     .name = "adb_device",
123e5dffaa5SMark Cave-Ayland     .version_id = 0,
124e5dffaa5SMark Cave-Ayland     .minimum_version_id = 0,
125e5dffaa5SMark Cave-Ayland     .fields = (VMStateField[]) {
126e5dffaa5SMark Cave-Ayland         VMSTATE_INT32(devaddr, ADBDevice),
127e5dffaa5SMark Cave-Ayland         VMSTATE_INT32(handler, ADBDevice),
128e5dffaa5SMark Cave-Ayland         VMSTATE_END_OF_LIST()
129e5dffaa5SMark Cave-Ayland     }
130e5dffaa5SMark Cave-Ayland };
131e5dffaa5SMark 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",
315e5dffaa5SMark Cave-Ayland     .version_id = 2,
316e5dffaa5SMark Cave-Ayland     .minimum_version_id = 2,
3171f1f0600SJuan Quintela     .fields = (VMStateField[]) {
318e5dffaa5SMark 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;
365*32f3a899SLaurent Vivier     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
3662e4a7c9cSAndreas Färber 
3672e4a7c9cSAndreas Färber     adc->devreq = adb_kbd_request;
3682e4a7c9cSAndreas Färber     dc->reset = adb_kbd_reset;
3692e4a7c9cSAndreas Färber     dc->vmsd = &vmstate_adb_kbd;
3702e4a7c9cSAndreas Färber }
3712e4a7c9cSAndreas Färber 
3722e4a7c9cSAndreas Färber static const TypeInfo adb_kbd_type_info = {
3732e4a7c9cSAndreas Färber     .name = TYPE_ADB_KEYBOARD,
3742e4a7c9cSAndreas Färber     .parent = TYPE_ADB_DEVICE,
3752e4a7c9cSAndreas Färber     .instance_size = sizeof(KBDState),
3762e4a7c9cSAndreas Färber     .instance_init = adb_kbd_initfn,
3772e4a7c9cSAndreas Färber     .class_init = adb_kbd_class_init,
3782e4a7c9cSAndreas Färber     .class_size = sizeof(ADBKeyboardClass),
3792e4a7c9cSAndreas Färber };
3802e4a7c9cSAndreas Färber 
381267002cdSbellard /***************************************************************/
382267002cdSbellard /* Mouse ADB device */
383267002cdSbellard 
3842e4a7c9cSAndreas Färber #define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
3852e4a7c9cSAndreas Färber 
386e2733d20Sbellard typedef struct MouseState {
3872e4a7c9cSAndreas Färber     /*< public >*/
3882e4a7c9cSAndreas Färber     ADBDevice parent_obj;
3892e4a7c9cSAndreas Färber     /*< private >*/
3902e4a7c9cSAndreas Färber 
391e2733d20Sbellard     int buttons_state, last_buttons_state;
392e2733d20Sbellard     int dx, dy, dz;
393e2733d20Sbellard } MouseState;
394e2733d20Sbellard 
3952e4a7c9cSAndreas Färber #define ADB_MOUSE_CLASS(class) \
3962e4a7c9cSAndreas Färber     OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
3972e4a7c9cSAndreas Färber #define ADB_MOUSE_GET_CLASS(obj) \
3982e4a7c9cSAndreas Färber     OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
3992e4a7c9cSAndreas Färber 
4002e4a7c9cSAndreas Färber typedef struct ADBMouseClass {
4012e4a7c9cSAndreas Färber     /*< public >*/
4022e4a7c9cSAndreas Färber     ADBDeviceClass parent_class;
4032e4a7c9cSAndreas Färber     /*< private >*/
4042e4a7c9cSAndreas Färber 
4052e4a7c9cSAndreas Färber     DeviceRealize parent_realize;
4062e4a7c9cSAndreas Färber } ADBMouseClass;
4072e4a7c9cSAndreas Färber 
408267002cdSbellard static void adb_mouse_event(void *opaque,
409267002cdSbellard                             int dx1, int dy1, int dz1, int buttons_state)
410267002cdSbellard {
4112e4a7c9cSAndreas Färber     MouseState *s = opaque;
412e2733d20Sbellard 
413e2733d20Sbellard     s->dx += dx1;
414e2733d20Sbellard     s->dy += dy1;
415e2733d20Sbellard     s->dz += dz1;
416e2733d20Sbellard     s->buttons_state = buttons_state;
417e2733d20Sbellard }
418e2733d20Sbellard 
419e2733d20Sbellard 
420e2733d20Sbellard static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
421e2733d20Sbellard {
4222e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(d);
423267002cdSbellard     int dx, dy;
424267002cdSbellard 
425e2733d20Sbellard     if (s->last_buttons_state == s->buttons_state &&
426e2733d20Sbellard         s->dx == 0 && s->dy == 0)
427e2733d20Sbellard         return 0;
428e2733d20Sbellard 
429e2733d20Sbellard     dx = s->dx;
430267002cdSbellard     if (dx < -63)
431267002cdSbellard         dx = -63;
432267002cdSbellard     else if (dx > 63)
433267002cdSbellard         dx = 63;
434267002cdSbellard 
435e2733d20Sbellard     dy = s->dy;
436267002cdSbellard     if (dy < -63)
437267002cdSbellard         dy = -63;
438267002cdSbellard     else if (dy > 63)
439267002cdSbellard         dy = 63;
440267002cdSbellard 
441e2733d20Sbellard     s->dx -= dx;
442e2733d20Sbellard     s->dy -= dy;
443e2733d20Sbellard     s->last_buttons_state = s->buttons_state;
444e2733d20Sbellard 
445267002cdSbellard     dx &= 0x7f;
446267002cdSbellard     dy &= 0x7f;
447267002cdSbellard 
448bec9d989Sbellard     if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
449267002cdSbellard         dy |= 0x80;
450bec9d989Sbellard     if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
451267002cdSbellard         dx |= 0x80;
452267002cdSbellard 
453bec9d989Sbellard     obuf[0] = dy;
454bec9d989Sbellard     obuf[1] = dx;
455bec9d989Sbellard     return 2;
456267002cdSbellard }
457267002cdSbellard 
458e2733d20Sbellard static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
459e2733d20Sbellard                              const uint8_t *buf, int len)
460267002cdSbellard {
4612e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(d);
462e2733d20Sbellard     int cmd, reg, olen;
463e2733d20Sbellard 
464bec9d989Sbellard     if ((buf[0] & 0x0f) == ADB_FLUSH) {
465bec9d989Sbellard         /* flush mouse fifo */
466bec9d989Sbellard         s->buttons_state = s->last_buttons_state;
467bec9d989Sbellard         s->dx = 0;
468bec9d989Sbellard         s->dy = 0;
469bec9d989Sbellard         s->dz = 0;
470bec9d989Sbellard         return 0;
471e2733d20Sbellard     }
472267002cdSbellard 
473267002cdSbellard     cmd = buf[0] & 0xc;
474267002cdSbellard     reg = buf[0] & 0x3;
475e2733d20Sbellard     olen = 0;
476267002cdSbellard     switch(cmd) {
477267002cdSbellard     case ADB_WRITEREG:
478ea026b2fSblueswir1         ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
479267002cdSbellard         switch(reg) {
480267002cdSbellard         case 2:
481267002cdSbellard             break;
482267002cdSbellard         case 3:
483267002cdSbellard             switch(buf[2]) {
484267002cdSbellard             case ADB_CMD_SELF_TEST:
485267002cdSbellard                 break;
486267002cdSbellard             case ADB_CMD_CHANGE_ID:
487267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ACT:
488267002cdSbellard             case ADB_CMD_CHANGE_ID_AND_ENABLE:
489267002cdSbellard                 d->devaddr = buf[1] & 0xf;
490267002cdSbellard                 break;
491267002cdSbellard             default:
492267002cdSbellard                 /* XXX: check this */
493267002cdSbellard                 d->devaddr = buf[1] & 0xf;
494267002cdSbellard                 break;
495267002cdSbellard             }
496267002cdSbellard         }
497267002cdSbellard         break;
498267002cdSbellard     case ADB_READREG:
499267002cdSbellard         switch(reg) {
500bec9d989Sbellard         case 0:
501bec9d989Sbellard             olen = adb_mouse_poll(d, obuf);
502bec9d989Sbellard             break;
503267002cdSbellard         case 1:
504267002cdSbellard             break;
505267002cdSbellard         case 3:
506e2733d20Sbellard             obuf[0] = d->handler;
507e2733d20Sbellard             obuf[1] = d->devaddr;
508e2733d20Sbellard             olen = 2;
509267002cdSbellard             break;
510267002cdSbellard         }
511ea026b2fSblueswir1         ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
512ea026b2fSblueswir1                     obuf[0], obuf[1]);
513267002cdSbellard         break;
514267002cdSbellard     }
515e2733d20Sbellard     return olen;
516267002cdSbellard }
517267002cdSbellard 
5182e4a7c9cSAndreas Färber static void adb_mouse_reset(DeviceState *dev)
5193988e897Sbellard {
5202e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(dev);
5212e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(dev);
5223988e897Sbellard 
5233988e897Sbellard     d->handler = 2;
5242e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_MOUSE;
5252e4a7c9cSAndreas Färber     s->last_buttons_state = s->buttons_state = 0;
5262e4a7c9cSAndreas Färber     s->dx = s->dy = s->dz = 0;
5273988e897Sbellard }
5283988e897Sbellard 
5292b2cd592SJuan Quintela static const VMStateDescription vmstate_adb_mouse = {
5302b2cd592SJuan Quintela     .name = "adb_mouse",
531e5dffaa5SMark Cave-Ayland     .version_id = 2,
532e5dffaa5SMark Cave-Ayland     .minimum_version_id = 2,
5332b2cd592SJuan Quintela     .fields = (VMStateField[]) {
534e5dffaa5SMark Cave-Ayland         VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device,
535e5dffaa5SMark Cave-Ayland                        ADBDevice),
5362b2cd592SJuan Quintela         VMSTATE_INT32(buttons_state, MouseState),
5372b2cd592SJuan Quintela         VMSTATE_INT32(last_buttons_state, MouseState),
5382b2cd592SJuan Quintela         VMSTATE_INT32(dx, MouseState),
5392b2cd592SJuan Quintela         VMSTATE_INT32(dy, MouseState),
5402b2cd592SJuan Quintela         VMSTATE_INT32(dz, MouseState),
5412b2cd592SJuan Quintela         VMSTATE_END_OF_LIST()
5429b64997fSblueswir1     }
5432b2cd592SJuan Quintela };
5449b64997fSblueswir1 
5452e4a7c9cSAndreas Färber static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
546267002cdSbellard {
5472e4a7c9cSAndreas Färber     MouseState *s = ADB_MOUSE(dev);
5482e4a7c9cSAndreas Färber     ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
549267002cdSbellard 
5502e4a7c9cSAndreas Färber     amc->parent_realize(dev, errp);
5512e4a7c9cSAndreas Färber 
5522e4a7c9cSAndreas Färber     qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
553267002cdSbellard }
55484ede329SAndreas Färber 
5552e4a7c9cSAndreas Färber static void adb_mouse_initfn(Object *obj)
5562e4a7c9cSAndreas Färber {
5572e4a7c9cSAndreas Färber     ADBDevice *d = ADB_DEVICE(obj);
5582e4a7c9cSAndreas Färber 
5592e4a7c9cSAndreas Färber     d->devaddr = ADB_DEVID_MOUSE;
5602e4a7c9cSAndreas Färber }
5612e4a7c9cSAndreas Färber 
5622e4a7c9cSAndreas Färber static void adb_mouse_class_init(ObjectClass *oc, void *data)
5632e4a7c9cSAndreas Färber {
5642e4a7c9cSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
5652e4a7c9cSAndreas Färber     ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
5662e4a7c9cSAndreas Färber     ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
5672e4a7c9cSAndreas Färber 
5682e4a7c9cSAndreas Färber     amc->parent_realize = dc->realize;
5692e4a7c9cSAndreas Färber     dc->realize = adb_mouse_realizefn;
570*32f3a899SLaurent Vivier     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
5712e4a7c9cSAndreas Färber 
5722e4a7c9cSAndreas Färber     adc->devreq = adb_mouse_request;
5732e4a7c9cSAndreas Färber     dc->reset = adb_mouse_reset;
5742e4a7c9cSAndreas Färber     dc->vmsd = &vmstate_adb_mouse;
5752e4a7c9cSAndreas Färber }
5762e4a7c9cSAndreas Färber 
5772e4a7c9cSAndreas Färber static const TypeInfo adb_mouse_type_info = {
5782e4a7c9cSAndreas Färber     .name = TYPE_ADB_MOUSE,
5792e4a7c9cSAndreas Färber     .parent = TYPE_ADB_DEVICE,
5802e4a7c9cSAndreas Färber     .instance_size = sizeof(MouseState),
5812e4a7c9cSAndreas Färber     .instance_init = adb_mouse_initfn,
5822e4a7c9cSAndreas Färber     .class_init = adb_mouse_class_init,
5832e4a7c9cSAndreas Färber     .class_size = sizeof(ADBMouseClass),
5842e4a7c9cSAndreas Färber };
5852e4a7c9cSAndreas Färber 
58684ede329SAndreas Färber 
58784ede329SAndreas Färber static void adb_register_types(void)
58884ede329SAndreas Färber {
58984ede329SAndreas Färber     type_register_static(&adb_bus_type_info);
5902e4a7c9cSAndreas Färber     type_register_static(&adb_device_type_info);
5912e4a7c9cSAndreas Färber     type_register_static(&adb_kbd_type_info);
5922e4a7c9cSAndreas Färber     type_register_static(&adb_mouse_type_info);
59384ede329SAndreas Färber }
59484ede329SAndreas Färber 
59584ede329SAndreas Färber type_init(adb_register_types)
596