]> git.proxmox.com Git - mirror_qemu.git/blame - hw/input/hid.c
Drop the deprecated lm32 target
[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,
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
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,
117 };
118 HIDState *hs = (HIDState *)dev;
119 HIDPointerEvent *e;
b5a1b443
EB
120 InputMoveEvent *move;
121 InputBtnEvent *btn;
dcfda673 122
8b84286f
GH
123 assert(hs->n < QUEUE_LENGTH);
124 e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
125
568c73a4 126 switch (evt->type) {
8b84286f 127 case INPUT_EVENT_KIND_REL:
32bafa8f 128 move = evt->u.rel.data;
b5a1b443
EB
129 if (move->axis == INPUT_AXIS_X) {
130 e->xdx += move->value;
131 } else if (move->axis == INPUT_AXIS_Y) {
132 e->ydy += move->value;
8b84286f
GH
133 }
134 break;
135
136 case INPUT_EVENT_KIND_ABS:
32bafa8f 137 move = evt->u.abs.data;
b5a1b443
EB
138 if (move->axis == INPUT_AXIS_X) {
139 e->xdx = move->value;
140 } else if (move->axis == INPUT_AXIS_Y) {
141 e->ydy = move->value;
8b84286f
GH
142 }
143 break;
144
145 case INPUT_EVENT_KIND_BTN:
32bafa8f 146 btn = evt->u.btn.data;
b5a1b443
EB
147 if (btn->down) {
148 e->buttons_state |= bmap[btn->button];
149 if (btn->button == INPUT_BUTTON_WHEEL_UP) {
8b84286f 150 e->dz--;
b5a1b443 151 } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
8b84286f
GH
152 e->dz++;
153 }
154 } else {
b5a1b443 155 e->buttons_state &= ~bmap[btn->button];
dcfda673 156 }
8b84286f
GH
157 break;
158
159 default:
160 /* keep gcc happy */
161 break;
dcfda673 162 }
8b84286f 163
dcfda673
GH
164}
165
8b84286f 166static void hid_pointer_sync(DeviceState *dev)
dcfda673 167{
8b84286f
GH
168 HIDState *hs = (HIDState *)dev;
169 HIDPointerEvent *prev, *curr, *next;
170 bool event_compression = false;
171
172 if (hs->n == QUEUE_LENGTH-1) {
173 /*
5d831be2 174 * Queue full. We are losing information, but we at least
8b84286f
GH
175 * 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;
193 }
194 }
195
196 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;
35e83d10 201 prev->ydy += curr->ydy;
8b84286f
GH
202 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 */
dcfda673 221 hs->n++;
8b84286f 222 hs->event(hs);
dcfda673 223 }
dcfda673
GH
224}
225
1ff5eedd
GH
226static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
227 InputEvent *evt)
dcfda673 228{
1ff5eedd
GH
229 HIDState *hs = (HIDState *)dev;
230 int scancodes[3], i, count;
dcfda673 231 int slot;
32bafa8f 232 InputKeyEvent *key = evt->u.key.data;
dcfda673 233
b5a1b443
EB
234 count = qemu_input_key_value_to_scancode(key->key,
235 key->down,
1ff5eedd
GH
236 scancodes);
237 if (hs->n + count > QUEUE_LENGTH) {
c80276b4 238 trace_hid_kbd_queue_full();
dcfda673
GH
239 return;
240 }
1ff5eedd
GH
241 for (i = 0; i < count; i++) {
242 slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
243 hs->kbd.keycodes[slot] = scancodes[i];
244 }
dcfda673
GH
245 hs->event(hs);
246}
247
248static void hid_keyboard_process_keycode(HIDState *hs)
249{
562f9375 250 uint8_t hid_code, index, key;
dcfda673
GH
251 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
2222e0a6
AG
259 if (!hs->n) {
260 trace_hid_kbd_queue_empty();
261 }
262
dcfda673 263 key = keycode & 0x7f;
562f9375
PB
264 index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
265 hid_code = hid_usage_keys[index];
dcfda673
GH
266 hs->kbd.modifiers &= ~(1 << 8);
267
268 switch (hid_code) {
269 case 0x00:
270 return;
271
272 case 0xe0:
562f9375 273 assert(key == 0x1d);
dcfda673 274 if (hs->kbd.modifiers & (1 << 9)) {
562f9375
PB
275 /* 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);
dcfda673
GH
281 return;
282 }
562f9375 283 /* fall through to process Ctrl_L */
dcfda673 284 case 0xe1 ... 0xe7:
562f9375
PB
285 /* 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 */
dcfda673
GH
288 if (keycode & (1 << 7)) {
289 hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
290 return;
291 }
562f9375
PB
292 /* 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 */
dcfda673
GH
300 hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
301 return;
562f9375
PB
302
303 case 0xea ... 0xef:
304 abort();
305
306 default:
307 break;
dcfda673
GH
308 }
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
21635e12
GH
348void hid_pointer_activate(HIDState *hs)
349{
350 if (!hs->ptr.mouse_grabbed) {
8b84286f 351 qemu_input_handler_activate(hs->s);
21635e12
GH
352 hs->ptr.mouse_grabbed = 1;
353 }
354}
355
dcfda673
GH
356int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
357{
8b84286f 358 int dx, dy, dz, l;
dcfda673
GH
359 int index;
360 HIDPointerEvent *e;
361
027c03f7
HG
362 hs->idle_pending = false;
363
21635e12 364 hid_pointer_activate(hs);
dcfda673
GH
365
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
dcfda673
GH
383 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) {
8b84286f 397 buf[l++] = e->buttons_state;
dcfda673
GH
398 }
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) {
8b84286f 412 buf[l++] = e->buttons_state;
dcfda673
GH
413 }
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{
027c03f7
HG
440 hs->idle_pending = false;
441
dcfda673
GH
442 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:
dcfda673
GH
487 memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
488 memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
489 hs->kbd.keys = 0;
51dbea77 490 hs->kbd.modifiers = 0;
dcfda673
GH
491 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;
b069d348
GH
499 hs->protocol = 1;
500 hs->idle = 0;
027c03f7
HG
501 hs->idle_pending = false;
502 hid_del_idle_timer(hs);
dcfda673
GH
503}
504
505void hid_free(HIDState *hs)
506{
8b84286f 507 qemu_input_handler_unregister(hs->s);
027c03f7 508 hid_del_idle_timer(hs);
dcfda673
GH
509}
510
1ff5eedd
GH
511static QemuInputHandler hid_keyboard_handler = {
512 .name = "QEMU HID Keyboard",
513 .mask = INPUT_EVENT_MASK_KEY,
514 .event = hid_keyboard_event,
515};
516
8b84286f
GH
517static 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
dcfda673
GH
531void hid_init(HIDState *hs, int kind, HIDEventFunc event)
532{
533 hs->kind = kind;
534 hs->event = event;
535
bb0db527 536 if (hs->kind == HID_KEYBOARD) {
1ff5eedd
GH
537 hs->s = qemu_input_handler_register((DeviceState *)hs,
538 &hid_keyboard_handler);
539 qemu_input_handler_activate(hs->s);
bb0db527 540 } else if (hs->kind == HID_MOUSE) {
8b84286f
GH
541 hs->s = qemu_input_handler_register((DeviceState *)hs,
542 &hid_mouse_handler);
dcfda673 543 } else if (hs->kind == HID_TABLET) {
8b84286f
GH
544 hs->s = qemu_input_handler_register((DeviceState *)hs,
545 &hid_tablet_handler);
dcfda673
GH
546 }
547}
ccd4ed06
MW
548
549static int hid_post_load(void *opaque, int version_id)
550{
551 HIDState *s = opaque;
552
027c03f7 553 hid_set_next_idle(s);
ba4d2606
GH
554
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 }
ccd4ed06
MW
575 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};