qxl: avoid unaligned pointer reads/writes
[qemu/ar7.git] / hw / usb / dev-hid.c
blobf9ea3033a1b4b2dd67ff73cef1ac6012887570f0
1 /*
2 * QEMU USB HID devices
4 * Copyright (c) 2005 Fabrice Bellard
5 * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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.
25 #include "qemu/osdep.h"
26 #include "hw/hw.h"
27 #include "ui/console.h"
28 #include "hw/usb.h"
29 #include "desc.h"
30 #include "qapi/error.h"
31 #include "qemu/timer.h"
32 #include "hw/input/hid.h"
34 /* HID interface requests */
35 #define GET_REPORT 0xa101
36 #define GET_IDLE 0xa102
37 #define GET_PROTOCOL 0xa103
38 #define SET_REPORT 0x2109
39 #define SET_IDLE 0x210a
40 #define SET_PROTOCOL 0x210b
42 /* HID descriptor types */
43 #define USB_DT_HID 0x21
44 #define USB_DT_REPORT 0x22
45 #define USB_DT_PHY 0x23
47 typedef struct USBHIDState {
48 USBDevice dev;
49 USBEndpoint *intr;
50 HIDState hid;
51 uint32_t usb_version;
52 char *display;
53 uint32_t head;
54 } USBHIDState;
56 #define TYPE_USB_HID "usb-hid"
57 #define USB_HID(obj) OBJECT_CHECK(USBHIDState, (obj), TYPE_USB_HID)
59 enum {
60 STR_MANUFACTURER = 1,
61 STR_PRODUCT_MOUSE,
62 STR_PRODUCT_TABLET,
63 STR_PRODUCT_KEYBOARD,
64 STR_SERIAL_COMPAT,
65 STR_CONFIG_MOUSE,
66 STR_CONFIG_TABLET,
67 STR_CONFIG_KEYBOARD,
68 STR_SERIAL_MOUSE,
69 STR_SERIAL_TABLET,
70 STR_SERIAL_KEYBOARD,
73 static const USBDescStrings desc_strings = {
74 [STR_MANUFACTURER] = "QEMU",
75 [STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
76 [STR_PRODUCT_TABLET] = "QEMU USB Tablet",
77 [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
78 [STR_SERIAL_COMPAT] = "42",
79 [STR_CONFIG_MOUSE] = "HID Mouse",
80 [STR_CONFIG_TABLET] = "HID Tablet",
81 [STR_CONFIG_KEYBOARD] = "HID Keyboard",
82 [STR_SERIAL_MOUSE] = "89126",
83 [STR_SERIAL_TABLET] = "28754",
84 [STR_SERIAL_KEYBOARD] = "68284",
87 static const USBDescIface desc_iface_mouse = {
88 .bInterfaceNumber = 0,
89 .bNumEndpoints = 1,
90 .bInterfaceClass = USB_CLASS_HID,
91 .bInterfaceSubClass = 0x01, /* boot */
92 .bInterfaceProtocol = 0x02,
93 .ndesc = 1,
94 .descs = (USBDescOther[]) {
96 /* HID descriptor */
97 .data = (uint8_t[]) {
98 0x09, /* u8 bLength */
99 USB_DT_HID, /* u8 bDescriptorType */
100 0x01, 0x00, /* u16 HID_class */
101 0x00, /* u8 country_code */
102 0x01, /* u8 num_descriptors */
103 USB_DT_REPORT, /* u8 type: Report */
104 52, 0, /* u16 len */
108 .eps = (USBDescEndpoint[]) {
110 .bEndpointAddress = USB_DIR_IN | 0x01,
111 .bmAttributes = USB_ENDPOINT_XFER_INT,
112 .wMaxPacketSize = 4,
113 .bInterval = 0x0a,
118 static const USBDescIface desc_iface_mouse2 = {
119 .bInterfaceNumber = 0,
120 .bNumEndpoints = 1,
121 .bInterfaceClass = USB_CLASS_HID,
122 .bInterfaceSubClass = 0x01, /* boot */
123 .bInterfaceProtocol = 0x02,
124 .ndesc = 1,
125 .descs = (USBDescOther[]) {
127 /* HID descriptor */
128 .data = (uint8_t[]) {
129 0x09, /* u8 bLength */
130 USB_DT_HID, /* u8 bDescriptorType */
131 0x01, 0x00, /* u16 HID_class */
132 0x00, /* u8 country_code */
133 0x01, /* u8 num_descriptors */
134 USB_DT_REPORT, /* u8 type: Report */
135 52, 0, /* u16 len */
139 .eps = (USBDescEndpoint[]) {
141 .bEndpointAddress = USB_DIR_IN | 0x01,
142 .bmAttributes = USB_ENDPOINT_XFER_INT,
143 .wMaxPacketSize = 4,
144 .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
149 static const USBDescIface desc_iface_tablet = {
150 .bInterfaceNumber = 0,
151 .bNumEndpoints = 1,
152 .bInterfaceClass = USB_CLASS_HID,
153 .bInterfaceProtocol = 0x00,
154 .ndesc = 1,
155 .descs = (USBDescOther[]) {
157 /* HID descriptor */
158 .data = (uint8_t[]) {
159 0x09, /* u8 bLength */
160 USB_DT_HID, /* u8 bDescriptorType */
161 0x01, 0x00, /* u16 HID_class */
162 0x00, /* u8 country_code */
163 0x01, /* u8 num_descriptors */
164 USB_DT_REPORT, /* u8 type: Report */
165 74, 0, /* u16 len */
169 .eps = (USBDescEndpoint[]) {
171 .bEndpointAddress = USB_DIR_IN | 0x01,
172 .bmAttributes = USB_ENDPOINT_XFER_INT,
173 .wMaxPacketSize = 8,
174 .bInterval = 0x0a,
179 static const USBDescIface desc_iface_tablet2 = {
180 .bInterfaceNumber = 0,
181 .bNumEndpoints = 1,
182 .bInterfaceClass = USB_CLASS_HID,
183 .bInterfaceProtocol = 0x00,
184 .ndesc = 1,
185 .descs = (USBDescOther[]) {
187 /* HID descriptor */
188 .data = (uint8_t[]) {
189 0x09, /* u8 bLength */
190 USB_DT_HID, /* u8 bDescriptorType */
191 0x01, 0x00, /* u16 HID_class */
192 0x00, /* u8 country_code */
193 0x01, /* u8 num_descriptors */
194 USB_DT_REPORT, /* u8 type: Report */
195 74, 0, /* u16 len */
199 .eps = (USBDescEndpoint[]) {
201 .bEndpointAddress = USB_DIR_IN | 0x01,
202 .bmAttributes = USB_ENDPOINT_XFER_INT,
203 .wMaxPacketSize = 8,
204 .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
209 static const USBDescIface desc_iface_keyboard = {
210 .bInterfaceNumber = 0,
211 .bNumEndpoints = 1,
212 .bInterfaceClass = USB_CLASS_HID,
213 .bInterfaceSubClass = 0x01, /* boot */
214 .bInterfaceProtocol = 0x01, /* keyboard */
215 .ndesc = 1,
216 .descs = (USBDescOther[]) {
218 /* HID descriptor */
219 .data = (uint8_t[]) {
220 0x09, /* u8 bLength */
221 USB_DT_HID, /* u8 bDescriptorType */
222 0x11, 0x01, /* u16 HID_class */
223 0x00, /* u8 country_code */
224 0x01, /* u8 num_descriptors */
225 USB_DT_REPORT, /* u8 type: Report */
226 0x3f, 0, /* u16 len */
230 .eps = (USBDescEndpoint[]) {
232 .bEndpointAddress = USB_DIR_IN | 0x01,
233 .bmAttributes = USB_ENDPOINT_XFER_INT,
234 .wMaxPacketSize = 8,
235 .bInterval = 0x0a,
240 static const USBDescIface desc_iface_keyboard2 = {
241 .bInterfaceNumber = 0,
242 .bNumEndpoints = 1,
243 .bInterfaceClass = USB_CLASS_HID,
244 .bInterfaceSubClass = 0x01, /* boot */
245 .bInterfaceProtocol = 0x01, /* keyboard */
246 .ndesc = 1,
247 .descs = (USBDescOther[]) {
249 /* HID descriptor */
250 .data = (uint8_t[]) {
251 0x09, /* u8 bLength */
252 USB_DT_HID, /* u8 bDescriptorType */
253 0x11, 0x01, /* u16 HID_class */
254 0x00, /* u8 country_code */
255 0x01, /* u8 num_descriptors */
256 USB_DT_REPORT, /* u8 type: Report */
257 0x3f, 0, /* u16 len */
261 .eps = (USBDescEndpoint[]) {
263 .bEndpointAddress = USB_DIR_IN | 0x01,
264 .bmAttributes = USB_ENDPOINT_XFER_INT,
265 .wMaxPacketSize = 8,
266 .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
271 static const USBDescDevice desc_device_mouse = {
272 .bcdUSB = 0x0100,
273 .bMaxPacketSize0 = 8,
274 .bNumConfigurations = 1,
275 .confs = (USBDescConfig[]) {
277 .bNumInterfaces = 1,
278 .bConfigurationValue = 1,
279 .iConfiguration = STR_CONFIG_MOUSE,
280 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
281 .bMaxPower = 50,
282 .nif = 1,
283 .ifs = &desc_iface_mouse,
288 static const USBDescDevice desc_device_mouse2 = {
289 .bcdUSB = 0x0200,
290 .bMaxPacketSize0 = 64,
291 .bNumConfigurations = 1,
292 .confs = (USBDescConfig[]) {
294 .bNumInterfaces = 1,
295 .bConfigurationValue = 1,
296 .iConfiguration = STR_CONFIG_MOUSE,
297 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
298 .bMaxPower = 50,
299 .nif = 1,
300 .ifs = &desc_iface_mouse2,
305 static const USBDescDevice desc_device_tablet = {
306 .bcdUSB = 0x0100,
307 .bMaxPacketSize0 = 8,
308 .bNumConfigurations = 1,
309 .confs = (USBDescConfig[]) {
311 .bNumInterfaces = 1,
312 .bConfigurationValue = 1,
313 .iConfiguration = STR_CONFIG_TABLET,
314 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
315 .bMaxPower = 50,
316 .nif = 1,
317 .ifs = &desc_iface_tablet,
322 static const USBDescDevice desc_device_tablet2 = {
323 .bcdUSB = 0x0200,
324 .bMaxPacketSize0 = 64,
325 .bNumConfigurations = 1,
326 .confs = (USBDescConfig[]) {
328 .bNumInterfaces = 1,
329 .bConfigurationValue = 1,
330 .iConfiguration = STR_CONFIG_TABLET,
331 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
332 .bMaxPower = 50,
333 .nif = 1,
334 .ifs = &desc_iface_tablet2,
339 static const USBDescDevice desc_device_keyboard = {
340 .bcdUSB = 0x0100,
341 .bMaxPacketSize0 = 8,
342 .bNumConfigurations = 1,
343 .confs = (USBDescConfig[]) {
345 .bNumInterfaces = 1,
346 .bConfigurationValue = 1,
347 .iConfiguration = STR_CONFIG_KEYBOARD,
348 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
349 .bMaxPower = 50,
350 .nif = 1,
351 .ifs = &desc_iface_keyboard,
356 static const USBDescDevice desc_device_keyboard2 = {
357 .bcdUSB = 0x0200,
358 .bMaxPacketSize0 = 64,
359 .bNumConfigurations = 1,
360 .confs = (USBDescConfig[]) {
362 .bNumInterfaces = 1,
363 .bConfigurationValue = 1,
364 .iConfiguration = STR_CONFIG_KEYBOARD,
365 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
366 .bMaxPower = 50,
367 .nif = 1,
368 .ifs = &desc_iface_keyboard2,
373 static const USBDescMSOS desc_msos_suspend = {
374 .SelectiveSuspendEnabled = true,
377 static const USBDesc desc_mouse = {
378 .id = {
379 .idVendor = 0x0627,
380 .idProduct = 0x0001,
381 .bcdDevice = 0,
382 .iManufacturer = STR_MANUFACTURER,
383 .iProduct = STR_PRODUCT_MOUSE,
384 .iSerialNumber = STR_SERIAL_MOUSE,
386 .full = &desc_device_mouse,
387 .str = desc_strings,
388 .msos = &desc_msos_suspend,
391 static const USBDesc desc_mouse2 = {
392 .id = {
393 .idVendor = 0x0627,
394 .idProduct = 0x0001,
395 .bcdDevice = 0,
396 .iManufacturer = STR_MANUFACTURER,
397 .iProduct = STR_PRODUCT_MOUSE,
398 .iSerialNumber = STR_SERIAL_MOUSE,
400 .full = &desc_device_mouse,
401 .high = &desc_device_mouse2,
402 .str = desc_strings,
403 .msos = &desc_msos_suspend,
406 static const USBDesc desc_tablet = {
407 .id = {
408 .idVendor = 0x0627,
409 .idProduct = 0x0001,
410 .bcdDevice = 0,
411 .iManufacturer = STR_MANUFACTURER,
412 .iProduct = STR_PRODUCT_TABLET,
413 .iSerialNumber = STR_SERIAL_TABLET,
415 .full = &desc_device_tablet,
416 .str = desc_strings,
417 .msos = &desc_msos_suspend,
420 static const USBDesc desc_tablet2 = {
421 .id = {
422 .idVendor = 0x0627,
423 .idProduct = 0x0001,
424 .bcdDevice = 0,
425 .iManufacturer = STR_MANUFACTURER,
426 .iProduct = STR_PRODUCT_TABLET,
427 .iSerialNumber = STR_SERIAL_TABLET,
429 .full = &desc_device_tablet,
430 .high = &desc_device_tablet2,
431 .str = desc_strings,
432 .msos = &desc_msos_suspend,
435 static const USBDesc desc_keyboard = {
436 .id = {
437 .idVendor = 0x0627,
438 .idProduct = 0x0001,
439 .bcdDevice = 0,
440 .iManufacturer = STR_MANUFACTURER,
441 .iProduct = STR_PRODUCT_KEYBOARD,
442 .iSerialNumber = STR_SERIAL_KEYBOARD,
444 .full = &desc_device_keyboard,
445 .str = desc_strings,
446 .msos = &desc_msos_suspend,
449 static const USBDesc desc_keyboard2 = {
450 .id = {
451 .idVendor = 0x0627,
452 .idProduct = 0x0001,
453 .bcdDevice = 0,
454 .iManufacturer = STR_MANUFACTURER,
455 .iProduct = STR_PRODUCT_KEYBOARD,
456 .iSerialNumber = STR_SERIAL_KEYBOARD,
458 .full = &desc_device_keyboard,
459 .high = &desc_device_keyboard2,
460 .str = desc_strings,
461 .msos = &desc_msos_suspend,
464 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
465 0x05, 0x01, /* Usage Page (Generic Desktop) */
466 0x09, 0x02, /* Usage (Mouse) */
467 0xa1, 0x01, /* Collection (Application) */
468 0x09, 0x01, /* Usage (Pointer) */
469 0xa1, 0x00, /* Collection (Physical) */
470 0x05, 0x09, /* Usage Page (Button) */
471 0x19, 0x01, /* Usage Minimum (1) */
472 0x29, 0x03, /* Usage Maximum (3) */
473 0x15, 0x00, /* Logical Minimum (0) */
474 0x25, 0x01, /* Logical Maximum (1) */
475 0x95, 0x03, /* Report Count (3) */
476 0x75, 0x01, /* Report Size (1) */
477 0x81, 0x02, /* Input (Data, Variable, Absolute) */
478 0x95, 0x01, /* Report Count (1) */
479 0x75, 0x05, /* Report Size (5) */
480 0x81, 0x01, /* Input (Constant) */
481 0x05, 0x01, /* Usage Page (Generic Desktop) */
482 0x09, 0x30, /* Usage (X) */
483 0x09, 0x31, /* Usage (Y) */
484 0x09, 0x38, /* Usage (Wheel) */
485 0x15, 0x81, /* Logical Minimum (-0x7f) */
486 0x25, 0x7f, /* Logical Maximum (0x7f) */
487 0x75, 0x08, /* Report Size (8) */
488 0x95, 0x03, /* Report Count (3) */
489 0x81, 0x06, /* Input (Data, Variable, Relative) */
490 0xc0, /* End Collection */
491 0xc0, /* End Collection */
494 static const uint8_t qemu_tablet_hid_report_descriptor[] = {
495 0x05, 0x01, /* Usage Page (Generic Desktop) */
496 0x09, 0x02, /* Usage (Mouse) */
497 0xa1, 0x01, /* Collection (Application) */
498 0x09, 0x01, /* Usage (Pointer) */
499 0xa1, 0x00, /* Collection (Physical) */
500 0x05, 0x09, /* Usage Page (Button) */
501 0x19, 0x01, /* Usage Minimum (1) */
502 0x29, 0x03, /* Usage Maximum (3) */
503 0x15, 0x00, /* Logical Minimum (0) */
504 0x25, 0x01, /* Logical Maximum (1) */
505 0x95, 0x03, /* Report Count (3) */
506 0x75, 0x01, /* Report Size (1) */
507 0x81, 0x02, /* Input (Data, Variable, Absolute) */
508 0x95, 0x01, /* Report Count (1) */
509 0x75, 0x05, /* Report Size (5) */
510 0x81, 0x01, /* Input (Constant) */
511 0x05, 0x01, /* Usage Page (Generic Desktop) */
512 0x09, 0x30, /* Usage (X) */
513 0x09, 0x31, /* Usage (Y) */
514 0x15, 0x00, /* Logical Minimum (0) */
515 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */
516 0x35, 0x00, /* Physical Minimum (0) */
517 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */
518 0x75, 0x10, /* Report Size (16) */
519 0x95, 0x02, /* Report Count (2) */
520 0x81, 0x02, /* Input (Data, Variable, Absolute) */
521 0x05, 0x01, /* Usage Page (Generic Desktop) */
522 0x09, 0x38, /* Usage (Wheel) */
523 0x15, 0x81, /* Logical Minimum (-0x7f) */
524 0x25, 0x7f, /* Logical Maximum (0x7f) */
525 0x35, 0x00, /* Physical Minimum (same as logical) */
526 0x45, 0x00, /* Physical Maximum (same as logical) */
527 0x75, 0x08, /* Report Size (8) */
528 0x95, 0x01, /* Report Count (1) */
529 0x81, 0x06, /* Input (Data, Variable, Relative) */
530 0xc0, /* End Collection */
531 0xc0, /* End Collection */
534 static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
535 0x05, 0x01, /* Usage Page (Generic Desktop) */
536 0x09, 0x06, /* Usage (Keyboard) */
537 0xa1, 0x01, /* Collection (Application) */
538 0x75, 0x01, /* Report Size (1) */
539 0x95, 0x08, /* Report Count (8) */
540 0x05, 0x07, /* Usage Page (Key Codes) */
541 0x19, 0xe0, /* Usage Minimum (224) */
542 0x29, 0xe7, /* Usage Maximum (231) */
543 0x15, 0x00, /* Logical Minimum (0) */
544 0x25, 0x01, /* Logical Maximum (1) */
545 0x81, 0x02, /* Input (Data, Variable, Absolute) */
546 0x95, 0x01, /* Report Count (1) */
547 0x75, 0x08, /* Report Size (8) */
548 0x81, 0x01, /* Input (Constant) */
549 0x95, 0x05, /* Report Count (5) */
550 0x75, 0x01, /* Report Size (1) */
551 0x05, 0x08, /* Usage Page (LEDs) */
552 0x19, 0x01, /* Usage Minimum (1) */
553 0x29, 0x05, /* Usage Maximum (5) */
554 0x91, 0x02, /* Output (Data, Variable, Absolute) */
555 0x95, 0x01, /* Report Count (1) */
556 0x75, 0x03, /* Report Size (3) */
557 0x91, 0x01, /* Output (Constant) */
558 0x95, 0x06, /* Report Count (6) */
559 0x75, 0x08, /* Report Size (8) */
560 0x15, 0x00, /* Logical Minimum (0) */
561 0x25, 0xff, /* Logical Maximum (255) */
562 0x05, 0x07, /* Usage Page (Key Codes) */
563 0x19, 0x00, /* Usage Minimum (0) */
564 0x29, 0xff, /* Usage Maximum (255) */
565 0x81, 0x00, /* Input (Data, Array) */
566 0xc0, /* End Collection */
569 static void usb_hid_changed(HIDState *hs)
571 USBHIDState *us = container_of(hs, USBHIDState, hid);
573 usb_wakeup(us->intr, 0);
576 static void usb_hid_handle_reset(USBDevice *dev)
578 USBHIDState *us = USB_HID(dev);
580 hid_reset(&us->hid);
583 static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
584 int request, int value, int index, int length, uint8_t *data)
586 USBHIDState *us = USB_HID(dev);
587 HIDState *hs = &us->hid;
588 int ret;
590 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
591 if (ret >= 0) {
592 return;
595 switch (request) {
596 /* hid specific requests */
597 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
598 switch (value >> 8) {
599 case 0x22:
600 if (hs->kind == HID_MOUSE) {
601 memcpy(data, qemu_mouse_hid_report_descriptor,
602 sizeof(qemu_mouse_hid_report_descriptor));
603 p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
604 } else if (hs->kind == HID_TABLET) {
605 memcpy(data, qemu_tablet_hid_report_descriptor,
606 sizeof(qemu_tablet_hid_report_descriptor));
607 p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
608 } else if (hs->kind == HID_KEYBOARD) {
609 memcpy(data, qemu_keyboard_hid_report_descriptor,
610 sizeof(qemu_keyboard_hid_report_descriptor));
611 p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
613 break;
614 default:
615 goto fail;
617 break;
618 case GET_REPORT:
619 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
620 p->actual_length = hid_pointer_poll(hs, data, length);
621 } else if (hs->kind == HID_KEYBOARD) {
622 p->actual_length = hid_keyboard_poll(hs, data, length);
624 break;
625 case SET_REPORT:
626 if (hs->kind == HID_KEYBOARD) {
627 p->actual_length = hid_keyboard_write(hs, data, length);
628 } else {
629 goto fail;
631 break;
632 case GET_PROTOCOL:
633 if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
634 goto fail;
636 data[0] = hs->protocol;
637 p->actual_length = 1;
638 break;
639 case SET_PROTOCOL:
640 if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
641 goto fail;
643 hs->protocol = value;
644 break;
645 case GET_IDLE:
646 data[0] = hs->idle;
647 p->actual_length = 1;
648 break;
649 case SET_IDLE:
650 hs->idle = (uint8_t) (value >> 8);
651 hid_set_next_idle(hs);
652 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
653 hid_pointer_activate(hs);
655 break;
656 default:
657 fail:
658 p->status = USB_RET_STALL;
659 break;
663 static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
665 USBHIDState *us = USB_HID(dev);
666 HIDState *hs = &us->hid;
667 uint8_t buf[p->iov.size];
668 int len = 0;
670 switch (p->pid) {
671 case USB_TOKEN_IN:
672 if (p->ep->nr == 1) {
673 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
674 hid_pointer_activate(hs);
676 if (!hid_has_events(hs)) {
677 p->status = USB_RET_NAK;
678 return;
680 hid_set_next_idle(hs);
681 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
682 len = hid_pointer_poll(hs, buf, p->iov.size);
683 } else if (hs->kind == HID_KEYBOARD) {
684 len = hid_keyboard_poll(hs, buf, p->iov.size);
686 usb_packet_copy(p, buf, len);
687 } else {
688 goto fail;
690 break;
691 case USB_TOKEN_OUT:
692 default:
693 fail:
694 p->status = USB_RET_STALL;
695 break;
699 static void usb_hid_unrealize(USBDevice *dev, Error **errp)
701 USBHIDState *us = USB_HID(dev);
703 hid_free(&us->hid);
706 static void usb_hid_initfn(USBDevice *dev, int kind,
707 const USBDesc *usb1, const USBDesc *usb2,
708 Error **errp)
710 USBHIDState *us = USB_HID(dev);
711 switch (us->usb_version) {
712 case 1:
713 dev->usb_desc = usb1;
714 break;
715 case 2:
716 dev->usb_desc = usb2;
717 break;
718 default:
719 dev->usb_desc = NULL;
721 if (!dev->usb_desc) {
722 error_setg(errp, "Invalid usb version %d for usb hid device",
723 us->usb_version);
724 return;
727 usb_desc_create_serial(dev);
728 usb_desc_init(dev);
729 us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
730 hid_init(&us->hid, kind, usb_hid_changed);
731 if (us->display && us->hid.s) {
732 qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL);
736 static void usb_tablet_realize(USBDevice *dev, Error **errp)
739 usb_hid_initfn(dev, HID_TABLET, &desc_tablet, &desc_tablet2, errp);
742 static void usb_mouse_realize(USBDevice *dev, Error **errp)
744 usb_hid_initfn(dev, HID_MOUSE, &desc_mouse, &desc_mouse2, errp);
747 static void usb_keyboard_realize(USBDevice *dev, Error **errp)
749 usb_hid_initfn(dev, HID_KEYBOARD, &desc_keyboard, &desc_keyboard2, errp);
752 static int usb_ptr_post_load(void *opaque, int version_id)
754 USBHIDState *s = opaque;
756 if (s->dev.remote_wakeup) {
757 hid_pointer_activate(&s->hid);
759 return 0;
762 static const VMStateDescription vmstate_usb_ptr = {
763 .name = "usb-ptr",
764 .version_id = 1,
765 .minimum_version_id = 1,
766 .post_load = usb_ptr_post_load,
767 .fields = (VMStateField[]) {
768 VMSTATE_USB_DEVICE(dev, USBHIDState),
769 VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
770 VMSTATE_END_OF_LIST()
774 static const VMStateDescription vmstate_usb_kbd = {
775 .name = "usb-kbd",
776 .version_id = 1,
777 .minimum_version_id = 1,
778 .fields = (VMStateField[]) {
779 VMSTATE_USB_DEVICE(dev, USBHIDState),
780 VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
781 VMSTATE_END_OF_LIST()
785 static void usb_hid_class_initfn(ObjectClass *klass, void *data)
787 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
789 uc->handle_reset = usb_hid_handle_reset;
790 uc->handle_control = usb_hid_handle_control;
791 uc->handle_data = usb_hid_handle_data;
792 uc->unrealize = usb_hid_unrealize;
793 uc->handle_attach = usb_desc_attach;
796 static const TypeInfo usb_hid_type_info = {
797 .name = TYPE_USB_HID,
798 .parent = TYPE_USB_DEVICE,
799 .instance_size = sizeof(USBHIDState),
800 .abstract = true,
801 .class_init = usb_hid_class_initfn,
804 static Property usb_tablet_properties[] = {
805 DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
806 DEFINE_PROP_STRING("display", USBHIDState, display),
807 DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
808 DEFINE_PROP_END_OF_LIST(),
811 static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
813 DeviceClass *dc = DEVICE_CLASS(klass);
814 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
816 uc->realize = usb_tablet_realize;
817 uc->product_desc = "QEMU USB Tablet";
818 dc->vmsd = &vmstate_usb_ptr;
819 dc->props = usb_tablet_properties;
820 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
823 static const TypeInfo usb_tablet_info = {
824 .name = "usb-tablet",
825 .parent = TYPE_USB_HID,
826 .class_init = usb_tablet_class_initfn,
829 static Property usb_mouse_properties[] = {
830 DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
831 DEFINE_PROP_END_OF_LIST(),
834 static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
836 DeviceClass *dc = DEVICE_CLASS(klass);
837 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
839 uc->realize = usb_mouse_realize;
840 uc->product_desc = "QEMU USB Mouse";
841 dc->vmsd = &vmstate_usb_ptr;
842 dc->props = usb_mouse_properties;
843 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
846 static const TypeInfo usb_mouse_info = {
847 .name = "usb-mouse",
848 .parent = TYPE_USB_HID,
849 .class_init = usb_mouse_class_initfn,
852 static Property usb_keyboard_properties[] = {
853 DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
854 DEFINE_PROP_STRING("display", USBHIDState, display),
855 DEFINE_PROP_END_OF_LIST(),
858 static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
860 DeviceClass *dc = DEVICE_CLASS(klass);
861 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
863 uc->realize = usb_keyboard_realize;
864 uc->product_desc = "QEMU USB Keyboard";
865 dc->vmsd = &vmstate_usb_kbd;
866 dc->props = usb_keyboard_properties;
867 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
870 static const TypeInfo usb_keyboard_info = {
871 .name = "usb-kbd",
872 .parent = TYPE_USB_HID,
873 .class_init = usb_keyboard_class_initfn,
876 static void usb_hid_register_types(void)
878 type_register_static(&usb_hid_type_info);
879 type_register_static(&usb_tablet_info);
880 usb_legacy_register("usb-tablet", "tablet", NULL);
881 type_register_static(&usb_mouse_info);
882 usb_legacy_register("usb-mouse", "mouse", NULL);
883 type_register_static(&usb_keyboard_info);
884 usb_legacy_register("usb-kbd", "keyboard", NULL);
887 type_init(usb_hid_register_types)