xref: /openbmc/qemu/hw/usb/dev-hid.c (revision 2993683b)
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          = 0xa0,
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          = 0xa0,
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          = 0x80,
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          = 0xa0,
257             .bMaxPower             = 50,
258             .nif = 1,
259             .ifs = &desc_iface_keyboard,
260         },
261     },
262 };
263 
264 static const USBDesc desc_mouse = {
265     .id = {
266         .idVendor          = 0x0627,
267         .idProduct         = 0x0001,
268         .bcdDevice         = 0,
269         .iManufacturer     = STR_MANUFACTURER,
270         .iProduct          = STR_PRODUCT_MOUSE,
271         .iSerialNumber     = STR_SERIALNUMBER,
272     },
273     .full = &desc_device_mouse,
274     .str  = desc_strings,
275 };
276 
277 static const USBDesc desc_tablet = {
278     .id = {
279         .idVendor          = 0x0627,
280         .idProduct         = 0x0001,
281         .bcdDevice         = 0,
282         .iManufacturer     = STR_MANUFACTURER,
283         .iProduct          = STR_PRODUCT_TABLET,
284         .iSerialNumber     = STR_SERIALNUMBER,
285     },
286     .full = &desc_device_tablet,
287     .str  = desc_strings,
288 };
289 
290 static const USBDesc desc_tablet2 = {
291     .id = {
292         .idVendor          = 0x0627,
293         .idProduct         = 0x0001,
294         .bcdDevice         = 0,
295         .iManufacturer     = STR_MANUFACTURER,
296         .iProduct          = STR_PRODUCT_TABLET,
297         .iSerialNumber     = STR_SERIALNUMBER,
298     },
299     .full = &desc_device_tablet,
300     .high = &desc_device_tablet2,
301     .str  = desc_strings,
302 };
303 
304 static const USBDesc desc_keyboard = {
305     .id = {
306         .idVendor          = 0x0627,
307         .idProduct         = 0x0001,
308         .bcdDevice         = 0,
309         .iManufacturer     = STR_MANUFACTURER,
310         .iProduct          = STR_PRODUCT_KEYBOARD,
311         .iSerialNumber     = STR_SERIALNUMBER,
312     },
313     .full = &desc_device_keyboard,
314     .str  = desc_strings,
315 };
316 
317 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
318     0x05, 0x01,		/* Usage Page (Generic Desktop) */
319     0x09, 0x02,		/* Usage (Mouse) */
320     0xa1, 0x01,		/* Collection (Application) */
321     0x09, 0x01,		/*   Usage (Pointer) */
322     0xa1, 0x00,		/*   Collection (Physical) */
323     0x05, 0x09,		/*     Usage Page (Button) */
324     0x19, 0x01,		/*     Usage Minimum (1) */
325     0x29, 0x03,		/*     Usage Maximum (3) */
326     0x15, 0x00,		/*     Logical Minimum (0) */
327     0x25, 0x01,		/*     Logical Maximum (1) */
328     0x95, 0x03,		/*     Report Count (3) */
329     0x75, 0x01,		/*     Report Size (1) */
330     0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
331     0x95, 0x01,		/*     Report Count (1) */
332     0x75, 0x05,		/*     Report Size (5) */
333     0x81, 0x01,		/*     Input (Constant) */
334     0x05, 0x01,		/*     Usage Page (Generic Desktop) */
335     0x09, 0x30,		/*     Usage (X) */
336     0x09, 0x31,		/*     Usage (Y) */
337     0x09, 0x38,		/*     Usage (Wheel) */
338     0x15, 0x81,		/*     Logical Minimum (-0x7f) */
339     0x25, 0x7f,		/*     Logical Maximum (0x7f) */
340     0x75, 0x08,		/*     Report Size (8) */
341     0x95, 0x03,		/*     Report Count (3) */
342     0x81, 0x06,		/*     Input (Data, Variable, Relative) */
343     0xc0,		/*   End Collection */
344     0xc0,		/* End Collection */
345 };
346 
347 static const uint8_t qemu_tablet_hid_report_descriptor[] = {
348     0x05, 0x01,		/* Usage Page (Generic Desktop) */
349     0x09, 0x01,		/* Usage (Pointer) */
350     0xa1, 0x01,		/* Collection (Application) */
351     0x09, 0x01,		/*   Usage (Pointer) */
352     0xa1, 0x00,		/*   Collection (Physical) */
353     0x05, 0x09,		/*     Usage Page (Button) */
354     0x19, 0x01,		/*     Usage Minimum (1) */
355     0x29, 0x03,		/*     Usage Maximum (3) */
356     0x15, 0x00,		/*     Logical Minimum (0) */
357     0x25, 0x01,		/*     Logical Maximum (1) */
358     0x95, 0x03,		/*     Report Count (3) */
359     0x75, 0x01,		/*     Report Size (1) */
360     0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
361     0x95, 0x01,		/*     Report Count (1) */
362     0x75, 0x05,		/*     Report Size (5) */
363     0x81, 0x01,		/*     Input (Constant) */
364     0x05, 0x01,		/*     Usage Page (Generic Desktop) */
365     0x09, 0x30,		/*     Usage (X) */
366     0x09, 0x31,		/*     Usage (Y) */
367     0x15, 0x00,		/*     Logical Minimum (0) */
368     0x26, 0xff, 0x7f,	/*     Logical Maximum (0x7fff) */
369     0x35, 0x00,		/*     Physical Minimum (0) */
370     0x46, 0xff, 0x7f,	/*     Physical Maximum (0x7fff) */
371     0x75, 0x10,		/*     Report Size (16) */
372     0x95, 0x02,		/*     Report Count (2) */
373     0x81, 0x02,		/*     Input (Data, Variable, Absolute) */
374     0x05, 0x01,		/*     Usage Page (Generic Desktop) */
375     0x09, 0x38,		/*     Usage (Wheel) */
376     0x15, 0x81,		/*     Logical Minimum (-0x7f) */
377     0x25, 0x7f,		/*     Logical Maximum (0x7f) */
378     0x35, 0x00,		/*     Physical Minimum (same as logical) */
379     0x45, 0x00,		/*     Physical Maximum (same as logical) */
380     0x75, 0x08,		/*     Report Size (8) */
381     0x95, 0x01,		/*     Report Count (1) */
382     0x81, 0x06,		/*     Input (Data, Variable, Relative) */
383     0xc0,		/*   End Collection */
384     0xc0,		/* End Collection */
385 };
386 
387 static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
388     0x05, 0x01,		/* Usage Page (Generic Desktop) */
389     0x09, 0x06,		/* Usage (Keyboard) */
390     0xa1, 0x01,		/* Collection (Application) */
391     0x75, 0x01,		/*   Report Size (1) */
392     0x95, 0x08,		/*   Report Count (8) */
393     0x05, 0x07,		/*   Usage Page (Key Codes) */
394     0x19, 0xe0,		/*   Usage Minimum (224) */
395     0x29, 0xe7,		/*   Usage Maximum (231) */
396     0x15, 0x00,		/*   Logical Minimum (0) */
397     0x25, 0x01,		/*   Logical Maximum (1) */
398     0x81, 0x02,		/*   Input (Data, Variable, Absolute) */
399     0x95, 0x01,		/*   Report Count (1) */
400     0x75, 0x08,		/*   Report Size (8) */
401     0x81, 0x01,		/*   Input (Constant) */
402     0x95, 0x05,		/*   Report Count (5) */
403     0x75, 0x01,		/*   Report Size (1) */
404     0x05, 0x08,		/*   Usage Page (LEDs) */
405     0x19, 0x01,		/*   Usage Minimum (1) */
406     0x29, 0x05,		/*   Usage Maximum (5) */
407     0x91, 0x02,		/*   Output (Data, Variable, Absolute) */
408     0x95, 0x01,		/*   Report Count (1) */
409     0x75, 0x03,		/*   Report Size (3) */
410     0x91, 0x01,		/*   Output (Constant) */
411     0x95, 0x06,		/*   Report Count (6) */
412     0x75, 0x08,		/*   Report Size (8) */
413     0x15, 0x00,		/*   Logical Minimum (0) */
414     0x25, 0xff,		/*   Logical Maximum (255) */
415     0x05, 0x07,		/*   Usage Page (Key Codes) */
416     0x19, 0x00,		/*   Usage Minimum (0) */
417     0x29, 0xff,		/*   Usage Maximum (255) */
418     0x81, 0x00,		/*   Input (Data, Array) */
419     0xc0,		/* End Collection */
420 };
421 
422 static void usb_hid_changed(HIDState *hs)
423 {
424     USBHIDState *us = container_of(hs, USBHIDState, hid);
425 
426     usb_wakeup(us->intr, 0);
427 }
428 
429 static void usb_hid_handle_reset(USBDevice *dev)
430 {
431     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
432 
433     hid_reset(&us->hid);
434 }
435 
436 static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
437                int request, int value, int index, int length, uint8_t *data)
438 {
439     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
440     HIDState *hs = &us->hid;
441     int ret;
442 
443     ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
444     if (ret >= 0) {
445         return;
446     }
447 
448     switch (request) {
449         /* hid specific requests */
450     case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
451         switch (value >> 8) {
452         case 0x22:
453             if (hs->kind == HID_MOUSE) {
454 		memcpy(data, qemu_mouse_hid_report_descriptor,
455 		       sizeof(qemu_mouse_hid_report_descriptor));
456                 p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
457             } else if (hs->kind == HID_TABLET) {
458                 memcpy(data, qemu_tablet_hid_report_descriptor,
459 		       sizeof(qemu_tablet_hid_report_descriptor));
460                 p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
461             } else if (hs->kind == HID_KEYBOARD) {
462                 memcpy(data, qemu_keyboard_hid_report_descriptor,
463                        sizeof(qemu_keyboard_hid_report_descriptor));
464                 p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
465             }
466             break;
467         default:
468             goto fail;
469         }
470         break;
471     case GET_REPORT:
472         if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
473             p->actual_length = hid_pointer_poll(hs, data, length);
474         } else if (hs->kind == HID_KEYBOARD) {
475             p->actual_length = hid_keyboard_poll(hs, data, length);
476         }
477         break;
478     case SET_REPORT:
479         if (hs->kind == HID_KEYBOARD) {
480             p->actual_length = hid_keyboard_write(hs, data, length);
481         } else {
482             goto fail;
483         }
484         break;
485     case GET_PROTOCOL:
486         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
487             goto fail;
488         }
489         data[0] = hs->protocol;
490         p->actual_length = 1;
491         break;
492     case SET_PROTOCOL:
493         if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
494             goto fail;
495         }
496         hs->protocol = value;
497         break;
498     case GET_IDLE:
499         data[0] = hs->idle;
500         p->actual_length = 1;
501         break;
502     case SET_IDLE:
503         hs->idle = (uint8_t) (value >> 8);
504         hid_set_next_idle(hs);
505         if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
506             hid_pointer_activate(hs);
507         }
508         break;
509     default:
510     fail:
511         p->status = USB_RET_STALL;
512         break;
513     }
514 }
515 
516 static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
517 {
518     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
519     HIDState *hs = &us->hid;
520     uint8_t buf[p->iov.size];
521     int len = 0;
522 
523     switch (p->pid) {
524     case USB_TOKEN_IN:
525         if (p->ep->nr == 1) {
526             if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
527                 hid_pointer_activate(hs);
528             }
529             if (!hid_has_events(hs)) {
530                 p->status = USB_RET_NAK;
531                 return;
532             }
533             hid_set_next_idle(hs);
534             if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
535                 len = hid_pointer_poll(hs, buf, p->iov.size);
536             } else if (hs->kind == HID_KEYBOARD) {
537                 len = hid_keyboard_poll(hs, buf, p->iov.size);
538             }
539             usb_packet_copy(p, buf, len);
540         } else {
541             goto fail;
542         }
543         break;
544     case USB_TOKEN_OUT:
545     default:
546     fail:
547         p->status = USB_RET_STALL;
548         break;
549     }
550 }
551 
552 static void usb_hid_handle_destroy(USBDevice *dev)
553 {
554     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
555 
556     hid_free(&us->hid);
557 }
558 
559 static int usb_hid_initfn(USBDevice *dev, int kind)
560 {
561     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
562 
563     usb_desc_init(dev);
564     us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
565     hid_init(&us->hid, kind, usb_hid_changed);
566     return 0;
567 }
568 
569 static int usb_tablet_initfn(USBDevice *dev)
570 {
571     USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
572 
573     switch (us->usb_version) {
574     case 1:
575         dev->usb_desc = &desc_tablet;
576         break;
577     case 2:
578         dev->usb_desc = &desc_tablet2;
579         break;
580     default:
581         error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)",
582                      us->usb_version);
583         return -1;
584     }
585 
586     return usb_hid_initfn(dev, HID_TABLET);
587 }
588 
589 static int usb_mouse_initfn(USBDevice *dev)
590 {
591     return usb_hid_initfn(dev, HID_MOUSE);
592 }
593 
594 static int usb_keyboard_initfn(USBDevice *dev)
595 {
596     return usb_hid_initfn(dev, HID_KEYBOARD);
597 }
598 
599 static int usb_ptr_post_load(void *opaque, int version_id)
600 {
601     USBHIDState *s = opaque;
602 
603     if (s->dev.remote_wakeup) {
604         hid_pointer_activate(&s->hid);
605     }
606     return 0;
607 }
608 
609 static const VMStateDescription vmstate_usb_ptr = {
610     .name = "usb-ptr",
611     .version_id = 1,
612     .minimum_version_id = 1,
613     .post_load = usb_ptr_post_load,
614     .fields = (VMStateField []) {
615         VMSTATE_USB_DEVICE(dev, USBHIDState),
616         VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
617         VMSTATE_END_OF_LIST()
618     }
619 };
620 
621 static const VMStateDescription vmstate_usb_kbd = {
622     .name = "usb-kbd",
623     .version_id = 1,
624     .minimum_version_id = 1,
625     .fields = (VMStateField []) {
626         VMSTATE_USB_DEVICE(dev, USBHIDState),
627         VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
628         VMSTATE_END_OF_LIST()
629     }
630 };
631 
632 static void usb_hid_class_initfn(ObjectClass *klass, void *data)
633 {
634     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
635 
636     uc->handle_reset   = usb_hid_handle_reset;
637     uc->handle_control = usb_hid_handle_control;
638     uc->handle_data    = usb_hid_handle_data;
639     uc->handle_destroy = usb_hid_handle_destroy;
640     uc->handle_attach  = usb_desc_attach;
641 }
642 
643 static Property usb_tablet_properties[] = {
644         DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
645         DEFINE_PROP_END_OF_LIST(),
646 };
647 
648 static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
649 {
650     DeviceClass *dc = DEVICE_CLASS(klass);
651     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
652 
653     usb_hid_class_initfn(klass, data);
654     uc->init           = usb_tablet_initfn;
655     uc->product_desc   = "QEMU USB Tablet";
656     dc->vmsd = &vmstate_usb_ptr;
657     dc->props = usb_tablet_properties;
658 }
659 
660 static const TypeInfo usb_tablet_info = {
661     .name          = "usb-tablet",
662     .parent        = TYPE_USB_DEVICE,
663     .instance_size = sizeof(USBHIDState),
664     .class_init    = usb_tablet_class_initfn,
665 };
666 
667 static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
668 {
669     DeviceClass *dc = DEVICE_CLASS(klass);
670     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
671 
672     usb_hid_class_initfn(klass, data);
673     uc->init           = usb_mouse_initfn;
674     uc->product_desc   = "QEMU USB Mouse";
675     uc->usb_desc       = &desc_mouse;
676     dc->vmsd = &vmstate_usb_ptr;
677 }
678 
679 static const TypeInfo usb_mouse_info = {
680     .name          = "usb-mouse",
681     .parent        = TYPE_USB_DEVICE,
682     .instance_size = sizeof(USBHIDState),
683     .class_init    = usb_mouse_class_initfn,
684 };
685 
686 static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
687 {
688     DeviceClass *dc = DEVICE_CLASS(klass);
689     USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
690 
691     usb_hid_class_initfn(klass, data);
692     uc->init           = usb_keyboard_initfn;
693     uc->product_desc   = "QEMU USB Keyboard";
694     uc->usb_desc       = &desc_keyboard;
695     dc->vmsd = &vmstate_usb_kbd;
696 }
697 
698 static const TypeInfo usb_keyboard_info = {
699     .name          = "usb-kbd",
700     .parent        = TYPE_USB_DEVICE,
701     .instance_size = sizeof(USBHIDState),
702     .class_init    = usb_keyboard_class_initfn,
703 };
704 
705 static void usb_hid_register_types(void)
706 {
707     type_register_static(&usb_tablet_info);
708     usb_legacy_register("usb-tablet", "tablet", NULL);
709     type_register_static(&usb_mouse_info);
710     usb_legacy_register("usb-mouse", "mouse", NULL);
711     type_register_static(&usb_keyboard_info);
712     usb_legacy_register("usb-kbd", "keyboard", NULL);
713 }
714 
715 type_init(usb_hid_register_types)
716