Statistics
| Branch: | Revision:

root / hw / usb / dev-hid.c @ 873123fe

History | View | Annotate | Download (20.2 kB)

1 59ae540c bellard
/*
2 59ae540c bellard
 * QEMU USB HID devices
3 5fafdf24 ths
 *
4 59ae540c bellard
 * Copyright (c) 2005 Fabrice Bellard
5 47b2d338 balrog
 * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
6 5fafdf24 ths
 *
7 59ae540c bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 59ae540c bellard
 * of this software and associated documentation files (the "Software"), to deal
9 59ae540c bellard
 * in the Software without restriction, including without limitation the rights
10 59ae540c bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 59ae540c bellard
 * copies of the Software, and to permit persons to whom the Software is
12 59ae540c bellard
 * furnished to do so, subject to the following conditions:
13 59ae540c bellard
 *
14 59ae540c bellard
 * The above copyright notice and this permission notice shall be included in
15 59ae540c bellard
 * all copies or substantial portions of the Software.
16 59ae540c bellard
 *
17 59ae540c bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 59ae540c bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 59ae540c bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 59ae540c bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 59ae540c bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 59ae540c bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 59ae540c bellard
 * THE SOFTWARE.
24 59ae540c bellard
 */
25 f1ae32a1 Gerd Hoffmann
#include "hw/hw.h"
26 87ecb68b pbrook
#include "console.h"
27 f1ae32a1 Gerd Hoffmann
#include "hw/usb.h"
28 f1ae32a1 Gerd Hoffmann
#include "hw/usb/desc.h"
29 d8dfad9c Blue Swirl
#include "qemu-timer.h"
30 f1ae32a1 Gerd Hoffmann
#include "hw/hid.h"
31 59ae540c bellard
32 59ae540c bellard
/* HID interface requests */
33 59ae540c bellard
#define GET_REPORT   0xa101
34 59ae540c bellard
#define GET_IDLE     0xa102
35 59ae540c bellard
#define GET_PROTOCOL 0xa103
36 47b2d338 balrog
#define SET_REPORT   0x2109
37 59ae540c bellard
#define SET_IDLE     0x210a
38 59ae540c bellard
#define SET_PROTOCOL 0x210b
39 59ae540c bellard
40 47b2d338 balrog
/* HID descriptor types */
41 47b2d338 balrog
#define USB_DT_HID    0x21
42 47b2d338 balrog
#define USB_DT_REPORT 0x22
43 47b2d338 balrog
#define USB_DT_PHY    0x23
44 47b2d338 balrog
45 0d878eec Gerd Hoffmann
typedef struct USBHIDState {
46 0d878eec Gerd Hoffmann
    USBDevice dev;
47 7567b51f Gerd Hoffmann
    USBEndpoint *intr;
48 0d878eec Gerd Hoffmann
    HIDState hid;
49 47b2d338 balrog
} USBHIDState;
50 47b2d338 balrog
51 0e4e9695 Gerd Hoffmann
enum {
52 0e4e9695 Gerd Hoffmann
    STR_MANUFACTURER = 1,
53 0e4e9695 Gerd Hoffmann
    STR_PRODUCT_MOUSE,
54 0e4e9695 Gerd Hoffmann
    STR_PRODUCT_TABLET,
55 0e4e9695 Gerd Hoffmann
    STR_PRODUCT_KEYBOARD,
56 0e4e9695 Gerd Hoffmann
    STR_SERIALNUMBER,
57 0e4e9695 Gerd Hoffmann
    STR_CONFIG_MOUSE,
58 0e4e9695 Gerd Hoffmann
    STR_CONFIG_TABLET,
59 0e4e9695 Gerd Hoffmann
    STR_CONFIG_KEYBOARD,
60 59ae540c bellard
};
61 59ae540c bellard
62 0e4e9695 Gerd Hoffmann
static const USBDescStrings desc_strings = {
63 93bfef4c Crístian Viana
    [STR_MANUFACTURER]     = "QEMU",
64 0e4e9695 Gerd Hoffmann
    [STR_PRODUCT_MOUSE]    = "QEMU USB Mouse",
65 0e4e9695 Gerd Hoffmann
    [STR_PRODUCT_TABLET]   = "QEMU USB Tablet",
66 0e4e9695 Gerd Hoffmann
    [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
67 7b074a22 Gerd Hoffmann
    [STR_SERIALNUMBER]     = "42", /* == remote wakeup works */
68 0e4e9695 Gerd Hoffmann
    [STR_CONFIG_MOUSE]     = "HID Mouse",
69 0e4e9695 Gerd Hoffmann
    [STR_CONFIG_TABLET]    = "HID Tablet",
70 0e4e9695 Gerd Hoffmann
    [STR_CONFIG_KEYBOARD]  = "HID Keyboard",
71 09b26c5e bellard
};
72 09b26c5e bellard
73 0e4e9695 Gerd Hoffmann
static const USBDescIface desc_iface_mouse = {
74 0e4e9695 Gerd Hoffmann
    .bInterfaceNumber              = 0,
75 0e4e9695 Gerd Hoffmann
    .bNumEndpoints                 = 1,
76 0e4e9695 Gerd Hoffmann
    .bInterfaceClass               = USB_CLASS_HID,
77 0e4e9695 Gerd Hoffmann
    .bInterfaceSubClass            = 0x01, /* boot */
78 0e4e9695 Gerd Hoffmann
    .bInterfaceProtocol            = 0x02,
79 0e4e9695 Gerd Hoffmann
    .ndesc                         = 1,
80 0e4e9695 Gerd Hoffmann
    .descs = (USBDescOther[]) {
81 0e4e9695 Gerd Hoffmann
        {
82 0e4e9695 Gerd Hoffmann
            /* HID descriptor */
83 0e4e9695 Gerd Hoffmann
            .data = (uint8_t[]) {
84 0e4e9695 Gerd Hoffmann
                0x09,          /*  u8  bLength */
85 0e4e9695 Gerd Hoffmann
                USB_DT_HID,    /*  u8  bDescriptorType */
86 0e4e9695 Gerd Hoffmann
                0x01, 0x00,    /*  u16 HID_class */
87 0e4e9695 Gerd Hoffmann
                0x00,          /*  u8  country_code */
88 0e4e9695 Gerd Hoffmann
                0x01,          /*  u8  num_descriptors */
89 0e4e9695 Gerd Hoffmann
                USB_DT_REPORT, /*  u8  type: Report */
90 0e4e9695 Gerd Hoffmann
                52, 0,         /*  u16 len */
91 0e4e9695 Gerd Hoffmann
            },
92 0e4e9695 Gerd Hoffmann
        },
93 0e4e9695 Gerd Hoffmann
    },
94 0e4e9695 Gerd Hoffmann
    .eps = (USBDescEndpoint[]) {
95 0e4e9695 Gerd Hoffmann
        {
96 0e4e9695 Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_IN | 0x01,
97 0e4e9695 Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_INT,
98 0e4e9695 Gerd Hoffmann
            .wMaxPacketSize        = 4,
99 0e4e9695 Gerd Hoffmann
            .bInterval             = 0x0a,
100 0e4e9695 Gerd Hoffmann
        },
101 0e4e9695 Gerd Hoffmann
    },
102 59ae540c bellard
};
103 59ae540c bellard
104 0e4e9695 Gerd Hoffmann
static const USBDescIface desc_iface_tablet = {
105 0e4e9695 Gerd Hoffmann
    .bInterfaceNumber              = 0,
106 0e4e9695 Gerd Hoffmann
    .bNumEndpoints                 = 1,
107 0e4e9695 Gerd Hoffmann
    .bInterfaceClass               = USB_CLASS_HID,
108 0e4e9695 Gerd Hoffmann
    .bInterfaceProtocol            = 0x02,
109 0e4e9695 Gerd Hoffmann
    .ndesc                         = 1,
110 0e4e9695 Gerd Hoffmann
    .descs = (USBDescOther[]) {
111 0e4e9695 Gerd Hoffmann
        {
112 0e4e9695 Gerd Hoffmann
            /* HID descriptor */
113 0e4e9695 Gerd Hoffmann
            .data = (uint8_t[]) {
114 0e4e9695 Gerd Hoffmann
                0x09,          /*  u8  bLength */
115 0e4e9695 Gerd Hoffmann
                USB_DT_HID,    /*  u8  bDescriptorType */
116 0e4e9695 Gerd Hoffmann
                0x01, 0x00,    /*  u16 HID_class */
117 0e4e9695 Gerd Hoffmann
                0x00,          /*  u8  country_code */
118 0e4e9695 Gerd Hoffmann
                0x01,          /*  u8  num_descriptors */
119 0e4e9695 Gerd Hoffmann
                USB_DT_REPORT, /*  u8  type: Report */
120 0e4e9695 Gerd Hoffmann
                74, 0,         /*  u16 len */
121 0e4e9695 Gerd Hoffmann
            },
122 0e4e9695 Gerd Hoffmann
        },
123 0e4e9695 Gerd Hoffmann
    },
124 0e4e9695 Gerd Hoffmann
    .eps = (USBDescEndpoint[]) {
125 0e4e9695 Gerd Hoffmann
        {
126 0e4e9695 Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_IN | 0x01,
127 0e4e9695 Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_INT,
128 0e4e9695 Gerd Hoffmann
            .wMaxPacketSize        = 8,
129 0e4e9695 Gerd Hoffmann
            .bInterval             = 0x0a,
130 0e4e9695 Gerd Hoffmann
        },
131 0e4e9695 Gerd Hoffmann
    },
132 0e4e9695 Gerd Hoffmann
};
133 0e4e9695 Gerd Hoffmann
134 0e4e9695 Gerd Hoffmann
static const USBDescIface desc_iface_keyboard = {
135 0e4e9695 Gerd Hoffmann
    .bInterfaceNumber              = 0,
136 0e4e9695 Gerd Hoffmann
    .bNumEndpoints                 = 1,
137 0e4e9695 Gerd Hoffmann
    .bInterfaceClass               = USB_CLASS_HID,
138 0e4e9695 Gerd Hoffmann
    .bInterfaceSubClass            = 0x01, /* boot */
139 0e4e9695 Gerd Hoffmann
    .bInterfaceProtocol            = 0x01, /* keyboard */
140 0e4e9695 Gerd Hoffmann
    .ndesc                         = 1,
141 0e4e9695 Gerd Hoffmann
    .descs = (USBDescOther[]) {
142 0e4e9695 Gerd Hoffmann
        {
143 0e4e9695 Gerd Hoffmann
            /* HID descriptor */
144 0e4e9695 Gerd Hoffmann
            .data = (uint8_t[]) {
145 0e4e9695 Gerd Hoffmann
                0x09,          /*  u8  bLength */
146 0e4e9695 Gerd Hoffmann
                USB_DT_HID,    /*  u8  bDescriptorType */
147 0e4e9695 Gerd Hoffmann
                0x11, 0x01,    /*  u16 HID_class */
148 0e4e9695 Gerd Hoffmann
                0x00,          /*  u8  country_code */
149 0e4e9695 Gerd Hoffmann
                0x01,          /*  u8  num_descriptors */
150 0e4e9695 Gerd Hoffmann
                USB_DT_REPORT, /*  u8  type: Report */
151 0e4e9695 Gerd Hoffmann
                0x3f, 0,       /*  u16 len */
152 0e4e9695 Gerd Hoffmann
            },
153 0e4e9695 Gerd Hoffmann
        },
154 0e4e9695 Gerd Hoffmann
    },
155 0e4e9695 Gerd Hoffmann
    .eps = (USBDescEndpoint[]) {
156 0e4e9695 Gerd Hoffmann
        {
157 0e4e9695 Gerd Hoffmann
            .bEndpointAddress      = USB_DIR_IN | 0x01,
158 0e4e9695 Gerd Hoffmann
            .bmAttributes          = USB_ENDPOINT_XFER_INT,
159 0e4e9695 Gerd Hoffmann
            .wMaxPacketSize        = 8,
160 0e4e9695 Gerd Hoffmann
            .bInterval             = 0x0a,
161 0e4e9695 Gerd Hoffmann
        },
162 0e4e9695 Gerd Hoffmann
    },
163 0e4e9695 Gerd Hoffmann
};
164 0e4e9695 Gerd Hoffmann
165 0e4e9695 Gerd Hoffmann
static const USBDescDevice desc_device_mouse = {
166 0e4e9695 Gerd Hoffmann
    .bcdUSB                        = 0x0100,
167 0e4e9695 Gerd Hoffmann
    .bMaxPacketSize0               = 8,
168 0e4e9695 Gerd Hoffmann
    .bNumConfigurations            = 1,
169 0e4e9695 Gerd Hoffmann
    .confs = (USBDescConfig[]) {
170 0e4e9695 Gerd Hoffmann
        {
171 0e4e9695 Gerd Hoffmann
            .bNumInterfaces        = 1,
172 0e4e9695 Gerd Hoffmann
            .bConfigurationValue   = 1,
173 0e4e9695 Gerd Hoffmann
            .iConfiguration        = STR_CONFIG_MOUSE,
174 0e4e9695 Gerd Hoffmann
            .bmAttributes          = 0xa0,
175 0e4e9695 Gerd Hoffmann
            .bMaxPower             = 50,
176 add75088 Brad Hards
            .nif = 1,
177 0e4e9695 Gerd Hoffmann
            .ifs = &desc_iface_mouse,
178 0e4e9695 Gerd Hoffmann
        },
179 0e4e9695 Gerd Hoffmann
    },
180 0e4e9695 Gerd Hoffmann
};
181 0e4e9695 Gerd Hoffmann
182 0e4e9695 Gerd Hoffmann
static const USBDescDevice desc_device_tablet = {
183 0e4e9695 Gerd Hoffmann
    .bcdUSB                        = 0x0100,
184 0e4e9695 Gerd Hoffmann
    .bMaxPacketSize0               = 8,
185 0e4e9695 Gerd Hoffmann
    .bNumConfigurations            = 1,
186 0e4e9695 Gerd Hoffmann
    .confs = (USBDescConfig[]) {
187 0e4e9695 Gerd Hoffmann
        {
188 0e4e9695 Gerd Hoffmann
            .bNumInterfaces        = 1,
189 0e4e9695 Gerd Hoffmann
            .bConfigurationValue   = 1,
190 0e4e9695 Gerd Hoffmann
            .iConfiguration        = STR_CONFIG_TABLET,
191 0e4e9695 Gerd Hoffmann
            .bmAttributes          = 0xa0,
192 0e4e9695 Gerd Hoffmann
            .bMaxPower             = 50,
193 add75088 Brad Hards
            .nif = 1,
194 0e4e9695 Gerd Hoffmann
            .ifs = &desc_iface_tablet,
195 0e4e9695 Gerd Hoffmann
        },
196 0e4e9695 Gerd Hoffmann
    },
197 0e4e9695 Gerd Hoffmann
};
198 0e4e9695 Gerd Hoffmann
199 0e4e9695 Gerd Hoffmann
static const USBDescDevice desc_device_keyboard = {
200 0e4e9695 Gerd Hoffmann
    .bcdUSB                        = 0x0100,
201 0e4e9695 Gerd Hoffmann
    .bMaxPacketSize0               = 8,
202 0e4e9695 Gerd Hoffmann
    .bNumConfigurations            = 1,
203 0e4e9695 Gerd Hoffmann
    .confs = (USBDescConfig[]) {
204 0e4e9695 Gerd Hoffmann
        {
205 0e4e9695 Gerd Hoffmann
            .bNumInterfaces        = 1,
206 0e4e9695 Gerd Hoffmann
            .bConfigurationValue   = 1,
207 0e4e9695 Gerd Hoffmann
            .iConfiguration        = STR_CONFIG_KEYBOARD,
208 0e4e9695 Gerd Hoffmann
            .bmAttributes          = 0xa0,
209 0e4e9695 Gerd Hoffmann
            .bMaxPower             = 50,
210 add75088 Brad Hards
            .nif = 1,
211 0e4e9695 Gerd Hoffmann
            .ifs = &desc_iface_keyboard,
212 0e4e9695 Gerd Hoffmann
        },
213 0e4e9695 Gerd Hoffmann
    },
214 0e4e9695 Gerd Hoffmann
};
215 0e4e9695 Gerd Hoffmann
216 0e4e9695 Gerd Hoffmann
static const USBDesc desc_mouse = {
217 0e4e9695 Gerd Hoffmann
    .id = {
218 0e4e9695 Gerd Hoffmann
        .idVendor          = 0x0627,
219 0e4e9695 Gerd Hoffmann
        .idProduct         = 0x0001,
220 0e4e9695 Gerd Hoffmann
        .bcdDevice         = 0,
221 0e4e9695 Gerd Hoffmann
        .iManufacturer     = STR_MANUFACTURER,
222 0e4e9695 Gerd Hoffmann
        .iProduct          = STR_PRODUCT_MOUSE,
223 0e4e9695 Gerd Hoffmann
        .iSerialNumber     = STR_SERIALNUMBER,
224 0e4e9695 Gerd Hoffmann
    },
225 0e4e9695 Gerd Hoffmann
    .full = &desc_device_mouse,
226 0e4e9695 Gerd Hoffmann
    .str  = desc_strings,
227 0e4e9695 Gerd Hoffmann
};
228 0e4e9695 Gerd Hoffmann
229 0e4e9695 Gerd Hoffmann
static const USBDesc desc_tablet = {
230 0e4e9695 Gerd Hoffmann
    .id = {
231 0e4e9695 Gerd Hoffmann
        .idVendor          = 0x0627,
232 0e4e9695 Gerd Hoffmann
        .idProduct         = 0x0001,
233 0e4e9695 Gerd Hoffmann
        .bcdDevice         = 0,
234 0e4e9695 Gerd Hoffmann
        .iManufacturer     = STR_MANUFACTURER,
235 0e4e9695 Gerd Hoffmann
        .iProduct          = STR_PRODUCT_TABLET,
236 0e4e9695 Gerd Hoffmann
        .iSerialNumber     = STR_SERIALNUMBER,
237 0e4e9695 Gerd Hoffmann
    },
238 0e4e9695 Gerd Hoffmann
    .full = &desc_device_tablet,
239 0e4e9695 Gerd Hoffmann
    .str  = desc_strings,
240 0e4e9695 Gerd Hoffmann
};
241 0e4e9695 Gerd Hoffmann
242 0e4e9695 Gerd Hoffmann
static const USBDesc desc_keyboard = {
243 0e4e9695 Gerd Hoffmann
    .id = {
244 0e4e9695 Gerd Hoffmann
        .idVendor          = 0x0627,
245 0e4e9695 Gerd Hoffmann
        .idProduct         = 0x0001,
246 0e4e9695 Gerd Hoffmann
        .bcdDevice         = 0,
247 0e4e9695 Gerd Hoffmann
        .iManufacturer     = STR_MANUFACTURER,
248 0e4e9695 Gerd Hoffmann
        .iProduct          = STR_PRODUCT_KEYBOARD,
249 0e4e9695 Gerd Hoffmann
        .iSerialNumber     = STR_SERIALNUMBER,
250 0e4e9695 Gerd Hoffmann
    },
251 0e4e9695 Gerd Hoffmann
    .full = &desc_device_keyboard,
252 0e4e9695 Gerd Hoffmann
    .str  = desc_strings,
253 47b2d338 balrog
};
254 47b2d338 balrog
255 59ae540c bellard
static const uint8_t qemu_mouse_hid_report_descriptor[] = {
256 976f8eef balrog
    0x05, 0x01,                /* Usage Page (Generic Desktop) */
257 976f8eef balrog
    0x09, 0x02,                /* Usage (Mouse) */
258 976f8eef balrog
    0xa1, 0x01,                /* Collection (Application) */
259 976f8eef balrog
    0x09, 0x01,                /*   Usage (Pointer) */
260 976f8eef balrog
    0xa1, 0x00,                /*   Collection (Physical) */
261 976f8eef balrog
    0x05, 0x09,                /*     Usage Page (Button) */
262 976f8eef balrog
    0x19, 0x01,                /*     Usage Minimum (1) */
263 976f8eef balrog
    0x29, 0x03,                /*     Usage Maximum (3) */
264 976f8eef balrog
    0x15, 0x00,                /*     Logical Minimum (0) */
265 976f8eef balrog
    0x25, 0x01,                /*     Logical Maximum (1) */
266 976f8eef balrog
    0x95, 0x03,                /*     Report Count (3) */
267 976f8eef balrog
    0x75, 0x01,                /*     Report Size (1) */
268 976f8eef balrog
    0x81, 0x02,                /*     Input (Data, Variable, Absolute) */
269 976f8eef balrog
    0x95, 0x01,                /*     Report Count (1) */
270 976f8eef balrog
    0x75, 0x05,                /*     Report Size (5) */
271 976f8eef balrog
    0x81, 0x01,                /*     Input (Constant) */
272 976f8eef balrog
    0x05, 0x01,                /*     Usage Page (Generic Desktop) */
273 976f8eef balrog
    0x09, 0x30,                /*     Usage (X) */
274 976f8eef balrog
    0x09, 0x31,                /*     Usage (Y) */
275 976f8eef balrog
    0x09, 0x38,                /*     Usage (Wheel) */
276 976f8eef balrog
    0x15, 0x81,                /*     Logical Minimum (-0x7f) */
277 976f8eef balrog
    0x25, 0x7f,                /*     Logical Maximum (0x7f) */
278 976f8eef balrog
    0x75, 0x08,                /*     Report Size (8) */
279 976f8eef balrog
    0x95, 0x03,                /*     Report Count (3) */
280 976f8eef balrog
    0x81, 0x06,                /*     Input (Data, Variable, Relative) */
281 976f8eef balrog
    0xc0,                /*   End Collection */
282 976f8eef balrog
    0xc0,                /* End Collection */
283 59ae540c bellard
};
284 59ae540c bellard
285 09b26c5e bellard
static const uint8_t qemu_tablet_hid_report_descriptor[] = {
286 976f8eef balrog
    0x05, 0x01,                /* Usage Page (Generic Desktop) */
287 976f8eef balrog
    0x09, 0x01,                /* Usage (Pointer) */
288 976f8eef balrog
    0xa1, 0x01,                /* Collection (Application) */
289 976f8eef balrog
    0x09, 0x01,                /*   Usage (Pointer) */
290 976f8eef balrog
    0xa1, 0x00,                /*   Collection (Physical) */
291 976f8eef balrog
    0x05, 0x09,                /*     Usage Page (Button) */
292 976f8eef balrog
    0x19, 0x01,                /*     Usage Minimum (1) */
293 976f8eef balrog
    0x29, 0x03,                /*     Usage Maximum (3) */
294 976f8eef balrog
    0x15, 0x00,                /*     Logical Minimum (0) */
295 976f8eef balrog
    0x25, 0x01,                /*     Logical Maximum (1) */
296 976f8eef balrog
    0x95, 0x03,                /*     Report Count (3) */
297 976f8eef balrog
    0x75, 0x01,                /*     Report Size (1) */
298 976f8eef balrog
    0x81, 0x02,                /*     Input (Data, Variable, Absolute) */
299 976f8eef balrog
    0x95, 0x01,                /*     Report Count (1) */
300 976f8eef balrog
    0x75, 0x05,                /*     Report Size (5) */
301 976f8eef balrog
    0x81, 0x01,                /*     Input (Constant) */
302 976f8eef balrog
    0x05, 0x01,                /*     Usage Page (Generic Desktop) */
303 976f8eef balrog
    0x09, 0x30,                /*     Usage (X) */
304 976f8eef balrog
    0x09, 0x31,                /*     Usage (Y) */
305 976f8eef balrog
    0x15, 0x00,                /*     Logical Minimum (0) */
306 de5c2d0a balrog
    0x26, 0xff, 0x7f,        /*     Logical Maximum (0x7fff) */
307 976f8eef balrog
    0x35, 0x00,                /*     Physical Minimum (0) */
308 de5c2d0a balrog
    0x46, 0xff, 0x7f,        /*     Physical Maximum (0x7fff) */
309 976f8eef balrog
    0x75, 0x10,                /*     Report Size (16) */
310 976f8eef balrog
    0x95, 0x02,                /*     Report Count (2) */
311 976f8eef balrog
    0x81, 0x02,                /*     Input (Data, Variable, Absolute) */
312 976f8eef balrog
    0x05, 0x01,                /*     Usage Page (Generic Desktop) */
313 976f8eef balrog
    0x09, 0x38,                /*     Usage (Wheel) */
314 976f8eef balrog
    0x15, 0x81,                /*     Logical Minimum (-0x7f) */
315 976f8eef balrog
    0x25, 0x7f,                /*     Logical Maximum (0x7f) */
316 976f8eef balrog
    0x35, 0x00,                /*     Physical Minimum (same as logical) */
317 976f8eef balrog
    0x45, 0x00,                /*     Physical Maximum (same as logical) */
318 976f8eef balrog
    0x75, 0x08,                /*     Report Size (8) */
319 976f8eef balrog
    0x95, 0x01,                /*     Report Count (1) */
320 976f8eef balrog
    0x81, 0x06,                /*     Input (Data, Variable, Relative) */
321 976f8eef balrog
    0xc0,                /*   End Collection */
322 976f8eef balrog
    0xc0,                /* End Collection */
323 09b26c5e bellard
};
324 09b26c5e bellard
325 47b2d338 balrog
static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
326 47b2d338 balrog
    0x05, 0x01,                /* Usage Page (Generic Desktop) */
327 47b2d338 balrog
    0x09, 0x06,                /* Usage (Keyboard) */
328 47b2d338 balrog
    0xa1, 0x01,                /* Collection (Application) */
329 47b2d338 balrog
    0x75, 0x01,                /*   Report Size (1) */
330 47b2d338 balrog
    0x95, 0x08,                /*   Report Count (8) */
331 47b2d338 balrog
    0x05, 0x07,                /*   Usage Page (Key Codes) */
332 47b2d338 balrog
    0x19, 0xe0,                /*   Usage Minimum (224) */
333 47b2d338 balrog
    0x29, 0xe7,                /*   Usage Maximum (231) */
334 47b2d338 balrog
    0x15, 0x00,                /*   Logical Minimum (0) */
335 47b2d338 balrog
    0x25, 0x01,                /*   Logical Maximum (1) */
336 47b2d338 balrog
    0x81, 0x02,                /*   Input (Data, Variable, Absolute) */
337 47b2d338 balrog
    0x95, 0x01,                /*   Report Count (1) */
338 47b2d338 balrog
    0x75, 0x08,                /*   Report Size (8) */
339 47b2d338 balrog
    0x81, 0x01,                /*   Input (Constant) */
340 47b2d338 balrog
    0x95, 0x05,                /*   Report Count (5) */
341 47b2d338 balrog
    0x75, 0x01,                /*   Report Size (1) */
342 47b2d338 balrog
    0x05, 0x08,                /*   Usage Page (LEDs) */
343 47b2d338 balrog
    0x19, 0x01,                /*   Usage Minimum (1) */
344 47b2d338 balrog
    0x29, 0x05,                /*   Usage Maximum (5) */
345 47b2d338 balrog
    0x91, 0x02,                /*   Output (Data, Variable, Absolute) */
346 47b2d338 balrog
    0x95, 0x01,                /*   Report Count (1) */
347 47b2d338 balrog
    0x75, 0x03,                /*   Report Size (3) */
348 47b2d338 balrog
    0x91, 0x01,                /*   Output (Constant) */
349 47b2d338 balrog
    0x95, 0x06,                /*   Report Count (6) */
350 47b2d338 balrog
    0x75, 0x08,                /*   Report Size (8) */
351 47b2d338 balrog
    0x15, 0x00,                /*   Logical Minimum (0) */
352 47b2d338 balrog
    0x25, 0xff,                /*   Logical Maximum (255) */
353 47b2d338 balrog
    0x05, 0x07,                /*   Usage Page (Key Codes) */
354 47b2d338 balrog
    0x19, 0x00,                /*   Usage Minimum (0) */
355 47b2d338 balrog
    0x29, 0xff,                /*   Usage Maximum (255) */
356 47b2d338 balrog
    0x81, 0x00,                /*   Input (Data, Array) */
357 47b2d338 balrog
    0xc0,                /* End Collection */
358 47b2d338 balrog
};
359 47b2d338 balrog
360 8bde6805 Gerd Hoffmann
static void usb_hid_changed(HIDState *hs)
361 47e699dc balrog
{
362 8bde6805 Gerd Hoffmann
    USBHIDState *us = container_of(hs, USBHIDState, hid);
363 47e699dc balrog
364 7567b51f Gerd Hoffmann
    usb_wakeup(us->intr);
365 47e699dc balrog
}
366 47e699dc balrog
367 8bde6805 Gerd Hoffmann
static void usb_hid_handle_reset(USBDevice *dev)
368 47b2d338 balrog
{
369 0d878eec Gerd Hoffmann
    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
370 0d878eec Gerd Hoffmann
371 dcfda673 Gerd Hoffmann
    hid_reset(&us->hid);
372 68735b6c Kevin O'Connor
}
373 68735b6c Kevin O'Connor
374 007fd62f Hans de Goede
static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
375 007fd62f Hans de Goede
               int request, int value, int index, int length, uint8_t *data)
