xref: /qemu/hw/input/hid.c (revision 0430891c)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU HID devices
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2005 Fabrice Bellard
549ab747fSPaolo Bonzini  * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
649ab747fSPaolo Bonzini  *
749ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
849ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
949ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1049ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1149ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1249ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1349ab747fSPaolo Bonzini  *
1449ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1549ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1649ab747fSPaolo Bonzini  *
1749ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1849ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1949ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2049ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2149ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2249ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2349ab747fSPaolo Bonzini  * THE SOFTWARE.
2449ab747fSPaolo Bonzini  */
25*0430891cSPeter Maydell #include "qemu/osdep.h"
2649ab747fSPaolo Bonzini #include "hw/hw.h"
2749ab747fSPaolo Bonzini #include "ui/console.h"
2849ab747fSPaolo Bonzini #include "qemu/timer.h"
2949ab747fSPaolo Bonzini #include "hw/input/hid.h"
3049ab747fSPaolo Bonzini 
3149ab747fSPaolo Bonzini #define HID_USAGE_ERROR_ROLLOVER        0x01
3249ab747fSPaolo Bonzini #define HID_USAGE_POSTFAIL              0x02
3349ab747fSPaolo Bonzini #define HID_USAGE_ERROR_UNDEFINED       0x03
3449ab747fSPaolo Bonzini 
3549ab747fSPaolo Bonzini /* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
3649ab747fSPaolo Bonzini  * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
3749ab747fSPaolo Bonzini static const uint8_t hid_usage_keys[0x100] = {
3849ab747fSPaolo Bonzini     0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
3949ab747fSPaolo Bonzini     0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
4049ab747fSPaolo Bonzini     0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
4149ab747fSPaolo Bonzini     0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
4249ab747fSPaolo Bonzini     0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
4349ab747fSPaolo Bonzini     0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
4449ab747fSPaolo Bonzini     0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
450ee4de58SDinar Valeev     0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
4649ab747fSPaolo Bonzini     0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
4749ab747fSPaolo Bonzini     0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
4849ab747fSPaolo Bonzini     0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
4949ab747fSPaolo Bonzini     0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
5049ab747fSPaolo Bonzini     0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
5149ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
5249ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5349ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
5449ab747fSPaolo Bonzini 
5549ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5649ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5749ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5849ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
5949ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6049ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6149ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
6249ab747fSPaolo Bonzini     0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6349ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
6449ab747fSPaolo Bonzini     0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
6549ab747fSPaolo Bonzini     0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
6649ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
6749ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6849ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6949ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7049ab747fSPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7149ab747fSPaolo Bonzini };
7249ab747fSPaolo Bonzini 
7349ab747fSPaolo Bonzini bool hid_has_events(HIDState *hs)
7449ab747fSPaolo Bonzini {
7549ab747fSPaolo Bonzini     return hs->n > 0 || hs->idle_pending;
7649ab747fSPaolo Bonzini }
7749ab747fSPaolo Bonzini 
7849ab747fSPaolo Bonzini static void hid_idle_timer(void *opaque)
7949ab747fSPaolo Bonzini {
8049ab747fSPaolo Bonzini     HIDState *hs = opaque;
8149ab747fSPaolo Bonzini 
8249ab747fSPaolo Bonzini     hs->idle_pending = true;
8349ab747fSPaolo Bonzini     hs->event(hs);
8449ab747fSPaolo Bonzini }
8549ab747fSPaolo Bonzini 
8649ab747fSPaolo Bonzini static void hid_del_idle_timer(HIDState *hs)
8749ab747fSPaolo Bonzini {
8849ab747fSPaolo Bonzini     if (hs->idle_timer) {
89bc72ad67SAlex Bligh         timer_del(hs->idle_timer);
90bc72ad67SAlex Bligh         timer_free(hs->idle_timer);
9149ab747fSPaolo Bonzini         hs->idle_timer = NULL;
9249ab747fSPaolo Bonzini     }
9349ab747fSPaolo Bonzini }
9449ab747fSPaolo Bonzini 
9549ab747fSPaolo Bonzini void hid_set_next_idle(HIDState *hs)
9649ab747fSPaolo Bonzini {
9749ab747fSPaolo Bonzini     if (hs->idle) {
98bc72ad67SAlex Bligh         uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
9949ab747fSPaolo Bonzini                                get_ticks_per_sec() * hs->idle * 4 / 1000;
10049ab747fSPaolo Bonzini         if (!hs->idle_timer) {
101bc72ad67SAlex Bligh             hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs);
10249ab747fSPaolo Bonzini         }
103bc72ad67SAlex Bligh         timer_mod_ns(hs->idle_timer, expire_time);
10449ab747fSPaolo Bonzini     } else {
10549ab747fSPaolo Bonzini         hid_del_idle_timer(hs);
10649ab747fSPaolo Bonzini     }
10749ab747fSPaolo Bonzini }
10849ab747fSPaolo Bonzini 
1098b84286fSGerd Hoffmann static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
1108b84286fSGerd Hoffmann                               InputEvent *evt)
11149ab747fSPaolo Bonzini {
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;
11949ab747fSPaolo Bonzini 
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             }
14849ab747fSPaolo Bonzini         } else {
149568c73a4SEric Blake             e->buttons_state &= ~bmap[evt->u.btn->button];
15049ab747fSPaolo Bonzini         }
1518b84286fSGerd Hoffmann         break;
1528b84286fSGerd Hoffmann 
1538b84286fSGerd Hoffmann     default:
1548b84286fSGerd Hoffmann         /* keep gcc happy */
1558b84286fSGerd Hoffmann         break;
15649ab747fSPaolo Bonzini     }
15749ab747fSPaolo Bonzini 
1588b84286fSGerd Hoffmann }
1598b84286fSGerd Hoffmann 
1608b84286fSGerd Hoffmann static void hid_pointer_sync(DeviceState *dev)
16149ab747fSPaolo Bonzini {
1628b84286fSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
1638b84286fSGerd Hoffmann     HIDPointerEvent *prev, *curr, *next;
1648b84286fSGerd Hoffmann     bool event_compression = false;
16549ab747fSPaolo Bonzini 
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;
17249ab747fSPaolo Bonzini     }
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++;
21649ab747fSPaolo Bonzini         hs->event(hs);
21749ab747fSPaolo Bonzini     }
2188b84286fSGerd Hoffmann }
21949ab747fSPaolo Bonzini 
2201ff5eeddSGerd Hoffmann static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
2211ff5eeddSGerd Hoffmann                                InputEvent *evt)
22249ab747fSPaolo Bonzini {
2231ff5eeddSGerd Hoffmann     HIDState *hs = (HIDState *)dev;
2241ff5eeddSGerd Hoffmann     int scancodes[3], i, count;
22549ab747fSPaolo Bonzini     int slot;
22649ab747fSPaolo Bonzini 
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) {
23149ab747fSPaolo Bonzini         fprintf(stderr, "usb-kbd: warning: key event queue full\n");
23249ab747fSPaolo Bonzini         return;
23349ab747fSPaolo Bonzini     }
2341ff5eeddSGerd Hoffmann     for (i = 0; i < count; i++) {
23549ab747fSPaolo Bonzini         slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
2361ff5eeddSGerd Hoffmann         hs->kbd.keycodes[slot] = scancodes[i];
2371ff5eeddSGerd Hoffmann     }
23849ab747fSPaolo Bonzini     hs->event(hs);
23949ab747fSPaolo Bonzini }
24049ab747fSPaolo Bonzini 
24149ab747fSPaolo Bonzini static void hid_keyboard_process_keycode(HIDState *hs)
24249ab747fSPaolo Bonzini {
243562f9375SPaolo Bonzini     uint8_t hid_code, index, key;
24449ab747fSPaolo Bonzini     int i, keycode, slot;
24549ab747fSPaolo Bonzini 
24649ab747fSPaolo Bonzini     if (hs->n == 0) {
24749ab747fSPaolo Bonzini         return;
24849ab747fSPaolo Bonzini     }
24949ab747fSPaolo Bonzini     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
25049ab747fSPaolo Bonzini     keycode = hs->kbd.keycodes[slot];
25149ab747fSPaolo Bonzini 
25249ab747fSPaolo Bonzini     key = keycode & 0x7f;
253562f9375SPaolo Bonzini     index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
254562f9375SPaolo Bonzini     hid_code = hid_usage_keys[index];
25549ab747fSPaolo Bonzini     hs->kbd.modifiers &= ~(1 << 8);
25649ab747fSPaolo Bonzini 
25749ab747fSPaolo Bonzini     switch (hid_code) {
25849ab747fSPaolo Bonzini     case 0x00:
25949ab747fSPaolo Bonzini         return;
26049ab747fSPaolo Bonzini 
26149ab747fSPaolo Bonzini     case 0xe0:
262562f9375SPaolo Bonzini         assert(key == 0x1d);
26349ab747fSPaolo Bonzini         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);
27049ab747fSPaolo Bonzini             return;
27149ab747fSPaolo Bonzini         }
272562f9375SPaolo Bonzini         /* fall through to process Ctrl_L */
27349ab747fSPaolo Bonzini     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          */
27749ab747fSPaolo Bonzini         if (keycode & (1 << 7)) {
27849ab747fSPaolo Bonzini             hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
27949ab747fSPaolo Bonzini             return;
28049ab747fSPaolo Bonzini         }
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          */
28949ab747fSPaolo Bonzini         hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
29049ab747fSPaolo Bonzini         return;
291562f9375SPaolo Bonzini 
292562f9375SPaolo Bonzini     case 0xea ... 0xef:
293562f9375SPaolo Bonzini         abort();
294562f9375SPaolo Bonzini 
295562f9375SPaolo Bonzini     default:
296562f9375SPaolo Bonzini         break;
29749ab747fSPaolo Bonzini     }
29849ab747fSPaolo Bonzini 
29949ab747fSPaolo Bonzini     if (keycode & (1 << 7)) {
30049ab747fSPaolo Bonzini         for (i = hs->kbd.keys - 1; i >= 0; i--) {
30149ab747fSPaolo Bonzini             if (hs->kbd.key[i] == hid_code) {
30249ab747fSPaolo Bonzini                 hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
30349ab747fSPaolo Bonzini                 hs->kbd.key[hs->kbd.keys] = 0x00;
30449ab747fSPaolo Bonzini                 break;
30549ab747fSPaolo Bonzini             }
30649ab747fSPaolo Bonzini         }
30749ab747fSPaolo Bonzini         if (i < 0) {
30849ab747fSPaolo Bonzini             return;
30949ab747fSPaolo Bonzini         }
31049ab747fSPaolo Bonzini     } else {
31149ab747fSPaolo Bonzini         for (i = hs->kbd.keys - 1; i >= 0; i--) {
31249ab747fSPaolo Bonzini             if (hs->kbd.key[i] == hid_code) {
31349ab747fSPaolo Bonzini                 break;
31449ab747fSPaolo Bonzini             }
31549ab747fSPaolo Bonzini         }
31649ab747fSPaolo Bonzini         if (i < 0) {
31749ab747fSPaolo Bonzini             if (hs->kbd.keys < sizeof(hs->kbd.key)) {
31849ab747fSPaolo Bonzini                 hs->kbd.key[hs->kbd.keys++] = hid_code;
31949ab747fSPaolo Bonzini             }
32049ab747fSPaolo Bonzini         } else {
32149ab747fSPaolo Bonzini             return;
32249ab747fSPaolo Bonzini         }
32349ab747fSPaolo Bonzini     }
32449ab747fSPaolo Bonzini }
32549ab747fSPaolo Bonzini 
32649ab747fSPaolo Bonzini static inline int int_clamp(int val, int vmin, int vmax)
32749ab747fSPaolo Bonzini {
32849ab747fSPaolo Bonzini     if (val < vmin) {
32949ab747fSPaolo Bonzini         return vmin;
33049ab747fSPaolo Bonzini     } else if (val > vmax) {
33149ab747fSPaolo Bonzini         return vmax;
33249ab747fSPaolo Bonzini     } else {
33349ab747fSPaolo Bonzini         return val;
33449ab747fSPaolo Bonzini     }
33549ab747fSPaolo Bonzini }
33649ab747fSPaolo Bonzini 
33749ab747fSPaolo Bonzini void hid_pointer_activate(HIDState *hs)
33849ab747fSPaolo Bonzini {
33949ab747fSPaolo Bonzini     if (!hs->ptr.mouse_grabbed) {
3408b84286fSGerd Hoffmann         qemu_input_handler_activate(hs->s);
34149ab747fSPaolo Bonzini         hs->ptr.mouse_grabbed = 1;
34249ab747fSPaolo Bonzini     }
34349ab747fSPaolo Bonzini }
34449ab747fSPaolo Bonzini 
34549ab747fSPaolo Bonzini int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
34649ab747fSPaolo Bonzini {
3478b84286fSGerd Hoffmann     int dx, dy, dz, l;
34849ab747fSPaolo Bonzini     int index;
34949ab747fSPaolo Bonzini     HIDPointerEvent *e;
35049ab747fSPaolo Bonzini 
35149ab747fSPaolo Bonzini     hs->idle_pending = false;
35249ab747fSPaolo Bonzini 
35349ab747fSPaolo Bonzini     hid_pointer_activate(hs);
35449ab747fSPaolo Bonzini 
35549ab747fSPaolo Bonzini     /* When the buffer is empty, return the last event.  Relative
35649ab747fSPaolo Bonzini        movements will all be zero.  */
35749ab747fSPaolo Bonzini     index = (hs->n ? hs->head : hs->head - 1);
35849ab747fSPaolo Bonzini     e = &hs->ptr.queue[index & QUEUE_MASK];
35949ab747fSPaolo Bonzini 
36049ab747fSPaolo Bonzini     if (hs->kind == HID_MOUSE) {
36149ab747fSPaolo Bonzini         dx = int_clamp(e->xdx, -127, 127);
36249ab747fSPaolo Bonzini         dy = int_clamp(e->ydy, -127, 127);
36349ab747fSPaolo Bonzini         e->xdx -= dx;
36449ab747fSPaolo Bonzini         e->ydy -= dy;
36549ab747fSPaolo Bonzini     } else {
36649ab747fSPaolo Bonzini         dx = e->xdx;
36749ab747fSPaolo Bonzini         dy = e->ydy;
36849ab747fSPaolo Bonzini     }
36949ab747fSPaolo Bonzini     dz = int_clamp(e->dz, -127, 127);
37049ab747fSPaolo Bonzini     e->dz -= dz;
37149ab747fSPaolo Bonzini 
37249ab747fSPaolo Bonzini     if (hs->n &&
37349ab747fSPaolo Bonzini         !e->dz &&
37449ab747fSPaolo Bonzini         (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
37549ab747fSPaolo Bonzini         /* that deals with this event */
37649ab747fSPaolo Bonzini         QUEUE_INCR(hs->head);
37749ab747fSPaolo Bonzini         hs->n--;
37849ab747fSPaolo Bonzini     }
37949ab747fSPaolo Bonzini 
38049ab747fSPaolo Bonzini     /* Appears we have to invert the wheel direction */
38149ab747fSPaolo Bonzini     dz = 0 - dz;
38249ab747fSPaolo Bonzini     l = 0;
38349ab747fSPaolo Bonzini     switch (hs->kind) {
38449ab747fSPaolo Bonzini     case HID_MOUSE:
38549ab747fSPaolo Bonzini         if (len > l) {
3868b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
38749ab747fSPaolo Bonzini         }
38849ab747fSPaolo Bonzini         if (len > l) {
38949ab747fSPaolo Bonzini             buf[l++] = dx;
39049ab747fSPaolo Bonzini         }
39149ab747fSPaolo Bonzini         if (len > l) {
39249ab747fSPaolo Bonzini             buf[l++] = dy;
39349ab747fSPaolo Bonzini         }
39449ab747fSPaolo Bonzini         if (len > l) {
39549ab747fSPaolo Bonzini             buf[l++] = dz;
39649ab747fSPaolo Bonzini         }
39749ab747fSPaolo Bonzini         break;
39849ab747fSPaolo Bonzini 
39949ab747fSPaolo Bonzini     case HID_TABLET:
40049ab747fSPaolo Bonzini         if (len > l) {
4018b84286fSGerd Hoffmann             buf[l++] = e->buttons_state;
40249ab747fSPaolo Bonzini         }
40349ab747fSPaolo Bonzini         if (len > l) {
40449ab747fSPaolo Bonzini             buf[l++] = dx & 0xff;
40549ab747fSPaolo Bonzini         }
40649ab747fSPaolo Bonzini         if (len > l) {
40749ab747fSPaolo Bonzini             buf[l++] = dx >> 8;
40849ab747fSPaolo Bonzini         }
40949ab747fSPaolo Bonzini         if (len > l) {
41049ab747fSPaolo Bonzini             buf[l++] = dy & 0xff;
41149ab747fSPaolo Bonzini         }
41249ab747fSPaolo Bonzini         if (len > l) {
41349ab747fSPaolo Bonzini             buf[l++] = dy >> 8;
41449ab747fSPaolo Bonzini         }
41549ab747fSPaolo Bonzini         if (len > l) {
41649ab747fSPaolo Bonzini             buf[l++] = dz;
41749ab747fSPaolo Bonzini         }
41849ab747fSPaolo Bonzini         break;
41949ab747fSPaolo Bonzini 
42049ab747fSPaolo Bonzini     default:
42149ab747fSPaolo Bonzini         abort();
42249ab747fSPaolo Bonzini     }
42349ab747fSPaolo Bonzini 
42449ab747fSPaolo Bonzini     return l;
42549ab747fSPaolo Bonzini }
42649ab747fSPaolo Bonzini 
42749ab747fSPaolo Bonzini int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
42849ab747fSPaolo Bonzini {
42949ab747fSPaolo Bonzini     hs->idle_pending = false;
43049ab747fSPaolo Bonzini 
43149ab747fSPaolo Bonzini     if (len < 2) {
43249ab747fSPaolo Bonzini         return 0;
43349ab747fSPaolo Bonzini     }
43449ab747fSPaolo Bonzini 
43549ab747fSPaolo Bonzini     hid_keyboard_process_keycode(hs);
43649ab747fSPaolo Bonzini 
43749ab747fSPaolo Bonzini     buf[0] = hs->kbd.modifiers & 0xff;
43849ab747fSPaolo Bonzini     buf[1] = 0;
43949ab747fSPaolo Bonzini     if (hs->kbd.keys > 6) {
44049ab747fSPaolo Bonzini         memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
44149ab747fSPaolo Bonzini     } else {
44249ab747fSPaolo Bonzini         memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
44349ab747fSPaolo Bonzini     }
44449ab747fSPaolo Bonzini 
44549ab747fSPaolo Bonzini     return MIN(8, len);
44649ab747fSPaolo Bonzini }
44749ab747fSPaolo Bonzini 
44849ab747fSPaolo Bonzini int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
44949ab747fSPaolo Bonzini {
45049ab747fSPaolo Bonzini     if (len > 0) {
45149ab747fSPaolo Bonzini         int ledstate = 0;
45249ab747fSPaolo Bonzini         /* 0x01: Num Lock LED
45349ab747fSPaolo Bonzini          * 0x02: Caps Lock LED
45449ab747fSPaolo Bonzini          * 0x04: Scroll Lock LED
45549ab747fSPaolo Bonzini          * 0x08: Compose LED
45649ab747fSPaolo Bonzini          * 0x10: Kana LED */
45749ab747fSPaolo Bonzini         hs->kbd.leds = buf[0];
45849ab747fSPaolo Bonzini         if (hs->kbd.leds & 0x04) {
45949ab747fSPaolo Bonzini             ledstate |= QEMU_SCROLL_LOCK_LED;
46049ab747fSPaolo Bonzini         }
46149ab747fSPaolo Bonzini         if (hs->kbd.leds & 0x01) {
46249ab747fSPaolo Bonzini             ledstate |= QEMU_NUM_LOCK_LED;
46349ab747fSPaolo Bonzini         }
46449ab747fSPaolo Bonzini         if (hs->kbd.leds & 0x02) {
46549ab747fSPaolo Bonzini             ledstate |= QEMU_CAPS_LOCK_LED;
46649ab747fSPaolo Bonzini         }
46749ab747fSPaolo Bonzini         kbd_put_ledstate(ledstate);
46849ab747fSPaolo Bonzini     }
46949ab747fSPaolo Bonzini     return 0;
47049ab747fSPaolo Bonzini }
47149ab747fSPaolo Bonzini 
47249ab747fSPaolo Bonzini void hid_reset(HIDState *hs)
47349ab747fSPaolo Bonzini {
47449ab747fSPaolo Bonzini     switch (hs->kind) {
47549ab747fSPaolo Bonzini     case HID_KEYBOARD:
47649ab747fSPaolo Bonzini         memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
47749ab747fSPaolo Bonzini         memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
47849ab747fSPaolo Bonzini         hs->kbd.keys = 0;
47949ab747fSPaolo Bonzini         break;
48049ab747fSPaolo Bonzini     case HID_MOUSE:
48149ab747fSPaolo Bonzini     case HID_TABLET:
48249ab747fSPaolo Bonzini         memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
48349ab747fSPaolo Bonzini         break;
48449ab747fSPaolo Bonzini     }
48549ab747fSPaolo Bonzini     hs->head = 0;
48649ab747fSPaolo Bonzini     hs->n = 0;
48749ab747fSPaolo Bonzini     hs->protocol = 1;
48849ab747fSPaolo Bonzini     hs->idle = 0;
48949ab747fSPaolo Bonzini     hs->idle_pending = false;
49049ab747fSPaolo Bonzini     hid_del_idle_timer(hs);
49149ab747fSPaolo Bonzini }
49249ab747fSPaolo Bonzini 
49349ab747fSPaolo Bonzini void hid_free(HIDState *hs)
49449ab747fSPaolo Bonzini {
4951ff5eeddSGerd Hoffmann     qemu_input_handler_unregister(hs->s);
49649ab747fSPaolo Bonzini     hid_del_idle_timer(hs);
49749ab747fSPaolo Bonzini }
49849ab747fSPaolo Bonzini 
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 
51949ab747fSPaolo Bonzini void hid_init(HIDState *hs, int kind, HIDEventFunc event)
52049ab747fSPaolo Bonzini {
52149ab747fSPaolo Bonzini     hs->kind = kind;
52249ab747fSPaolo Bonzini     hs->event = event;
52349ab747fSPaolo Bonzini 
52449ab747fSPaolo Bonzini     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);
52849ab747fSPaolo Bonzini     } else if (hs->kind == HID_MOUSE) {
5298b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5308b84286fSGerd Hoffmann                                             &hid_mouse_handler);
53149ab747fSPaolo Bonzini     } else if (hs->kind == HID_TABLET) {
5328b84286fSGerd Hoffmann         hs->s = qemu_input_handler_register((DeviceState *)hs,
5338b84286fSGerd Hoffmann                                             &hid_tablet_handler);
53449ab747fSPaolo Bonzini     }
53549ab747fSPaolo Bonzini }
53649ab747fSPaolo Bonzini 
53749ab747fSPaolo Bonzini static int hid_post_load(void *opaque, int version_id)
53849ab747fSPaolo Bonzini {
53949ab747fSPaolo Bonzini     HIDState *s = opaque;
54049ab747fSPaolo Bonzini 
54149ab747fSPaolo Bonzini     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     }
56349ab747fSPaolo Bonzini     return 0;
56449ab747fSPaolo Bonzini }
56549ab747fSPaolo Bonzini 
56649ab747fSPaolo Bonzini static const VMStateDescription vmstate_hid_ptr_queue = {
56749ab747fSPaolo Bonzini     .name = "HIDPointerEventQueue",
56849ab747fSPaolo Bonzini     .version_id = 1,
56949ab747fSPaolo Bonzini     .minimum_version_id = 1,
57049ab747fSPaolo Bonzini     .fields = (VMStateField[]) {
57149ab747fSPaolo Bonzini         VMSTATE_INT32(xdx, HIDPointerEvent),
57249ab747fSPaolo Bonzini         VMSTATE_INT32(ydy, HIDPointerEvent),
57349ab747fSPaolo Bonzini         VMSTATE_INT32(dz, HIDPointerEvent),
57449ab747fSPaolo Bonzini         VMSTATE_INT32(buttons_state, HIDPointerEvent),
57549ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
57649ab747fSPaolo Bonzini     }
57749ab747fSPaolo Bonzini };
57849ab747fSPaolo Bonzini 
57949ab747fSPaolo Bonzini const VMStateDescription vmstate_hid_ptr_device = {
58049ab747fSPaolo Bonzini     .name = "HIDPointerDevice",
58149ab747fSPaolo Bonzini     .version_id = 1,
58249ab747fSPaolo Bonzini     .minimum_version_id = 1,
58349ab747fSPaolo Bonzini     .post_load = hid_post_load,
58449ab747fSPaolo Bonzini     .fields = (VMStateField[]) {
58549ab747fSPaolo Bonzini         VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
58649ab747fSPaolo Bonzini                              vmstate_hid_ptr_queue, HIDPointerEvent),
58749ab747fSPaolo Bonzini         VMSTATE_UINT32(head, HIDState),
58849ab747fSPaolo Bonzini         VMSTATE_UINT32(n, HIDState),
58949ab747fSPaolo Bonzini         VMSTATE_INT32(protocol, HIDState),
59049ab747fSPaolo Bonzini         VMSTATE_UINT8(idle, HIDState),
59149ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST(),
59249ab747fSPaolo Bonzini     }
59349ab747fSPaolo Bonzini };
59449ab747fSPaolo Bonzini 
59549ab747fSPaolo Bonzini const VMStateDescription vmstate_hid_keyboard_device = {
59649ab747fSPaolo Bonzini     .name = "HIDKeyboardDevice",
59749ab747fSPaolo Bonzini     .version_id = 1,
59849ab747fSPaolo Bonzini     .minimum_version_id = 1,
59949ab747fSPaolo Bonzini     .post_load = hid_post_load,
60049ab747fSPaolo Bonzini     .fields = (VMStateField[]) {
60149ab747fSPaolo Bonzini         VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
60249ab747fSPaolo Bonzini         VMSTATE_UINT32(head, HIDState),
60349ab747fSPaolo Bonzini         VMSTATE_UINT32(n, HIDState),
60449ab747fSPaolo Bonzini         VMSTATE_UINT16(kbd.modifiers, HIDState),
60549ab747fSPaolo Bonzini         VMSTATE_UINT8(kbd.leds, HIDState),
60649ab747fSPaolo Bonzini         VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
60749ab747fSPaolo Bonzini         VMSTATE_INT32(kbd.keys, HIDState),
60849ab747fSPaolo Bonzini         VMSTATE_INT32(protocol, HIDState),
60949ab747fSPaolo Bonzini         VMSTATE_UINT8(idle, HIDState),
61049ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST(),
61149ab747fSPaolo Bonzini     }
61249ab747fSPaolo Bonzini };
613