#endif /* CONFIG_USB_SUSPEND */
 
-static int usb_suspend(struct device *dev, pm_message_t message)
+/**
+ * usb_external_suspend_device - external suspend of a USB device and its interfaces
+ * @udev: the usb_device to suspend
+ * @msg: Power Management message describing this state transition
+ *
+ * This routine handles external suspend requests: ones not generated
+ * internally by a USB driver (autosuspend) but rather coming from the user
+ * (via sysfs) or the PM core (system sleep).  The suspend will be carried
+ * out regardless of @udev's usage counter or those of its interfaces,
+ * and regardless of whether or not remote wakeup is enabled.  Of course,
+ * interface drivers still have the option of failing the suspend (if
+ * there are unsuspended children, for example).
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
        int     status;
 
-       if (is_usb_device(dev)) {
-               struct usb_device *udev = to_usb_device(dev);
-
-               usb_pm_lock(udev);
-               udev->auto_pm = 0;
-               status = usb_suspend_both(udev, message);
-               usb_pm_unlock(udev);
-       } else
-               status = 0;
+       usb_pm_lock(udev);
+       udev->auto_pm = 0;
+       status = usb_suspend_both(udev, msg);
+       usb_pm_unlock(udev);
        return status;
 }
 
-static int usb_resume(struct device *dev)
+/**
+ * usb_external_resume_device - external resume of a USB device and its interfaces
+ * @udev: the usb_device to resume
+ *
+ * This routine handles external resume requests: ones not generated
+ * internally by a USB driver (autoresume) but rather coming from the user
+ * (via sysfs), the PM core (system resume), or the device itself (remote
+ * wakeup).  @udev's usage counter is unaffected.
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_external_resume_device(struct usb_device *udev)
 {
        int     status;
 
-       if (is_usb_device(dev)) {
-               struct usb_device *udev = to_usb_device(dev);
-
-               usb_pm_lock(udev);
-               udev->auto_pm = 0;
-               status = usb_resume_both(udev);
-               usb_pm_unlock(udev);
+       usb_pm_lock(udev);
+       udev->auto_pm = 0;
+       status = usb_resume_both(udev);
+       usb_pm_unlock(udev);
 
-               /* Rebind drivers that had no suspend method? */
-       } else
-               status = 0;
+       /* Now that the device is awake, we can start trying to autosuspend
+        * it again. */
+       if (status == 0)
+               usb_try_autosuspend_device(udev);
        return status;
 }
 
+static int usb_suspend(struct device *dev, pm_message_t message)
+{
+       if (!is_usb_device(dev))        /* Ignore PM for interfaces */
+               return 0;
+       return usb_external_suspend_device(to_usb_device(dev), message);
+}
+
+static int usb_resume(struct device *dev)
+{
+       if (!is_usb_device(dev))        /* Ignore PM for interfaces */
+               return 0;
+       return usb_external_resume_device(to_usb_device(dev));
+}
+
+#else
+
+#define usb_suspend    NULL
+#define usb_resume     NULL
+
 #endif /* CONFIG_PM */
 
 struct bus_type usb_bus_type = {
        .name =         "usb",
        .match =        usb_device_match,
        .uevent =       usb_uevent,
-#ifdef CONFIG_PM
        .suspend =      usb_suspend,
        .resume =       usb_resume,
-#endif
 };
 
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 #include <linux/platform_device.h>
+#include <linux/workqueue.h>
 
 #include <linux/usb.h>
 
        return status;
 }
 
+/* Workqueue routine for root-hub remote wakeup */
+static void hcd_resume_work(struct work_struct *work)
+{
+       struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work);
+       struct usb_device *udev = hcd->self.root_hub;
+
+       usb_lock_device(udev);
+       usb_external_resume_device(udev);
+       usb_unlock_device(udev);
+}
+
 /**
  * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
  * @hcd: host controller for this root hub
  *
  * The USB host controller calls this function when its root hub is
  * suspended (with the remote wakeup feature enabled) and a remote
- * wakeup request is received.  It queues a request for khubd to
- * resume the root hub (that is, manage its downstream ports again).
+ * wakeup request is received.  The routine submits a workqueue request
+ * to resume the root hub (that is, manage its downstream ports again).
  */
 void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 {
 
        spin_lock_irqsave (&hcd_root_hub_lock, flags);
        if (hcd->rh_registered)
-               usb_resume_root_hub (hcd->self.root_hub);
+               queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
        spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
        init_timer(&hcd->rh_timer);
        hcd->rh_timer.function = rh_timer_func;
        hcd->rh_timer.data = (unsigned long) hcd;
+#ifdef CONFIG_PM
+       INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
+#endif
 
        hcd->driver = driver;
        hcd->product_desc = (driver->product_desc) ? driver->product_desc :
        hcd->rh_registered = 0;
        spin_unlock_irq (&hcd_root_hub_lock);
 
+#ifdef CONFIG_PM
+       flush_workqueue(ksuspend_usb_wq);
+#endif
+
        mutex_lock(&usb_bus_list_lock);
        usb_disconnect(&hcd->self.root_hub);
        mutex_unlock(&usb_bus_list_lock);
 
 
        struct timer_list       rh_timer;       /* drives root-hub polling */
        struct urb              *status_urb;    /* the current status urb */
+#ifdef CONFIG_PM
+       struct work_struct      wakeup_work;    /* for remote wakeup */
+#endif
 
        /*
         * hardware info/state
 
        usb_lock_device(udev);
        if (udev->state == USB_STATE_SUSPENDED) {
                dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
-               status = usb_autoresume_device(udev);
-
-               /* Give the interface drivers a chance to do something,
-                * then autosuspend the device again. */
-               if (status == 0)
-                       usb_autosuspend_device(udev);
+               status = usb_external_resume_device(udev);
        }
        usb_unlock_device(udev);
        return status;
 #define hub_resume NULL
 #endif
 
-void usb_resume_root_hub(struct usb_device *hdev)
-{
-       struct usb_hub *hub = hdev_to_hub(hdev);
-
-       kick_khubd(hub);
-}
-
 
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
  *
 
 
 static int nousb;      /* Disable USB when built into kernel image */
 
-struct workqueue_struct *ksuspend_usb_wq;      /* For autosuspend */
+/* Workqueue for autosuspend and for remote wakeup of root hubs */
+struct workqueue_struct *ksuspend_usb_wq;
 
 #ifdef CONFIG_USB_SUSPEND
 static int usb_autosuspend_delay = 2;          /* Default delay value,
 
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 
 extern void usb_kick_khubd(struct usb_device *dev);
-extern void usb_resume_root_hub(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,
                            const struct usb_device_id *id);
 
 extern void usb_autosuspend_work(struct work_struct *work);
 extern int usb_port_suspend(struct usb_device *dev);
 extern int usb_port_resume(struct usb_device *dev);
+extern int usb_external_suspend_device(struct usb_device *udev,
+               pm_message_t msg);
+extern int usb_external_resume_device(struct usb_device *udev);
 
 static inline void usb_pm_lock(struct usb_device *udev)
 {