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 */ 25d6454270SMarkus Armbruster 260430891cSPeter Maydell #include "qemu/osdep.h" 2728ecbaeeSPaolo Bonzini #include "ui/console.h" 281de7afc9SPaolo Bonzini #include "qemu/timer.h" 290d09e41aSPaolo Bonzini #include "hw/input/hid.h" 30d6454270SMarkus Armbruster #include "migration/vmstate.h" 31c80276b4SGerd Hoffmann #include "trace.h" 32dcfda673SGerd Hoffmann 33dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_ROLLOVER 0x01 34dcfda673SGerd Hoffmann #define HID_USAGE_POSTFAIL 0x02 35dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_UNDEFINED 0x03 36dcfda673SGerd Hoffmann 37dcfda673SGerd Hoffmann /* Indices are QEMU keycodes, values are from HID Usage Table. Indices 38dcfda673SGerd Hoffmann * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ 39dcfda673SGerd Hoffmann static const uint8_t hid_usage_keys[0x100] = { 40dcfda673SGerd Hoffmann 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 41dcfda673SGerd Hoffmann 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, 42dcfda673SGerd Hoffmann 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, 43dcfda673SGerd Hoffmann 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, 44dcfda673SGerd Hoffmann 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, 45dcfda673SGerd Hoffmann 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, 46dcfda673SGerd Hoffmann 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, 470ee4de58SDinar Valeev 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 48dcfda673SGerd Hoffmann 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, 49dcfda673SGerd Hoffmann 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, 5086f3bf0eSPeter Korsgaard 0x5a, 0x5b, 0x62, 0x63, 0x46, 0x00, 0x64, 0x44, 51dcfda673SGerd Hoffmann 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 52dcfda673SGerd Hoffmann 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, 53dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 54*f9c48124SKatsuhiro Ueno 0x88, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 55*f9c48124SKatsuhiro Ueno 0x00, 0x8a, 0x00, 0x8b, 0x00, 0x89, 0xe7, 0x65, 56dcfda673SGerd Hoffmann 57dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 60dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, 61160997faSTao Wu 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 62160997faSTao Wu 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 63160997faSTao Wu 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, 64dcfda673SGerd Hoffmann 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 6586f3bf0eSPeter Korsgaard 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x4a, 66dcfda673SGerd Hoffmann 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, 67dcfda673SGerd Hoffmann 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, 68160997faSTao Wu 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x66, 0x00, 69dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73dcfda673SGerd Hoffmann }; 74dcfda673SGerd Hoffmann 75dcfda673SGerd Hoffmann bool hid_has_events(HIDState *hs) 76dcfda673SGerd Hoffmann { 77027c03f7SHans de Goede return hs->n > 0 || hs->idle_pending; 78dcfda673SGerd Hoffmann } 79dcfda673SGerd Hoffmann 80027c03f7SHans de Goede static void hid_idle_timer(void *opaque) 81b069d348SGerd Hoffmann { 82027c03f7SHans de Goede HIDState *hs = opaque; 83027c03f7SHans de Goede 84027c03f7SHans de Goede hs->idle_pending = true; 85027c03f7SHans de Goede hs->event(hs); 86027c03f7SHans de Goede } 87027c03f7SHans de Goede 88027c03f7SHans de Goede static void hid_del_idle_timer(HIDState *hs) 89027c03f7SHans de Goede { 90027c03f7SHans de Goede if (hs->idle_timer) { 91bc72ad67SAlex Bligh timer_free(hs->idle_timer); 92027c03f7SHans de Goede hs->idle_timer = NULL; 93027c03f7SHans de Goede } 94027c03f7SHans de Goede } 95027c03f7SHans de Goede 96027c03f7SHans de Goede void hid_set_next_idle(HIDState *hs) 97027c03f7SHans de Goede { 98027c03f7SHans de Goede if (hs->idle) { 99bc72ad67SAlex Bligh uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 10073bcb24dSRutuja Shah NANOSECONDS_PER_SECOND * hs->idle * 4 / 1000; 101027c03f7SHans de Goede if (!hs->idle_timer) { 102bc72ad67SAlex Bligh hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs); 103027c03f7SHans de Goede } 104bc72ad67SAlex Bligh timer_mod_ns(hs->idle_timer, expire_time); 105027c03f7SHans de Goede } else { 106027c03f7SHans de Goede hid_del_idle_timer(hs); 107027c03f7SHans de Goede } 108b069d348SGerd Hoffmann } 109b069d348SGerd Hoffmann 1108b84286fSGerd Hoffmann static void hid_pointer_event(DeviceState *dev, QemuConsole *src, 1118b84286fSGerd Hoffmann InputEvent *evt) 112dcfda673SGerd Hoffmann { 1137fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 1148b84286fSGerd Hoffmann [INPUT_BUTTON_LEFT] = 0x01, 1158b84286fSGerd Hoffmann [INPUT_BUTTON_RIGHT] = 0x02, 1168b84286fSGerd Hoffmann [INPUT_BUTTON_MIDDLE] = 0x04, 1178b84286fSGerd Hoffmann }; 1188b84286fSGerd Hoffmann HIDState *hs = (HIDState *)dev; 1198b84286fSGerd Hoffmann HIDPointerEvent *e; 120b5a1b443SEric Blake InputMoveEvent *move; 121b5a1b443SEric Blake InputBtnEvent *btn; 122dcfda673SGerd Hoffmann 1238b84286fSGerd Hoffmann assert(hs->n < QUEUE_LENGTH); 1248b84286fSGerd Hoffmann e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; 1258b84286fSGerd Hoffmann 126568c73a4SEric Blake switch (evt->type) { 1278b84286fSGerd Hoffmann case INPUT_EVENT_KIND_REL: 12832bafa8fSEric Blake move = evt->u.rel.data; 129b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 130b5a1b443SEric Blake e->xdx += move->value; 131b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 132b5a1b443SEric Blake e->ydy += move->value; 1338b84286fSGerd Hoffmann } 1348b84286fSGerd Hoffmann break; 1358b84286fSGerd Hoffmann 1368b84286fSGerd Hoffmann case INPUT_EVENT_KIND_ABS: 13732bafa8fSEric Blake move = evt->u.abs.data; 138b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 139b5a1b443SEric Blake e->xdx = move->value; 140b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 141b5a1b443SEric Blake e->ydy = move->value; 1428b84286fSGerd Hoffmann } 1438b84286fSGerd Hoffmann break; 1448b84286fSGerd Hoffmann 1458b84286fSGerd Hoffmann case INPUT_EVENT_KIND_BTN: 14632bafa8fSEric Blake btn = evt->u.btn.data; 147b5a1b443SEric Blake if (btn->down) { 148b5a1b443SEric Blake e->buttons_state |= bmap[btn->button]; 149b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 1508b84286fSGerd Hoffmann e->dz--; 151b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 1528b84286fSGerd Hoffmann e->dz++; 1538b84286fSGerd Hoffmann } 154dcfda673SGerd Hoffmann } else { 155b5a1b443SEric Blake e->buttons_state &= ~bmap[btn->button]; 156dcfda673SGerd Hoffmann } 1578b84286fSGerd Hoffmann break; 1588b84286fSGerd Hoffmann 1598b84286fSGerd Hoffmann default: 1608b84286fSGerd Hoffmann /* keep gcc happy */ 1618b84286fSGerd Hoffmann break; 162dcfda673SGerd Hoffmann } 163dcfda673SGerd Hoffmann 1648b84286fSGerd Hoffmann } 1658b84286fSGerd Hoffmann 1668b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev) 167dcfda673SGerd Hoffmann { 1688b84286fSGerd Hoffmann HIDState *hs = (HIDState *)dev; 1698b84286fSGerd Hoffmann HIDPointerEvent *prev, *curr, *next; 1708b84286fSGerd Hoffmann bool event_compression = false; 171dcfda673SGerd Hoffmann 1728b84286fSGerd Hoffmann if (hs->n == QUEUE_LENGTH-1) { 1738b84286fSGerd Hoffmann /* 1745d831be2SStefan Weil * Queue full. We are losing information, but we at least 1758b84286fSGerd Hoffmann * keep track of most recent button state. 1768b84286fSGerd Hoffmann */ 1778b84286fSGerd Hoffmann return; 178dcfda673SGerd Hoffmann } 1798b84286fSGerd Hoffmann 1808b84286fSGerd Hoffmann prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK]; 1818b84286fSGerd Hoffmann curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; 1828b84286fSGerd Hoffmann next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK]; 1838b84286fSGerd Hoffmann 1848b84286fSGerd Hoffmann if (hs->n > 0) { 1858b84286fSGerd Hoffmann /* 1868b84286fSGerd Hoffmann * No button state change between previous and current event 1878b84286fSGerd Hoffmann * (and previous wasn't seen by the guest yet), so there is 1888b84286fSGerd Hoffmann * motion information only and we can combine the two event 1898b84286fSGerd Hoffmann * into one. 1908b84286fSGerd Hoffmann */ 1918b84286fSGerd Hoffmann if (curr->buttons_state == prev->buttons_state) { 1928b84286fSGerd Hoffmann event_compression = true; 1938b84286fSGerd Hoffmann } 1948b84286fSGerd Hoffmann } 1958b84286fSGerd Hoffmann 1968b84286fSGerd Hoffmann if (event_compression) { 1978b84286fSGerd Hoffmann /* add current motion to previous, clear current */ 1988b84286fSGerd Hoffmann if (hs->kind == HID_MOUSE) { 1998b84286fSGerd Hoffmann prev->xdx += curr->xdx; 2008b84286fSGerd Hoffmann curr->xdx = 0; 20135e83d10SChristian Burger prev->ydy += curr->ydy; 2028b84286fSGerd Hoffmann curr->ydy = 0; 2038b84286fSGerd Hoffmann } else { 2048b84286fSGerd Hoffmann prev->xdx = curr->xdx; 2058b84286fSGerd Hoffmann prev->ydy = curr->ydy; 2068b84286fSGerd Hoffmann } 2078b84286fSGerd Hoffmann prev->dz += curr->dz; 2088b84286fSGerd Hoffmann curr->dz = 0; 2098b84286fSGerd Hoffmann } else { 2108b84286fSGerd Hoffmann /* prepate next (clear rel, copy abs + btns) */ 2118b84286fSGerd Hoffmann if (hs->kind == HID_MOUSE) { 2128b84286fSGerd Hoffmann next->xdx = 0; 2138b84286fSGerd Hoffmann next->ydy = 0; 2148b84286fSGerd Hoffmann } else { 2158b84286fSGerd Hoffmann next->xdx = curr->xdx; 2168b84286fSGerd Hoffmann next->ydy = curr->ydy; 2178b84286fSGerd Hoffmann } 2188b84286fSGerd Hoffmann next->dz = 0; 2198b84286fSGerd Hoffmann next->buttons_state = curr->buttons_state; 2208b84286fSGerd Hoffmann /* make current guest visible, notify guest */ 2218b84286fSGerd Hoffmann hs->n++; 222dcfda673SGerd Hoffmann hs->event(hs); 223dcfda673SGerd Hoffmann } 2248b84286fSGerd Hoffmann } 225dcfda673SGerd Hoffmann 2261ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, 2271ff5eeddSGerd Hoffmann InputEvent *evt) 228dcfda673SGerd Hoffmann { 2291ff5eeddSGerd Hoffmann HIDState *hs = (HIDState *)dev; 2301ff5eeddSGerd Hoffmann int scancodes[3], i, count; 231dcfda673SGerd Hoffmann int slot; 23232bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 233dcfda673SGerd Hoffmann 234b5a1b443SEric Blake count = qemu_input_key_value_to_scancode(key->key, 235b5a1b443SEric Blake key->down, 2361ff5eeddSGerd Hoffmann scancodes); 2371ff5eeddSGerd Hoffmann if (hs->n + count > QUEUE_LENGTH) { 238c80276b4SGerd Hoffmann trace_hid_kbd_queue_full(); 239dcfda673SGerd Hoffmann return; 240dcfda673SGerd Hoffmann } 2411ff5eeddSGerd Hoffmann for (i = 0; i < count; i++) { 242dcfda673SGerd Hoffmann slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; 2431ff5eeddSGerd Hoffmann hs->kbd.keycodes[slot] = scancodes[i]; 2441ff5eeddSGerd Hoffmann } 245dcfda673SGerd Hoffmann hs->event(hs); 246dcfda673SGerd Hoffmann } 247dcfda673SGerd Hoffmann 248dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs) 249dcfda673SGerd Hoffmann { 250562f9375SPaolo Bonzini uint8_t hid_code, index, key; 251dcfda673SGerd Hoffmann int i, keycode, slot; 252dcfda673SGerd Hoffmann 253dcfda673SGerd Hoffmann if (hs->n == 0) { 254dcfda673SGerd Hoffmann return; 255dcfda673SGerd Hoffmann } 256dcfda673SGerd Hoffmann slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; 257dcfda673SGerd Hoffmann keycode = hs->kbd.keycodes[slot]; 258dcfda673SGerd Hoffmann 2592222e0a6SAlexander Graf if (!hs->n) { 2602222e0a6SAlexander Graf trace_hid_kbd_queue_empty(); 2612222e0a6SAlexander Graf } 2622222e0a6SAlexander Graf 263dcfda673SGerd Hoffmann key = keycode & 0x7f; 264562f9375SPaolo Bonzini index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1); 265562f9375SPaolo Bonzini hid_code = hid_usage_keys[index]; 266dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << 8); 267dcfda673SGerd Hoffmann 268dcfda673SGerd Hoffmann switch (hid_code) { 269dcfda673SGerd Hoffmann case 0x00: 270dcfda673SGerd Hoffmann return; 271dcfda673SGerd Hoffmann 272dcfda673SGerd Hoffmann case 0xe0: 273562f9375SPaolo Bonzini assert(key == 0x1d); 274dcfda673SGerd Hoffmann if (hs->kbd.modifiers & (1 << 9)) { 275562f9375SPaolo Bonzini /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0. 276562f9375SPaolo Bonzini * Here we're processing the second hid_code. By dropping bit 9 277562f9375SPaolo Bonzini * and setting bit 8, the scancode after 0x1d will access the 278562f9375SPaolo Bonzini * second half of the table. 279562f9375SPaolo Bonzini */ 280562f9375SPaolo Bonzini hs->kbd.modifiers ^= (1 << 8) | (1 << 9); 281dcfda673SGerd Hoffmann return; 282dcfda673SGerd Hoffmann } 283562f9375SPaolo Bonzini /* fall through to process Ctrl_L */ 284dcfda673SGerd Hoffmann case 0xe1 ... 0xe7: 285562f9375SPaolo Bonzini /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R. 286562f9375SPaolo Bonzini * Handle releases here, or fall through to process presses. 287562f9375SPaolo Bonzini */ 288dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 289dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); 290dcfda673SGerd Hoffmann return; 291dcfda673SGerd Hoffmann } 292562f9375SPaolo Bonzini /* fall through */ 293562f9375SPaolo Bonzini case 0xe8 ... 0xe9: 294562f9375SPaolo Bonzini /* USB modifiers are just 1 byte long. Bits 8 and 9 of 295562f9375SPaolo Bonzini * hs->kbd.modifiers implement a state machine that detects the 296562f9375SPaolo Bonzini * 0xe0 and 0xe1/0x1d sequences. These bits do not follow the 297562f9375SPaolo Bonzini * usual rules where bit 7 marks released keys; they are cleared 298562f9375SPaolo Bonzini * elsewhere in the function as the state machine dictates. 299562f9375SPaolo Bonzini */ 300dcfda673SGerd Hoffmann hs->kbd.modifiers |= 1 << (hid_code & 0x0f); 301dcfda673SGerd Hoffmann return; 302562f9375SPaolo Bonzini 303562f9375SPaolo Bonzini case 0xea ... 0xef: 304562f9375SPaolo Bonzini abort(); 305562f9375SPaolo Bonzini 306562f9375SPaolo Bonzini default: 307562f9375SPaolo Bonzini break; 308dcfda673SGerd Hoffmann } 309dcfda673SGerd Hoffmann 310dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 311dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 312dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 313dcfda673SGerd Hoffmann hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; 314dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys] = 0x00; 315dcfda673SGerd Hoffmann break; 316dcfda673SGerd Hoffmann } 317dcfda673SGerd Hoffmann } 318dcfda673SGerd Hoffmann if (i < 0) { 319dcfda673SGerd Hoffmann return; 320dcfda673SGerd Hoffmann } 321dcfda673SGerd Hoffmann } else { 322dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 323dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 324dcfda673SGerd Hoffmann break; 325dcfda673SGerd Hoffmann } 326dcfda673SGerd Hoffmann } 327dcfda673SGerd Hoffmann if (i < 0) { 328dcfda673SGerd Hoffmann if (hs->kbd.keys < sizeof(hs->kbd.key)) { 329dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys++] = hid_code; 330dcfda673SGerd Hoffmann } 331dcfda673SGerd Hoffmann } else { 332dcfda673SGerd Hoffmann return; 333dcfda673SGerd Hoffmann } 334dcfda673SGerd Hoffmann } 335dcfda673SGerd Hoffmann } 336dcfda673SGerd Hoffmann 337dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax) 338dcfda673SGerd Hoffmann { 339dcfda673SGerd Hoffmann if (val < vmin) { 340dcfda673SGerd Hoffmann return vmin; 341dcfda673SGerd Hoffmann } else if (val > vmax) { 342dcfda673SGerd Hoffmann return vmax; 343dcfda673SGerd Hoffmann } else { 344dcfda673SGerd Hoffmann return val; 345dcfda673SGerd Hoffmann } 346dcfda673SGerd Hoffmann } 347dcfda673SGerd Hoffmann 34821635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs) 34921635e12SGerd Hoffmann { 35021635e12SGerd Hoffmann if (!hs->ptr.mouse_grabbed) { 3518b84286fSGerd Hoffmann qemu_input_handler_activate(hs->s); 35221635e12SGerd Hoffmann hs->ptr.mouse_grabbed = 1; 35321635e12SGerd Hoffmann } 35421635e12SGerd Hoffmann } 35521635e12SGerd Hoffmann 356dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) 357dcfda673SGerd Hoffmann { 3588b84286fSGerd Hoffmann int dx, dy, dz, l; 359dcfda673SGerd Hoffmann int index; 360dcfda673SGerd Hoffmann HIDPointerEvent *e; 361dcfda673SGerd Hoffmann 362027c03f7SHans de Goede hs->idle_pending = false; 363027c03f7SHans de Goede 36421635e12SGerd Hoffmann hid_pointer_activate(hs); 365dcfda673SGerd Hoffmann 366dcfda673SGerd Hoffmann /* When the buffer is empty, return the last event. Relative 367dcfda673SGerd Hoffmann movements will all be zero. */ 368dcfda673SGerd Hoffmann index = (hs->n ? hs->head : hs->head - 1); 369dcfda673SGerd Hoffmann e = &hs->ptr.queue[index & QUEUE_MASK]; 370dcfda673SGerd Hoffmann 371dcfda673SGerd Hoffmann if (hs->kind == HID_MOUSE) { 372dcfda673SGerd Hoffmann dx = int_clamp(e->xdx, -127, 127); 373dcfda673SGerd Hoffmann dy = int_clamp(e->ydy, -127, 127); 374dcfda673SGerd Hoffmann e->xdx -= dx; 375dcfda673SGerd Hoffmann e->ydy -= dy; 376dcfda673SGerd Hoffmann } else { 377dcfda673SGerd Hoffmann dx = e->xdx; 378dcfda673SGerd Hoffmann dy = e->ydy; 379dcfda673SGerd Hoffmann } 380dcfda673SGerd Hoffmann dz = int_clamp(e->dz, -127, 127); 381dcfda673SGerd Hoffmann e->dz -= dz; 382dcfda673SGerd Hoffmann 383dcfda673SGerd Hoffmann if (hs->n && 384dcfda673SGerd Hoffmann !e->dz && 385dcfda673SGerd Hoffmann (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { 386dcfda673SGerd Hoffmann /* that deals with this event */ 387dcfda673SGerd Hoffmann QUEUE_INCR(hs->head); 388dcfda673SGerd Hoffmann hs->n--; 389dcfda673SGerd Hoffmann } 390dcfda673SGerd Hoffmann 391dcfda673SGerd Hoffmann /* Appears we have to invert the wheel direction */ 392dcfda673SGerd Hoffmann dz = 0 - dz; 393dcfda673SGerd Hoffmann l = 0; 394dcfda673SGerd Hoffmann switch (hs->kind) { 395dcfda673SGerd Hoffmann case HID_MOUSE: 396dcfda673SGerd Hoffmann if (len > l) { 3978b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 398dcfda673SGerd Hoffmann } 399dcfda673SGerd Hoffmann if (len > l) { 400dcfda673SGerd Hoffmann buf[l++] = dx; 401dcfda673SGerd Hoffmann } 402dcfda673SGerd Hoffmann if (len > l) { 403dcfda673SGerd Hoffmann buf[l++] = dy; 404dcfda673SGerd Hoffmann } 405dcfda673SGerd Hoffmann if (len > l) { 406dcfda673SGerd Hoffmann buf[l++] = dz; 407dcfda673SGerd Hoffmann } 408dcfda673SGerd Hoffmann break; 409dcfda673SGerd Hoffmann 410dcfda673SGerd Hoffmann case HID_TABLET: 411dcfda673SGerd Hoffmann if (len > l) { 4128b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 413dcfda673SGerd Hoffmann } 414dcfda673SGerd Hoffmann if (len > l) { 415dcfda673SGerd Hoffmann buf[l++] = dx & 0xff; 416dcfda673SGerd Hoffmann } 417dcfda673SGerd Hoffmann if (len > l) { 418dcfda673SGerd Hoffmann buf[l++] = dx >> 8; 419dcfda673SGerd Hoffmann } 420dcfda673SGerd Hoffmann if (len > l) { 421dcfda673SGerd Hoffmann buf[l++] = dy & 0xff; 422dcfda673SGerd Hoffmann } 423dcfda673SGerd Hoffmann if (len > l) { 424dcfda673SGerd Hoffmann buf[l++] = dy >> 8; 425dcfda673SGerd Hoffmann } 426dcfda673SGerd Hoffmann if (len > l) { 427dcfda673SGerd Hoffmann buf[l++] = dz; 428dcfda673SGerd Hoffmann } 429dcfda673SGerd Hoffmann break; 430dcfda673SGerd Hoffmann 431dcfda673SGerd Hoffmann default: 432dcfda673SGerd Hoffmann abort(); 433dcfda673SGerd Hoffmann } 434dcfda673SGerd Hoffmann 435dcfda673SGerd Hoffmann return l; 436dcfda673SGerd Hoffmann } 437dcfda673SGerd Hoffmann 438dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) 439dcfda673SGerd Hoffmann { 440027c03f7SHans de Goede hs->idle_pending = false; 441027c03f7SHans de Goede 442dcfda673SGerd Hoffmann if (len < 2) { 443dcfda673SGerd Hoffmann return 0; 444dcfda673SGerd Hoffmann } 445dcfda673SGerd Hoffmann 446dcfda673SGerd Hoffmann hid_keyboard_process_keycode(hs); 447dcfda673SGerd Hoffmann 448dcfda673SGerd Hoffmann buf[0] = hs->kbd.modifiers & 0xff; 449dcfda673SGerd Hoffmann buf[1] = 0; 450dcfda673SGerd Hoffmann if (hs->kbd.keys > 6) { 451dcfda673SGerd Hoffmann memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); 452dcfda673SGerd Hoffmann } else { 453dcfda673SGerd Hoffmann memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); 454dcfda673SGerd Hoffmann } 455dcfda673SGerd Hoffmann 456dcfda673SGerd Hoffmann return MIN(8, len); 457dcfda673SGerd Hoffmann } 458dcfda673SGerd Hoffmann 459dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) 460dcfda673SGerd Hoffmann { 461dcfda673SGerd Hoffmann if (len > 0) { 462dcfda673SGerd Hoffmann int ledstate = 0; 463dcfda673SGerd Hoffmann /* 0x01: Num Lock LED 464dcfda673SGerd Hoffmann * 0x02: Caps Lock LED 465dcfda673SGerd Hoffmann * 0x04: Scroll Lock LED 466dcfda673SGerd Hoffmann * 0x08: Compose LED 467dcfda673SGerd Hoffmann * 0x10: Kana LED */ 468dcfda673SGerd Hoffmann hs->kbd.leds = buf[0]; 469dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x04) { 470dcfda673SGerd Hoffmann ledstate |= QEMU_SCROLL_LOCK_LED; 471dcfda673SGerd Hoffmann } 472dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x01) { 473dcfda673SGerd Hoffmann ledstate |= QEMU_NUM_LOCK_LED; 474dcfda673SGerd Hoffmann } 475dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x02) { 476dcfda673SGerd Hoffmann ledstate |= QEMU_CAPS_LOCK_LED; 477dcfda673SGerd Hoffmann } 478dcfda673SGerd Hoffmann kbd_put_ledstate(ledstate); 479dcfda673SGerd Hoffmann } 480dcfda673SGerd Hoffmann return 0; 481dcfda673SGerd Hoffmann } 482dcfda673SGerd Hoffmann 483dcfda673SGerd Hoffmann void hid_reset(HIDState *hs) 484dcfda673SGerd Hoffmann { 485dcfda673SGerd Hoffmann switch (hs->kind) { 486dcfda673SGerd Hoffmann case HID_KEYBOARD: 487dcfda673SGerd Hoffmann memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); 488dcfda673SGerd Hoffmann memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); 489dcfda673SGerd Hoffmann hs->kbd.keys = 0; 49051dbea77SAlexander Graf hs->kbd.modifiers = 0; 491dcfda673SGerd Hoffmann break; 492dcfda673SGerd Hoffmann case HID_MOUSE: 493dcfda673SGerd Hoffmann case HID_TABLET: 494dcfda673SGerd Hoffmann memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); 495dcfda673SGerd Hoffmann break; 496dcfda673SGerd Hoffmann } 497dcfda673SGerd Hoffmann hs->head = 0; 498dcfda673SGerd Hoffmann hs->n = 0; 499b069d348SGerd Hoffmann hs->protocol = 1; 500b069d348SGerd Hoffmann hs->idle = 0; 501027c03f7SHans de Goede hs->idle_pending = false; 502027c03f7SHans de Goede hid_del_idle_timer(hs); 503dcfda673SGerd Hoffmann } 504dcfda673SGerd Hoffmann 505dcfda673SGerd Hoffmann void hid_free(HIDState *hs) 506dcfda673SGerd Hoffmann { 5071ff5eeddSGerd Hoffmann qemu_input_handler_unregister(hs->s); 508027c03f7SHans de Goede hid_del_idle_timer(hs); 509dcfda673SGerd Hoffmann } 510dcfda673SGerd Hoffmann 5111ff5eeddSGerd Hoffmann static QemuInputHandler hid_keyboard_handler = { 5121ff5eeddSGerd Hoffmann .name = "QEMU HID Keyboard", 5131ff5eeddSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 5141ff5eeddSGerd Hoffmann .event = hid_keyboard_event, 5151ff5eeddSGerd Hoffmann }; 5161ff5eeddSGerd Hoffmann 5178b84286fSGerd Hoffmann static QemuInputHandler hid_mouse_handler = { 5188b84286fSGerd Hoffmann .name = "QEMU HID Mouse", 5198b84286fSGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 5208b84286fSGerd Hoffmann .event = hid_pointer_event, 5218b84286fSGerd Hoffmann .sync = hid_pointer_sync, 5228b84286fSGerd Hoffmann }; 5238b84286fSGerd Hoffmann 5248b84286fSGerd Hoffmann static QemuInputHandler hid_tablet_handler = { 5258b84286fSGerd Hoffmann .name = "QEMU HID Tablet", 5268b84286fSGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, 5278b84286fSGerd Hoffmann .event = hid_pointer_event, 5288b84286fSGerd Hoffmann .sync = hid_pointer_sync, 5298b84286fSGerd Hoffmann }; 5308b84286fSGerd Hoffmann 531dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event) 532dcfda673SGerd Hoffmann { 533dcfda673SGerd Hoffmann hs->kind = kind; 534dcfda673SGerd Hoffmann hs->event = event; 535dcfda673SGerd Hoffmann 536bb0db527SMichael Walle if (hs->kind == HID_KEYBOARD) { 5371ff5eeddSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5381ff5eeddSGerd Hoffmann &hid_keyboard_handler); 5391ff5eeddSGerd Hoffmann qemu_input_handler_activate(hs->s); 540bb0db527SMichael Walle } else if (hs->kind == HID_MOUSE) { 5418b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5428b84286fSGerd Hoffmann &hid_mouse_handler); 543dcfda673SGerd Hoffmann } else if (hs->kind == HID_TABLET) { 5448b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5458b84286fSGerd Hoffmann &hid_tablet_handler); 546dcfda673SGerd Hoffmann } 547dcfda673SGerd Hoffmann } 548ccd4ed06SMichael Walle 549ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id) 550ccd4ed06SMichael Walle { 551ccd4ed06SMichael Walle HIDState *s = opaque; 552ccd4ed06SMichael Walle 553027c03f7SHans de Goede hid_set_next_idle(s); 554ba4d2606SGerd Hoffmann 555ba4d2606SGerd Hoffmann if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET || 556ba4d2606SGerd Hoffmann s->kind == HID_MOUSE)) { 557ba4d2606SGerd Hoffmann /* 558ba4d2606SGerd Hoffmann * Handle ptr device migration from old qemu with full queue. 559ba4d2606SGerd Hoffmann * 560ba4d2606SGerd Hoffmann * Throw away everything but the last event, so we propagate 561ba4d2606SGerd Hoffmann * at least the current button state to the guest. Also keep 562ba4d2606SGerd Hoffmann * current position for the tablet, signal "no motion" for the 563ba4d2606SGerd Hoffmann * mouse. 564ba4d2606SGerd Hoffmann */ 565ba4d2606SGerd Hoffmann HIDPointerEvent evt; 566ba4d2606SGerd Hoffmann evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK]; 567ba4d2606SGerd Hoffmann if (s->kind == HID_MOUSE) { 568ba4d2606SGerd Hoffmann evt.xdx = 0; 569ba4d2606SGerd Hoffmann evt.ydy = 0; 570ba4d2606SGerd Hoffmann } 571ba4d2606SGerd Hoffmann s->ptr.queue[0] = evt; 572ba4d2606SGerd Hoffmann s->head = 0; 573ba4d2606SGerd Hoffmann s->n = 1; 574ba4d2606SGerd Hoffmann } 575ccd4ed06SMichael Walle return 0; 576ccd4ed06SMichael Walle } 577ccd4ed06SMichael Walle 578ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = { 579ccd4ed06SMichael Walle .name = "HIDPointerEventQueue", 580ccd4ed06SMichael Walle .version_id = 1, 581ccd4ed06SMichael Walle .minimum_version_id = 1, 582ccd4ed06SMichael Walle .fields = (VMStateField[]) { 583ccd4ed06SMichael Walle VMSTATE_INT32(xdx, HIDPointerEvent), 584ccd4ed06SMichael Walle VMSTATE_INT32(ydy, HIDPointerEvent), 585ccd4ed06SMichael Walle VMSTATE_INT32(dz, HIDPointerEvent), 586ccd4ed06SMichael Walle VMSTATE_INT32(buttons_state, HIDPointerEvent), 587ccd4ed06SMichael Walle VMSTATE_END_OF_LIST() 588ccd4ed06SMichael Walle } 589ccd4ed06SMichael Walle }; 590ccd4ed06SMichael Walle 591ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = { 592ccd4ed06SMichael Walle .name = "HIDPointerDevice", 593ccd4ed06SMichael Walle .version_id = 1, 594ccd4ed06SMichael Walle .minimum_version_id = 1, 595ccd4ed06SMichael Walle .post_load = hid_post_load, 596ccd4ed06SMichael Walle .fields = (VMStateField[]) { 597ccd4ed06SMichael Walle VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0, 598ccd4ed06SMichael Walle vmstate_hid_ptr_queue, HIDPointerEvent), 599ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 600ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 601ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 602ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 603ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 604ccd4ed06SMichael Walle } 605ccd4ed06SMichael Walle }; 606ccd4ed06SMichael Walle 607ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = { 608ccd4ed06SMichael Walle .name = "HIDKeyboardDevice", 609ccd4ed06SMichael Walle .version_id = 1, 610ccd4ed06SMichael Walle .minimum_version_id = 1, 611ccd4ed06SMichael Walle .post_load = hid_post_load, 612ccd4ed06SMichael Walle .fields = (VMStateField[]) { 613ccd4ed06SMichael Walle VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH), 614ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 615ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 616ccd4ed06SMichael Walle VMSTATE_UINT16(kbd.modifiers, HIDState), 617ccd4ed06SMichael Walle VMSTATE_UINT8(kbd.leds, HIDState), 618ccd4ed06SMichael Walle VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16), 619ccd4ed06SMichael Walle VMSTATE_INT32(kbd.keys, HIDState), 620ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 621ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 622ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 623ccd4ed06SMichael Walle } 624ccd4ed06SMichael Walle }; 625