/*
* QEMU USB HID devices
- *
+ *
* 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
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
int kind;
int protocol;
int idle;
+ int changed;
} USBHIDState;
/* mostly the same values as the Bochs USB Mouse device */
0x01, /* u8 bNumInterfaces; (1) */
0x01, /* u8 bConfigurationValue; */
0x04, /* u8 iConfiguration; */
- 0xa0, /* u8 bmAttributes;
+ 0xa0, /* u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
50, /* u8 MaxPower; */
-
+
/* USB 1.1:
* USB 2.0, single TT organization (mandatory):
* one interface, protocol 0
0x01, /* u8 if_bInterfaceSubClass; */
0x02, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
0x07, /* u8 if_iInterface; */
-
+
/* HID descriptor */
0x09, /* u8 bLength; */
0x21, /* u8 bDescriptorType; */
0x01, /* u8 bNumInterfaces; (1) */
0x01, /* u8 bConfigurationValue; */
0x05, /* u8 iConfiguration; */
- 0xa0, /* u8 bmAttributes;
+ 0xa0, /* u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
50, /* u8 MaxPower; */
-
+
/* USB 1.1:
* USB 2.0, single TT organization (mandatory):
* one interface, protocol 0
0x01, /* u8 bNumInterfaces; (1) */
0x01, /* u8 bConfigurationValue; */
0x06, /* u8 iConfiguration; */
- 0xa0, /* u8 bmAttributes;
+ 0xa0, /* u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
};
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,
- 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
+ 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
- 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
+ 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
0xC0, 0xC0,
};
static void usb_mouse_event(void *opaque,
int dx1, int dy1, int dz1, int buttons_state)
{
- USBMouseState *s = opaque;
+ USBHIDState *hs = opaque;
+ USBMouseState *s = &hs->ptr;
s->dx += dx1;
s->dy += dy1;
s->dz += dz1;
s->buttons_state = buttons_state;
+ hs->changed = 1;
}
static void usb_tablet_event(void *opaque,
int x, int y, int dz, int buttons_state)
{
- USBMouseState *s = opaque;
+ USBHIDState *hs = opaque;
+ USBMouseState *s = &hs->ptr;
s->x = x;
s->y = y;
s->dz += dz;
s->buttons_state = buttons_state;
+ hs->changed = 1;
}
static void usb_keyboard_event(void *opaque, int keycode)
{
- USBKeyboardState *s = opaque;
+ USBHIDState *hs = opaque;
+ USBKeyboardState *s = &hs->kbd;
uint8_t hid_code, key;
int i;
hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
s->modifiers &= ~(1 << 8);
+ hs->changed = 1;
+
switch (hid_code) {
case 0x00:
return;
return val;
}
-static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len)
+static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len)
{
int dx, dy, dz, b, l;
+ USBMouseState *s = &hs->ptr;
if (!s->mouse_grabbed) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s,
+ s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs,
0, "QEMU USB Mouse");
s->mouse_grabbed = 1;
}
-
+
dx = int_clamp(s->dx, -128, 127);
dy = int_clamp(s->dy, -128, 127);
dz = int_clamp(s->dz, -128, 127);
s->dx -= dx;
s->dy -= dy;
s->dz -= dz;
-
+
b = 0;
if (s->buttons_state & MOUSE_EVENT_LBUTTON)
b |= 0x01;
b |= 0x02;
if (s->buttons_state & MOUSE_EVENT_MBUTTON)
b |= 0x04;
-
+
buf[0] = b;
buf[1] = dx;
buf[2] = dy;
return l;
}
-static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
+static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len)
{
int dz, b, l;
+ USBMouseState *s = &hs->ptr;
if (!s->mouse_grabbed) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s,
+ s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
1, "QEMU USB Tablet");
s->mouse_grabbed = 1;
}
-
+
dz = int_clamp(s->dz, -128, 127);
s->dz -= dz;
{
USBHIDState *s = (USBHIDState *)dev;
- qemu_add_kbd_event_handler(usb_keyboard_event, &s->kbd);
+ qemu_add_kbd_event_handler(usb_keyboard_event, s);
s->protocol = 1;
}
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch(value >> 8) {
case USB_DT_DEVICE:
- memcpy(data, qemu_mouse_dev_descriptor,
+ memcpy(data, qemu_mouse_dev_descriptor,
sizeof(qemu_mouse_dev_descriptor));
ret = sizeof(qemu_mouse_dev_descriptor);
break;
case USB_DT_CONFIG:
if (s->kind == USB_MOUSE) {
- memcpy(data, qemu_mouse_config_descriptor,
+ memcpy(data, qemu_mouse_config_descriptor,
sizeof(qemu_mouse_config_descriptor));
ret = sizeof(qemu_mouse_config_descriptor);
} else if (s->kind == USB_TABLET) {
- memcpy(data, qemu_tablet_config_descriptor,
+ memcpy(data, qemu_tablet_config_descriptor,
sizeof(qemu_tablet_config_descriptor));
ret = sizeof(qemu_tablet_config_descriptor);
} else if (s->kind == USB_KEYBOARD) {
- memcpy(data, qemu_keyboard_config_descriptor,
+ memcpy(data, qemu_keyboard_config_descriptor,
sizeof(qemu_keyboard_config_descriptor));
ret = sizeof(qemu_keyboard_config_descriptor);
}
switch(value >> 8) {
case 0x22:
if (s->kind == USB_MOUSE) {
- memcpy(data, qemu_mouse_hid_report_descriptor,
+ memcpy(data, qemu_mouse_hid_report_descriptor,
sizeof(qemu_mouse_hid_report_descriptor));
ret = sizeof(qemu_mouse_hid_report_descriptor);
} else if (s->kind == USB_TABLET) {
- memcpy(data, qemu_tablet_hid_report_descriptor,
+ memcpy(data, qemu_tablet_hid_report_descriptor,
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,
+ memcpy(data, qemu_keyboard_hid_report_descriptor,
sizeof(qemu_keyboard_hid_report_descriptor));
ret = sizeof(qemu_keyboard_hid_report_descriptor);
}
break;
case GET_REPORT:
if (s->kind == USB_MOUSE)
- ret = usb_mouse_poll(&s->ptr, data, length);
+ ret = usb_mouse_poll(s, data, length);
else if (s->kind == USB_TABLET)
- ret = usb_tablet_poll(&s->ptr, data, length);
+ ret = usb_tablet_poll(s, data, length);
else if (s->kind == USB_KEYBOARD)
ret = usb_keyboard_poll(&s->kbd, data, length);
break;
switch(p->pid) {
case USB_TOKEN_IN:
if (p->devep == 1) {
+ /* TODO: Implement finite idle delays. */
+ if (!(s->changed || s->idle))
+ return USB_RET_NAK;
+ s->changed = 0;
if (s->kind == USB_MOUSE)
- ret = usb_mouse_poll(&s->ptr, p->data, p->len);
+ ret = usb_mouse_poll(s, p->data, p->len);
else if (s->kind == USB_TABLET)
- ret = usb_tablet_poll(&s->ptr, p->data, p->len);
+ ret = usb_tablet_poll(s, p->data, p->len);
else if (s->kind == USB_KEYBOARD)
ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
} else {
s->dev.handle_data = usb_hid_handle_data;
s->dev.handle_destroy = usb_hid_handle_destroy;
s->kind = USB_TABLET;
+ /* Force poll routine to be run and grab input the first time. */
+ s->changed = 1;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
s->dev.handle_data = usb_hid_handle_data;
s->dev.handle_destroy = usb_hid_handle_destroy;
s->kind = USB_MOUSE;
+ /* Force poll routine to be run and grab input the first time. */
+ s->changed = 1;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");