summaryrefslogtreecommitdiffstats
path: root/hw/usb/dev-hid.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb/dev-hid.c')
-rw-r--r--hw/usb/dev-hid.c139
1 files changed, 108 insertions, 31 deletions
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index b3dcd23109..b4ace04eef 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -23,10 +23,10 @@
* THE SOFTWARE.
*/
#include "hw/hw.h"
-#include "console.h"
+#include "ui/console.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
-#include "qemu-timer.h"
+#include "qemu/timer.h"
#include "hw/hid.h"
/* HID interface requests */
@@ -46,6 +46,7 @@ typedef struct USBHIDState {
USBDevice dev;
USBEndpoint *intr;
HIDState hid;
+ uint32_t usb_version;
} USBHIDState;
enum {
@@ -131,6 +132,36 @@ static const USBDescIface desc_iface_tablet = {
},
};
+static const USBDescIface desc_iface_tablet2 = {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceProtocol = 0x02,
+ .ndesc = 1,
+ .descs = (USBDescOther[]) {
+ {
+ /* HID descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_HID, /* u8 bDescriptorType */
+ 0x01, 0x00, /* u16 HID_class */
+ 0x00, /* u8 country_code */
+ 0x01, /* u8 num_descriptors */
+ USB_DT_REPORT, /* u8 type: Report */
+ 74, 0, /* u16 len */
+ },
+ },
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_IN | 0x01,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = 8,
+ .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */
+ },
+ },
+};
+
static const USBDescIface desc_iface_keyboard = {
.bInterfaceNumber = 0,
.bNumEndpoints = 1,
@@ -196,6 +227,23 @@ static const USBDescDevice desc_device_tablet = {
},
};
+static const USBDescDevice desc_device_tablet2 = {
+ .bcdUSB = 0x0200,
+ .bMaxPacketSize0 = 64,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG_TABLET,
+ .bmAttributes = 0xa0,
+ .bMaxPower = 50,
+ .nif = 1,
+ .ifs = &desc_iface_tablet2,
+ },
+ },
+};
+
static const USBDescDevice desc_device_keyboard = {
.bcdUSB = 0x0100,
.bMaxPacketSize0 = 8,
@@ -239,6 +287,20 @@ static const USBDesc desc_tablet = {
.str = desc_strings,
};
+static const USBDesc desc_tablet2 = {
+ .id = {
+ .idVendor = 0x0627,
+ .idProduct = 0x0001,
+ .bcdDevice = 0,
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT_TABLET,
+ .iSerialNumber = STR_SERIALNUMBER,
+ },
+ .full = &desc_device_tablet,
+ .high = &desc_device_tablet2,
+ .str = desc_strings,
+};
+
static const USBDesc desc_keyboard = {
.id = {
.idVendor = 0x0627,
@@ -371,7 +433,7 @@ static void usb_hid_handle_reset(USBDevice *dev)
hid_reset(&us->hid);
}
-static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
+static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
@@ -380,10 +442,9 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
- return ret;
+ return;
}
- ret = 0;
switch (request) {
/* hid specific requests */
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
@@ -392,15 +453,15 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
if (hs->kind == HID_MOUSE) {
memcpy(data, qemu_mouse_hid_report_descriptor,
sizeof(qemu_mouse_hid_report_descriptor));
- ret = sizeof(qemu_mouse_hid_report_descriptor);
+ p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
} else if (hs->kind == HID_TABLET) {
memcpy(data, qemu_tablet_hid_report_descriptor,
sizeof(qemu_tablet_hid_report_descriptor));
- ret = sizeof(qemu_tablet_hid_report_descriptor);
+ p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
} else if (hs->kind == HID_KEYBOARD) {
memcpy(data, qemu_keyboard_hid_report_descriptor,
sizeof(qemu_keyboard_hid_report_descriptor));
- ret = sizeof(qemu_keyboard_hid_report_descriptor);
+ p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
}
break;
default:
@@ -409,14 +470,14 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
break;
case GET_REPORT:
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- ret = hid_pointer_poll(hs, data, length);
+ p->actual_length = hid_pointer_poll(hs, data, length);
} else if (hs->kind == HID_KEYBOARD) {
- ret = hid_keyboard_poll(hs, data, length);
+ p->actual_length = hid_keyboard_poll(hs, data, length);
}
break;
case SET_REPORT:
if (hs->kind == HID_KEYBOARD) {
- ret = hid_keyboard_write(hs, data, length);
+ p->actual_length = hid_keyboard_write(hs, data, length);
} else {
goto fail;
}
@@ -425,61 +486,57 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
goto fail;
}
- ret = 1;
data[0] = hs->protocol;
+ p->actual_length = 1;
break;
case SET_PROTOCOL:
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
goto fail;
}
- ret = 0;
hs->protocol = value;
break;
case GET_IDLE:
- ret = 1;
data[0] = hs->idle;
+ p->actual_length = 1;
break;
case SET_IDLE:
hs->idle = (uint8_t) (value >> 8);
- hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
+ hid_set_next_idle(hs);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
hid_pointer_activate(hs);
}
- ret = 0;
break;
default:
fail:
- ret = USB_RET_STALL;
+ p->status = USB_RET_STALL;
break;
}
- return ret;
}
-static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
+static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
{
USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
HIDState *hs = &us->hid;
uint8_t buf[p->iov.size];
- int ret = 0;
+ int len = 0;
switch (p->pid) {
case USB_TOKEN_IN:
if (p->ep->nr == 1) {
- int64_t curtime = qemu_get_clock_ns(vm_clock);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
hid_pointer_activate(hs);
}
- if (!hid_has_events(hs) &&
- (!hs->idle || hs->next_idle_clock - curtime > 0)) {
- return USB_RET_NAK;
+ if (!hid_has_events(hs)) {
+ p->status = USB_RET_NAK;
+ return;
}
- hid_set_next_idle(hs, curtime);
+ hid_set_next_idle(hs);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
- ret = hid_pointer_poll(hs, buf, p->iov.size);
+ len = hid_pointer_poll(hs, buf, p->iov.size);
} else if (hs->kind == HID_KEYBOARD) {
- ret = hid_keyboard_poll(hs, buf, p->iov.size);
+ len = hid_keyboard_poll(hs, buf, p->iov.size);
}
- usb_packet_copy(p, buf, ret);
+ usb_packet_copy(p, buf, len);
} else {
goto fail;
}
@@ -487,10 +544,9 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_OUT:
default:
fail:
- ret = USB_RET_STALL;
+ p->status = USB_RET_STALL;
break;
}
- return ret;
}
static void usb_hid_handle_destroy(USBDevice *dev)
@@ -512,6 +568,21 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
static int usb_tablet_initfn(USBDevice *dev)
{
+ USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+
+ switch (us->usb_version) {
+ case 1:
+ dev->usb_desc = &desc_tablet;
+ break;
+ case 2:
+ dev->usb_desc = &desc_tablet2;
+ break;
+ default:
+ error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)",
+ us->usb_version);
+ return -1;
+ }
+
return usb_hid_initfn(dev, HID_TABLET);
}
@@ -566,8 +637,14 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
uc->handle_control = usb_hid_handle_control;
uc->handle_data = usb_hid_handle_data;
uc->handle_destroy = usb_hid_handle_destroy;
+ uc->handle_attach = usb_desc_attach;
}
+static Property usb_tablet_properties[] = {
+ DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -576,8 +653,8 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
usb_hid_class_initfn(klass, data);
uc->init = usb_tablet_initfn;
uc->product_desc = "QEMU USB Tablet";
- uc->usb_desc = &desc_tablet;
dc->vmsd = &vmstate_usb_ptr;
+ dc->props = usb_tablet_properties;
}
static TypeInfo usb_tablet_info = {