Browse Source

Merge remote-tracking branch 'remotes/kraxel/tags/usb-20200617-pull-request' into staging

usb-host: add hostdevice property, workaround libusb bug

# gpg: Signature made Wed 17 Jun 2020 11:47:37 BST
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/usb-20200617-pull-request:
  usb-host: workaround libusb bug
  usb: add hostdevice property to usb-host

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell 5 years ago
parent
commit
26bf4a2921
2 changed files with 76 additions and 14 deletions
  1. 75 14
      hw/usb/host-libusb.c
  2. 1 0
      hw/usb/trace-events

+ 75 - 14
hw/usb/host-libusb.c

@@ -80,6 +80,7 @@ struct USBHostDevice {
 
 
     /* properties */
     /* properties */
     struct USBAutoFilter             match;
     struct USBAutoFilter             match;
+    char                             *hostdevice;
     int32_t                          bootindex;
     int32_t                          bootindex;
     uint32_t                         iso_urb_count;
     uint32_t                         iso_urb_count;
     uint32_t                         iso_urb_frames;
     uint32_t                         iso_urb_frames;
@@ -97,6 +98,7 @@ struct USBHostDevice {
     int                              addr;
     int                              addr;
     char                             port[16];
     char                             port[16];
 
 
+    int                              hostfd;
     libusb_device                    *dev;
     libusb_device                    *dev;
     libusb_device_handle             *dh;
     libusb_device_handle             *dh;
     struct libusb_device_descriptor  ddesc;
     struct libusb_device_descriptor  ddesc;
@@ -880,26 +882,45 @@ static void usb_host_ep_update(USBHostDevice *s)
     libusb_free_config_descriptor(conf);
     libusb_free_config_descriptor(conf);
 }
 }
 
 
-static int usb_host_open(USBHostDevice *s, libusb_device *dev)
+static int usb_host_open(USBHostDevice *s, libusb_device *dev, int hostfd)
 {
 {
     USBDevice *udev = USB_DEVICE(s);
     USBDevice *udev = USB_DEVICE(s);
-    int bus_num = libusb_get_bus_number(dev);
-    int addr    = libusb_get_device_address(dev);
+    int bus_num = 0;
+    int addr = 0;
     int rc;
     int rc;
     Error *local_err = NULL;
     Error *local_err = NULL;
 
 
     if (s->bh_postld_pending) {
     if (s->bh_postld_pending) {
         return -1;
         return -1;
     }
     }
-
-    trace_usb_host_open_started(bus_num, addr);
-
     if (s->dh != NULL) {
     if (s->dh != NULL) {
         goto fail;
         goto fail;
     }
     }
-    rc = libusb_open(dev, &s->dh);
-    if (rc != 0) {
-        goto fail;
+
+    if (dev) {
+        bus_num = libusb_get_bus_number(dev);
+        addr = libusb_get_device_address(dev);
+        trace_usb_host_open_started(bus_num, addr);
+
+        rc = libusb_open(dev, &s->dh);
+        if (rc != 0) {
+            goto fail;
+        }
+    } else {
+#if LIBUSB_API_VERSION >= 0x01000107
+        trace_usb_host_open_hostfd(hostfd);
+
+        rc = libusb_wrap_sys_device(ctx, hostfd, &s->dh);
+        if (rc != 0) {
+            goto fail;
+        }
+        s->hostfd  = hostfd;
+        dev = libusb_get_device(s->dh);
+        bus_num = libusb_get_bus_number(dev);
+        addr = libusb_get_device_address(dev);
+#else
+        g_assert_not_reached();
+#endif
     }
     }
 
 
     s->dev     = dev;
     s->dev     = dev;
@@ -951,6 +972,7 @@ fail:
 static void usb_host_abort_xfers(USBHostDevice *s)
 static void usb_host_abort_xfers(USBHostDevice *s)
 {
 {
     USBHostRequest *r, *rtmp;
     USBHostRequest *r, *rtmp;
+    int limit = 100;
 
 
     QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) {
     QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) {
         usb_host_req_abort(r);
         usb_host_req_abort(r);
@@ -961,6 +983,19 @@ static void usb_host_abort_xfers(USBHostDevice *s)
         memset(&tv, 0, sizeof(tv));
         memset(&tv, 0, sizeof(tv));
         tv.tv_usec = 2500;
         tv.tv_usec = 2500;
         libusb_handle_events_timeout(ctx, &tv);
         libusb_handle_events_timeout(ctx, &tv);
+        if (--limit == 0) {
+            /*
+             * Don't wait forever for libusb calling the complete
+             * callback (which will unlink and free the request).
+             *
+             * Leaking memory here, to make sure libusb will not
+             * access memory which we have released already.
+             */
+            QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) {
+                QTAILQ_REMOVE(&s->requests, r, next);
+            }
+            return;
+        }
     }
     }
 }
 }
 
 
@@ -988,6 +1023,11 @@ static int usb_host_close(USBHostDevice *s)
     s->dh = NULL;
     s->dh = NULL;
     s->dev = NULL;
     s->dev = NULL;
 
 
