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