Commit 47b2d338d982c9e26b2af6b51c1cc0da7cbd2b60

Authored by balrog
1 parent 07cf0ba0

Add USB HID keyboard.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2996 c046a42c-6fe2-441c-8c8c-71466251a162
hw/usb-hid.c
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 * QEMU USB HID devices 2 * QEMU USB HID devices
3 * 3 *
4 * Copyright (c) 2005 Fabrice Bellard 4 * Copyright (c) 2005 Fabrice Bellard
  5 + * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
5 * 6 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal 8 * of this software and associated documentation files (the "Software"), to deal
@@ -27,21 +28,44 @@ @@ -27,21 +28,44 @@
27 #define GET_REPORT 0xa101 28 #define GET_REPORT 0xa101
28 #define GET_IDLE 0xa102 29 #define GET_IDLE 0xa102
29 #define GET_PROTOCOL 0xa103 30 #define GET_PROTOCOL 0xa103
  31 +#define SET_REPORT 0x2109
30 #define SET_IDLE 0x210a 32 #define SET_IDLE 0x210a
31 #define SET_PROTOCOL 0x210b 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 typedef struct USBMouseState { 44 typedef struct USBMouseState {
37 - USBDevice dev;  
38 int dx, dy, dz, buttons_state; 45 int dx, dy, dz, buttons_state;
39 int x, y; 46 int x, y;
40 - int kind;  
41 int mouse_grabbed; 47 int mouse_grabbed;
42 QEMUPutMouseEntry *eh_entry; 48 QEMUPutMouseEntry *eh_entry;
43 } USBMouseState; 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 /* mostly the same values as the Bochs USB Mouse device */ 69 /* mostly the same values as the Bochs USB Mouse device */
46 static const uint8_t qemu_mouse_dev_descriptor[] = { 70 static const uint8_t qemu_mouse_dev_descriptor[] = {
47 0x12, /* u8 bLength; */ 71 0x12, /* u8 bLength; */
@@ -98,7 +122,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = { @@ -98,7 +122,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = {
98 0x03, /* u8 if_bInterfaceClass; */ 122 0x03, /* u8 if_bInterfaceClass; */
99 0x01, /* u8 if_bInterfaceSubClass; */ 123 0x01, /* u8 if_bInterfaceSubClass; */
100 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 124 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
101 - 0x05, /* u8 if_iInterface; */ 125 + 0x07, /* u8 if_iInterface; */
102 126
103 /* HID descriptor */ 127 /* HID descriptor */
104 0x09, /* u8 bLength; */ 128 0x09, /* u8 bLength; */
@@ -125,7 +149,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { @@ -125,7 +149,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = {
125 0x22, 0x00, /* u16 wTotalLength; */ 149 0x22, 0x00, /* u16 wTotalLength; */
126 0x01, /* u8 bNumInterfaces; (1) */ 150 0x01, /* u8 bNumInterfaces; (1) */
127 0x01, /* u8 bConfigurationValue; */ 151 0x01, /* u8 bConfigurationValue; */
128 - 0x04, /* u8 iConfiguration; */ 152 + 0x05, /* u8 iConfiguration; */
129 0xa0, /* u8 bmAttributes; 153 0xa0, /* u8 bmAttributes;
130 Bit 7: must be set, 154 Bit 7: must be set,
131 6: Self-powered, 155 6: Self-powered,
@@ -153,7 +177,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = { @@ -153,7 +177,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = {
153 0x03, /* u8 if_bInterfaceClass; */ 177 0x03, /* u8 if_bInterfaceClass; */
154 0x01, /* u8 if_bInterfaceSubClass; */ 178 0x01, /* u8 if_bInterfaceSubClass; */
155 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 179 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
156 - 0x05, /* u8 if_iInterface; */ 180 + 0x07, /* u8 if_iInterface; */
157 181
158 /* HID descriptor */ 182 /* HID descriptor */
159 0x09, /* u8 bLength; */ 183 0x09, /* u8 bLength; */
@@ -173,6 +197,61 @@ static const uint8_t qemu_tablet_config_descriptor[] = { @@ -173,6 +197,61 @@ static const uint8_t qemu_tablet_config_descriptor[] = {
173 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ 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 static const uint8_t qemu_mouse_hid_report_descriptor[] = { 255 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
177 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 256 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
178 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 257 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
@@ -223,6 +302,83 @@ static const uint8_t qemu_tablet_hid_report_descriptor[] = { @@ -223,6 +302,83 @@ static const uint8_t qemu_tablet_hid_report_descriptor[] = {
223 0xC0, /* End Collection */ 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 static void usb_mouse_event(void *opaque, 382 static void usb_mouse_event(void *opaque,
227 int dx1, int dy1, int dz1, int buttons_state) 383 int dx1, int dy1, int dz1, int buttons_state)
228 { 384 {
@@ -245,6 +401,51 @@ static void usb_tablet_event(void *opaque, @@ -245,6 +401,51 @@ static void usb_tablet_event(void *opaque,
245 s->buttons_state = buttons_state; 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 static inline int int_clamp(int val, int vmin, int vmax) 449 static inline int int_clamp(int val, int vmin, int vmax)
249 { 450 {
250 if (val < vmin) 451 if (val < vmin)
@@ -326,22 +527,59 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) @@ -326,22 +527,59 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
326 return l; 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 static void usb_mouse_handle_reset(USBDevice *dev) 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 int index, int length, uint8_t *data) 580 int index, int length, uint8_t *data)
343 { 581 {
344 - USBMouseState *s = (USBMouseState *)dev; 582 + USBHIDState *s = (USBHIDState *)dev;
345 int ret = 0; 583 int ret = 0;
346 584
347 switch(request) { 585 switch(request) {
@@ -387,7 +625,11 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, @@ -387,7 +625,11 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
387 memcpy(data, qemu_tablet_config_descriptor, 625 memcpy(data, qemu_tablet_config_descriptor,
388 sizeof(qemu_tablet_config_descriptor)); 626 sizeof(qemu_tablet_config_descriptor));
389 ret = sizeof(qemu_tablet_config_descriptor); 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 break; 633 break;
392 case USB_DT_STRING: 634 case USB_DT_STRING:
393 switch(value & 0xff) { 635 switch(value & 0xff) {
@@ -405,10 +647,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, @@ -405,10 +647,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
405 break; 647 break;
406 case 2: 648 case 2:
407 /* product description */ 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 break; 651 break;
413 case 3: 652 case 3:
414 /* vendor description */ 653 /* vendor description */
@@ -418,6 +657,12 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, @@ -418,6 +657,12 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
418 ret = set_usb_string(data, "HID Mouse"); 657 ret = set_usb_string(data, "HID Mouse");
419 break; 658 break;
420 case 5: 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 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); 666 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
422 break; 667 break;
423 default: 668 default:
@@ -454,19 +699,48 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, @@ -454,19 +699,48 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
454 memcpy(data, qemu_tablet_hid_report_descriptor, 699 memcpy(data, qemu_tablet_hid_report_descriptor,
455 sizeof(qemu_tablet_hid_report_descriptor)); 700 sizeof(qemu_tablet_hid_report_descriptor));
456 ret = sizeof(qemu_tablet_hid_report_descriptor); 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 default: 708 default:
460 goto fail; 709 goto fail;
461 } 710 }
462 break; 711 break;
463 case GET_REPORT: 712 case GET_REPORT:
464 if (s->kind == USB_MOUSE) 713 if (s->kind == USB_MOUSE)
465 - ret = usb_mouse_poll(s, data, length); 714 + ret = usb_mouse_poll(&s->ptr, data, length);
466 else if (s->kind == USB_TABLET) 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 break; 741 break;
469 case SET_IDLE: 742 case SET_IDLE:
  743 + s->idle = value;
470 ret = 0; 744 ret = 0;
471 break; 745 break;
472 default: 746 default:
@@ -477,18 +751,20 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value, @@ -477,18 +751,20 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
477 return ret; 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 int ret = 0; 757 int ret = 0;
484 758
485 switch(p->pid) { 759 switch(p->pid) {
486 case USB_TOKEN_IN: 760 case USB_TOKEN_IN:
487 if (p->devep == 1) { 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 } else { 768 } else {
493 goto fail; 769 goto fail;
494 } 770 }
@@ -502,28 +778,30 @@ static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) @@ -502,28 +778,30 @@ static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p)
502 return ret; 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 qemu_free(s); 788 qemu_free(s);
511 } 789 }
512 790
513 USBDevice *usb_tablet_init(void) 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 if (!s) 796 if (!s)
519 return NULL; 797 return NULL;
520 s->dev.speed = USB_SPEED_FULL; 798 s->dev.speed = USB_SPEED_FULL;
521 s->dev.handle_packet = usb_generic_handle_packet; 799 s->dev.handle_packet = usb_generic_handle_packet;
522 800
523 s->dev.handle_reset = usb_mouse_handle_reset; 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 s->kind = USB_TABLET; 805 s->kind = USB_TABLET;
528 806
529 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); 807 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
@@ -533,21 +811,42 @@ USBDevice *usb_tablet_init(void) @@ -533,21 +811,42 @@ USBDevice *usb_tablet_init(void)
533 811
534 USBDevice *usb_mouse_init(void) 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 if (!s) 817 if (!s)
540 return NULL; 818 return NULL;
541 s->dev.speed = USB_SPEED_FULL; 819 s->dev.speed = USB_SPEED_FULL;
542 s->dev.handle_packet = usb_generic_handle_packet; 820 s->dev.handle_packet = usb_generic_handle_packet;
543 821
544 s->dev.handle_reset = usb_mouse_handle_reset; 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 s->kind = USB_MOUSE; 826 s->kind = USB_MOUSE;
549 827
550 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); 828 pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
551 829
552 return (USBDevice *)s; 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
@@ -218,6 +218,7 @@ void usb_host_info(void); @@ -218,6 +218,7 @@ void usb_host_info(void);
218 /* usb-hid.c */ 218 /* usb-hid.c */
219 USBDevice *usb_mouse_init(void); 219 USBDevice *usb_mouse_init(void);
220 USBDevice *usb_tablet_init(void); 220 USBDevice *usb_tablet_init(void);
  221 +USBDevice *usb_keyboard_init(void);
221 222
222 /* usb-msd.c */ 223 /* usb-msd.c */
223 USBDevice *usb_msd_init(const char *filename); 224 USBDevice *usb_msd_init(const char *filename);
qemu-doc.texi
@@ -1362,6 +1362,8 @@ Pass through the host device identified by @var{vendor_id:product_id} @@ -1362,6 +1362,8 @@ Pass through the host device identified by @var{vendor_id:product_id}
1362 Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet} 1362 Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet}
1363 above but it can be used with the tslib library because in addition to touch 1363 above but it can be used with the tslib library because in addition to touch
1364 coordinates it reports touch pressure. 1364 coordinates it reports touch pressure.
  1365 +@item @code{keyboard}
  1366 +Standard USB keyboard. Will override the PS/2 keyboard (if present).
1365 @end table 1367 @end table
1366 1368
1367 @node host_usb_devices 1369 @node host_usb_devices
@@ -4319,7 +4319,9 @@ static int usb_device_add(const char *devname) @@ -4319,7 +4319,9 @@ static int usb_device_add(const char *devname)
4319 } else if (!strcmp(devname, "mouse")) { 4319 } else if (!strcmp(devname, "mouse")) {
4320 dev = usb_mouse_init(); 4320 dev = usb_mouse_init();
4321 } else if (!strcmp(devname, "tablet")) { 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 } else if (strstart(devname, "disk:", &p)) { 4325 } else if (strstart(devname, "disk:", &p)) {
4324 dev = usb_msd_init(p); 4326 dev = usb_msd_init(p);
4325 } else if (!strcmp(devname, "wacom-tablet")) { 4327 } else if (!strcmp(devname, "wacom-tablet")) {