149ab747fSPaolo Bonzini /* 249ab747fSPaolo Bonzini * QEMU HID devices 349ab747fSPaolo Bonzini * 449ab747fSPaolo Bonzini * Copyright (c) 2005 Fabrice Bellard 549ab747fSPaolo Bonzini * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) 649ab747fSPaolo Bonzini * 749ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 849ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 949ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights 1049ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1149ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1249ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions: 1349ab747fSPaolo Bonzini * 1449ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1549ab747fSPaolo Bonzini * all copies or substantial portions of the Software. 1649ab747fSPaolo Bonzini * 1749ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1849ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1949ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2049ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2149ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2249ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2349ab747fSPaolo Bonzini * THE SOFTWARE. 2449ab747fSPaolo Bonzini */ 250430891cSPeter Maydell #include "qemu/osdep.h" 2649ab747fSPaolo Bonzini #include "hw/hw.h" 2749ab747fSPaolo Bonzini #include "ui/console.h" 2849ab747fSPaolo Bonzini #include "qemu/timer.h" 2949ab747fSPaolo Bonzini #include "hw/input/hid.h" 30c80276b4SGerd Hoffmann #include "trace.h" 3149ab747fSPaolo Bonzini 3249ab747fSPaolo Bonzini #define HID_USAGE_ERROR_ROLLOVER 0x01 3349ab747fSPaolo Bonzini #define HID_USAGE_POSTFAIL 0x02 3449ab747fSPaolo Bonzini #define HID_USAGE_ERROR_UNDEFINED 0x03 3549ab747fSPaolo Bonzini 3649ab747fSPaolo Bonzini /* Indices are QEMU keycodes, values are from HID Usage Table. Indices 3749ab747fSPaolo Bonzini * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ 3849ab747fSPaolo Bonzini static const uint8_t hid_usage_keys[0x100] = { 3949ab747fSPaolo Bonzini 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 4049ab747fSPaolo Bonzini 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, 4149ab747fSPaolo Bonzini 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, 4249ab747fSPaolo Bonzini 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, 4349ab747fSPaolo Bonzini 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, 4449ab747fSPaolo Bonzini 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, 4549ab747fSPaolo Bonzini 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, 460ee4de58SDinar Valeev 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 4749ab747fSPaolo Bonzini 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, 4849ab747fSPaolo Bonzini 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, 4986f3bf0eSPeter Korsgaard 0x5a, 0x5b, 0x62, 0x63, 0x46, 0x00, 0x64, 0x44, 5049ab747fSPaolo Bonzini 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 5149ab747fSPaolo Bonzini 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, 5249ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 5349ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 5449ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 5549ab747fSPaolo Bonzini 5649ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 5749ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 5849ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 5949ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, 60*160997faSTao Wu 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61*160997faSTao Wu 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 62*160997faSTao Wu 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, 6349ab747fSPaolo Bonzini 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 6486f3bf0eSPeter Korsgaard 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x4a, 6549ab747fSPaolo Bonzini 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, 6649ab747fSPaolo Bonzini 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, 67*160997faSTao Wu 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x66, 0x00, 6849ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 6949ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7049ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7149ab747fSPaolo Bonzini 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7249ab747fSPaolo Bonzini }; 7349ab747fSPaolo Bonzini 7449ab747fSPaolo Bonzini bool hid_has_events(HIDState *hs) 7549ab747fSPaolo Bonzini { 7649ab747fSPaolo Bonzini return hs->n > 0 || hs->idle_pending; 7749ab747fSPaolo Bonzini } 7849ab747fSPaolo Bonzini 7949ab747fSPaolo Bonzini static void hid_idle_timer(void *opaque) 8049ab747fSPaolo Bonzini { 8149ab747fSPaolo Bonzini HIDState *hs = opaque; 8249ab747fSPaolo Bonzini 8349ab747fSPaolo Bonzini hs->idle_pending = true; 8449ab747fSPaolo Bonzini hs->event(hs); 8549ab747fSPaolo Bonzini } 8649ab747fSPaolo Bonzini 8749ab747fSPaolo Bonzini static void hid_del_idle_timer(HIDState *hs) 8849ab747fSPaolo Bonzini { 8949ab747fSPaolo Bonzini if (hs->idle_timer) { 90bc72ad67SAlex Bligh timer_del(hs->idle_timer); 91bc72ad67SAlex Bligh timer_free(hs->idle_timer); 9249ab747fSPaolo Bonzini hs->idle_timer = NULL; 9349ab747fSPaolo Bonzini } 9449ab747fSPaolo Bonzini } 9549ab747fSPaolo Bonzini 9649ab747fSPaolo Bonzini void hid_set_next_idle(HIDState *hs) 9749ab747fSPaolo Bonzini { 9849ab747fSPaolo Bonzini 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; 10149ab747fSPaolo Bonzini if (!hs->idle_timer) { 102bc72ad67SAlex Bligh hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs); 10349ab747fSPaolo Bonzini } 104bc72ad67SAlex Bligh timer_mod_ns(hs->idle_timer, expire_time); 10549ab747fSPaolo Bonzini } else { 10649ab747fSPaolo Bonzini hid_del_idle_timer(hs); 10749ab747fSPaolo Bonzini } 10849ab747fSPaolo Bonzini } 10949ab747fSPaolo Bonzini 1108b84286fSGerd Hoffmann static void hid_pointer_event(DeviceState *dev, QemuConsole *src, 1118b84286fSGerd Hoffmann InputEvent *evt) 11249ab747fSPaolo Bonzini { 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; 12249ab747fSPaolo Bonzini 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 } 15449ab747fSPaolo Bonzini } else { 155b5a1b443SEric Blake e->buttons_state &= ~bmap[btn->button]; 15649ab747fSPaolo Bonzini } 1578b84286fSGerd Hoffmann break; 1588b84286fSGerd Hoffmann 1598b84286fSGerd Hoffmann default: 1608b84286fSGerd Hoffmann /* keep gcc happy */ 1618b84286fSGerd Hoffmann break; 16249ab747fSPaolo Bonzini } 16349ab747fSPaolo Bonzini 1648b84286fSGerd Hoffmann } 1658b84286fSGerd Hoffmann 1668b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev) 16749ab747fSPaolo Bonzini { 1688b84286fSGerd Hoffmann HIDState *hs = (HIDState *)dev; 1698b84286fSGerd Hoffmann HIDPointerEvent *prev, *curr, *next; 1708b84286fSGerd Hoffmann bool event_compression = false; 17149ab747fSPaolo Bonzini 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; 17849ab747fSPaolo Bonzini } 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++; 22249ab747fSPaolo Bonzini hs->event(hs); 22349ab747fSPaolo Bonzini } 2248b84286fSGerd Hoffmann } 22549ab747fSPaolo Bonzini 2261ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, 2271ff5eeddSGerd Hoffmann InputEvent *evt) 22849ab747fSPaolo Bonzini { 2291ff5eeddSGerd Hoffmann HIDState *hs = (HIDState *)dev; 2301ff5eeddSGerd Hoffmann int scancodes[3], i, count; 23149ab747fSPaolo Bonzini int slot; 23232bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 23349ab747fSPaolo Bonzini 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(); 23949ab747fSPaolo Bonzini return; 24049ab747fSPaolo Bonzini } 2411ff5eeddSGerd Hoffmann for (i = 0; i < count; i++) { 24249ab747fSPaolo Bonzini slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; 2431ff5eeddSGerd Hoffmann hs->kbd.keycodes[slot] = scancodes[i]; 2441ff5eeddSGerd Hoffmann } 24549ab747fSPaolo Bonzini hs->event(hs); 24649ab747fSPaolo Bonzini } 24749ab747fSPaolo Bonzini 24849ab747fSPaolo Bonzini static void hid_keyboard_process_keycode(HIDState *hs) 24949ab747fSPaolo Bonzini { 250562f9375SPaolo Bonzini uint8_t hid_code, index, key; 25149ab747fSPaolo Bonzini int i, keycode, slot; 25249ab747fSPaolo Bonzini 25349ab747fSPaolo Bonzini if (hs->n == 0) { 25449ab747fSPaolo Bonzini return; 25549ab747fSPaolo Bonzini } 25649ab747fSPaolo Bonzini slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; 25749ab747fSPaolo Bonzini keycode = hs->kbd.keycodes[slot]; 25849ab747fSPaolo Bonzini 2592222e0a6SAlexander Graf if (!hs->n) { 2602222e0a6SAlexander Graf trace_hid_kbd_queue_empty(); 2612222e0a6SAlexander Graf } 2622222e0a6SAlexander Graf 26349ab747fSPaolo Bonzini key = keycode & 0x7f; 264562f9375SPaolo Bonzini index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1); 265562f9375SPaolo Bonzini hid_code = hid_usage_keys[index]; 26649ab747fSPaolo Bonzini hs->kbd.modifiers &= ~(1 << 8); 26749ab747fSPaolo Bonzini 26849ab747fSPaolo Bonzini switch (hid_code) { 26949ab747fSPaolo Bonzini case 0x00: 27049ab747fSPaolo Bonzini return; 27149ab747fSPaolo Bonzini 27249ab747fSPaolo Bonzini case 0xe0: 273562f9375SPaolo Bonzini assert(key == 0x1d); 27449ab747fSPaolo Bonzini 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); 28149ab747fSPaolo Bonzini return; 28249ab747fSPaolo Bonzini } 283562f9375SPaolo Bonzini /* fall through to process Ctrl_L */ 28449ab747fSPaolo Bonzini 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 */ 28849ab747fSPaolo Bonzini if (keycode & (1 << 7)) { 28949ab747fSPaolo Bonzini hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); 29049ab747fSPaolo Bonzini return; 29149ab747fSPaolo Bonzini } 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 */ 30049ab747fSPaolo Bonzini hs->kbd.modifiers |= 1 << (hid_code & 0x0f); 30149ab747fSPaolo Bonzini return; 302562f9375SPaolo Bonzini 303562f9375SPaolo Bonzini case 0xea ... 0xef: 304562f9375SPaolo Bonzini abort(); 305562f9375SPaolo Bonzini 306562f9375SPaolo Bonzini default: 307562f9375SPaolo Bonzini break; 30849ab747fSPaolo Bonzini } 30949ab747fSPaolo Bonzini 31049ab747fSPaolo Bonzini if (keycode & (1 << 7)) { 31149ab747fSPaolo Bonzini for (i = hs->kbd.keys - 1; i >= 0; i--) { 31249ab747fSPaolo Bonzini if (hs->kbd.key[i] == hid_code) { 31349ab747fSPaolo Bonzini hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; 31449ab747fSPaolo Bonzini hs->kbd.key[hs->kbd.keys] = 0x00; 31549ab747fSPaolo Bonzini break; 31649ab747fSPaolo Bonzini } 31749ab747fSPaolo Bonzini } 31849ab747fSPaolo Bonzini if (i < 0) { 31949ab747fSPaolo Bonzini return; 32049ab747fSPaolo Bonzini } 32149ab747fSPaolo Bonzini } else { 32249ab747fSPaolo Bonzini for (i = hs->kbd.keys - 1; i >= 0; i--) { 32349ab747fSPaolo Bonzini if (hs->kbd.key[i] == hid_code) { 32449ab747fSPaolo Bonzini break; 32549ab747fSPaolo Bonzini } 32649ab747fSPaolo Bonzini } 32749ab747fSPaolo Bonzini if (i < 0) { 32849ab747fSPaolo Bonzini if (hs->kbd.keys < sizeof(hs->kbd.key)) { 32949ab747fSPaolo Bonzini hs->kbd.key[hs->kbd.keys++] = hid_code; 33049ab747fSPaolo Bonzini } 33149ab747fSPaolo Bonzini } else { 33249ab747fSPaolo Bonzini return; 33349ab747fSPaolo Bonzini } 33449ab747fSPaolo Bonzini } 33549ab747fSPaolo Bonzini } 33649ab747fSPaolo Bonzini 33749ab747fSPaolo Bonzini static inline int int_clamp(int val, int vmin, int vmax) 33849ab747fSPaolo Bonzini { 33949ab747fSPaolo Bonzini if (val < vmin) { 34049ab747fSPaolo Bonzini return vmin; 34149ab747fSPaolo Bonzini } else if (val > vmax) { 34249ab747fSPaolo Bonzini return vmax; 34349ab747fSPaolo Bonzini } else { 34449ab747fSPaolo Bonzini return val; 34549ab747fSPaolo Bonzini } 34649ab747fSPaolo Bonzini } 34749ab747fSPaolo Bonzini 34849ab747fSPaolo Bonzini void hid_pointer_activate(HIDState *hs) 34949ab747fSPaolo Bonzini { 35049ab747fSPaolo Bonzini if (!hs->ptr.mouse_grabbed) { 3518b84286fSGerd Hoffmann qemu_input_handler_activate(hs->s); 35249ab747fSPaolo Bonzini hs->ptr.mouse_grabbed = 1; 35349ab747fSPaolo Bonzini } 35449ab747fSPaolo Bonzini } 35549ab747fSPaolo Bonzini 35649ab747fSPaolo Bonzini int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) 35749ab747fSPaolo Bonzini { 3588b84286fSGerd Hoffmann int dx, dy, dz, l; 35949ab747fSPaolo Bonzini int index; 36049ab747fSPaolo Bonzini HIDPointerEvent *e; 36149ab747fSPaolo Bonzini 36249ab747fSPaolo Bonzini hs->idle_pending = false; 36349ab747fSPaolo Bonzini 36449ab747fSPaolo Bonzini hid_pointer_activate(hs); 36549ab747fSPaolo Bonzini 36649ab747fSPaolo Bonzini /* When the buffer is empty, return the last event. Relative 36749ab747fSPaolo Bonzini movements will all be zero. */ 36849ab747fSPaolo Bonzini index = (hs->n ? hs->head : hs->head - 1); 36949ab747fSPaolo Bonzini e = &hs->ptr.queue[index & QUEUE_MASK]; 37049ab747fSPaolo Bonzini 37149ab747fSPaolo Bonzini if (hs->kind == HID_MOUSE) { 37249ab747fSPaolo Bonzini dx = int_clamp(e->xdx, -127, 127); 37349ab747fSPaolo Bonzini dy = int_clamp(e->ydy, -127, 127); 37449ab747fSPaolo Bonzini e->xdx -= dx; 37549ab747fSPaolo Bonzini e->ydy -= dy; 37649ab747fSPaolo Bonzini } else { 37749ab747fSPaolo Bonzini dx = e->xdx; 37849ab747fSPaolo Bonzini dy = e->ydy; 37949ab747fSPaolo Bonzini } 38049ab747fSPaolo Bonzini dz = int_clamp(e->dz, -127, 127); 38149ab747fSPaolo Bonzini e->dz -= dz; 38249ab747fSPaolo Bonzini 38349ab747fSPaolo Bonzini if (hs->n && 38449ab747fSPaolo Bonzini !e->dz && 38549ab747fSPaolo Bonzini (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { 38649ab747fSPaolo Bonzini /* that deals with this event */ 38749ab747fSPaolo Bonzini QUEUE_INCR(hs->head); 38849ab747fSPaolo Bonzini hs->n--; 38949ab747fSPaolo Bonzini } 39049ab747fSPaolo Bonzini 39149ab747fSPaolo Bonzini /* Appears we have to invert the wheel direction */ 39249ab747fSPaolo Bonzini dz = 0 - dz; 39349ab747fSPaolo Bonzini l = 0; 39449ab747fSPaolo Bonzini switch (hs->kind) { 39549ab747fSPaolo Bonzini case HID_MOUSE: 39649ab747fSPaolo Bonzini if (len > l) { 3978b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 39849ab747fSPaolo Bonzini } 39949ab747fSPaolo Bonzini if (len > l) { 40049ab747fSPaolo Bonzini buf[l++] = dx; 40149ab747fSPaolo Bonzini } 40249ab747fSPaolo Bonzini if (len > l) { 40349ab747fSPaolo Bonzini buf[l++] = dy; 40449ab747fSPaolo Bonzini } 40549ab747fSPaolo Bonzini if (len > l) { 40649ab747fSPaolo Bonzini buf[l++] = dz; 40749ab747fSPaolo Bonzini } 40849ab747fSPaolo Bonzini break; 40949ab747fSPaolo Bonzini 41049ab747fSPaolo Bonzini case HID_TABLET: 41149ab747fSPaolo Bonzini if (len > l) { 4128b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 41349ab747fSPaolo Bonzini } 41449ab747fSPaolo Bonzini if (len > l) { 41549ab747fSPaolo Bonzini buf[l++] = dx & 0xff; 41649ab747fSPaolo Bonzini } 41749ab747fSPaolo Bonzini if (len > l) { 41849ab747fSPaolo Bonzini buf[l++] = dx >> 8; 41949ab747fSPaolo Bonzini } 42049ab747fSPaolo Bonzini if (len > l) { 42149ab747fSPaolo Bonzini buf[l++] = dy & 0xff; 42249ab747fSPaolo Bonzini } 42349ab747fSPaolo Bonzini if (len > l) { 42449ab747fSPaolo Bonzini buf[l++] = dy >> 8; 42549ab747fSPaolo Bonzini } 42649ab747fSPaolo Bonzini if (len > l) { 42749ab747fSPaolo Bonzini buf[l++] = dz; 42849ab747fSPaolo Bonzini } 42949ab747fSPaolo Bonzini break; 43049ab747fSPaolo Bonzini 43149ab747fSPaolo Bonzini default: 43249ab747fSPaolo Bonzini abort(); 43349ab747fSPaolo Bonzini } 43449ab747fSPaolo Bonzini 43549ab747fSPaolo Bonzini return l; 43649ab747fSPaolo Bonzini } 43749ab747fSPaolo Bonzini 43849ab747fSPaolo Bonzini int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) 43949ab747fSPaolo Bonzini { 44049ab747fSPaolo Bonzini hs->idle_pending = false; 44149ab747fSPaolo Bonzini 44249ab747fSPaolo Bonzini if (len < 2) { 44349ab747fSPaolo Bonzini return 0; 44449ab747fSPaolo Bonzini } 44549ab747fSPaolo Bonzini 44649ab747fSPaolo Bonzini hid_keyboard_process_keycode(hs); 44749ab747fSPaolo Bonzini 44849ab747fSPaolo Bonzini buf[0] = hs->kbd.modifiers & 0xff; 44949ab747fSPaolo Bonzini buf[1] = 0; 45049ab747fSPaolo Bonzini if (hs->kbd.keys > 6) { 45149ab747fSPaolo Bonzini memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); 45249ab747fSPaolo Bonzini } else { 45349ab747fSPaolo Bonzini memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); 45449ab747fSPaolo Bonzini } 45549ab747fSPaolo Bonzini 45649ab747fSPaolo Bonzini return MIN(8, len); 45749ab747fSPaolo Bonzini } 45849ab747fSPaolo Bonzini 45949ab747fSPaolo Bonzini int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) 46049ab747fSPaolo Bonzini { 46149ab747fSPaolo Bonzini if (len > 0) { 46249ab747fSPaolo Bonzini int ledstate = 0; 46349ab747fSPaolo Bonzini /* 0x01: Num Lock LED 46449ab747fSPaolo Bonzini * 0x02: Caps Lock LED 46549ab747fSPaolo Bonzini * 0x04: Scroll Lock LED 46649ab747fSPaolo Bonzini * 0x08: Compose LED 46749ab747fSPaolo Bonzini * 0x10: Kana LED */ 46849ab747fSPaolo Bonzini hs->kbd.leds = buf[0]; 46949ab747fSPaolo Bonzini if (hs->kbd.leds & 0x04) { 47049ab747fSPaolo Bonzini ledstate |= QEMU_SCROLL_LOCK_LED; 47149ab747fSPaolo Bonzini } 47249ab747fSPaolo Bonzini if (hs->kbd.leds & 0x01) { 47349ab747fSPaolo Bonzini ledstate |= QEMU_NUM_LOCK_LED; 47449ab747fSPaolo Bonzini } 47549ab747fSPaolo Bonzini if (hs->kbd.leds & 0x02) { 47649ab747fSPaolo Bonzini ledstate |= QEMU_CAPS_LOCK_LED; 47749ab747fSPaolo Bonzini } 47849ab747fSPaolo Bonzini kbd_put_ledstate(ledstate); 47949ab747fSPaolo Bonzini } 48049ab747fSPaolo Bonzini return 0; 48149ab747fSPaolo Bonzini } 48249ab747fSPaolo Bonzini 48349ab747fSPaolo Bonzini void hid_reset(HIDState *hs) 48449ab747fSPaolo Bonzini { 48549ab747fSPaolo Bonzini switch (hs->kind) { 48649ab747fSPaolo Bonzini case HID_KEYBOARD: 48749ab747fSPaolo Bonzini memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); 48849ab747fSPaolo Bonzini memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); 48949ab747fSPaolo Bonzini hs->kbd.keys = 0; 49051dbea77SAlexander Graf hs->kbd.modifiers = 0; 49149ab747fSPaolo Bonzini break; 49249ab747fSPaolo Bonzini case HID_MOUSE: 49349ab747fSPaolo Bonzini case HID_TABLET: 49449ab747fSPaolo Bonzini memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); 49549ab747fSPaolo Bonzini break; 49649ab747fSPaolo Bonzini } 49749ab747fSPaolo Bonzini hs->head = 0; 49849ab747fSPaolo Bonzini hs->n = 0; 49949ab747fSPaolo Bonzini hs->protocol = 1; 50049ab747fSPaolo Bonzini hs->idle = 0; 50149ab747fSPaolo Bonzini hs->idle_pending = false; 50249ab747fSPaolo Bonzini hid_del_idle_timer(hs); 50349ab747fSPaolo Bonzini } 50449ab747fSPaolo Bonzini 50549ab747fSPaolo Bonzini void hid_free(HIDState *hs) 50649ab747fSPaolo Bonzini { 5071ff5eeddSGerd Hoffmann qemu_input_handler_unregister(hs->s); 50849ab747fSPaolo Bonzini hid_del_idle_timer(hs); 50949ab747fSPaolo Bonzini } 51049ab747fSPaolo Bonzini 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 53149ab747fSPaolo Bonzini void hid_init(HIDState *hs, int kind, HIDEventFunc event) 53249ab747fSPaolo Bonzini { 53349ab747fSPaolo Bonzini hs->kind = kind; 53449ab747fSPaolo Bonzini hs->event = event; 53549ab747fSPaolo Bonzini 53649ab747fSPaolo Bonzini 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); 54049ab747fSPaolo Bonzini } else if (hs->kind == HID_MOUSE) { 5418b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5428b84286fSGerd Hoffmann &hid_mouse_handler); 54349ab747fSPaolo Bonzini } else if (hs->kind == HID_TABLET) { 5448b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5458b84286fSGerd Hoffmann &hid_tablet_handler); 54649ab747fSPaolo Bonzini } 54749ab747fSPaolo Bonzini } 54849ab747fSPaolo Bonzini 54949ab747fSPaolo Bonzini static int hid_post_load(void *opaque, int version_id) 55049ab747fSPaolo Bonzini { 55149ab747fSPaolo Bonzini HIDState *s = opaque; 55249ab747fSPaolo Bonzini 55349ab747fSPaolo Bonzini 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 } 57549ab747fSPaolo Bonzini return 0; 57649ab747fSPaolo Bonzini } 57749ab747fSPaolo Bonzini 57849ab747fSPaolo Bonzini static const VMStateDescription vmstate_hid_ptr_queue = { 57949ab747fSPaolo Bonzini .name = "HIDPointerEventQueue", 58049ab747fSPaolo Bonzini .version_id = 1, 58149ab747fSPaolo Bonzini .minimum_version_id = 1, 58249ab747fSPaolo Bonzini .fields = (VMStateField[]) { 58349ab747fSPaolo Bonzini VMSTATE_INT32(xdx, HIDPointerEvent), 58449ab747fSPaolo Bonzini VMSTATE_INT32(ydy, HIDPointerEvent), 58549ab747fSPaolo Bonzini VMSTATE_INT32(dz, HIDPointerEvent), 58649ab747fSPaolo Bonzini VMSTATE_INT32(buttons_state, HIDPointerEvent), 58749ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 58849ab747fSPaolo Bonzini } 58949ab747fSPaolo Bonzini }; 59049ab747fSPaolo Bonzini 59149ab747fSPaolo Bonzini const VMStateDescription vmstate_hid_ptr_device = { 59249ab747fSPaolo Bonzini .name = "HIDPointerDevice", 59349ab747fSPaolo Bonzini .version_id = 1, 59449ab747fSPaolo Bonzini .minimum_version_id = 1, 59549ab747fSPaolo Bonzini .post_load = hid_post_load, 59649ab747fSPaolo Bonzini .fields = (VMStateField[]) { 59749ab747fSPaolo Bonzini VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0, 59849ab747fSPaolo Bonzini vmstate_hid_ptr_queue, HIDPointerEvent), 59949ab747fSPaolo Bonzini VMSTATE_UINT32(head, HIDState), 60049ab747fSPaolo Bonzini VMSTATE_UINT32(n, HIDState), 60149ab747fSPaolo Bonzini VMSTATE_INT32(protocol, HIDState), 60249ab747fSPaolo Bonzini VMSTATE_UINT8(idle, HIDState), 60349ab747fSPaolo Bonzini VMSTATE_END_OF_LIST(), 60449ab747fSPaolo Bonzini } 60549ab747fSPaolo Bonzini }; 60649ab747fSPaolo Bonzini 60749ab747fSPaolo Bonzini const VMStateDescription vmstate_hid_keyboard_device = { 60849ab747fSPaolo Bonzini .name = "HIDKeyboardDevice", 60949ab747fSPaolo Bonzini .version_id = 1, 61049ab747fSPaolo Bonzini .minimum_version_id = 1, 61149ab747fSPaolo Bonzini .post_load = hid_post_load, 61249ab747fSPaolo Bonzini .fields = (VMStateField[]) { 61349ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH), 61449ab747fSPaolo Bonzini VMSTATE_UINT32(head, HIDState), 61549ab747fSPaolo Bonzini VMSTATE_UINT32(n, HIDState), 61649ab747fSPaolo Bonzini VMSTATE_UINT16(kbd.modifiers, HIDState), 61749ab747fSPaolo Bonzini VMSTATE_UINT8(kbd.leds, HIDState), 61849ab747fSPaolo Bonzini VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16), 61949ab747fSPaolo Bonzini VMSTATE_INT32(kbd.keys, HIDState), 62049ab747fSPaolo Bonzini VMSTATE_INT32(protocol, HIDState), 62149ab747fSPaolo Bonzini VMSTATE_UINT8(idle, HIDState), 62249ab747fSPaolo Bonzini VMSTATE_END_OF_LIST(), 62349ab747fSPaolo Bonzini } 62449ab747fSPaolo Bonzini }; 625