]> git.proxmox.com Git - mirror_qemu.git/blame - hw/input/hid.c
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
[mirror_qemu.git] / hw / input / hid.c
CommitLineData
dcfda673
GH
1/*
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 */
83c9f4ca 25#include "hw/hw.h"
28ecbaee 26#include "ui/console.h"
1de7afc9 27#include "qemu/timer.h"
0d09e41a 28#include "hw/input/hid.h"
dcfda673
GH
29
30#define HID_USAGE_ERROR_ROLLOVER 0x01
31#define HID_USAGE_POSTFAIL 0x02
32#define HID_USAGE_ERROR_UNDEFINED 0x03
33
34/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
35 * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
36static const uint8_t hid_usage_keys[0x100] = {
37 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
38 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
39 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
40 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
41 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
42 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
43 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
0ee4de58 44 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
dcfda673
GH
45 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
46 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
47 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
48 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
49 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
53
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
61 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
63 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
64 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70};
71
72bool hid_has_events(HIDState *hs)
73{
027c03f7 74 return hs->n > 0 || hs->idle_pending;
dcfda673
GH
75}
76
027c03f7 77static void hid_idle_timer(void *opaque)
b069d348 78{
027c03f7
HG
79 HIDState *hs = opaque;
80
81 hs->idle_pending = true;
82 hs->event(hs);
83}
84
85static void hid_del_idle_timer(HIDState *hs)
86{
87 if (hs->idle_timer) {
bc72ad67
AB
88 timer_del(hs->idle_timer);
89 timer_free(hs->idle_timer);
027c03f7
HG
90 hs->idle_timer = NULL;
91 }
92}
93
94void hid_set_next_idle(HIDState *hs)
95{
96 if (hs->idle) {
bc72ad67 97 uint64_t expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
027c03f7
HG
98 get_ticks_per_sec() * hs->idle * 4 / 1000;
99 if (!hs->idle_timer) {
bc72ad67 100 hs->idle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hid_idle_timer, hs);
027c03f7 101 }
bc72ad67 102 timer_mod_ns(hs->idle_timer, expire_time);
027c03f7
HG
103 } else {
104 hid_del_idle_timer(hs);
105 }
b069d348
GH
106}
107
8b84286f
GH
108static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
109 InputEvent *evt)
dcfda673 110{
8b84286f
GH
111 static const int bmap[INPUT_BUTTON_MAX] = {
112 [INPUT_BUTTON_LEFT] = 0x01,
113 [INPUT_BUTTON_RIGHT] = 0x02,
114 [INPUT_BUTTON_MIDDLE] = 0x04,
115 };
116 HIDState *hs = (HIDState *)dev;
117 HIDPointerEvent *e;
dcfda673 118
8b84286f
GH
119 assert(hs->n < QUEUE_LENGTH);
120 e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
121
122 switch (evt->kind) {
123 case INPUT_EVENT_KIND_REL:
124 if (evt->rel->axis == INPUT_AXIS_X) {
125 e->xdx += evt->rel->value;
126 } else if (evt->rel->axis == INPUT_AXIS_Y) {
35e83d10 127 e->ydy += evt->rel->value;
8b84286f
GH
128 }
129 break;
130
131 case INPUT_EVENT_KIND_ABS:
132 if (evt->rel->axis == INPUT_AXIS_X) {
133 e->xdx = evt->rel->value;
134 } else if (evt->rel->axis == INPUT_AXIS_Y) {
135 e->ydy = evt->rel->value;
136 }
137 break;
138
139 case INPUT_EVENT_KIND_BTN:
140 if (evt->btn->down) {
141 e->buttons_state |= bmap[evt->btn->button];
142 if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
143 e->dz--;
144 } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
145 e->dz++;
146 }
147 } else {
148 e->buttons_state &= ~bmap[evt->btn->button];
dcfda673 149 }
8b84286f
GH
150 break;
151
152 default:
153 /* keep gcc happy */
154 break;
dcfda673 155 }
8b84286f 156
dcfda673
GH
157}
158
8b84286f 159static void hid_pointer_sync(DeviceState *dev)
dcfda673 160{
8b84286f
GH
161 HIDState *hs = (HIDState *)dev;
162 HIDPointerEvent *prev, *curr, *next;
163 bool event_compression = false;
164
165 if (hs->n == QUEUE_LENGTH-1) {
166 /*
5d831be2 167 * Queue full. We are losing information, but we at least
8b84286f
GH
168 * keep track of most recent button state.
169 */
170 return;
171 }
172
173 prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
174 curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
175 next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
176
177 if (hs->n > 0) {
178 /*
179 * No button state change between previous and current event
180 * (and previous wasn't seen by the guest yet), so there is
181 * motion information only and we can combine the two event
182 * into one.
183 */
184 if (curr->buttons_state == prev->buttons_state) {
185 event_compression = true;
186 }
187 }
188
189 if (event_compression) {
190 /* add current motion to previous, clear current */
191 if (hs->kind == HID_MOUSE) {
192 prev->xdx += curr->xdx;
193 curr->xdx = 0;
35e83d10 194 prev->ydy += curr->ydy;
8b84286f
GH
195 curr->ydy = 0;
196 } else {
197 prev->xdx = curr->xdx;
198 prev->ydy = curr->ydy;
199 }
200 prev->dz += curr->dz;
201 curr->dz = 0;
202 } else {
203 /* prepate next (clear rel, copy abs + btns) */
204 if (hs->kind == HID_MOUSE) {
205 next->xdx = 0;
206 next->ydy = 0;
207 } else {
208 next->xdx = curr->xdx;
209 next->ydy = curr->ydy;
210 }
211 next->dz = 0;
212 next->buttons_state = curr->buttons_state;
213 /* make current guest visible, notify guest */
dcfda673 214 hs->n++;
8b84286f 215 hs->event(hs);
dcfda673 216 }
dcfda673
GH
217}
218
1ff5eedd
GH
219static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
220 InputEvent *evt)
dcfda673 221{
1ff5eedd
GH
222 HIDState *hs = (HIDState *)dev;
223 int scancodes[3], i, count;
dcfda673
GH
224 int slot;
225
1ff5eedd
GH
226 count = qemu_input_key_value_to_scancode(evt->key->key,
227 evt->key->down,
228 scancodes);
229 if (hs->n + count > QUEUE_LENGTH) {
dcfda673
GH
230 fprintf(stderr, "usb-kbd: warning: key event queue full\n");
231 return;
232 }
1ff5eedd
GH
233 for (i = 0; i < count; i++) {
234 slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
235 hs->kbd.keycodes[slot] = scancodes[i];
236 }
dcfda673
GH
237 hs->event(hs);
238}
239
240static void hid_keyboard_process_keycode(HIDState *hs)
241{
242 uint8_t hid_code, key;
243 int i, keycode, slot;
244
245 if (hs->n == 0) {
246 return;
247 }
248 slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
249 keycode = hs->kbd.keycodes[slot];
250
251 key = keycode & 0x7f;
252 hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
253 hs->kbd.modifiers &= ~(1 << 8);
254
255 switch (hid_code) {
256 case 0x00:
257 return;
258
259 case 0xe0:
260 if (hs->kbd.modifiers & (1 << 9)) {
261 hs->kbd.modifiers ^= 3 << 8;
262 return;
263 }
264 case 0xe1 ... 0xe7:
265 if (keycode & (1 << 7)) {
266 hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
267 return;
268 }
269 case 0xe8 ... 0xef:
270 hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
271 return;
272 }
273
274 if (keycode & (1 << 7)) {
275 for (i = hs->kbd.keys - 1; i >= 0; i--) {
276 if (hs->kbd.key[i] == hid_code) {
277 hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
278 hs->kbd.key[hs->kbd.keys] = 0x00;
279 break;
280 }
281 }
282 if (i < 0) {
283 return;
284 }
285 } else {
286 for (i = hs->kbd.keys - 1; i >= 0; i--) {
287 if (hs->kbd.key[i] == hid_code) {
288 break;
289 }
290 }
291 if (i < 0) {
292 if (hs->kbd.keys < sizeof(hs->kbd.key)) {
293 hs->kbd.key[hs->kbd.keys++] = hid_code;
294 }
295 } else {
296 return;
297 }
298 }
299}
300
301static inline int int_clamp(int val, int vmin, int vmax)
302{
303 if (val < vmin) {
304 return vmin;
305 } else if (val > vmax) {
306 return vmax;
307 } else {
308 return val;
309 }
310}
311
21635e12
GH
312void hid_pointer_activate(HIDState *hs)
313{
314 if (!hs->ptr.mouse_grabbed) {
8b84286f 315 qemu_input_handler_activate(hs->s);
21635e12
GH
316 hs->ptr.mouse_grabbed = 1;
317 }
318}
319
dcfda673
GH
320int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
321{
8b84286f 322 int dx, dy, dz, l;
dcfda673
GH
323 int index;
324 HIDPointerEvent *e;
325
027c03f7
HG
326 hs->idle_pending = false;
327
21635e12 328 hid_pointer_activate(hs);
dcfda673
GH
329
330 /* When the buffer is empty, return the last event. Relative
331 movements will all be zero. */
332 index = (hs->n ? hs->head : hs->head - 1);
333 e = &hs->ptr.queue[index & QUEUE_MASK];
334
335 if (hs->kind == HID_MOUSE) {
336 dx = int_clamp(e->xdx, -127, 127);
337 dy = int_clamp(e->ydy, -127, 127);
338 e->xdx -= dx;
339 e->ydy -= dy;
340 } else {
341 dx = e->xdx;
342 dy = e->ydy;
343 }
344 dz = int_clamp(e->dz, -127, 127);
345 e->dz -= dz;
346
dcfda673
GH
347 if (hs->n &&
348 !e->dz &&
349 (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
350 /* that deals with this event */
351 QUEUE_INCR(hs->head);
352 hs->n--;
353 }
354
355 /* Appears we have to invert the wheel direction */
356 dz = 0 - dz;
357 l = 0;
358 switch (hs->kind) {
359 case HID_MOUSE:
360 if (len > l) {
8b84286f 361 buf[l++] = e->buttons_state;
dcfda673
GH
362 }
363 if (len > l) {
364 buf[l++] = dx;
365 }
366 if (len > l) {
367 buf[l++] = dy;
368 }
369 if (len > l) {
370 buf[l++] = dz;
371 }
372 break;
373
374 case HID_TABLET:
375 if (len > l) {
8b84286f 376 buf[l++] = e->buttons_state;
dcfda673
GH
377 }
378 if (len > l) {
379 buf[l++] = dx & 0xff;
380 }
381 if (len > l) {
382 buf[l++] = dx >> 8;
383 }
384 if (len > l) {
385 buf[l++] = dy & 0xff;
386 }
387 if (len > l) {
388 buf[l++] = dy >> 8;
389 }
390 if (len > l) {
391 buf[l++] = dz;
392 }
393 break;
394
395 default:
396 abort();
397 }
398
399 return l;
400}
401
402int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
403{
027c03f7
HG
404 hs->idle_pending = false;
405
dcfda673
GH
406 if (len < 2) {
407 return 0;
408 }
409
410 hid_keyboard_process_keycode(hs);
411
412 buf[0] = hs->kbd.modifiers & 0xff;
413 buf[1] = 0;
414 if (hs->kbd.keys > 6) {
415 memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
416 } else {
417 memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
418 }
419
420 return MIN(8, len);
421}
422
423int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
424{
425 if (len > 0) {
426 int ledstate = 0;
427 /* 0x01: Num Lock LED
428 * 0x02: Caps Lock LED
429 * 0x04: Scroll Lock LED
430 * 0x08: Compose LED
431 * 0x10: Kana LED */
432 hs->kbd.leds = buf[0];
433 if (hs->kbd.leds & 0x04) {
434 ledstate |= QEMU_SCROLL_LOCK_LED;
435 }
436 if (hs->kbd.leds & 0x01) {
437 ledstate |= QEMU_NUM_LOCK_LED;
438 }
439 if (hs->kbd.leds & 0x02) {
440 ledstate |= QEMU_CAPS_LOCK_LED;
441 }
442 kbd_put_ledstate(ledstate);
443 }
444 return 0;
445}
446
447void hid_reset(HIDState *hs)
448{
449 switch (hs->kind) {
450 case HID_KEYBOARD:
dcfda673
GH
451 memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
452 memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
453 hs->kbd.keys = 0;
454 break;
455 case HID_MOUSE:
456 case HID_TABLET:
457 memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
458 break;
459 }
460 hs->head = 0;
461 hs->n = 0;
b069d348
GH
462 hs->protocol = 1;
463 hs->idle = 0;
027c03f7
HG
464 hs->idle_pending = false;
465 hid_del_idle_timer(hs);
dcfda673
GH
466}
467
468void hid_free(HIDState *hs)
469{
8b84286f 470 qemu_input_handler_unregister(hs->s);
027c03f7 471 hid_del_idle_timer(hs);
dcfda673
GH
472}
473
1ff5eedd
GH
474static QemuInputHandler hid_keyboard_handler = {
475 .name = "QEMU HID Keyboard",
476 .mask = INPUT_EVENT_MASK_KEY,
477 .event = hid_keyboard_event,
478};
479
8b84286f
GH
480static QemuInputHandler hid_mouse_handler = {
481 .name = "QEMU HID Mouse",
482 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
483 .event = hid_pointer_event,
484 .sync = hid_pointer_sync,
485};
486
487static QemuInputHandler hid_tablet_handler = {
488 .name = "QEMU HID Tablet",
489 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
490 .event = hid_pointer_event,
491 .sync = hid_pointer_sync,
492};
493
dcfda673
GH
494void hid_init(HIDState *hs, int kind, HIDEventFunc event)
495{
496 hs->kind = kind;
497 hs->event = event;
498
bb0db527 499 if (hs->kind == HID_KEYBOARD) {
1ff5eedd
GH
500 hs->s = qemu_input_handler_register((DeviceState *)hs,
501 &hid_keyboard_handler);
502 qemu_input_handler_activate(hs->s);
bb0db527 503 } else if (hs->kind == HID_MOUSE) {
8b84286f
GH
504 hs->s = qemu_input_handler_register((DeviceState *)hs,
505 &hid_mouse_handler);
dcfda673 506 } else if (hs->kind == HID_TABLET) {
8b84286f
GH
507 hs->s = qemu_input_handler_register((DeviceState *)hs,
508 &hid_tablet_handler);
dcfda673
GH
509 }
510}
ccd4ed06
MW
511
512static int hid_post_load(void *opaque, int version_id)
513{
514 HIDState *s = opaque;
515
027c03f7 516 hid_set_next_idle(s);
ba4d2606
GH
517
518 if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
519 s->kind == HID_MOUSE)) {
520 /*
521 * Handle ptr device migration from old qemu with full queue.
522 *
523 * Throw away everything but the last event, so we propagate
524 * at least the current button state to the guest. Also keep
525 * current position for the tablet, signal "no motion" for the
526 * mouse.
527 */
528 HIDPointerEvent evt;
529 evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
530 if (s->kind == HID_MOUSE) {
531 evt.xdx = 0;
532 evt.ydy = 0;
533 }
534 s->ptr.queue[0] = evt;
535 s->head = 0;
536 s->n = 1;
537 }
ccd4ed06
MW
538 return 0;
539}
540
541static const VMStateDescription vmstate_hid_ptr_queue = {
542 .name = "HIDPointerEventQueue",
543 .version_id = 1,
544 .minimum_version_id = 1,
545 .fields = (VMStateField[]) {
546 VMSTATE_INT32(xdx, HIDPointerEvent),
547 VMSTATE_INT32(ydy, HIDPointerEvent),
548 VMSTATE_INT32(dz, HIDPointerEvent),
549 VMSTATE_INT32(buttons_state, HIDPointerEvent),
550 VMSTATE_END_OF_LIST()
551 }
552};
553
554const VMStateDescription vmstate_hid_ptr_device = {
555 .name = "HIDPointerDevice",
556 .version_id = 1,
557 .minimum_version_id = 1,
558 .post_load = hid_post_load,
559 .fields = (VMStateField[]) {
560 VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
561 vmstate_hid_ptr_queue, HIDPointerEvent),
562 VMSTATE_UINT32(head, HIDState),
563 VMSTATE_UINT32(n, HIDState),
564 VMSTATE_INT32(protocol, HIDState),
565 VMSTATE_UINT8(idle, HIDState),
566 VMSTATE_END_OF_LIST(),
567 }
568};
569
570const VMStateDescription vmstate_hid_keyboard_device = {
571 .name = "HIDKeyboardDevice",
572 .version_id = 1,
573 .minimum_version_id = 1,
574 .post_load = hid_post_load,
575 .fields = (VMStateField[]) {
576 VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
577 VMSTATE_UINT32(head, HIDState),
578 VMSTATE_UINT32(n, HIDState),
579 VMSTATE_UINT16(kbd.modifiers, HIDState),
580 VMSTATE_UINT8(kbd.leds, HIDState),
581 VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
582 VMSTATE_INT32(kbd.keys, HIDState),
583 VMSTATE_INT32(protocol, HIDState),
584 VMSTATE_UINT8(idle, HIDState),
585 VMSTATE_END_OF_LIST(),
586 }
587};