This is a note to let you know that I've just added the patch titled
Subject: USB: separate root and non-root suspend/resume
to my gregkh-2.6 tree. Its filename is
usb-separate-root-and-non-root-suspend-resume.patch
This tree can be found at
http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
>From [EMAIL PROTECTED] Wed May 30 12:34:45 2007
From: Alan Stern <[EMAIL PROTECTED]>
Date: Wed, 30 May 2007 15:34:36 -0400 (EDT)
Subject: USB: separate root and non-root suspend/resume
To: Greg KH <[EMAIL PROTECTED]>
Cc: USB development list <[email protected]>
Message-ID: <[EMAIL PROTECTED]>
This patch (as916) completes the separation of code paths for suspend
and resume of root hubs as opposed to non-root devices. Root hubs
will be power-managed through their bus_suspend and bus_resume
methods, whereas normal devices will use usb_port_suspend() and
usb_port_resume().
Changes to the hcd_bus_{suspend,resume} routines mostly represent
motion of code that was already present elsewhere. They include:
Adding debugging log messages,
Setting the device state appropriately, and
Adding a resume recovery time delay.
Changes to the port-suspend and port-resume routines in hub.c include:
Removal of checks for root devices (since they will never
be triggered), and
Removal of checks for NULL or invalid device pointers (these
were left over from earlier kernel versions and aren't needed
at all).
Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
---
drivers/usb/core/generic.c | 45 +++++++++++++------------------------
drivers/usb/core/hcd.c | 54 ++++++++++++++++++++++++++++-----------------
drivers/usb/core/hcd.h | 14 +----------
drivers/usb/core/hub.c | 42 ++++++-----------------------------
4 files changed, 60 insertions(+), 95 deletions(-)
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -196,20 +196,15 @@ static int generic_suspend(struct usb_de
{
int rc;
- rc = usb_port_suspend(udev);
-
- /* Root hubs don't have upstream ports to suspend,
- * so the line above won't do much for them. We have to
- * shut down their downstream HC-to-USB interfaces manually,
- * by doing a bus (or "global") suspend.
+ /* Normal USB devices suspend through their upstream port.
+ * Root hubs don't have upstream ports to suspend,
+ * so we have to shut down their downstream HC-to-USB
+ * interfaces manually by doing a bus (or "global") suspend.
*/
- if (rc == 0 && !udev->parent) {
- rc = hcd_bus_suspend(udev->bus);
- if (rc) {
- dev_dbg(&udev->dev, "'global' suspend %d\n", rc);
- usb_port_resume(udev);
- }
- }
+ if (!udev->parent)
+ rc = hcd_bus_suspend(udev);
+ else
+ rc = usb_port_suspend(udev);
return rc;
}
@@ -217,25 +212,17 @@ static int generic_resume(struct usb_dev
{
int rc;
- if (udev->reset_resume)
+ /* Normal USB devices resume/reset through their upstream port.
+ * Root hubs don't have upstream ports to resume or reset,
+ * so we have to start up their downstream HC-to-USB
+ * interfaces manually by doing a bus (or "global") resume.
+ */
+ if (!udev->parent)
+ rc = hcd_bus_resume(udev);
+ else if (udev->reset_resume)
rc = usb_reset_suspended_device(udev);
else
rc = usb_port_resume(udev);
-
- /* Root hubs don't have upstream ports to resume or reset,
- * so the line above won't do much for them. We have to
- * start up their downstream HC-to-USB interfaces manually,
- * by doing a bus (or "global") resume.
- */
- if (rc == 0 && !udev->parent) {
- rc = hcd_bus_resume(udev->bus);
- if (rc)
- dev_dbg(&udev->dev, "'global' resume %d\n", rc);
- else {
- /* TRSMRCY = 10 msec */
- msleep(10);
- }
- }
return rc;
}
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1257,40 +1257,54 @@ rescan:
#ifdef CONFIG_PM
-int hcd_bus_suspend (struct usb_bus *bus)
+int hcd_bus_suspend(struct usb_device *rhdev)
{
- struct usb_hcd *hcd;
- int status;
-
- hcd = container_of (bus, struct usb_hcd, self);
- if (!hcd->driver->bus_suspend)
- return -ENOENT;
- hcd->state = HC_STATE_QUIESCING;
- status = hcd->driver->bus_suspend (hcd);
- if (status == 0)
+ struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
+ int status;
+ int old_state = hcd->state;
+
+ dev_dbg(&rhdev->dev, "bus %s%s\n",
+ rhdev->auto_pm ? "auto-" : "", "suspend");
+ if (!hcd->driver->bus_suspend) {
+ status = -ENOENT;
+ } else {
+ hcd->state = HC_STATE_QUIESCING;
+ status = hcd->driver->bus_suspend(hcd);
+ }
+ if (status == 0) {
+ usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
hcd->state = HC_STATE_SUSPENDED;
- else
- dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+ } else {
+ hcd->state = old_state;
+ dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"suspend", status);
+ }
return status;
}
-int hcd_bus_resume (struct usb_bus *bus)
+int hcd_bus_resume(struct usb_device *rhdev)
{
- struct usb_hcd *hcd;
- int status;
+ struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
+ int status;
- hcd = container_of (bus, struct usb_hcd, self);
+ dev_dbg(&rhdev->dev, "usb %s%s\n",
+ rhdev->auto_pm ? "auto-" : "", "resume");
if (!hcd->driver->bus_resume)
return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
return 0;
+
hcd->state = HC_STATE_RESUMING;
- status = hcd->driver->bus_resume (hcd);
- if (status == 0)
+ status = hcd->driver->bus_resume(hcd);
+ if (status == 0) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+ usb_set_device_state(rhdev, rhdev->actconfig
+ ? USB_STATE_CONFIGURED
+ : USB_STATE_ADDRESS);
hcd->state = HC_STATE_RUNNING;
- else {
- dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+ } else {
+ dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"resume", status);
usb_hc_died(hcd);
}
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -364,23 +364,13 @@ extern int usb_find_interface_driver (st
#ifdef CONFIG_PM
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_root_hub_lost_power (struct usb_device *rhdev);
-extern int hcd_bus_suspend (struct usb_bus *bus);
-extern int hcd_bus_resume (struct usb_bus *bus);
+extern int hcd_bus_suspend(struct usb_device *rhdev);
+extern int hcd_bus_resume(struct usb_device *rhdev);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
-
-static inline int hcd_bus_suspend(struct usb_bus *bus)
-{
- return 0;
-}
-
-static inline int hcd_bus_resume (struct usb_bus *bus)
-{
- return 0;
-}
#endif /* CONFIG_PM */
/*
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1726,17 +1726,8 @@ int usb_port_suspend(struct usb_device *
{
int status = 0;
- /* we change the device's upstream USB link,
- * but root hubs have no upstream USB link.
- */
- if (udev->parent)
- status = hub_port_suspend(hdev_to_hub(udev->parent),
- udev->portnum, udev);
- else {
- dev_dbg(&udev->dev, "usb %ssuspend\n",
- udev->auto_pm ? "auto-" : "");
- usb_set_device_state(udev, USB_STATE_SUSPENDED);
- }
+ status = hub_port_suspend(hdev_to_hub(udev->parent),
+ udev->portnum, udev);
return status;
}
@@ -1779,8 +1770,7 @@ static int finish_port_resume(struct usb
status);
else if (udev->actconfig) {
le16_to_cpus(&devstatus);
- if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
- && udev->parent) {
+ if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE,
@@ -1793,10 +1783,6 @@ static int finish_port_resume(struct usb
"wakeup, status %d\n", status);
}
status = 0;
-
- } else if (udev->devnum <= 0) {
- dev_dbg(&udev->dev, "bogus resume!\n");
- status = -EINVAL;
}
return status;
}
@@ -1825,9 +1811,8 @@ hub_port_resume(struct usb_hub *hub, int
port1, status);
} else {
/* drive resume for at least 20 msec */
- if (udev)
- dev_dbg(&udev->dev, "usb %sresume\n",
- udev->auto_pm ? "auto-" : "");
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ udev->auto_pm ? "auto-" : "");
msleep(25);
#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
@@ -1855,8 +1840,7 @@ SuspendCleared:
USB_PORT_FEAT_C_SUSPEND);
/* TRSMRCY = 10 msec */
msleep(10);
- if (udev)
- status = finish_port_resume(udev);
+ status = finish_port_resume(udev);
}
}
if (status < 0)
@@ -1886,18 +1870,8 @@ int usb_port_resume(struct usb_device *u
{
int status;
- /* we change the device's upstream USB link,
- * but root hubs have no upstream USB link.
- */
- if (udev->parent) {
- // NOTE this fails if parent is also suspended...
- status = hub_port_resume(hdev_to_hub(udev->parent),
- udev->portnum, udev);
- } else {
- dev_dbg(&udev->dev, "usb %sresume\n",
- udev->auto_pm ? "auto-" : "");
- status = finish_port_resume(udev);
- }
+ status = hub_port_resume(hdev_to_hub(udev->parent),
+ udev->portnum, udev);
if (status < 0)
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
return status;
Patches currently in gregkh-2.6 which might be from [EMAIL PROTECTED] are
driver/driver-core-make-devt_attr-and-uevent_attr-static.patch
driver/sysfs-add-sysfs_dirent-s_name.patch
driver/sysfs-consolidate-sysfs_dirent-creation-functions.patch
driver/sysfs-add-sysfs_dirent-s_parent.patch
driver/sysfs-allocate-inode-number-using-ida.patch
driver/sysfs-kill-attribute-file-orphaning.patch
driver/sysfs-fix-error-handling-in-binattr-write.patch
driver/sysfs-flatten-and-fix-sysfs_rename_dir-error-handling.patch
driver/sysfs-flatten-cleanup-paths-in-sysfs_add_link-and-create_dir.patch
driver/sysfs-implement-bin_buffer.patch
driver/sysfs-implement-kobj_sysfs_assoc_lock.patch
driver/sysfs-implement-sysfs_dirent-active-reference-and-immediate-disconnect.patch
driver/sysfs-kill-unnecessary-attribute-owner.patch
driver/sysfs-make-sysfs_dirent-s_element-a-union.patch
driver/sysfs-make-sysfs_put-ignore-null-sd.patch
driver/sysfs-move-release_sysfs_dirent-to-dir.c.patch
driver/sysfs-reimplement-syfs_drop_dentry.patch
driver/sysfs-reimplement-symlink-using-sysfs_dirent-tree.patch
driver/sysfs-separate-out-sysfs_attach_dentry.patch
driver/ida-implement-idr-based-id-allocator.patch
driver/idr-fix-obscure-bug-in-allocation-path.patch
driver/idr-separate-out-idr_mark_full.patch
driver/sysfs-fix-parent-refcounting-during-rename-and-move.patch
driver/sysfs-fix-root-sysfs_dirent-root-dentry-association.patch
driver/sysfs-make-sysfs_alloc_ino-static.patch
driver/sysfs-move-s_active-functions-to-fs-sysfs-dir.c.patch
driver/sysfs-reorganize-sysfs_new_indoe-and-sysfs_create.patch
driver/sysfs-slim-down-sysfs_dirent-s_active.patch
driver/sysfs-use-iget_locked-instead-of-new_inode.patch
driver/sysfs-use-singly-linked-list-for-sysfs_dirent-tree.patch
usb/usb-add-usb-persist-facility.patch
usb/usb-core-hub.c-prevent-re-enumeration-on-hnp.patch
usb/usb-unusual_dev-sync-up-some-reported-devices-from-ubuntu.patch
usb/usb-add-reset_resume-device-quirk.patch
usb/ohci-fix-machine-check-in-ohci_hub_status_data.patch
usb/usb-don-t-unsuspend-for-a-new-connection.patch
usb/usb-implement-pm-freeze-and-prethaw.patch
usb/usb-disable-file_storage-usb_config_att_wakeup.patch
usb/usb-interface-pm-state.patch
usb/usb-make-hub-driver-s-release-more-robust.patch
usb/usb-move-bus_suspend-and-bus_resume-method-calls.patch
usb/usb-remove-locktree-routine-from-the-hub-driver.patch
usb/usb-remove-references-to-dev.power.power_state.patch
usb/usb-make-device-reset-stop-retrying-after-disconnect.patch
usb/usb-add-power-persist-device-attribute.patch
usb/usb-add-reset_resume-method.patch
usb/usb-g_file_storage-call-allow_signal.patch
usb/usb-remove-__usb_port_suspend.patch
usb/usb-remove-excess-code-from-hub.c.patch
usb/usb-separate-root-and-non-root-suspend-resume.patch
usb/usb-unify-reset_resume-and-normal-resume.patch
usb/usb-add-usb_device_and_interface_info-for-device-matching.patch
usb/usb-ehci-fix-handover-for-designated-full-speed-ports.patch
usb/usb-ehci-ohci-handover-changes.patch
usb/usb-prevent-char-device-open-deregister-race.patch
usb/usb-rework-c-style-comments.patch
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel