This patch does some of the things we've been talking about.  It permits 
usb_reset_device() to run on a non-root hub, and it makes usb_reset_device 
responsible for disconnecting the children rather than khubd.

This is maybe not yet quite as robust as the existing code, because we 
don't retry and handle errors in hub_port_disable().  That's one reason 
why I'm not submitting it for inclusion.  But I would like to see what 
people think about this.

In a sense this implements the beginnings of the pre-reset and post-reset 
notifications needed for unsolicited resets.  These notifications are only 
sent to the hub driver and they don't propagate down the device tree.  But 
you can start to see how this might work.

I haven't tested this beyond making sure it doesn't interfere with normal 
device resets.  It's kind of hard to set up a situation where a non-root 
hub requires a reset!  (Maybe I'll try adding a special sysfs attribute 
that automatically resets its device...)

Alan Stern



===== drivers/usb/core/hub.c 1.180 vs edited =====
--- 1.180/drivers/usb/core/hub.c        Thu Jul  1 14:55:29 2004
+++ edited/drivers/usb/core/hub.c       Thu Jul  1 15:16:58 2004
@@ -811,52 +811,32 @@
        }
 }
 
-static int hub_reset(struct usb_hub *hub)
+static void hub_pre_reset(struct usb_device *hdev)
 {
-       struct usb_device *hdev = hub->hdev;
+       struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]);
        int i;
 
-       /* Disconnect any attached devices */
-       for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
+       usb_kill_urb(hub->urb);
+
+       for (i = 0; i < hdev->maxchild; ++i) {
                if (hdev->children[i])
                        usb_disconnect(&hdev->children[i]);
        }
-
-       /* Attempt to reset the hub */
-       if (hub->urb)
-               usb_kill_urb(hub->urb);
-       else
-               return -1;
-
-       if (usb_reset_device(hdev))
-               return -1;
-
-       hub->urb->dev = hdev;                                                    
-       if (usb_submit_urb(hub->urb, GFP_KERNEL))
-               return -1;
-
-       hub_power_on(hub);
-
-       return 0;
 }
 
-/* FIXME!  This routine should be subsumed into hub_reset */
-static void hub_start_disconnect(struct usb_device *hdev)
+static void hub_post_reset(struct usb_device *hdev)
 {
-       struct usb_device *parent = hdev->parent;
-       int i;
+       struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]);
+       int rc;
 
-       /* Find the device pointer to disconnect */
-       if (parent) {
-               for (i = 0; i < parent->maxchild; i++) {
-                       if (parent->children[i] == hdev) {
-                               usb_disconnect(&parent->children[i]);
-                               return;
-                       }
-               }
+       hub->urb->dev = hdev;
+       rc = usb_submit_urb(hub->urb, GFP_KERNEL);
+       if (rc) {
+               dev_err(&hub->intf->dev,
+                               "error submitting status urb: %d\n", rc);
+               return;
        }
-
-       dev_err(&hdev->dev, "cannot disconnect hub!\n");
+       hub_power_on(hub);
 }
 
 
@@ -1794,10 +1774,10 @@
                        dev_dbg (hub_dev, "resetting for error %d\n",
                                hub->error);
 
-                       if (hub_reset(hub)) {
+                       ret = usb_reset_device(hdev);
+                       if (ret) {
                                dev_dbg (hub_dev,
-                                       "can't reset; disconnecting\n");
-                               hub_start_disconnect(hdev);
+                                       "error resetting hub: %d\n", ret);
                                goto loop;
                        }
 
@@ -2059,6 +2039,7 @@
        struct usb_device_descriptor descriptor = udev->descriptor;
        int i, ret, port = -1;
        struct usb_hub *hub;
+       int udev_is_a_hub = 0;
 
        if (udev->state == USB_STATE_NOTATTACHED ||
                        udev->state == USB_STATE_SUSPENDED) {
@@ -2067,13 +2048,11 @@
                return -EINVAL;
        }
 
-       /* FIXME: This should be legal for regular hubs.  Root hubs may
-        * have special requirements. */
-       if (udev->maxchild) {
-               /* this requires hub- or hcd-specific logic;
-                * see hub_reset() and OHCI hc_restart()
+       if (!parent) {
+               /* this requires hcd-specific logic;
+                * see OHCI hc_restart()
                 */
-               dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__);
+               dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__);
                return -EISDIR;
        }
 
@@ -2089,6 +2068,14 @@
                return -ENOENT;
        }
 
+       /* If we're resetting an active hub, take some special actions */
+       if (udev->actconfig &&
+                       udev->actconfig->interface[0]->dev.driver ==
+                       &hub_driver.driver) {
+               udev_is_a_hub = 1;
+               hub_pre_reset(udev);
+       }
+
        /* ep0 maxpacket size may change; let the HCD know about it.
         * Other endpoints will be handled by re-enumeration. */
        usb_disable_endpoint(udev, 0);
@@ -2107,7 +2094,7 @@
        }
   
        if (!udev->actconfig)
-               return 0;
+               goto done;
 
        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                        USB_REQ_SET_CONFIGURATION, 0,
@@ -2141,6 +2128,9 @@
                }
        }
 
+done:
+       if (udev_is_a_hub)
+               hub_post_reset(udev);
        return 0;
  
 re_enumerate:




-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 - 
digital self defense, top technical experts, no vendor pitches, 
unmatched networking opportunities. Visit www.blackhat.com
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to