376 59ae540c bellard
{
377 0d878eec Gerd Hoffmann
    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
378 0d878eec Gerd Hoffmann
    HIDState *hs = &us->hid;
379 0e4e9695 Gerd Hoffmann
    int ret;
380 59ae540c bellard
381 007fd62f Hans de Goede
    ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
382 0e4e9695 Gerd Hoffmann
    if (ret >= 0) {
383 0e4e9695 Gerd Hoffmann
        return ret;
384 0e4e9695 Gerd Hoffmann
    }
385 59ae540c bellard
386 0e4e9695 Gerd Hoffmann
    ret = 0;
387 0d878eec Gerd Hoffmann
    switch (request) {
388 59ae540c bellard
        /* hid specific requests */
389 59ae540c bellard
    case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
390 0d878eec Gerd Hoffmann
        switch (value >> 8) {
391 59ae540c bellard
        case 0x22:
392 0d878eec Gerd Hoffmann
            if (hs->kind == HID_MOUSE) {
393 5fafdf24 ths
                memcpy(data, qemu_mouse_hid_report_descriptor,
394 09b26c5e bellard
                       sizeof(qemu_mouse_hid_report_descriptor));
395 09b26c5e bellard
                ret = sizeof(qemu_mouse_hid_report_descriptor);
396 0d878eec Gerd Hoffmann
            } else if (hs->kind == HID_TABLET) {
397 0d878eec Gerd Hoffmann
                memcpy(data, qemu_tablet_hid_report_descriptor,
398 09b26c5e bellard
                       sizeof(qemu_tablet_hid_report_descriptor));
399 09b26c5e bellard
                ret = sizeof(qemu_tablet_hid_report_descriptor);
400 0d878eec Gerd Hoffmann
            } else if (hs->kind == HID_KEYBOARD) {
401 5fafdf24 ths
                memcpy(data, qemu_keyboard_hid_report_descriptor,
402 47b2d338 balrog
                       sizeof(qemu_keyboard_hid_report_descriptor));
403 47b2d338 balrog
                ret = sizeof(qemu_keyboard_hid_report_descriptor);
404 47b2d338 balrog
            }
405 47b2d338 balrog
            break;
406 59ae540c bellard
        default:
407 59ae540c bellard
            goto fail;
408 59ae540c bellard
        }
409 59ae540c bellard
        break;
410 59ae540c bellard
    case GET_REPORT:
411 0d878eec Gerd Hoffmann
        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
412 0d878eec Gerd Hoffmann
            ret = hid_pointer_poll(hs, data, length);
413 0d878eec Gerd Hoffmann
        } else if (hs->kind == HID_KEYBOARD) {
414 0d878eec Gerd Hoffmann
            ret = hid_keyboard_poll(hs, data, length);
415 e7e73892 Gerd Hoffmann
        }
416 47b2d338 balrog
        break;
417 47b2d338 balrog
    case SET_REPORT:
418 0d878eec Gerd Hoffmann
        if (hs->kind == HID_KEYBOARD) {
419 0d878eec Gerd Hoffmann
            ret = hid_keyboard_write(hs, data, length);
420 0d878eec Gerd Hoffmann
        } else {
421 47b2d338 balrog
            goto fail;
422 0d878eec Gerd Hoffmann
        }
423 47b2d338 balrog
        break;
424 47b2d338 balrog
    case GET_PROTOCOL:
425 0d878eec Gerd Hoffmann
        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
426 47b2d338 balrog
            goto fail;
427 0d878eec Gerd Hoffmann
        }
