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 */ 2583c9f4caSPaolo Bonzini #include "hw/hw.h" 2628ecbaeeSPaolo Bonzini #include "ui/console.h" 271de7afc9SPaolo Bonzini #include "qemu/timer.h" 280d09e41aSPaolo Bonzini #include "hw/input/hid.h" 29dcfda673SGerd Hoffmann 30dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_ROLLOVER 0x01 31dcfda673SGerd Hoffmann #define HID_USAGE_POSTFAIL 0x02 32dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_UNDEFINED 0x03 33dcfda673SGerd Hoffmann 34dcfda673SGerd Hoffmann /* Indices are QEMU keycodes, values are from HID Usage Table. Indices 35dcfda673SGerd Hoffmann * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ 36dcfda673SGerd Hoffmann static const uint8_t hid_usage_keys[0x100] = { 37dcfda673SGerd Hoffmann 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 38dcfda673SGerd Hoffmann 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, 39dcfda673SGerd Hoffmann 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, 40dcfda673SGerd Hoffmann 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, 41dcfda673SGerd Hoffmann 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, 42dcfda673SGerd Hoffmann 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, 43dcfda673SGerd Hoffmann 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, 440ee4de58SDinar Valeev 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 45dcfda673SGerd Hoffmann 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, 46dcfda673SGerd Hoffmann 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, 47dcfda673SGerd Hoffmann 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, 48dcfda673SGerd Hoffmann 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 49dcfda673SGerd Hoffmann 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, 50dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 51dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 53dcfda673SGerd Hoffmann 54dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x58, 0xe4, 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, 0x00, 0x54, 0x00, 0x46, 61dcfda673SGerd Hoffmann 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 62dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, 63dcfda673SGerd Hoffmann 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, 64dcfda673SGerd Hoffmann 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, 65dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00, 66dcfda673SGerd Hoffmann 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 }; 71dcfda673SGerd Hoffmann 72dcfda673SGerd Hoffmann bool hid_has_events(HIDState *hs) 73dcfda673SGerd Hoffmann { 74027c03f7SHans de Goede return hs->n > 0 || hs->idle_pending; 75dcfda673SGerd Hoffmann } 76dcfda673SGerd Hoffmann 77027c03f7SHans de Goede static void hid_idle_timer(void *opaque) 78b069d348SGerd Hoffmann { 79027c03f7SHans de Goede HIDState *hs = opaque; 80027c03f7SHans de Goede 81027c03f7SHans de Goede hs->idle_pending = true; 82027c03f7SHans de Goede hs->event(hs); 83027c03f7SHans de Goede } 84027c03f7SHans de Goede 85027c03f7SHans de Goede static void hid_del_idle_timer(HIDState *hs) 86027c03f7SHans de Goede { 87027c03f7SHans de Goede if (hs->idle_timer) { 88bc72ad67SAlex Bligh timer_del(hs->idle_timer); 89bc72ad67SAlex Bligh timer_free(hs->idle_timer); 90027c03f7SHans de Goede hs->idle_timer = NULL; 91027c03f7SHans de Goede } 92027c03f7SHans de Goede } 93027c03f7SHans de Goede 94027c03f7SHans de Goede void hid_set_next_idle(HIDState *hs) 95027c03f7SHans de Goede { 96027c03f7SHans de Goede if (hs->idle) { 97bc72ad67SAlex Bligh uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 98027c03f7SHans de Goede get_ticks_per_sec() * hs->idle * 4 / 1000; 99027c03f7SHans de Goede if (!hs->idle_timer) { 100bc72ad67SAlex Bligh hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs); 101027c03f7SHans de Goede } 102bc72ad67SAlex Bligh timer_mod_ns(hs->idle_timer, expire_time); 103027c03f7SHans de Goede } else { 104027c03f7SHans de Goede hid_del_idle_timer(hs); 105027c03f7SHans de Goede } 106b069d348SGerd Hoffmann } 107b069d348SGerd Hoffmann 1088b84286fSGerd Hoffmann static void hid_pointer_event(DeviceState *dev, QemuConsole *src, 1098b84286fSGerd Hoffmann InputEvent *evt) 110dcfda673SGerd Hoffmann { 1118b84286fSGerd Hoffmann static const int bmap[INPUT_BUTTON_MAX] = { 1128b84286fSGerd Hoffmann [INPUT_BUTTON_LEFT] = 0x01, 1138b84286fSGerd Hoffmann [INPUT_BUTTON_RIGHT] = 0x02, 1148b84286fSGerd Hoffmann [INPUT_BUTTON_MIDDLE] = 0x04, 1158b84286fSGerd Hoffmann }; 1168b84286fSGerd Hoffmann HIDState *hs = (HIDState *)dev; 1178b84286fSGerd Hoffmann HIDPointerEvent *e; 118dcfda673SGerd Hoffmann 1198b84286fSGerd Hoffmann assert(hs->n < QUEUE_LENGTH); 1208b84286fSGerd Hoffmann e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; 1218b84286fSGerd Hoffmann 122*568c73a4SEric Blake switch (evt->type) { 1238b84286fSGerd Hoffmann case INPUT_EVENT_KIND_REL: 124*568c73a4SEric Blake if (evt->u.rel->axis == INPUT_AXIS_X) { 125*568c73a4SEric Blake e->xdx += evt->u.rel->value; 126*568c73a4SEric Blake } else if (evt->u.rel->axis == INPUT_AXIS_Y) { 127*568c73a4SEric Blake e->ydy += evt->u.rel->value; 1288b84286fSGerd Hoffmann } 1298b84286fSGerd Hoffmann break; 1308b84286fSGerd Hoffmann 1318b84286fSGerd Hoffmann case INPUT_EVENT_KIND_ABS: 132*568c73a4SEric Blake if (evt->u.rel->axis == INPUT_AXIS_X) { 133*568c73a4SEric Blake e->xdx = evt->u.rel->value; 134*568c73a4SEric Blake } else if (evt->u.rel->axis == INPUT_AXIS_Y) { 135*568c73a4SEric Blake e->ydy = evt->u.rel->value; 1368b84286fSGerd Hoffmann } 1378b84286fSGerd Hoffmann break; 1388b84286fSGerd Hoffmann 1398b84286fSGerd Hoffmann case INPUT_EVENT_KIND_BTN: 140*568c73a4SEric Blake if (evt->u.btn->down) { 141*568c73a4SEric Blake e->buttons_state |= bmap[evt->u.btn->button]; 142*568c73a4SEric Blake if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) { 1438b84286fSGerd Hoffmann e->dz--; 144*568c73a4SEric Blake } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) { 1458b84286fSGerd Hoffmann e->dz++; 1468b84286fSGerd Hoffmann } 147dcfda673SGerd Hoffmann } else { 148*568c73a4SEric Blake e->buttons_state &= ~bmap[evt->u.btn->button]; 149dcfda673SGerd Hoffmann } 1508b84286fSGerd Hoffmann break; 1518b84286fSGerd Hoffmann 1528b84286fSGerd Hoffmann default: 1538b84286fSGerd Hoffmann /* keep gcc happy */ 1548b84286fSGerd Hoffmann break; 155dcfda673SGerd Hoffmann } 156dcfda673SGerd Hoffmann 1578b84286fSGerd Hoffmann } 1588b84286fSGerd Hoffmann 1598b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev) 160dcfda673SGerd Hoffmann { 1618b84286fSGerd Hoffmann HIDState *hs = (HIDState *)dev; 1628b84286fSGerd Hoffmann HIDPointerEvent *prev, *curr, *next; 1638b84286fSGerd Hoffmann bool event_compression = false; 164dcfda673SGerd Hoffmann 1658b84286fSGerd Hoffmann if (hs->n == QUEUE_LENGTH-1) { 1668b84286fSGerd Hoffmann /* 1675d831be2SStefan Weil * Queue full. We are losing information, but we at least 1688b84286fSGerd Hoffmann * keep track of most recent button state. 1698b84286fSGerd Hoffmann */ 1708b84286fSGerd Hoffmann return; 171dcfda673SGerd Hoffmann } 1728b84286fSGerd Hoffmann 1738b84286fSGerd Hoffmann prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK]; 1748b84286fSGerd Hoffmann curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; 1758b84286fSGerd Hoffmann next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK]; 1768b84286fSGerd Hoffmann 1778b84286fSGerd Hoffmann if (hs->n > 0) { 1788b84286fSGerd Hoffmann /* 1798b84286fSGerd Hoffmann * No button state change between previous and current event 1808b84286fSGerd Hoffmann * (and previous wasn't seen by the guest yet), so there is 1818b84286fSGerd Hoffmann * motion information only and we can combine the two event 1828b84286fSGerd Hoffmann * into one. 1838b84286fSGerd Hoffmann */ 1848b84286fSGerd Hoffmann if (curr->buttons_state == prev->buttons_state) { 1858b84286fSGerd Hoffmann event_compression = true; 1868b84286fSGerd Hoffmann } 1878b84286fSGerd Hoffmann } 1888b84286fSGerd Hoffmann 1898b84286fSGerd Hoffmann if (event_compression) { 1908b84286fSGerd Hoffmann /* add current motion to previous, clear current */ 1918b84286fSGerd Hoffmann if (hs->kind == HID_MOUSE) { 1928b84286fSGerd Hoffmann prev->xdx += curr->xdx; 1938b84286fSGerd Hoffmann curr->xdx = 0; 19435e83d10SChristian Burger prev->ydy += curr->ydy; 1958b84286fSGerd Hoffmann curr->ydy = 0; 1968b84286fSGerd Hoffmann } else { 1978b84286fSGerd Hoffmann prev->xdx = curr->xdx; 1988b84286fSGerd Hoffmann prev->ydy = curr->ydy; 1998b84286fSGerd Hoffmann } 2008b84286fSGerd Hoffmann prev->dz += curr->dz; 2018b84286fSGerd Hoffmann curr->dz = 0; 2028b84286fSGerd Hoffmann } else { 2038b84286fSGerd Hoffmann /* prepate next (clear rel, copy abs + btns) */ 2048b84286fSGerd Hoffmann if (hs->kind == HID_MOUSE) { 2058b84286fSGerd Hoffmann next->xdx = 0; 2068b84286fSGerd Hoffmann next->ydy = 0; 2078b84286fSGerd Hoffmann } else { 2088b84286fSGerd Hoffmann next->xdx = curr->xdx; 2098b84286fSGerd Hoffmann next->ydy = curr->ydy; 2108b84286fSGerd Hoffmann } 2118b84286fSGerd Hoffmann next->dz = 0; 2128b84286fSGerd Hoffmann next->buttons_state = curr->buttons_state; 2138b84286fSGerd Hoffmann /* make current guest visible, notify guest */ 2148b84286fSGerd Hoffmann hs->n++; 215dcfda673SGerd Hoffmann hs->event(hs); 216dcfda673SGerd Hoffmann } 2178b84286fSGerd Hoffmann } 218dcfda673SGerd Hoffmann 2191ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, 2201ff5eeddSGerd Hoffmann InputEvent *evt) 221dcfda673SGerd Hoffmann { 2221ff5eeddSGerd Hoffmann HIDState *hs = (HIDState *)dev; 2231ff5eeddSGerd Hoffmann int scancodes[3], i, count; 224dcfda673SGerd Hoffmann int slot; 225dcfda673SGerd Hoffmann 226*568c73a4SEric Blake count = qemu_input_key_value_to_scancode(evt->u.key->key, 227*568c73a4SEric Blake evt->u.key->down, 2281ff5eeddSGerd Hoffmann scancodes); 2291ff5eeddSGerd Hoffmann if (hs->n + count > QUEUE_LENGTH) { 230dcfda673SGerd Hoffmann fprintf(stderr, "usb-kbd: warning: key event queue full\n"); 231dcfda673SGerd Hoffmann return; 232dcfda673SGerd Hoffmann } 2331ff5eeddSGerd Hoffmann for (i = 0; i < count; i++) { 234dcfda673SGerd Hoffmann slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; 2351ff5eeddSGerd Hoffmann hs->kbd.keycodes[slot] = scancodes[i]; 2361ff5eeddSGerd Hoffmann } 237dcfda673SGerd Hoffmann hs->event(hs); 238dcfda673SGerd Hoffmann } 239dcfda673SGerd Hoffmann 240dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs) 241dcfda673SGerd Hoffmann { 242562f9375SPaolo Bonzini uint8_t hid_code, index, key; 243dcfda673SGerd Hoffmann int i, keycode, slot; 244dcfda673SGerd Hoffmann 245dcfda673SGerd Hoffmann if (hs->n == 0) { 246dcfda673SGerd Hoffmann return; 247dcfda673SGerd Hoffmann } 248dcfda673SGerd Hoffmann slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; 249dcfda673SGerd Hoffmann keycode = hs->kbd.keycodes[slot]; 250dcfda673SGerd Hoffmann 251dcfda673SGerd Hoffmann key = keycode & 0x7f; 252562f9375SPaolo Bonzini index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1); 253562f9375SPaolo Bonzini hid_code = hid_usage_keys[index]; 254dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << 8); 255dcfda673SGerd Hoffmann 256dcfda673SGerd Hoffmann switch (hid_code) { 257dcfda673SGerd Hoffmann case 0x00: 258dcfda673SGerd Hoffmann return; 259dcfda673SGerd Hoffmann 260dcfda673SGerd Hoffmann case 0xe0: 261562f9375SPaolo Bonzini assert(key == 0x1d); 262dcfda673SGerd Hoffmann if (hs->kbd.modifiers & (1 << 9)) { 263562f9375SPaolo Bonzini /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0. 264562f9375SPaolo Bonzini * Here we're processing the second hid_code. By dropping bit 9 265562f9375SPaolo Bonzini * and setting bit 8, the scancode after 0x1d will access the 266562f9375SPaolo Bonzini * second half of the table. 267562f9375SPaolo Bonzini */ 268562f9375SPaolo Bonzini hs->kbd.modifiers ^= (1 << 8) | (1 << 9); 269dcfda673SGerd Hoffmann return; 270dcfda673SGerd Hoffmann } 271562f9375SPaolo Bonzini /* fall through to process Ctrl_L */ 272dcfda673SGerd Hoffmann case 0xe1 ... 0xe7: 273562f9375SPaolo Bonzini /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R. 274562f9375SPaolo Bonzini * Handle releases here, or fall through to process presses. 275562f9375SPaolo Bonzini */ 276dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 277dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); 278dcfda673SGerd Hoffmann return; 279dcfda673SGerd Hoffmann } 280562f9375SPaolo Bonzini /* fall through */ 281562f9375SPaolo Bonzini case 0xe8 ... 0xe9: 282562f9375SPaolo Bonzini /* USB modifiers are just 1 byte long. Bits 8 and 9 of 283562f9375SPaolo Bonzini * hs->kbd.modifiers implement a state machine that detects the 284562f9375SPaolo Bonzini * 0xe0 and 0xe1/0x1d sequences. These bits do not follow the 285562f9375SPaolo Bonzini * usual rules where bit 7 marks released keys; they are cleared 286562f9375SPaolo Bonzini * elsewhere in the function as the state machine dictates. 287562f9375SPaolo Bonzini */ 288dcfda673SGerd Hoffmann hs->kbd.modifiers |= 1 << (hid_code & 0x0f); 289dcfda673SGerd Hoffmann return; 290562f9375SPaolo Bonzini 291562f9375SPaolo Bonzini case 0xea ... 0xef: 292562f9375SPaolo Bonzini abort(); 293562f9375SPaolo Bonzini 294562f9375SPaolo Bonzini default: 295562f9375SPaolo Bonzini break; 296dcfda673SGerd Hoffmann } 297dcfda673SGerd Hoffmann 298dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 299dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 300dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 301dcfda673SGerd Hoffmann hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; 302dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys] = 0x00; 303dcfda673SGerd Hoffmann break; 304dcfda673SGerd Hoffmann } 305dcfda673SGerd Hoffmann } 306dcfda673SGerd Hoffmann if (i < 0) { 307dcfda673SGerd Hoffmann return; 308dcfda673SGerd Hoffmann } 309dcfda673SGerd Hoffmann } else { 310dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 311dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 312dcfda673SGerd Hoffmann break; 313dcfda673SGerd Hoffmann } 314dcfda673SGerd Hoffmann } 315dcfda673SGerd Hoffmann if (i < 0) { 316dcfda673SGerd Hoffmann if (hs->kbd.keys < sizeof(hs->kbd.key)) { 317dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys++] = hid_code; 318dcfda673SGerd Hoffmann } 319dcfda673SGerd Hoffmann } else { 320dcfda673SGerd Hoffmann return; 321dcfda673SGerd Hoffmann } 322dcfda673SGerd Hoffmann } 323dcfda673SGerd Hoffmann } 324dcfda673SGerd Hoffmann 325dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax) 326dcfda673SGerd Hoffmann { 327dcfda673SGerd Hoffmann if (val < vmin) { 328dcfda673SGerd Hoffmann return vmin; 329dcfda673SGerd Hoffmann } else if (val > vmax) { 330dcfda673SGerd Hoffmann return vmax; 331dcfda673SGerd Hoffmann } else { 332dcfda673SGerd Hoffmann return val; 333dcfda673SGerd Hoffmann } 334dcfda673SGerd Hoffmann } 335dcfda673SGerd Hoffmann 33621635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs) 33721635e12SGerd Hoffmann { 33821635e12SGerd Hoffmann if (!hs->ptr.mouse_grabbed) { 3398b84286fSGerd Hoffmann qemu_input_handler_activate(hs->s); 34021635e12SGerd Hoffmann hs->ptr.mouse_grabbed = 1; 34121635e12SGerd Hoffmann } 34221635e12SGerd Hoffmann } 34321635e12SGerd Hoffmann 344dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) 345dcfda673SGerd Hoffmann { 3468b84286fSGerd Hoffmann int dx, dy, dz, l; 347dcfda673SGerd Hoffmann int index; 348dcfda673SGerd Hoffmann HIDPointerEvent *e; 349dcfda673SGerd Hoffmann 350027c03f7SHans de Goede hs->idle_pending = false; 351027c03f7SHans de Goede 35221635e12SGerd Hoffmann hid_pointer_activate(hs); 353dcfda673SGerd Hoffmann 354dcfda673SGerd Hoffmann /* When the buffer is empty, return the last event. Relative 355dcfda673SGerd Hoffmann movements will all be zero. */ 356dcfda673SGerd Hoffmann index = (hs->n ? hs->head : hs->head - 1); 357dcfda673SGerd Hoffmann e = &hs->ptr.queue[index & QUEUE_MASK]; 358dcfda673SGerd Hoffmann 359dcfda673SGerd Hoffmann if (hs->kind == HID_MOUSE) { 360dcfda673SGerd Hoffmann dx = int_clamp(e->xdx, -127, 127); 361dcfda673SGerd Hoffmann dy = int_clamp(e->ydy, -127, 127); 362dcfda673SGerd Hoffmann e->xdx -= dx; 363dcfda673SGerd Hoffmann e->ydy -= dy; 364dcfda673SGerd Hoffmann } else { 365dcfda673SGerd Hoffmann dx = e->xdx; 366dcfda673SGerd Hoffmann dy = e->ydy; 367dcfda673SGerd Hoffmann } 368dcfda673SGerd Hoffmann dz = int_clamp(e->dz, -127, 127); 369dcfda673SGerd Hoffmann e->dz -= dz; 370dcfda673SGerd Hoffmann 371dcfda673SGerd Hoffmann if (hs->n && 372dcfda673SGerd Hoffmann !e->dz && 373dcfda673SGerd Hoffmann (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { 374dcfda673SGerd Hoffmann /* that deals with this event */ 375dcfda673SGerd Hoffmann QUEUE_INCR(hs->head); 376dcfda673SGerd Hoffmann hs->n--; 377dcfda673SGerd Hoffmann } 378dcfda673SGerd Hoffmann 379dcfda673SGerd Hoffmann /* Appears we have to invert the wheel direction */ 380dcfda673SGerd Hoffmann dz = 0 - dz; 381dcfda673SGerd Hoffmann l = 0; 382dcfda673SGerd Hoffmann switch (hs->kind) { 383dcfda673SGerd Hoffmann case HID_MOUSE: 384dcfda673SGerd Hoffmann if (len > l) { 3858b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 386dcfda673SGerd Hoffmann } 387dcfda673SGerd Hoffmann if (len > l) { 388dcfda673SGerd Hoffmann buf[l++] = dx; 389dcfda673SGerd Hoffmann } 390dcfda673SGerd Hoffmann if (len > l) { 391dcfda673SGerd Hoffmann buf[l++] = dy; 392dcfda673SGerd Hoffmann } 393dcfda673SGerd Hoffmann if (len > l) { 394dcfda673SGerd Hoffmann buf[l++] = dz; 395dcfda673SGerd Hoffmann } 396dcfda673SGerd Hoffmann break; 397dcfda673SGerd Hoffmann 398dcfda673SGerd Hoffmann case HID_TABLET: 399dcfda673SGerd Hoffmann if (len > l) { 4008b84286fSGerd Hoffmann buf[l++] = e->buttons_state; 401dcfda673SGerd Hoffmann } 402dcfda673SGerd Hoffmann if (len > l) { 403dcfda673SGerd Hoffmann buf[l++] = dx & 0xff; 404dcfda673SGerd Hoffmann } 405dcfda673SGerd Hoffmann if (len > l) { 406dcfda673SGerd Hoffmann buf[l++] = dx >> 8; 407dcfda673SGerd Hoffmann } 408dcfda673SGerd Hoffmann if (len > l) { 409dcfda673SGerd Hoffmann buf[l++] = dy & 0xff; 410dcfda673SGerd Hoffmann } 411dcfda673SGerd Hoffmann if (len > l) { 412dcfda673SGerd Hoffmann buf[l++] = dy >> 8; 413dcfda673SGerd Hoffmann } 414dcfda673SGerd Hoffmann if (len > l) { 415dcfda673SGerd Hoffmann buf[l++] = dz; 416dcfda673SGerd Hoffmann } 417dcfda673SGerd Hoffmann break; 418dcfda673SGerd Hoffmann 419dcfda673SGerd Hoffmann default: 420dcfda673SGerd Hoffmann abort(); 421dcfda673SGerd Hoffmann } 422dcfda673SGerd Hoffmann 423dcfda673SGerd Hoffmann return l; 424dcfda673SGerd Hoffmann } 425dcfda673SGerd Hoffmann 426dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) 427dcfda673SGerd Hoffmann { 428027c03f7SHans de Goede hs->idle_pending = false; 429027c03f7SHans de Goede 430dcfda673SGerd Hoffmann if (len < 2) { 431dcfda673SGerd Hoffmann return 0; 432dcfda673SGerd Hoffmann } 433dcfda673SGerd Hoffmann 434dcfda673SGerd Hoffmann hid_keyboard_process_keycode(hs); 435dcfda673SGerd Hoffmann 436dcfda673SGerd Hoffmann buf[0] = hs->kbd.modifiers & 0xff; 437dcfda673SGerd Hoffmann buf[1] = 0; 438dcfda673SGerd Hoffmann if (hs->kbd.keys > 6) { 439dcfda673SGerd Hoffmann memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); 440dcfda673SGerd Hoffmann } else { 441dcfda673SGerd Hoffmann memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); 442dcfda673SGerd Hoffmann } 443dcfda673SGerd Hoffmann 444dcfda673SGerd Hoffmann return MIN(8, len); 445dcfda673SGerd Hoffmann } 446dcfda673SGerd Hoffmann 447dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) 448dcfda673SGerd Hoffmann { 449dcfda673SGerd Hoffmann if (len > 0) { 450dcfda673SGerd Hoffmann int ledstate = 0; 451dcfda673SGerd Hoffmann /* 0x01: Num Lock LED 452dcfda673SGerd Hoffmann * 0x02: Caps Lock LED 453dcfda673SGerd Hoffmann * 0x04: Scroll Lock LED 454dcfda673SGerd Hoffmann * 0x08: Compose LED 455dcfda673SGerd Hoffmann * 0x10: Kana LED */ 456dcfda673SGerd Hoffmann hs->kbd.leds = buf[0]; 457dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x04) { 458dcfda673SGerd Hoffmann ledstate |= QEMU_SCROLL_LOCK_LED; 459dcfda673SGerd Hoffmann } 460dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x01) { 461dcfda673SGerd Hoffmann ledstate |= QEMU_NUM_LOCK_LED; 462dcfda673SGerd Hoffmann } 463dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x02) { 464dcfda673SGerd Hoffmann ledstate |= QEMU_CAPS_LOCK_LED; 465dcfda673SGerd Hoffmann } 466dcfda673SGerd Hoffmann kbd_put_ledstate(ledstate); 467dcfda673SGerd Hoffmann } 468dcfda673SGerd Hoffmann return 0; 469dcfda673SGerd Hoffmann } 470dcfda673SGerd Hoffmann 471dcfda673SGerd Hoffmann void hid_reset(HIDState *hs) 472dcfda673SGerd Hoffmann { 473dcfda673SGerd Hoffmann switch (hs->kind) { 474dcfda673SGerd Hoffmann case HID_KEYBOARD: 475dcfda673SGerd Hoffmann memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); 476dcfda673SGerd Hoffmann memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); 477dcfda673SGerd Hoffmann hs->kbd.keys = 0; 478dcfda673SGerd Hoffmann break; 479dcfda673SGerd Hoffmann case HID_MOUSE: 480dcfda673SGerd Hoffmann case HID_TABLET: 481dcfda673SGerd Hoffmann memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); 482dcfda673SGerd Hoffmann break; 483dcfda673SGerd Hoffmann } 484dcfda673SGerd Hoffmann hs->head = 0; 485dcfda673SGerd Hoffmann hs->n = 0; 486b069d348SGerd Hoffmann hs->protocol = 1; 487b069d348SGerd Hoffmann hs->idle = 0; 488027c03f7SHans de Goede hs->idle_pending = false; 489027c03f7SHans de Goede hid_del_idle_timer(hs); 490dcfda673SGerd Hoffmann } 491dcfda673SGerd Hoffmann 492dcfda673SGerd Hoffmann void hid_free(HIDState *hs) 493dcfda673SGerd Hoffmann { 4941ff5eeddSGerd Hoffmann qemu_input_handler_unregister(hs->s); 495027c03f7SHans de Goede hid_del_idle_timer(hs); 496dcfda673SGerd Hoffmann } 497dcfda673SGerd Hoffmann 4981ff5eeddSGerd Hoffmann static QemuInputHandler hid_keyboard_handler = { 4991ff5eeddSGerd Hoffmann .name = "QEMU HID Keyboard", 5001ff5eeddSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 5011ff5eeddSGerd Hoffmann .event = hid_keyboard_event, 5021ff5eeddSGerd Hoffmann }; 5031ff5eeddSGerd Hoffmann 5048b84286fSGerd Hoffmann static QemuInputHandler hid_mouse_handler = { 5058b84286fSGerd Hoffmann .name = "QEMU HID Mouse", 5068b84286fSGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 5078b84286fSGerd Hoffmann .event = hid_pointer_event, 5088b84286fSGerd Hoffmann .sync = hid_pointer_sync, 5098b84286fSGerd Hoffmann }; 5108b84286fSGerd Hoffmann 5118b84286fSGerd Hoffmann static QemuInputHandler hid_tablet_handler = { 5128b84286fSGerd Hoffmann .name = "QEMU HID Tablet", 5138b84286fSGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, 5148b84286fSGerd Hoffmann .event = hid_pointer_event, 5158b84286fSGerd Hoffmann .sync = hid_pointer_sync, 5168b84286fSGerd Hoffmann }; 5178b84286fSGerd Hoffmann 518dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event) 519dcfda673SGerd Hoffmann { 520dcfda673SGerd Hoffmann hs->kind = kind; 521dcfda673SGerd Hoffmann hs->event = event; 522dcfda673SGerd Hoffmann 523bb0db527SMichael Walle if (hs->kind == HID_KEYBOARD) { 5241ff5eeddSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5251ff5eeddSGerd Hoffmann &hid_keyboard_handler); 5261ff5eeddSGerd Hoffmann qemu_input_handler_activate(hs->s); 527bb0db527SMichael Walle } else if (hs->kind == HID_MOUSE) { 5288b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5298b84286fSGerd Hoffmann &hid_mouse_handler); 530dcfda673SGerd Hoffmann } else if (hs->kind == HID_TABLET) { 5318b84286fSGerd Hoffmann hs->s = qemu_input_handler_register((DeviceState *)hs, 5328b84286fSGerd Hoffmann &hid_tablet_handler); 533dcfda673SGerd Hoffmann } 534dcfda673SGerd Hoffmann } 535ccd4ed06SMichael Walle 536ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id) 537ccd4ed06SMichael Walle { 538ccd4ed06SMichael Walle HIDState *s = opaque; 539ccd4ed06SMichael Walle 540027c03f7SHans de Goede hid_set_next_idle(s); 541ba4d2606SGerd Hoffmann 542ba4d2606SGerd Hoffmann if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET || 543ba4d2606SGerd Hoffmann s->kind == HID_MOUSE)) { 544ba4d2606SGerd Hoffmann /* 545ba4d2606SGerd Hoffmann * Handle ptr device migration from old qemu with full queue. 546ba4d2606SGerd Hoffmann * 547ba4d2606SGerd Hoffmann * Throw away everything but the last event, so we propagate 548ba4d2606SGerd Hoffmann * at least the current button state to the guest. Also keep 549ba4d2606SGerd Hoffmann * current position for the tablet, signal "no motion" for the 550ba4d2606SGerd Hoffmann * mouse. 551ba4d2606SGerd Hoffmann */ 552ba4d2606SGerd Hoffmann HIDPointerEvent evt; 553ba4d2606SGerd Hoffmann evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK]; 554ba4d2606SGerd Hoffmann if (s->kind == HID_MOUSE) { 555ba4d2606SGerd Hoffmann evt.xdx = 0; 556ba4d2606SGerd Hoffmann evt.ydy = 0; 557ba4d2606SGerd Hoffmann } 558ba4d2606SGerd Hoffmann s->ptr.queue[0] = evt; 559ba4d2606SGerd Hoffmann s->head = 0; 560ba4d2606SGerd Hoffmann s->n = 1; 561ba4d2606SGerd Hoffmann } 562ccd4ed06SMichael Walle return 0; 563ccd4ed06SMichael Walle } 564ccd4ed06SMichael Walle 565ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = { 566ccd4ed06SMichael Walle .name = "HIDPointerEventQueue", 567ccd4ed06SMichael Walle .version_id = 1, 568ccd4ed06SMichael Walle .minimum_version_id = 1, 569ccd4ed06SMichael Walle .fields = (VMStateField[]) { 570ccd4ed06SMichael Walle VMSTATE_INT32(xdx, HIDPointerEvent), 571ccd4ed06SMichael Walle VMSTATE_INT32(ydy, HIDPointerEvent), 572ccd4ed06SMichael Walle VMSTATE_INT32(dz, HIDPointerEvent), 573ccd4ed06SMichael Walle VMSTATE_INT32(buttons_state, HIDPointerEvent), 574ccd4ed06SMichael Walle VMSTATE_END_OF_LIST() 575ccd4ed06SMichael Walle } 576ccd4ed06SMichael Walle }; 577ccd4ed06SMichael Walle 578ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = { 579ccd4ed06SMichael Walle .name = "HIDPointerDevice", 580ccd4ed06SMichael Walle .version_id = 1, 581ccd4ed06SMichael Walle .minimum_version_id = 1, 582ccd4ed06SMichael Walle .post_load = hid_post_load, 583ccd4ed06SMichael Walle .fields = (VMStateField[]) { 584ccd4ed06SMichael Walle VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0, 585ccd4ed06SMichael Walle vmstate_hid_ptr_queue, HIDPointerEvent), 586ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 587ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 588ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 589ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 590ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 591ccd4ed06SMichael Walle } 592ccd4ed06SMichael Walle }; 593ccd4ed06SMichael Walle 594ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = { 595ccd4ed06SMichael Walle .name = "HIDKeyboardDevice", 596ccd4ed06SMichael Walle .version_id = 1, 597ccd4ed06SMichael Walle .minimum_version_id = 1, 598ccd4ed06SMichael Walle .post_load = hid_post_load, 599ccd4ed06SMichael Walle .fields = (VMStateField[]) { 600ccd4ed06SMichael Walle VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH), 601ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 602ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 603ccd4ed06SMichael Walle VMSTATE_UINT16(kbd.modifiers, HIDState), 604ccd4ed06SMichael Walle VMSTATE_UINT8(kbd.leds, HIDState), 605ccd4ed06SMichael Walle VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16), 606ccd4ed06SMichael Walle VMSTATE_INT32(kbd.keys, HIDState), 607ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 608ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 609ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 610ccd4ed06SMichael Walle } 611ccd4ed06SMichael Walle }; 612