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