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