Commit 47b2d338d982c9e26b2af6b51c1cc0da7cbd2b60
1 parent
07cf0ba0
Add USB HID keyboard.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2996 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
350 additions
and
46 deletions
hw/usb-hid.c
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | * QEMU USB HID devices |
3 | 3 | * |
4 | 4 | * Copyright (c) 2005 Fabrice Bellard |
5 | + * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com) | |
5 | 6 | * |
6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | 8 | * of this software and associated documentation files (the "Software"), to deal |
... | ... | @@ -27,21 +28,44 @@ |
27 | 28 | #define GET_REPORT 0xa101 |
28 | 29 | #define GET_IDLE 0xa102 |
29 | 30 | #define GET_PROTOCOL 0xa103 |
31 | +#define SET_REPORT 0x2109 | |
30 | 32 | #define SET_IDLE 0x210a |
31 | 33 | #define SET_PROTOCOL 0x210b |
32 | 34 | |
33 | -#define USB_MOUSE 1 | |
34 | -#define USB_TABLET 2 | |
35 | +/* HID descriptor types */ | |
36 | +#define USB_DT_HID 0x21 | |
37 | +#define USB_DT_REPORT 0x22 | |
38 | +#define USB_DT_PHY 0x23 | |
39 | + | |
40 | +#define USB_MOUSE 1 | |
41 | +#define USB_TABLET 2 | |
42 | +#define USB_KEYBOARD 3 | |
35 | 43 | |
36 | 44 | typedef struct USBMouseState { |
37 | - USBDevice dev; | |
38 | 45 | int dx, dy, dz, buttons_state; |
39 | 46 | int x, y; |
40 | - int kind; | |
41 | 47 | int mouse_grabbed; |
42 | 48 | QEMUPutMouseEntry *eh_entry; |
43 | 49 | } USBMouseState; |
44 | 50 | |
51 | +typedef struct USBKeyboardState { | |
52 | + uint16_t modifiers; | |
53 | + uint8_t leds; | |
54 | + uint8_t key[16]; | |
55 | + int keys; | |
56 | +} USBKeyboardState; | |
57 | + | |
58 | +typedef struct USBHIDState { | |
59 | + USBDevice dev; | |
60 | + union { | |
61 | + USBMouseState ptr; | |
62 | + USBKeyboardState kbd; | |
63 | + }; | |
64 | + int kind; | |
65 | + int protocol; | |
66 | + int idle; | |
67 | +} USBHIDState; | |
68 | + | |
45 | 69 | /* mostly the same values as the Bochs USB Mouse device */ |
46 | 70 | static const uint8_t qemu_mouse_dev_descriptor[] = { |
47 | 71 | 0x12, /* u8 bLength; */ |
... | ... | @@ -98,7 +122,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = { |
98 | 122 | 0x03, /* u8 if_bInterfaceClass; */ |
99 | 123 | 0x01, /* u8 if_bInterfaceSubClass; */ |
100 | 124 | 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ |
101 | - 0x05, /* u8 if_iInterface; */ | |
125 | + 0x07, /* u8 if_iInterface; */ | |
102 | 126 | |
103 | 127 | /* HID descriptor */ |
104 | 128 | 0x09, /* u8 bLength; */ |
... | ... | @@ -125,7 +149,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { |
125 | 149 | 0x22, 0x00, /* u16 wTotalLength; */ |
126 | 150 | 0x01, /* u8 bNumInterfaces; (1) */ |
127 | 151 | 0x01, /* u8 bConfigurationValue; */ |
128 | - 0x04, /* u8 iConfiguration; */ | |
152 | + 0x05, /* u8 iConfiguration; */ | |
129 | 153 | 0xa0, /* u8 bmAttributes; |
130 | 154 | Bit 7: must be set, |
131 | 155 | 6: Self-powered, |
... | ... | @@ -153,7 +177,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { |
153 | 177 | 0x03, /* u8 if_bInterfaceClass; */ |
154 | 178 | 0x01, /* u8 if_bInterfaceSubClass; */ |
155 | 179 | 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ |
156 | - 0x05, /* u8 if_iInterface; */ | |
180 | + 0x07, /* u8 if_iInterface; */ | |
157 | 181 | |
158 | 182 | /* HID descriptor */ |
159 | 183 | 0x09, /* u8 bLength; */ |
... | ... | @@ -173,6 +197,61 @@ static const uint8_t qemu_tablet_config_descriptor[] = { |
173 | 197 | 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ |
174 | 198 | }; |
175 | 199 | |
200 | +static const uint8_t qemu_keyboard_config_descriptor[] = { | |
201 | + /* one configuration */ | |
202 | + 0x09, /* u8 bLength; */ | |
203 | + USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ | |
204 | + 0x22, 0x00, /* u16 wTotalLength; */ | |
205 | + 0x01, /* u8 bNumInterfaces; (1) */ | |
206 | + 0x01, /* u8 bConfigurationValue; */ | |
207 | + 0x06, /* u8 iConfiguration; */ | |
208 | + 0xa0, /* u8 bmAttributes; | |
209 | + Bit 7: must be set, | |
210 | + 6: Self-powered, | |
211 | + 5: Remote wakeup, | |
212 | + 4..0: resvd */ | |
213 | + 0x32, /* u8 MaxPower; */ | |
214 | + | |
215 | + /* USB 1.1: | |
216 | + * USB 2.0, single TT organization (mandatory): | |
217 | + * one interface, protocol 0 | |
218 | + * | |
219 | + * USB 2.0, multiple TT organization (optional): | |
220 | + * two interfaces, protocols 1 (like single TT) | |
221 | + * and 2 (multiple TT mode) ... config is | |
222 | + * sometimes settable | |
223 | + * NOT IMPLEMENTED | |
224 | + */ | |
225 | + | |
226 | + /* one interface */ | |
227 | + 0x09, /* u8 if_bLength; */ | |
228 | + USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ | |
229 | + 0x00, /* u8 if_bInterfaceNumber; */ | |
230 | + 0x00, /* u8 if_bAlternateSetting; */ | |
231 | + 0x01, /* u8 if_bNumEndpoints; */ | |
232 | + 0x03, /* u8 if_bInterfaceClass; HID */ | |
233 | + 0x01, /* u8 if_bInterfaceSubClass; Boot */ | |
234 | + 0x01, /* u8 if_bInterfaceProtocol; Keyboard */ | |
235 | + 0x07, /* u8 if_iInterface; */ | |
236 | + | |
237 | + /* HID descriptor */ | |
238 | + 0x09, /* u8 bLength; */ | |
239 | + USB_DT_HID, /* u8 bDescriptorType; */ | |
240 | + 0x11, 0x01, /* u16 HID_class */ | |
241 | + 0x00, /* u8 country_code */ | |
242 | + 0x01, /* u8 num_descriptors */ | |
243 | + USB_DT_REPORT, /* u8 type; Report */ | |
244 | + 0x3f, 0x00, /* u16 len */ | |
245 | + | |
246 | + /* one endpoint (status change endpoint) */ | |
247 | + 0x07, /* u8 ep_bLength; */ | |
248 | + USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */ | |
249 | + USB_DIR_IN | 0x01, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ | |
250 | + 0x03, /* u8 ep_bmAttributes; Interrupt */ | |
251 | + 0x08, 0x00, /* u16 ep_wMaxPacketSize; */ | |
252 | + 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ | |
253 | +}; | |
254 | + | |
176 | 255 | static const uint8_t qemu_mouse_hid_report_descriptor[] = { |
177 | 256 | 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, |
178 | 257 | 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, |
... | ... | @@ -223,6 +302,83 @@ static const uint8_t qemu_tablet_hid_report_descriptor[] = { |
223 | 302 | 0xC0, /* End Collection */ |
224 | 303 | }; |
225 | 304 | |
305 | +static const uint8_t qemu_keyboard_hid_report_descriptor[] = { | |
306 | + 0x05, 0x01, /* Usage Page (Generic Desktop) */ | |
307 | + 0x09, 0x06, /* Usage (Keyboard) */ | |
308 | + 0xa1, 0x01, /* Collection (Application) */ | |
309 | + 0x75, 0x01, /* Report Size (1) */ | |
310 | + 0x95, 0x08, /* Report Count (8) */ | |
311 | + 0x05, 0x07, /* Usage Page (Key Codes) */ | |
312 | + 0x19, 0xe0, /* Usage Minimum (224) */ | |
313 | + 0x29, 0xe7, /* Usage Maximum (231) */ | |
314 | + 0x15, 0x00, /* Logical Minimum (0) */ | |
315 | + 0x25, 0x01, /* Logical Maximum (1) */ | |
316 | + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ | |
317 | + 0x95, 0x01, /* Report Count (1) */ | |
318 | + 0x75, 0x08, /* Report Size (8) */ | |
319 | + 0x81, 0x01, /* Input (Constant) */ | |
320 | + 0x95, 0x05, /* Report Count (5) */ | |
321 | + 0x75, 0x01, /* Report Size (1) */ | |
322 | + 0x05, 0x08, /* Usage Page (LEDs) */ | |
323 | + 0x19, 0x01, /* Usage Minimum (1) */ | |
324 | + 0x29, 0x05, /* Usage Maximum (5) */ | |
325 | + 0x91, 0x02, /* Output (Data, Variable, Absolute) */ | |
326 | + 0x95, 0x01, /* Report Count (1) */ | |
327 | + 0x75, 0x03, /* Report Size (3) */ | |
328 | + 0x91, 0x01, /* Output (Constant) */ | |
329 | + 0x95, 0x06, /* Report Count (6) */ | |
330 | + 0x75, 0x08, /* Report Size (8) */ | |
331 | + 0x15, 0x00, /* Logical Minimum (0) */ | |
332 | + 0x25, 0xff, /* Logical Maximum (255) */ | |
333 | + 0x05, 0x07, /* Usage Page (Key Codes) */ | |
334 | + 0x19, 0x00, /* Usage Minimum (0) */ | |
335 | + 0x29, 0xff, /* Usage Maximum (255) */ | |
336 | + 0x81, 0x00, /* Input (Data, Array) */ | |
337 | + 0xc0, /* End Collection */ | |
338 | +}; | |
339 | + | |
340 | +#define USB_HID_USAGE_ERROR_ROLLOVER 0x01 | |
341 | +#define USB_HID_USAGE_POSTFAIL 0x02 | |
342 | +#define USB_HID_USAGE_ERROR_UNDEFINED 0x03 | |
343 | + | |
344 | +/* Indices are QEMU keycodes, values are from HID Usage Table. Indices | |
345 | + * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */ | |
346 | +static const uint8_t usb_hid_usage_keys[0x100] = { | |
347 | + 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, | |
348 | + 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b, | |
349 | + 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, | |
350 | + 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, | |
351 | + 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, | |
352 | + 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, | |
353 | + 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, | |
354 | + 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, | |
355 | + 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, | |
356 | + 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, | |
357 | + 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, | |
358 | + 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, | |
359 | + 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, | |
360 | + 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, | |
361 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
362 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, | |
363 | + | |
364 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
365 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
366 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
367 | + 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, | |
368 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
369 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
370 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, | |
371 | + 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
372 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, | |
373 | + 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, | |
374 | + 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, | |
375 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
376 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
377 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
378 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
379 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
380 | +}; | |
381 | + | |
226 | 382 | static void usb_mouse_event(void *opaque, |
227 | 383 | int dx1, int dy1, int dz1, int buttons_state) |
228 | 384 | { |
... | ... | @@ -245,6 +401,51 @@ static void usb_tablet_event(void *opaque, |
245 | 401 | s->buttons_state = buttons_state; |
246 | 402 | } |
247 | 403 | |
404 | +static void usb_keyboard_event(void *opaque, int keycode) | |
405 | +{ | |
406 | + USBKeyboardState *s = opaque; | |
407 | + uint8_t hid_code, key; | |
408 | + int i; | |
409 | + | |
410 | + key = keycode & 0x7f; | |
411 | + hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))]; | |
412 | + s->modifiers &= ~(1 << 8); | |
413 | + | |
414 | + switch (hid_code) { | |
415 | + case 0x00: | |
416 | + return; | |
417 | + | |
418 | + case 0xe0: | |
419 | + if (s->modifiers & (1 << 9)) { | |
420 | + s->modifiers ^= 3 << 8; | |
421 | + return; | |
422 | + } | |
423 | + case 0xe1 ... 0xe7: | |
424 | + if (keycode & (1 << 7)) { | |
425 | + s->modifiers &= ~(1 << (hid_code & 0x0f)); | |
426 | + return; | |
427 | + } | |
428 | + case 0xe8 ... 0xef: | |
429 | + s->modifiers |= 1 << (hid_code & 0x0f); | |
430 | + return; | |
431 | + } | |
432 | + | |
433 | + if (keycode & (1 << 7)) { | |
434 | + for (i = s->keys - 1; i >= 0; i --) | |
435 | + if (s->key[i] == hid_code) { | |
436 | + s->key[i] = s->key[-- s->keys]; | |
437 | + s->key[s->keys] = 0x00; | |
438 | + return; | |
439 | + } | |
440 | + } else { | |
441 | + for (i = s->keys - 1; i >= 0; i --) | |
442 | + if (s->key[i] == hid_code) | |
443 | + return; | |
444 | + if (s->keys < sizeof(s->key)) | |
445 | + s->key[s->keys ++] = hid_code; | |
446 | + } | |
447 | +} | |
448 | + | |
248 | 449 | static inline int int_clamp(int val, int vmin, int vmax) |
249 | 450 | { |
250 | 451 | if (val < vmin) |
... | ... | @@ -326,22 +527,59 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) |
326 | 527 | return l; |
327 | 528 | } |
328 | 529 | |
530 | +static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len) | |
531 | +{ | |
532 | + if (len < 2) | |
533 | + return 0; | |
534 | + | |
535 | + buf[0] = s->modifiers & 0xff; | |
536 | + buf[1] = 0; | |
537 | + if (s->keys > 6) | |
538 | + memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2); | |
539 | + else | |
540 | + memcpy(buf + 2, s->key, MIN(8, len) - 2); | |
541 | + | |
542 | + return MIN(8, len); | |
543 | +} | |
544 | + | |
545 | +static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len) | |
546 | +{ | |
547 | + if (len > 0) { | |
548 | + /* 0x01: Num Lock LED | |
549 | + * 0x02: Caps Lock LED | |
550 | + * 0x04: Scroll Lock LED | |
551 | + * 0x08: Compose LED | |
552 | + * 0x10: Kana LED */ | |
553 | + s->leds = buf[0]; | |
554 | + } | |
555 | + return 0; | |
556 | +} | |
557 | + | |
329 | 558 | static void usb_mouse_handle_reset(USBDevice *dev) |
330 | 559 | { |
331 | - USBMouseState *s = (USBMouseState *)dev; | |
332 | - | |
333 | - s->dx = 0; | |
334 | - s->dy = 0; | |
335 | - s->dz = 0; | |
336 | - s->x = 0; | |
337 | - s->y = 0; | |
338 | - s->buttons_state = 0; | |
560 | + USBHIDState *s = (USBHIDState *)dev; | |
561 | + | |
562 | + s->ptr.dx = 0; | |
563 | + s->ptr.dy = 0; | |
564 | + s->ptr.dz = 0; | |
565 | + s->ptr.x = 0; | |
566 | + s->ptr.y = 0; | |
567 | + s->ptr.buttons_state = 0; | |
568 | + s->protocol = 1; | |
569 | +} | |
570 | + | |
571 | +static void usb_keyboard_handle_reset(USBDevice *dev) | |
572 | +{ | |
573 | + USBHIDState *s = (USBHIDState *)dev; | |
574 | + | |
575 | + qemu_add_kbd_event_handler(usb_keyboard_event, &s->kbd); | |
576 | + s->protocol = 1; | |
339 | 577 | } |
340 | 578 | |
341 | -static int usb_mouse_handle_control(USBDevice *dev, int request, int value, | |
579 | +static int usb_hid_handle_control(USBDevice *dev, int request, int value, | |
342 | 580 | int index, int length, uint8_t *data) |
343 | 581 | { |
344 | - USBMouseState *s = (USBMouseState *)dev; | |
582 | + USBHIDState *s = (USBHIDState *)dev; | |
345 | 583 | int ret = 0; |
346 | 584 | |
347 | 585 | switch(request) { |
... | ... | @@ -387,7 +625,11 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
387 | 625 | memcpy(data, qemu_tablet_config_descriptor, |
388 | 626 | sizeof(qemu_tablet_config_descriptor)); |
389 | 627 | ret = sizeof(qemu_tablet_config_descriptor); |
390 | - } | |
628 | + } else if (s->kind == USB_KEYBOARD) { | |
629 | + memcpy(data, qemu_keyboard_config_descriptor, | |
630 | + sizeof(qemu_keyboard_config_descriptor)); | |
631 | + ret = sizeof(qemu_keyboard_config_descriptor); | |
632 | + } | |
391 | 633 | break; |
392 | 634 | case USB_DT_STRING: |
393 | 635 | switch(value & 0xff) { |
... | ... | @@ -405,10 +647,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
405 | 647 | break; |
406 | 648 | case 2: |
407 | 649 | /* product description */ |
408 | - if (s->kind == USB_MOUSE) | |
409 | - ret = set_usb_string(data, "QEMU USB Mouse"); | |
410 | - else if (s->kind == USB_TABLET) | |
411 | - ret = set_usb_string(data, "QEMU USB Tablet"); | |
650 | + ret = set_usb_string(data, s->dev.devname); | |
412 | 651 | break; |
413 | 652 | case 3: |
414 | 653 | /* vendor description */ |
... | ... | @@ -418,6 +657,12 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
418 | 657 | ret = set_usb_string(data, "HID Mouse"); |
419 | 658 | break; |
420 | 659 | case 5: |
660 | + ret = set_usb_string(data, "HID Tablet"); | |
661 | + break; | |
662 | + case 6: | |
663 | + ret = set_usb_string(data, "HID Keyboard"); | |
664 | + break; | |
665 | + case 7: | |
421 | 666 | ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); |
422 | 667 | break; |
423 | 668 | default: |
... | ... | @@ -454,19 +699,48 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
454 | 699 | memcpy(data, qemu_tablet_hid_report_descriptor, |
455 | 700 | sizeof(qemu_tablet_hid_report_descriptor)); |
456 | 701 | ret = sizeof(qemu_tablet_hid_report_descriptor); |
457 | - } | |
458 | - break; | |
702 | + } else if (s->kind == USB_KEYBOARD) { | |
703 | + memcpy(data, qemu_keyboard_hid_report_descriptor, | |
704 | + sizeof(qemu_keyboard_hid_report_descriptor)); | |
705 | + ret = sizeof(qemu_keyboard_hid_report_descriptor); | |
706 | + } | |
707 | + break; | |
459 | 708 | default: |
460 | 709 | goto fail; |
461 | 710 | } |
462 | 711 | break; |
463 | 712 | case GET_REPORT: |
464 | 713 | if (s->kind == USB_MOUSE) |
465 | - ret = usb_mouse_poll(s, data, length); | |
714 | + ret = usb_mouse_poll(&s->ptr, data, length); | |
466 | 715 | else if (s->kind == USB_TABLET) |
467 | - ret = usb_tablet_poll(s, data, length); | |
716 | + ret = usb_tablet_poll(&s->ptr, data, length); | |
717 | + else if (s->kind == USB_KEYBOARD) | |
718 | + ret = usb_keyboard_poll(&s->kbd, data, length); | |
719 | + break; | |
720 | + case SET_REPORT: | |
721 | + if (s->kind == USB_KEYBOARD) | |
722 | + ret = usb_keyboard_write(&s->kbd, data, length); | |
723 | + else | |
724 | + goto fail; | |
725 | + break; | |
726 | + case GET_PROTOCOL: | |
727 | + if (s->kind != USB_KEYBOARD) | |
728 | + goto fail; | |
729 | + ret = 1; | |
730 | + data[0] = s->protocol; | |
731 | + break; | |
732 | + case SET_PROTOCOL: | |
733 | + if (s->kind != USB_KEYBOARD) | |
734 | + goto fail; | |
735 | + ret = 0; | |
736 | + s->protocol = value; | |
737 | + break; | |
738 | + case GET_IDLE: | |
739 | + ret = 1; | |
740 | + data[0] = s->idle; | |
468 | 741 | break; |
469 | 742 | case SET_IDLE: |
743 | + s->idle = value; | |
470 | 744 | ret = 0; |
471 | 745 | break; |
472 | 746 | default: |
... | ... | @@ -477,18 +751,20 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, |
477 | 751 | return ret; |
478 | 752 | } |
479 | 753 | |
480 | -static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) | |
754 | +static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) | |
481 | 755 | { |
482 | - USBMouseState *s = (USBMouseState *)dev; | |
756 | + USBHIDState *s = (USBHIDState *)dev; | |
483 | 757 | int ret = 0; |
484 | 758 | |
485 | 759 | switch(p->pid) { |
486 | 760 | case USB_TOKEN_IN: |
487 | 761 | if (p->devep == 1) { |
488 | - if (s->kind == USB_MOUSE) | |
489 | - ret = usb_mouse_poll(s, p->data, p->len); | |
490 | - else if (s->kind == USB_TABLET) | |
491 | - ret = usb_tablet_poll(s, p->data, p->len); | |
762 | + if (s->kind == USB_MOUSE) | |
763 | + ret = usb_mouse_poll(&s->ptr, p->data, p->len); | |
764 | + else if (s->kind == USB_TABLET) | |
765 | + ret = usb_tablet_poll(&s->ptr, p->data, p->len); | |
766 | + else if (s->kind == USB_KEYBOARD) | |
767 | + ret = usb_keyboard_poll(&s->kbd, p->data, p->len); | |
492 | 768 | } else { |
493 | 769 | goto fail; |
494 | 770 | } |
... | ... | @@ -502,28 +778,30 @@ static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) |
502 | 778 | return ret; |
503 | 779 | } |
504 | 780 | |
505 | -static void usb_mouse_handle_destroy(USBDevice *dev) | |
781 | +static void usb_hid_handle_destroy(USBDevice *dev) | |
506 | 782 | { |
507 | - USBMouseState *s = (USBMouseState *)dev; | |
783 | + USBHIDState *s = (USBHIDState *)dev; | |
508 | 784 | |
509 | - qemu_remove_mouse_event_handler(s->eh_entry); | |
785 | + if (s->kind != USB_KEYBOARD) | |
786 | + qemu_remove_mouse_event_handler(s->ptr.eh_entry); | |
787 | + /* TODO: else */ | |
510 | 788 | qemu_free(s); |
511 | 789 | } |
512 | 790 | |
513 | 791 | USBDevice *usb_tablet_init(void) |
514 | 792 | { |
515 | - USBMouseState *s; | |
793 | + USBHIDState *s; | |
516 | 794 | |
517 | - s = qemu_mallocz(sizeof(USBMouseState)); | |
795 | + s = qemu_mallocz(sizeof(USBHIDState)); | |
518 | 796 | if (!s) |
519 | 797 | return NULL; |
520 | 798 | s->dev.speed = USB_SPEED_FULL; |
521 | 799 | s->dev.handle_packet = usb_generic_handle_packet; |
522 | 800 | |
523 | 801 | s->dev.handle_reset = usb_mouse_handle_reset; |
524 | - s->dev.handle_control = usb_mouse_handle_control; | |
525 | - s->dev.handle_data = usb_mouse_handle_data; | |
526 | - s->dev.handle_destroy = usb_mouse_handle_destroy; | |
802 | + s->dev.handle_control = usb_hid_handle_control; | |
803 | + s->dev.handle_data = usb_hid_handle_data; | |
804 | + s->dev.handle_destroy = usb_hid_handle_destroy; | |
527 | 805 | s->kind = USB_TABLET; |
528 | 806 | |
529 | 807 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); |
... | ... | @@ -533,21 +811,42 @@ USBDevice *usb_tablet_init(void) |
533 | 811 | |
534 | 812 | USBDevice *usb_mouse_init(void) |
535 | 813 | { |
536 | - USBMouseState *s; | |
814 | + USBHIDState *s; | |
537 | 815 | |
538 | - s = qemu_mallocz(sizeof(USBMouseState)); | |
816 | + s = qemu_mallocz(sizeof(USBHIDState)); | |
539 | 817 | if (!s) |
540 | 818 | return NULL; |
541 | 819 | s->dev.speed = USB_SPEED_FULL; |
542 | 820 | s->dev.handle_packet = usb_generic_handle_packet; |
543 | 821 | |
544 | 822 | s->dev.handle_reset = usb_mouse_handle_reset; |
545 | - s->dev.handle_control = usb_mouse_handle_control; | |
546 | - s->dev.handle_data = usb_mouse_handle_data; | |
547 | - s->dev.handle_destroy = usb_mouse_handle_destroy; | |
823 | + s->dev.handle_control = usb_hid_handle_control; | |
824 | + s->dev.handle_data = usb_hid_handle_data; | |
825 | + s->dev.handle_destroy = usb_hid_handle_destroy; | |
548 | 826 | s->kind = USB_MOUSE; |
549 | 827 | |
550 | 828 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); |
551 | 829 | |
552 | 830 | return (USBDevice *)s; |
553 | 831 | } |
832 | + | |
833 | +USBDevice *usb_keyboard_init(void) | |
834 | +{ | |
835 | + USBHIDState *s; | |
836 | + | |
837 | + s = qemu_mallocz(sizeof(USBHIDState)); | |
838 | + if (!s) | |
839 | + return NULL; | |
840 | + s->dev.speed = USB_SPEED_FULL; | |
841 | + s->dev.handle_packet = usb_generic_handle_packet; | |
842 | + | |
843 | + s->dev.handle_reset = usb_keyboard_handle_reset; | |
844 | + s->dev.handle_control = usb_hid_handle_control; | |
845 | + s->dev.handle_data = usb_hid_handle_data; | |
846 | + s->dev.handle_destroy = usb_hid_handle_destroy; | |
847 | + s->kind = USB_KEYBOARD; | |
848 | + | |
849 | + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard"); | |
850 | + | |
851 | + return (USBDevice *) s; | |
852 | +} | ... | ... |
hw/usb.h
qemu-doc.texi
... | ... | @@ -1362,6 +1362,8 @@ Pass through the host device identified by @var{vendor_id:product_id} |
1362 | 1362 | Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet} |
1363 | 1363 | above but it can be used with the tslib library because in addition to touch |
1364 | 1364 | coordinates it reports touch pressure. |
1365 | +@item @code{keyboard} | |
1366 | +Standard USB keyboard. Will override the PS/2 keyboard (if present). | |
1365 | 1367 | @end table |
1366 | 1368 | |
1367 | 1369 | @node host_usb_devices | ... | ... |
vl.c
... | ... | @@ -4319,7 +4319,9 @@ static int usb_device_add(const char *devname) |
4319 | 4319 | } else if (!strcmp(devname, "mouse")) { |
4320 | 4320 | dev = usb_mouse_init(); |
4321 | 4321 | } else if (!strcmp(devname, "tablet")) { |
4322 | - dev = usb_tablet_init(); | |
4322 | + dev = usb_tablet_init(); | |
4323 | + } else if (!strcmp(devname, "keyboard")) { | |
4324 | + dev = usb_keyboard_init(); | |
4323 | 4325 | } else if (strstart(devname, "disk:", &p)) { |
4324 | 4326 | dev = usb_msd_init(p); |
4325 | 4327 | } else if (!strcmp(devname, "wacom-tablet")) { | ... | ... |