xref: /qemu/hw/input/hid.c (revision 91dbeeda2d2cf85e733ddd86aa84de12bdf8cd4a)
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  */
250430891cSPeter Maydell #include "qemu/osdep.h"
2683c9f4caSPaolo Bonzini #include "hw/hw.h"
2728ecbaeeSPaolo Bonzini #include "ui/console.h"
281de7afc9SPaolo Bonzini #include "qemu/timer.h"
290d09e41aSPaolo Bonzini #include "hw/input/hid.h"
30dcfda673SGerd Hoffmann 
31dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_ROLLOVER        0x01
32dcfda673SGerd Hoffmann #define HID_USAGE_POSTFAIL              0x02
33dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_UNDEFINED       0x03
34dcfda673SGerd Hoffmann 
35dcfda673SGerd Hoffmann /* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
36dcfda673SGerd Hoffmann  * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
37dcfda673SGerd Hoffmann static const uint8_t hid_usage_keys[0x100] = {
38dcfda673SGerd Hoffmann     0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
39dcfda673SGerd Hoffmann     0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
40dcfda673SGerd Hoffmann     0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
41dcfda673SGerd Hoffmann     0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
42dcfda673SGerd Hoffmann     0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
43dcfda673SGerd Hoffmann     0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
44dcfda673SGerd Hoffmann     0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
450ee4de58SDinar Valeev     0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
46dcfda673SGerd Hoffmann     0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
47dcfda673SGerd Hoffmann     0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
48*91dbeedaSDaniel Serpell     0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44,
49dcfda673SGerd Hoffmann     0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
50dcfda673SGerd Hoffmann     0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
51dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
52dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
54dcfda673SGerd Hoffmann 
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, 0x00, 0x00, 0x00, 0x00,
58dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
59dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
62dcfda673SGerd Hoffmann     0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
64dcfda673SGerd Hoffmann     0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
65dcfda673SGerd Hoffmann     0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
66dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 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     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71dcfda673SGerd Hoffmann };
72dcfda673SGerd Hoffmann 
73dcfda673SGerd Hoffmann bool hid_has_events(HIDState *hs)
74dcfda673SGerd Hoffmann {
75027c03f7SHans de Goede     return hs->n > 0 || hs->idle_pending;
76dcfda673SGerd Hoffmann }
77dcfda673SGerd Hoffmann 
78027c03f7SHans de Goede static void hid_idle_timer(void *opaque)
79b069d348SGerd Hoffmann {
80027c03f7SHans de Goede     HIDState *hs = opaque;
81027c03f7SHans de Goede 
82027c03f7SHans de Goede     hs->idle_pending = true;
83027c03f7SHans de Goede     hs->event(hs);
84027c03f7SHans de Goede }
85027c03f7SHans de Goede 
86027c03f7SHans de Goede static void hid_del_idle_timer(HIDState *hs)
87027c03f7SHans de Goede {
88027c03f7SHans de Goede     if (hs->idle_timer) {
89bc72ad67SAlex Bligh         timer_del(hs->idle_timer);
90bc72ad67SAlex Bligh         timer_free(hs->idle_timer);
91027c03f7SHans de Goede         hs->idle_timer = NULL;
92027c03f7SHans de Goede     }
93027c03f7SHans de Goede }
94027c03f7SHans de Goede 
95027c03f7SHans de Goede void hid_set_next_idle(HIDState *hs)
96027c03f7SHans de Goede {
97027c03f7SHans de Goede     if (hs->idle) {
98bc72ad67SAlex Bligh         uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
99027c03f7SHans de Goede                                get_ticks_per_sec() * hs->idle * 4 / 1000;
100027c03f7SHans de Goede         if (!hs->idle_timer) {
101bc72ad67SAlex Bligh             hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs);
102027c03f7SHans de Goede         }
103bc72ad67SAlex Bligh         timer_mod_ns(hs->idle_timer, expire_time);
104027c03f7SHans de Goede     } else {
105027c03f7SHans de Goede         hid_del_idle_timer(hs);
106027c03f7SHans de Goede     }
107b069d348SGerd Hoffmann }
108b069d348SGerd Hoffmann 
1098b84286fSGerd Hoffmann static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
1108b84286fSGerd Hoffmann                               InputEvent *evt)
111dcfda673SGerd Hoffmann {
1127fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
1138b84286fSGerd Hoffmann         [INPUT_BUTTON_LEFT]   = 0x01,
1148b84286fSGerd Hoffmann         [INPUT_BUTTON_RIGHT]  = 0x02,
1158b84286fSGerd Hoffmann         [INPUT_BUTTON_MIDDLE] = 0x04,
1168b84286fSGerd Hoffmann     };
1178b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1188b84286fSGerd Hoffmann     HIDPointerEvent *e;
119dcfda673SGerd Hoffmann 
1208b84286fSGerd Hoffmann     assert(hs->n < QUEUE_LENGTH);
1218b84286fSGerd Hoffmann     e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1228b84286fSGerd Hoffmann 
123568c73a4SEric Blake     switch (evt->type) {
1248b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_REL:
125568c73a4SEric Blake         if (evt->u.rel->axis == INPUT_AXIS_X) {
126568c73a4SEric Blake             e->xdx += evt->u.rel->value;
127568c73a4SEric Blake         } else if (evt->u.rel->axis == INPUT_AXIS_Y) {
128568c73a4SEric Blake             e->ydy += evt->u.rel->value;
1298b84286fSGerd Hoffmann         }
1308b84286fSGerd Hoffmann         break;
1318b84286fSGerd Hoffmann 
1328b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_ABS:
133568c73a4SEric Blake         if (evt->u.rel->axis == INPUT_AXIS_X) {
134568c73a4SEric Blake             e->xdx = evt->u.rel->value;
135568c73a4SEric Blake         } else if (evt->u.rel->axis == INPUT_AXIS_Y) {
136568c73a4SEric Blake             e->ydy = evt->u.rel->value;
1378b84286fSGerd Hoffmann         }
1388b84286fSGerd Hoffmann         break;
1398b84286fSGerd Hoffmann 
1408b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
141568c73a4SEric Blake         if (evt->u.btn->down) {
142568c73a4SEric Blake             e->buttons_state |= bmap[evt->u.btn->button];
143d20a580bSEric Blake             if (evt->u.btn->button == INPUT_BUTTON_WHEELUP) {
1448b84286fSGerd Hoffmann                 e->dz--;
145d20a580bSEric Blake             } else if (evt->u.btn->button == INPUT_BUTTON_WHEELDOWN) {
1468b84286fSGerd Hoffmann                 e->dz++;
1478b84286fSGerd Hoffmann             }
148dcfda673SGerd Hoffmann         } else {
149568c73a4SEric Blake             e->buttons_state &= ~bmap[evt->u.btn->button];
150dcfda673SGerd Hoffmann         }
1518b84286fSGerd Hoffmann         break;
1528b84286fSGerd Hoffmann 
1538b84286fSGerd Hoffmann     default:
1548b84286fSGerd Hoffmann         /* keep gcc happy */
1558b84286fSGerd Hoffmann         break;
156dcfda673SGerd Hoffmann     }
157dcfda673SGerd Hoffmann 
1588b84286fSGerd Hoffmann }
1598b84286fSGerd Hoffmann 
1608b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev)
161dcfda673SGerd Hoffmann {
1628b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1638b84286fSGerd Hoffmann     HIDPointerEvent *prev, *curr, *next;
1648b84286fSGerd Hoffmann     bool event_compression = false;
165dcfda673SGerd Hoffmann 
1668b84286fSGerd Hoffmann     if (hs->n == QUEUE_LENGTH-1) {
1678b84286fSGerd Hoffmann         /*
1685d831be2SStefan Weil          * Queue full.  We are losing information, but we at least
1698b84286fSGerd Hoffmann          * keep track of most recent button state.
1708b84286fSGerd Hoffmann          */
1718b84286fSGerd Hoffmann         return;
172dcfda673SGerd Hoffmann     }
1738b84286fSGerd Hoffmann 
1748b84286fSGerd Hoffmann     prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
1758b84286fSGerd Hoffmann     curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1768b84286fSGerd Hoffmann     next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
1778b84286fSGerd Hoffmann 
1788b84286fSGerd Hoffmann     if (hs->n > 0) {
1798b84286fSGerd Hoffmann         /*
1808b84286fSGerd Hoffmann          * No button state change between previous and current event
1818b84286fSGerd Hoffmann          * (and previous wasn't seen by the guest yet), so there is
1828b84286fSGerd Hoffmann          * motion information only and we can combine the two event
1838b84286fSGerd Hoffmann          * into one.
1848b84286fSGerd Hoffmann          */
1858b84286fSGerd Hoffmann         if (curr->buttons_state == prev->buttons_state) {
1868b84286fSGerd Hoffmann             event_compression = true;
1878b84286fSGerd Hoffmann         }
1888b84286fSGerd Hoffmann     }
1898b84286fSGerd Hoffmann 
1908b84286fSGerd Hoffmann     if (event_compression) {
1918b84286fSGerd Hoffmann         /* add current motion to previous, clear current */
1928b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
1938b84286fSGerd Hoffmann             prev->xdx += curr->xdx;
1948b84286fSGerd Hoffmann             curr->xdx = 0;
19535e83d10SChristian Burger             prev->ydy += curr->ydy;
1968b84286fSGerd Hoffmann             curr->ydy = 0;
1978b84286fSGerd Hoffmann         } else {
1988b84286fSGerd Hoffmann             prev->xdx = curr->xdx;
1998b84286fSGerd Hoffmann             prev->ydy = curr->ydy;
2008b84286fSGerd Hoffmann         }
2018b84286fSGerd Hoffmann         prev->dz += curr->dz;
2028b84286fSGerd Hoffmann         curr->dz = 0;
2038b84286fSGerd Hoffmann     } else {
2048b84286fSGerd Hoffmann         /* prepate next (clear rel, copy abs + btns) */
2058b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
2068b84286fSGerd Hoffmann             next->xdx = 0;
2078b84286fSGerd Hoffmann             next->ydy = 0;
2088b84286fSGerd Hoffmann         } else {
2098b84286fSGerd Hoffmann             next->xdx = curr->xdx;
2108b84286fSGerd Hoffmann             next->ydy = curr->ydy;
2118b84286fSGerd Hoffmann         }
2128b84286fSGerd Hoffmann         next->dz = 0;
2138b84286fSGerd Hoffmann         next->buttons_state = curr->buttons_state;
2148b84286fSGerd Hoffmann         /* make current guest visible, notify guest */
2158b84286fSGerd Hoffmann         hs->n++;
216dcfda673SGerd Hoffmann         hs->event(hs);
217dcfda673SGerd Hoffmann     }
2188b84286fSGerd Hoffmann }
219dcfda673SGerd Hoffmann 
2201ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
2211ff5eeddSGerd Hoffmann                                InputEvent *evt)
222dcfda673SGerd Hoffmann {
2231ff5eeddSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
2241ff5eeddSGerd Hoffmann     int scancodes[3], i, count;
225dcfda673SGerd Hoffmann     int slot;
226dcfda673SGerd Hoffmann 
227568c73a4SEric Blake     count = qemu_input_key_value_to_scancode(evt->u.key->key,
228568c73a4SEric Blake                                              evt->u.key->down,
2291ff5eeddSGerd Hoffmann                                              scancodes);
2301ff5eeddSGerd Hoffmann     if (hs->n + count > QUEUE_LENGTH) {
231dcfda673SGerd Hoffmann         fprintf(stderr, "usb-kbd: warning: key event queue full\n");
232dcfda673SGerd Hoffmann         return;
233dcfda673SGerd Hoffmann     }
2341ff5eeddSGerd Hoffmann     for (i = 0; i < count; i++) {
235dcfda673SGerd Hoffmann         slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
2361ff5eeddSGerd Hoffmann         hs->kbd.keycodes[slot] = scancodes[i];
2371ff5eeddSGerd Hoffmann     }
238dcfda673SGerd Hoffmann     hs->event(hs);
239dcfda673SGerd Hoffmann }
240dcfda673SGerd Hoffmann 
241dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs)
242dcfda673SGerd Hoffmann {
243562f9375SPaolo Bonzini     uint8_t hid_code, index, key;
244dcfda673SGerd Hoffmann     int i, keycode, slot;
245dcfda673SGerd Hoffmann 
246dcfda673SGerd Hoffmann     if (hs->n == 0) {
247dcfda673SGerd Hoffmann         return;
248dcfda673SGerd Hoffmann     }
249dcfda673SGerd Hoffmann     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
250dcfda673SGerd Hoffmann     keycode = hs->kbd.keycodes[slot];
251dcfda673SGerd Hoffmann 
252dcfda673SGerd Hoffmann     key = keycode & 0x7f;
253562f9375SPaolo Bonzini     index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
254562f9375SPaolo Bonzini     hid_code = hid_usage_keys[index];
255dcfda673SGerd Hoffmann     hs->kbd.modifiers &= ~(1 << 8);
256dcfda673SGerd Hoffmann 
257dcfda673SGerd Hoffmann     switch (hid_code) {
258dcfda673SGerd Hoffmann     case 0x00:
259dcfda673SGerd Hoffmann         return;
260dcfda673SGerd Hoffmann 
261dcfda673SGerd Hoffmann     case 0xe0:
262562f9375SPaolo Bonzini         assert(key == 0x1d);
263dcfda673SGerd Hoffmann         if (hs->kbd.modifiers & (1 << 9)) {
264562f9375SPaolo Bonzini             /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
265562f9375SPaolo Bonzini              * Here we're processing the second hid_code.  By dropping bit 9
266562f9375SPaolo Bonzini              * and setting bit 8, the scancode after 0x1d will access the
267562f9375SPaolo Bonzini              * second half of the table.
268562f9375SPaolo Bonzini              */
269562f9375SPaolo Bonzini             hs->kbd.modifiers ^= (1 << 8) | (1 << 9);
270dcfda673SGerd Hoffmann             return;
271dcfda673SGerd Hoffmann         }
272562f9375SPaolo Bonzini         /* fall through to process Ctrl_L */
273dcfda673SGerd Hoffmann     case 0xe1 ... 0xe7:
274562f9375SPaolo Bonzini         /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
275562f9375SPaolo Bonzini          * Handle releases here, or fall through to process presses.
276562f9375SPaolo Bonzini          */
277dcfda673SGerd Hoffmann         if (keycode & (1 << 7)) {
278dcfda673SGerd Hoffmann             hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
279dcfda673SGerd Hoffmann             return;
280dcfda673SGerd Hoffmann         }
281562f9375SPaolo Bonzini         /* fall through */
282562f9375SPaolo Bonzini     case 0xe8 ... 0xe9:
283562f9375SPaolo Bonzini         /* USB modifiers are just 1 byte long.  Bits 8 and 9 of
284562f9375SPaolo Bonzini          * hs->kbd.modifiers implement a state machine that detects the
285562f9375SPaolo Bonzini          * 0xe0 and 0xe1/0x1d sequences.  These bits do not follow the
286562f9375SPaolo Bonzini          * usual rules where bit 7 marks released keys; they are cleared
287562f9375SPaolo Bonzini          * elsewhere in the function as the state machine dictates.
288562f9375SPaolo Bonzini          */
289dcfda673SGerd Hoffmann         hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
290dcfda673SGerd Hoffmann         return;
291562f9375SPaolo Bonzini 
292562f9375SPaolo Bonzini     case 0xea ... 0xef:
293562f9375SPaolo Bonzini         abort();
294562f9375SPaolo Bonzini 
295562f9375SPaolo Bonzini     default:
296562f9375SPaolo Bonzini         break;
297dcfda673SGerd Hoffmann     }
298dcfda673SGerd Hoffmann 
299dcfda673SGerd Hoffmann     if (keycode & (1 << 7)) {
300dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
301dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
302dcfda673SGerd Hoffmann                 hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
303dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys] = 0x00;
304dcfda673SGerd Hoffmann                 break;
305dcfda673SGerd Hoffmann             }
306dcfda673SGerd Hoffmann         }
307dcfda673SGerd Hoffmann         if (i < 0) {
308dcfda673SGerd Hoffmann             return;
309dcfda673SGerd Hoffmann         }
310dcfda673SGerd Hoffmann     } else {
311dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
312dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
313dcfda673SGerd Hoffmann                 break;
314dcfda673SGerd Hoffmann             }
315dcfda673SGerd Hoffmann         }
316dcfda673SGerd Hoffmann         if (i < 0) {
317dcfda673SGerd Hoffmann             if (hs->kbd.keys < sizeof(hs->kbd.key)) {
318dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys++] = hid_code;
319dcfda673SGerd Hoffmann             }
320dcfda673SGerd Hoffmann         } else {
321dcfda673SGerd Hoffmann             return;
322dcfda673SGerd Hoffmann         }
323dcfda673SGerd Hoffmann     }
324dcfda673SGerd Hoffmann }
325dcfda673SGerd Hoffmann 
326dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax)
327dcfda673SGerd Hoffmann {
328dcfda673SGerd Hoffmann     if (val < vmin) {
329dcfda673SGerd Hoffmann         return vmin;
330dcfda673SGerd Hoffmann     } else if (val > vmax) {
331dcfda673SGerd Hoffmann         return vmax;
332dcfda673SGerd Hoffmann     } else {
333dcfda673SGerd Hoffmann         return val;
334dcfda673SGerd Hoffmann     }
335dcfda673SGerd Hoffmann }
336dcfda673SGerd Hoffmann 
33721635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs)
33821635e12SGerd Hoffmann {
33921635e12SGerd Hoffmann     if (!hs->ptr.mouse_grabbed) {
3408b84286fSGerd Hoffmann         qemu_input_handler_activate(hs->s);
34121635e12SGerd Hoffmann         hs->ptr.mouse_grabbed = 1;
34221635e12SGerd Hoffmann     }
34321635e12SGerd Hoffmann }
34421635e12SGerd Hoffmann 
345dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
346dcfda673SGerd Hoffmann {
3478b84286fSGerd Hoffmann     int dx, dy, dz, l;
348dcfda673SGerd Hoffmann     int index;
349dcfda673SGerd Hoffmann     HIDPointerEvent *e;
350dcfda673SGerd Hoffmann 
351027c03f7SHans de Goede     hs->idle_pending = false;
352027c03f7SHans de Goede 
35321635e12SGerd Hoffmann     hid_pointer_activate(hs);
354dcfda673SGerd Hoffmann 
355dcfda673SGerd Hoffmann     /* When the buffer is empty, return the last event.  Relative
356dcfda673SGerd Hoffmann        movements will all be zero.  */
357dcfda673SGerd Hoffmann     index = (hs->n ? hs->head : hs->head - 1);
358dcfda673SGerd Hoffmann     e = &hs->ptr.queue[index & QUEUE_MASK];
359dcfda673SGerd Hoffmann 
360dcfda673SGerd Hoffmann     if (hs->kind == HID_MOUSE) {
361dcfda673SGerd Hoffmann         dx = int_clamp(e->xdx, -127, 127);
362dcfda673SGerd Hoffmann         dy = int_clamp(e->ydy, -127, 127);
363dcfda673SGerd Hoffmann         e->xdx -= dx;
364dcfda673SGerd Hoffmann         e->ydy -= dy;
365dcfda673SGerd Hoffmann     } else {
366dcfda673SGerd Hoffmann         dx = e->xdx;
367dcfda673SGerd Hoffmann         dy = e->ydy;
368dcfda673SGerd Hoffmann     }
369dcfda673SGerd Hoffmann     dz = int_clamp(e->dz, -127, 127);
370dcfda673SGerd Hoffmann     e->dz -= dz;
371dcfda673SGerd Hoffmann 
372dcfda673SGerd Hoffmann     if (hs->n &&
373dcfda673SGerd Hoffmann         !e->dz &&
374dcfda673SGerd Hoffmann         (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
375dcfda673SGerd Hoffmann         /* that deals with this event */
376dcfda673SGerd Hoffmann         QUEUE_INCR(hs->head);
377dcfda673SGerd Hoffmann         hs->n--;
378dcfda673SGerd Hoffmann     }
379dcfda673SGerd Hoffmann 
380dcfda673SGerd Hoffmann     /* Appears we have to invert the wheel direction */
381dcfda673SGerd Hoffmann     dz = 0 - dz;
382dcfda673SGerd Hoffmann     l = 0;
383dcfda673SGerd Hoffmann     switch (hs->kind) {
384dcfda673SGerd Hoffmann     case HID_MOUSE:
385dcfda673SGerd Hoffmann         if (len > l) {
3868b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
387dcfda673SGerd Hoffmann         }
388dcfda673SGerd Hoffmann         if (len > l) {
389dcfda673SGerd Hoffmann             buf[l++] = dx;
390dcfda673SGerd Hoffmann         }
391dcfda673SGerd Hoffmann         if (len > l) {
392dcfda673SGerd Hoffmann             buf[l++] = dy;
393dcfda673SGerd Hoffmann         }
394dcfda673SGerd Hoffmann         if (len > l) {
395dcfda673SGerd Hoffmann             buf[l++] = dz;
396dcfda673SGerd Hoffmann         }
397dcfda673SGerd Hoffmann         break;
398dcfda673SGerd Hoffmann 
399dcfda673SGerd Hoffmann     case HID_TABLET:
400dcfda673SGerd Hoffmann         if (len > l) {
4018b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
402dcfda673SGerd Hoffmann         }
403dcfda673SGerd Hoffmann         if (len > l) {
404dcfda673SGerd Hoffmann             buf[l++] = dx & 0xff;
405dcfda673SGerd Hoffmann         }
406dcfda673SGerd Hoffmann         if (len > l) {
407dcfda673SGerd Hoffmann             buf[l++] = dx >> 8;
408dcfda673SGerd Hoffmann         }
409dcfda673SGerd Hoffmann         if (len > l) {
410dcfda673SGerd Hoffmann             buf[l++] = dy & 0xff;
411dcfda673SGerd Hoffmann         }
412dcfda673SGerd Hoffmann         if (len > l) {
413dcfda673SGerd Hoffmann             buf[l++] = dy >> 8;
414dcfda673SGerd Hoffmann         }
415dcfda673SGerd Hoffmann         if (len > l) {
416dcfda673SGerd Hoffmann             buf[l++] = dz;
417dcfda673SGerd Hoffmann         }
418dcfda673SGerd Hoffmann         break;
419dcfda673SGerd Hoffmann 
420dcfda673SGerd Hoffmann     default:
421dcfda673SGerd Hoffmann         abort();
422dcfda673SGerd Hoffmann     }
423dcfda673SGerd Hoffmann 
424dcfda673SGerd Hoffmann     return l;
425dcfda673SGerd Hoffmann }
426dcfda673SGerd Hoffmann 
427dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
428dcfda673SGerd Hoffmann {
429027c03f7SHans de Goede     hs->idle_pending = false;
430027c03f7SHans de Goede 
431dcfda673SGerd Hoffmann     if (len < 2) {
432dcfda673SGerd Hoffmann         return 0;
433dcfda673SGerd Hoffmann     }
434dcfda673SGerd Hoffmann 
435dcfda673SGerd Hoffmann     hid_keyboard_process_keycode(hs);
436dcfda673SGerd Hoffmann 
437dcfda673SGerd Hoffmann     buf[0] = hs->kbd.modifiers & 0xff;
438dcfda673SGerd Hoffmann     buf[1] = 0;
439dcfda673SGerd Hoffmann     if (hs->kbd.keys > 6) {
440dcfda673SGerd Hoffmann         memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
441dcfda673SGerd Hoffmann     } else {
442dcfda673SGerd Hoffmann         memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
443dcfda673SGerd Hoffmann     }
444dcfda673SGerd Hoffmann 
445dcfda673SGerd Hoffmann     return MIN(8, len);
446dcfda673SGerd Hoffmann }
447dcfda673SGerd Hoffmann 
448dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
449dcfda673SGerd Hoffmann {
450dcfda673SGerd Hoffmann     if (len > 0) {
451dcfda673SGerd Hoffmann         int ledstate = 0;
452dcfda673SGerd Hoffmann         /* 0x01: Num Lock LED
453dcfda673SGerd Hoffmann          * 0x02: Caps Lock LED
454dcfda673SGerd Hoffmann          * 0x04: Scroll Lock LED
455dcfda673SGerd Hoffmann          * 0x08: Compose LED
456dcfda673SGerd Hoffmann          * 0x10: Kana LED */
457dcfda673SGerd Hoffmann         hs->kbd.leds = buf[0];
458dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x04) {
459dcfda673SGerd Hoffmann             ledstate |= QEMU_SCROLL_LOCK_LED;
460dcfda673SGerd Hoffmann         }
461dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x01) {
462dcfda673SGerd Hoffmann             ledstate |= QEMU_NUM_LOCK_LED;
463dcfda673SGerd Hoffmann         }
464dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x02) {
465dcfda673SGerd Hoffmann             ledstate |= QEMU_CAPS_LOCK_LED;
466dcfda673SGerd Hoffmann         }
467dcfda673SGerd Hoffmann         kbd_put_ledstate(ledstate);
468dcfda673SGerd Hoffmann     }
469dcfda673SGerd Hoffmann     return 0;
470dcfda673SGerd Hoffmann }
471dcfda673SGerd Hoffmann 
472dcfda673SGerd Hoffmann void hid_reset(HIDState *hs)
473dcfda673SGerd Hoffmann {
474dcfda673SGerd Hoffmann     switch (hs->kind) {
475dcfda673SGerd Hoffmann     case HID_KEYBOARD:
476dcfda673SGerd Hoffmann         memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
477dcfda673SGerd Hoffmann         memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
478dcfda673SGerd Hoffmann         hs->kbd.keys = 0;
479dcfda673SGerd Hoffmann         break;
480dcfda673SGerd Hoffmann     case HID_MOUSE:
481dcfda673SGerd Hoffmann     case HID_TABLET:
482dcfda673SGerd Hoffmann         memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
483dcfda673SGerd Hoffmann         break;
484dcfda673SGerd Hoffmann     }
485dcfda673SGerd Hoffmann     hs->head = 0;
486dcfda673SGerd Hoffmann     hs->n = 0;
487b069d348SGerd Hoffmann     hs->protocol = 1;
488b069d348SGerd Hoffmann     hs->idle = 0;
489027c03f7SHans de Goede     hs->idle_pending = false;
490027c03f7SHans de Goede     hid_del_idle_timer(hs);
491dcfda673SGerd Hoffmann }
492dcfda673SGerd Hoffmann 
493dcfda673SGerd Hoffmann void hid_free(HIDState *hs)
494dcfda673SGerd Hoffmann {
4951ff5eeddSGerd Hoffmann     qemu_input_handler_unregister(hs->s);
496027c03f7SHans de Goede     hid_del_idle_timer(hs);
497dcfda673SGerd Hoffmann }
498dcfda673SGerd Hoffmann 
4991ff5eeddSGerd Hoffmann static QemuInputHandler hid_keyboard_handler = {
5001ff5eeddSGerd Hoffmann     .name  = "QEMU HID Keyboard",
5011ff5eeddSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
5021ff5eeddSGerd Hoffmann     .event = hid_keyboard_event,
5031ff5eeddSGerd Hoffmann };
5041ff5eeddSGerd Hoffmann 
5058b84286fSGerd Hoffmann static QemuInputHandler hid_mouse_handler = {
5068b84286fSGerd Hoffmann     .name  = "QEMU HID Mouse",
5078b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
5088b84286fSGerd Hoffmann     .event = hid_pointer_event,
5098b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
5108b84286fSGerd Hoffmann };
5118b84286fSGerd Hoffmann 
5128b84286fSGerd Hoffmann static QemuInputHandler hid_tablet_handler = {
5138b84286fSGerd Hoffmann     .name  = "QEMU HID Tablet",
5148b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
5158b84286fSGerd Hoffmann     .event = hid_pointer_event,
5168b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
5178b84286fSGerd Hoffmann };
5188b84286fSGerd Hoffmann 
519dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event)
520dcfda673SGerd Hoffmann {
521dcfda673SGerd Hoffmann     hs->kind = kind;
522dcfda673SGerd Hoffmann     hs->event = event;
523dcfda673SGerd Hoffmann 
524bb0db527SMichael Walle     if (hs->kind == HID_KEYBOARD) {
5251ff5eeddSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5261ff5eeddSGerd Hoffmann                                             &hid_keyboard_handler);
5271ff5eeddSGerd Hoffmann         qemu_input_handler_activate(hs->s);
528bb0db527SMichael Walle     } else if (hs->kind == HID_MOUSE) {
5298b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5308b84286fSGerd Hoffmann                                             &hid_mouse_handler);
531dcfda673SGerd Hoffmann     } else if (hs->kind == HID_TABLET) {
5328b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5338b84286fSGerd Hoffmann                                             &hid_tablet_handler);
534dcfda673SGerd Hoffmann     }
535dcfda673SGerd Hoffmann }
536ccd4ed06SMichael Walle 
537ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id)
538ccd4ed06SMichael Walle {
539ccd4ed06SMichael Walle     HIDState *s = opaque;
540ccd4ed06SMichael Walle 
541027c03f7SHans de Goede     hid_set_next_idle(s);
542ba4d2606SGerd Hoffmann 
543ba4d2606SGerd Hoffmann     if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
544ba4d2606SGerd Hoffmann                                  s->kind == HID_MOUSE)) {
545ba4d2606SGerd Hoffmann         /*
546ba4d2606SGerd Hoffmann          * Handle ptr device migration from old qemu with full queue.
547ba4d2606SGerd Hoffmann          *
548ba4d2606SGerd Hoffmann          * Throw away everything but the last event, so we propagate
549ba4d2606SGerd Hoffmann          * at least the current button state to the guest.  Also keep
550ba4d2606SGerd Hoffmann          * current position for the tablet, signal "no motion" for the
551ba4d2606SGerd Hoffmann          * mouse.
552ba4d2606SGerd Hoffmann          */
553ba4d2606SGerd Hoffmann         HIDPointerEvent evt;
554ba4d2606SGerd Hoffmann         evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
555ba4d2606SGerd Hoffmann         if (s->kind == HID_MOUSE) {
556ba4d2606SGerd Hoffmann             evt.xdx = 0;
557ba4d2606SGerd Hoffmann             evt.ydy = 0;
558ba4d2606SGerd Hoffmann         }
559ba4d2606SGerd Hoffmann         s->ptr.queue[0] = evt;
560ba4d2606SGerd Hoffmann         s->head = 0;
561ba4d2606SGerd Hoffmann         s->n = 1;
562ba4d2606SGerd Hoffmann     }
563ccd4ed06SMichael Walle     return 0;
564ccd4ed06SMichael Walle }
565ccd4ed06SMichael Walle 
566ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = {
567ccd4ed06SMichael Walle     .name = "HIDPointerEventQueue",
568ccd4ed06SMichael Walle     .version_id = 1,
569ccd4ed06SMichael Walle     .minimum_version_id = 1,
570ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
571ccd4ed06SMichael Walle         VMSTATE_INT32(xdx, HIDPointerEvent),
572ccd4ed06SMichael Walle         VMSTATE_INT32(ydy, HIDPointerEvent),
573ccd4ed06SMichael Walle         VMSTATE_INT32(dz, HIDPointerEvent),
574ccd4ed06SMichael Walle         VMSTATE_INT32(buttons_state, HIDPointerEvent),
575ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST()
576ccd4ed06SMichael Walle     }
577ccd4ed06SMichael Walle };
578ccd4ed06SMichael Walle 
579ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = {
580ccd4ed06SMichael Walle     .name = "HIDPointerDevice",
581ccd4ed06SMichael Walle     .version_id = 1,
582ccd4ed06SMichael Walle     .minimum_version_id = 1,
583ccd4ed06SMichael Walle     .post_load = hid_post_load,
584ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
585ccd4ed06SMichael Walle         VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
586ccd4ed06SMichael Walle                              vmstate_hid_ptr_queue, HIDPointerEvent),
587ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
588ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
589ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
590ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
591ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
592ccd4ed06SMichael Walle     }
593ccd4ed06SMichael Walle };
594ccd4ed06SMichael Walle 
595ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = {
596ccd4ed06SMichael Walle     .name = "HIDKeyboardDevice",
597ccd4ed06SMichael Walle     .version_id = 1,
598ccd4ed06SMichael Walle     .minimum_version_id = 1,
599ccd4ed06SMichael Walle     .post_load = hid_post_load,
600ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
601ccd4ed06SMichael Walle         VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
602ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
603ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
604ccd4ed06SMichael Walle         VMSTATE_UINT16(kbd.modifiers, HIDState),
605ccd4ed06SMichael Walle         VMSTATE_UINT8(kbd.leds, HIDState),
606ccd4ed06SMichael Walle         VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
607ccd4ed06SMichael Walle         VMSTATE_INT32(kbd.keys, HIDState),
608ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
609ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
610ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
611ccd4ed06SMichael Walle     }
612ccd4ed06SMichael Walle };
613