xref: /openbmc/qemu/hw/usb/dev-hid.c (revision a719a27c)
1 /*
2  * QEMU USB 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  */
25 #include "hw/hw.h"
26 #include "ui/console.h"
27 #include "hw/usb.h"
28 #include "hw/usb/desc.h"
29 #include "qemu/timer.h"
30 #include "hw/input/hid.h"
31 
32 /* HID interface requests */
33 #define GET_REPORT   0xa101
34 #define GET_IDLE     0xa102
35 #define GET_PROTOCOL 0xa103
36 #define SET_REPORT   0x2109
37 #define SET_IDLE     0x210a
38 #define SET_PROTOCOL 0x210b
39 
40 /* HID descriptor types */
41 #define USB_DT_HID    0x21
42 #define USB_DT_REPORT 0x22
43 #define USB_DT_PHY    0x23
44 
45 typedef struct USBHIDState {
46     USBDevice dev;
47     USBEndpoint *intr;
48     HIDState hid;
49     uint32_t usb_version;
50 } USBHIDState;
51 
52 enum {
53     STR_MANUFACTURER = 1,
54     STR_PRODUCT_MOUSE,
55     STR_PRODUCT_TABLET,
56     STR_PRODUCT_KEYBOARD,
57     STR_SERIALNUMBER,
58     STR_CONFIG_MOUSE,
59     STR_CONFIG_TABLET,
60     STR_CONFIG_KEYBOARD,
61 };
62 
63 static const USBDescStrings desc_strings = {
64     [STR_MANUFACTURER]     = "QEMU",
65     [STR_PRODUCT_MOUSE]    = "QEMU USB Mouse",
66     [STR_PRODUCT_TABLET]   = "QEMU USB Tablet",
67     [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
68     [STR_SERIALNUMBER]     = "42", /* == remote wakeup works */
69     [STR_CONFIG_MOUSE]     = "HID Mouse",
70     [STR_CONFIG_TABLET]    = "HID Tablet",
71     [STR_CONFIG_KEYBOARD]  = "HID Keyboard",
72 };
73 
74 static const USBDescIface desc_iface_mouse = {
75     .bInterfaceNumber              = 0,
76     .bNumEndpoints                 = 1,
77     .bInterfaceClass               = USB_CLASS_HID,
78     .bInterfaceSubClass            = 0x01, /* boot */
79     .bInterfaceProtocol            = 0x02,
80     .ndesc                         = 1,
81     .descs = (USBDescOther[]) {
82         {
83             /* HID descriptor */
84             .data = (uint8_t[]) {
85                 0x09,          /*  u8  bLength */
86                 USB_DT_HID,    /*  u8  bDescriptorType */
87                 0x01, 0x00,    /*  u16 HID_class */
88                 0x00,          /*  u8  country_code */
89                 0x01,          /*  u8  num_descriptors */
90                 USB_DT_REPORT, /*  u8  type: Report */
91                 52, 0,         /*  u16 len */
92             },
93         },
94     },
95     .eps = (USBDescEndpoint[]) {
96         {
97             .bEndpointAddress      = USB_DIR_IN | 0x01,
98             .bmAttributes          = USB_ENDPOINT_XFER_INT,
99             .wMaxPacketSize        = 4,
100             .bInterval             = 0x0a,
101         },
102     },
103 };
104 
105 static const USBDescIface desc_iface_tablet = {
106     .bInterfaceNumber              = 0,
107     .bNumEndpoints                 = 1,
108     .bInterfaceClass               = USB_CLASS_HID,
109     .bInterfaceProtocol            = 0x02,
110     .ndesc                         = 1,
111     .descs = (USBDescOther[]) {
112         {
113             /* HID descriptor */
114             .data = (uint8_t[]) {
115                 0x09,          /*  u8  bLength */
116                 USB_DT_HID,    /*  u8  bDescriptorType */
117                 0x01, 0x00,    /*  u16 HID_class */
118                 0x00,          /*  u8  country_code */
119                 0x01,          /*  u8  num_descriptors */
120                 USB_DT_REPORT, /*  u8  type: Report */
121                 74, 0,         /*  u16 len */
122             },
123         },
124     },
125     .eps = (USBDescEndpoint[]) {
126         {
127             .bEndpointAddress      = USB_DIR_IN | 0x01,
128             .bmAttributes          = USB_ENDPOINT_XFER_INT,
129             .wMaxPacketSize        = 8,
130             .bInterval             = 0x0a,
131         },
132     },
133 };
134 
135 static const USBDescIface desc_iface_tablet2 = {
136     .bInterfaceNumber              = 0,
137     .bNumEndpoints                 = 1,
138     .bInterfaceClass               = USB_CLASS_HID,
139     .bInterfaceProtocol            = 0x02,
140     .ndesc                         = 1,
141     .descs = (USBDescOther[]) {
142         {
143             /* HID descriptor */
144             .data = (uint8_t[]) {
145                 0x09,          /*  u8  bLength */
146                 USB_DT_HID,    /*  u8  bDescriptorType */
147                 0x01, 0x00,    /*  u16 HID_class */
148                 0x00,          /*  u8  country_code */
149                 0x01,          /*  u8  num_descriptors */
150                 USB_DT_REPORT, /*  u8  type: Report */
151                 74, 0,         /*  u16 len */
152             },
153         },
154     },
155     .eps = (USBDescEndpoint[]) {
156         {
157             .bEndpointAddress      = USB_DIR_IN | 0x01,
158             .bmAttributes          = USB_ENDPOINT_XFER_INT,
159             .wMaxPacketSize        = 8,
160             .bInterval             = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
161         },
162     },
163 };
164 
165 static const USBDescIface desc_iface_keyboard = {
166     .bInterfaceNumber              = 0,
167     .bNumEndpoints                 = 1,
168     .bInterfaceClass               = USB_CLASS_HID,
169     .bInterfaceSubClass            = 0x01, /* boot */
170     .bInterfaceProtocol            = 0x01, /* keyboard */
171     .ndesc                         = 1,
172     .descs = (USBDescOther[]) {
173         {
174             /* HID descriptor */
175             .data = (uint8_t[]) {
176                 0x09,          /*  u8  bLength */
177                 USB_DT_HID,    /*  u8  bDescriptorType */
178                 0x11, 0x01,    /*  u16 HID_class */
179                 0x00,          /*  u8  country_code */
180                 0x01,          /*  u8  num_descriptors */
181                 USB_DT_REPORT, /*  u8  type: Report */
182                 0x3f, 0,       /*  u16 len */
183             },
184         },
185     },
186     .eps = (USBDescEndpoint[]) {
187         {
188             .bEndpointAddress      = USB_DIR_IN | 0x01,
189             .bmAttributes          = USB_ENDPOINT_XFER_INT,
190             .wMaxPacketSize        = 8,
191             .bInterval             = 0x0a,
192         },
193     },
194 };
195 
196 static const USBDescDevice desc_device_mouse = {
197     .bcdUSB                        = 0x0100,
198     .bMaxPacketSize0               = 8,
199     .bNumConfigurations            = 1,
200     .confs = (USBDescConfig[]) {
201         {
202             .bNumInterfaces        = 1,
203             .bConfigurationValue   = 1,
204             .iConfiguration        = STR_CONFIG_MOUSE,
205             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
206             .bMaxPower             = 50,
207             .nif = 1,
208             .ifs = &desc_iface_mouse,
209         },
210     },
211 };
212 
213 static const USBDescDevice desc_device_tablet = {
214     .bcdUSB                        = 0x0100,
215     .bMaxPacketSize0               = 8,
216     .bNumConfigurations            = 1,
217     .confs = (USBDescConfig[]) {
218         {
219             .bNumInterfaces        = 1,
220             .bConfigurationValue   = 1,
221             .iConfiguration        = STR_CONFIG_TABLET,
222             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
223             .bMaxPower             = 50,
224             .nif = 1,
225             .ifs = &desc_iface_tablet,
226         },
227     },
228 };
229 
230 static const USBDescDevice desc_device_tablet2 = {
231     .bcdUSB                        = 0x0200,
232     .bMaxPacketSize0               = 64,
233     .bNumConfigurations            = 1,
234     .confs = (USBDescConfig[]) {
235         {
236             .bNumInterfaces        = 1,
237             .bConfigurationValue   = 1,
238             .iConfiguration        = STR_CONFIG_TABLET,
239             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
240             .bMaxPower             = 50,
241             .nif = 1,
242             .ifs = &desc_iface_tablet2,
243         },
244     },
245 };
246 
247 static const USBDescDevice desc_device_keyboard = {
248     .bcdUSB                        = 0x0100,
249     .bMaxPacketSize0               = 8,
250     .bNumConfigurations            = 1,
251     .confs = (USBDescConfig[]) {
252         {
253             .bNumInterfaces        = 1,
254             .bConfigurationValue   = 1,
255             .iConfiguration        = STR_CONFIG_KEYBOARD,
256             .bmAttributes          = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
257             .bMaxPower             = 50,
258             .nif = 1,
259             .ifs = &desc_iface_keyboard,
260         },
261     },
262 };
263 
264 static const USBDescMSOS desc_msos_suspend = {
265     .SelectiveSuspendEnabled = true,
266 };
267 
268 static const USBDesc desc_mouse = {
269     .id = {
270         .idVendor          = 0x0627,
271         .idProduct         = 0x0001,
272         .bcdDevice         = 0,
273         .iManufacturer     = STR_MANUFACTURER,
274         .iProduct          = STR_PRODUCT_MOUSE,
275         .iSerialNumber     = STR_SERIALNUMBER,
276     },
277     .full = &desc_device_mouse,
278     .str  = desc_strings,
279     .msos = &desc_msos_suspend,
280 };
281 
282 static const USBDesc desc_tablet = {
283     .id = {
284         .idVendor          = 0x0627,
285         .idProduct         = 0x0001,
286         .bcdDevice         = 0,
287         .iManufacturer     = STR_MANUFACTURER,
288         .iProduct          = STR_PRODUCT_TABLET,
289         .iSerialNumber     = STR_SERIALNUMBER,
290     },
291     .full = &desc_device_tablet,
292     .str  = desc_strings,
293     .msos = &desc_msos_suspend,
294 };
295 
296 static const USBDesc desc_tablet2 = {
297     .id = {
298         .idVendor          = 0x0627,
299         .idProduct         = 0x0001,
300         .bcdDevice         = 0,
301         .iManufacturer     = STR_MANUFACTURER,
302         .iProduct          = STR_PRODUCT_TABLET,
303         .iSerialNumber     = STR_SERIALNUMBER,
304     },
305     .full = &desc_device_tablet,
306     .high = &desc_device_tablet2,
307     .str  = desc_strings,
308     .msos = &desc_msos_suspend,
309 };
310 
311 static const USBDesc desc_keyboard = {
312     .id = {
313         .idVendor          = 0x0627,
314         .idProduct         = 0x0001,
315         .bcdDevice         = 0,
316         .iManufacturer     = STR_MANUFACTURER,
317         .iProduct          = STR_PRODUCT_KEYBOARD,
318         .iSerialNumber     = STR_SERIALNUMBER,
319     },
320     .full = &desc_device_keyboard,
321     .str  = desc_strings,
322     .msos = &desc_msos_suspend,
323 };
324 
325 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
326     0x05, 0x01,		/* Usage Page (Generic Desktop) */
327     0x09, 0x02,		/* Usage (Mouse) */
328     0xa1, 0x01,		/* Collection (Application) */
329     0x09, 0x01,		/*   Usage (Pointer) */
330     0xa1, 0x00,		/*   Collection (Physical) */
331     0x05, 0x09,		/*     Usage Page (Button) */
332     0x19, 0x01,		/*     Usage Minimum (1) */
333     0x29, 0x03,		/*     Usage Maximum (3) */
334     0x15, 0x00,		/*     Logical Minimum (0) */
335     0x25, 0x01,		/*     Logical Maximum (1) */
336     0x95, 0x03,		/*     Report Count (3) */
337     0x75, 0x01,		/*     Report Size (1) */
338     0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
339     0x95, 0x01,		/*     Report Count (1) */
340     0x75, 0x05,		/*     Report Size (5) */
341     0x81, 0x01,		/*     Input (Constant) */
342     0x05, 0x01,		/*     Usage Page (Generic Desktop) */
343     0x09, 0x30,		/*     Usage (X) */
344     0x09, 0x31,		/*     Usage (Y) */
345     0x09, 0x38,		/*     Usage (Wheel) */
346     0x15, 0x81,		/*     Logical Minimum (-0x7f) */
347     0x25, 0x7f,		/*     Logical Maximum (0x7f) */
348     0x75, 0x08,		/*     Report Size (8) */
349     0x95, 0x03,		/*     Report Count (3) */
350     0x81, 0x06,		/*     Input (Data, Variable, Relative) */
351     0xc0,		/*   End Collection */
352     0xc0,		/* End Collection */
353 };
354 
355 static const uint8_t qemu_tablet_hid_report_descriptor[] = {
356     0x05, 0x01,		/* Usage Page (Generic Desktop) */
357     0x09, 0x01,		/* Usage (Pointer) */
358     0xa1, 0x01,		/* Collection (Application) */
359     0x09, 0x01,		/*   Usage (Pointer) */
360     0xa1, 0x00,		/*   Collection (Physical) */
361     0x05, 0x09,		/*     Usage Page (Button) */
362     0x19, 0x01,		/*     Usage Minimum (1) */
363     0x29, 0x03,		/*     Usage Maximum (3) */
364     0x15, 0x00,		/*     Logical Minimum (0) */
365     0x25, 0x01,		/*     Logical Maximum (1) */
366     0x95, 0x03,		/*     Report Count (3) */
367     0x75, 0x01,		/*     Report Size (1) */
368     0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
369     0x95, 0x01,		/*     Report Count (1) */
370     0x75, 0x05,		/*     Report Size (5) */
371     0x81, 0x01,		/*     Input (Constant) */
372     0x05, 0x01,		/*     Usage Page (Generic Desktop) */
373     0x09, 0x30,		/*     Usage (X) */
374     0x09, 0x31,		/*     Usage (Y) */
375     0x15, 0x00,		/*     Logical Minimum (0) */
376     0x26, 0xff, 0x7f,	/*     Logical Maximum (0x7fff) */
377     0x35, 0x00,		/*     Physical Minimum (0) */
378     0x46, 0xff, 0x7f,	/*     Physical Maximum (0x7fff) */
379     0x75, 0x10,		/*     Report Size (16) */
380     0x95, 0x02,		/*     Report Count (2) */
381     0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
382     0x05, 0x01,		/*     Usage Page (Generic Desktop) */
383     0x09, 0x38,		/*     Usage (Wheel) */
384     0x15, 0x81,		/*     Logical Minimum (-0x7f) */
385     0x25, 0x7f,		/*     Logical Maximum (0x7f) */
386     0x35, 0x00,		/*     Physical Minimum (same as logical) */
387     0x45, 0x00,		/*     Physical Maximum (same as logical) */
388     0x75, 0x08,		/*     Report Size (8) */
389     0x95, 0x01,		/*     Report Count (1) */
390     0x81, 0x06,		/*     Input (Data, Variable, Relative) */
391     0xc0,		/*   End Collection */
392     0xc0,		/* End Collection */
393 };
394 
395 static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
396     0x05, 0x01,		/* Usage Page (Generic Desktop) */
397     0x09, 0x06,		/* Usage (Keyboard) */
398     0xa1, 0x01,		/* Collection (Application) */
399     0x75, 0x01,		/*   Report Size (1) */
400     0x95, 0x08,		/*   Report Count (8) */
401     0x05, 0x07,		/*   Usage Page (Key Codes) */
402     0x19, 0xe0,		/*   Usage Minimum (224) */
403     0x29, 0xe7,		/*   Usage Maximum (231) */
404     0x15, 0x00,		/*   Logical Minimum (0) */
405     0x25, 0x01,		/*   Logical Maximum (1) */
406     0x81, 0x02,		/*   Input (Data, Variable, Absolute) */
407     0x95, 0x01,		/*   Report Count (1) */
408     0x75, 0x08,		/*   Report Size (8) */
409     0x81, 0x01,		/*   Input (Constant) */
410     0x95, 0x05,		/*   Report Count (5) */
411     0x75, 0x01,		/*   Report Size (1) */
412     0x05, 0x08,		/*   Usage Page (LEDs) */
413     0x19, 0x01,		/*   Usage Minimum (1) */
414     0x29, 0x05,		/*   Usage Maximum (5) */
415     0x91, 0x02,		/*   Output (Data, Variable, Absolute) */
416     0x95, 0x01,		/*   Report Count (1) */
417     0x75, 0x03,		/*   Report Size (3) */
418     0x91, 0x01,		/*   Output (Constant) */
419     0x95, 0x06,		/*   Report Count (6) */
420     0x75, 0x08,		/*   Report Size (8) */
421     0x15, 0x00,		/*   Logical Minimum (0) */
422     0x25, 0xff,		/*   Logical Maximum (255) */
423     0x05, 0x07,		/*   Usage Page (Key Codes) */
424     0x19, 0x00,		/*   Usage Minimum (0) */
425     0x29, 0xff,		/*   Usage Maximum (255) */
426     0x81, 0x00,		/*   Input (Data, Array) */
427     0xc0,		/* End Collection */
428 };
429 
430 static void usb_hid_changed(HIDState *hs)
431 {
432     USBHIDState *us = container_of(hs, USBHIDState, hid);
433 
434     usb_wakeup(us->intr, 0);
435 }
436 
437 static void usb_hid_handle_reset(USBDevice *dev)
438 {
439     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
440 
441     hid_reset(&us->hid);
442 }
443 
444 static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
445                int request, int value, int index, int length, uint8_t *data)
446 {
447     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
448     HIDState *hs = &us->hid;
449     int ret;
450 
451     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
452     if (ret >= 0) {
453         return;
454     }
455 
456     switch (request) {
457         /* hid specific requests */
458     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
459         switch (value >> 8) {
460         case 0x22:
461             if (hs->kind == HID_MOUSE) {
462 		memcpy(data, qemu_mouse_hid_report_descriptor,
463 		       sizeof(qemu_mouse_hid_report_descriptor));
464                 p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
465             } else if (hs->kind == HID_TABLET) {
466                 memcpy(data, qemu_tablet_hid_report_descriptor,
467 		       sizeof(qemu_tablet_hid_report_descriptor));
468                 p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
469             } else if (hs->kind == HID_KEYBOARD) {
470                 memcpy(data, qemu_keyboard_hid_report_descriptor,
471                        sizeof(qemu_keyboard_hid_report_descriptor));
472                 p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
473             }
474             break;
475         default:
476             goto fail;
477         }
478         break;
479     case GET_REPORT:
480         if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
481             p->actual_length = hid_pointer_poll(hs, data, length);
482         } else if (hs->kind == HID_KEYBOARD) {
483             p->actual_length = hid_keyboard_poll(hs, data, length);
484         }
485         break;
486     case SET_REPORT:
487         if (hs->kind == HID_KEYBOARD) {
488             p->actual_length = hid_keyboard_write(hs, data, length);
489         } else {
490             goto fail;
491         }
492         break;
493     case GET_PROTOCOL:
494         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
495             goto fail;
496         }
497         data[0] = hs->protocol;
498         p->actual_length = 1;
499         break;
500     case SET_PROTOCOL:
501         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
502             goto fail;
503         }
504         hs->protocol = value;
505         break;
506     case GET_IDLE:
507         data[0] = hs->idle;
508         p->actual_length = 1;
509         break;
510     case SET_IDLE:
511         hs->idle = (uint8_t) (value >> 8);
512         hid_set_next_idle(hs);
513         if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
514             hid_pointer_activate(hs);
515         }
516         break;
517     default:
518     fail:
519         p->status = USB_RET_STALL;
520         break;
521     }
522 }
523 
524 static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
525 {
526     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
527     HIDState *hs = &us->hid;
528     uint8_t buf[p->iov.size];
529     int len = 0;
530 
531     switch (p->pid) {
532     case USB_TOKEN_IN:
533         if (p->ep->nr == 1) {
534             if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
535                 hid_pointer_activate(hs);
536             }
537             if (!hid_has_events(hs)) {
538                 p->status = USB_RET_NAK;
539                 return;
540             }
541             hid_set_next_idle(hs);
542             if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
543                 len = hid_pointer_poll(hs, buf, p->iov.size);
544             } else if (hs->kind == HID_KEYBOARD) {
545                 len = hid_keyboard_poll(hs, buf, p->iov.size);
546             }
547             usb_packet_copy(p, buf, len);
548         } else {
549             goto fail;
550         }
551         break;
552     case USB_TOKEN_OUT:
553     default:
554     fail:
555         p->status = USB_RET_STALL;
556         break;
557     }
558 }
559 
560 static void usb_hid_handle_destroy(USBDevice *dev)
561 {
562     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
563 
564     hid_free(&us->hid);
565 }
566 
567 static int usb_hid_initfn(USBDevice *dev, int kind)
568 {
569     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
570 
571     if (dev->serial) {
572         usb_desc_set_string(dev, STR_SERIALNUMBER, dev->serial);
573     }
574     usb_desc_init(dev);
575     us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
576     hid_init(&us->hid, kind, usb_hid_changed);
577     return 0;
578 }
579 
580 static int usb_tablet_initfn(USBDevice *dev)
581 {
582     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
583 
584     switch (us->usb_version) {
585     case 1:
586         dev->usb_desc = &desc_tablet;
587         break;
588     case 2:
589         dev->usb_desc = &desc_tablet2;
590         break;
591     default:
592         error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)",
593                      us->usb_version);
594         return -1;
595     }
596 
597     return usb_hid_initfn(dev, HID_TABLET);
598 }
599 
600 static int usb_mouse_initfn(USBDevice *dev)
601 {
602     return usb_hid_initfn(dev, HID_MOUSE);
603 }
604 
605 static int usb_keyboard_initfn(USBDevice *dev)
606 {
607     return usb_hid_initfn(dev, HID_KEYBOARD);
608 }
609 
610 static int usb_ptr_post_load(void *opaque, int version_id)
611 {
612     USBHIDState *s = opaque;
613 
614     if (s->dev.remote_wakeup) {
615         hid_pointer_activate(&s->hid);
616     }
617     return 0;
618 }
619 
620 static const VMStateDescription vmstate_usb_ptr = {
621     .name = "usb-ptr",
622     .version_id = 1,
623     .minimum_version_id = 1,
624     .post_load = usb_ptr_post_load,
625     .fields = (VMStateField []) {
626         VMSTATE_USB_DEVICE(dev, USBHIDState),
627         VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
628         VMSTATE_END_OF_LIST()
629     }
630 };
631 
632 static const VMStateDescription vmstate_usb_kbd = {
633     .name = "usb-kbd",
634     .version_id = 1,
635     .minimum_version_id = 1,
636     .fields = (VMStateField []) {
637         VMSTATE_USB_DEVICE(dev, USBHIDState),
638         VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
639         VMSTATE_END_OF_LIST()
640     }
641 };
642 
643 static void usb_hid_class_initfn(ObjectClass *klass, void *data)
644 {
645     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
646 
647     uc->handle_reset   = usb_hid_handle_reset;
648     uc->handle_control = usb_hid_handle_control;
649     uc->handle_data    = usb_hid_handle_data;
650     uc->handle_destroy = usb_hid_handle_destroy;
651     uc->handle_attach  = usb_desc_attach;
652 }
653 
654 static Property usb_tablet_properties[] = {
655         DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
656         DEFINE_PROP_END_OF_LIST(),
657 };
658 
659 static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
660 {
661     DeviceClass *dc = DEVICE_CLASS(klass);
662     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
663 
664     usb_hid_class_initfn(klass, data);
665     uc->init           = usb_tablet_initfn;
666     uc->product_desc   = "QEMU USB Tablet";
667     dc->vmsd = &vmstate_usb_ptr;
668     dc->props = usb_tablet_properties;
669     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
670 }
671 
672 static const TypeInfo usb_tablet_info = {
673     .name          = "usb-tablet",
674     .parent        = TYPE_USB_DEVICE,
675     .instance_size = sizeof(USBHIDState),
676     .class_init    = usb_tablet_class_initfn,
677 };
678 
679 static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
680 {
681     DeviceClass *dc = DEVICE_CLASS(klass);
682     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
683 
684     usb_hid_class_initfn(klass, data);
685     uc->init           = usb_mouse_initfn;
686     uc->product_desc   = "QEMU USB Mouse";
687     uc->usb_desc       = &desc_mouse;
688     dc->vmsd = &vmstate_usb_ptr;
689     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
690 }
691 
692 static const TypeInfo usb_mouse_info = {
693     .name          = "usb-mouse",
694     .parent        = TYPE_USB_DEVICE,
695     .instance_size = sizeof(USBHIDState),
696     .class_init    = usb_mouse_class_initfn,
697 };
698 
699 static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
700 {
701     DeviceClass *dc = DEVICE_CLASS(klass);
702     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
703 
704     usb_hid_class_initfn(klass, data);
705     uc->init           = usb_keyboard_initfn;
706     uc->product_desc   = "QEMU USB Keyboard";
707     uc->usb_desc       = &desc_keyboard;
708     dc->vmsd = &vmstate_usb_kbd;
709     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
710 }
711 
712 static const TypeInfo usb_keyboard_info = {
713     .name          = "usb-kbd",
714     .parent        = TYPE_USB_DEVICE,
715     .instance_size = sizeof(USBHIDState),
716     .class_init    = usb_keyboard_class_initfn,
717 };
718 
719 static void usb_hid_register_types(void)
720 {
721     type_register_static(&usb_tablet_info);
722     usb_legacy_register("usb-tablet", "tablet", NULL);
723     type_register_static(&usb_mouse_info);
724     usb_legacy_register("usb-mouse", "mouse", NULL);
725     type_register_static(&usb_keyboard_info);
726     usb_legacy_register("usb-kbd", "keyboard", NULL);
727 }
728 
729 type_init(usb_hid_register_types)
730