45e84a0
From c936f649d4a6b87cabe809170874f6b560cc0524 Mon Sep 17 00:00:00 2001
45e84a0
From: Gerd Hoffmann <kraxel@redhat.com>
45e84a0
Date: Thu, 5 Jan 2012 15:49:18 +0100
45e84a0
Subject: [PATCH 17/25] usb-host: properly release port on unplug & exit
45e84a0
45e84a0
Factor out port release into a separate function.  Call release function
45e84a0
in exit notifier too.  Add explicit call the USBDEVFS_RELEASE_PORT
45e84a0
ioctl, just closing the hub file handle seems not to be enougth.  Make
45e84a0
sure we release the port before resetting the device, otherwise host
45e84a0
drivers will not re-attach.
45e84a0
45e84a0
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
45e84a0
---
45e84a0
 usb-linux.c |   28 ++++++++++++++++++++--------
45e84a0
 1 files changed, 20 insertions(+), 8 deletions(-)
45e84a0
45e84a0
diff --git a/usb-linux.c b/usb-linux.c
45e84a0
index ed14bb1..749ce71 100644
45e84a0
--- a/usb-linux.c
45e84a0
+++ b/usb-linux.c
45e84a0
@@ -116,6 +116,7 @@ typedef struct USBHostDevice {
45e84a0
     USBDevice dev;
45e84a0
     int       fd;
45e84a0
     int       hub_fd;
45e84a0
+    int       hub_port;
45e84a0
45e84a0
     uint8_t   descr[8192];
45e84a0
     int       descr_len;
45e84a0
@@ -434,7 +435,7 @@ static int usb_host_claim_port(USBHostDevice *s)
45e84a0
 {
45e84a0
 #ifdef USBDEVFS_CLAIM_PORT
45e84a0
     char *h, hub_name[64], line[1024];
45e84a0
-    int hub_addr, portnr, ret;
45e84a0
+    int hub_addr, ret;
45e84a0
45e84a0
     snprintf(hub_name, sizeof(hub_name), "%d-%s",
45e84a0
              s->match.bus_num, s->match.port);
45e84a0
@@ -442,13 +443,13 @@ static int usb_host_claim_port(USBHostDevice *s)
45e84a0
     /* try strip off last ".$portnr" to get hub */
45e84a0
     h = strrchr(hub_name, '.');
45e84a0
     if (h != NULL) {
45e84a0
-        portnr = atoi(h+1);
45e84a0
+        s->hub_port = atoi(h+1);
45e84a0
         *h = '\0';
45e84a0
     } else {
45e84a0
         /* no dot in there -> it is the root hub */
45e84a0
         snprintf(hub_name, sizeof(hub_name), "usb%d",
45e84a0
                  s->match.bus_num);
45e84a0
-        portnr = atoi(s->match.port);
45e84a0
+        s->hub_port = atoi(s->match.port);
45e84a0
     }
45e84a0
45e84a0
     if (!usb_host_read_file(line, sizeof(line), "devnum",
45e84a0
@@ -469,20 +470,32 @@ static int usb_host_claim_port(USBHostDevice *s)
45e84a0
         return -1;
45e84a0
     }
45e84a0
45e84a0
-    ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
45e84a0
+    ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
45e84a0
     if (ret < 0) {
45e84a0
         close(s->hub_fd);
45e84a0
         s->hub_fd = -1;
45e84a0
         return -1;
45e84a0
     }
45e84a0
45e84a0
-    trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
45e84a0
+    trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
45e84a0
     return 0;
45e84a0
 #else
45e84a0
     return -1;
45e84a0
 #endif
45e84a0
 }
45e84a0
45e84a0
+static void usb_host_release_port(USBHostDevice *s)
45e84a0
+{
45e84a0
+    if (s->hub_fd == -1) {
45e84a0
+        return;
45e84a0
+    }
45e84a0
+#ifdef USBDEVFS_RELEASE_PORT
45e84a0
+    ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
45e84a0
+#endif
45e84a0
+    close(s->hub_fd);
45e84a0
+    s->hub_fd = -1;
45e84a0
+}
45e84a0
+
45e84a0
 static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
45e84a0
 {
45e84a0
     /* earlier Linux 2.4 do not support that */
45e84a0
@@ -635,10 +648,8 @@ static void usb_host_handle_destroy(USBDevice *dev)
45e84a0
 {
45e84a0
     USBHostDevice *s = (USBHostDevice *)dev;
45e84a0
45e84a0
+    usb_host_release_port(s);
45e84a0
     usb_host_close(s);
45e84a0
-    if (s->hub_fd != -1) {
45e84a0
-        close(s->hub_fd);
45e84a0
-    }
45e84a0
     QTAILQ_REMOVE(&hostdevs, s, next);
45e84a0
     qemu_remove_exit_notifier(&s->exit);
45e84a0
 }
45e84a0
@@ -1402,6 +1413,7 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data)
45e84a0
 {
45e84a0
     USBHostDevice *s = container_of(n, USBHostDevice, exit);
45e84a0
45e84a0
+    usb_host_release_port(s);
45e84a0
     if (s->fd != -1) {
45e84a0
         usb_host_do_reset(s);;
45e84a0
     }
45e84a0
-- 
45e84a0
1.7.7.5
45e84a0