428 47b2d338 balrog
        ret = 1;
429 b069d348 Gerd Hoffmann
        data[0] = hs->protocol;
430 47b2d338 balrog
        break;
431 47b2d338 balrog
    case SET_PROTOCOL:
432 0d878eec Gerd Hoffmann
        if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
433 47b2d338 balrog
            goto fail;
434 0d878eec Gerd Hoffmann
        }
435 47b2d338 balrog
        ret = 0;
436 b069d348 Gerd Hoffmann
        hs->protocol = value;
437 47b2d338 balrog
        break;
438 47b2d338 balrog
    case GET_IDLE:
439 47b2d338 balrog
        ret = 1;
440 b069d348 Gerd Hoffmann
        data[0] = hs->idle;
441 59ae540c bellard
        break;
442 59ae540c bellard
    case SET_IDLE:
443 b069d348 Gerd Hoffmann
        hs->idle = (uint8_t) (value >> 8);
444 b069d348 Gerd Hoffmann
        hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
445 21635e12 Gerd Hoffmann
        if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
446 21635e12 Gerd Hoffmann
            hid_pointer_activate(hs);
447 21635e12 Gerd Hoffmann
        }
448 59ae540c bellard
        ret = 0;
449 59ae540c bellard
        break;
450 59ae540c bellard
    default:
