blob: aa4fb826fd27d02c668b4dca7075b5ac618d099b [file] [log] [blame]
Gerd Hoffmanndcfda672011-07-15 15:08:01 +02001/*
2 * QEMU HID devices
3 *
4 * Copyright (c) 2005 Fabrice Bellard
5 * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
Peter Maydell04308912016-01-26 18:17:30 +000025#include "qemu/osdep.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010026#include "hw/hw.h"
Paolo Bonzini28ecbae2012-11-28 12:06:30 +010027#include "ui/console.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010028#include "qemu/timer.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010029#include "hw/input/hid.h"
Gerd Hoffmannc80276b2016-06-23 11:51:35 +020030#include "trace.h"
Gerd Hoffmanndcfda672011-07-15 15:08:01 +020031
32#define HID_USAGE_ERROR_ROLLOVER 0x01
33#define HID_USAGE_POSTFAIL 0x02
34#define HID_USAGE_ERROR_UNDEFINED 0x03
35
36/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
37 * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
38static const uint8_t hid_usage_keys[0x100] = {
39 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
40 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
41 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
42 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
43 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
44 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
45 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
Dinar Valeev0ee4de52015-01-21 23:48:41 +010046 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
Gerd Hoffmanndcfda672011-07-15 15:08:01 +020047 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
48 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
Peter Korsgaard86f3bf02016-10-28 16:51:32 +020049 0x5a, 0x5b, 0x62, 0x63, 0x46, 0x00, 0x64, 0x44,
Gerd Hoffmanndcfda672011-07-15 15:08:01 +020050 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
51 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
55
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
Tao Wu160997f2017-12-06 22:56:39 -080060 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00,
62 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
Gerd Hoffmanndcfda672011-07-15 15:08:01 +020063 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Peter Korsgaard86f3bf02016-10-28 16:51:32 +020064 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x4a,
Gerd Hoffmanndcfda672011-07-15 15:08:01 +020065 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
66 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
Tao Wu160997f2017-12-06 22:56:39 -080067 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x66, 0x00,
Gerd Hoffmanndcfda672011-07-15 15:08:01 +020068 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72};
73
74bool hid_has_events(HIDState *hs)
75{
Hans de Goede027c03f2012-12-14 14:35:38 +010076 return hs->n > 0 || hs->idle_pending;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +020077}
78
Hans de Goede027c03f2012-12-14 14:35:38 +010079static void hid_idle_timer(void *opaque)
Gerd Hoffmannb069d342011-07-15 15:52:33 +020080{
Hans de Goede027c03f2012-12-14 14:35:38 +010081 HIDState *hs = opaque;
82
83 hs->idle_pending = true;
84 hs->event(hs);
85}
86
87static void hid_del_idle_timer(HIDState *hs)
88{
89 if (hs->idle_timer) {
Alex Blighbc72ad62013-08-21 16:03:08 +010090 timer_del(hs->idle_timer);
91 timer_free(hs->idle_timer);
Hans de Goede027c03f2012-12-14 14:35:38 +010092 hs->idle_timer = NULL;
93 }
94}
95
96void hid_set_next_idle(HIDState *hs)
97{
98 if (hs->idle) {
Alex Blighbc72ad62013-08-21 16:03:08 +010099 uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
Rutuja Shah73bcb242016-03-21 21:32:30 +0530100 NANOSECONDS_PER_SECOND * hs->idle * 4 / 1000;
Hans de Goede027c03f2012-12-14 14:35:38 +0100101 if (!hs->idle_timer) {
Alex Blighbc72ad62013-08-21 16:03:08 +0100102 hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs);
Hans de Goede027c03f2012-12-14 14:35:38 +0100103 }
Alex Blighbc72ad62013-08-21 16:03:08 +0100104 timer_mod_ns(hs->idle_timer, expire_time);
Hans de Goede027c03f2012-12-14 14:35:38 +0100105 } else {
106 hid_del_idle_timer(hs);
107 }
Gerd Hoffmannb069d342011-07-15 15:52:33 +0200108}
109
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200110static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
111 InputEvent *evt)
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200112{
Eric Blake7fb1cf12015-11-18 01:52:57 -0700113 static const int bmap[INPUT_BUTTON__MAX] = {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200114 [INPUT_BUTTON_LEFT] = 0x01,
115 [INPUT_BUTTON_RIGHT] = 0x02,
116 [INPUT_BUTTON_MIDDLE] = 0x04,
117 };
118 HIDState *hs = (HIDState *)dev;
119 HIDPointerEvent *e;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700120 InputMoveEvent *move;
121 InputBtnEvent *btn;
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200122
123 assert(hs->n < QUEUE_LENGTH);
124 e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
125
Eric Blake568c73a2015-10-26 16:34:58 -0600126 switch (evt->type) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200127 case INPUT_EVENT_KIND_REL:
Eric Blake32bafa82016-03-17 16:48:37 -0600128 move = evt->u.rel.data;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700129 if (move->axis == INPUT_AXIS_X) {
130 e->xdx += move->value;
131 } else if (move->axis == INPUT_AXIS_Y) {
132 e->ydy += move->value;
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200133 }
134 break;
135
136 case INPUT_EVENT_KIND_ABS:
Eric Blake32bafa82016-03-17 16:48:37 -0600137 move = evt->u.abs.data;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700138 if (move->axis == INPUT_AXIS_X) {
139 e->xdx = move->value;
140 } else if (move->axis == INPUT_AXIS_Y) {
141 e->ydy = move->value;
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200142 }
143 break;
144
145 case INPUT_EVENT_KIND_BTN:
Eric Blake32bafa82016-03-17 16:48:37 -0600146 btn = evt->u.btn.data;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700147 if (btn->down) {
148 e->buttons_state |= bmap[btn->button];
149 if (btn->button == INPUT_BUTTON_WHEEL_UP) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200150 e->dz--;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700151 } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200152 e->dz++;
153 }
154 } else {
Eric Blakeb5a1b442016-03-03 09:16:49 -0700155 e->buttons_state &= ~bmap[btn->button];
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200156 }
157 break;
158
159 default:
160 /* keep gcc happy */
161 break;
162 }
163
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200164}
165
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200166static void hid_pointer_sync(DeviceState *dev)
167{
168 HIDState *hs = (HIDState *)dev;
169 HIDPointerEvent *prev, *curr, *next;
170 bool event_compression = false;
171
172 if (hs->n == QUEUE_LENGTH-1) {
173 /*
Stefan Weil5d831be2014-06-13 20:42:57 +0200174 * Queue full. We are losing information, but we at least
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200175 * keep track of most recent button state.
176 */
177 return;
178 }
179
180 prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
181 curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
182 next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
183
184 if (hs->n > 0) {
185 /*
186 * No button state change between previous and current event
187 * (and previous wasn't seen by the guest yet), so there is
188 * motion information only and we can combine the two event
189 * into one.
190 */
191 if (curr->buttons_state == prev->buttons_state) {
192 event_compression = true;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200193 }
194 }
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200195
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200196 if (event_compression) {
197 /* add current motion to previous, clear current */
198 if (hs->kind == HID_MOUSE) {
199 prev->xdx += curr->xdx;
200 curr->xdx = 0;
Christian Burger35e83d12014-06-14 20:19:41 +0100201 prev->ydy += curr->ydy;
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200202 curr->ydy = 0;
203 } else {
204 prev->xdx = curr->xdx;
205 prev->ydy = curr->ydy;
206 }
207 prev->dz += curr->dz;
208 curr->dz = 0;
209 } else {
210 /* prepate next (clear rel, copy abs + btns) */
211 if (hs->kind == HID_MOUSE) {
212 next->xdx = 0;
213 next->ydy = 0;
214 } else {
215 next->xdx = curr->xdx;
216 next->ydy = curr->ydy;
217 }
218 next->dz = 0;
219 next->buttons_state = curr->buttons_state;
220 /* make current guest visible, notify guest */
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200221 hs->n++;
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200222 hs->event(hs);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200223 }
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200224}
225
Gerd Hoffmann1ff5eed2014-03-11 13:52:27 +0100226static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
227 InputEvent *evt)
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200228{
Gerd Hoffmann1ff5eed2014-03-11 13:52:27 +0100229 HIDState *hs = (HIDState *)dev;
230 int scancodes[3], i, count;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200231 int slot;
Eric Blake32bafa82016-03-17 16:48:37 -0600232 InputKeyEvent *key = evt->u.key.data;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200233
Eric Blakeb5a1b442016-03-03 09:16:49 -0700234 count = qemu_input_key_value_to_scancode(key->key,
235 key->down,
Gerd Hoffmann1ff5eed2014-03-11 13:52:27 +0100236 scancodes);
237 if (hs->n + count > QUEUE_LENGTH) {
Gerd Hoffmannc80276b2016-06-23 11:51:35 +0200238 trace_hid_kbd_queue_full();
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200239 return;
240 }
Gerd Hoffmann1ff5eed2014-03-11 13:52:27 +0100241 for (i = 0; i < count; i++) {
242 slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
243 hs->kbd.keycodes[slot] = scancodes[i];
244 }
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200245 hs->event(hs);
246}
247
248static void hid_keyboard_process_keycode(HIDState *hs)
249{
Paolo Bonzini562f9372015-07-14 11:18:06 +0200250 uint8_t hid_code, index, key;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200251 int i, keycode, slot;
252
253 if (hs->n == 0) {
254 return;
255 }
256 slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
257 keycode = hs->kbd.keycodes[slot];
258
Alexander Graf2222e0a2017-03-30 16:22:55 +0200259 if (!hs->n) {
260 trace_hid_kbd_queue_empty();
261 }
262
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200263 key = keycode & 0x7f;
Paolo Bonzini562f9372015-07-14 11:18:06 +0200264 index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
265 hid_code = hid_usage_keys[index];
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200266 hs->kbd.modifiers &= ~(1 << 8);
267
268 switch (hid_code) {
269 case 0x00:
270 return;
271
272 case 0xe0:
Paolo Bonzini562f9372015-07-14 11:18:06 +0200273 assert(key == 0x1d);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200274 if (hs->kbd.modifiers & (1 << 9)) {
Paolo Bonzini562f9372015-07-14 11:18:06 +0200275 /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
276 * Here we're processing the second hid_code. By dropping bit 9
277 * and setting bit 8, the scancode after 0x1d will access the
278 * second half of the table.
279 */
280 hs->kbd.modifiers ^= (1 << 8) | (1 << 9);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200281 return;
282 }
Paolo Bonzini562f9372015-07-14 11:18:06 +0200283 /* fall through to process Ctrl_L */
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200284 case 0xe1 ... 0xe7:
Paolo Bonzini562f9372015-07-14 11:18:06 +0200285 /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
286 * Handle releases here, or fall through to process presses.
287 */
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200288 if (keycode & (1 << 7)) {
289 hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
290 return;
291 }
Paolo Bonzini562f9372015-07-14 11:18:06 +0200292 /* fall through */
293 case 0xe8 ... 0xe9:
294 /* USB modifiers are just 1 byte long. Bits 8 and 9 of
295 * hs->kbd.modifiers implement a state machine that detects the
296 * 0xe0 and 0xe1/0x1d sequences. These bits do not follow the
297 * usual rules where bit 7 marks released keys; they are cleared
298 * elsewhere in the function as the state machine dictates.
299 */
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200300 hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
301 return;
Paolo Bonzini562f9372015-07-14 11:18:06 +0200302
303 case 0xea ... 0xef:
304 abort();
305
306 default:
307 break;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200308 }
309
310 if (keycode & (1 << 7)) {
311 for (i = hs->kbd.keys - 1; i >= 0; i--) {
312 if (hs->kbd.key[i] == hid_code) {
313 hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
314 hs->kbd.key[hs->kbd.keys] = 0x00;
315 break;
316 }
317 }
318 if (i < 0) {
319 return;
320 }
321 } else {
322 for (i = hs->kbd.keys - 1; i >= 0; i--) {
323 if (hs->kbd.key[i] == hid_code) {
324 break;
325 }
326 }
327 if (i < 0) {
328 if (hs->kbd.keys < sizeof(hs->kbd.key)) {
329 hs->kbd.key[hs->kbd.keys++] = hid_code;
330 }
331 } else {
332 return;
333 }
334 }
335}
336
337static inline int int_clamp(int val, int vmin, int vmax)
338{
339 if (val < vmin) {
340 return vmin;
341 } else if (val > vmax) {
342 return vmax;
343 } else {
344 return val;
345 }
346}
347
Gerd Hoffmann21635e12011-08-09 12:35:57 +0200348void hid_pointer_activate(HIDState *hs)
349{
350 if (!hs->ptr.mouse_grabbed) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200351 qemu_input_handler_activate(hs->s);
Gerd Hoffmann21635e12011-08-09 12:35:57 +0200352 hs->ptr.mouse_grabbed = 1;
353 }
354}
355
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200356int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
357{
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200358 int dx, dy, dz, l;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200359 int index;
360 HIDPointerEvent *e;
361
Hans de Goede027c03f2012-12-14 14:35:38 +0100362 hs->idle_pending = false;
363
Gerd Hoffmann21635e12011-08-09 12:35:57 +0200364 hid_pointer_activate(hs);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200365
366 /* When the buffer is empty, return the last event. Relative
367 movements will all be zero. */
368 index = (hs->n ? hs->head : hs->head - 1);
369 e = &hs->ptr.queue[index & QUEUE_MASK];
370
371 if (hs->kind == HID_MOUSE) {
372 dx = int_clamp(e->xdx, -127, 127);
373 dy = int_clamp(e->ydy, -127, 127);
374 e->xdx -= dx;
375 e->ydy -= dy;
376 } else {
377 dx = e->xdx;
378 dy = e->ydy;
379 }
380 dz = int_clamp(e->dz, -127, 127);
381 e->dz -= dz;
382
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200383 if (hs->n &&
384 !e->dz &&
385 (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
386 /* that deals with this event */
387 QUEUE_INCR(hs->head);
388 hs->n--;
389 }
390
391 /* Appears we have to invert the wheel direction */
392 dz = 0 - dz;
393 l = 0;
394 switch (hs->kind) {
395 case HID_MOUSE:
396 if (len > l) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200397 buf[l++] = e->buttons_state;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200398 }
399 if (len > l) {
400 buf[l++] = dx;
401 }
402 if (len > l) {
403 buf[l++] = dy;
404 }
405 if (len > l) {
406 buf[l++] = dz;
407 }
408 break;
409
410 case HID_TABLET:
411 if (len > l) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200412 buf[l++] = e->buttons_state;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200413 }
414 if (len > l) {
415 buf[l++] = dx & 0xff;
416 }
417 if (len > l) {
418 buf[l++] = dx >> 8;
419 }
420 if (len > l) {
421 buf[l++] = dy & 0xff;
422 }
423 if (len > l) {
424 buf[l++] = dy >> 8;
425 }
426 if (len > l) {
427 buf[l++] = dz;
428 }
429 break;
430
431 default:
432 abort();
433 }
434
435 return l;
436}
437
438int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
439{
Hans de Goede027c03f2012-12-14 14:35:38 +0100440 hs->idle_pending = false;
441
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200442 if (len < 2) {
443 return 0;
444 }
445
446 hid_keyboard_process_keycode(hs);
447
448 buf[0] = hs->kbd.modifiers & 0xff;
449 buf[1] = 0;
450 if (hs->kbd.keys > 6) {
451 memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
452 } else {
453 memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
454 }
455
456 return MIN(8, len);
457}
458
459int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
460{
461 if (len > 0) {
462 int ledstate = 0;
463 /* 0x01: Num Lock LED
464 * 0x02: Caps Lock LED
465 * 0x04: Scroll Lock LED
466 * 0x08: Compose LED
467 * 0x10: Kana LED */
468 hs->kbd.leds = buf[0];
469 if (hs->kbd.leds & 0x04) {
470 ledstate |= QEMU_SCROLL_LOCK_LED;
471 }
472 if (hs->kbd.leds & 0x01) {
473 ledstate |= QEMU_NUM_LOCK_LED;
474 }
475 if (hs->kbd.leds & 0x02) {
476 ledstate |= QEMU_CAPS_LOCK_LED;
477 }
478 kbd_put_ledstate(ledstate);
479 }
480 return 0;
481}
482
483void hid_reset(HIDState *hs)
484{
485 switch (hs->kind) {
486 case HID_KEYBOARD:
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200487 memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
488 memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
489 hs->kbd.keys = 0;
Alexander Graf51dbea72017-06-22 09:41:35 +0200490 hs->kbd.modifiers = 0;
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200491 break;
492 case HID_MOUSE:
493 case HID_TABLET:
494 memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
495 break;
496 }
497 hs->head = 0;
498 hs->n = 0;
Gerd Hoffmannb069d342011-07-15 15:52:33 +0200499 hs->protocol = 1;
500 hs->idle = 0;
Hans de Goede027c03f2012-12-14 14:35:38 +0100501 hs->idle_pending = false;
502 hid_del_idle_timer(hs);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200503}
504
505void hid_free(HIDState *hs)
506{
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200507 qemu_input_handler_unregister(hs->s);
Hans de Goede027c03f2012-12-14 14:35:38 +0100508 hid_del_idle_timer(hs);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200509}
510
Gerd Hoffmann1ff5eed2014-03-11 13:52:27 +0100511static QemuInputHandler hid_keyboard_handler = {
512 .name = "QEMU HID Keyboard",
513 .mask = INPUT_EVENT_MASK_KEY,
514 .event = hid_keyboard_event,
515};
516
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200517static QemuInputHandler hid_mouse_handler = {
518 .name = "QEMU HID Mouse",
519 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
520 .event = hid_pointer_event,
521 .sync = hid_pointer_sync,
522};
523
524static QemuInputHandler hid_tablet_handler = {
525 .name = "QEMU HID Tablet",
526 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
527 .event = hid_pointer_event,
528 .sync = hid_pointer_sync,
529};
530
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200531void hid_init(HIDState *hs, int kind, HIDEventFunc event)
532{
533 hs->kind = kind;
534 hs->event = event;
535
Michael Wallebb0db522011-08-09 23:54:52 +0200536 if (hs->kind == HID_KEYBOARD) {
Gerd Hoffmann1ff5eed2014-03-11 13:52:27 +0100537 hs->s = qemu_input_handler_register((DeviceState *)hs,
538 &hid_keyboard_handler);
539 qemu_input_handler_activate(hs->s);
Michael Wallebb0db522011-08-09 23:54:52 +0200540 } else if (hs->kind == HID_MOUSE) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200541 hs->s = qemu_input_handler_register((DeviceState *)hs,
542 &hid_mouse_handler);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200543 } else if (hs->kind == HID_TABLET) {
Gerd Hoffmann8b842862014-05-19 15:02:21 +0200544 hs->s = qemu_input_handler_register((DeviceState *)hs,
545 &hid_tablet_handler);
Gerd Hoffmanndcfda672011-07-15 15:08:01 +0200546 }
547}
Michael Walleccd4ed02011-08-09 23:54:53 +0200548
549static int hid_post_load(void *opaque, int version_id)
550{
551 HIDState *s = opaque;
552
Hans de Goede027c03f2012-12-14 14:35:38 +0100553 hid_set_next_idle(s);
Gerd Hoffmannba4d2602014-11-27 10:02:35 +0100554
555 if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
556 s->kind == HID_MOUSE)) {
557 /*
558 * Handle ptr device migration from old qemu with full queue.
559 *
560 * Throw away everything but the last event, so we propagate
561 * at least the current button state to the guest. Also keep
562 * current position for the tablet, signal "no motion" for the
563 * mouse.
564 */
565 HIDPointerEvent evt;
566 evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
567 if (s->kind == HID_MOUSE) {
568 evt.xdx = 0;
569 evt.ydy = 0;
570 }
571 s->ptr.queue[0] = evt;
572 s->head = 0;
573 s->n = 1;
574 }
Michael Walleccd4ed02011-08-09 23:54:53 +0200575 return 0;
576}
577
578static const VMStateDescription vmstate_hid_ptr_queue = {
579 .name = "HIDPointerEventQueue",
580 .version_id = 1,
581 .minimum_version_id = 1,
582 .fields = (VMStateField[]) {
583 VMSTATE_INT32(xdx, HIDPointerEvent),
584 VMSTATE_INT32(ydy, HIDPointerEvent),
585 VMSTATE_INT32(dz, HIDPointerEvent),
586 VMSTATE_INT32(buttons_state, HIDPointerEvent),
587 VMSTATE_END_OF_LIST()
588 }
589};
590
591const VMStateDescription vmstate_hid_ptr_device = {
592 .name = "HIDPointerDevice",
593 .version_id = 1,
594 .minimum_version_id = 1,
595 .post_load = hid_post_load,
596 .fields = (VMStateField[]) {
597 VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
598 vmstate_hid_ptr_queue, HIDPointerEvent),
599 VMSTATE_UINT32(head, HIDState),
600 VMSTATE_UINT32(n, HIDState),
601 VMSTATE_INT32(protocol, HIDState),
602 VMSTATE_UINT8(idle, HIDState),
603 VMSTATE_END_OF_LIST(),
604 }
605};
606
607const VMStateDescription vmstate_hid_keyboard_device = {
608 .name = "HIDKeyboardDevice",
609 .version_id = 1,
610 .minimum_version_id = 1,
611 .post_load = hid_post_load,
612 .fields = (VMStateField[]) {
613 VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
614 VMSTATE_UINT32(head, HIDState),
615 VMSTATE_UINT32(n, HIDState),
616 VMSTATE_UINT16(kbd.modifiers, HIDState),
617 VMSTATE_UINT8(kbd.leds, HIDState),
618 VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
619 VMSTATE_INT32(kbd.keys, HIDState),
620 VMSTATE_INT32(protocol, HIDState),
621 VMSTATE_UINT8(idle, HIDState),
622 VMSTATE_END_OF_LIST(),
623 }
624};