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