Signed-off-by: Hans de Goede <hdego...@redhat.com> --- hw/usb/dev-hid.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-)
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index aa59ec4..69f89ff 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -45,6 +45,7 @@ typedef struct USBHIDState { USBDevice dev; USBEndpoint *intr; + USBPacket *async_packet_pending; HIDState hid; } USBHIDState; @@ -357,10 +358,30 @@ static const uint8_t qemu_keyboard_hid_report_descriptor[] = { 0xc0, /* End Collection */ }; +static void usb_data_in_complete(HIDState *hs, USBPacket *p) +{ + uint8_t buf[p->iov.size]; + int len = 0; + + hid_set_next_idle(hs); + if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { + len = hid_pointer_poll(hs, buf, p->iov.size); + } else if (hs->kind == HID_KEYBOARD) { + len = hid_keyboard_poll(hs, buf, p->iov.size); + } + usb_packet_copy(p, buf, len); +} + static void usb_hid_changed(HIDState *hs) { USBHIDState *us = container_of(hs, USBHIDState, hid); + if (us->async_packet_pending) { + us->async_packet_pending->status = USB_RET_SUCCESS; /* Clear ASYNC */ + usb_data_in_complete(hs, us->async_packet_pending); + usb_packet_complete(&us->dev, us->async_packet_pending); + us->async_packet_pending = NULL; + } usb_wakeup(us->intr); } @@ -455,8 +476,6 @@ 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 len = 0; switch (p->pid) { case USB_TOKEN_IN: @@ -465,16 +484,12 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) hid_pointer_activate(hs); } if (!hid_has_events(hs)) { - p->status = USB_RET_NAK; + assert(us->async_packet_pending == NULL); + us->async_packet_pending = p; + p->status = USB_RET_ASYNC; return; } - hid_set_next_idle(hs); - if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { - len = hid_pointer_poll(hs, buf, p->iov.size); - } else if (hs->kind == HID_KEYBOARD) { - len = hid_keyboard_poll(hs, buf, p->iov.size); - } - usb_packet_copy(p, buf, len); + usb_data_in_complete(hs, p); } else { goto fail; } @@ -487,6 +502,14 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) } } +static void usb_hid_cancel_packet(USBDevice *dev, USBPacket *p) +{ + USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); + + assert(us->async_packet_pending == p); + us->async_packet_pending = NULL; +} + static void usb_hid_handle_destroy(USBDevice *dev) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); @@ -560,6 +583,7 @@ 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->cancel_packet = usb_hid_cancel_packet; } static void usb_tablet_class_initfn(ObjectClass *klass, void *data) -- 1.7.12.1