451 59ae540c bellard
    fail:
452 59ae540c bellard
        ret = USB_RET_STALL;
453 59ae540c bellard
        break;
454 59ae540c bellard
    }
455 59ae540c bellard
    return ret;
456 59ae540c bellard
}
457 59ae540c bellard
458 47b2d338 balrog
static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
459 59ae540c bellard
{
460 0d878eec Gerd Hoffmann
    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
461 0d878eec Gerd Hoffmann
    HIDState *hs = &us->hid;
462 4f4321c1 Gerd Hoffmann
    uint8_t buf[p->iov.size];
463 09b26c5e bellard
    int ret = 0;
464 59ae540c bellard
465 0d878eec Gerd Hoffmann
    switch (p->pid) {
466 59ae540c bellard
    case USB_TOKEN_IN:
467 079d0b7f Gerd Hoffmann
        if (p->ep->nr == 1) {
468 74475455 Paolo Bonzini
            int64_t curtime = qemu_get_clock_ns(vm_clock);
469 299aa1c6 Gerd Hoffmann
            if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
470 299aa1c6 Gerd Hoffmann
                hid_pointer_activate(hs);
471 299aa1c6 Gerd Hoffmann
            }
472 38931fa8 Gerd Hoffmann
            if (!hid_has_events(hs) &&
473 b069d348 Gerd Hoffmann
                (!hs->idle || hs->next_idle_clock - curtime > 0)) {
474 117b3ae6 pbrook
                return USB_RET_NAK;
475 13f8b97a Paolo Bonzini
            }
476 b069d348 Gerd Hoffmann
            hid_set_next_idle(hs, curtime);
477 0d878eec Gerd Hoffmann
            if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
478 0d878eec Gerd Hoffmann
                ret = hid_pointer_poll(hs, buf, p->iov.size);
479 0d878eec Gerd Hoffmann
            } else if (hs->kind == HID_KEYBOARD) {
480 0d878eec Gerd Hoffmann
                ret = hid_keyboard_poll(hs, buf, p->iov.size);
481 13f8b97a Paolo Bonzini
            }
482 4f4321c1 Gerd Hoffmann
            usb_packet_copy(p, buf, ret);
483 59ae540c bellard
        } else {
484 59ae540c bellard
            goto fail;
485 59ae540c bellard
        }
