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, 44dcfda673SGerd Hoffmann 0xe2, 0x2c, 0x32, 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) { 88*bc72ad67SAlex Bligh timer_del(hs->idle_timer); 89*bc72ad67SAlex 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) { 97*bc72ad67SAlex 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) { 100*bc72ad67SAlex Bligh hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs); 101027c03f7SHans de Goede } 102*bc72ad67SAlex 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 108dcfda673SGerd Hoffmann static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) 109dcfda673SGerd Hoffmann { 110dcfda673SGerd Hoffmann e->xdx = e->ydy = e->dz = 0; 111dcfda673SGerd Hoffmann e->buttons_state = buttons; 112dcfda673SGerd Hoffmann } 113dcfda673SGerd Hoffmann 114dcfda673SGerd Hoffmann static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, 115dcfda673SGerd Hoffmann int x1, int y1, int z1) { 116dcfda673SGerd Hoffmann if (xyrel) { 117dcfda673SGerd Hoffmann e->xdx += x1; 118dcfda673SGerd Hoffmann e->ydy += y1; 119dcfda673SGerd Hoffmann } else { 120dcfda673SGerd Hoffmann e->xdx = x1; 121dcfda673SGerd Hoffmann e->ydy = y1; 122dcfda673SGerd Hoffmann /* Windows drivers do not like the 0/0 position and ignore such 123dcfda673SGerd Hoffmann * events. */ 124dcfda673SGerd Hoffmann if (!(x1 | y1)) { 12518f88f11SBlue Swirl e->xdx = 1; 126dcfda673SGerd Hoffmann } 127dcfda673SGerd Hoffmann } 128dcfda673SGerd Hoffmann e->dz += z1; 129dcfda673SGerd Hoffmann } 130dcfda673SGerd Hoffmann 131dcfda673SGerd Hoffmann static void hid_pointer_event(void *opaque, 132dcfda673SGerd Hoffmann int x1, int y1, int z1, int buttons_state) 133dcfda673SGerd Hoffmann { 134dcfda673SGerd Hoffmann HIDState *hs = opaque; 135dcfda673SGerd Hoffmann unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; 136dcfda673SGerd Hoffmann unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; 137dcfda673SGerd Hoffmann 138dcfda673SGerd Hoffmann /* We combine events where feasible to keep the queue small. We shouldn't 139dcfda673SGerd Hoffmann * combine anything with the first event of a particular button state, as 140dcfda673SGerd Hoffmann * that would change the location of the button state change. When the 141dcfda673SGerd Hoffmann * queue is empty, a second event is needed because we don't know if 142dcfda673SGerd Hoffmann * the first event changed the button state. */ 143dcfda673SGerd Hoffmann if (hs->n == QUEUE_LENGTH) { 144dcfda673SGerd Hoffmann /* Queue full. Discard old button state, combine motion normally. */ 145dcfda673SGerd Hoffmann hs->ptr.queue[use_slot].buttons_state = buttons_state; 146dcfda673SGerd Hoffmann } else if (hs->n < 2 || 147dcfda673SGerd Hoffmann hs->ptr.queue[use_slot].buttons_state != buttons_state || 148dcfda673SGerd Hoffmann hs->ptr.queue[previous_slot].buttons_state != 149dcfda673SGerd Hoffmann hs->ptr.queue[use_slot].buttons_state) { 150dcfda673SGerd Hoffmann /* Cannot or should not combine, so add an empty item to the queue. */ 151dcfda673SGerd Hoffmann QUEUE_INCR(use_slot); 152dcfda673SGerd Hoffmann hs->n++; 153dcfda673SGerd Hoffmann hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); 154dcfda673SGerd Hoffmann } 155dcfda673SGerd Hoffmann hid_pointer_event_combine(&hs->ptr.queue[use_slot], 156dcfda673SGerd Hoffmann hs->kind == HID_MOUSE, 157dcfda673SGerd Hoffmann x1, y1, z1); 158dcfda673SGerd Hoffmann hs->event(hs); 159dcfda673SGerd Hoffmann } 160dcfda673SGerd Hoffmann 161dcfda673SGerd Hoffmann static void hid_keyboard_event(void *opaque, int keycode) 162dcfda673SGerd Hoffmann { 163dcfda673SGerd Hoffmann HIDState *hs = opaque; 164dcfda673SGerd Hoffmann int slot; 165dcfda673SGerd Hoffmann 166dcfda673SGerd Hoffmann if (hs->n == QUEUE_LENGTH) { 167dcfda673SGerd Hoffmann fprintf(stderr, "usb-kbd: warning: key event queue full\n"); 168dcfda673SGerd Hoffmann return; 169dcfda673SGerd Hoffmann } 170dcfda673SGerd Hoffmann slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; 171dcfda673SGerd Hoffmann hs->kbd.keycodes[slot] = keycode; 172dcfda673SGerd Hoffmann hs->event(hs); 173dcfda673SGerd Hoffmann } 174dcfda673SGerd Hoffmann 175dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs) 176dcfda673SGerd Hoffmann { 177dcfda673SGerd Hoffmann uint8_t hid_code, key; 178dcfda673SGerd Hoffmann int i, keycode, slot; 179dcfda673SGerd Hoffmann 180dcfda673SGerd Hoffmann if (hs->n == 0) { 181dcfda673SGerd Hoffmann return; 182dcfda673SGerd Hoffmann } 183dcfda673SGerd Hoffmann slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--; 184dcfda673SGerd Hoffmann keycode = hs->kbd.keycodes[slot]; 185dcfda673SGerd Hoffmann 186dcfda673SGerd Hoffmann key = keycode & 0x7f; 187dcfda673SGerd Hoffmann hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))]; 188dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << 8); 189dcfda673SGerd Hoffmann 190dcfda673SGerd Hoffmann switch (hid_code) { 191dcfda673SGerd Hoffmann case 0x00: 192dcfda673SGerd Hoffmann return; 193dcfda673SGerd Hoffmann 194dcfda673SGerd Hoffmann case 0xe0: 195dcfda673SGerd Hoffmann if (hs->kbd.modifiers & (1 << 9)) { 196dcfda673SGerd Hoffmann hs->kbd.modifiers ^= 3 << 8; 197dcfda673SGerd Hoffmann return; 198dcfda673SGerd Hoffmann } 199dcfda673SGerd Hoffmann case 0xe1 ... 0xe7: 200dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 201dcfda673SGerd Hoffmann hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f)); 202dcfda673SGerd Hoffmann return; 203dcfda673SGerd Hoffmann } 204dcfda673SGerd Hoffmann case 0xe8 ... 0xef: 205dcfda673SGerd Hoffmann hs->kbd.modifiers |= 1 << (hid_code & 0x0f); 206dcfda673SGerd Hoffmann return; 207dcfda673SGerd Hoffmann } 208dcfda673SGerd Hoffmann 209dcfda673SGerd Hoffmann if (keycode & (1 << 7)) { 210dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 211dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 212dcfda673SGerd Hoffmann hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys]; 213dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys] = 0x00; 214dcfda673SGerd Hoffmann break; 215dcfda673SGerd Hoffmann } 216dcfda673SGerd Hoffmann } 217dcfda673SGerd Hoffmann if (i < 0) { 218dcfda673SGerd Hoffmann return; 219dcfda673SGerd Hoffmann } 220dcfda673SGerd Hoffmann } else { 221dcfda673SGerd Hoffmann for (i = hs->kbd.keys - 1; i >= 0; i--) { 222dcfda673SGerd Hoffmann if (hs->kbd.key[i] == hid_code) { 223dcfda673SGerd Hoffmann break; 224dcfda673SGerd Hoffmann } 225dcfda673SGerd Hoffmann } 226dcfda673SGerd Hoffmann if (i < 0) { 227dcfda673SGerd Hoffmann if (hs->kbd.keys < sizeof(hs->kbd.key)) { 228dcfda673SGerd Hoffmann hs->kbd.key[hs->kbd.keys++] = hid_code; 229dcfda673SGerd Hoffmann } 230dcfda673SGerd Hoffmann } else { 231dcfda673SGerd Hoffmann return; 232dcfda673SGerd Hoffmann } 233dcfda673SGerd Hoffmann } 234dcfda673SGerd Hoffmann } 235dcfda673SGerd Hoffmann 236dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax) 237dcfda673SGerd Hoffmann { 238dcfda673SGerd Hoffmann if (val < vmin) { 239dcfda673SGerd Hoffmann return vmin; 240dcfda673SGerd Hoffmann } else if (val > vmax) { 241dcfda673SGerd Hoffmann return vmax; 242dcfda673SGerd Hoffmann } else { 243dcfda673SGerd Hoffmann return val; 244dcfda673SGerd Hoffmann } 245dcfda673SGerd Hoffmann } 246dcfda673SGerd Hoffmann 24721635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs) 24821635e12SGerd Hoffmann { 24921635e12SGerd Hoffmann if (!hs->ptr.mouse_grabbed) { 25021635e12SGerd Hoffmann qemu_activate_mouse_event_handler(hs->ptr.eh_entry); 25121635e12SGerd Hoffmann hs->ptr.mouse_grabbed = 1; 25221635e12SGerd Hoffmann } 25321635e12SGerd Hoffmann } 25421635e12SGerd Hoffmann 255dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) 256dcfda673SGerd Hoffmann { 257dcfda673SGerd Hoffmann int dx, dy, dz, b, l; 258dcfda673SGerd Hoffmann int index; 259dcfda673SGerd Hoffmann HIDPointerEvent *e; 260dcfda673SGerd Hoffmann 261027c03f7SHans de Goede hs->idle_pending = false; 262027c03f7SHans de Goede 26321635e12SGerd Hoffmann hid_pointer_activate(hs); 264dcfda673SGerd Hoffmann 265dcfda673SGerd Hoffmann /* When the buffer is empty, return the last event. Relative 266dcfda673SGerd Hoffmann movements will all be zero. */ 267dcfda673SGerd Hoffmann index = (hs->n ? hs->head : hs->head - 1); 268dcfda673SGerd Hoffmann e = &hs->ptr.queue[index & QUEUE_MASK]; 269dcfda673SGerd Hoffmann 270dcfda673SGerd Hoffmann if (hs->kind == HID_MOUSE) { 271dcfda673SGerd Hoffmann dx = int_clamp(e->xdx, -127, 127); 272dcfda673SGerd Hoffmann dy = int_clamp(e->ydy, -127, 127); 273dcfda673SGerd Hoffmann e->xdx -= dx; 274dcfda673SGerd Hoffmann e->ydy -= dy; 275dcfda673SGerd Hoffmann } else { 276dcfda673SGerd Hoffmann dx = e->xdx; 277dcfda673SGerd Hoffmann dy = e->ydy; 278dcfda673SGerd Hoffmann } 279dcfda673SGerd Hoffmann dz = int_clamp(e->dz, -127, 127); 280dcfda673SGerd Hoffmann e->dz -= dz; 281dcfda673SGerd Hoffmann 282dcfda673SGerd Hoffmann b = 0; 283dcfda673SGerd Hoffmann if (e->buttons_state & MOUSE_EVENT_LBUTTON) { 284dcfda673SGerd Hoffmann b |= 0x01; 285dcfda673SGerd Hoffmann } 286dcfda673SGerd Hoffmann if (e->buttons_state & MOUSE_EVENT_RBUTTON) { 287dcfda673SGerd Hoffmann b |= 0x02; 288dcfda673SGerd Hoffmann } 289dcfda673SGerd Hoffmann if (e->buttons_state & MOUSE_EVENT_MBUTTON) { 290dcfda673SGerd Hoffmann b |= 0x04; 291dcfda673SGerd Hoffmann } 292dcfda673SGerd Hoffmann 293dcfda673SGerd Hoffmann if (hs->n && 294dcfda673SGerd Hoffmann !e->dz && 295dcfda673SGerd Hoffmann (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { 296dcfda673SGerd Hoffmann /* that deals with this event */ 297dcfda673SGerd Hoffmann QUEUE_INCR(hs->head); 298dcfda673SGerd Hoffmann hs->n--; 299dcfda673SGerd Hoffmann } 300dcfda673SGerd Hoffmann 301dcfda673SGerd Hoffmann /* Appears we have to invert the wheel direction */ 302dcfda673SGerd Hoffmann dz = 0 - dz; 303dcfda673SGerd Hoffmann l = 0; 304dcfda673SGerd Hoffmann switch (hs->kind) { 305dcfda673SGerd Hoffmann case HID_MOUSE: 306dcfda673SGerd Hoffmann if (len > l) { 307dcfda673SGerd Hoffmann buf[l++] = b; 308dcfda673SGerd Hoffmann } 309dcfda673SGerd Hoffmann if (len > l) { 310dcfda673SGerd Hoffmann buf[l++] = dx; 311dcfda673SGerd Hoffmann } 312dcfda673SGerd Hoffmann if (len > l) { 313dcfda673SGerd Hoffmann buf[l++] = dy; 314dcfda673SGerd Hoffmann } 315dcfda673SGerd Hoffmann if (len > l) { 316dcfda673SGerd Hoffmann buf[l++] = dz; 317dcfda673SGerd Hoffmann } 318dcfda673SGerd Hoffmann break; 319dcfda673SGerd Hoffmann 320dcfda673SGerd Hoffmann case HID_TABLET: 321dcfda673SGerd Hoffmann if (len > l) { 322dcfda673SGerd Hoffmann buf[l++] = b; 323dcfda673SGerd Hoffmann } 324dcfda673SGerd Hoffmann if (len > l) { 325dcfda673SGerd Hoffmann buf[l++] = dx & 0xff; 326dcfda673SGerd Hoffmann } 327dcfda673SGerd Hoffmann if (len > l) { 328dcfda673SGerd Hoffmann buf[l++] = dx >> 8; 329dcfda673SGerd Hoffmann } 330dcfda673SGerd Hoffmann if (len > l) { 331dcfda673SGerd Hoffmann buf[l++] = dy & 0xff; 332dcfda673SGerd Hoffmann } 333dcfda673SGerd Hoffmann if (len > l) { 334dcfda673SGerd Hoffmann buf[l++] = dy >> 8; 335dcfda673SGerd Hoffmann } 336dcfda673SGerd Hoffmann if (len > l) { 337dcfda673SGerd Hoffmann buf[l++] = dz; 338dcfda673SGerd Hoffmann } 339dcfda673SGerd Hoffmann break; 340dcfda673SGerd Hoffmann 341dcfda673SGerd Hoffmann default: 342dcfda673SGerd Hoffmann abort(); 343dcfda673SGerd Hoffmann } 344dcfda673SGerd Hoffmann 345dcfda673SGerd Hoffmann return l; 346dcfda673SGerd Hoffmann } 347dcfda673SGerd Hoffmann 348dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) 349dcfda673SGerd Hoffmann { 350027c03f7SHans de Goede hs->idle_pending = false; 351027c03f7SHans de Goede 352dcfda673SGerd Hoffmann if (len < 2) { 353dcfda673SGerd Hoffmann return 0; 354dcfda673SGerd Hoffmann } 355dcfda673SGerd Hoffmann 356dcfda673SGerd Hoffmann hid_keyboard_process_keycode(hs); 357dcfda673SGerd Hoffmann 358dcfda673SGerd Hoffmann buf[0] = hs->kbd.modifiers & 0xff; 359dcfda673SGerd Hoffmann buf[1] = 0; 360dcfda673SGerd Hoffmann if (hs->kbd.keys > 6) { 361dcfda673SGerd Hoffmann memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); 362dcfda673SGerd Hoffmann } else { 363dcfda673SGerd Hoffmann memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2); 364dcfda673SGerd Hoffmann } 365dcfda673SGerd Hoffmann 366dcfda673SGerd Hoffmann return MIN(8, len); 367dcfda673SGerd Hoffmann } 368dcfda673SGerd Hoffmann 369dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len) 370dcfda673SGerd Hoffmann { 371dcfda673SGerd Hoffmann if (len > 0) { 372dcfda673SGerd Hoffmann int ledstate = 0; 373dcfda673SGerd Hoffmann /* 0x01: Num Lock LED 374dcfda673SGerd Hoffmann * 0x02: Caps Lock LED 375dcfda673SGerd Hoffmann * 0x04: Scroll Lock LED 376dcfda673SGerd Hoffmann * 0x08: Compose LED 377dcfda673SGerd Hoffmann * 0x10: Kana LED */ 378dcfda673SGerd Hoffmann hs->kbd.leds = buf[0]; 379dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x04) { 380dcfda673SGerd Hoffmann ledstate |= QEMU_SCROLL_LOCK_LED; 381dcfda673SGerd Hoffmann } 382dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x01) { 383dcfda673SGerd Hoffmann ledstate |= QEMU_NUM_LOCK_LED; 384dcfda673SGerd Hoffmann } 385dcfda673SGerd Hoffmann if (hs->kbd.leds & 0x02) { 386dcfda673SGerd Hoffmann ledstate |= QEMU_CAPS_LOCK_LED; 387dcfda673SGerd Hoffmann } 388dcfda673SGerd Hoffmann kbd_put_ledstate(ledstate); 389dcfda673SGerd Hoffmann } 390dcfda673SGerd Hoffmann return 0; 391dcfda673SGerd Hoffmann } 392dcfda673SGerd Hoffmann 393dcfda673SGerd Hoffmann void hid_reset(HIDState *hs) 394dcfda673SGerd Hoffmann { 395dcfda673SGerd Hoffmann switch (hs->kind) { 396dcfda673SGerd Hoffmann case HID_KEYBOARD: 397dcfda673SGerd Hoffmann memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes)); 398dcfda673SGerd Hoffmann memset(hs->kbd.key, 0, sizeof(hs->kbd.key)); 399dcfda673SGerd Hoffmann hs->kbd.keys = 0; 400dcfda673SGerd Hoffmann break; 401dcfda673SGerd Hoffmann case HID_MOUSE: 402dcfda673SGerd Hoffmann case HID_TABLET: 403dcfda673SGerd Hoffmann memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue)); 404dcfda673SGerd Hoffmann break; 405dcfda673SGerd Hoffmann } 406dcfda673SGerd Hoffmann hs->head = 0; 407dcfda673SGerd Hoffmann hs->n = 0; 408b069d348SGerd Hoffmann hs->protocol = 1; 409b069d348SGerd Hoffmann hs->idle = 0; 410027c03f7SHans de Goede hs->idle_pending = false; 411027c03f7SHans de Goede hid_del_idle_timer(hs); 412dcfda673SGerd Hoffmann } 413dcfda673SGerd Hoffmann 414dcfda673SGerd Hoffmann void hid_free(HIDState *hs) 415dcfda673SGerd Hoffmann { 416dcfda673SGerd Hoffmann switch (hs->kind) { 417dcfda673SGerd Hoffmann case HID_KEYBOARD: 4185a37532dSGerd Hoffmann qemu_remove_kbd_event_handler(hs->kbd.eh_entry); 419dcfda673SGerd Hoffmann break; 420dcfda673SGerd Hoffmann case HID_MOUSE: 421dcfda673SGerd Hoffmann case HID_TABLET: 422dcfda673SGerd Hoffmann qemu_remove_mouse_event_handler(hs->ptr.eh_entry); 423dcfda673SGerd Hoffmann break; 424dcfda673SGerd Hoffmann } 425027c03f7SHans de Goede hid_del_idle_timer(hs); 426dcfda673SGerd Hoffmann } 427dcfda673SGerd Hoffmann 428dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event) 429dcfda673SGerd Hoffmann { 430dcfda673SGerd Hoffmann hs->kind = kind; 431dcfda673SGerd Hoffmann hs->event = event; 432dcfda673SGerd Hoffmann 433bb0db527SMichael Walle if (hs->kind == HID_KEYBOARD) { 4345a37532dSGerd Hoffmann hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs); 435bb0db527SMichael Walle } else if (hs->kind == HID_MOUSE) { 436dcfda673SGerd Hoffmann hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, 437dcfda673SGerd Hoffmann 0, "QEMU HID Mouse"); 438dcfda673SGerd Hoffmann } else if (hs->kind == HID_TABLET) { 439dcfda673SGerd Hoffmann hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, 440dcfda673SGerd Hoffmann 1, "QEMU HID Tablet"); 441dcfda673SGerd Hoffmann } 442dcfda673SGerd Hoffmann } 443ccd4ed06SMichael Walle 444ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id) 445ccd4ed06SMichael Walle { 446ccd4ed06SMichael Walle HIDState *s = opaque; 447ccd4ed06SMichael Walle 448027c03f7SHans de Goede hid_set_next_idle(s); 449ccd4ed06SMichael Walle return 0; 450ccd4ed06SMichael Walle } 451ccd4ed06SMichael Walle 452ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = { 453ccd4ed06SMichael Walle .name = "HIDPointerEventQueue", 454ccd4ed06SMichael Walle .version_id = 1, 455ccd4ed06SMichael Walle .minimum_version_id = 1, 456ccd4ed06SMichael Walle .fields = (VMStateField[]) { 457ccd4ed06SMichael Walle VMSTATE_INT32(xdx, HIDPointerEvent), 458ccd4ed06SMichael Walle VMSTATE_INT32(ydy, HIDPointerEvent), 459ccd4ed06SMichael Walle VMSTATE_INT32(dz, HIDPointerEvent), 460ccd4ed06SMichael Walle VMSTATE_INT32(buttons_state, HIDPointerEvent), 461ccd4ed06SMichael Walle VMSTATE_END_OF_LIST() 462ccd4ed06SMichael Walle } 463ccd4ed06SMichael Walle }; 464ccd4ed06SMichael Walle 465ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = { 466ccd4ed06SMichael Walle .name = "HIDPointerDevice", 467ccd4ed06SMichael Walle .version_id = 1, 468ccd4ed06SMichael Walle .minimum_version_id = 1, 469ccd4ed06SMichael Walle .post_load = hid_post_load, 470ccd4ed06SMichael Walle .fields = (VMStateField[]) { 471ccd4ed06SMichael Walle VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0, 472ccd4ed06SMichael Walle vmstate_hid_ptr_queue, HIDPointerEvent), 473ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 474ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 475ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 476ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 477ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 478ccd4ed06SMichael Walle } 479ccd4ed06SMichael Walle }; 480ccd4ed06SMichael Walle 481ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = { 482ccd4ed06SMichael Walle .name = "HIDKeyboardDevice", 483ccd4ed06SMichael Walle .version_id = 1, 484ccd4ed06SMichael Walle .minimum_version_id = 1, 485ccd4ed06SMichael Walle .post_load = hid_post_load, 486ccd4ed06SMichael Walle .fields = (VMStateField[]) { 487ccd4ed06SMichael Walle VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH), 488ccd4ed06SMichael Walle VMSTATE_UINT32(head, HIDState), 489ccd4ed06SMichael Walle VMSTATE_UINT32(n, HIDState), 490ccd4ed06SMichael Walle VMSTATE_UINT16(kbd.modifiers, HIDState), 491ccd4ed06SMichael Walle VMSTATE_UINT8(kbd.leds, HIDState), 492ccd4ed06SMichael Walle VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16), 493ccd4ed06SMichael Walle VMSTATE_INT32(kbd.keys, HIDState), 494ccd4ed06SMichael Walle VMSTATE_INT32(protocol, HIDState), 495ccd4ed06SMichael Walle VMSTATE_UINT8(idle, HIDState), 496ccd4ed06SMichael Walle VMSTATE_END_OF_LIST(), 497ccd4ed06SMichael Walle } 498ccd4ed06SMichael Walle }; 499