sim-card
/
qemu
Archived
10
0
Fork 0

Add USB HID keyboard.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2996 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
balrog 2007-06-22 08:16:00 +00:00
parent 07cf0ba03b
commit 47b2d338d9
4 changed files with 350 additions and 46 deletions

View File

@ -2,6 +2,7 @@
* QEMU USB HID devices * QEMU USB HID devices
* *
* Copyright (c) 2005 Fabrice Bellard * Copyright (c) 2005 Fabrice Bellard
* Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -27,21 +28,44 @@
#define GET_REPORT 0xa101 #define GET_REPORT 0xa101
#define GET_IDLE 0xa102 #define GET_IDLE 0xa102
#define GET_PROTOCOL 0xa103 #define GET_PROTOCOL 0xa103
#define SET_REPORT 0x2109
#define SET_IDLE 0x210a #define SET_IDLE 0x210a
#define SET_PROTOCOL 0x210b #define SET_PROTOCOL 0x210b
/* HID descriptor types */
#define USB_DT_HID 0x21
#define USB_DT_REPORT 0x22
#define USB_DT_PHY 0x23
#define USB_MOUSE 1 #define USB_MOUSE 1
#define USB_TABLET 2 #define USB_TABLET 2
#define USB_KEYBOARD 3
typedef struct USBMouseState { typedef struct USBMouseState {
USBDevice dev;
int dx, dy, dz, buttons_state; int dx, dy, dz, buttons_state;
int x, y; int x, y;
int kind;
int mouse_grabbed; int mouse_grabbed;
QEMUPutMouseEntry *eh_entry; QEMUPutMouseEntry *eh_entry;
} USBMouseState; } USBMouseState;
typedef struct USBKeyboardState {
uint16_t modifiers;
uint8_t leds;
uint8_t key[16];
int keys;
} USBKeyboardState;
typedef struct USBHIDState {
USBDevice dev;
union {
USBMouseState ptr;
USBKeyboardState kbd;
};
int kind;
int protocol;
int idle;
} USBHIDState;
/* mostly the same values as the Bochs USB Mouse device */ /* mostly the same values as the Bochs USB Mouse device */
static const uint8_t qemu_mouse_dev_descriptor[] = { static const uint8_t qemu_mouse_dev_descriptor[] = {
0x12, /* u8 bLength; */ 0x12, /* u8 bLength; */
@ -98,7 +122,7 @@ static const uint8_t qemu_mouse_config_descriptor[] = {
0x03, /* u8 if_bInterfaceClass; */ 0x03, /* u8 if_bInterfaceClass; */
0x01, /* u8 if_bInterfaceSubClass; */ 0x01, /* u8 if_bInterfaceSubClass; */
0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
0x05, /* u8 if_iInterface; */ 0x07, /* u8 if_iInterface; */
/* HID descriptor */ /* HID descriptor */
0x09, /* u8 bLength; */ 0x09, /* u8 bLength; */
@ -125,7 +149,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = {
0x22, 0x00, /* u16 wTotalLength; */ 0x22, 0x00, /* u16 wTotalLength; */
0x01, /* u8 bNumInterfaces; (1) */ 0x01, /* u8 bNumInterfaces; (1) */
0x01, /* u8 bConfigurationValue; */ 0x01, /* u8 bConfigurationValue; */
0x04, /* u8 iConfiguration; */ 0x05, /* u8 iConfiguration; */
0xa0, /* u8 bmAttributes; 0xa0, /* u8 bmAttributes;
Bit 7: must be set, Bit 7: must be set,
6: Self-powered, 6: Self-powered,
@ -153,7 +177,7 @@ static const uint8_t qemu_tablet_config_descriptor[] = {
0x03, /* u8 if_bInterfaceClass; */ 0x03, /* u8 if_bInterfaceClass; */
0x01, /* u8 if_bInterfaceSubClass; */ 0x01, /* u8 if_bInterfaceSubClass; */
0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ 0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
0x05, /* u8 if_iInterface; */ 0x07, /* u8 if_iInterface; */
/* HID descriptor */ /* HID descriptor */
0x09, /* u8 bLength; */ 0x09, /* u8 bLength; */
@ -173,6 +197,61 @@ static const uint8_t qemu_tablet_config_descriptor[] = {
0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */ 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
}; };
static const uint8_t qemu_keyboard_config_descriptor[] = {
/* one configuration */
0x09, /* u8 bLength; */
USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */
0x22, 0x00, /* u16 wTotalLength; */
0x01, /* u8 bNumInterfaces; (1) */
0x01, /* u8 bConfigurationValue; */
0x06, /* u8 iConfiguration; */
0xa0, /* u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
0x32, /* u8 MaxPower; */
/* USB 1.1:
* USB 2.0, single TT organization (mandatory):
* one interface, protocol 0
*
* USB 2.0, multiple TT organization (optional):
* two interfaces, protocols 1 (like single TT)
* and 2 (multiple TT mode) ... config is
* sometimes settable
* NOT IMPLEMENTED
*/
/* one interface */
0x09, /* u8 if_bLength; */
USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */
0x00, /* u8 if_bInterfaceNumber; */
0x00, /* u8 if_bAlternateSetting; */
0x01, /* u8 if_bNumEndpoints; */
0x03, /* u8 if_bInterfaceClass; HID */
0x01, /* u8 if_bInterfaceSubClass; Boot */
0x01, /* u8 if_bInterfaceProtocol; Keyboard */
0x07, /* u8 if_iInterface; */
/* HID descriptor */
0x09, /* u8 bLength; */
USB_DT_HID, /* u8 bDescriptorType; */
0x11, 0x01, /* u16 HID_class */
0x00, /* u8 country_code */
0x01, /* u8 num_descriptors */
USB_DT_REPORT, /* u8 type; Report */
0x3f, 0x00, /* u16 len */
/* one endpoint (status change endpoint) */
0x07, /* u8 ep_bLength; */
USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */
USB_DIR_IN | 0x01, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* u8 ep_bmAttributes; Interrupt */
0x08, 0x00, /* u16 ep_wMaxPacketSize; */
0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
};
static const uint8_t qemu_mouse_hid_report_descriptor[] = { static const uint8_t qemu_mouse_hid_report_descriptor[] = {
0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
@ -223,6 +302,83 @@ static const uint8_t qemu_tablet_hid_report_descriptor[] = {
0xC0, /* End Collection */ 0xC0, /* End Collection */
}; };
static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x06, /* Usage (Keyboard) */
0xa1, 0x01, /* Collection (Application) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x08, /* Report Count (8) */
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0xe0, /* Usage Minimum (224) */
0x29, 0xe7, /* Usage Maximum (231) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x81, 0x02, /* Input (Data, Variable, Absolute) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x08, /* Report Size (8) */
0x81, 0x01, /* Input (Constant) */
0x95, 0x05, /* Report Count (5) */
0x75, 0x01, /* Report Size (1) */
0x05, 0x08, /* Usage Page (LEDs) */
0x19, 0x01, /* Usage Minimum (1) */
0x29, 0x05, /* Usage Maximum (5) */
0x91, 0x02, /* Output (Data, Variable, Absolute) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x03, /* Report Size (3) */
0x91, 0x01, /* Output (Constant) */
0x95, 0x06, /* Report Count (6) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0xff, /* Logical Maximum (255) */
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0x00, /* Usage Minimum (0) */
0x29, 0xff, /* Usage Maximum (255) */
0x81, 0x00, /* Input (Data, Array) */
0xc0, /* End Collection */
};
#define USB_HID_USAGE_ERROR_ROLLOVER 0x01
#define USB_HID_USAGE_POSTFAIL 0x02
#define USB_HID_USAGE_ERROR_UNDEFINED 0x03
/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
* above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
static const uint8_t usb_hid_usage_keys[0x100] = {
0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static void usb_mouse_event(void *opaque, static void usb_mouse_event(void *opaque,
int dx1, int dy1, int dz1, int buttons_state) int dx1, int dy1, int dz1, int buttons_state)
{ {
@ -245,6 +401,51 @@ static void usb_tablet_event(void *opaque,
s->buttons_state = buttons_state; s->buttons_state = buttons_state;
} }
static void usb_keyboard_event(void *opaque, int keycode)
{
USBKeyboardState *s = opaque;
uint8_t hid_code, key;
int i;
key = keycode & 0x7f;
hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
s->modifiers &= ~(1 << 8);
switch (hid_code) {
case 0x00:
return;
case 0xe0:
if (s->modifiers & (1 << 9)) {
s->modifiers ^= 3 << 8;
return;
}
case 0xe1 ... 0xe7:
if (keycode & (1 << 7)) {
s->modifiers &= ~(1 << (hid_code & 0x0f));
return;
}
case 0xe8 ... 0xef:
s->modifiers |= 1 << (hid_code & 0x0f);
return;
}
if (keycode & (1 << 7)) {
for (i = s->keys - 1; i >= 0; i --)
if (s->key[i] == hid_code) {
s->key[i] = s->key[-- s->keys];
s->key[s->keys] = 0x00;
return;
}
} else {
for (i = s->keys - 1; i >= 0; i --)
if (s->key[i] == hid_code)
return;
if (s->keys < sizeof(s->key))
s->key[s->keys ++] = hid_code;
}
}
static inline int int_clamp(int val, int vmin, int vmax) static inline int int_clamp(int val, int vmin, int vmax)
{ {
if (val < vmin) if (val < vmin)
@ -326,22 +527,59 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
return l; return l;
} }
static void usb_mouse_handle_reset(USBDevice *dev) static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len)
{ {
USBMouseState *s = (USBMouseState *)dev; if (len < 2)
return 0;
s->dx = 0; buf[0] = s->modifiers & 0xff;
s->dy = 0; buf[1] = 0;
s->dz = 0; if (s->keys > 6)
s->x = 0; memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
s->y = 0; else
s->buttons_state = 0; memcpy(buf + 2, s->key, MIN(8, len) - 2);
return MIN(8, len);
} }
static int usb_mouse_handle_control(USBDevice *dev, int request, int value, static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
{
if (len > 0) {
/* 0x01: Num Lock LED
* 0x02: Caps Lock LED
* 0x04: Scroll Lock LED
* 0x08: Compose LED
* 0x10: Kana LED */
s->leds = buf[0];
}
return 0;
}
static void usb_mouse_handle_reset(USBDevice *dev)
{
USBHIDState *s = (USBHIDState *)dev;
s->ptr.dx = 0;
s->ptr.dy = 0;
s->ptr.dz = 0;
s->ptr.x = 0;
s->ptr.y = 0;
s->ptr.buttons_state = 0;
s->protocol = 1;
}
static void usb_keyboard_handle_reset(USBDevice *dev)
{
USBHIDState *s = (USBHIDState *)dev;
qemu_add_kbd_event_handler(usb_keyboard_event, &s->kbd);
s->protocol = 1;
}
static int usb_hid_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data) int index, int length, uint8_t *data)
{ {
USBMouseState *s = (USBMouseState *)dev; USBHIDState *s = (USBHIDState *)dev;
int ret = 0; int ret = 0;
switch(request) { switch(request) {
@ -387,6 +625,10 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
memcpy(data, qemu_tablet_config_descriptor, memcpy(data, qemu_tablet_config_descriptor,
sizeof(qemu_tablet_config_descriptor)); sizeof(qemu_tablet_config_descriptor));
ret = sizeof(qemu_tablet_config_descriptor); ret = sizeof(qemu_tablet_config_descriptor);
} else if (s->kind == USB_KEYBOARD) {
memcpy(data, qemu_keyboard_config_descriptor,
sizeof(qemu_keyboard_config_descriptor));
ret = sizeof(qemu_keyboard_config_descriptor);
} }
break; break;
case USB_DT_STRING: case USB_DT_STRING:
@ -405,10 +647,7 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
break; break;
case 2: case 2:
/* product description */ /* product description */
if (s->kind == USB_MOUSE) ret = set_usb_string(data, s->dev.devname);
ret = set_usb_string(data, "QEMU USB Mouse");
else if (s->kind == USB_TABLET)
ret = set_usb_string(data, "QEMU USB Tablet");
break; break;
case 3: case 3:
/* vendor description */ /* vendor description */
@ -418,6 +657,12 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
ret = set_usb_string(data, "HID Mouse"); ret = set_usb_string(data, "HID Mouse");
break; break;
case 5: case 5:
ret = set_usb_string(data, "HID Tablet");
break;
case 6:
ret = set_usb_string(data, "HID Keyboard");
break;
case 7:
ret = set_usb_string(data, "Endpoint1 Interrupt Pipe"); ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
break; break;
default: default:
@ -454,6 +699,10 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
memcpy(data, qemu_tablet_hid_report_descriptor, memcpy(data, qemu_tablet_hid_report_descriptor,
sizeof(qemu_tablet_hid_report_descriptor)); sizeof(qemu_tablet_hid_report_descriptor));
ret = sizeof(qemu_tablet_hid_report_descriptor); ret = sizeof(qemu_tablet_hid_report_descriptor);
} else if (s->kind == USB_KEYBOARD) {
memcpy(data, qemu_keyboard_hid_report_descriptor,
sizeof(qemu_keyboard_hid_report_descriptor));
ret = sizeof(qemu_keyboard_hid_report_descriptor);
} }
break; break;
default: default:
@ -462,11 +711,36 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
break; break;
case GET_REPORT: case GET_REPORT:
if (s->kind == USB_MOUSE) if (s->kind == USB_MOUSE)
ret = usb_mouse_poll(s, data, length); ret = usb_mouse_poll(&s->ptr, data, length);
else if (s->kind == USB_TABLET) else if (s->kind == USB_TABLET)
ret = usb_tablet_poll(s, data, length); ret = usb_tablet_poll(&s->ptr, data, length);
else if (s->kind == USB_KEYBOARD)
ret = usb_keyboard_poll(&s->kbd, data, length);
break;
case SET_REPORT:
if (s->kind == USB_KEYBOARD)
ret = usb_keyboard_write(&s->kbd, data, length);
else
goto fail;
break;
case GET_PROTOCOL:
if (s->kind != USB_KEYBOARD)
goto fail;
ret = 1;
data[0] = s->protocol;
break;
case SET_PROTOCOL:
if (s->kind != USB_KEYBOARD)
goto fail;
ret = 0;
s->protocol = value;
break;
case GET_IDLE:
ret = 1;
data[0] = s->idle;
break; break;
case SET_IDLE: case SET_IDLE:
s->idle = value;
ret = 0; ret = 0;
break; break;
default: default:
@ -477,18 +751,20 @@ static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
return ret; return ret;
} }
static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p) static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
{ {
USBMouseState *s = (USBMouseState *)dev; USBHIDState *s = (USBHIDState *)dev;
int ret = 0; int ret = 0;
switch(p->pid) { switch(p->pid) {
case USB_TOKEN_IN: case USB_TOKEN_IN:
if (p->devep == 1) { if (p->devep == 1) {
if (s->kind == USB_MOUSE) if (s->kind == USB_MOUSE)
ret = usb_mouse_poll(s, p->data, p->len); ret = usb_mouse_poll(&s->ptr, p->data, p->len);
else if (s->kind == USB_TABLET) else if (s->kind == USB_TABLET)
ret = usb_tablet_poll(s, p->data, p->len); ret = usb_tablet_poll(&s->ptr, p->data, p->len);
else if (s->kind == USB_KEYBOARD)
ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
} else { } else {
goto fail; goto fail;
} }
@ -502,28 +778,30 @@ static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p)
return ret; return ret;
} }
static void usb_mouse_handle_destroy(USBDevice *dev) static void usb_hid_handle_destroy(USBDevice *dev)
{ {
USBMouseState *s = (USBMouseState *)dev; USBHIDState *s = (USBHIDState *)dev;
qemu_remove_mouse_event_handler(s->eh_entry); if (s->kind != USB_KEYBOARD)
qemu_remove_mouse_event_handler(s->ptr.eh_entry);
/* TODO: else */
qemu_free(s); qemu_free(s);
} }
USBDevice *usb_tablet_init(void) USBDevice *usb_tablet_init(void)
{ {
USBMouseState *s; USBHIDState *s;
s = qemu_mallocz(sizeof(USBMouseState)); s = qemu_mallocz(sizeof(USBHIDState));
if (!s) if (!s)
return NULL; return NULL;
s->dev.speed = USB_SPEED_FULL; s->dev.speed = USB_SPEED_FULL;
s->dev.handle_packet = usb_generic_handle_packet; s->dev.handle_packet = usb_generic_handle_packet;
s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_reset = usb_mouse_handle_reset;
s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_control = usb_hid_handle_control;
s->dev.handle_data = usb_mouse_handle_data; s->dev.handle_data = usb_hid_handle_data;
s->dev.handle_destroy = usb_mouse_handle_destroy; s->dev.handle_destroy = usb_hid_handle_destroy;
s->kind = USB_TABLET; s->kind = USB_TABLET;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
@ -533,21 +811,42 @@ USBDevice *usb_tablet_init(void)
USBDevice *usb_mouse_init(void) USBDevice *usb_mouse_init(void)
{ {
USBMouseState *s; USBHIDState *s;
s = qemu_mallocz(sizeof(USBMouseState)); s = qemu_mallocz(sizeof(USBHIDState));
if (!s) if (!s)
return NULL; return NULL;
s->dev.speed = USB_SPEED_FULL; s->dev.speed = USB_SPEED_FULL;
s->dev.handle_packet = usb_generic_handle_packet; s->dev.handle_packet = usb_generic_handle_packet;
s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_reset = usb_mouse_handle_reset;
s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_control = usb_hid_handle_control;
s->dev.handle_data = usb_mouse_handle_data; s->dev.handle_data = usb_hid_handle_data;
s->dev.handle_destroy = usb_mouse_handle_destroy; s->dev.handle_destroy = usb_hid_handle_destroy;
s->kind = USB_MOUSE; s->kind = USB_MOUSE;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
return (USBDevice *)s; return (USBDevice *)s;
} }
USBDevice *usb_keyboard_init(void)
{
USBHIDState *s;
s = qemu_mallocz(sizeof(USBHIDState));
if (!s)
return NULL;
s->dev.speed = USB_SPEED_FULL;
s->dev.handle_packet = usb_generic_handle_packet;
s->dev.handle_reset = usb_keyboard_handle_reset;
s->dev.handle_control = usb_hid_handle_control;
s->dev.handle_data = usb_hid_handle_data;
s->dev.handle_destroy = usb_hid_handle_destroy;
s->kind = USB_KEYBOARD;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard");
return (USBDevice *) s;
}

View File

@ -218,6 +218,7 @@ void usb_host_info(void);
/* usb-hid.c */ /* usb-hid.c */
USBDevice *usb_mouse_init(void); USBDevice *usb_mouse_init(void);
USBDevice *usb_tablet_init(void); USBDevice *usb_tablet_init(void);
USBDevice *usb_keyboard_init(void);
/* usb-msd.c */ /* usb-msd.c */
USBDevice *usb_msd_init(const char *filename); USBDevice *usb_msd_init(const char *filename);

View File

@ -1362,6 +1362,8 @@ Pass through the host device identified by @var{vendor_id:product_id}
Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet} Virtual Wacom PenPartner tablet. This device is similar to the @code{tablet}
above but it can be used with the tslib library because in addition to touch above but it can be used with the tslib library because in addition to touch
coordinates it reports touch pressure. coordinates it reports touch pressure.
@item @code{keyboard}
Standard USB keyboard. Will override the PS/2 keyboard (if present).
@end table @end table
@node host_usb_devices @node host_usb_devices

2
vl.c
View File

@ -4320,6 +4320,8 @@ static int usb_device_add(const char *devname)
dev = usb_mouse_init(); dev = usb_mouse_init();
} else if (!strcmp(devname, "tablet")) { } else if (!strcmp(devname, "tablet")) {
dev = usb_tablet_init(); dev = usb_tablet_init();
} else if (!strcmp(devname, "keyboard")) {
dev = usb_keyboard_init();
} else if (strstart(devname, "disk:", &p)) { } else if (strstart(devname, "disk:", &p)) {
dev = usb_msd_init(p); dev = usb_msd_init(p);
} else if (!strcmp(devname, "wacom-tablet")) { } else if (!strcmp(devname, "wacom-tablet")) {