486 59ae540c bellard
        break;
487 59ae540c bellard
    case USB_TOKEN_OUT:
488 59ae540c bellard
    default:
489 59ae540c bellard
    fail:
490 59ae540c bellard
        ret = USB_RET_STALL;
491 59ae540c bellard
        break;
492 59ae540c bellard
    }
493 59ae540c bellard
    return ret;
494 59ae540c bellard
}
495 59ae540c bellard
496 8bde6805 Gerd Hoffmann
static void usb_hid_handle_destroy(USBDevice *dev)
497 09b26c5e bellard
{
498 0d878eec Gerd Hoffmann
    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
499 a980a065 Gerd Hoffmann
500 8bde6805 Gerd Hoffmann
    hid_free(&us->hid);
501 8bde6805 Gerd Hoffmann
}
502 8bde6805 Gerd Hoffmann
503 8bde6805 Gerd Hoffmann
static int usb_hid_initfn(USBDevice *dev, int kind)
504 8bde6805 Gerd Hoffmann
{
505 8bde6805 Gerd Hoffmann
    USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
506 8bde6805 Gerd Hoffmann
507 8bde6805 Gerd Hoffmann
    usb_desc_init(dev);
508 7567b51f Gerd Hoffmann
    us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
509 8bde6805 Gerd Hoffmann
    hid_init(&us->hid, kind, usb_hid_changed);
510 806b6024 Gerd Hoffmann
    return 0;
511 09b26c5e bellard
}
512 09b26c5e bellard
513 806b6024 Gerd Hoffmann
static int usb_tablet_initfn(USBDevice *dev)
514 59ae540c bellard
{
515 0d878eec Gerd Hoffmann
    return usb_hid_initfn(dev, HID_TABLET);
516 806b6024 Gerd Hoffmann
}
517 59ae540c bellard
518 806b6024 Gerd Hoffmann
static int usb_mouse_initfn(USBDevice *dev)
519 806b6024 Gerd Hoffmann
{
520 0d878eec Gerd Hoffmann
    return usb_hid_initfn(dev, HID_MOUSE);
521 806b6024 Gerd Hoffmann
}
522 59ae540c bellard
523 806b6024 Gerd Hoffmann
static int usb_keyboard_initfn(USBDevice *dev)
524 806b6024 Gerd Hoffmann
{
525 0d878eec Gerd Hoffmann
    return usb_hid_initfn(dev, HID_KEYBOARD);
526 806b6024 Gerd Hoffmann
}
527 59ae540c bellard
528 3a3286bf Gerd Hoffmann
static int usb_ptr_post_load(void *opaque, int version_id)
529 3a3286bf Gerd Hoffmann
{
530 3a3286bf Gerd Hoffmann
    USBHIDState *s = opaque;
531 3a3286bf Gerd Hoffmann
532 3a3286bf Gerd Hoffmann
    if (s->dev.remote_wakeup) {
533 3a3286bf Gerd Hoffmann
        hid_pointer_activate(&s->hid);
534 3a3286bf Gerd Hoffmann
    }
535 3a3286bf Gerd Hoffmann
    return 0;
536 3a3286bf Gerd Hoffmann
}
537 3a3286bf Gerd Hoffmann
538 ee59e6b3 Gerd Hoffmann
static const VMStateDescription vmstate_usb_ptr = {
539 ee59e6b3 Gerd Hoffmann
    .name = "usb-ptr",
540 ee59e6b3 Gerd Hoffmann
    .version_id = 1,
541 ee59e6b3 Gerd Hoffmann
    .minimum_version_id = 1,
542 3a3286bf Gerd Hoffmann
    .post_load = usb_ptr_post_load,
543 ee59e6b3 Gerd Hoffmann
    .fields = (VMStateField []) {
544 ee59e6b3 Gerd Hoffmann
        VMSTATE_USB_DEVICE(dev, USBHIDState),
545 1f42d222 Michael Walle
        VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
546 ee59e6b3 Gerd Hoffmann
        VMSTATE_END_OF_LIST()
547 ee59e6b3 Gerd Hoffmann
    }
548 ee59e6b3 Gerd Hoffmann
};
549 ee59e6b3 Gerd Hoffmann
550 ee59e6b3 Gerd Hoffmann
static const VMStateDescription vmstate_usb_kbd = {
551 ee59e6b3 Gerd Hoffmann
    .name = "usb-kbd",
552 ee59e6b3 Gerd Hoffmann
    .version_id = 1,
553 ee59e6b3 Gerd Hoffmann
    .minimum_version_id = 1,
554 ee59e6b3 Gerd Hoffmann
    .fields = (VMStateField []) {
555 ee59e6b3 Gerd Hoffmann
        VMSTATE_USB_DEVICE(dev, USBHIDState),
556 1f42d222 Michael Walle
        VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
557 ee59e6b3 Gerd Hoffmann
        VMSTATE_END_OF_LIST()
558 ee59e6b3 Gerd Hoffmann
    }
559 ee59e6b3 Gerd Hoffmann
};
560 ee59e6b3 Gerd Hoffmann
561 7f595609 Anthony Liguori
static void usb_hid_class_initfn(ObjectClass *klass, void *data)
562 62aed765 Anthony Liguori
{
563 62aed765 Anthony Liguori
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
564 62aed765 Anthony Liguori
565 62aed765 Anthony Liguori
    uc->handle_reset   = usb_hid_handle_reset;
566 62aed765 Anthony Liguori
    uc->handle_control = usb_hid_handle_control;
567 62aed765 Anthony Liguori
    uc->handle_data    = usb_hid_handle_data;
568 62aed765 Anthony Liguori
    uc->handle_destroy = usb_hid_handle_destroy;
569 62aed765 Anthony Liguori
}
570 62aed765 Anthony Liguori
571 7f595609 Anthony Liguori
static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
572 7f595609 Anthony Liguori
{
573 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
574 7f595609 Anthony Liguori
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
575 7f595609 Anthony Liguori
576 7f595609 Anthony Liguori
    usb_hid_class_initfn(klass, data);
577 7f595609 Anthony Liguori
    uc->init           = usb_tablet_initfn;
578 7f595609 Anthony Liguori
    uc->product_desc   = "QEMU USB Tablet";
579 7f595609 Anthony Liguori
    uc->usb_desc       = &desc_tablet;
580 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_usb_ptr;
581 7f595609 Anthony Liguori
}
582 7f595609 Anthony Liguori
583 39bffca2 Anthony Liguori
static TypeInfo usb_tablet_info = {
584 39bffca2 Anthony Liguori
    .name          = "usb-tablet",
585 39bffca2 Anthony Liguori
    .parent        = TYPE_USB_DEVICE,
586 39bffca2 Anthony Liguori
    .instance_size = sizeof(USBHIDState),
587 39bffca2 Anthony Liguori
    .class_init    = usb_tablet_class_initfn,
588 62aed765 Anthony Liguori
};
589 62aed765 Anthony Liguori
590 62aed765 Anthony Liguori
static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
591 62aed765 Anthony Liguori
{
592 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
593 62aed765 Anthony Liguori
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
594 62aed765 Anthony Liguori
595 7f595609 Anthony Liguori
    usb_hid_class_initfn(klass, data);
596 62aed765 Anthony Liguori
    uc->init           = usb_mouse_initfn;
597 62aed765 Anthony Liguori
    uc->product_desc   = "QEMU USB Mouse";
598 62aed765 Anthony Liguori
    uc->usb_desc       = &desc_mouse;
599 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_usb_ptr;
600 62aed765 Anthony Liguori
}
601 62aed765 Anthony Liguori
602 39bffca2 Anthony Liguori
static TypeInfo usb_mouse_info = {
603 39bffca2 Anthony Liguori
    .name          = "usb-mouse",
604 39bffca2 Anthony Liguori
    .parent        = TYPE_USB_DEVICE,
605 39bffca2 Anthony Liguori
    .instance_size = sizeof(USBHIDState),
606 39bffca2 Anthony Liguori
    .class_init    = usb_mouse_class_initfn,
607 62aed765 Anthony Liguori
};
608 62aed765 Anthony Liguori
609 62aed765 Anthony Liguori
static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
610 62aed765 Anthony Liguori
{
611 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
612 62aed765 Anthony Liguori
    USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
613 62aed765 Anthony Liguori
614 7f595609 Anthony Liguori
    usb_hid_class_initfn(klass, data);
615 62aed765 Anthony Liguori
    uc->init           = usb_keyboard_initfn;
616 62aed765 Anthony Liguori
    uc->product_desc   = "QEMU USB Keyboard";
617 62aed765 Anthony Liguori
    uc->usb_desc       = &desc_keyboard;
618 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_usb_kbd;
619 62aed765 Anthony Liguori
}
620 62aed765 Anthony Liguori
621 39bffca2 Anthony Liguori
static TypeInfo usb_keyboard_info = {
622 39bffca2 Anthony Liguori
    .name          = "usb-kbd",
623 39bffca2 Anthony Liguori
    .parent        = TYPE_USB_DEVICE,
624 39bffca2 Anthony Liguori
    .instance_size = sizeof(USBHIDState),
625 39bffca2 Anthony Liguori
    .class_init    = usb_keyboard_class_initfn,
626 806b6024 Gerd Hoffmann
};
627 806b6024 Gerd Hoffmann
628 83f7d43a Andreas Färber
static void usb_hid_register_types(void)
629 806b6024 Gerd Hoffmann
{
630 39bffca2 Anthony Liguori
    type_register_static(&usb_tablet_info);
631 ba02430f Anthony Liguori
    usb_legacy_register("usb-tablet", "tablet", NULL);
632 39bffca2 Anthony Liguori
    type_register_static(&usb_mouse_info);
633 ba02430f Anthony Liguori
    usb_legacy_register("usb-mouse", "mouse", NULL);
634 39bffca2 Anthony Liguori
    type_register_static(&usb_keyboard_info);
635 ba02430f Anthony Liguori
    usb_legacy_register("usb-kbd", "keyboard", NULL);
636 806b6024 Gerd Hoffmann
}
637 83f7d43a Andreas Färber
638 83f7d43a Andreas Färber
type_init(usb_hid_register_types)