Greg:

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.

Please apply.

Alan Stern



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

===== drivers/usb/core/hub.c 1.200 vs edited =====
--- 1.200/drivers/usb/core/hub.c        Mon Sep 13 11:58:21 2004
+++ edited/drivers/usb/core/hub.c       Mon Sep 13 12:12:00 2004
@@ -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: YOU BE THE JUDGE. Be one of 170
Project Admins to receive an Apple iPod Mini FREE for your judgement on
who ports your project to Linux PPC the best. Sponsored by IBM. 
Deadline: Sept. 13. Go here: http://sf.net/ppc_contest.php
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to