xref: /qemu/hw/input/hid.c (revision 86f3bf0ebec1df6e7fd2dd5a4e76cbbcd2d1b01e)
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"
30c80276b4SGerd Hoffmann #include "trace.h"
31dcfda673SGerd Hoffmann 
32dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_ROLLOVER        0x01
33dcfda673SGerd Hoffmann #define HID_USAGE_POSTFAIL              0x02
34dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_UNDEFINED       0x03
35dcfda673SGerd Hoffmann 
36dcfda673SGerd Hoffmann /* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
37dcfda673SGerd Hoffmann  * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
38dcfda673SGerd Hoffmann static const uint8_t hid_usage_keys[0x100] = {
39dcfda673SGerd Hoffmann     0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
40dcfda673SGerd Hoffmann     0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
41dcfda673SGerd Hoffmann     0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
42dcfda673SGerd Hoffmann     0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
43dcfda673SGerd Hoffmann     0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
44dcfda673SGerd Hoffmann     0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
45dcfda673SGerd Hoffmann     0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
460ee4de58SDinar Valeev     0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
47dcfda673SGerd Hoffmann     0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
48dcfda673SGerd Hoffmann     0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
49*86f3bf0eSPeter Korsgaard     0x5a, 0x5b, 0x62, 0x63, 0x46, 0x00, 0x64, 0x44,
50dcfda673SGerd Hoffmann     0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
51dcfda673SGerd Hoffmann     0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
52dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
53dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
55dcfda673SGerd Hoffmann 
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, 0x00, 0x00, 0x00, 0x00,
59dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
60dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
63dcfda673SGerd Hoffmann     0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64*86f3bf0eSPeter Korsgaard     0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x4a,
65dcfda673SGerd Hoffmann     0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
66dcfda673SGerd Hoffmann     0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
67dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 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     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72dcfda673SGerd Hoffmann };
73dcfda673SGerd Hoffmann 
74dcfda673SGerd Hoffmann bool hid_has_events(HIDState *hs)
75dcfda673SGerd Hoffmann {
76027c03f7SHans de Goede     return hs->n > 0 || hs->idle_pending;
77dcfda673SGerd Hoffmann }
78dcfda673SGerd Hoffmann 
79027c03f7SHans de Goede static void hid_idle_timer(void *opaque)
80b069d348SGerd Hoffmann {
81027c03f7SHans de Goede     HIDState *hs = opaque;
82027c03f7SHans de Goede 
83027c03f7SHans de Goede     hs->idle_pending = true;
84027c03f7SHans de Goede     hs->event(hs);
85027c03f7SHans de Goede }
86027c03f7SHans de Goede 
87027c03f7SHans de Goede static void hid_del_idle_timer(HIDState *hs)
88027c03f7SHans de Goede {
89027c03f7SHans de Goede     if (hs->idle_timer) {
90bc72ad67SAlex Bligh         timer_del(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 
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 
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,
1178b84286fSGerd Hoffmann     };
1188b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1198b84286fSGerd Hoffmann     HIDPointerEvent *e;
120b5a1b443SEric Blake     InputMoveEvent *move;
121b5a1b443SEric Blake     InputBtnEvent *btn;
122dcfda673SGerd Hoffmann 
1238b84286fSGerd Hoffmann     assert(hs->n < QUEUE_LENGTH);
1248b84286fSGerd Hoffmann     e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1258b84286fSGerd Hoffmann 
126568c73a4SEric Blake     switch (evt->type) {
1278b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_REL:
12832bafa8fSEric Blake         move = evt->u.rel.data;
129b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
130b5a1b443SEric Blake             e->xdx += move->value;
131b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
132b5a1b443SEric Blake             e->ydy += move->value;
1338b84286fSGerd Hoffmann         }
1348b84286fSGerd Hoffmann         break;
1358b84286fSGerd Hoffmann 
1368b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_ABS:
13732bafa8fSEric Blake         move = evt->u.abs.data;
138b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
139b5a1b443SEric Blake             e->xdx = move->value;
140b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
141b5a1b443SEric Blake             e->ydy = move->value;
1428b84286fSGerd Hoffmann         }
1438b84286fSGerd Hoffmann         break;
1448b84286fSGerd Hoffmann 
1458b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
14632bafa8fSEric Blake         btn = evt->u.btn.data;
147b5a1b443SEric Blake         if (btn->down) {
148b5a1b443SEric Blake             e->buttons_state |= bmap[btn->button];
149b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
1508b84286fSGerd Hoffmann                 e->dz--;
151b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
1528b84286fSGerd Hoffmann                 e->dz++;
1538b84286fSGerd Hoffmann             }
154dcfda673SGerd Hoffmann         } else {
155b5a1b443SEric Blake             e->buttons_state &= ~bmap[btn->button];
156dcfda673SGerd Hoffmann         }
1578b84286fSGerd Hoffmann         break;
1588b84286fSGerd Hoffmann 
1598b84286fSGerd Hoffmann     default:
1608b84286fSGerd Hoffmann         /* keep gcc happy */
1618b84286fSGerd Hoffmann         break;
162dcfda673SGerd Hoffmann     }
163dcfda673SGerd Hoffmann 
1648b84286fSGerd Hoffmann }
1658b84286fSGerd Hoffmann 
1668b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev)
167dcfda673SGerd Hoffmann {
1688b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1698b84286fSGerd Hoffmann     HIDPointerEvent *prev, *curr, *next;
1708b84286fSGerd Hoffmann     bool event_compression = false;
171dcfda673SGerd Hoffmann 
1728b84286fSGerd Hoffmann     if (hs->n == QUEUE_LENGTH-1) {
1738b84286fSGerd Hoffmann         /*
1745d831be2SStefan Weil          * Queue full.  We are losing information, but we at least
1758b84286fSGerd Hoffmann          * keep track of most recent button state.
1768b84286fSGerd Hoffmann          */
1778b84286fSGerd Hoffmann         return;
178dcfda673SGerd Hoffmann     }
1798b84286fSGerd Hoffmann 
1808b84286fSGerd Hoffmann     prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
1818b84286fSGerd Hoffmann     curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1828b84286fSGerd Hoffmann     next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
1838b84286fSGerd Hoffmann 
1848b84286fSGerd Hoffmann     if (hs->n > 0) {
1858b84286fSGerd Hoffmann         /*
1868b84286fSGerd Hoffmann          * No button state change between previous and current event
1878b84286fSGerd Hoffmann          * (and previous wasn't seen by the guest yet), so there is
1888b84286fSGerd Hoffmann          * motion information only and we can combine the two event
1898b84286fSGerd Hoffmann          * into one.
1908b84286fSGerd Hoffmann          */
1918b84286fSGerd Hoffmann         if (curr->buttons_state == prev->buttons_state) {
1928b84286fSGerd Hoffmann             event_compression = true;
1938b84286fSGerd Hoffmann         }
1948b84286fSGerd Hoffmann     }
1958b84286fSGerd Hoffmann 
1968b84286fSGerd Hoffmann     if (event_compression) {
1978b84286fSGerd Hoffmann         /* add current motion to previous, clear current */
1988b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
1998b84286fSGerd Hoffmann             prev->xdx += curr->xdx;
2008b84286fSGerd Hoffmann             curr->xdx = 0;
20135e83d10SChristian Burger             prev->ydy += curr->ydy;
2028b84286fSGerd Hoffmann             curr->ydy = 0;
2038b84286fSGerd Hoffmann         } else {
2048b84286fSGerd Hoffmann             prev->xdx = curr->xdx;
2058b84286fSGerd Hoffmann             prev->ydy = curr->ydy;
2068b84286fSGerd Hoffmann         }
2078b84286fSGerd Hoffmann         prev->dz += curr->dz;
2088b84286fSGerd Hoffmann         curr->dz = 0;
2098b84286fSGerd Hoffmann     } else {
2108b84286fSGerd Hoffmann         /* prepate next (clear rel, copy abs + btns) */
2118b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
2128b84286fSGerd Hoffmann             next->xdx = 0;
2138b84286fSGerd Hoffmann             next->ydy = 0;
2148b84286fSGerd Hoffmann         } else {
2158b84286fSGerd Hoffmann             next->xdx = curr->xdx;
2168b84286fSGerd Hoffmann             next->ydy = curr->ydy;
2178b84286fSGerd Hoffmann         }
2188b84286fSGerd Hoffmann         next->dz = 0;
2198b84286fSGerd Hoffmann         next->buttons_state = curr->buttons_state;
2208b84286fSGerd Hoffmann         /* make current guest visible, notify guest */
2218b84286fSGerd Hoffmann         hs->n++;
222dcfda673SGerd Hoffmann         hs->event(hs);
223dcfda673SGerd Hoffmann     }
2248b84286fSGerd Hoffmann }
225dcfda673SGerd Hoffmann 
2261ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
2271ff5eeddSGerd Hoffmann                                InputEvent *evt)
228dcfda673SGerd Hoffmann {
2291ff5eeddSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
2301ff5eeddSGerd Hoffmann     int scancodes[3], i, count;
231dcfda673SGerd Hoffmann     int slot;
23232bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
233dcfda673SGerd Hoffmann 
234b5a1b443SEric Blake     count = qemu_input_key_value_to_scancode(key->key,
235b5a1b443SEric Blake                                              key->down,
2361ff5eeddSGerd Hoffmann                                              scancodes);
2371ff5eeddSGerd Hoffmann     if (hs->n + count > QUEUE_LENGTH) {
238c80276b4SGerd Hoffmann         trace_hid_kbd_queue_full();
239dcfda673SGerd Hoffmann         return;
240dcfda673SGerd Hoffmann     }
2411ff5eeddSGerd Hoffmann     for (i = 0; i < count; i++) {
242dcfda673SGerd Hoffmann         slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
2431ff5eeddSGerd Hoffmann         hs->kbd.keycodes[slot] = scancodes[i];
2441ff5eeddSGerd Hoffmann     }
245dcfda673SGerd Hoffmann     hs->event(hs);
246dcfda673SGerd Hoffmann }
247dcfda673SGerd Hoffmann 
248dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs)
249dcfda673SGerd Hoffmann {
250562f9375SPaolo Bonzini     uint8_t hid_code, index, key;
251dcfda673SGerd Hoffmann     int i, keycode, slot;
252dcfda673SGerd Hoffmann 
253dcfda673SGerd Hoffmann     if (hs->n == 0) {
254dcfda673SGerd Hoffmann         return;
255dcfda673SGerd Hoffmann     }
256dcfda673SGerd Hoffmann     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
257dcfda673SGerd Hoffmann     keycode = hs->kbd.keycodes[slot];
258dcfda673SGerd Hoffmann 
259dcfda673SGerd Hoffmann     key = keycode & 0x7f;
260562f9375SPaolo Bonzini     index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
261562f9375SPaolo Bonzini     hid_code = hid_usage_keys[index];
262dcfda673SGerd Hoffmann     hs->kbd.modifiers &= ~(1 << 8);
263dcfda673SGerd Hoffmann 
264dcfda673SGerd Hoffmann     switch (hid_code) {
265dcfda673SGerd Hoffmann     case 0x00:
266dcfda673SGerd Hoffmann         return;
267dcfda673SGerd Hoffmann 
268dcfda673SGerd Hoffmann     case 0xe0:
269562f9375SPaolo Bonzini         assert(key == 0x1d);
270dcfda673SGerd Hoffmann         if (hs->kbd.modifiers & (1 << 9)) {
271562f9375SPaolo Bonzini             /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
272562f9375SPaolo Bonzini              * Here we're processing the second hid_code.  By dropping bit 9
273562f9375SPaolo Bonzini              * and setting bit 8, the scancode after 0x1d will access the
274562f9375SPaolo Bonzini              * second half of the table.
275562f9375SPaolo Bonzini              */
276562f9375SPaolo Bonzini             hs->kbd.modifiers ^= (1 << 8) | (1 << 9);
277dcfda673SGerd Hoffmann             return;
278dcfda673SGerd Hoffmann         }
279562f9375SPaolo Bonzini         /* fall through to process Ctrl_L */
280dcfda673SGerd Hoffmann     case 0xe1 ... 0xe7:
281562f9375SPaolo Bonzini         /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
282562f9375SPaolo Bonzini          * Handle releases here, or fall through to process presses.
283562f9375SPaolo Bonzini          */
284dcfda673SGerd Hoffmann         if (keycode & (1 << 7)) {
285dcfda673SGerd Hoffmann             hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
286dcfda673SGerd Hoffmann             return;
287dcfda673SGerd Hoffmann         }
288562f9375SPaolo Bonzini         /* fall through */
289562f9375SPaolo Bonzini     case 0xe8 ... 0xe9:
290562f9375SPaolo Bonzini         /* USB modifiers are just 1 byte long.  Bits 8 and 9 of
291562f9375SPaolo Bonzini          * hs->kbd.modifiers implement a state machine that detects the
292562f9375SPaolo Bonzini          * 0xe0 and 0xe1/0x1d sequences.  These bits do not follow the
293562f9375SPaolo Bonzini          * usual rules where bit 7 marks released keys; they are cleared
294562f9375SPaolo Bonzini          * elsewhere in the function as the state machine dictates.
295562f9375SPaolo Bonzini          */
296dcfda673SGerd Hoffmann         hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
297dcfda673SGerd Hoffmann         return;
298562f9375SPaolo Bonzini 
299562f9375SPaolo Bonzini     case 0xea ... 0xef:
300562f9375SPaolo Bonzini         abort();
301562f9375SPaolo Bonzini 
302562f9375SPaolo Bonzini     default:
303562f9375SPaolo Bonzini         break;
304dcfda673SGerd Hoffmann     }
305dcfda673SGerd Hoffmann 
306dcfda673SGerd Hoffmann     if (keycode & (1 << 7)) {
307dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
308dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
309dcfda673SGerd Hoffmann                 hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
310dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys] = 0x00;
311dcfda673SGerd Hoffmann                 break;
312dcfda673SGerd Hoffmann             }
313dcfda673SGerd Hoffmann         }
314dcfda673SGerd Hoffmann         if (i < 0) {
315dcfda673SGerd Hoffmann             return;
316dcfda673SGerd Hoffmann         }
317dcfda673SGerd Hoffmann     } else {
318dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
319dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
320dcfda673SGerd Hoffmann                 break;
321dcfda673SGerd Hoffmann             }
322dcfda673SGerd Hoffmann         }
323dcfda673SGerd Hoffmann         if (i < 0) {
324dcfda673SGerd Hoffmann             if (hs->kbd.keys < sizeof(hs->kbd.key)) {
325dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys++] = hid_code;
326dcfda673SGerd Hoffmann             }
327dcfda673SGerd Hoffmann         } else {
328dcfda673SGerd Hoffmann             return;
329dcfda673SGerd Hoffmann         }
330dcfda673SGerd Hoffmann     }
331dcfda673SGerd Hoffmann }
332dcfda673SGerd Hoffmann 
333dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax)
334dcfda673SGerd Hoffmann {
335dcfda673SGerd Hoffmann     if (val < vmin) {
336dcfda673SGerd Hoffmann         return vmin;
337dcfda673SGerd Hoffmann     } else if (val > vmax) {
338dcfda673SGerd Hoffmann         return vmax;
339dcfda673SGerd Hoffmann     } else {
340dcfda673SGerd Hoffmann         return val;
341dcfda673SGerd Hoffmann     }
342dcfda673SGerd Hoffmann }
343dcfda673SGerd Hoffmann 
34421635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs)
34521635e12SGerd Hoffmann {
34621635e12SGerd Hoffmann     if (!hs->ptr.mouse_grabbed) {
3478b84286fSGerd Hoffmann         qemu_input_handler_activate(hs->s);
34821635e12SGerd Hoffmann         hs->ptr.mouse_grabbed = 1;
34921635e12SGerd Hoffmann     }
35021635e12SGerd Hoffmann }
35121635e12SGerd Hoffmann 
352dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
353dcfda673SGerd Hoffmann {
3548b84286fSGerd Hoffmann     int dx, dy, dz, l;
355dcfda673SGerd Hoffmann     int index;
356dcfda673SGerd Hoffmann     HIDPointerEvent *e;
357dcfda673SGerd Hoffmann 
358027c03f7SHans de Goede     hs->idle_pending = false;
359027c03f7SHans de Goede 
36021635e12SGerd Hoffmann     hid_pointer_activate(hs);
361dcfda673SGerd Hoffmann 
362dcfda673SGerd Hoffmann     /* When the buffer is empty, return the last event.  Relative
363dcfda673SGerd Hoffmann        movements will all be zero.  */
364dcfda673SGerd Hoffmann     index = (hs->n ? hs->head : hs->head - 1);
365dcfda673SGerd Hoffmann     e = &hs->ptr.queue[index & QUEUE_MASK];
366dcfda673SGerd Hoffmann 
367dcfda673SGerd Hoffmann     if (hs->kind == HID_MOUSE) {
368dcfda673SGerd Hoffmann         dx = int_clamp(e->xdx, -127, 127);
369dcfda673SGerd Hoffmann         dy = int_clamp(e->ydy, -127, 127);
370dcfda673SGerd Hoffmann         e->xdx -= dx;
371dcfda673SGerd Hoffmann         e->ydy -= dy;
372dcfda673SGerd Hoffmann     } else {
373dcfda673SGerd Hoffmann         dx = e->xdx;
374dcfda673SGerd Hoffmann         dy = e->ydy;
375dcfda673SGerd Hoffmann     }
376dcfda673SGerd Hoffmann     dz = int_clamp(e->dz, -127, 127);
377dcfda673SGerd Hoffmann     e->dz -= dz;
378dcfda673SGerd Hoffmann 
379dcfda673SGerd Hoffmann     if (hs->n &&
380dcfda673SGerd Hoffmann         !e->dz &&
381dcfda673SGerd Hoffmann         (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
382dcfda673SGerd Hoffmann         /* that deals with this event */
383dcfda673SGerd Hoffmann         QUEUE_INCR(hs->head);
384dcfda673SGerd Hoffmann         hs->n--;
385dcfda673SGerd Hoffmann     }
386dcfda673SGerd Hoffmann 
387dcfda673SGerd Hoffmann     /* Appears we have to invert the wheel direction */
388dcfda673SGerd Hoffmann     dz = 0 - dz;
389dcfda673SGerd Hoffmann     l = 0;
390dcfda673SGerd Hoffmann     switch (hs->kind) {
391dcfda673SGerd Hoffmann     case HID_MOUSE:
392dcfda673SGerd Hoffmann         if (len > l) {
3938b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
394dcfda673SGerd Hoffmann         }
395dcfda673SGerd Hoffmann         if (len > l) {
396dcfda673SGerd Hoffmann             buf[l++] = dx;
397dcfda673SGerd Hoffmann         }
398dcfda673SGerd Hoffmann         if (len > l) {
399dcfda673SGerd Hoffmann             buf[l++] = dy;
400dcfda673SGerd Hoffmann         }
401dcfda673SGerd Hoffmann         if (len > l) {
402dcfda673SGerd Hoffmann             buf[l++] = dz;
403dcfda673SGerd Hoffmann         }
404dcfda673SGerd Hoffmann         break;
405dcfda673SGerd Hoffmann 
406dcfda673SGerd Hoffmann     case HID_TABLET:
407dcfda673SGerd Hoffmann         if (len > l) {
4088b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
409dcfda673SGerd Hoffmann         }
410dcfda673SGerd Hoffmann         if (len > l) {
411dcfda673SGerd Hoffmann             buf[l++] = dx & 0xff;
412dcfda673SGerd Hoffmann         }
413dcfda673SGerd Hoffmann         if (len > l) {
414dcfda673SGerd Hoffmann             buf[l++] = dx >> 8;
415dcfda673SGerd Hoffmann         }
416dcfda673SGerd Hoffmann         if (len > l) {
417dcfda673SGerd Hoffmann             buf[l++] = dy & 0xff;
418dcfda673SGerd Hoffmann         }
419dcfda673SGerd Hoffmann         if (len > l) {
420dcfda673SGerd Hoffmann             buf[l++] = dy >> 8;
421dcfda673SGerd Hoffmann         }
422dcfda673SGerd Hoffmann         if (len > l) {
423dcfda673SGerd Hoffmann             buf[l++] = dz;
424dcfda673SGerd Hoffmann         }
425dcfda673SGerd Hoffmann         break;
426dcfda673SGerd Hoffmann 
427dcfda673SGerd Hoffmann     default:
428dcfda673SGerd Hoffmann         abort();
429dcfda673SGerd Hoffmann     }
430dcfda673SGerd Hoffmann 
431dcfda673SGerd Hoffmann     return l;
432dcfda673SGerd Hoffmann }
433dcfda673SGerd Hoffmann 
434dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
435dcfda673SGerd Hoffmann {
436027c03f7SHans de Goede     hs->idle_pending = false;
437027c03f7SHans de Goede 
438dcfda673SGerd Hoffmann     if (len < 2) {
439dcfda673SGerd Hoffmann         return 0;
440dcfda673SGerd Hoffmann     }
441dcfda673SGerd Hoffmann 
442dcfda673SGerd Hoffmann     hid_keyboard_process_keycode(hs);
443dcfda673SGerd Hoffmann 
444dcfda673SGerd Hoffmann     buf[0] = hs->kbd.modifiers & 0xff;
445dcfda673SGerd Hoffmann     buf[1] = 0;
446dcfda673SGerd Hoffmann     if (hs->kbd.keys > 6) {
447dcfda673SGerd Hoffmann         memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
448dcfda673SGerd Hoffmann     } else {
449dcfda673SGerd Hoffmann         memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
450dcfda673SGerd Hoffmann     }
451dcfda673SGerd Hoffmann 
452dcfda673SGerd Hoffmann     return MIN(8, len);
453dcfda673SGerd Hoffmann }
454dcfda673SGerd Hoffmann 
455dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
456dcfda673SGerd Hoffmann {
457dcfda673SGerd Hoffmann     if (len > 0) {
458dcfda673SGerd Hoffmann         int ledstate = 0;
459dcfda673SGerd Hoffmann         /* 0x01: Num Lock LED
460dcfda673SGerd Hoffmann          * 0x02: Caps Lock LED
461dcfda673SGerd Hoffmann          * 0x04: Scroll Lock LED
462dcfda673SGerd Hoffmann          * 0x08: Compose LED
463dcfda673SGerd Hoffmann          * 0x10: Kana LED */
464dcfda673SGerd Hoffmann         hs->kbd.leds = buf[0];
465dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x04) {
466dcfda673SGerd Hoffmann             ledstate |= QEMU_SCROLL_LOCK_LED;
467dcfda673SGerd Hoffmann         }
468dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x01) {
469dcfda673SGerd Hoffmann             ledstate |= QEMU_NUM_LOCK_LED;
470dcfda673SGerd Hoffmann         }
471dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x02) {
472dcfda673SGerd Hoffmann             ledstate |= QEMU_CAPS_LOCK_LED;
473dcfda673SGerd Hoffmann         }
474dcfda673SGerd Hoffmann         kbd_put_ledstate(ledstate);
475dcfda673SGerd Hoffmann     }
476dcfda673SGerd Hoffmann     return 0;
477dcfda673SGerd Hoffmann }
478dcfda673SGerd Hoffmann 
479dcfda673SGerd Hoffmann void hid_reset(HIDState *hs)
480dcfda673SGerd Hoffmann {
481dcfda673SGerd Hoffmann     switch (hs->kind) {
482dcfda673SGerd Hoffmann     case HID_KEYBOARD:
483dcfda673SGerd Hoffmann         memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
484dcfda673SGerd Hoffmann         memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
485dcfda673SGerd Hoffmann         hs->kbd.keys = 0;
486dcfda673SGerd Hoffmann         break;
487dcfda673SGerd Hoffmann     case HID_MOUSE:
488dcfda673SGerd Hoffmann     case HID_TABLET:
489dcfda673SGerd Hoffmann         memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
490dcfda673SGerd Hoffmann         break;
491dcfda673SGerd Hoffmann     }
492dcfda673SGerd Hoffmann     hs->head = 0;
493dcfda673SGerd Hoffmann     hs->n = 0;
494b069d348SGerd Hoffmann     hs->protocol = 1;
495b069d348SGerd Hoffmann     hs->idle = 0;
496027c03f7SHans de Goede     hs->idle_pending = false;
497027c03f7SHans de Goede     hid_del_idle_timer(hs);
498dcfda673SGerd Hoffmann }
499dcfda673SGerd Hoffmann 
500dcfda673SGerd Hoffmann void hid_free(HIDState *hs)
501dcfda673SGerd Hoffmann {
5021ff5eeddSGerd Hoffmann     qemu_input_handler_unregister(hs->s);
503027c03f7SHans de Goede     hid_del_idle_timer(hs);
504dcfda673SGerd Hoffmann }
505dcfda673SGerd Hoffmann 
5061ff5eeddSGerd Hoffmann static QemuInputHandler hid_keyboard_handler = {
5071ff5eeddSGerd Hoffmann     .name  = "QEMU HID Keyboard",
5081ff5eeddSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
5091ff5eeddSGerd Hoffmann     .event = hid_keyboard_event,
5101ff5eeddSGerd Hoffmann };
5111ff5eeddSGerd Hoffmann 
5128b84286fSGerd Hoffmann static QemuInputHandler hid_mouse_handler = {
5138b84286fSGerd Hoffmann     .name  = "QEMU HID Mouse",
5148b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
5158b84286fSGerd Hoffmann     .event = hid_pointer_event,
5168b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
5178b84286fSGerd Hoffmann };
5188b84286fSGerd Hoffmann 
5198b84286fSGerd Hoffmann static QemuInputHandler hid_tablet_handler = {
5208b84286fSGerd Hoffmann     .name  = "QEMU HID Tablet",
5218b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
5228b84286fSGerd Hoffmann     .event = hid_pointer_event,
5238b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
5248b84286fSGerd Hoffmann };
5258b84286fSGerd Hoffmann 
526dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event)
527dcfda673SGerd Hoffmann {
528dcfda673SGerd Hoffmann     hs->kind = kind;
529dcfda673SGerd Hoffmann     hs->event = event;
530dcfda673SGerd Hoffmann 
531bb0db527SMichael Walle     if (hs->kind == HID_KEYBOARD) {
5321ff5eeddSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5331ff5eeddSGerd Hoffmann                                             &hid_keyboard_handler);
5341ff5eeddSGerd Hoffmann         qemu_input_handler_activate(hs->s);
535bb0db527SMichael Walle     } else if (hs->kind == HID_MOUSE) {
5368b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5378b84286fSGerd Hoffmann                                             &hid_mouse_handler);
538dcfda673SGerd Hoffmann     } else if (hs->kind == HID_TABLET) {
5398b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5408b84286fSGerd Hoffmann                                             &hid_tablet_handler);
541dcfda673SGerd Hoffmann     }
542dcfda673SGerd Hoffmann }
543ccd4ed06SMichael Walle 
544ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id)
545ccd4ed06SMichael Walle {
546ccd4ed06SMichael Walle     HIDState *s = opaque;
547ccd4ed06SMichael Walle 
548027c03f7SHans de Goede     hid_set_next_idle(s);
549ba4d2606SGerd Hoffmann 
550ba4d2606SGerd Hoffmann     if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
551ba4d2606SGerd Hoffmann                                  s->kind == HID_MOUSE)) {
552ba4d2606SGerd Hoffmann         /*
553ba4d2606SGerd Hoffmann          * Handle ptr device migration from old qemu with full queue.
554ba4d2606SGerd Hoffmann          *
555ba4d2606SGerd Hoffmann          * Throw away everything but the last event, so we propagate
556ba4d2606SGerd Hoffmann          * at least the current button state to the guest.  Also keep
557ba4d2606SGerd Hoffmann          * current position for the tablet, signal "no motion" for the
558ba4d2606SGerd Hoffmann          * mouse.
559ba4d2606SGerd Hoffmann          */
560ba4d2606SGerd Hoffmann         HIDPointerEvent evt;
561ba4d2606SGerd Hoffmann         evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
562ba4d2606SGerd Hoffmann         if (s->kind == HID_MOUSE) {
563ba4d2606SGerd Hoffmann             evt.xdx = 0;
564ba4d2606SGerd Hoffmann             evt.ydy = 0;
565ba4d2606SGerd Hoffmann         }
566ba4d2606SGerd Hoffmann         s->ptr.queue[0] = evt;
567ba4d2606SGerd Hoffmann         s->head = 0;
568ba4d2606SGerd Hoffmann         s->n = 1;
569ba4d2606SGerd Hoffmann     }
570ccd4ed06SMichael Walle     return 0;
571ccd4ed06SMichael Walle }
572ccd4ed06SMichael Walle 
573ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = {
574ccd4ed06SMichael Walle     .name = "HIDPointerEventQueue",
575ccd4ed06SMichael Walle     .version_id = 1,
576ccd4ed06SMichael Walle     .minimum_version_id = 1,
577ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
578ccd4ed06SMichael Walle         VMSTATE_INT32(xdx, HIDPointerEvent),
579ccd4ed06SMichael Walle         VMSTATE_INT32(ydy, HIDPointerEvent),
580ccd4ed06SMichael Walle         VMSTATE_INT32(dz, HIDPointerEvent),
581ccd4ed06SMichael Walle         VMSTATE_INT32(buttons_state, HIDPointerEvent),
582ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST()
583ccd4ed06SMichael Walle     }
584ccd4ed06SMichael Walle };
585ccd4ed06SMichael Walle 
586ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = {
587ccd4ed06SMichael Walle     .name = "HIDPointerDevice",
588ccd4ed06SMichael Walle     .version_id = 1,
589ccd4ed06SMichael Walle     .minimum_version_id = 1,
590ccd4ed06SMichael Walle     .post_load = hid_post_load,
591ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
592ccd4ed06SMichael Walle         VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
593ccd4ed06SMichael Walle                              vmstate_hid_ptr_queue, HIDPointerEvent),
594ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
595ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
596ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
597ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
598ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
599ccd4ed06SMichael Walle     }
600ccd4ed06SMichael Walle };
601ccd4ed06SMichael Walle 
602ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = {
603ccd4ed06SMichael Walle     .name = "HIDKeyboardDevice",
604ccd4ed06SMichael Walle     .version_id = 1,
605ccd4ed06SMichael Walle     .minimum_version_id = 1,
606ccd4ed06SMichael Walle     .post_load = hid_post_load,
607ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
608ccd4ed06SMichael Walle         VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
609ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
610ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
611ccd4ed06SMichael Walle         VMSTATE_UINT16(kbd.modifiers, HIDState),
612ccd4ed06SMichael Walle         VMSTATE_UINT8(kbd.leds, HIDState),
613ccd4ed06SMichael Walle         VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
614ccd4ed06SMichael Walle         VMSTATE_INT32(kbd.keys, HIDState),
615ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
616ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
617ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
618ccd4ed06SMichael Walle     }
619ccd4ed06SMichael Walle };
620