Merge remote branch 'kwolf/for-anthony' into staging
[qemu.git] / hw / usb-hid.c
blob90a2b49e1d76f202e99cf33942e67894cdd8f70f
1 /*
2 * QEMU USB HID devices
4 * Copyright (c) 2005 Fabrice Bellard
5 * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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.
25 #include "hw.h"
26 #include "console.h"
27 #include "usb.h"
28 #include "usb-desc.h"
29 #include "sysemu.h"
31 /* HID interface requests */
32 #define GET_REPORT 0xa101
33 #define GET_IDLE 0xa102
34 #define GET_PROTOCOL 0xa103
35 #define SET_REPORT 0x2109
36 #define SET_IDLE 0x210a
37 #define SET_PROTOCOL 0x210b
39 /* HID descriptor types */
40 #define USB_DT_HID 0x21
41 #define USB_DT_REPORT 0x22
42 #define USB_DT_PHY 0x23
44 #define USB_MOUSE 1
45 #define USB_TABLET 2
46 #define USB_KEYBOARD 3
48 typedef struct USBMouseState {
49 int dx, dy, dz, buttons_state;
50 int x, y;
51 int mouse_grabbed;
52 QEMUPutMouseEntry *eh_entry;
53 } USBMouseState;
55 typedef struct USBKeyboardState {
56 uint16_t modifiers;
57 uint8_t leds;
58 uint8_t key[16];
59 int keys;
60 } USBKeyboardState;
62 typedef struct USBHIDState {
63 USBDevice dev;
64 union {
65 USBMouseState ptr;
66 USBKeyboardState kbd;
68 int kind;
69 int protocol;
70 uint8_t idle;
71 int64_t next_idle_clock;
72 int changed;
73 void *datain_opaque;
74 void (*datain)(void *);
75 } USBHIDState;
77 enum {
78 STR_MANUFACTURER = 1,
79 STR_PRODUCT_MOUSE,
80 STR_PRODUCT_TABLET,
81 STR_PRODUCT_KEYBOARD,
82 STR_SERIALNUMBER,
83 STR_CONFIG_MOUSE,
84 STR_CONFIG_TABLET,
85 STR_CONFIG_KEYBOARD,
88 static const USBDescStrings desc_strings = {
89 [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
90 [STR_PRODUCT_MOUSE] = "QEMU USB Mouse",
91 [STR_PRODUCT_TABLET] = "QEMU USB Tablet",
92 [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
93 [STR_SERIALNUMBER] = "42", /* == remote wakeup works */
94 [STR_CONFIG_MOUSE] = "HID Mouse",
95 [STR_CONFIG_TABLET] = "HID Tablet",
96 [STR_CONFIG_KEYBOARD] = "HID Keyboard",
99 static const USBDescIface desc_iface_mouse = {
100 .bInterfaceNumber = 0,
101 .bNumEndpoints = 1,
102 .bInterfaceClass = USB_CLASS_HID,
103 .bInterfaceSubClass = 0x01, /* boot */
104 .bInterfaceProtocol = 0x02,
105 .ndesc = 1,
106 .descs = (USBDescOther[]) {
108 /* HID descriptor */
109 .data = (uint8_t[]) {
110 0x09, /* u8 bLength */
111 USB_DT_HID, /* u8 bDescriptorType */
112 0x01, 0x00, /* u16 HID_class */
113 0x00, /* u8 country_code */
114 0x01, /* u8 num_descriptors */
115 USB_DT_REPORT, /* u8 type: Report */
116 52, 0, /* u16 len */
120 .eps = (USBDescEndpoint[]) {
122 .bEndpointAddress = USB_DIR_IN | 0x01,
123 .bmAttributes = USB_ENDPOINT_XFER_INT,
124 .wMaxPacketSize = 4,
125 .bInterval = 0x0a,
130 static const USBDescIface desc_iface_tablet = {
131 .bInterfaceNumber = 0,
132 .bNumEndpoints = 1,
133 .bInterfaceClass = USB_CLASS_HID,
134 .bInterfaceSubClass = 0x01, /* boot */
135 .bInterfaceProtocol = 0x02,
136 .ndesc = 1,
137 .descs = (USBDescOther[]) {
139 /* HID descriptor */
140 .data = (uint8_t[]) {
141 0x09, /* u8 bLength */
142 USB_DT_HID, /* u8 bDescriptorType */
143 0x01, 0x00, /* u16 HID_class */
144 0x00, /* u8 country_code */
145 0x01, /* u8 num_descriptors */
146 USB_DT_REPORT, /* u8 type: Report */
147 74, 0, /* u16 len */
151 .eps = (USBDescEndpoint[]) {
153 .bEndpointAddress = USB_DIR_IN | 0x01,
154 .bmAttributes = USB_ENDPOINT_XFER_INT,
155 .wMaxPacketSize = 8,
156 .bInterval = 0x0a,
161 static const USBDescIface desc_iface_keyboard = {
162 .bInterfaceNumber = 0,
163 .bNumEndpoints = 1,
164 .bInterfaceClass = USB_CLASS_HID,
165 .bInterfaceSubClass = 0x01, /* boot */
166 .bInterfaceProtocol = 0x01, /* keyboard */
167 .ndesc = 1,
168 .descs = (USBDescOther[]) {
170 /* HID descriptor */
171 .data = (uint8_t[]) {
172 0x09, /* u8 bLength */
173 USB_DT_HID, /* u8 bDescriptorType */
174 0x11, 0x01, /* u16 HID_class */
175 0x00, /* u8 country_code */
176 0x01, /* u8 num_descriptors */
177 USB_DT_REPORT, /* u8 type: Report */
178 0x3f, 0, /* u16 len */
182 .eps = (USBDescEndpoint[]) {
184 .bEndpointAddress = USB_DIR_IN | 0x01,
185 .bmAttributes = USB_ENDPOINT_XFER_INT,
186 .wMaxPacketSize = 8,
187 .bInterval = 0x0a,
192 static const USBDescDevice desc_device_mouse = {
193 .bcdUSB = 0x0100,
194 .bMaxPacketSize0 = 8,
195 .bNumConfigurations = 1,
196 .confs = (USBDescConfig[]) {
198 .bNumInterfaces = 1,
199 .bConfigurationValue = 1,
200 .iConfiguration = STR_CONFIG_MOUSE,
201 .bmAttributes = 0xa0,
202 .bMaxPower = 50,
203 .ifs = &desc_iface_mouse,
208 static const USBDescDevice desc_device_tablet = {
209 .bcdUSB = 0x0100,
210 .bMaxPacketSize0 = 8,
211 .bNumConfigurations = 1,
212 .confs = (USBDescConfig[]) {
214 .bNumInterfaces = 1,
215 .bConfigurationValue = 1,
216 .iConfiguration = STR_CONFIG_TABLET,
217 .bmAttributes = 0xa0,
218 .bMaxPower = 50,
219 .ifs = &desc_iface_tablet,
224 static const USBDescDevice desc_device_keyboard = {
225 .bcdUSB = 0x0100,
226 .bMaxPacketSize0 = 8,
227 .bNumConfigurations = 1,
228 .confs = (USBDescConfig[]) {
230 .bNumInterfaces = 1,
231 .bConfigurationValue = 1,
232 .iConfiguration = STR_CONFIG_KEYBOARD,
233 .bmAttributes = 0xa0,
234 .bMaxPower = 50,
235 .ifs = &desc_iface_keyboard,
240 static const USBDesc desc_mouse = {
241 .id = {
242 .idVendor = 0x0627,
243 .idProduct = 0x0001,
244 .bcdDevice = 0,
245 .iManufacturer = STR_MANUFACTURER,
246 .iProduct = STR_PRODUCT_MOUSE,
247 .iSerialNumber = STR_SERIALNUMBER,
249 .full = &desc_device_mouse,
250 .str = desc_strings,
253 static const USBDesc desc_tablet = {
254 .id = {
255 .idVendor = 0x0627,
256 .idProduct = 0x0001,
257 .bcdDevice = 0,
258 .iManufacturer = STR_MANUFACTURER,
259 .iProduct = STR_PRODUCT_TABLET,
260 .iSerialNumber = STR_SERIALNUMBER,
262 .full = &desc_device_tablet,
263 .str = desc_strings,
266 static const USBDesc desc_keyboard = {
267 .id = {
268 .idVendor = 0x0627,
269 .idProduct = 0x0001,
270 .bcdDevice = 0,
271 .iManufacturer = STR_MANUFACTURER,
272 .iProduct = STR_PRODUCT_KEYBOARD,
273 .iSerialNumber = STR_SERIALNUMBER,
275 .full = &desc_device_keyboard,
276 .str = desc_strings,
279 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
280 0x05, 0x01, /* Usage Page (Generic Desktop) */
281 0x09, 0x02, /* Usage (Mouse) */
282 0xa1, 0x01, /* Collection (Application) */
283 0x09, 0x01, /* Usage (Pointer) */
284 0xa1, 0x00, /* Collection (Physical) */
285 0x05, 0x09, /* Usage Page (Button) */
286 0x19, 0x01, /* Usage Minimum (1) */
287 0x29, 0x03, /* Usage Maximum (3) */
288 0x15, 0x00, /* Logical Minimum (0) */
289 0x25, 0x01, /* Logical Maximum (1) */
290 0x95, 0x03, /* Report Count (3) */
291 0x75, 0x01, /* Report Size (1) */
292 0x81, 0x02, /* Input (Data, Variable, Absolute) */
293 0x95, 0x01, /* Report Count (1) */
294 0x75, 0x05, /* Report Size (5) */
295 0x81, 0x01, /* Input (Constant) */
296 0x05, 0x01, /* Usage Page (Generic Desktop) */
297 0x09, 0x30, /* Usage (X) */
298 0x09, 0x31, /* Usage (Y) */
299 0x09, 0x38, /* Usage (Wheel) */
300 0x15, 0x81, /* Logical Minimum (-0x7f) */
301 0x25, 0x7f, /* Logical Maximum (0x7f) */
302 0x75, 0x08, /* Report Size (8) */
303 0x95, 0x03, /* Report Count (3) */
304 0x81, 0x06, /* Input (Data, Variable, Relative) */
305 0xc0, /* End Collection */
306 0xc0, /* End Collection */
309 static const uint8_t qemu_tablet_hid_report_descriptor[] = {
310 0x05, 0x01, /* Usage Page (Generic Desktop) */
311 0x09, 0x01, /* Usage (Pointer) */
312 0xa1, 0x01, /* Collection (Application) */
313 0x09, 0x01, /* Usage (Pointer) */
314 0xa1, 0x00, /* Collection (Physical) */
315 0x05, 0x09, /* Usage Page (Button) */
316 0x19, 0x01, /* Usage Minimum (1) */
317 0x29, 0x03, /* Usage Maximum (3) */
318 0x15, 0x00, /* Logical Minimum (0) */
319 0x25, 0x01, /* Logical Maximum (1) */
320 0x95, 0x03, /* Report Count (3) */
321 0x75, 0x01, /* Report Size (1) */
322 0x81, 0x02, /* Input (Data, Variable, Absolute) */
323 0x95, 0x01, /* Report Count (1) */
324 0x75, 0x05, /* Report Size (5) */
325 0x81, 0x01, /* Input (Constant) */
326 0x05, 0x01, /* Usage Page (Generic Desktop) */
327 0x09, 0x30, /* Usage (X) */
328 0x09, 0x31, /* Usage (Y) */
329 0x15, 0x00, /* Logical Minimum (0) */
330 0x26, 0xff, 0x7f, /* Logical Maximum (0x7fff) */
331 0x35, 0x00, /* Physical Minimum (0) */
332 0x46, 0xff, 0x7f, /* Physical Maximum (0x7fff) */
333 0x75, 0x10, /* Report Size (16) */
334 0x95, 0x02, /* Report Count (2) */
335 0x81, 0x02, /* Input (Data, Variable, Absolute) */
336 0x05, 0x01, /* Usage Page (Generic Desktop) */
337 0x09, 0x38, /* Usage (Wheel) */
338 0x15, 0x81, /* Logical Minimum (-0x7f) */
339 0x25, 0x7f, /* Logical Maximum (0x7f) */
340 0x35, 0x00, /* Physical Minimum (same as logical) */
341 0x45, 0x00, /* Physical Maximum (same as logical) */
342 0x75, 0x08, /* Report Size (8) */
343 0x95, 0x01, /* Report Count (1) */
344 0x81, 0x06, /* Input (Data, Variable, Relative) */
345 0xc0, /* End Collection */
346 0xc0, /* End Collection */
349 static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
350 0x05, 0x01, /* Usage Page (Generic Desktop) */
351 0x09, 0x06, /* Usage (Keyboard) */
352 0xa1, 0x01, /* Collection (Application) */
353 0x75, 0x01, /* Report Size (1) */
354 0x95, 0x08, /* Report Count (8) */
355 0x05, 0x07, /* Usage Page (Key Codes) */
356 0x19, 0xe0, /* Usage Minimum (224) */
357 0x29, 0xe7, /* Usage Maximum (231) */
358 0x15, 0x00, /* Logical Minimum (0) */
359 0x25, 0x01, /* Logical Maximum (1) */
360 0x81, 0x02, /* Input (Data, Variable, Absolute) */
361 0x95, 0x01, /* Report Count (1) */
362 0x75, 0x08, /* Report Size (8) */
363 0x81, 0x01, /* Input (Constant) */
364 0x95, 0x05, /* Report Count (5) */
365 0x75, 0x01, /* Report Size (1) */
366 0x05, 0x08, /* Usage Page (LEDs) */
367 0x19, 0x01, /* Usage Minimum (1) */
368 0x29, 0x05, /* Usage Maximum (5) */
369 0x91, 0x02, /* Output (Data, Variable, Absolute) */
370 0x95, 0x01, /* Report Count (1) */
371 0x75, 0x03, /* Report Size (3) */
372 0x91, 0x01, /* Output (Constant) */
373 0x95, 0x06, /* Report Count (6) */
374 0x75, 0x08, /* Report Size (8) */
375 0x15, 0x00, /* Logical Minimum (0) */
376 0x25, 0xff, /* Logical Maximum (255) */
377 0x05, 0x07, /* Usage Page (Key Codes) */
378 0x19, 0x00, /* Usage Minimum (0) */
379 0x29, 0xff, /* Usage Maximum (255) */
380 0x81, 0x00, /* Input (Data, Array) */
381 0xc0, /* End Collection */
384 #define USB_HID_USAGE_ERROR_ROLLOVER 0x01
385 #define USB_HID_USAGE_POSTFAIL 0x02
386 #define USB_HID_USAGE_ERROR_UNDEFINED 0x03
388 /* Indices are QEMU keycodes, values are from HID Usage Table. Indices
389 * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
390 static const uint8_t usb_hid_usage_keys[0x100] = {
391 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
392 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
393 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
394 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
395 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
396 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
397 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
398 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
399 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
400 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
401 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
402 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
403 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
404 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
405 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
408 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
412 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
413 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
414 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
415 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
417 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
418 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
419 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
422 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
426 static void usb_hid_changed(USBHIDState *hs)
428 hs->changed = 1;
430 if (hs->datain)
431 hs->datain(hs->datain_opaque);
433 usb_wakeup(&hs->dev);
436 static void usb_mouse_event(void *opaque,
437 int dx1, int dy1, int dz1, int buttons_state)
439 USBHIDState *hs = opaque;
440 USBMouseState *s = &hs->ptr;
442 s->dx += dx1;
443 s->dy += dy1;
444 s->dz += dz1;
445 s->buttons_state = buttons_state;
447 usb_hid_changed(hs);
450 static void usb_tablet_event(void *opaque,
451 int x, int y, int dz, int buttons_state)
453 USBHIDState *hs = opaque;
454 USBMouseState *s = &hs->ptr;
456 s->x = x;
457 s->y = y;
458 s->dz += dz;
459 s->buttons_state = buttons_state;
461 usb_hid_changed(hs);
464 static void usb_keyboard_event(void *opaque, int keycode)
466 USBHIDState *hs = opaque;
467 USBKeyboardState *s = &hs->kbd;
468 uint8_t hid_code, key;
469 int i;
471 key = keycode & 0x7f;
472 hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
473 s->modifiers &= ~(1 << 8);
475 switch (hid_code) {
476 case 0x00:
477 return;
479 case 0xe0:
480 if (s->modifiers & (1 << 9)) {
481 s->modifiers ^= 3 << 8;
482 usb_hid_changed(hs);
483 return;
485 case 0xe1 ... 0xe7:
486 if (keycode & (1 << 7)) {
487 s->modifiers &= ~(1 << (hid_code & 0x0f));
488 usb_hid_changed(hs);
489 return;
491 case 0xe8 ... 0xef:
492 s->modifiers |= 1 << (hid_code & 0x0f);
493 usb_hid_changed(hs);
494 return;
497 if (keycode & (1 << 7)) {
498 for (i = s->keys - 1; i >= 0; i --)
499 if (s->key[i] == hid_code) {
500 s->key[i] = s->key[-- s->keys];
501 s->key[s->keys] = 0x00;
502 usb_hid_changed(hs);
503 break;
505 if (i < 0)
506 return;
507 } else {
508 for (i = s->keys - 1; i >= 0; i --)
509 if (s->key[i] == hid_code)
510 break;
511 if (i < 0) {
512 if (s->keys < sizeof(s->key))
513 s->key[s->keys ++] = hid_code;
514 } else
515 return;
518 usb_hid_changed(hs);
521 static inline int int_clamp(int val, int vmin, int vmax)
523 if (val < vmin)
524 return vmin;
525 else if (val > vmax)
526 return vmax;
527 else
528 return val;
531 static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len)
533 int dx, dy, dz, b, l;
534 USBMouseState *s = &hs->ptr;
536 if (!s->mouse_grabbed) {
537 qemu_activate_mouse_event_handler(s->eh_entry);
538 s->mouse_grabbed = 1;
541 dx = int_clamp(s->dx, -127, 127);
542 dy = int_clamp(s->dy, -127, 127);
543 dz = int_clamp(s->dz, -127, 127);
545 s->dx -= dx;
546 s->dy -= dy;
547 s->dz -= dz;
549 /* Appears we have to invert the wheel direction */
550 dz = 0 - dz;
552 b = 0;
553 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
554 b |= 0x01;
555 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
556 b |= 0x02;
557 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
558 b |= 0x04;
560 l = 0;
561 if (len > l)
562 buf[l ++] = b;
563 if (len > l)
564 buf[l ++] = dx;
565 if (len > l)
566 buf[l ++] = dy;
567 if (len > l)
568 buf[l ++] = dz;
569 return l;
572 static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len)
574 int dz, b, l;
575 USBMouseState *s = &hs->ptr;
577 if (!s->mouse_grabbed) {
578 qemu_activate_mouse_event_handler(s->eh_entry);
579 s->mouse_grabbed = 1;
582 dz = int_clamp(s->dz, -127, 127);
583 s->dz -= dz;
585 /* Appears we have to invert the wheel direction */
586 dz = 0 - dz;
587 b = 0;
588 if (s->buttons_state & MOUSE_EVENT_LBUTTON)
589 b |= 0x01;
590 if (s->buttons_state & MOUSE_EVENT_RBUTTON)
591 b |= 0x02;
592 if (s->buttons_state & MOUSE_EVENT_MBUTTON)
593 b |= 0x04;
595 buf[0] = b;
596 buf[1] = s->x & 0xff;
597 buf[2] = s->x >> 8;
598 buf[3] = s->y & 0xff;
599 buf[4] = s->y >> 8;
600 buf[5] = dz;
601 l = 6;
603 return l;
606 static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len)
608 if (len < 2)
609 return 0;
611 buf[0] = s->modifiers & 0xff;
612 buf[1] = 0;
613 if (s->keys > 6)
614 memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
615 else
616 memcpy(buf + 2, s->key, MIN(8, len) - 2);
618 return MIN(8, len);
621 static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
623 if (len > 0) {
624 int ledstate = 0;
625 /* 0x01: Num Lock LED
626 * 0x02: Caps Lock LED
627 * 0x04: Scroll Lock LED
628 * 0x08: Compose LED
629 * 0x10: Kana LED */
630 s->leds = buf[0];
631 if (s->leds & 0x04)
632 ledstate |= QEMU_SCROLL_LOCK_LED;
633 if (s->leds & 0x01)
634 ledstate |= QEMU_NUM_LOCK_LED;
635 if (s->leds & 0x02)
636 ledstate |= QEMU_CAPS_LOCK_LED;
637 kbd_put_ledstate(ledstate);
639 return 0;
642 static void usb_mouse_handle_reset(USBDevice *dev)
644 USBHIDState *s = (USBHIDState *)dev;
646 s->ptr.dx = 0;
647 s->ptr.dy = 0;
648 s->ptr.dz = 0;
649 s->ptr.x = 0;
650 s->ptr.y = 0;
651 s->ptr.buttons_state = 0;
652 s->protocol = 1;
655 static void usb_keyboard_handle_reset(USBDevice *dev)
657 USBHIDState *s = (USBHIDState *)dev;
659 qemu_add_kbd_event_handler(usb_keyboard_event, s);
660 s->protocol = 1;
663 static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
665 s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
668 static int usb_hid_handle_control(USBDevice *dev, int request, int value,
669 int index, int length, uint8_t *data)
671 USBHIDState *s = (USBHIDState *)dev;
672 int ret;
674 ret = usb_desc_handle_control(dev, request, value, index, length, data);
675 if (ret >= 0) {
676 return ret;
679 ret = 0;
680 switch(request) {
681 case DeviceRequest | USB_REQ_GET_INTERFACE:
682 data[0] = 0;
683 ret = 1;
684 break;
685 case DeviceOutRequest | USB_REQ_SET_INTERFACE:
686 ret = 0;
687 break;
688 /* hid specific requests */
689 case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
690 switch(value >> 8) {
691 case 0x22:
692 if (s->kind == USB_MOUSE) {
693 memcpy(data, qemu_mouse_hid_report_descriptor,
694 sizeof(qemu_mouse_hid_report_descriptor));
695 ret = sizeof(qemu_mouse_hid_report_descriptor);
696 } else if (s->kind == USB_TABLET) {
697 memcpy(data, qemu_tablet_hid_report_descriptor,
698 sizeof(qemu_tablet_hid_report_descriptor));
699 ret = sizeof(qemu_tablet_hid_report_descriptor);
700 } else if (s->kind == USB_KEYBOARD) {
701 memcpy(data, qemu_keyboard_hid_report_descriptor,
702 sizeof(qemu_keyboard_hid_report_descriptor));
703 ret = sizeof(qemu_keyboard_hid_report_descriptor);
705 break;
706 default:
707 goto fail;
709 break;
710 case GET_REPORT:
711 if (s->kind == USB_MOUSE)
712 ret = usb_mouse_poll(s, data, length);
713 else if (s->kind == USB_TABLET)
714 ret = usb_tablet_poll(s, data, length);
715 else if (s->kind == USB_KEYBOARD)
716 ret = usb_keyboard_poll(&s->kbd, data, length);
717 break;
718 case SET_REPORT:
719 if (s->kind == USB_KEYBOARD)
720 ret = usb_keyboard_write(&s->kbd, data, length);
721 else
722 goto fail;
723 break;
724 case GET_PROTOCOL:
725 if (s->kind != USB_KEYBOARD)
726 goto fail;
727 ret = 1;
728 data[0] = s->protocol;
729 break;
730 case SET_PROTOCOL:
731 if (s->kind != USB_KEYBOARD)
732 goto fail;
733 ret = 0;
734 s->protocol = value;
735 break;
736 case GET_IDLE:
737 ret = 1;
738 data[0] = s->idle;
739 break;
740 case SET_IDLE:
741 s->idle = (uint8_t) (value >> 8);
742 usb_hid_set_next_idle(s, qemu_get_clock(vm_clock));
743 ret = 0;
744 break;
745 default:
746 fail:
747 ret = USB_RET_STALL;
748 break;
750 return ret;
753 static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
755 USBHIDState *s = (USBHIDState *)dev;
756 int ret = 0;
758 switch(p->pid) {
759 case USB_TOKEN_IN:
760 if (p->devep == 1) {
761 int64_t curtime = qemu_get_clock(vm_clock);
762 if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
763 return USB_RET_NAK;
764 usb_hid_set_next_idle(s, curtime);
765 s->changed = 0;
766 if (s->kind == USB_MOUSE)
767 ret = usb_mouse_poll(s, p->data, p->len);
768 else if (s->kind == USB_TABLET)
769 ret = usb_tablet_poll(s, p->data, p->len);
770 else if (s->kind == USB_KEYBOARD)
771 ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
772 } else {
773 goto fail;
775 break;
776 case USB_TOKEN_OUT:
777 default:
778 fail:
779 ret = USB_RET_STALL;
780 break;
782 return ret;
785 static void usb_hid_handle_destroy(USBDevice *dev)
787 USBHIDState *s = (USBHIDState *)dev;
789 switch(s->kind) {
790 case USB_KEYBOARD:
791 qemu_remove_kbd_event_handler();
792 break;
793 default:
794 qemu_remove_mouse_event_handler(s->ptr.eh_entry);
798 static int usb_hid_initfn(USBDevice *dev, int kind)
800 USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
802 usb_desc_init(dev);
803 s->kind = kind;
805 if (s->kind == USB_MOUSE) {
806 s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s,
807 0, "QEMU USB Mouse");
808 } else if (s->kind == USB_TABLET) {
809 s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s,
810 1, "QEMU USB Tablet");
813 /* Force poll routine to be run and grab input the first time. */
814 s->changed = 1;
815 return 0;
818 static int usb_tablet_initfn(USBDevice *dev)
820 return usb_hid_initfn(dev, USB_TABLET);
823 static int usb_mouse_initfn(USBDevice *dev)
825 return usb_hid_initfn(dev, USB_MOUSE);
828 static int usb_keyboard_initfn(USBDevice *dev)
830 return usb_hid_initfn(dev, USB_KEYBOARD);
833 void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
835 USBHIDState *s = (USBHIDState *)dev;
837 s->datain_opaque = opaque;
838 s->datain = datain;
841 static struct USBDeviceInfo hid_info[] = {
843 .product_desc = "QEMU USB Tablet",
844 .qdev.name = "usb-tablet",
845 .usbdevice_name = "tablet",
846 .qdev.size = sizeof(USBHIDState),
847 .usb_desc = &desc_tablet,
848 .init = usb_tablet_initfn,
849 .handle_packet = usb_generic_handle_packet,
850 .handle_reset = usb_mouse_handle_reset,
851 .handle_control = usb_hid_handle_control,
852 .handle_data = usb_hid_handle_data,
853 .handle_destroy = usb_hid_handle_destroy,
855 .product_desc = "QEMU USB Mouse",
856 .qdev.name = "usb-mouse",
857 .usbdevice_name = "mouse",
858 .qdev.size = sizeof(USBHIDState),
859 .usb_desc = &desc_mouse,
860 .init = usb_mouse_initfn,
861 .handle_packet = usb_generic_handle_packet,
862 .handle_reset = usb_mouse_handle_reset,
863 .handle_control = usb_hid_handle_control,
864 .handle_data = usb_hid_handle_data,
865 .handle_destroy = usb_hid_handle_destroy,
867 .product_desc = "QEMU USB Keyboard",
868 .qdev.name = "usb-kbd",
869 .usbdevice_name = "keyboard",
870 .qdev.size = sizeof(USBHIDState),
871 .usb_desc = &desc_keyboard,
872 .init = usb_keyboard_initfn,
873 .handle_packet = usb_generic_handle_packet,
874 .handle_reset = usb_keyboard_handle_reset,
875 .handle_control = usb_hid_handle_control,
876 .handle_data = usb_hid_handle_data,
877 .handle_destroy = usb_hid_handle_destroy,
879 /* end of list */
883 static void usb_hid_register_devices(void)
885 usb_qdev_register_many(hid_info);
887 device_init(usb_hid_register_devices)