ChangeSet 1.1867.3.14, 2004/09/14 12:16:46-07:00, [EMAIL PROTECTED]

[PATCH] USB: Allow device resets for hubs

This patch adds support for calling usb_reset_device() on hubs (other than
root hubs).  It uses some of the new routines added recently by David
Brownell to shorten and simplify the code.  The only place where this is
called is if khubd encounters a serious error with a hub, so I don't
expect it to turn up very often in ordinary use.


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


 drivers/usb/core/hub.c |   82 +++++++++++++++++--------------------------------
 1 files changed, 29 insertions(+), 53 deletions(-)


diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c    2004-10-19 08:13:16 -07:00
+++ b/drivers/usb/core/hub.c    2004-10-19 08:13:16 -07:00
@@ -651,8 +651,6 @@
                flush_scheduled_work();
 }
 
-#ifdef CONFIG_USB_SUSPEND
-
 static void hub_reactivate(struct usb_hub *hub)
 {
        int     status;
@@ -665,8 +663,6 @@
                schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);
 }
 
-#endif
-
 static void hub_disconnect(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata (intf);
@@ -808,54 +804,26 @@
        }
 }
 
-/* caller has locked the hub and must own the device lock */
-static int hub_reset(struct usb_hub *hub)
+/* caller has locked the hub device */
+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++) {
+       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;
+       hub_quiesce(hub);
 }
 
-/* caller has locked the hub */
-/* FIXME!  This routine should be subsumed into hub_reset */
-static void hub_start_disconnect(struct usb_device *hdev)
+/* caller has locked the hub device */
+static void hub_post_reset(struct usb_device *hdev)
 {
-       struct usb_device *parent = hdev->parent;
-       int i;
-
-       /* 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;
-                       }
-               }
-       }
+       struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]);
 
-       dev_err(&hdev->dev, "cannot disconnect hub!\n");
+       hub_reactivate(hub);
+       hub_power_on(hub);
 }
 
 
@@ -2493,10 +2461,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;
                        }
 
@@ -2767,6 +2735,7 @@
        struct usb_device *parent = udev->parent;
        struct usb_device_descriptor descriptor = udev->descriptor;
        int i, ret, port = -1;
+       int udev_is_a_hub = 0;
 
        if (udev->state == USB_STATE_NOTATTACHED ||
                        udev->state == USB_STATE_SUSPENDED) {
@@ -2775,13 +2744,9 @@
                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()
-                */
-               dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__);
+       if (!parent) {
+               /* this requires hcd-specific logic; see OHCI hc_restart() */
+               dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__);
                return -EISDIR;
        }
 
@@ -2797,6 +2762,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);
@@ -2815,7 +2788,7 @@
        }
   
        if (!udev->actconfig)
-               return 0;
+               goto done;
 
        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                        USB_REQ_SET_CONFIGURATION, 0,
@@ -2849,6 +2822,9 @@
                }
        }
 
+done:
+       if (udev_is_a_hub)
+               hub_post_reset(udev);
        return 0;
  
 re_enumerate:



-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal
Use IT products in your business? Tell us what you think of them. Give us
Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to