aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb/redirect.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 66637a85da..490c90fae1 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -662,21 +662,22 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
usbredir_handle_status(dev, p, status);
}
+/*
+ * Handle interrupt out data, the usbredir protocol expects us to do this
+ * async, so that it can report back a completion status. But guests will
+ * expect immediate completion for an interrupt endpoint, and handling this
+ * async causes migration issues. So we report success directly, counting
+ * on the fact that output interrupt packets normally always succeed.
+ */
static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
- /* Output interrupt endpoint, normal async operation */
struct usb_redir_interrupt_packet_header interrupt_packet;
uint8_t buf[p->iov.size];
DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
p->iov.size, p->id);
- if (usbredir_already_in_flight(dev, p->id)) {
- p->status = USB_RET_ASYNC;
- return;
- }
-
interrupt_packet.endpoint = ep;
interrupt_packet.length = p->iov.size;
@@ -685,7 +686,6 @@ static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev,
usbredirparser_send_interrupt_packet(dev->parser, p->id,
&interrupt_packet, buf, p->iov.size);
usbredirparser_do_write(dev->parser);
- p->status = USB_RET_ASYNC;
}
static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
@@ -1647,11 +1647,13 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
/* 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) {
- usbredir_handle_status(dev, p, interrupt_packet->status);
- p->actual_length = interrupt_packet->length;
- usb_packet_complete(&dev->dev, p);
+ /*
+ * We report output interrupt packets as completed directly upon
+ * submission, so all we can do here if one failed is warn.
+ */
+ if (interrupt_packet->status) {
+ WARNING("interrupt output failed status %d ep %02X id %"PRIu64"\n",
+ interrupt_packet->status, ep, id);
}
}
}