xref: /qemu/hw/input/hid.c (revision d328fef93ae757a0dd65ed786a4086e27952eef3)
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,
54f9c48124SKatsuhiro Ueno     0x88, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00,
55f9c48124SKatsuhiro 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 
hid_has_events(HIDState * hs)75dcfda673SGerd Hoffmann bool hid_has_events(HIDState *hs)
76dcfda673SGerd Hoffmann {
77027c03f7SHans de Goede     return hs->n > 0 || hs->idle_pending;
78dcfda673SGerd Hoffmann }
79dcfda673SGerd Hoffmann 
hid_idle_timer(void * opaque)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 
hid_del_idle_timer(HIDState * hs)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 
hid_set_next_idle(HIDState * hs)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 
hid_pointer_event(DeviceState * dev,QemuConsole * src,InputEvent * evt)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,
1171e2d5558SNoah Bergbauer         [INPUT_BUTTON_SIDE] = 0x08,
1181e2d5558SNoah Bergbauer         [INPUT_BUTTON_EXTRA] = 0x10,
1198b84286fSGerd Hoffmann     };
1208b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1218b84286fSGerd Hoffmann     HIDPointerEvent *e;
122b5a1b443SEric Blake     InputMoveEvent *move;
123b5a1b443SEric Blake     InputBtnEvent *btn;
124dcfda673SGerd Hoffmann 
1258b84286fSGerd Hoffmann     assert(hs->n < QUEUE_LENGTH);
1268b84286fSGerd Hoffmann     e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1278b84286fSGerd Hoffmann 
128568c73a4SEric Blake     switch (evt->type) {
1298b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_REL:
13032bafa8fSEric Blake         move = evt->u.rel.data;
131b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
132b5a1b443SEric Blake             e->xdx += move->value;
133b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
134b5a1b443SEric Blake             e->ydy += move->value;
1358b84286fSGerd Hoffmann         }
1368b84286fSGerd Hoffmann         break;
1378b84286fSGerd Hoffmann 
1388b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_ABS:
13932bafa8fSEric Blake         move = evt->u.abs.data;
140b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
141b5a1b443SEric Blake             e->xdx = move->value;
142b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
143b5a1b443SEric Blake             e->ydy = move->value;
1448b84286fSGerd Hoffmann         }
1458b84286fSGerd Hoffmann         break;
1468b84286fSGerd Hoffmann 
1478b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
14832bafa8fSEric Blake         btn = evt->u.btn.data;
149b5a1b443SEric Blake         if (btn->down) {
150b5a1b443SEric Blake             e->buttons_state |= bmap[btn->button];
151b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
1528b84286fSGerd Hoffmann                 e->dz--;
153b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
1548b84286fSGerd Hoffmann                 e->dz++;
1558b84286fSGerd Hoffmann             }
156dcfda673SGerd Hoffmann         } else {
157b5a1b443SEric Blake             e->buttons_state &= ~bmap[btn->button];
158dcfda673SGerd Hoffmann         }
1598b84286fSGerd Hoffmann         break;
1608b84286fSGerd Hoffmann 
1618b84286fSGerd Hoffmann     default:
1628b84286fSGerd Hoffmann         /* keep gcc happy */
1638b84286fSGerd Hoffmann         break;
164dcfda673SGerd Hoffmann     }
165dcfda673SGerd Hoffmann 
1668b84286fSGerd Hoffmann }
1678b84286fSGerd Hoffmann 
hid_pointer_sync(DeviceState * dev)1688b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev)
169dcfda673SGerd Hoffmann {
1708b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1718b84286fSGerd Hoffmann     HIDPointerEvent *prev, *curr, *next;
1728b84286fSGerd Hoffmann     bool event_compression = false;
173dcfda673SGerd Hoffmann 
1748b84286fSGerd Hoffmann     if (hs->n == QUEUE_LENGTH-1) {
1758b84286fSGerd Hoffmann         /*
1765d831be2SStefan Weil          * Queue full.  We are losing information, but we at least
1778b84286fSGerd Hoffmann          * keep track of most recent button state.
1788b84286fSGerd Hoffmann          */
1798b84286fSGerd Hoffmann         return;
180dcfda673SGerd Hoffmann     }
1818b84286fSGerd Hoffmann 
1828b84286fSGerd Hoffmann     prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
1838b84286fSGerd Hoffmann     curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1848b84286fSGerd Hoffmann     next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
1858b84286fSGerd Hoffmann 
1868b84286fSGerd Hoffmann     if (hs->n > 0) {
1878b84286fSGerd Hoffmann         /*
1888b84286fSGerd Hoffmann          * No button state change between previous and current event
1898b84286fSGerd Hoffmann          * (and previous wasn't seen by the guest yet), so there is
1908b84286fSGerd Hoffmann          * motion information only and we can combine the two event
1918b84286fSGerd Hoffmann          * into one.
1928b84286fSGerd Hoffmann          */
1938b84286fSGerd Hoffmann         if (curr->buttons_state == prev->buttons_state) {
1948b84286fSGerd Hoffmann             event_compression = true;
1958b84286fSGerd Hoffmann         }
1968b84286fSGerd Hoffmann     }
1978b84286fSGerd Hoffmann 
1988b84286fSGerd Hoffmann     if (event_compression) {
1998b84286fSGerd Hoffmann         /* add current motion to previous, clear current */
2008b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
2018b84286fSGerd Hoffmann             prev->xdx += curr->xdx;
2028b84286fSGerd Hoffmann             curr->xdx = 0;
20335e83d10SChristian Burger             prev->ydy += curr->ydy;
2048b84286fSGerd Hoffmann             curr->ydy = 0;
2058b84286fSGerd Hoffmann         } else {
2068b84286fSGerd Hoffmann             prev->xdx = curr->xdx;
2078b84286fSGerd Hoffmann             prev->ydy = curr->ydy;
2088b84286fSGerd Hoffmann         }
2098b84286fSGerd Hoffmann         prev->dz += curr->dz;
2108b84286fSGerd Hoffmann         curr->dz = 0;
2118b84286fSGerd Hoffmann     } else {
2129b4b4e51SMichael Tokarev         /* prepare next (clear rel, copy abs + btns) */
2138b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
2148b84286fSGerd Hoffmann             next->xdx = 0;
2158b84286fSGerd Hoffmann             next->ydy = 0;
2168b84286fSGerd Hoffmann         } else {
2178b84286fSGerd Hoffmann             next->xdx = curr->xdx;
2188b84286fSGerd Hoffmann             next->ydy = curr->ydy;
2198b84286fSGerd Hoffmann         }
2208b84286fSGerd Hoffmann         next->dz = 0;
2218b84286fSGerd Hoffmann         next->buttons_state = curr->buttons_state;
2228b84286fSGerd Hoffmann         /* make current guest visible, notify guest */
2238b84286fSGerd Hoffmann         hs->n++;
224dcfda673SGerd Hoffmann         hs->event(hs);
225dcfda673SGerd Hoffmann     }
2268b84286fSGerd Hoffmann }
227dcfda673SGerd Hoffmann 
hid_keyboard_event(DeviceState * dev,QemuConsole * src,InputEvent * evt)2281ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
2291ff5eeddSGerd Hoffmann                                InputEvent *evt)
230dcfda673SGerd Hoffmann {
2311ff5eeddSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
2321ff5eeddSGerd Hoffmann     int scancodes[3], i, count;
233dcfda673SGerd Hoffmann     int slot;
23432bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
235dcfda673SGerd Hoffmann 
236b5a1b443SEric Blake     count = qemu_input_key_value_to_scancode(key->key,
237b5a1b443SEric Blake                                              key->down,
2381ff5eeddSGerd Hoffmann                                              scancodes);
2391ff5eeddSGerd Hoffmann     if (hs->n + count > QUEUE_LENGTH) {
240c80276b4SGerd Hoffmann         trace_hid_kbd_queue_full();
241dcfda673SGerd Hoffmann         return;
242dcfda673SGerd Hoffmann     }
2431ff5eeddSGerd Hoffmann     for (i = 0; i < count; i++) {
244dcfda673SGerd Hoffmann         slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
2451ff5eeddSGerd Hoffmann         hs->kbd.keycodes[slot] = scancodes[i];
2461ff5eeddSGerd Hoffmann     }
247dcfda673SGerd Hoffmann     hs->event(hs);
248dcfda673SGerd Hoffmann }
249dcfda673SGerd Hoffmann 
hid_keyboard_process_keycode(HIDState * hs)250dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs)
251dcfda673SGerd Hoffmann {
252562f9375SPaolo Bonzini     uint8_t hid_code, index, key;
253dcfda673SGerd Hoffmann     int i, keycode, slot;
254dcfda673SGerd Hoffmann 
255dcfda673SGerd Hoffmann     if (hs->n == 0) {
256dcfda673SGerd Hoffmann         return;
257dcfda673SGerd Hoffmann     }
258dcfda673SGerd Hoffmann     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
259dcfda673SGerd Hoffmann     keycode = hs->kbd.keycodes[slot];
260dcfda673SGerd Hoffmann 
2612222e0a6SAlexander Graf     if (!hs->n) {
2622222e0a6SAlexander Graf         trace_hid_kbd_queue_empty();
2632222e0a6SAlexander Graf     }
2642222e0a6SAlexander Graf 
265dcfda673SGerd Hoffmann     key = keycode & 0x7f;
266562f9375SPaolo Bonzini     index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
267562f9375SPaolo Bonzini     hid_code = hid_usage_keys[index];
268dcfda673SGerd Hoffmann     hs->kbd.modifiers &= ~(1 << 8);
269dcfda673SGerd Hoffmann 
270dcfda673SGerd Hoffmann     switch (hid_code) {
271dcfda673SGerd Hoffmann     case 0x00:
272dcfda673SGerd Hoffmann         return;
273dcfda673SGerd Hoffmann 
274dcfda673SGerd Hoffmann     case 0xe0:
275562f9375SPaolo Bonzini         assert(key == 0x1d);
276dcfda673SGerd Hoffmann         if (hs->kbd.modifiers & (1 << 9)) {
277562f9375SPaolo Bonzini             /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
278562f9375SPaolo Bonzini              * Here we're processing the second hid_code.  By dropping bit 9
279562f9375SPaolo Bonzini              * and setting bit 8, the scancode after 0x1d will access the
280562f9375SPaolo Bonzini              * second half of the table.
281562f9375SPaolo Bonzini              */
282562f9375SPaolo Bonzini             hs->kbd.modifiers ^= (1 << 8) | (1 << 9);
283dcfda673SGerd Hoffmann             return;
284dcfda673SGerd Hoffmann         }
285562f9375SPaolo Bonzini         /* fall through to process Ctrl_L */
286dcfda673SGerd Hoffmann     case 0xe1 ... 0xe7:
287562f9375SPaolo Bonzini         /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
288562f9375SPaolo Bonzini          * Handle releases here, or fall through to process presses.
289562f9375SPaolo Bonzini          */
290dcfda673SGerd Hoffmann         if (keycode & (1 << 7)) {
291dcfda673SGerd Hoffmann             hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
292dcfda673SGerd Hoffmann             return;
293dcfda673SGerd Hoffmann         }
294562f9375SPaolo Bonzini         /* fall through */
295562f9375SPaolo Bonzini     case 0xe8 ... 0xe9:
296562f9375SPaolo Bonzini         /* USB modifiers are just 1 byte long.  Bits 8 and 9 of
297562f9375SPaolo Bonzini          * hs->kbd.modifiers implement a state machine that detects the
298562f9375SPaolo Bonzini          * 0xe0 and 0xe1/0x1d sequences.  These bits do not follow the
299562f9375SPaolo Bonzini          * usual rules where bit 7 marks released keys; they are cleared
300562f9375SPaolo Bonzini          * elsewhere in the function as the state machine dictates.
301562f9375SPaolo Bonzini          */
302dcfda673SGerd Hoffmann         hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
303dcfda673SGerd Hoffmann         return;
304562f9375SPaolo Bonzini 
305562f9375SPaolo Bonzini     case 0xea ... 0xef:
306562f9375SPaolo Bonzini         abort();
307562f9375SPaolo Bonzini 
308562f9375SPaolo Bonzini     default:
309562f9375SPaolo Bonzini         break;
310dcfda673SGerd Hoffmann     }
311dcfda673SGerd Hoffmann 
312dcfda673SGerd Hoffmann     if (keycode & (1 << 7)) {
313dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
314dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
315dcfda673SGerd Hoffmann                 hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
316dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys] = 0x00;
317dcfda673SGerd Hoffmann                 break;
318dcfda673SGerd Hoffmann             }
319dcfda673SGerd Hoffmann         }
320dcfda673SGerd Hoffmann         if (i < 0) {
321dcfda673SGerd Hoffmann             return;
322dcfda673SGerd Hoffmann         }
323dcfda673SGerd Hoffmann     } else {
324dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
325dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
326dcfda673SGerd Hoffmann                 break;
327dcfda673SGerd Hoffmann             }
328dcfda673SGerd Hoffmann         }
329dcfda673SGerd Hoffmann         if (i < 0) {
330dcfda673SGerd Hoffmann             if (hs->kbd.keys < sizeof(hs->kbd.key)) {
331dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys++] = hid_code;
332dcfda673SGerd Hoffmann             }
333dcfda673SGerd Hoffmann         } else {
334dcfda673SGerd Hoffmann             return;
335dcfda673SGerd Hoffmann         }
336dcfda673SGerd Hoffmann     }
337dcfda673SGerd Hoffmann }
338dcfda673SGerd Hoffmann 
int_clamp(int val,int vmin,int vmax)339dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax)
340dcfda673SGerd Hoffmann {
341dcfda673SGerd Hoffmann     if (val < vmin) {
342dcfda673SGerd Hoffmann         return vmin;
343dcfda673SGerd Hoffmann     } else if (val > vmax) {
344dcfda673SGerd Hoffmann         return vmax;
345dcfda673SGerd Hoffmann     } else {
346dcfda673SGerd Hoffmann         return val;
347dcfda673SGerd Hoffmann     }
348dcfda673SGerd Hoffmann }
349dcfda673SGerd Hoffmann 
hid_pointer_activate(HIDState * hs)35021635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs)
35121635e12SGerd Hoffmann {
35221635e12SGerd Hoffmann     if (!hs->ptr.mouse_grabbed) {
3538b84286fSGerd Hoffmann         qemu_input_handler_activate(hs->s);
35421635e12SGerd Hoffmann         hs->ptr.mouse_grabbed = 1;
35521635e12SGerd Hoffmann     }
35621635e12SGerd Hoffmann }
35721635e12SGerd Hoffmann 
hid_pointer_poll(HIDState * hs,uint8_t * buf,int len)358dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
359dcfda673SGerd Hoffmann {
3608b84286fSGerd Hoffmann     int dx, dy, dz, l;
361dcfda673SGerd Hoffmann     int index;
362dcfda673SGerd Hoffmann     HIDPointerEvent *e;
363dcfda673SGerd Hoffmann 
364027c03f7SHans de Goede     hs->idle_pending = false;
365027c03f7SHans de Goede 
36621635e12SGerd Hoffmann     hid_pointer_activate(hs);
367dcfda673SGerd Hoffmann 
368dcfda673SGerd Hoffmann     /* When the buffer is empty, return the last event.  Relative
369dcfda673SGerd Hoffmann        movements will all be zero.  */
370dcfda673SGerd Hoffmann     index = (hs->n ? hs->head : hs->head - 1);
371dcfda673SGerd Hoffmann     e = &hs->ptr.queue[index & QUEUE_MASK];
372dcfda673SGerd Hoffmann 
373dcfda673SGerd Hoffmann     if (hs->kind == HID_MOUSE) {
374dcfda673SGerd Hoffmann         dx = int_clamp(e->xdx, -127, 127);
375dcfda673SGerd Hoffmann         dy = int_clamp(e->ydy, -127, 127);
376dcfda673SGerd Hoffmann         e->xdx -= dx;
377dcfda673SGerd Hoffmann         e->ydy -= dy;
378dcfda673SGerd Hoffmann     } else {
379dcfda673SGerd Hoffmann         dx = e->xdx;
380dcfda673SGerd Hoffmann         dy = e->ydy;
381dcfda673SGerd Hoffmann     }
382dcfda673SGerd Hoffmann     dz = int_clamp(e->dz, -127, 127);
383dcfda673SGerd Hoffmann     e->dz -= dz;
384dcfda673SGerd Hoffmann 
385dcfda673SGerd Hoffmann     if (hs->n &&
386dcfda673SGerd Hoffmann         !e->dz &&
387dcfda673SGerd Hoffmann         (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
388dcfda673SGerd Hoffmann         /* that deals with this event */
389dcfda673SGerd Hoffmann         QUEUE_INCR(hs->head);
390dcfda673SGerd Hoffmann         hs->n--;
391dcfda673SGerd Hoffmann     }
392dcfda673SGerd Hoffmann 
393dcfda673SGerd Hoffmann     /* Appears we have to invert the wheel direction */
394dcfda673SGerd Hoffmann     dz = 0 - dz;
395dcfda673SGerd Hoffmann     l = 0;
396dcfda673SGerd Hoffmann     switch (hs->kind) {
397dcfda673SGerd Hoffmann     case HID_MOUSE:
398dcfda673SGerd Hoffmann         if (len > l) {
3998b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
400dcfda673SGerd Hoffmann         }
401dcfda673SGerd Hoffmann         if (len > l) {
402dcfda673SGerd Hoffmann             buf[l++] = dx;
403dcfda673SGerd Hoffmann         }
404dcfda673SGerd Hoffmann         if (len > l) {
405dcfda673SGerd Hoffmann             buf[l++] = dy;
406dcfda673SGerd Hoffmann         }
407dcfda673SGerd Hoffmann         if (len > l) {
408dcfda673SGerd Hoffmann             buf[l++] = dz;
409dcfda673SGerd Hoffmann         }
410dcfda673SGerd Hoffmann         break;
411dcfda673SGerd Hoffmann 
412dcfda673SGerd Hoffmann     case HID_TABLET:
413dcfda673SGerd Hoffmann         if (len > l) {
4148b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
415dcfda673SGerd Hoffmann         }
416dcfda673SGerd Hoffmann         if (len > l) {
417dcfda673SGerd Hoffmann             buf[l++] = dx & 0xff;
418dcfda673SGerd Hoffmann         }
419dcfda673SGerd Hoffmann         if (len > l) {
420dcfda673SGerd Hoffmann             buf[l++] = dx >> 8;
421dcfda673SGerd Hoffmann         }
422dcfda673SGerd Hoffmann         if (len > l) {
423dcfda673SGerd Hoffmann             buf[l++] = dy & 0xff;
424dcfda673SGerd Hoffmann         }
425dcfda673SGerd Hoffmann         if (len > l) {
426dcfda673SGerd Hoffmann             buf[l++] = dy >> 8;
427dcfda673SGerd Hoffmann         }
428dcfda673SGerd Hoffmann         if (len > l) {
429dcfda673SGerd Hoffmann             buf[l++] = dz;
430dcfda673SGerd Hoffmann         }
431dcfda673SGerd Hoffmann         break;
432dcfda673SGerd Hoffmann 
433dcfda673SGerd Hoffmann     default:
434dcfda673SGerd Hoffmann         abort();
435dcfda673SGerd Hoffmann     }
436dcfda673SGerd Hoffmann 
437dcfda673SGerd Hoffmann     return l;
438dcfda673SGerd Hoffmann }
439dcfda673SGerd Hoffmann 
hid_keyboard_poll(HIDState * hs,uint8_t * buf,int len)440dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
441dcfda673SGerd Hoffmann {
442027c03f7SHans de Goede     hs->idle_pending = false;
443027c03f7SHans de Goede 
444dcfda673SGerd Hoffmann     if (len < 2) {
445dcfda673SGerd Hoffmann         return 0;
446dcfda673SGerd Hoffmann     }
447dcfda673SGerd Hoffmann 
448dcfda673SGerd Hoffmann     hid_keyboard_process_keycode(hs);
449dcfda673SGerd Hoffmann 
450dcfda673SGerd Hoffmann     buf[0] = hs->kbd.modifiers & 0xff;
451dcfda673SGerd Hoffmann     buf[1] = 0;
452dcfda673SGerd Hoffmann     if (hs->kbd.keys > 6) {
453dcfda673SGerd Hoffmann         memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
454dcfda673SGerd Hoffmann     } else {
455dcfda673SGerd Hoffmann         memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
456dcfda673SGerd Hoffmann     }
457dcfda673SGerd Hoffmann 
458dcfda673SGerd Hoffmann     return MIN(8, len);
459dcfda673SGerd Hoffmann }
460dcfda673SGerd Hoffmann 
hid_keyboard_write(HIDState * hs,uint8_t * buf,int len)461dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
462dcfda673SGerd Hoffmann {
463dcfda673SGerd Hoffmann     if (len > 0) {
464dcfda673SGerd Hoffmann         int ledstate = 0;
465dcfda673SGerd Hoffmann         /* 0x01: Num Lock LED
466dcfda673SGerd Hoffmann          * 0x02: Caps Lock LED
467dcfda673SGerd Hoffmann          * 0x04: Scroll Lock LED
468dcfda673SGerd Hoffmann          * 0x08: Compose LED
469dcfda673SGerd Hoffmann          * 0x10: Kana LED */
470dcfda673SGerd Hoffmann         hs->kbd.leds = buf[0];
471dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x04) {
472dcfda673SGerd Hoffmann             ledstate |= QEMU_SCROLL_LOCK_LED;
473dcfda673SGerd Hoffmann         }
474dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x01) {
475dcfda673SGerd Hoffmann             ledstate |= QEMU_NUM_LOCK_LED;
476dcfda673SGerd Hoffmann         }
477dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x02) {
478dcfda673SGerd Hoffmann             ledstate |= QEMU_CAPS_LOCK_LED;
479dcfda673SGerd Hoffmann         }
480dcfda673SGerd Hoffmann         kbd_put_ledstate(ledstate);
481dcfda673SGerd Hoffmann     }
482dcfda673SGerd Hoffmann     return 0;
483dcfda673SGerd Hoffmann }
484dcfda673SGerd Hoffmann 
hid_reset(HIDState * hs)485dcfda673SGerd Hoffmann void hid_reset(HIDState *hs)
486dcfda673SGerd Hoffmann {
487dcfda673SGerd Hoffmann     switch (hs->kind) {
488dcfda673SGerd Hoffmann     case HID_KEYBOARD:
489dcfda673SGerd Hoffmann         memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
490dcfda673SGerd Hoffmann         memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
491dcfda673SGerd Hoffmann         hs->kbd.keys = 0;
49251dbea77SAlexander Graf         hs->kbd.modifiers = 0;
493dcfda673SGerd Hoffmann         break;
494dcfda673SGerd Hoffmann     case HID_MOUSE:
495dcfda673SGerd Hoffmann     case HID_TABLET:
496dcfda673SGerd Hoffmann         memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
497dcfda673SGerd Hoffmann         break;
498dcfda673SGerd Hoffmann     }
499dcfda673SGerd Hoffmann     hs->head = 0;
500dcfda673SGerd Hoffmann     hs->n = 0;
501b069d348SGerd Hoffmann     hs->protocol = 1;
502b069d348SGerd Hoffmann     hs->idle = 0;
503027c03f7SHans de Goede     hs->idle_pending = false;
504027c03f7SHans de Goede     hid_del_idle_timer(hs);
505dcfda673SGerd Hoffmann }
506dcfda673SGerd Hoffmann 
hid_free(HIDState * hs)507dcfda673SGerd Hoffmann void hid_free(HIDState *hs)
508dcfda673SGerd Hoffmann {
5091ff5eeddSGerd Hoffmann     qemu_input_handler_unregister(hs->s);
510027c03f7SHans de Goede     hid_del_idle_timer(hs);
511dcfda673SGerd Hoffmann }
512dcfda673SGerd Hoffmann 
513b1be65f6SPhilippe Mathieu-Daudé static const QemuInputHandler hid_keyboard_handler = {
5141ff5eeddSGerd Hoffmann     .name  = "QEMU HID Keyboard",
5151ff5eeddSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
5161ff5eeddSGerd Hoffmann     .event = hid_keyboard_event,
5171ff5eeddSGerd Hoffmann };
5181ff5eeddSGerd Hoffmann 
519b1be65f6SPhilippe Mathieu-Daudé static const QemuInputHandler hid_mouse_handler = {
5208b84286fSGerd Hoffmann     .name  = "QEMU HID Mouse",
5218b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
5228b84286fSGerd Hoffmann     .event = hid_pointer_event,
5238b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
5248b84286fSGerd Hoffmann };
5258b84286fSGerd Hoffmann 
526b1be65f6SPhilippe Mathieu-Daudé static const QemuInputHandler hid_tablet_handler = {
5278b84286fSGerd Hoffmann     .name  = "QEMU HID Tablet",
5288b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
5298b84286fSGerd Hoffmann     .event = hid_pointer_event,
5308b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
5318b84286fSGerd Hoffmann };
5328b84286fSGerd Hoffmann 
hid_init(HIDState * hs,int kind,HIDEventFunc event)533dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event)
534dcfda673SGerd Hoffmann {
535dcfda673SGerd Hoffmann     hs->kind = kind;
536dcfda673SGerd Hoffmann     hs->event = event;
537dcfda673SGerd Hoffmann 
538bb0db527SMichael Walle     if (hs->kind == HID_KEYBOARD) {
5391ff5eeddSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5401ff5eeddSGerd Hoffmann                                             &hid_keyboard_handler);
5411ff5eeddSGerd Hoffmann         qemu_input_handler_activate(hs->s);
542bb0db527SMichael Walle     } else if (hs->kind == HID_MOUSE) {
5438b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5448b84286fSGerd Hoffmann                                             &hid_mouse_handler);
545dcfda673SGerd Hoffmann     } else if (hs->kind == HID_TABLET) {
5468b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5478b84286fSGerd Hoffmann                                             &hid_tablet_handler);
548dcfda673SGerd Hoffmann     }
549dcfda673SGerd Hoffmann }
550ccd4ed06SMichael Walle 
hid_post_load(void * opaque,int version_id)551ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id)
552ccd4ed06SMichael Walle {
553ccd4ed06SMichael Walle     HIDState *s = opaque;
554ccd4ed06SMichael Walle 
555027c03f7SHans de Goede     hid_set_next_idle(s);
556ba4d2606SGerd Hoffmann 
557ba4d2606SGerd Hoffmann     if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
558ba4d2606SGerd Hoffmann                                  s->kind == HID_MOUSE)) {
559ba4d2606SGerd Hoffmann         /*
560ba4d2606SGerd Hoffmann          * Handle ptr device migration from old qemu with full queue.
561ba4d2606SGerd Hoffmann          *
562ba4d2606SGerd Hoffmann          * Throw away everything but the last event, so we propagate
563ba4d2606SGerd Hoffmann          * at least the current button state to the guest.  Also keep
564ba4d2606SGerd Hoffmann          * current position for the tablet, signal "no motion" for the
565ba4d2606SGerd Hoffmann          * mouse.
566ba4d2606SGerd Hoffmann          */
567ba4d2606SGerd Hoffmann         HIDPointerEvent evt;
568ba4d2606SGerd Hoffmann         evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
569ba4d2606SGerd Hoffmann         if (s->kind == HID_MOUSE) {
570ba4d2606SGerd Hoffmann             evt.xdx = 0;
571ba4d2606SGerd Hoffmann             evt.ydy = 0;
572ba4d2606SGerd Hoffmann         }
573ba4d2606SGerd Hoffmann         s->ptr.queue[0] = evt;
574ba4d2606SGerd Hoffmann         s->head = 0;
575ba4d2606SGerd Hoffmann         s->n = 1;
576ba4d2606SGerd Hoffmann     }
577ccd4ed06SMichael Walle     return 0;
578ccd4ed06SMichael Walle }
579ccd4ed06SMichael Walle 
580ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = {
581ccd4ed06SMichael Walle     .name = "HIDPointerEventQueue",
582ccd4ed06SMichael Walle     .version_id = 1,
583ccd4ed06SMichael Walle     .minimum_version_id = 1,
584*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
585ccd4ed06SMichael Walle         VMSTATE_INT32(xdx, HIDPointerEvent),
586ccd4ed06SMichael Walle         VMSTATE_INT32(ydy, HIDPointerEvent),
587ccd4ed06SMichael Walle         VMSTATE_INT32(dz, HIDPointerEvent),
588ccd4ed06SMichael Walle         VMSTATE_INT32(buttons_state, HIDPointerEvent),
589ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST()
590ccd4ed06SMichael Walle     }
591ccd4ed06SMichael Walle };
592ccd4ed06SMichael Walle 
593ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = {
594ccd4ed06SMichael Walle     .name = "HIDPointerDevice",
595ccd4ed06SMichael Walle     .version_id = 1,
596ccd4ed06SMichael Walle     .minimum_version_id = 1,
597ccd4ed06SMichael Walle     .post_load = hid_post_load,
598*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
599ccd4ed06SMichael Walle         VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
600ccd4ed06SMichael Walle                              vmstate_hid_ptr_queue, HIDPointerEvent),
601ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
602ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
603ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
604ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
605ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
606ccd4ed06SMichael Walle     }
607ccd4ed06SMichael Walle };
608ccd4ed06SMichael Walle 
609ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = {
610ccd4ed06SMichael Walle     .name = "HIDKeyboardDevice",
611ccd4ed06SMichael Walle     .version_id = 1,
612ccd4ed06SMichael Walle     .minimum_version_id = 1,
613ccd4ed06SMichael Walle     .post_load = hid_post_load,
614*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
615ccd4ed06SMichael Walle         VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
616ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
617ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
618ccd4ed06SMichael Walle         VMSTATE_UINT16(kbd.modifiers, HIDState),
619ccd4ed06SMichael Walle         VMSTATE_UINT8(kbd.leds, HIDState),
620ccd4ed06SMichael Walle         VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
621ccd4ed06SMichael Walle         VMSTATE_INT32(kbd.keys, HIDState),
622ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
623ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
624ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
625ccd4ed06SMichael Walle     }
626ccd4ed06SMichael Walle };
627