In order to avoid having to poll for the result of an iso transfer
add the possibility to request the "complete" callback which is being
used for bulk transfers as well.

Signed-off-by: Juergen Gross <jgr...@suse.com>
---
 hw/usb/core.c        |  2 +-
 hw/usb/host-libusb.c | 24 ++++++++++++++++++++++--
 include/hw/usb.h     |  2 ++
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/hw/usb/core.c b/hw/usb/core.c
index cf34755..bc01713 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -428,7 +428,7 @@ void usb_handle_packet(USBDevice *dev, USBPacket *p)
         usb_process_one(p);
         if (p->status == USB_RET_ASYNC) {
             /* hcd drivers cannot handle async for isoc */
-            assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
+            assert(p->ep->type != USB_ENDPOINT_XFER_ISOC || p->isoc_complete);
             /* using async for interrupt packets breaks migration */
             assert(p->ep->type != USB_ENDPOINT_XFER_INT ||
                    (dev->flags & (1 << USB_DEV_FLAG_IS_HOST)));
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index a5f9dab..9e39b29 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -120,6 +120,7 @@ struct USBHostIsoXfer {
     struct libusb_transfer           *xfer;
     bool                             copy_complete;
     unsigned int                     packet;
+    QTAILQ_HEAD(, USBPacket)         callback;
     QTAILQ_ENTRY(USBHostIsoXfer)     next;
 };
 
@@ -432,6 +433,17 @@ static void usb_host_req_abort(USBHostRequest *r)
 
 /* ------------------------------------------------------------------------ */
 
+static void usb_host_iso_xfer_complete(USBHostIsoXfer *xfer)
+{
+    USBHostDevice *s = xfer->ring->host;
+    USBPacket *packet;
+
+    while ((packet = QTAILQ_FIRST(&xfer->callback)) != NULL) {
+        QTAILQ_REMOVE(&xfer->callback, packet, isoc_queue);
+        usb_packet_complete(USB_DEVICE(s), packet);
+    }
+}
+
 static void usb_host_req_complete_iso(struct libusb_transfer *transfer)
 {
     USBHostIsoXfer *xfer = transfer->user_data;
@@ -451,6 +463,7 @@ static void usb_host_req_complete_iso(struct 
libusb_transfer *transfer)
     if (xfer->ring->ep->pid == USB_TOKEN_IN) {
         QTAILQ_INSERT_TAIL(&xfer->ring->copy, xfer, next);
     } else {
+        usb_host_iso_xfer_complete(xfer);
         QTAILQ_INSERT_TAIL(&xfer->ring->unused, xfer, next);
     }
 }
@@ -654,6 +667,10 @@ static void usb_host_iso_data_out(USBHostDevice *s, 
USBPacket *p)
         usb_host_iso_reset_xfer(xfer);
         QTAILQ_INSERT_TAIL(&ring->copy, xfer, next);
     }
+    if (p->isoc_complete) {
+        p->status = USB_RET_ASYNC;
+        QTAILQ_INSERT_TAIL(&xfer->callback, p, isoc_queue);
+    }
     usb_host_iso_data_copy(xfer, p);
 
     if (QTAILQ_EMPTY(&ring->inflight)) {
@@ -671,6 +688,7 @@ static void usb_host_iso_data_out(USBHostDevice *s, 
USBPacket *p)
         rc = libusb_submit_transfer(xfer->xfer);
         if (rc != 0) {
             usb_host_libusb_error("libusb_submit_transfer [iso]", rc);
+            usb_host_iso_xfer_complete(xfer);
             QTAILQ_INSERT_TAIL(&ring->unused, xfer, next);
             if (rc == LIBUSB_ERROR_NO_DEVICE) {
                 disconnect = true;
@@ -1329,8 +1347,10 @@ static void usb_host_handle_data(USBDevice *udev, 
USBPacket *p)
         } else {
             usb_host_iso_data_out(s, p);
         }
-        trace_usb_host_req_complete(s->bus_num, s->addr, p,
-                                    p->status, p->actual_length);
+        if (p->status != USB_RET_ASYNC) {
+            trace_usb_host_req_complete(s->bus_num, s->addr, p,
+                                        p->status, p->actual_length);
+        }
         return;
     default:
         p->status = USB_RET_STALL;
diff --git a/include/hw/usb.h b/include/hw/usb.h
index b20b959..e8f5a63 100644
--- a/include/hw/usb.h
+++ b/include/hw/usb.h
@@ -398,6 +398,7 @@ struct USBPacket {
     uint64_t parameter; /* control transfers */
     bool short_not_ok;
     bool int_req;
+    bool isoc_complete;
     int status; /* USB_RET_* status code */
     int actual_length; /* Number of bytes actually transferred */
     /* Internal use by the USB layer.  */
@@ -405,6 +406,7 @@ struct USBPacket {
     USBCombinedPacket *combined;
     QTAILQ_ENTRY(USBPacket) queue;
     QTAILQ_ENTRY(USBPacket) combined_entry;
+    QTAILQ_ENTRY(USBPacket) isoc_queue;
 };
 
 struct USBCombinedPacket {
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

Reply via email to