1dcfda673SGerd Hoffmann /* 2dcfda673SGerd Hoffmann * QEMU HID devices 3dcfda673SGerd Hoffmann * 4dcfda673SGerd Hoffmann * Copyright (c) 2005 Fabrice Bellard 5dcfda673SGerd Hoffmann * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) 6dcfda673SGerd Hoffmann * 7dcfda673SGerd Hoffmann * Permission is hereby granted, free of charge, to any person obtaining a copy 8dcfda673SGerd Hoffmann * of this software and associated documentation files (the "Software"), to deal 9dcfda673SGerd Hoffmann * in the Software without restriction, including without limitation the rights 10dcfda673SGerd Hoffmann * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11dcfda673SGerd Hoffmann * copies of the Software, and to permit persons to whom the Software is 12dcfda673SGerd Hoffmann * furnished to do so, subject to the following conditions: 13dcfda673SGerd Hoffmann * 14dcfda673SGerd Hoffmann * The above copyright notice and this permission notice shall be included in 15dcfda673SGerd Hoffmann * all copies or substantial portions of the Software. 16dcfda673SGerd Hoffmann * 17dcfda673SGerd Hoffmann * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18dcfda673SGerd Hoffmann * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19dcfda673SGerd Hoffmann * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20dcfda673SGerd Hoffmann * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21dcfda673SGerd Hoffmann * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22dcfda673SGerd Hoffmann * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23dcfda673SGerd Hoffmann * THE SOFTWARE. 24dcfda673SGerd Hoffmann */ 250430891cSPeter Maydell #include "qemu/osdep.h" 2683c9f4caSPaolo Bonzini #include "hw/hw.h" 2728ecbaeeSPaolo Bonzini #include "ui/console.h" 281de7afc9SPaolo Bonzini #include "qemu/timer.h" 290d09e41aSPaolo Bonzini #include "hw/input/hid.h" 30dcfda673SGerd Hoffmann 31dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_ROLLOVER 0x01 32dcfda673SGerd Hoffmann #define HID_USAGE_POSTFAIL 0x02 33dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_UNDEFINED 0x03 34dcfda673SGerd Hoffmann 35dcfda673SGerd Hoffmann /* Indices are QEMU keycodes, values are from HID Usage Table. Indices 36dcfda673SGerd Hoffmann * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ 37dcfda673SGerd Hoffmann static const uint8_t hid_usage_keys[0x100] = { 38dcfda673SGerd Hoffmann 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 39dcfda673SGerd Hoffmann 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, 40dcfda673SGerd Hoffmann 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, 41dcfda673SGerd Hoffmann 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, 42dcfda673SGerd Hoffmann 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, 43dcfda673SGerd Hoffmann 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, 44dcfda673SGerd Hoffmann 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, 450ee4de58SDinar Valeev 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 46dcfda673SGerd Hoffmann 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, 47dcfda673SGerd Hoffmann 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, 4891dbeedaSDaniel Serpell 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44, 49dcfda673SGerd Hoffmann 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 50dcfda673SGerd Hoffmann 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, 51dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 52dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 54dcfda673SGerd Hoffmann 55dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, 59dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, 62dcfda673SGerd Hoffmann 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, 64dcfda673SGerd Hoffmann 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, 65dcfda673SGerd Hoffmann 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, 66dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00, 67dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71dcfda673SGerd Hoffmann }; 72dcfda673SGerd Hoffmann 73dcfda673SGerd Hoffmann bool hid_has_events(HIDState *hs) 74dcfda673SGerd Hoffmann { 75027c03f7SHans de Goede return hs->n > 0 || hs->idle_pending; 76dcfda673SGerd Hoffmann } 77dcfda673SGerd Hoffmann 78027c03f7SHans de Goede static void hid_idle_timer(void *opaque) 79b069d348SGerd Hoffmann { 80027c03f7SHans de Goede HIDState *hs = opaque; 81027c03f7SHans de Goede 82027c03f7SHans de Goede hs->idle_pending = true; 83027c03f7SHans de Goede hs->event(hs); 84027c03f7SHans de Goede } 85027c03f7SHans de Goede 86027c03f7SHans de Goede static void hid_del_idle_timer(HIDState *hs) 87027c03f7SHans de Goede { 88027c03f7SHans de Goede if (hs->idle_timer) { 89bc72ad67SAlex Bligh timer_del(hs->idle_timer); 90bc72ad67SAlex Bligh timer_free(hs->idle_timer); 91027c03f7SHans de Goede hs->idle_timer = NULL; 92027c03f7SHans de Goede } 93027c03f7SHans de Goede } 94027c03f7SHans de Goede 95027c03f7SHans de Goede void hid_set_next_idle(HIDState *hs) 96027c03f7SHans de Goede { 97027c03f7SHans de Goede if (hs->idle) { 98bc72ad67SAlex Bligh uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 99*73bcb24dSRutuja Shah NANOSECONDS_PER_SECOND * hs->idle * 4 / 1000; 100027c03f7SHans de Goede if (!hs->idle_timer) { 101bc72ad67SAlex Bligh hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs); 102027c03f7SHans de Goede } 103bc72ad67SAlex Bligh timer_mod_ns(hs->idle_timer, expire_time); 104027c03f7SHans de Goede } else { 105027c03f7SHans de Goede hid_del_idle_timer(hs); 106027c03f7SHans de Goede } 107b069d348SGerd Hoffmann } 108b069d348SGerd Hoffmann 1098b84286fSGerd Hoffmann static void hid_pointer_event(DeviceState *dev, QemuConsole *src, 1108b84286fSGerd Hoffmann InputEvent *evt) 111dcfda673SGerd Hoffmann { 1127fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 1138b84286fSGerd Hoffmann [INPUT_BUTTON_LEFT] = 0x01, 1148b84286fSGerd Hoffmann [INPUT_BUTTON_RIGHT] = 0x02, 1158b84286fSGerd Hoffmann [INPUT_BUTTON_MIDDLE] = 0x04, 1168b84286fSGerd Hoffmann }; 1178b84286fSGerd Hoffmann HIDState *hs = (HIDState *)dev; 1188b84286fSGerd Hoffmann HIDPointerEvent *e; 119b5a1b443SEric Blake InputMoveEvent *move; 120b5a1b443SEric Blake InputBtnEvent *btn; 121dcfda673SGerd Hoffmann 1228b84286fSGerd Hoffmann assert(hs->n < QUEUE_LENGTH); 1238b84286fSGerd Hoffmann e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; 1248b84286fSGerd Hoffmann 125568c73a4SEric Blake switch (evt->type) { 1268b84286fSGerd Hoffmann case INPUT_EVENT_KIND_REL: 12732bafa8fSEric Blake move = evt->u.rel.data; 128b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 129b5a1b443SEric Blake e->xdx += move->value; 130b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 131b5a1b443SEric Blake e->ydy += move->value; 1328b84286fSGerd Hoffmann } 1338b84286fSGerd Hoffmann break; 1348b84286fSGerd Hoffmann 1358b84286fSGerd Hoffmann case INPUT_EVENT_KIND_ABS: 13632bafa8fSEric Blake move = evt->u.abs.data; 137b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 138b5a1b443SEric Blake e->xdx = move->value; 139b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 140b5a1b443SEric Blake e->ydy = move->value; 1418b84286fSGerd Hoffmann } 1428b84286fSGerd Hoffmann break; 1438b84286fSGerd Hoffmann 1448b84286fSGerd Hoffmann case INPUT_EVENT_KIND_BTN: 14532bafa8fSEric Blake btn = evt->u.btn.data; 146b5a1b443SEric Blake if (btn->down) { 147b5a1b443SEric Blake e->buttons_state |= bmap[btn->button]; 148b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 1498b84286fSGerd Hoffmann e->dz--; 150b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 1518b84286fSGerd Hoffmann e->dz++; 1528b84286fSGerd Hoffmann } 153dcfda673SGerd Hoffmann } else { 154b5a1b443SEric Blake e->buttons_state &= ~bmap[btn->button]; 155dcfda673SGerd Hoffmann } 1568b84286fSGerd Hoffmann break; 1578b84286fSGerd Hoffmann 1588b84286fSGerd Hoffmann default: 1598b84286fSGerd Hoffmann /* keep gcc happy */ 1608b84286fSGerd Hoffmann break; 161dcfda673SGerd Hoffmann } 162dcfda673SGerd Hoffmann 1638b84286fSGerd Hoffmann } 1648b84286fSGerd Hoffmann 1658b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev) 166dcfda673SGerd Hoffmann { 1678b84286fSGerd Hoffmann HIDState *hs = (HIDState *)dev; 1688b84286fSGerd Hoffmann HIDPointerEvent *prev, *curr, *next; 1698b84286fSGerd Hoffmann bool event_compression = false; 170dcfda673SGerd Hoffmann 1718b84286fSGerd Hoffmann if (hs->n == QUEUE_LENGTH-1) { 1728b84286fSGerd Hoffmann /* 1735d831be2SStefan Weil * Queue full. We are losing information, but we at least 1748b84286fSGerd Hoffmann * keep track of most recent button state. 1758b84286fSGerd Hoffmann */ 1768b84286fSGerd Hoffmann return; 177dcfda673SGerd Hoffmann } 1788b84286fSGerd Hoffmann 1798b84286fSGerd Hoffmann prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK]; 1808b84286fSGerd Hoffmann curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; 1818b84286fSGerd Hoffmann next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK]; 1828b84286fSGerd Hoffmann 1838b84286fSGerd Hoffmann if (hs->n > 0) { 1848b84286fSGerd Hoffmann /* 1858b84286fSGerd Hoffmann * No button state change between previous and current event 1868b84286fSGerd Hoffmann * (and previous wasn't seen by the guest yet), so there is 1878b84286fSGerd Hoffmann * motion information only and we can combine the two event 1888b84286fSGerd Hoffmann * into one. 1898b84286fSGerd Hoffmann */ 1908b84286fSGerd Hoffmann if (curr->buttons_state == prev->buttons_state) { 1918b84286fSGerd Hoffmann event_compression = true; 1928b84286fSGerd Hoffmann } 1938b84286fSGerd Hoffmann } 1948b84286fSGerd Hoffmann 1958b84286fSGerd Hoffmann if (event_compression) { 1968b84286fSGerd Hoffmann /* add current motion to previous, clear current */ 1978b84286fSGerd Hoffmann if (hs->kind == HID_MOUSE) { 1988b84286fSGerd Hoffmann prev->xdx += curr->xdx; 1998b84286fSGerd Hoffmann curr->xdx = 0; 20035e83d10SChristian Burger prev->ydy += curr->ydy; 2018b84286fSGerd Hoffmann curr->ydy = 0; 2028b84286fSGerd Hoffmann } else { 2038b84286fSGerd Hoffmann prev->xdx = curr->xdx; 2048b84286fSGerd Hoffmann prev->ydy = curr->ydy; 2058b84286fSGerd Hoffmann } 2068b84286fSGerd Hoffmann prev->dz += curr->dz; 2078b84286fSGerd Hoffmann curr->dz = 0; 2088b84286fSGerd Hoffmann } else { 2098b84286fSGerd Hoffmann /* prepate next (clear rel, copy abs + btns) */ 2108b84286fSGerd Hoffmann if (hs->kind == HID_MOUSE) { 2118b84286fSGerd Hoffmann next->xdx = 0; 2128b84286fSGerd Hoffmann next->ydy = 0; 2138b84286fSGerd Hoffmann } else { 2148b84286fSGerd Hoffmann next->xdx = curr->xdx; 2158b84286fSGerd Hoffmann next->ydy = curr->ydy; 2168b84286fSGerd Hoffmann } 2178b84286fSGerd Hoffmann next->dz = 0; 2188b84286fSGerd Hoffmann next->buttons_state = curr->buttons_state; 2198b84286fSGerd Hoffmann /* make current guest visible, notify guest */ 2208b84286fSGerd Hoffmann hs->n++; 221dcfda673SGerd Hoffmann hs->event(hs); 222dcfda673SGerd Hoffmann } 2238b84286fSGerd Hoffmann } 224dcfda673SGerd Hoffmann 2251ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, 2261ff5eeddSGerd Hoffmann InputEvent *evt) 227dcfda673SGerd Hoffmann { 2281ff5eeddSGerd Hoffmann HIDState *hs = (HIDState *)dev; 2291ff5eeddSGerd Hoffmann int scancodes[3], i, count; 230dcfda673SGerd Hoffmann int slot; 23132bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 232dcfda673SGerd Hoffmann 233b5a1b443SEric Blake count = qemu_input_key_value_to_scancode(key->key, 234b5a1b443SEric Blake key->down, 2351ff5eeddSGerd Hoffmann scancodes); 2361ff5eeddSGerd Hoffmann if (hs->n + count > QUEUE_LENGTH) { 237dcfda673SGerd Hoffmann fprintf(stderr, "usb-kbd: warning: key event queue full\n"); 238dcfda673SGerd Hoffmann return; 239dcfda673SGerd Hoffmann } 2401ff5eeddSGerd Hoffmann for (i = 0; i < count; i++) { 241dcfda673SGerd Hoffmann slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; 2421ff5eeddSGerd Hoffmann hs->kbd.keycodes[slot] = scancodes[i]; 2431ff5eeddSGerd Hoffmann } 244dcfda673SGerd Hoffmann hs->event(hs); 245dcfda673SGerd Hoffmann } 246dcfda673SGerd Hoffmann 247dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs) 248dcfda673SGerd Hoffmann { 249562f9375SPaolo Bonzini uint8_t hid_code, index, key; 250dcfda673SGerd Hoffmann int i, keycode, slot; 251dcfda673SGerd Hoffmann 252dcfda673SGerd Hoffmann if (hs->n == 0) { 253dcfda673SGerd Hoffmann return; 254dcfda673SGerd Hoffmann } 255dcfda673SGerd Hoffmann slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; 256dcfda673SGerd Hoffmann keycode = hs->kbd.keycodes[slot]; 257dcfda673SGerd Hoffmann 258dcfda673SGerd Hoffmann key = keycode & 0x7f; 259562f9375SPaolo Bonzini index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1); 260562f9375SPaolo Bonzini hid_code = hid_usage_keys[index]; 261dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << 8); 262dcfda673SGerd Hoffmann 263dcfda673SGerd Hoffmann switch (hid_code) { 264dcfda673SGerd Hoffmann case 0x00: 265dcfda673SGerd Hoffmann return; 266dcfda673SGerd Hoffmann 267dcfda673SGerd Hoffmann case 0xe0: 268562f9375SPaolo Bonzini assert(key == 0x1d); 269dcfda673SGerd Hoffmann if (hs->kbd.modifiers & (1 << 9)) { 270562f9375SPaolo Bonzini /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0. 271562f9375SPaolo Bonzini * Here we're processing the second hid_code. By dropping bit 9 272562f9375SPaolo Bonzini * and setting bit 8, the scancode after 0x1d will access the 273562f9375SPaolo Bonzini * second half of the table. 274562f9375SPaolo Bonzini */ 275562f9375SPaolo Bonzini hs->kbd.modifiers ^= (1 << 8) | (1 << 9); 276dcfda673SGerd Hoffmann return; 277dcfda673SGerd Hoffmann } 278562f9375SPaolo Bonzini /* fall through to process Ctrl_L */ 279dcfda673SGerd Hoffmann case 0xe1 ... 0xe7: 280562f9375SPaolo Bonzini /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R. 281562f9375SPaolo Bonzini * Handle releases here, or fall through to process presses. 282562f9375SPaolo Bonzini */ 283dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 284dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); 285dcfda673SGerd Hoffmann return; 286dcfda673SGerd Hoffmann } 287562f9375SPaolo Bonzini /* fall through */ 288562f9375SPaolo Bonzini case 0xe8 ... 0xe9: 289562f9375SPaolo Bonzini /* USB modifiers are just 1 byte long. Bits 8 and 9 of 290562f9375SPaolo Bonzini * hs->kbd.modifiers implement a state machine that detects the 291562f9375SPaolo Bonzini * 0xe0 and 0xe1/0x1d sequences. These bits do not follow the 292562f9375SPaolo Bonzini * usual rules where bit 7 marks released keys; they are cleared 293562f9375SPaolo Bonzini * elsewhere in the function as the state machine dictates. 294562f9375SPaolo Bonzini */ 295dcfda673SGerd Hoffmann hs->kbd.modifiers |= 1 << (hid_code & 0x0f); 296dcfda673SGerd Hoffmann return; 297562f9375SPaolo Bonzini 298562f9375SPaolo Bonzini case 0xea ... 0xef: 299562f9375SPaolo Bonzini abort(); 300562f9375SPaolo Bonzini 301562f9375SPaolo Bonzini default: 302562f9375SPaolo Bonzini break; 303dcfda673SGerd Hoffmann } 304dcfda673SGerd Hoffmann 305dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 306dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 307dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 308dcfda673SGerd Hoffmann hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; 309dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys] = 0x00; 310dcfda673SGerd Hoffmann break; 311dcfda673SGerd Hoffmann } 312dcfda673SGerd Hoffmann } 313dcfda673SGerd Hoffmann if (i < 0) { 314dcfda673SGerd Hoffmann return; 315dcfda673SGerd Hoffmann } 316dcfda673SGerd Hoffmann } else { 317dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 318dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 319dcfda673SGerd Hoffmann break; 320dcfda673SGerd Hoffmann } 321dcfda673SGerd Hoffmann } 322dcfda673SGerd Hoffmann if (i < 0) { 323dcfda673SGerd Hoffmann if (hs->kbd.keys < sizeof(hs->kbd.key)) { 324dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys++] = hid_code; 325dcfda673SGerd Hoffmann } 326dcfda673SGerd Hoffmann } else { 327dcfda673SGerd Hoffmann return; 328dcfda673SGerd Hoffmann } 329dcfda673SGerd Hoffmann } 330dcfda673SGerd Hoffmann } 331dcfda673SGerd Hoffmann 332dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax) 333dcfda673SGerd Hoffmann { 334dcfda673SGerd Hoffmann if (val < vmin) { 335dcfda673SGerd Hoffmann return vmin; 336dcfda673SGerd Hoffmann } else if (val > vmax) { 337dcfda673SGerd Hoffmann return vmax; 338dcfda673SGerd Hoffmann } else { 339dcfda673SGerd Hoffmann return val; 340dcfda673SGerd Hoffmann } 341dcfda673SGerd Hoffmann } 342dcfda673SGerd Hoffmann 34321635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs) 34421635e12SGerd Hoffmann { 34521635e12SGerd Hoffmann if (!hs->ptr.mouse_grabbed) { 3468b84286fSGerd Hoffmann qemu_input_handler_activate(hs->s); 34721635e12SGerd Hoffmann hs->ptr.mouse_grabbed = 1; 34821635e12SGerd Hoffmann } 34921635e12SGerd Hoffmann } 35021635e12SGerd Hoffmann 351dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) 352dcfda673SGerd Hoffmann { 3538b84286fSGerd Hoffmann int dx, dy, dz, l; 354dcfda673SGerd Hoffmann int index; 355dcfda673SGerd Hoffmann HIDPointerEvent *e; 356dcfda673SGerd Hoffmann 357027c03f7SHans de Goede hs->idle_pending = false; 358027c03f7SHans de Goede 35921635e12SGerd Hoffmann hid_pointer_activate(hs); 360dcfda673SGerd Hoffmann 361dcfda673SGerd Hoffmann /* When the buffer is empty, return the last event. Relative 362dcfda673SGerd Hoffmann movements will all be zero. */ 363dcfda673SGerd Hoffmann index = (hs->n ? hs->head : hs->head - 1); 364dcfda673SGerd Hoffmann e = &hs->ptr.queue[index & QUEUE_MASK]; 365dcfda673SGerd Hoffmann 366dcfda673SGerd Hoffmann if (hs->kind == HID_MOUSE) { 367dcfda673SGerd Hoffmann dx = int_clamp(e->xdx, -127, 127); 368dcfda673SGerd Hoffmann dy = int_clamp(e->ydy, -127, 127); 369dcfda673SGerd Hoffmann e->xdx -= dx; 370dcfda673SGerd Hoffmann e->ydy -= dy; 371dcfda673SGerd Hoffmann } else { 372dcfda673SGerd Hoffmann dx = e->xdx; 373dcfda673SGerd Hoffmann dy = e->ydy; 374dcfda673SGerd Hoffmann } 375dcfda673SGerd Hoffmann dz = int_clamp(e->dz, -127, 127); 376dcfda673SGerd Hoffmann e->dz -= dz; 377dcfda673SGerd Hoffmann 378dcfda673SGerd Hoffmann if (hs->n && 379dcfda673SGerd Hoffmann !e->dz && 380dcfda673SGerd Hoffmann (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { 381dcfda673SGerd Hoffmann /* that deals with this event */ 382dcfda673SGerd Hoffmann QUEUE_INCR(hs->head); 383dcfda673SGerd Hoffmann hs->n--; 384dcfda673SGerd Hoffmann } 385dcfda673SGerd Hoffmann 386dcfda673SGerd Hoffmann /* Appears we have to invert the wheel direction */ 387dcfda673SGerd Hoffmann dz = 0 - dz; 388dcfda673SGerd Hoffmann l = 0; 389dcfda673SGerd Hoffmann switch (hs->kind) { 390dcfda673SGerd Hoffmann case HID_MOUSE: 391dcfda673SGerd Hoffmann if (len > l) { 3928b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 393dcfda673SGerd Hoffmann } 394dcfda673SGerd Hoffmann if (len > l) { 395dcfda673SGerd Hoffmann buf[l++] = dx; 396dcfda673SGerd Hoffmann } 397dcfda673SGerd Hoffmann if (len > l) { 398dcfda673SGerd Hoffmann buf[l++] = dy; 399dcfda673SGerd Hoffmann } 400dcfda673SGerd Hoffmann if (len > l) { 401dcfda673SGerd Hoffmann buf[l++] = dz; 402dcfda673SGerd Hoffmann } 403dcfda673SGerd Hoffmann break; 404dcfda673SGerd Hoffmann 405dcfda673SGerd Hoffmann case HID_TABLET: 406dcfda673SGerd Hoffmann if (len > l) { 4078b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 408dcfda673SGerd Hoffmann } 409dcfda673SGerd Hoffmann if (len > l) { 410dcfda673SGerd Hoffmann buf[l++] = dx & 0xff; 411dcfda673SGerd Hoffmann } 412dcfda673SGerd Hoffmann if (len > l) { 413dcfda673SGerd Hoffmann buf[l++] = dx >> 8; 414dcfda673SGerd Hoffmann } 415dcfda673SGerd Hoffmann if (len > l) { 416dcfda673SGerd Hoffmann buf[l++] = dy & 0xff; 417dcfda673SGerd Hoffmann } 418dcfda673SGerd Hoffmann if (len > l) { 419dcfda673SGerd Hoffmann buf[l++] = dy >> 8; 420dcfda673SGerd Hoffmann } 421dcfda673SGerd Hoffmann if (len > l) { 422dcfda673SGerd Hoffmann buf[l++] = dz; 423dcfda673SGerd Hoffmann } 424dcfda673SGerd Hoffmann break; 425dcfda673SGerd Hoffmann 426dcfda673SGerd Hoffmann default: 427dcfda673SGerd Hoffmann abort(); 428dcfda673SGerd Hoffmann } 429dcfda673SGerd Hoffmann 430dcfda673SGerd Hoffmann return l; 431dcfda673SGerd Hoffmann } 432dcfda673SGerd Hoffmann 433dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) 434dcfda673SGerd Hoffmann { 435027c03f7SHans de Goede hs->idle_pending = false; 436027c03f7SHans de Goede 437dcfda673SGerd Hoffmann if (len < 2) { 438dcfda673SGerd Hoffmann return 0; 439dcfda673SGerd Hoffmann } 440dcfda673SGerd Hoffmann 441dcfda673SGerd Hoffmann hid_keyboard_process_keycode(hs); 442dcfda673SGerd Hoffmann 443dcfda673SGerd Hoffmann buf[0] = hs->kbd.modifiers & 0xff; 444dcfda673SGerd Hoffmann buf[1] = 0; 445dcfda673SGerd Hoffmann if (hs->kbd.keys > 6) { 446dcfda673SGerd Hoffmann memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); 447dcfda673SGerd Hoffmann } else { 448dcfda673SGerd Hoffmann memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); 449dcfda673SGerd Hoffmann } 450dcfda673SGerd Hoffmann 451dcfda673SGerd Hoffmann return MIN(8, len); 452dcfda673SGerd Hoffmann } 453dcfda673SGerd Hoffmann 454dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) 455dcfda673SGerd Hoffmann { 456dcfda673SGerd Hoffmann if (len > 0) { 457dcfda673SGerd Hoffmann int ledstate = 0; 458dcfda673SGerd Hoffmann /* 0x01: Num Lock LED 459dcfda673SGerd Hoffmann * 0x02: Caps Lock LED 460dcfda673SGerd Hoffmann * 0x04: Scroll Lock LED 461dcfda673SGerd Hoffmann * 0x08: Compose LED 462dcfda673SGerd Hoffmann * 0x10: Kana LED */ 463dcfda673SGerd Hoffmann hs->kbd.leds = buf[0]; 464dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x04) { 465dcfda673SGerd Hoffmann ledstate |= QEMU_SCROLL_LOCK_LED; 466dcfda673SGerd Hoffmann } 467dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x01) { 468dcfda673SGerd Hoffmann ledstate |= QEMU_NUM_LOCK_LED; 469dcfda673SGerd Hoffmann } 470dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x02) { 471dcfda673SGerd Hoffmann ledstate |= QEMU_CAPS_LOCK_LED; 472dcfda673SGerd Hoffmann } 473dcfda673SGerd Hoffmann kbd_put_ledstate(ledstate); 474dcfda673SGerd Hoffmann } 475dcfda673SGerd Hoffmann return 0; 476dcfda673SGerd Hoffmann } 477dcfda673SGerd Hoffmann 478dcfda673SGerd Hoffmann void hid_reset(HIDState *hs) 479dcfda673SGerd Hoffmann { 480dcfda673SGerd Hoffmann switch (hs->kind) { 481dcfda673SGerd Hoffmann case HID_KEYBOARD: 482dcfda673SGerd Hoffmann memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); 483dcfda673SGerd Hoffmann memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); 484dcfda673SGerd Hoffmann hs->kbd.keys = 0; 485dcfda673SGerd Hoffmann break; 486dcfda673SGerd Hoffmann case HID_MOUSE: 487dcfda673SGerd Hoffmann case HID_TABLET: 488dcfda673SGerd Hoffmann memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); 489dcfda673SGerd Hoffmann break; 490dcfda673SGerd Hoffmann } 491dcfda673SGerd Hoffmann hs->head = 0; 492dcfda673SGerd Hoffmann hs->n = 0; 493b069d348SGerd Hoffmann hs->protocol = 1; 494b069d348SGerd Hoffmann hs->idle = 0; 495027c03f7SHans de Goede hs->idle_pending = false; 496027c03f7SHans de Goede hid_del_idle_timer(hs); 497dcfda673SGerd Hoffmann } 498dcfda673SGerd Hoffmann 499dcfda673SGerd Hoffmann void hid_free(HIDState *hs) 500dcfda673SGerd Hoffmann { 5011ff5eeddSGerd Hoffmann qemu_input_handler_unregister(hs->s); 502027c03f7SHans de Goede hid_del_idle_timer(hs); 503dcfda673SGerd Hoffmann } 504dcfda673SGerd Hoffmann 5051ff5eeddSGerd Hoffmann static QemuInputHandler hid_keyboard_handler = { 5061ff5eeddSGerd Hoffmann .name = "QEMU HID Keyboard", 5071ff5eeddSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 5081ff5eeddSGerd Hoffmann .event = hid_keyboard_event, 5091ff5eeddSGerd Hoffmann }; 5101ff5eeddSGerd Hoffmann 5118b84286fSGerd Hoffmann static QemuInputHandler hid_mouse_handler = { 5128b84286fSGerd Hoffmann .name = "QEMU HID Mouse", 5138b84286fSGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 5148b84286fSGerd Hoffmann .event = hid_pointer_event, 5158b84286fSGerd Hoffmann .sync = hid_pointer_sync, 5168b84286fSGerd Hoffmann }; 5178b84286fSGerd Hoffmann 5188b84286fSGerd Hoffmann static QemuInputHandler hid_tablet_handler = { 5198b84286fSGerd Hoffmann .name = "QEMU HID Tablet", 5208b84286fSGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, 5218b84286fSGerd Hoffmann .event = hid_pointer_event, 5228b84286fSGerd Hoffmann .sync = hid_pointer_sync, 5238b84286fSGerd Hoffmann }; 5248b84286fSGerd Hoffmann 525dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event) 526dcfda673SGerd Hoffmann { 527dcfda673SGerd Hoffmann hs->kind = kind; 528dcfda673SGerd Hoffmann hs->event = event; 529dcfda673SGerd Hoffmann 530bb0db527SMichael Walle if (hs->kind == HID_KEYBOARD) { 5311ff5eeddSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5321ff5eeddSGerd Hoffmann &hid_keyboard_handler); 5331ff5eeddSGerd Hoffmann qemu_input_handler_activate(hs->s); 534bb0db527SMichael Walle } else if (hs->kind == HID_MOUSE) { 5358b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5368b84286fSGerd Hoffmann &hid_mouse_handler); 537dcfda673SGerd Hoffmann } else if (hs->kind == HID_TABLET) { 5388b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5398b84286fSGerd Hoffmann &hid_tablet_handler); 540dcfda673SGerd Hoffmann } 541dcfda673SGerd Hoffmann } 542ccd4ed06SMichael Walle 543ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id) 544ccd4ed06SMichael Walle { 545ccd4ed06SMichael Walle HIDState *s = opaque; 546ccd4ed06SMichael Walle 547027c03f7SHans de Goede hid_set_next_idle(s); 548ba4d2606SGerd Hoffmann 549ba4d2606SGerd Hoffmann if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET || 550ba4d2606SGerd Hoffmann s->kind == HID_MOUSE)) { 551ba4d2606SGerd Hoffmann /* 552ba4d2606SGerd Hoffmann * Handle ptr device migration from old qemu with full queue. 553ba4d2606SGerd Hoffmann * 554ba4d2606SGerd Hoffmann * Throw away everything but the last event, so we propagate 555ba4d2606SGerd Hoffmann * at least the current button state to the guest. Also keep 556ba4d2606SGerd Hoffmann * current position for the tablet, signal "no motion" for the 557ba4d2606SGerd Hoffmann * mouse. 558ba4d2606SGerd Hoffmann */ 559ba4d2606SGerd Hoffmann HIDPointerEvent evt; 560ba4d2606SGerd Hoffmann evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK]; 561ba4d2606SGerd Hoffmann if (s->kind == HID_MOUSE) { 562ba4d2606SGerd Hoffmann evt.xdx = 0; 563ba4d2606SGerd Hoffmann evt.ydy = 0; 564ba4d2606SGerd Hoffmann } 565ba4d2606SGerd Hoffmann s->ptr.queue[0] = evt; 566ba4d2606SGerd Hoffmann s->head = 0; 567ba4d2606SGerd Hoffmann s->n = 1; 568ba4d2606SGerd Hoffmann } 569ccd4ed06SMichael Walle return 0; 570ccd4ed06SMichael Walle } 571ccd4ed06SMichael Walle 572ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = { 573ccd4ed06SMichael Walle .name = "HIDPointerEventQueue", 574ccd4ed06SMichael Walle .version_id = 1, 575ccd4ed06SMichael Walle .minimum_version_id = 1, 576ccd4ed06SMichael Walle .fields = (VMStateField[]) { 577ccd4ed06SMichael Walle VMSTATE_INT32(xdx, HIDPointerEvent), 578ccd4ed06SMichael Walle VMSTATE_INT32(ydy, HIDPointerEvent), 579ccd4ed06SMichael Walle VMSTATE_INT32(dz, HIDPointerEvent), 580ccd4ed06SMichael Walle VMSTATE_INT32(buttons_state, HIDPointerEvent), 581ccd4ed06SMichael Walle VMSTATE_END_OF_LIST() 582ccd4ed06SMichael Walle } 583ccd4ed06SMichael Walle }; 584ccd4ed06SMichael Walle 585ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = { 586ccd4ed06SMichael Walle .name = "HIDPointerDevice", 587ccd4ed06SMichael Walle .version_id = 1, 588ccd4ed06SMichael Walle .minimum_version_id = 1, 589ccd4ed06SMichael Walle .post_load = hid_post_load, 590ccd4ed06SMichael Walle .fields = (VMStateField[]) { 591ccd4ed06SMichael Walle VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0, 592ccd4ed06SMichael Walle vmstate_hid_ptr_queue, HIDPointerEvent), 593ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 594ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 595ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 596ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 597ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 598ccd4ed06SMichael Walle } 599ccd4ed06SMichael Walle }; 600ccd4ed06SMichael Walle 601ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = { 602ccd4ed06SMichael Walle .name = "HIDKeyboardDevice", 603ccd4ed06SMichael Walle .version_id = 1, 604ccd4ed06SMichael Walle .minimum_version_id = 1, 605ccd4ed06SMichael Walle .post_load = hid_post_load, 606ccd4ed06SMichael Walle .fields = (VMStateField[]) { 607ccd4ed06SMichael Walle VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH), 608ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 609ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 610ccd4ed06SMichael Walle VMSTATE_UINT16(kbd.modifiers, HIDState), 611ccd4ed06SMichael Walle VMSTATE_UINT8(kbd.leds, HIDState), 612ccd4ed06SMichael Walle VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16), 613ccd4ed06SMichael Walle VMSTATE_INT32(kbd.keys, HIDState), 614ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 615ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 616ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 617ccd4ed06SMichael Walle } 618ccd4ed06SMichael Walle }; 619