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