]> err.no Git - linux-2.6/blobdiff - drivers/usb/core/hub.c
USB: remove CONFIG_USB_PERSIST setting
[linux-2.6] / drivers / usb / core / hub.c
index 087e3bb70e090f4536417ca1156cea5abfc746f3..6dc589955d75da4a8d5edc37e52f7e8aaedfffe8 100644 (file)
 #include "hcd.h"
 #include "hub.h"
 
-#ifdef CONFIG_USB_PERSIST
-#define        USB_PERSIST     1
-#else
-#define        USB_PERSIST     0
-#endif
-
 /* if we are in debug mode, always announce new devices */
 #ifdef DEBUG
 #ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
@@ -644,6 +638,81 @@ static void hub_stop(struct usb_hub *hub)
        hub_quiesce(hub);
 }
 
+#define HUB_RESET              1
+#define HUB_RESUME             2
+#define HUB_RESET_RESUME       3
+
+#ifdef CONFIG_PM
+
+static void hub_restart(struct usb_hub *hub, int type)
+{
+       struct usb_device *hdev = hub->hdev;
+       int port1;
+
+       /* Check each of the children to see if they require
+        * USB-PERSIST handling or disconnection.  Also check
+        * each unoccupied port to make sure it is still disabled.
+        */
+       for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+               struct usb_device *udev = hdev->children[port1-1];
+               int status = 0;
+               u16 portstatus, portchange;
+
+               if (!udev || udev->state == USB_STATE_NOTATTACHED) {
+                       if (type != HUB_RESET) {
+                               status = hub_port_status(hub, port1,
+                                               &portstatus, &portchange);
+                               if (status == 0 && (portstatus &
+                                               USB_PORT_STAT_ENABLE))
+                                       clear_port_feature(hdev, port1,
+                                                       USB_PORT_FEAT_ENABLE);
+                       }
+                       continue;
+               }
+
+               /* Was the power session lost while we were suspended? */
+               switch (type) {
+               case HUB_RESET_RESUME:
+                       portstatus = 0;
+                       portchange = USB_PORT_STAT_C_CONNECTION;
+                       break;
+
+               case HUB_RESET:
+               case HUB_RESUME:
+                       status = hub_port_status(hub, port1,
+                                       &portstatus, &portchange);
+                       break;
+               }
+
+               /* For "USB_PERSIST"-enabled children we must
+                * mark the child device for reset-resume and
+                * turn off the various status changes to prevent
+                * khubd from disconnecting it later.
+                */
+               if (udev->persist_enabled && status == 0 &&
+                               !(portstatus & USB_PORT_STAT_ENABLE)) {
+                       if (portchange & USB_PORT_STAT_C_ENABLE)
+                               clear_port_feature(hub->hdev, port1,
+                                               USB_PORT_FEAT_C_ENABLE);
+                       if (portchange & USB_PORT_STAT_C_CONNECTION)
+                               clear_port_feature(hub->hdev, port1,
+                                               USB_PORT_FEAT_C_CONNECTION);
+                       udev->reset_resume = 1;
+               }
+
+               /* Otherwise for a reset_resume we must disconnect the child,
+                * but as we may not lock the child device here
+                * we have to do a "logical" disconnect.
+                */
+               else if (type == HUB_RESET_RESUME)
+                       hub_port_logical_disconnect(hub, port1);
+       }
+
+       hub_activate(hub);
+}
+
+#endif /* CONFIG_PM */
+
 /* caller has locked the hub device */
 static int hub_pre_reset(struct usb_interface *intf)
 {
@@ -1848,9 +1917,8 @@ static int finish_port_resume(struct usb_device *udev)
  * the host and the device is the same as it was when the device
  * suspended.
  *
- * If CONFIG_USB_PERSIST and @udev->reset_resume are both set then this
- * routine won't check that the port is still enabled.  Furthermore,
- * if @udev->reset_resume is set then finish_port_resume() above will
+ * If @udev->reset_resume is set then this routine won't check that the
+ * port is still enabled.  Furthermore, finish_port_resume() above will
  * reset @udev.  The end result is that a broken power session can be
  * recovered and @udev will appear to persist across a loss of VBUS power.
  *
@@ -1862,8 +1930,8 @@ static int finish_port_resume(struct usb_device *udev)
  * to it will be lost.  Using the USB_PERSIST facility, the device can be
  * made to appear as if it had not disconnected.
  *
- * This facility is inherently dangerous.  Although usb_reset_device()
- * makes every effort to insure that the same device is present after the
+ * This facility can be dangerous.  Although usb_reset_device() makes
+ * every effort to insure that the same device is present after the
  * reset as before, it cannot provide a 100% guarantee.  Furthermore it's
  * quite possible for a device to remain unaltered but its media to be
  * changed.  If the user replaces a flash memory card while the system is
@@ -1908,7 +1976,7 @@ int usb_port_resume(struct usb_device *udev)
                status = hub_port_status(hub, port1, &portstatus, &portchange);
 
  SuspendCleared:
-               if (USB_PERSIST && udev->reset_resume)
+               if (udev->reset_resume)
                        want_flags = USB_PORT_STAT_POWER
                                        | USB_PORT_STAT_CONNECTION;
                else
@@ -2015,49 +2083,20 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
 
 static int hub_resume(struct usb_interface *intf)
 {
-       struct usb_hub          *hub = usb_get_intfdata (intf);
-
-       dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
+       struct usb_hub *hub = usb_get_intfdata(intf);
 
-       /* tell khubd to look for changes on this hub */
-       hub_activate(hub);
+       dev_dbg(&intf->dev, "%s\n", __func__);
+       hub_restart(hub, HUB_RESUME);
        return 0;
 }
 
 static int hub_reset_resume(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata(intf);
-       struct usb_device *hdev = hub->hdev;
-       int port1;
 
+       dev_dbg(&intf->dev, "%s\n", __func__);
        hub_power_on(hub);
-
-       for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-               struct usb_device *child = hdev->children[port1-1];
-
-               if (child) {
-
-                       /* For "USB_PERSIST"-enabled children we must
-                        * mark the child device for reset-resume and
-                        * turn off the connect-change status to prevent
-                        * khubd from disconnecting it later.
-                        */
-                       if (USB_PERSIST && child->persist_enabled) {
-                               child->reset_resume = 1;
-                               clear_port_feature(hdev, port1,
-                                               USB_PORT_FEAT_C_CONNECTION);
-
-                       /* Otherwise we must disconnect the child,
-                        * but as we may not lock the child device here
-                        * we have to do a "logical" disconnect.
-                        */
-                       } else {
-                               hub_port_logical_disconnect(hub, port1);
-                       }
-               }
-       }
-
-       hub_activate(hub);
+       hub_restart(hub, HUB_RESET_RESUME);
        return 0;
 }
 
@@ -2067,10 +2106,10 @@ static int hub_reset_resume(struct usb_interface *intf)
  *
  * The USB host controller driver calls this function when its root hub
  * is resumed and Vbus power has been interrupted or the controller
- * has been reset.  The routine marks @rhdev as having lost power.  When
- * the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST
- * is enabled then it will carry out power-session recovery, otherwise
- * it will disconnect all the child devices.
+ * has been reset.  The routine marks @rhdev as having lost power.
+ * When the hub driver is resumed it will take notice and carry out
+ * power-session recovery for all the "USB-PERSIST"-enabled child devices;
+ * the others will be disconnected.
  */
 void usb_root_hub_lost_power(struct usb_device *rhdev)
 {