]> Git Repo - qemu.git/blame - hw/usb/dev-hid.c
usb: call reset handler before updating state
[qemu.git] / hw / usb / dev-hid.c
CommitLineData
59ae540c
FB
1/*
2 * QEMU USB HID devices
5fafdf24 3 *
59ae540c 4 * Copyright (c) 2005 Fabrice Bellard
47b2d338 5 * Copyright (c) 2007 OpenMoko, Inc. ([email protected])
5fafdf24 6 *
59ae540c
FB
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 */
e532b2e0 25#include "qemu/osdep.h"
f1ae32a1 26#include "hw/hw.h"
28ecbaee 27#include "ui/console.h"
f1ae32a1 28#include "hw/usb.h"
463581a8 29#include "desc.h"
da34e65c 30#include "qapi/error.h"
1de7afc9 31#include "qemu/timer.h"
0d09e41a 32#include "hw/input/hid.h"
59ae540c
FB
33
34/* HID interface requests */
35#define GET_REPORT 0xa101
36#define GET_IDLE 0xa102
37#define GET_PROTOCOL 0xa103
47b2d338 38#define SET_REPORT 0x2109
59ae540c
FB
39#define SET_IDLE 0x210a
40#define SET_PROTOCOL 0x210b
41
47b2d338
AZ
42/* HID descriptor types */
43#define USB_DT_HID 0x21
44#define USB_DT_REPORT 0x22
45#define USB_DT_PHY 0x23
46
0d878eec
GH
47typedef struct USBHIDState {
48 USBDevice dev;
7567b51f 49 USBEndpoint *intr;
0d878eec 50 HIDState hid;
427e3aa1 51 uint32_t usb_version;
f85d2831
GH
52 char *display;
53 uint32_t head;
47b2d338
AZ
54} USBHIDState;
55
f5669129
GA
56#define TYPE_USB_HID "usb-hid"
57#define USB_HID(obj) OBJECT_CHECK(USBHIDState, (obj), TYPE_USB_HID)
58
0e4e9695
GH
59enum {
60 STR_MANUFACTURER = 1,
61 STR_PRODUCT_MOUSE,
62 STR_PRODUCT_TABLET,
63 STR_PRODUCT_KEYBOARD,
b63e1050 64 STR_SERIAL_COMPAT,
0e4e9695
GH
65 STR_CONFIG_MOUSE,
66 STR_CONFIG_TABLET,
67 STR_CONFIG_KEYBOARD,
b63e1050
GH
68 STR_SERIAL_MOUSE,
69 STR_SERIAL_TABLET,
70 STR_SERIAL_KEYBOARD,
59ae540c
FB
71};
72
0e4e9695 73static const USBDescStrings desc_strings = {
93bfef4c 74 [STR_MANUFACTURER] = "QEMU",
0e4e9695
GH
75 [STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
76 [STR_PRODUCT_TABLET] = "QEMU USB Tablet",
77 [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
b63e1050 78 [STR_SERIAL_COMPAT] = "42",
0e4e9695
GH
79 [STR_CONFIG_MOUSE] = "HID Mouse",
80 [STR_CONFIG_TABLET] = "HID Tablet",
81 [STR_CONFIG_KEYBOARD] = "HID Keyboard",
b63e1050
GH
82 [STR_SERIAL_MOUSE] = "89126",
83 [STR_SERIAL_TABLET] = "28754",
84 [STR_SERIAL_KEYBOARD] = "68284",
09b26c5e
FB
85};
86
0e4e9695
GH
87static const USBDescIface desc_iface_mouse = {
88 .bInterfaceNumber = 0,
89 .bNumEndpoints = 1,
90 .bInterfaceClass = USB_CLASS_HID,
91 .bInterfaceSubClass = 0x01, /* boot */
92 .bInterfaceProtocol = 0x02,
93 .ndesc = 1,
94 .descs = (USBDescOther[]) {
95 {
96 /* HID descriptor */
97 .data = (uint8_t[]) {
98 0x09, /* u8 bLength */
99 USB_DT_HID, /* u8 bDescriptorType */
100 0x01, 0x00, /* u16 HID_class */
101 0x00, /* u8 country_code */
102 0x01, /* u8 num_descriptors */
103 USB_DT_REPORT, /* u8 type: Report */
104 52, 0, /* u16 len */
105 },
106 },
107 },
108 .eps = (USBDescEndpoint[]) {
109 {
110 .bEndpointAddress = USB_DIR_IN | 0x01,
111 .bmAttributes = USB_ENDPOINT_XFER_INT,
112 .wMaxPacketSize = 4,
113 .bInterval = 0x0a,
114 },
115 },
59ae540c
FB
116};
117
58e4fee2
JV
118static const USBDescIface desc_iface_mouse2 = {
119 .bInterfaceNumber = 0,
120 .bNumEndpoints = 1,
121 .bInterfaceClass = USB_CLASS_HID,
122 .bInterfaceSubClass = 0x01, /* boot */
123 .bInterfaceProtocol = 0x02,
124 .ndesc = 1,
125 .descs = (USBDescOther[]) {
126 {
127 /* HID descriptor */
128 .data = (uint8_t[]) {
129 0x09, /* u8 bLength */
130 USB_DT_HID, /* u8 bDescriptorType */
131 0x01, 0x00, /* u16 HID_class */
132 0x00, /* u8 country_code */
133 0x01, /* u8 num_descriptors */
134 USB_DT_REPORT, /* u8 type: Report */
135 52, 0, /* u16 len */
136 },
137 },
138 },
139 .eps = (USBDescEndpoint[]) {
140 {
141 .bEndpointAddress = USB_DIR_IN | 0x01,
142 .bmAttributes = USB_ENDPOINT_XFER_INT,
143 .wMaxPacketSize = 4,
144 .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
145 },
146 },
147};
148
0e4e9695
GH
149static const USBDescIface desc_iface_tablet = {
150 .bInterfaceNumber = 0,
151 .bNumEndpoints = 1,
152 .bInterfaceClass = USB_CLASS_HID,
0cd089e9 153 .bInterfaceProtocol = 0x00,
0e4e9695
GH
154 .ndesc = 1,
155 .descs = (USBDescOther[]) {
156 {
157 /* HID descriptor */
158 .data = (uint8_t[]) {
159 0x09, /* u8 bLength */
160 USB_DT_HID, /* u8 bDescriptorType */
161 0x01, 0x00, /* u16 HID_class */
162 0x00, /* u8 country_code */
163 0x01, /* u8 num_descriptors */
164 USB_DT_REPORT, /* u8 type: Report */
165 74, 0, /* u16 len */
166 },
167 },
168 },
169 .eps = (USBDescEndpoint[]) {
170 {
171 .bEndpointAddress = USB_DIR_IN | 0x01,
172 .bmAttributes = USB_ENDPOINT_XFER_INT,
173 .wMaxPacketSize = 8,
174 .bInterval = 0x0a,
175 },
176 },
177};
178
427e3aa1
HG
179static const USBDescIface desc_iface_tablet2 = {
180 .bInterfaceNumber = 0,
181 .bNumEndpoints = 1,
182 .bInterfaceClass = USB_CLASS_HID,
0cd089e9 183 .bInterfaceProtocol = 0x00,
427e3aa1
HG
184 .ndesc = 1,
185 .descs = (USBDescOther[]) {
186 {
187 /* HID descriptor */
188 .data = (uint8_t[]) {
189 0x09, /* u8 bLength */
190 USB_DT_HID, /* u8 bDescriptorType */
191 0x01, 0x00, /* u16 HID_class */
192 0x00, /* u8 country_code */
193 0x01, /* u8 num_descriptors */
194 USB_DT_REPORT, /* u8 type: Report */
195 74, 0, /* u16 len */
196 },
197 },
198 },
199 .eps = (USBDescEndpoint[]) {
200 {
201 .bEndpointAddress = USB_DIR_IN | 0x01,
202 .bmAttributes = USB_ENDPOINT_XFER_INT,
203 .wMaxPacketSize = 8,
204 .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
205 },
206 },
207};
208
0e4e9695
GH
209static const USBDescIface desc_iface_keyboard = {
210 .bInterfaceNumber = 0,
211 .bNumEndpoints = 1,
212 .bInterfaceClass = USB_CLASS_HID,
213 .bInterfaceSubClass = 0x01, /* boot */
214 .bInterfaceProtocol = 0x01, /* keyboard */
215 .ndesc = 1,
216 .descs = (USBDescOther[]) {
217 {
218 /* HID descriptor */
219 .data = (uint8_t[]) {
220 0x09, /* u8 bLength */
221 USB_DT_HID, /* u8 bDescriptorType */
222 0x11, 0x01, /* u16 HID_class */
223 0x00, /* u8 country_code */
224 0x01, /* u8 num_descriptors */
225 USB_DT_REPORT, /* u8 type: Report */
226 0x3f, 0, /* u16 len */
227 },
228 },
229 },
230 .eps = (USBDescEndpoint[]) {
231 {
232 .bEndpointAddress = USB_DIR_IN | 0x01,
233 .bmAttributes = USB_ENDPOINT_XFER_INT,
234 .wMaxPacketSize = 8,
235 .bInterval = 0x0a,
236 },
237 },
238};
239
b13ce076
JV
240static const USBDescIface desc_iface_keyboard2 = {
241 .bInterfaceNumber = 0,
242 .bNumEndpoints = 1,
243 .bInterfaceClass = USB_CLASS_HID,
244 .bInterfaceSubClass = 0x01, /* boot */
245 .bInterfaceProtocol = 0x01, /* keyboard */
246 .ndesc = 1,
247 .descs = (USBDescOther[]) {
248 {
249 /* HID descriptor */
250 .data = (uint8_t[]) {
251 0x09, /* u8 bLength */
252 USB_DT_HID, /* u8 bDescriptorType */
253 0x11, 0x01, /* u16 HID_class */
254 0x00, /* u8 country_code */
255 0x01, /* u8 num_descriptors */
256 USB_DT_REPORT, /* u8 type: Report */
257 0x3f, 0, /* u16 len */
258 },
259 },
260 },
261 .eps = (USBDescEndpoint[]) {
262 {
263 .bEndpointAddress = USB_DIR_IN | 0x01,
264 .bmAttributes = USB_ENDPOINT_XFER_INT,
265 .wMaxPacketSize = 8,
266 .bInterval = 7, /* 2 ^ (8-1) * 125 usecs = 8 ms */
267 },
268 },
269};
270
0e4e9695
GH
271static const USBDescDevice desc_device_mouse = {
272 .bcdUSB = 0x0100,
273 .bMaxPacketSize0 = 8,
274 .bNumConfigurations = 1,
275 .confs = (USBDescConfig[]) {
276 {
277 .bNumInterfaces = 1,
278 .bConfigurationValue = 1,
279 .iConfiguration = STR_CONFIG_MOUSE,
bd93976a 280 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
0e4e9695 281 .bMaxPower = 50,
add75088 282 .nif = 1,
0e4e9695
GH
283 .ifs = &desc_iface_mouse,
284 },
285 },
286};
287
58e4fee2
JV
288static const USBDescDevice desc_device_mouse2 = {
289 .bcdUSB = 0x0200,
290 .bMaxPacketSize0 = 64,
291 .bNumConfigurations = 1,
292 .confs = (USBDescConfig[]) {
293 {
294 .bNumInterfaces = 1,
295 .bConfigurationValue = 1,
296 .iConfiguration = STR_CONFIG_MOUSE,
297 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
298 .bMaxPower = 50,
299 .nif = 1,
300 .ifs = &desc_iface_mouse2,
301 },
302 },
303};
304
0e4e9695
GH
305static const USBDescDevice desc_device_tablet = {
306 .bcdUSB = 0x0100,
307 .bMaxPacketSize0 = 8,
308 .bNumConfigurations = 1,
309 .confs = (USBDescConfig[]) {
310 {
311 .bNumInterfaces = 1,
312 .bConfigurationValue = 1,
313 .iConfiguration = STR_CONFIG_TABLET,
bd93976a 314 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
0e4e9695 315 .bMaxPower = 50,
add75088 316 .nif = 1,
0e4e9695
GH
317 .ifs = &desc_iface_tablet,
318 },
319 },
320};
321
427e3aa1
HG
322static const USBDescDevice desc_device_tablet2 = {
323 .bcdUSB = 0x0200,
324 .bMaxPacketSize0 = 64,
325 .bNumConfigurations = 1,
326 .confs = (USBDescConfig[]) {
327 {
328 .bNumInterfaces = 1,
329 .bConfigurationValue = 1,
330 .iConfiguration = STR_CONFIG_TABLET,
bd93976a 331 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
427e3aa1
HG
332 .bMaxPower = 50,
333 .nif = 1,
334 .ifs = &desc_iface_tablet2,
335 },
336 },
337};
338
0e4e9695
GH
339static const USBDescDevice desc_device_keyboard = {
340 .bcdUSB = 0x0100,
341 .bMaxPacketSize0 = 8,
342 .bNumConfigurations = 1,
343 .confs = (USBDescConfig[]) {
344 {
345 .bNumInterfaces = 1,
346 .bConfigurationValue = 1,
347 .iConfiguration = STR_CONFIG_KEYBOARD,
bd93976a 348 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
0e4e9695 349 .bMaxPower = 50,
add75088 350 .nif = 1,
0e4e9695
GH
351 .ifs = &desc_iface_keyboard,
352 },
353 },
354};
355
b13ce076
JV
356static const USBDescDevice desc_device_keyboard2 = {
357 .bcdUSB = 0x0200,
358 .bMaxPacketSize0 = 64,
359 .bNumConfigurations = 1,
360 .confs = (USBDescConfig[]) {
361 {
362 .bNumInterfaces = 1,
363 .bConfigurationValue = 1,
364 .iConfiguration = STR_CONFIG_KEYBOARD,
365 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
366 .bMaxPower = 50,
367 .nif = 1,
368 .ifs = &desc_iface_keyboard2,
369 },
370 },
371};
372
88678fbd
GH
373static const USBDescMSOS desc_msos_suspend = {
374 .SelectiveSuspendEnabled = true,
375};
376
0e4e9695
GH
377static const USBDesc desc_mouse = {
378 .id = {
379 .idVendor = 0x0627,
380 .idProduct = 0x0001,
381 .bcdDevice = 0,
382 .iManufacturer = STR_MANUFACTURER,
383 .iProduct = STR_PRODUCT_MOUSE,
b63e1050 384 .iSerialNumber = STR_SERIAL_MOUSE,
0e4e9695
GH
385 },
386 .full = &desc_device_mouse,
387 .str = desc_strings,
88678fbd 388 .msos = &desc_msos_suspend,
0e4e9695
GH
389};
390
58e4fee2
JV
391static const USBDesc desc_mouse2 = {
392 .id = {
393 .idVendor = 0x0627,
394 .idProduct = 0x0001,
395 .bcdDevice = 0,
396 .iManufacturer = STR_MANUFACTURER,
397 .iProduct = STR_PRODUCT_MOUSE,
b63e1050 398 .iSerialNumber = STR_SERIAL_MOUSE,
58e4fee2
JV
399 },
400 .full = &desc_device_mouse,
401 .high = &desc_device_mouse2,
402 .str = desc_strings,
403 .msos = &desc_msos_suspend,
404};
405
0e4e9695
GH
406static const USBDesc desc_tablet = {
407 .id = {
408 .idVendor = 0x0627,
409 .idProduct = 0x0001,
410 .bcdDevice = 0,
411 .iManufacturer = STR_MANUFACTURER,
412 .iProduct = STR_PRODUCT_TABLET,
b63e1050 413 .iSerialNumber = STR_SERIAL_TABLET,
0e4e9695
GH
414 },
415 .full = &desc_device_tablet,
416 .str = desc_strings,
88678fbd 417 .msos = &desc_msos_suspend,
0e4e9695
GH
418};
419
427e3aa1
HG
420static const USBDesc desc_tablet2 = {
421 .id = {
422 .idVendor = 0x0627,
423 .idProduct = 0x0001,
424 .bcdDevice = 0,
425 .iManufacturer = STR_MANUFACTURER,
426 .iProduct = STR_PRODUCT_TABLET,
b63e1050 427 .iSerialNumber = STR_SERIAL_TABLET,
427e3aa1
HG
428 },
429 .full = &desc_device_tablet,
430 .high = &desc_device_tablet2,
431 .str = desc_strings,
88678fbd 432 .msos = &desc_msos_suspend,
427e3aa1
HG
433};
434
0e4e9695
GH
435static const USBDesc desc_keyboard = {
436 .id = {
437 .idVendor = 0x0627,
438 .idProduct = 0x0001,
439 .bcdDevice = 0,
440 .iManufacturer = STR_MANUFACTURER,
441 .iProduct = STR_PRODUCT_KEYBOARD,
b63e1050 442 .iSerialNumber = STR_SERIAL_KEYBOARD,
0e4e9695
GH
443 },
444 .full = &desc_device_keyboard,
445 .str = desc_strings,
88678fbd 446 .msos = &desc_msos_suspend,
47b2d338
AZ
447};
448
b13ce076
JV
449static const USBDesc desc_keyboard2 = {
450 .id = {
451 .idVendor = 0x0627,
452 .idProduct = 0x0001,
453 .bcdDevice = 0,
454 .iManufacturer = STR_MANUFACTURER,
455 .iProduct = STR_PRODUCT_KEYBOARD,
b63e1050 456 .iSerialNumber = STR_SERIAL_KEYBOARD,
b13ce076
JV
457 },
458 .full = &desc_device_keyboard,
459 .high = &desc_device_keyboard2,
460 .str = desc_strings,
461 .msos = &desc_msos_suspend,
462};
463
59ae540c 464static const uint8_t qemu_mouse_hid_report_descriptor[] = {
976f8eef
AZ
465 0x05, 0x01, /* Usage Page (Generic Desktop) */
466 0x09, 0x02, /* Usage (Mouse) */
467 0xa1, 0x01, /* Collection (Application) */
468 0x09, 0x01, /* Usage (Pointer) */
469 0xa1, 0x00, /* Collection (Physical) */
470 0x05, 0x09, /* Usage Page (Button) */
471 0x19, 0x01, /* Usage Minimum (1) */
472 0x29, 0x03, /* Usage Maximum (3) */
473 0x15, 0x00, /* Logical Minimum (0) */
474 0x25, 0x01, /* Logical Maximum (1) */
475 0x95, 0x03, /* Report Count (3) */
476 0x75, 0x01, /* Report Size (1) */
477 0x81, 0x02, /* Input (Data, Variable, Absolute) */
478 0x95, 0x01, /* Report Count (1) */
479 0x75, 0x05, /* Report Size (5) */
480 0x81, 0x01, /* Input (Constant) */
481 0x05, 0x01, /* Usage Page (Generic Desktop) */
482 0x09, 0x30, /* Usage (X) */
483 0x09, 0x31, /* Usage (Y) */
484 0x09, 0x38, /* Usage (Wheel) */
485 0x15, 0x81, /* Logical Minimum (-0x7f) */
486 0x25, 0x7f, /* Logical Maximum (0x7f) */
487 0x75, 0x08, /* Report Size (8) */
488 0x95, 0x03, /* Report Count (3) */
489 0x81, 0x06, /* Input (Data, Variable, Relative) */
490 0xc0, /* End Collection */
491 0xc0, /* End Collection */
59ae540c
FB
492};
493
09b26c5e 494static const uint8_t qemu_tablet_hid_report_descriptor[] = {
976f8eef 495 0x05, 0x01, /* Usage Page (Generic Desktop) */
0cd089e9 496 0x09, 0x02, /* Usage (Mouse) */
976f8eef
AZ
497 0xa1, 0x01, /* Collection (Application) */
498 0x09, 0x01, /* Usage (Pointer) */
499 0xa1, 0x00, /* Collection (Physical) */
500 0x05, 0x09, /* Usage Page (Button) */
501 0x19, 0x01, /* Usage Minimum (1) */
502 0x29, 0x03, /* Usage Maximum (3) */
503 0x15, 0x00, /* Logical Minimum (0) */
504 0x25, 0x01, /* Logical Maximum (1) */
505 0x95, 0x03, /* Report Count (3) */
506 0x75, 0x01, /* Report Size (1) */
507 0x81, 0x02, /* Input (Data, Variable, Absolute) */
508 0x95, 0x01, /* Report Count (1) */
509 0x75, 0x05, /* Report Size (5) */
510 0x81, 0x01, /* Input (Constant) */
511 0x05, 0x01, /* Usage Page (Generic Desktop) */
512 0x09, 0x30, /* Usage (X) */
513 0x09, 0x31, /* Usage (Y) */
514 0x15, 0x00, /* Logical Minimum (0) */
de5c2d0a 515 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */
976f8eef 516 0x35, 0x00, /* Physical Minimum (0) */
de5c2d0a 517 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */
976f8eef
AZ
518 0x75, 0x10, /* Report Size (16) */
519 0x95, 0x02, /* Report Count (2) */
520 0x81, 0x02, /* Input (Data, Variable, Absolute) */
521 0x05, 0x01, /* Usage Page (Generic Desktop) */
522 0x09, 0x38, /* Usage (Wheel) */
523 0x15, 0x81, /* Logical Minimum (-0x7f) */
524 0x25, 0x7f, /* Logical Maximum (0x7f) */
525 0x35, 0x00, /* Physical Minimum (same as logical) */
526 0x45, 0x00, /* Physical Maximum (same as logical) */
527 0x75, 0x08, /* Report Size (8) */
528 0x95, 0x01, /* Report Count (1) */
529 0x81, 0x06, /* Input (Data, Variable, Relative) */
530 0xc0, /* End Collection */
531 0xc0, /* End Collection */
09b26c5e
FB
532};
533
47b2d338
AZ
534static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
535 0x05, 0x01, /* Usage Page (Generic Desktop) */
536 0x09, 0x06, /* Usage (Keyboard) */
537 0xa1, 0x01, /* Collection (Application) */
538 0x75, 0x01, /* Report Size (1) */
539 0x95, 0x08, /* Report Count (8) */
540 0x05, 0x07, /* Usage Page (Key Codes) */
541 0x19, 0xe0, /* Usage Minimum (224) */
542 0x29, 0xe7, /* Usage Maximum (231) */
543 0x15, 0x00, /* Logical Minimum (0) */
544 0x25, 0x01, /* Logical Maximum (1) */
545 0x81, 0x02, /* Input (Data, Variable, Absolute) */
546 0x95, 0x01, /* Report Count (1) */
547 0x75, 0x08, /* Report Size (8) */
548 0x81, 0x01, /* Input (Constant) */
549 0x95, 0x05, /* Report Count (5) */
550 0x75, 0x01, /* Report Size (1) */
551 0x05, 0x08, /* Usage Page (LEDs) */
552 0x19, 0x01, /* Usage Minimum (1) */
553 0x29, 0x05, /* Usage Maximum (5) */
554 0x91, 0x02, /* Output (Data, Variable, Absolute) */
555 0x95, 0x01, /* Report Count (1) */
556 0x75, 0x03, /* Report Size (3) */
557 0x91, 0x01, /* Output (Constant) */
558 0x95, 0x06, /* Report Count (6) */
559 0x75, 0x08, /* Report Size (8) */
560 0x15, 0x00, /* Logical Minimum (0) */
561 0x25, 0xff, /* Logical Maximum (255) */
562 0x05, 0x07, /* Usage Page (Key Codes) */
563 0x19, 0x00, /* Usage Minimum (0) */
564 0x29, 0xff, /* Usage Maximum (255) */
565 0x81, 0x00, /* Input (Data, Array) */
566 0xc0, /* End Collection */
567};
568
8bde6805 569static void usb_hid_changed(HIDState *hs)
47e699dc 570{
8bde6805 571 USBHIDState *us = container_of(hs, USBHIDState, hid);
47e699dc 572
8550a02d 573 usb_wakeup(us->intr, 0);
47e699dc
AZ
574}
575
8bde6805 576static void usb_hid_handle_reset(USBDevice *dev)
47b2d338 577{
f5669129 578 USBHIDState *us = USB_HID(dev);
0d878eec 579
dcfda673 580 hid_reset(&us->hid);
68735b6c
KC
581}
582
9a77a0f5 583static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
007fd62f 584 int request, int value, int index, int length, uint8_t *data)
59ae540c 585{
f5669129 586 USBHIDState *us = USB_HID(dev);
0d878eec 587 HIDState *hs = &us->hid;
0e4e9695 588 int ret;
59ae540c 589
007fd62f 590 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
0e4e9695 591 if (ret >= 0) {
9a77a0f5 592 return;
0e4e9695 593 }
59ae540c 594
0d878eec 595 switch (request) {
59ae540c
FB
596 /* hid specific requests */
597 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
0d878eec 598 switch (value >> 8) {
59ae540c 599 case 0x22:
0d878eec 600 if (hs->kind == HID_MOUSE) {
7d37435b
PB
601 memcpy(data, qemu_mouse_hid_report_descriptor,
602 sizeof(qemu_mouse_hid_report_descriptor));
9a77a0f5 603 p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
0d878eec
GH
604 } else if (hs->kind == HID_TABLET) {
605 memcpy(data, qemu_tablet_hid_report_descriptor,
7d37435b 606 sizeof(qemu_tablet_hid_report_descriptor));
9a77a0f5 607 p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
0d878eec 608 } else if (hs->kind == HID_KEYBOARD) {
5fafdf24 609 memcpy(data, qemu_keyboard_hid_report_descriptor,
47b2d338 610 sizeof(qemu_keyboard_hid_report_descriptor));
9a77a0f5 611 p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
47b2d338
AZ
612 }
613 break;
59ae540c
FB
614 default:
615 goto fail;
616 }
617 break;
618 case GET_REPORT:
0d878eec 619 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
9a77a0f5 620 p->actual_length = hid_pointer_poll(hs, data, length);
0d878eec 621 } else if (hs->kind == HID_KEYBOARD) {
9a77a0f5 622 p->actual_length = hid_keyboard_poll(hs, data, length);
e7e73892 623 }
47b2d338
AZ
624 break;
625 case SET_REPORT:
0d878eec 626 if (hs->kind == HID_KEYBOARD) {
9a77a0f5 627 p->actual_length = hid_keyboard_write(hs, data, length);
0d878eec 628 } else {
47b2d338 629 goto fail;
0d878eec 630 }
47b2d338
AZ
631 break;
632 case GET_PROTOCOL:
0d878eec 633 if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
47b2d338 634 goto fail;
0d878eec 635 }
b069d348 636 data[0] = hs->protocol;
9a77a0f5 637 p->actual_length = 1;
47b2d338
AZ
638 break;
639 case SET_PROTOCOL:
0d878eec 640 if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
47b2d338 641 goto fail;
0d878eec 642 }
b069d348 643 hs->protocol = value;
47b2d338
AZ
644 break;
645 case GET_IDLE:
b069d348 646 data[0] = hs->idle;
9a77a0f5 647 p->actual_length = 1;
59ae540c
FB
648 break;
649 case SET_IDLE:
b069d348 650 hs->idle = (uint8_t) (value >> 8);
027c03f7 651 hid_set_next_idle(hs);
21635e12
GH
652 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
653 hid_pointer_activate(hs);
654 }
59ae540c
FB
655 break;
656 default:
657 fail:
9a77a0f5 658 p->status = USB_RET_STALL;
59ae540c
FB
659 break;
660 }
59ae540c
FB
661}
662
9a77a0f5 663static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
59ae540c 664{
f5669129 665 USBHIDState *us = USB_HID(dev);
0d878eec 666 HIDState *hs = &us->hid;
4f4321c1 667 uint8_t buf[p->iov.size];
9a77a0f5 668 int len = 0;
59ae540c 669
0d878eec 670 switch (p->pid) {
59ae540c 671 case USB_TOKEN_IN:
079d0b7f 672 if (p->ep->nr == 1) {
299aa1c6
GH
673 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
674 hid_pointer_activate(hs);
675 }
027c03f7 676 if (!hid_has_events(hs)) {
9a77a0f5
HG
677 p->status = USB_RET_NAK;
678 return;
13f8b97a 679 }
027c03f7 680 hid_set_next_idle(hs);
0d878eec 681 if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
9a77a0f5 682 len = hid_pointer_poll(hs, buf, p->iov.size);
0d878eec 683 } else if (hs->kind == HID_KEYBOARD) {
9a77a0f5 684 len = hid_keyboard_poll(hs, buf, p->iov.size);
13f8b97a 685 }
9a77a0f5 686 usb_packet_copy(p, buf, len);
59ae540c
FB
687 } else {
688 goto fail;
689 }
690 break;
691 case USB_TOKEN_OUT:
692 default:
693 fail:
9a77a0f5 694 p->status = USB_RET_STALL;
59ae540c
FB
695 break;
696 }
59ae540c
FB
697}
698
c4fe9700 699static void usb_hid_unrealize(USBDevice *dev, Error **errp)
09b26c5e 700{
f5669129 701 USBHIDState *us = USB_HID(dev);
a980a065 702
8bde6805
GH
703 hid_free(&us->hid);
704}
705
ff326ffa
JV
706static void usb_hid_initfn(USBDevice *dev, int kind,
707 const USBDesc *usb1, const USBDesc *usb2,
708 Error **errp)
8bde6805 709{
f5669129 710 USBHIDState *us = USB_HID(dev);
ff326ffa
JV
711 switch (us->usb_version) {
712 case 1:
713 dev->usb_desc = usb1;
714 break;
715 case 2:
716 dev->usb_desc = usb2;
717 break;
718 default:
719 dev->usb_desc = NULL;
720 }
721 if (!dev->usb_desc) {
722 error_setg(errp, "Invalid usb version %d for usb hid device",
723 us->usb_version);
724 return;
725 }
8bde6805 726
b63e1050 727 usb_desc_create_serial(dev);
8bde6805 728 usb_desc_init(dev);
7567b51f 729 us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
8bde6805 730 hid_init(&us->hid, kind, usb_hid_changed);
f85d2831
GH
731 if (us->display && us->hid.s) {
732 qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL);
733 }
09b26c5e
FB
734}
735
276b7ac8 736static void usb_tablet_realize(USBDevice *dev, Error **errp)
59ae540c 737{
427e3aa1 738
ff326ffa 739 usb_hid_initfn(dev, HID_TABLET, &desc_tablet, &desc_tablet2, errp);
806b6024 740}
59ae540c 741
276b7ac8 742static void usb_mouse_realize(USBDevice *dev, Error **errp)
806b6024 743{
58e4fee2 744 usb_hid_initfn(dev, HID_MOUSE, &desc_mouse, &desc_mouse2, errp);
806b6024 745}
59ae540c 746
276b7ac8 747static void usb_keyboard_realize(USBDevice *dev, Error **errp)
806b6024 748{
b13ce076 749 usb_hid_initfn(dev, HID_KEYBOARD, &desc_keyboard, &desc_keyboard2, errp);
806b6024 750}
59ae540c 751
3a3286bf
GH
752static int usb_ptr_post_load(void *opaque, int version_id)
753{
754 USBHIDState *s = opaque;
755
756 if (s->dev.remote_wakeup) {
757 hid_pointer_activate(&s->hid);
758 }
759 return 0;
760}
761
ee59e6b3
GH
762static const VMStateDescription vmstate_usb_ptr = {
763 .name = "usb-ptr",
764 .version_id = 1,
765 .minimum_version_id = 1,
3a3286bf 766 .post_load = usb_ptr_post_load,
6e3d652a 767 .fields = (VMStateField[]) {
ee59e6b3 768 VMSTATE_USB_DEVICE(dev, USBHIDState),
1f42d222 769 VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
ee59e6b3
GH
770 VMSTATE_END_OF_LIST()
771 }
772};
773
774static const VMStateDescription vmstate_usb_kbd = {
775 .name = "usb-kbd",
776 .version_id = 1,
777 .minimum_version_id = 1,
6e3d652a 778 .fields = (VMStateField[]) {
ee59e6b3 779 VMSTATE_USB_DEVICE(dev, USBHIDState),
1f42d222 780 VMSTATE_HID_KEYBOARD_DEVICE(hid, USBHIDState),
ee59e6b3
GH
781 VMSTATE_END_OF_LIST()
782 }
783};
784
7f595609 785static void usb_hid_class_initfn(ObjectClass *klass, void *data)
62aed765
AL
786{
787 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
788
62aed765
AL
789 uc->handle_reset = usb_hid_handle_reset;
790 uc->handle_control = usb_hid_handle_control;
791 uc->handle_data = usb_hid_handle_data;
c4fe9700 792 uc->unrealize = usb_hid_unrealize;
427e3aa1 793 uc->handle_attach = usb_desc_attach;
62aed765
AL
794}
795
f5669129
GA
796static const TypeInfo usb_hid_type_info = {
797 .name = TYPE_USB_HID,
798 .parent = TYPE_USB_DEVICE,
799 .instance_size = sizeof(USBHIDState),
800 .abstract = true,
801 .class_init = usb_hid_class_initfn,
802};
803
427e3aa1
HG
804static Property usb_tablet_properties[] = {
805 DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
f85d2831
GH
806 DEFINE_PROP_STRING("display", USBHIDState, display),
807 DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
427e3aa1
HG
808 DEFINE_PROP_END_OF_LIST(),
809};
810
7f595609
AL
811static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
812{
39bffca2 813 DeviceClass *dc = DEVICE_CLASS(klass);
7f595609
AL
814 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
815
276b7ac8 816 uc->realize = usb_tablet_realize;
7f595609 817 uc->product_desc = "QEMU USB Tablet";
39bffca2 818 dc->vmsd = &vmstate_usb_ptr;
427e3aa1 819 dc->props = usb_tablet_properties;
31efd2e8 820 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
7f595609
AL
821}
822
8c43a6f0 823static const TypeInfo usb_tablet_info = {
39bffca2 824 .name = "usb-tablet",
f5669129 825 .parent = TYPE_USB_HID,
39bffca2 826 .class_init = usb_tablet_class_initfn,
62aed765
AL
827};
828
58e4fee2
JV
829static Property usb_mouse_properties[] = {
830 DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
831 DEFINE_PROP_END_OF_LIST(),
832};
833
62aed765
AL
834static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
835{
39bffca2 836 DeviceClass *dc = DEVICE_CLASS(klass);
62aed765
AL
837 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
838
276b7ac8 839 uc->realize = usb_mouse_realize;
62aed765 840 uc->product_desc = "QEMU USB Mouse";
39bffca2 841 dc->vmsd = &vmstate_usb_ptr;
58e4fee2 842 dc->props = usb_mouse_properties;
125ee0ed 843 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
62aed765
AL
844}
845
8c43a6f0 846static const TypeInfo usb_mouse_info = {
39bffca2 847 .name = "usb-mouse",
f5669129 848 .parent = TYPE_USB_HID,
39bffca2 849 .class_init = usb_mouse_class_initfn,
62aed765
AL
850};
851
f85d2831 852static Property usb_keyboard_properties[] = {
b13ce076 853 DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
f85d2831
GH
854 DEFINE_PROP_STRING("display", USBHIDState, display),
855 DEFINE_PROP_END_OF_LIST(),
856};
857
62aed765
AL
858static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
859{
39bffca2 860 DeviceClass *dc = DEVICE_CLASS(klass);
62aed765
AL
861 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
862
276b7ac8 863 uc->realize = usb_keyboard_realize;
62aed765 864 uc->product_desc = "QEMU USB Keyboard";
39bffca2 865 dc->vmsd = &vmstate_usb_kbd;
f85d2831 866 dc->props = usb_keyboard_properties;
125ee0ed 867 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
62aed765
AL
868}
869
8c43a6f0 870static const TypeInfo usb_keyboard_info = {
39bffca2 871 .name = "usb-kbd",
f5669129 872 .parent = TYPE_USB_HID,
39bffca2 873 .class_init = usb_keyboard_class_initfn,
806b6024
GH
874};
875
83f7d43a 876static void usb_hid_register_types(void)
806b6024 877{
f5669129 878 type_register_static(&usb_hid_type_info);
39bffca2 879 type_register_static(&usb_tablet_info);
ba02430f 880 usb_legacy_register("usb-tablet", "tablet", NULL);
39bffca2 881 type_register_static(&usb_mouse_info);
ba02430f 882 usb_legacy_register("usb-mouse", "mouse", NULL);
39bffca2 883 type_register_static(&usb_keyboard_info);
ba02430f 884 usb_legacy_register("usb-kbd", "keyboard", NULL);
806b6024 885}
83f7d43a
AF
886
887type_init(usb_hid_register_types)
This page took 1.176482 seconds and 4 git commands to generate.