summary refs log tree commit diff stats
path: root/hw/usb/redirect.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb/redirect.c')
-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);
         }
     }
 }