xref: /qemu/hw/input/hid.c (revision 35e83d10f230616888cc4258ceddf06a612dde8a)
1dcfda673SGerd Hoffmann /*
2dcfda673SGerd Hoffmann  * QEMU HID devices
3dcfda673SGerd Hoffmann  *
4dcfda673SGerd Hoffmann  * Copyright (c) 2005 Fabrice Bellard
5dcfda673SGerd Hoffmann  * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
6dcfda673SGerd Hoffmann  *
7dcfda673SGerd Hoffmann  * Permission is hereby granted, free of charge, to any person obtaining a copy
8dcfda673SGerd Hoffmann  * of this software and associated documentation files (the "Software"), to deal
9dcfda673SGerd Hoffmann  * in the Software without restriction, including without limitation the rights
10dcfda673SGerd Hoffmann  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11dcfda673SGerd Hoffmann  * copies of the Software, and to permit persons to whom the Software is
12dcfda673SGerd Hoffmann  * furnished to do so, subject to the following conditions:
13dcfda673SGerd Hoffmann  *
14dcfda673SGerd Hoffmann  * The above copyright notice and this permission notice shall be included in
15dcfda673SGerd Hoffmann  * all copies or substantial portions of the Software.
16dcfda673SGerd Hoffmann  *
17dcfda673SGerd Hoffmann  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18dcfda673SGerd Hoffmann  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19dcfda673SGerd Hoffmann  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20dcfda673SGerd Hoffmann  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21dcfda673SGerd Hoffmann  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22dcfda673SGerd Hoffmann  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23dcfda673SGerd Hoffmann  * THE SOFTWARE.
24dcfda673SGerd Hoffmann  */
2583c9f4caSPaolo Bonzini #include "hw/hw.h"
2628ecbaeeSPaolo Bonzini #include "ui/console.h"
271de7afc9SPaolo Bonzini #include "qemu/timer.h"
280d09e41aSPaolo Bonzini #include "hw/input/hid.h"
29dcfda673SGerd Hoffmann 
30dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_ROLLOVER        0x01
31dcfda673SGerd Hoffmann #define HID_USAGE_POSTFAIL              0x02
32dcfda673SGerd Hoffmann #define HID_USAGE_ERROR_UNDEFINED       0x03
33dcfda673SGerd Hoffmann 
34dcfda673SGerd Hoffmann /* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
35dcfda673SGerd Hoffmann  * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
36dcfda673SGerd Hoffmann static const uint8_t hid_usage_keys[0x100] = {
37dcfda673SGerd Hoffmann     0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
38dcfda673SGerd Hoffmann     0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
39dcfda673SGerd Hoffmann     0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
40dcfda673SGerd Hoffmann     0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
41dcfda673SGerd Hoffmann     0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
42dcfda673SGerd Hoffmann     0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
43dcfda673SGerd Hoffmann     0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
44dcfda673SGerd Hoffmann     0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
45dcfda673SGerd Hoffmann     0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
46dcfda673SGerd Hoffmann     0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
47dcfda673SGerd Hoffmann     0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
48dcfda673SGerd Hoffmann     0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
49dcfda673SGerd Hoffmann     0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
50dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
51dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
53dcfda673SGerd Hoffmann 
54dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
58dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
61dcfda673SGerd Hoffmann     0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
63dcfda673SGerd Hoffmann     0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
64dcfda673SGerd Hoffmann     0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
65dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
66dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69dcfda673SGerd Hoffmann     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70dcfda673SGerd Hoffmann };
71dcfda673SGerd Hoffmann 
72dcfda673SGerd Hoffmann bool hid_has_events(HIDState *hs)
73dcfda673SGerd Hoffmann {
74027c03f7SHans de Goede     return hs->n > 0 || hs->idle_pending;
75dcfda673SGerd Hoffmann }
76dcfda673SGerd Hoffmann 
77027c03f7SHans de Goede static void hid_idle_timer(void *opaque)
78b069d348SGerd Hoffmann {
79027c03f7SHans de Goede     HIDState *hs = opaque;
80027c03f7SHans de Goede 
81027c03f7SHans de Goede     hs->idle_pending = true;
82027c03f7SHans de Goede     hs->event(hs);
83027c03f7SHans de Goede }
84027c03f7SHans de Goede 
85027c03f7SHans de Goede static void hid_del_idle_timer(HIDState *hs)
86027c03f7SHans de Goede {
87027c03f7SHans de Goede     if (hs->idle_timer) {
88bc72ad67SAlex Bligh         timer_del(hs->idle_timer);
89bc72ad67SAlex Bligh         timer_free(hs->idle_timer);
90027c03f7SHans de Goede         hs->idle_timer = NULL;
91027c03f7SHans de Goede     }
92027c03f7SHans de Goede }
93027c03f7SHans de Goede 
94027c03f7SHans de Goede void hid_set_next_idle(HIDState *hs)
95027c03f7SHans de Goede {
96027c03f7SHans de Goede     if (hs->idle) {
97bc72ad67SAlex Bligh         uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
98027c03f7SHans de Goede                                get_ticks_per_sec() * hs->idle * 4 / 1000;
99027c03f7SHans de Goede         if (!hs->idle_timer) {
100bc72ad67SAlex Bligh             hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs);
101027c03f7SHans de Goede         }
102bc72ad67SAlex Bligh         timer_mod_ns(hs->idle_timer, expire_time);
103027c03f7SHans de Goede     } else {
104027c03f7SHans de Goede         hid_del_idle_timer(hs);
105027c03f7SHans de Goede     }
106b069d348SGerd Hoffmann }
107b069d348SGerd Hoffmann 
1088b84286fSGerd Hoffmann static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
1098b84286fSGerd Hoffmann                               InputEvent *evt)
110dcfda673SGerd Hoffmann {
1118b84286fSGerd Hoffmann     static const int bmap[INPUT_BUTTON_MAX] = {
1128b84286fSGerd Hoffmann         [INPUT_BUTTON_LEFT]   = 0x01,
1138b84286fSGerd Hoffmann         [INPUT_BUTTON_RIGHT]  = 0x02,
1148b84286fSGerd Hoffmann         [INPUT_BUTTON_MIDDLE] = 0x04,
1158b84286fSGerd Hoffmann     };
1168b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1178b84286fSGerd Hoffmann     HIDPointerEvent *e;
118dcfda673SGerd Hoffmann 
1198b84286fSGerd Hoffmann     assert(hs->n < QUEUE_LENGTH);
1208b84286fSGerd Hoffmann     e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1218b84286fSGerd Hoffmann 
1228b84286fSGerd Hoffmann     switch (evt->kind) {
1238b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_REL:
1248b84286fSGerd Hoffmann         if (evt->rel->axis == INPUT_AXIS_X) {
1258b84286fSGerd Hoffmann             e->xdx += evt->rel->value;
1268b84286fSGerd Hoffmann         } else if (evt->rel->axis == INPUT_AXIS_Y) {
127*35e83d10SChristian Burger             e->ydy += evt->rel->value;
1288b84286fSGerd Hoffmann         }
1298b84286fSGerd Hoffmann         break;
1308b84286fSGerd Hoffmann 
1318b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_ABS:
1328b84286fSGerd Hoffmann         if (evt->rel->axis == INPUT_AXIS_X) {
1338b84286fSGerd Hoffmann             e->xdx = evt->rel->value;
1348b84286fSGerd Hoffmann         } else if (evt->rel->axis == INPUT_AXIS_Y) {
1358b84286fSGerd Hoffmann             e->ydy = evt->rel->value;
1368b84286fSGerd Hoffmann         }
1378b84286fSGerd Hoffmann         break;
1388b84286fSGerd Hoffmann 
1398b84286fSGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
1408b84286fSGerd Hoffmann         if (evt->btn->down) {
1418b84286fSGerd Hoffmann             e->buttons_state |= bmap[evt->btn->button];
1428b84286fSGerd Hoffmann             if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
1438b84286fSGerd Hoffmann                 e->dz--;
1448b84286fSGerd Hoffmann             } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
1458b84286fSGerd Hoffmann                 e->dz++;
1468b84286fSGerd Hoffmann             }
147dcfda673SGerd Hoffmann         } else {
1488b84286fSGerd Hoffmann             e->buttons_state &= ~bmap[evt->btn->button];
149dcfda673SGerd Hoffmann         }
1508b84286fSGerd Hoffmann         break;
1518b84286fSGerd Hoffmann 
1528b84286fSGerd Hoffmann     default:
1538b84286fSGerd Hoffmann         /* keep gcc happy */
1548b84286fSGerd Hoffmann         break;
155dcfda673SGerd Hoffmann     }
156dcfda673SGerd Hoffmann 
1578b84286fSGerd Hoffmann }
1588b84286fSGerd Hoffmann 
1598b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev)
160dcfda673SGerd Hoffmann {
1618b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1628b84286fSGerd Hoffmann     HIDPointerEvent *prev, *curr, *next;
1638b84286fSGerd Hoffmann     bool event_compression = false;
164dcfda673SGerd Hoffmann 
1658b84286fSGerd Hoffmann     if (hs->n == QUEUE_LENGTH-1) {
1668b84286fSGerd Hoffmann         /*
1675d831be2SStefan Weil          * Queue full.  We are losing information, but we at least
1688b84286fSGerd Hoffmann          * keep track of most recent button state.
1698b84286fSGerd Hoffmann          */
1708b84286fSGerd Hoffmann         return;
171dcfda673SGerd Hoffmann     }
1728b84286fSGerd Hoffmann 
1738b84286fSGerd Hoffmann     prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
1748b84286fSGerd Hoffmann     curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
1758b84286fSGerd Hoffmann     next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
1768b84286fSGerd Hoffmann 
1778b84286fSGerd Hoffmann     if (hs->n > 0) {
1788b84286fSGerd Hoffmann         /*
1798b84286fSGerd Hoffmann          * No button state change between previous and current event
1808b84286fSGerd Hoffmann          * (and previous wasn't seen by the guest yet), so there is
1818b84286fSGerd Hoffmann          * motion information only and we can combine the two event
1828b84286fSGerd Hoffmann          * into one.
1838b84286fSGerd Hoffmann          */
1848b84286fSGerd Hoffmann         if (curr->buttons_state == prev->buttons_state) {
1858b84286fSGerd Hoffmann             event_compression = true;
1868b84286fSGerd Hoffmann         }
1878b84286fSGerd Hoffmann     }
1888b84286fSGerd Hoffmann 
1898b84286fSGerd Hoffmann     if (event_compression) {
1908b84286fSGerd Hoffmann         /* add current motion to previous, clear current */
1918b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
1928b84286fSGerd Hoffmann             prev->xdx += curr->xdx;
1938b84286fSGerd Hoffmann             curr->xdx = 0;
194*35e83d10SChristian Burger             prev->ydy += curr->ydy;
1958b84286fSGerd Hoffmann             curr->ydy = 0;
1968b84286fSGerd Hoffmann         } else {
1978b84286fSGerd Hoffmann             prev->xdx = curr->xdx;
1988b84286fSGerd Hoffmann             prev->ydy = curr->ydy;
1998b84286fSGerd Hoffmann         }
2008b84286fSGerd Hoffmann         prev->dz += curr->dz;
2018b84286fSGerd Hoffmann         curr->dz = 0;
2028b84286fSGerd Hoffmann     } else {
2038b84286fSGerd Hoffmann         /* prepate next (clear rel, copy abs + btns) */
2048b84286fSGerd Hoffmann         if (hs->kind == HID_MOUSE) {
2058b84286fSGerd Hoffmann             next->xdx = 0;
2068b84286fSGerd Hoffmann             next->ydy = 0;
2078b84286fSGerd Hoffmann         } else {
2088b84286fSGerd Hoffmann             next->xdx = curr->xdx;
2098b84286fSGerd Hoffmann             next->ydy = curr->ydy;
2108b84286fSGerd Hoffmann         }
2118b84286fSGerd Hoffmann         next->dz = 0;
2128b84286fSGerd Hoffmann         next->buttons_state = curr->buttons_state;
2138b84286fSGerd Hoffmann         /* make current guest visible, notify guest */
2148b84286fSGerd Hoffmann         hs->n++;
215dcfda673SGerd Hoffmann         hs->event(hs);
216dcfda673SGerd Hoffmann     }
2178b84286fSGerd Hoffmann }
218dcfda673SGerd Hoffmann 
2191ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
2201ff5eeddSGerd Hoffmann                                InputEvent *evt)
221dcfda673SGerd Hoffmann {
2221ff5eeddSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
2231ff5eeddSGerd Hoffmann     int scancodes[3], i, count;
224dcfda673SGerd Hoffmann     int slot;
225dcfda673SGerd Hoffmann 
2261ff5eeddSGerd Hoffmann     count = qemu_input_key_value_to_scancode(evt->key->key,
2271ff5eeddSGerd Hoffmann                                              evt->key->down,
2281ff5eeddSGerd Hoffmann                                              scancodes);
2291ff5eeddSGerd Hoffmann     if (hs->n + count > QUEUE_LENGTH) {
230dcfda673SGerd Hoffmann         fprintf(stderr, "usb-kbd: warning: key event queue full\n");
231dcfda673SGerd Hoffmann         return;
232dcfda673SGerd Hoffmann     }
2331ff5eeddSGerd Hoffmann     for (i = 0; i < count; i++) {
234dcfda673SGerd Hoffmann         slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
2351ff5eeddSGerd Hoffmann         hs->kbd.keycodes[slot] = scancodes[i];
2361ff5eeddSGerd Hoffmann     }
237dcfda673SGerd Hoffmann     hs->event(hs);
238dcfda673SGerd Hoffmann }
239dcfda673SGerd Hoffmann 
240dcfda673SGerd Hoffmann static void hid_keyboard_process_keycode(HIDState *hs)
241dcfda673SGerd Hoffmann {
242dcfda673SGerd Hoffmann     uint8_t hid_code, key;
243dcfda673SGerd Hoffmann     int i, keycode, slot;
244dcfda673SGerd Hoffmann 
245dcfda673SGerd Hoffmann     if (hs->n == 0) {
246dcfda673SGerd Hoffmann         return;
247dcfda673SGerd Hoffmann     }
248dcfda673SGerd Hoffmann     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
249dcfda673SGerd Hoffmann     keycode = hs->kbd.keycodes[slot];
250dcfda673SGerd Hoffmann 
251dcfda673SGerd Hoffmann     key = keycode & 0x7f;
252dcfda673SGerd Hoffmann     hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
253dcfda673SGerd Hoffmann     hs->kbd.modifiers &= ~(1 << 8);
254dcfda673SGerd Hoffmann 
255dcfda673SGerd Hoffmann     switch (hid_code) {
256dcfda673SGerd Hoffmann     case 0x00:
257dcfda673SGerd Hoffmann         return;
258dcfda673SGerd Hoffmann 
259dcfda673SGerd Hoffmann     case 0xe0:
260dcfda673SGerd Hoffmann         if (hs->kbd.modifiers & (1 << 9)) {
261dcfda673SGerd Hoffmann             hs->kbd.modifiers ^= 3 << 8;
262dcfda673SGerd Hoffmann             return;
263dcfda673SGerd Hoffmann         }
264dcfda673SGerd Hoffmann     case 0xe1 ... 0xe7:
265dcfda673SGerd Hoffmann         if (keycode & (1 << 7)) {
266dcfda673SGerd Hoffmann             hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
267dcfda673SGerd Hoffmann             return;
268dcfda673SGerd Hoffmann         }
269dcfda673SGerd Hoffmann     case 0xe8 ... 0xef:
270dcfda673SGerd Hoffmann         hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
271dcfda673SGerd Hoffmann         return;
272dcfda673SGerd Hoffmann     }
273dcfda673SGerd Hoffmann 
274dcfda673SGerd Hoffmann     if (keycode & (1 << 7)) {
275dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
276dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
277dcfda673SGerd Hoffmann                 hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
278dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys] = 0x00;
279dcfda673SGerd Hoffmann                 break;
280dcfda673SGerd Hoffmann             }
281dcfda673SGerd Hoffmann         }
282dcfda673SGerd Hoffmann         if (i < 0) {
283dcfda673SGerd Hoffmann             return;
284dcfda673SGerd Hoffmann         }
285dcfda673SGerd Hoffmann     } else {
286dcfda673SGerd Hoffmann         for (i = hs->kbd.keys - 1; i >= 0; i--) {
287dcfda673SGerd Hoffmann             if (hs->kbd.key[i] == hid_code) {
288dcfda673SGerd Hoffmann                 break;
289dcfda673SGerd Hoffmann             }
290dcfda673SGerd Hoffmann         }
291dcfda673SGerd Hoffmann         if (i < 0) {
292dcfda673SGerd Hoffmann             if (hs->kbd.keys < sizeof(hs->kbd.key)) {
293dcfda673SGerd Hoffmann                 hs->kbd.key[hs->kbd.keys++] = hid_code;
294dcfda673SGerd Hoffmann             }
295dcfda673SGerd Hoffmann         } else {
296dcfda673SGerd Hoffmann             return;
297dcfda673SGerd Hoffmann         }
298dcfda673SGerd Hoffmann     }
299dcfda673SGerd Hoffmann }
300dcfda673SGerd Hoffmann 
301dcfda673SGerd Hoffmann static inline int int_clamp(int val, int vmin, int vmax)
302dcfda673SGerd Hoffmann {
303dcfda673SGerd Hoffmann     if (val < vmin) {
304dcfda673SGerd Hoffmann         return vmin;
305dcfda673SGerd Hoffmann     } else if (val > vmax) {
306dcfda673SGerd Hoffmann         return vmax;
307dcfda673SGerd Hoffmann     } else {
308dcfda673SGerd Hoffmann         return val;
309dcfda673SGerd Hoffmann     }
310dcfda673SGerd Hoffmann }
311dcfda673SGerd Hoffmann 
31221635e12SGerd Hoffmann void hid_pointer_activate(HIDState *hs)
31321635e12SGerd Hoffmann {
31421635e12SGerd Hoffmann     if (!hs->ptr.mouse_grabbed) {
3158b84286fSGerd Hoffmann         qemu_input_handler_activate(hs->s);
31621635e12SGerd Hoffmann         hs->ptr.mouse_grabbed = 1;
31721635e12SGerd Hoffmann     }
31821635e12SGerd Hoffmann }
31921635e12SGerd Hoffmann 
320dcfda673SGerd Hoffmann int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
321dcfda673SGerd Hoffmann {
3228b84286fSGerd Hoffmann     int dx, dy, dz, l;
323dcfda673SGerd Hoffmann     int index;
324dcfda673SGerd Hoffmann     HIDPointerEvent *e;
325dcfda673SGerd Hoffmann 
326027c03f7SHans de Goede     hs->idle_pending = false;
327027c03f7SHans de Goede 
32821635e12SGerd Hoffmann     hid_pointer_activate(hs);
329dcfda673SGerd Hoffmann 
330dcfda673SGerd Hoffmann     /* When the buffer is empty, return the last event.  Relative
331dcfda673SGerd Hoffmann        movements will all be zero.  */
332dcfda673SGerd Hoffmann     index = (hs->n ? hs->head : hs->head - 1);
333dcfda673SGerd Hoffmann     e = &hs->ptr.queue[index & QUEUE_MASK];
334dcfda673SGerd Hoffmann 
335dcfda673SGerd Hoffmann     if (hs->kind == HID_MOUSE) {
336dcfda673SGerd Hoffmann         dx = int_clamp(e->xdx, -127, 127);
337dcfda673SGerd Hoffmann         dy = int_clamp(e->ydy, -127, 127);
338dcfda673SGerd Hoffmann         e->xdx -= dx;
339dcfda673SGerd Hoffmann         e->ydy -= dy;
340dcfda673SGerd Hoffmann     } else {
341dcfda673SGerd Hoffmann         dx = e->xdx;
342dcfda673SGerd Hoffmann         dy = e->ydy;
343dcfda673SGerd Hoffmann     }
344dcfda673SGerd Hoffmann     dz = int_clamp(e->dz, -127, 127);
345dcfda673SGerd Hoffmann     e->dz -= dz;
346dcfda673SGerd Hoffmann 
347dcfda673SGerd Hoffmann     if (hs->n &&
348dcfda673SGerd Hoffmann         !e->dz &&
349dcfda673SGerd Hoffmann         (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
350dcfda673SGerd Hoffmann         /* that deals with this event */
351dcfda673SGerd Hoffmann         QUEUE_INCR(hs->head);
352dcfda673SGerd Hoffmann         hs->n--;
353dcfda673SGerd Hoffmann     }
354dcfda673SGerd Hoffmann 
355dcfda673SGerd Hoffmann     /* Appears we have to invert the wheel direction */
356dcfda673SGerd Hoffmann     dz = 0 - dz;
357dcfda673SGerd Hoffmann     l = 0;
358dcfda673SGerd Hoffmann     switch (hs->kind) {
359dcfda673SGerd Hoffmann     case HID_MOUSE:
360dcfda673SGerd Hoffmann         if (len > l) {
3618b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
362dcfda673SGerd Hoffmann         }
363dcfda673SGerd Hoffmann         if (len > l) {
364dcfda673SGerd Hoffmann             buf[l++] = dx;
365dcfda673SGerd Hoffmann         }
366dcfda673SGerd Hoffmann         if (len > l) {
367dcfda673SGerd Hoffmann             buf[l++] = dy;
368dcfda673SGerd Hoffmann         }
369dcfda673SGerd Hoffmann         if (len > l) {
370dcfda673SGerd Hoffmann             buf[l++] = dz;
371dcfda673SGerd Hoffmann         }
372dcfda673SGerd Hoffmann         break;
373dcfda673SGerd Hoffmann 
374dcfda673SGerd Hoffmann     case HID_TABLET:
375dcfda673SGerd Hoffmann         if (len > l) {
3768b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
377dcfda673SGerd Hoffmann         }
378dcfda673SGerd Hoffmann         if (len > l) {
379dcfda673SGerd Hoffmann             buf[l++] = dx & 0xff;
380dcfda673SGerd Hoffmann         }
381dcfda673SGerd Hoffmann         if (len > l) {
382dcfda673SGerd Hoffmann             buf[l++] = dx >> 8;
383dcfda673SGerd Hoffmann         }
384dcfda673SGerd Hoffmann         if (len > l) {
385dcfda673SGerd Hoffmann             buf[l++] = dy & 0xff;
386dcfda673SGerd Hoffmann         }
387dcfda673SGerd Hoffmann         if (len > l) {
388dcfda673SGerd Hoffmann             buf[l++] = dy >> 8;
389dcfda673SGerd Hoffmann         }
390dcfda673SGerd Hoffmann         if (len > l) {
391dcfda673SGerd Hoffmann             buf[l++] = dz;
392dcfda673SGerd Hoffmann         }
393dcfda673SGerd Hoffmann         break;
394dcfda673SGerd Hoffmann 
395dcfda673SGerd Hoffmann     default:
396dcfda673SGerd Hoffmann         abort();
397dcfda673SGerd Hoffmann     }
398dcfda673SGerd Hoffmann 
399dcfda673SGerd Hoffmann     return l;
400dcfda673SGerd Hoffmann }
401dcfda673SGerd Hoffmann 
402dcfda673SGerd Hoffmann int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
403dcfda673SGerd Hoffmann {
404027c03f7SHans de Goede     hs->idle_pending = false;
405027c03f7SHans de Goede 
406dcfda673SGerd Hoffmann     if (len < 2) {
407dcfda673SGerd Hoffmann         return 0;
408dcfda673SGerd Hoffmann     }
409dcfda673SGerd Hoffmann 
410dcfda673SGerd Hoffmann     hid_keyboard_process_keycode(hs);
411dcfda673SGerd Hoffmann 
412dcfda673SGerd Hoffmann     buf[0] = hs->kbd.modifiers & 0xff;
413dcfda673SGerd Hoffmann     buf[1] = 0;
414dcfda673SGerd Hoffmann     if (hs->kbd.keys > 6) {
415dcfda673SGerd Hoffmann         memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
416dcfda673SGerd Hoffmann     } else {
417dcfda673SGerd Hoffmann         memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
418dcfda673SGerd Hoffmann     }
419dcfda673SGerd Hoffmann 
420dcfda673SGerd Hoffmann     return MIN(8, len);
421dcfda673SGerd Hoffmann }
422dcfda673SGerd Hoffmann 
423dcfda673SGerd Hoffmann int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
424dcfda673SGerd Hoffmann {
425dcfda673SGerd Hoffmann     if (len > 0) {
426dcfda673SGerd Hoffmann         int ledstate = 0;
427dcfda673SGerd Hoffmann         /* 0x01: Num Lock LED
428dcfda673SGerd Hoffmann          * 0x02: Caps Lock LED
429dcfda673SGerd Hoffmann          * 0x04: Scroll Lock LED
430dcfda673SGerd Hoffmann          * 0x08: Compose LED
431dcfda673SGerd Hoffmann          * 0x10: Kana LED */
432dcfda673SGerd Hoffmann         hs->kbd.leds = buf[0];
433dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x04) {
434dcfda673SGerd Hoffmann             ledstate |= QEMU_SCROLL_LOCK_LED;
435dcfda673SGerd Hoffmann         }
436dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x01) {
437dcfda673SGerd Hoffmann             ledstate |= QEMU_NUM_LOCK_LED;
438dcfda673SGerd Hoffmann         }
439dcfda673SGerd Hoffmann         if (hs->kbd.leds & 0x02) {
440dcfda673SGerd Hoffmann             ledstate |= QEMU_CAPS_LOCK_LED;
441dcfda673SGerd Hoffmann         }
442dcfda673SGerd Hoffmann         kbd_put_ledstate(ledstate);
443dcfda673SGerd Hoffmann     }
444dcfda673SGerd Hoffmann     return 0;
445dcfda673SGerd Hoffmann }
446dcfda673SGerd Hoffmann 
447dcfda673SGerd Hoffmann void hid_reset(HIDState *hs)
448dcfda673SGerd Hoffmann {
449dcfda673SGerd Hoffmann     switch (hs->kind) {
450dcfda673SGerd Hoffmann     case HID_KEYBOARD:
451dcfda673SGerd Hoffmann         memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
452dcfda673SGerd Hoffmann         memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
453dcfda673SGerd Hoffmann         hs->kbd.keys = 0;
454dcfda673SGerd Hoffmann         break;
455dcfda673SGerd Hoffmann     case HID_MOUSE:
456dcfda673SGerd Hoffmann     case HID_TABLET:
457dcfda673SGerd Hoffmann         memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
458dcfda673SGerd Hoffmann         break;
459dcfda673SGerd Hoffmann     }
460dcfda673SGerd Hoffmann     hs->head = 0;
461dcfda673SGerd Hoffmann     hs->n = 0;
462b069d348SGerd Hoffmann     hs->protocol = 1;
463b069d348SGerd Hoffmann     hs->idle = 0;
464027c03f7SHans de Goede     hs->idle_pending = false;
465027c03f7SHans de Goede     hid_del_idle_timer(hs);
466dcfda673SGerd Hoffmann }
467dcfda673SGerd Hoffmann 
468dcfda673SGerd Hoffmann void hid_free(HIDState *hs)
469dcfda673SGerd Hoffmann {
4701ff5eeddSGerd Hoffmann     qemu_input_handler_unregister(hs->s);
471027c03f7SHans de Goede     hid_del_idle_timer(hs);
472dcfda673SGerd Hoffmann }
473dcfda673SGerd Hoffmann 
4741ff5eeddSGerd Hoffmann static QemuInputHandler hid_keyboard_handler = {
4751ff5eeddSGerd Hoffmann     .name  = "QEMU HID Keyboard",
4761ff5eeddSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
4771ff5eeddSGerd Hoffmann     .event = hid_keyboard_event,
4781ff5eeddSGerd Hoffmann };
4791ff5eeddSGerd Hoffmann 
4808b84286fSGerd Hoffmann static QemuInputHandler hid_mouse_handler = {
4818b84286fSGerd Hoffmann     .name  = "QEMU HID Mouse",
4828b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
4838b84286fSGerd Hoffmann     .event = hid_pointer_event,
4848b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
4858b84286fSGerd Hoffmann };
4868b84286fSGerd Hoffmann 
4878b84286fSGerd Hoffmann static QemuInputHandler hid_tablet_handler = {
4888b84286fSGerd Hoffmann     .name  = "QEMU HID Tablet",
4898b84286fSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
4908b84286fSGerd Hoffmann     .event = hid_pointer_event,
4918b84286fSGerd Hoffmann     .sync  = hid_pointer_sync,
4928b84286fSGerd Hoffmann };
4938b84286fSGerd Hoffmann 
494dcfda673SGerd Hoffmann void hid_init(HIDState *hs, int kind, HIDEventFunc event)
495dcfda673SGerd Hoffmann {
496dcfda673SGerd Hoffmann     hs->kind = kind;
497dcfda673SGerd Hoffmann     hs->event = event;
498dcfda673SGerd Hoffmann 
499bb0db527SMichael Walle     if (hs->kind == HID_KEYBOARD) {
5001ff5eeddSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5011ff5eeddSGerd Hoffmann                                             &hid_keyboard_handler);
5021ff5eeddSGerd Hoffmann         qemu_input_handler_activate(hs->s);
503bb0db527SMichael Walle     } else if (hs->kind == HID_MOUSE) {
5048b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5058b84286fSGerd Hoffmann                                             &hid_mouse_handler);
506dcfda673SGerd Hoffmann     } else if (hs->kind == HID_TABLET) {
5078b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5088b84286fSGerd Hoffmann                                             &hid_tablet_handler);
509dcfda673SGerd Hoffmann     }
510dcfda673SGerd Hoffmann }
511ccd4ed06SMichael Walle 
512ccd4ed06SMichael Walle static int hid_post_load(void *opaque, int version_id)
513ccd4ed06SMichael Walle {
514ccd4ed06SMichael Walle     HIDState *s = opaque;
515ccd4ed06SMichael Walle 
516027c03f7SHans de Goede     hid_set_next_idle(s);
517ccd4ed06SMichael Walle     return 0;
518ccd4ed06SMichael Walle }
519ccd4ed06SMichael Walle 
520ccd4ed06SMichael Walle static const VMStateDescription vmstate_hid_ptr_queue = {
521ccd4ed06SMichael Walle     .name = "HIDPointerEventQueue",
522ccd4ed06SMichael Walle     .version_id = 1,
523ccd4ed06SMichael Walle     .minimum_version_id = 1,
524ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
525ccd4ed06SMichael Walle         VMSTATE_INT32(xdx, HIDPointerEvent),
526ccd4ed06SMichael Walle         VMSTATE_INT32(ydy, HIDPointerEvent),
527ccd4ed06SMichael Walle         VMSTATE_INT32(dz, HIDPointerEvent),
528ccd4ed06SMichael Walle         VMSTATE_INT32(buttons_state, HIDPointerEvent),
529ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST()
530ccd4ed06SMichael Walle     }
531ccd4ed06SMichael Walle };
532ccd4ed06SMichael Walle 
533ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_ptr_device = {
534ccd4ed06SMichael Walle     .name = "HIDPointerDevice",
535ccd4ed06SMichael Walle     .version_id = 1,
536ccd4ed06SMichael Walle     .minimum_version_id = 1,
537ccd4ed06SMichael Walle     .post_load = hid_post_load,
538ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
539ccd4ed06SMichael Walle         VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
540ccd4ed06SMichael Walle                              vmstate_hid_ptr_queue, HIDPointerEvent),
541ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
542ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
543ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
544ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
545ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
546ccd4ed06SMichael Walle     }
547ccd4ed06SMichael Walle };
548ccd4ed06SMichael Walle 
549ccd4ed06SMichael Walle const VMStateDescription vmstate_hid_keyboard_device = {
550ccd4ed06SMichael Walle     .name = "HIDKeyboardDevice",
551ccd4ed06SMichael Walle     .version_id = 1,
552ccd4ed06SMichael Walle     .minimum_version_id = 1,
553ccd4ed06SMichael Walle     .post_load = hid_post_load,
554ccd4ed06SMichael Walle     .fields = (VMStateField[]) {
555ccd4ed06SMichael Walle         VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
556ccd4ed06SMichael Walle         VMSTATE_UINT32(head, HIDState),
557ccd4ed06SMichael Walle         VMSTATE_UINT32(n, HIDState),
558ccd4ed06SMichael Walle         VMSTATE_UINT16(kbd.modifiers, HIDState),
559ccd4ed06SMichael Walle         VMSTATE_UINT8(kbd.leds, HIDState),
560ccd4ed06SMichael Walle         VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
561ccd4ed06SMichael Walle         VMSTATE_INT32(kbd.keys, HIDState),
562ccd4ed06SMichael Walle         VMSTATE_INT32(protocol, HIDState),
563ccd4ed06SMichael Walle         VMSTATE_UINT8(idle, HIDState),
564ccd4ed06SMichael Walle         VMSTATE_END_OF_LIST(),
565ccd4ed06SMichael Walle     }
566ccd4ed06SMichael Walle };
567