Greg:

This patch (as554) makes the hub driver disconnect any child USB devices 
when it is unbound from a hub.  Normally this will never happen, but there 
are a few oddball ways to unbind the hub driver while leaving the children 
intact.  For example, the new "unbind" sysfs attribute can be used for 
this purpose.

Given that unbinding hubs with children is now safe, the patch also
removes the code that prevented people from doing so using usbfs.

Alan Stern



Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

Index: usb-2.6/drivers/usb/core/hub.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/hub.c
+++ usb-2.6/drivers/usb/core/hub.c
@@ -729,10 +729,29 @@ fail:
 
 static unsigned highspeed_hubs;
 
+/* Called after the hub driver is unbound from a hub with children */
+static void hub_remove_children_work(void *__hub)
+{
+       struct usb_hub          *hub = __hub;
+       struct usb_device       *hdev = hub->hdev;
+       int                     i;
+
+       kfree(hub);
+
+       usb_lock_device(hdev);
+       for (i = 0; i < hdev->maxchild; ++i) {
+               if (hdev->children[i])
+                       usb_disconnect(&hdev->children[i]);
+       }
+       usb_unlock_device(hdev);
+       usb_put_dev(hdev);
+}
+
 static void hub_disconnect(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata (intf);
        struct usb_device *hdev;
+       int n, port1;
 
        usb_set_intfdata (intf, NULL);
        hdev = hub->hdev;
@@ -760,8 +779,27 @@ static void hub_disconnect(struct usb_in
                hub->buffer = NULL;
        }
 
-       /* Free the memory */
-       kfree(hub);
+       /* If there are any children then this is an unbind only, not a
+        * physical disconnection.  The active ports must be disabled
+        * and later on we must call usb_disconnect().  We can't call
+        * it now because we may not hold the hub's device lock.
+        */
+       n = 0;
+       for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+               if (hdev->children[port1 - 1]) {
+                       ++n;
+                       hub_port_disable(hub, port1, 1);
+               }
+       }
+
+       if (n == 0)
+               kfree(hub);
+       else {
+               /* Reuse the hub->leds work_struct for our own purposes */
+               INIT_WORK(&hub->leds, hub_remove_children_work, hub);
+               schedule_work(&hub->leds);
+               usb_get_dev(hdev);
+       }
 }
 
 static int hub_probe(struct usb_interface *intf, const struct usb_device_id 
*id)
Index: usb-2.6/drivers/usb/core/devio.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/devio.c
+++ usb-2.6/drivers/usb/core/devio.c
@@ -1283,7 +1283,6 @@ static int proc_ioctl (struct dev_state 
        int                     retval = 0;
        struct usb_interface    *intf = NULL;
        struct usb_driver       *driver = NULL;
-       int                     i;
 
        /* get input parameters and alloc buffer */
        if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
@@ -1315,15 +1314,6 @@ static int proc_ioctl (struct dev_state 
        /* disconnect kernel driver from interface */
        case USBDEVFS_DISCONNECT:
 
-               /* don't allow the user to unbind the hub driver from
-                * a hub with children to manage */
-               for (i = 0; i < ps->dev->maxchild; ++i) {
-                       if (ps->dev->children[i])
-                               retval = -EBUSY;
-               }
-               if (retval)
-                       break;
-
                down_write(&usb_bus_type.subsys.rwsem);
                if (intf->dev.driver) {
                        driver = to_usb_driver(intf->dev.driver);



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to