@@ -68,6 +68,7 @@ struct endp_data {
QTAILQ_HEAD(, buf_packet) bufpq;
int32_t bufpq_size;
int32_t bufpq_target_size;
+ USBPacket *pending_async_packet;
};
struct PacketIdQueueEntry {
@@ -323,12 +324,23 @@ static void packet_id_queue_empty(struct PacketIdQueue *q)
static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+ int ep_idx;
if (p->combined) {
usb_combined_packet_cancel(udev, p);
return;
}
+ ep_idx = p->ep->nr;
+ if (p->pid == USB_TOKEN_IN) {
+ ep_idx += 16;
+ }
+ if (dev->endpoint[ep_idx].pending_async_packet) {
+ assert(dev->endpoint[ep_idx].pending_async_packet == p);
+ dev->endpoint[ep_idx].pending_async_packet = NULL;
+ return;
+ }
+
packet_id_queue_add(&dev->cancelled, p->id);
usbredirparser_send_cancel_data_packet(dev->parser, p->id);
usbredirparser_do_write(dev->parser);
@@ -366,8 +378,12 @@ static void usbredir_fill_already_in_flight(USBRedirDevice *dev)
usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl);
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]);
- usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]);
+ if (udev->ep_in[ep].type == USB_ENDPOINT_XFER_BULK) {
+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]);
+ }
+ if (udev->ep_out[ep].type == USB_ENDPOINT_XFER_BULK) {
+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]);
+ }
}
}
@@ -620,12 +636,25 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
p->status = USB_RET_ASYNC;
}
+static void usbredir_interrupt_in_complete(USBRedirDevice *dev, USBPacket *p,
+ uint8_t ep, int status, uint8_t *data, int len)
+{
+ DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, status, len);
+
+ if (len > p->iov.size) {
+ ERROR("received int data is larger then packet ep %02X\n", ep);
+ len = p->iov.size;
+ status = usb_redir_babble;
+ }
+ usb_packet_copy(p, data, len);
+ usbredir_handle_status(dev, p, status);
+}
+
static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
/* Input interrupt endpoint, buffered packet input */
struct buf_packet *intp;
- int status, len;
if (!dev->endpoint[EP2I(ep)].interrupt_started &&
QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
@@ -647,22 +676,15 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
if (intp == NULL) {
DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
- p->status = USB_RET_NAK;
+ assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
+ dev->endpoint[EP2I(ep)].pending_async_packet = p;
+ p->status = USB_RET_ASYNC;
return;
}
- DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
- intp->status, intp->len);
- status = intp->status;
- len = intp->len;
- if (len > p->iov.size) {
- ERROR("received int data is larger then packet ep %02X\n", ep);
- len = p->iov.size;
- status = usb_redir_babble;
- }
- usb_packet_copy(p, intp->data, len);
+ usbredir_interrupt_in_complete(dev, p, ep, intp->status,
+ intp->data, intp->len);
bufp_free(dev, intp, ep);
- usbredir_handle_status(dev, p, status);
}
static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev,
@@ -1661,8 +1683,16 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
return;
}
- /* bufp_alloc also adds the packet to the ep queue */
- bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
+ if (dev->endpoint[EP2I(ep)].pending_async_packet) {
+ USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet;
+ usbredir_interrupt_in_complete(dev, p, ep,
+ interrupt_packet->status, data, data_len);
+ usb_packet_complete(&dev->dev, p);
+ dev->endpoint[EP2I(ep)].pending_async_packet = NULL;
+ } else {
+ /* bufp_alloc also adds the packet to the ep queue */
+ bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
+ }
} else {
USBPacket *p = usbredir_find_packet_by_id(dev, ep, id);
if (p) {
This allows to hcd code to slow down its timer, rather then having to poll us every ms. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- hw/usb/redirect.c | 64 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 17 deletions(-)