+    if (s->hostfd != -1) {
+        close(s->hostfd);
+        s->hostfd = -1;
+    }
+
     usb_host_auto_check(NULL);
     usb_host_auto_check(NULL);
     return 0;
     return 0;
 }
 }
@@ -1025,9 +1065,6 @@ static libusb_device *usb_host_find_ref(int bus, int addr)
     libusb_device *ret = NULL;
     libusb_device *ret = NULL;
     int i, n;
     int i, n;
 
 
-    if (usb_host_init() != 0) {
-        return NULL;
-    }
     n = libusb_get_device_list(ctx, &devs);
     n = libusb_get_device_list(ctx, &devs);
     for (i = 0; i < n; i++) {
     for (i = 0; i < n; i++) {
         if (libusb_get_bus_number(devs[i]) == bus &&
         if (libusb_get_bus_number(devs[i]) == bus &&
@@ -1046,6 +1083,10 @@ static void usb_host_realize(USBDevice *udev, Error **errp)
     libusb_device *ldev;
     libusb_device *ldev;
     int rc;
     int rc;
 
 
+    if (usb_host_init() != 0) {
+        error_setg(errp, "failed to init libusb");
+        return;
+    }
     if (s->match.vendor_id > 0xffff) {
     if (s->match.vendor_id > 0xffff) {
         error_setg(errp, "vendorid out of range");
         error_setg(errp, "vendorid out of range");
         return;
         return;
@@ -1064,7 +1105,24 @@ static void usb_host_realize(USBDevice *udev, Error **errp)
     udev->auto_attach = 0;
     udev->auto_attach = 0;
     QTAILQ_INIT(&s->requests);
     QTAILQ_INIT(&s->requests);
     QTAILQ_INIT(&s->isorings);
     QTAILQ_INIT(&s->isorings);
+    s->hostfd = -1;
 
 
+#if LIBUSB_API_VERSION >= 0x01000107
+    if (s->hostdevice) {
+        int fd;
+        s->needs_autoscan = false;
+        fd = qemu_open(s->hostdevice, O_RDWR);
+        if (fd < 0) {
+            error_setg_errno(errp, errno, "failed to open %s", s->hostdevice);
+            return;
+        }
+        rc = usb_host_open(s, NULL, fd);
+        if (rc < 0) {
+            error_setg(errp, "failed to open host usb device %s", s->hostdevice);
+            return;
+        }
+    } else
+#endif
     if (s->match.addr && s->match.bus_num &&
     if (s->match.addr && s->match.bus_num &&
         !s->match.vendor_id &&
         !s->match.vendor_id &&
         !s->match.product_id &&
         !s->match.product_id &&
@@ -1077,7 +1135,7 @@ static void usb_host_realize(USBDevice *udev, Error **errp)
                        s->match.bus_num, s->match.addr);
                        s->match.bus_num, s->match.addr);
             return;
             return;
         }
         }
-        rc = usb_host_open(s, ldev);
+        rc = usb_host_open(s, ldev, 0);
         libusb_unref_device(ldev);
         libusb_unref_device(ldev);
         if (rc < 0) {
         if (rc < 0) {
             error_setg(errp, "failed to open host usb device %d:%d",
             error_setg(errp, "failed to open host usb device %d:%d",
@@ -1605,6 +1663,9 @@ static Property usb_host_dev_properties[] = {
     DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
     DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
     DEFINE_PROP_UINT32("vendorid",  USBHostDevice, match.vendor_id,  0),
     DEFINE_PROP_UINT32("vendorid",  USBHostDevice, match.vendor_id,  0),
     DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
     DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
+#if LIBUSB_API_VERSION >= 0x01000107
+    DEFINE_PROP_STRING("hostdevice", USBHostDevice, hostdevice),
+#endif
     DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
     DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
     DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames,   32),
     DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames,   32),
     DEFINE_PROP_BOOL("guest-reset", USBHostDevice,
     DEFINE_PROP_BOOL("guest-reset", USBHostDevice,
@@ -1723,7 +1784,7 @@ static void usb_host_auto_check(void *unused)
                 if (s->dh != NULL) {
                 if (s->dh != NULL) {
                     continue;
                     continue;
                 }
                 }
-                if (usb_host_open(s, devs[i]) < 0) {
+                if (usb_host_open(s, devs[i], 0) < 0) {
                     s->errcount++;
                     s->errcount++;
                     continue;
                     continue;
                 }
                 }

+ 1 - 0
hw/usb/trace-events

@@ -291,6 +291,7 @@ usb_mtp_file_monitor_event(int dev, const char *path, const char *s) "dev %d, pa
 
 
 # host-libusb.c
 # host-libusb.c
 usb_host_open_started(int bus, int addr) "dev %d:%d"
 usb_host_open_started(int bus, int addr) "dev %d:%d"
+usb_host_open_hostfd(int hostfd) "hostfd %d"
 usb_host_open_success(int bus, int addr) "dev %d:%d"
 usb_host_open_success(int bus, int addr) "dev %d:%d"
 usb_host_open_failure(int bus, int addr) "dev %d:%d"
 usb_host_open_failure(int bus, int addr) "dev %d:%d"
 usb_host_close(int bus, int addr) "dev %d:%d"
 usb_host_close(int bus, int addr) "dev %d:%d"