aboutsummaryrefslogtreecommitdiffstats
path: root/usb.current
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2008-08-20 13:07:31 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2008-08-20 13:07:31 -0700
commit0fadf3ad444c16aae5fd9256d4bd3f285f89c297 (patch)
treee0ba850b8af629d6ed0d7763271417a477dbb38c /usb.current
parent96299169f566ff0059bbcabb7555dbcf4ddc7f69 (diff)
downloadpatches-0fadf3ad444c16aae5fd9256d4bd3f285f89c297.tar.gz
move some usb patches to usb.current
Diffstat (limited to 'usb.current')
-rw-r--r--usb.current/usb-add-new-pm-callback-methods-for-usb.patch184
-rw-r--r--usb.current/usb-add-udev-argument-to-interface-suspend-resume-functions.patch97
-rw-r--r--usb.current/usb-defer-set-interface-for-suspended-devices.patch103
-rw-r--r--usb.current/usb-don-t-rebind-before-complete-callback.patch92
4 files changed, 476 insertions, 0 deletions
diff --git a/usb.current/usb-add-new-pm-callback-methods-for-usb.patch b/usb.current/usb-add-new-pm-callback-methods-for-usb.patch
new file mode 100644
index 00000000000000..8ec19a4c62b787
--- /dev/null
+++ b/usb.current/usb-add-new-pm-callback-methods-for-usb.patch
@@ -0,0 +1,184 @@
+From stern+48acf28e@rowland.harvard.edu Tue Aug 12 11:34:16 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 12 Aug 2008 14:34:10 -0400 (EDT)
+Subject: USB: Add new PM callback methods for USB
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0808121430520.2248-100000@iolanthe.rowland.org>
+
+
+This patch (as1129) adds support for the new PM callbacks to usbcore.
+The new callbacks merely invoke the same old USB power management
+routines as the old ones did.
+
+A minor improvement is that the callbacks are present only in the
+"USB-device" device_type structure, rather than in the bus_type
+structure. This way they will be invoked only for USB devices, not
+for USB interfaces. The core USB PM routines automatically handle
+suspending and resuming interfaces along with their devices.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/driver.c | 15 +--------
+ drivers/usb/core/usb.c | 73 ++++++++++++++++++++++++++++++++++++++++++----
+ drivers/usb/core/usb.h | 3 +
+ 3 files changed, 72 insertions(+), 19 deletions(-)
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -1630,12 +1630,10 @@ int usb_external_resume_device(struct us
+ return status;
+ }
+
+-static int usb_suspend(struct device *dev, pm_message_t message)
++int usb_suspend(struct device *dev, pm_message_t message)
+ {
+ struct usb_device *udev;
+
+- if (!is_usb_device(dev)) /* Ignore PM for interfaces */
+- return 0;
+ udev = to_usb_device(dev);
+
+ /* If udev is already suspended, we can skip this suspend and
+@@ -1654,12 +1652,10 @@ static int usb_suspend(struct device *de
+ return usb_external_suspend_device(udev, message);
+ }
+
+-static int usb_resume(struct device *dev)
++int usb_resume(struct device *dev)
+ {
+ struct usb_device *udev;
+
+- if (!is_usb_device(dev)) /* Ignore PM for interfaces */
+- return 0;
+ udev = to_usb_device(dev);
+
+ /* If udev->skip_sys_resume is set then udev was already suspended
+@@ -1671,17 +1667,10 @@ static int usb_resume(struct device *dev
+ return usb_external_resume_device(udev);
+ }
+
+-#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,
+- .suspend = usb_suspend,
+- .resume = usb_resume,
+ };
+--- a/drivers/usb/core/usb.c
++++ b/drivers/usb/core/usb.c
+@@ -219,12 +219,6 @@ static int usb_dev_uevent(struct device
+ }
+ #endif /* CONFIG_HOTPLUG */
+
+-struct device_type usb_device_type = {
+- .name = "usb_device",
+- .release = usb_release_dev,
+- .uevent = usb_dev_uevent,
+-};
+-
+ #ifdef CONFIG_PM
+
+ static int ksuspend_usb_init(void)
+@@ -244,13 +238,80 @@ static void ksuspend_usb_cleanup(void)
+ destroy_workqueue(ksuspend_usb_wq);
+ }
+
++/* USB device Power-Management thunks.
++ * There's no need to distinguish here between quiescing a USB device
++ * and powering it down; the generic_suspend() routine takes care of
++ * it by skipping the usb_port_suspend() call for a quiesce. And for
++ * USB interfaces there's no difference at all.
++ */
++
++static int usb_dev_prepare(struct device *dev)
++{
++ return 0; /* Implement eventually? */
++}
++
++static void usb_dev_complete(struct device *dev)
++{
++ /* Currently used only for rebinding interfaces */
++ usb_resume(dev); /* Implement eventually? */
++}
++
++static int usb_dev_suspend(struct device *dev)
++{
++ return usb_suspend(dev, PMSG_SUSPEND);
++}
++
++static int usb_dev_resume(struct device *dev)
++{
++ return usb_resume(dev);
++}
++
++static int usb_dev_freeze(struct device *dev)
++{
++ return usb_suspend(dev, PMSG_FREEZE);
++}
++
++static int usb_dev_thaw(struct device *dev)
++{
++ return usb_resume(dev);
++}
++
++static int usb_dev_poweroff(struct device *dev)
++{
++ return usb_suspend(dev, PMSG_HIBERNATE);
++}
++
++static int usb_dev_restore(struct device *dev)
++{
++ return usb_resume(dev);
++}
++
++static struct pm_ops usb_device_pm_ops = {
++ .prepare = usb_dev_prepare,
++ .complete = usb_dev_complete,
++ .suspend = usb_dev_suspend,
++ .resume = usb_dev_resume,
++ .freeze = usb_dev_freeze,
++ .thaw = usb_dev_thaw,
++ .poweroff = usb_dev_poweroff,
++ .restore = usb_dev_restore,
++};
++
+ #else
+
+ #define ksuspend_usb_init() 0
+ #define ksuspend_usb_cleanup() do {} while (0)
++#define usb_device_pm_ops (* (struct pm_ops *) 0)
+
+ #endif /* CONFIG_PM */
+
++struct device_type usb_device_type = {
++ .name = "usb_device",
++ .release = usb_release_dev,
++ .uevent = usb_dev_uevent,
++ .pm = &usb_device_pm_ops,
++};
++
+
+ /* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+ static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+--- a/drivers/usb/core/usb.h
++++ b/drivers/usb/core/usb.h
+@@ -41,6 +41,9 @@ extern void usb_host_cleanup(void);
+
+ #ifdef CONFIG_PM
+
++extern int usb_suspend(struct device *dev, pm_message_t msg);
++extern int usb_resume(struct device *dev);
++
+ 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);
diff --git a/usb.current/usb-add-udev-argument-to-interface-suspend-resume-functions.patch b/usb.current/usb-add-udev-argument-to-interface-suspend-resume-functions.patch
new file mode 100644
index 00000000000000..1dda0e579fe670
--- /dev/null
+++ b/usb.current/usb-add-udev-argument-to-interface-suspend-resume-functions.patch
@@ -0,0 +1,97 @@
+From stern+48acf28e@rowland.harvard.edu Tue Aug 12 11:33:28 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 12 Aug 2008 14:33:27 -0400 (EDT)
+Subject: USB: Add udev argument to interface suspend/resume functions
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0808121429120.2248-100000@iolanthe.rowland.org>
+
+
+This patch (as1127) makes a minor change to the prototypes of the
+usb_suspend_interface() and usb_resume_interface() routines. Now the
+usb_device structure is passed as an argument, instead of being
+computed on-the-fly from the usb_interface argument.
+
+It makes the code look simpler, even if it really isn't much different
+from before.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/driver.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -926,14 +926,14 @@ static int usb_resume_device(struct usb_
+ }
+
+ /* Caller has locked intf's usb_device's pm mutex */
+-static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
++static int usb_suspend_interface(struct usb_device *udev,
++ struct usb_interface *intf, pm_message_t msg)
+ {
+ struct usb_driver *driver;
+ int status = 0;
+
+ /* with no hardware, USB interfaces only use FREEZE and ON states */
+- if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+- !is_active(intf))
++ if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf))
+ goto done;
+
+ if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */
+@@ -944,7 +944,7 @@ static int usb_suspend_interface(struct
+ status = driver->suspend(intf, msg);
+ if (status == 0)
+ mark_quiesced(intf);
+- else if (!interface_to_usbdev(intf)->auto_pm)
++ else if (!udev->auto_pm)
+ dev_err(&intf->dev, "%s error %d\n",
+ "suspend", status);
+ } else {
+@@ -961,13 +961,13 @@ static int usb_suspend_interface(struct
+ }
+
+ /* Caller has locked intf's usb_device's pm_mutex */
+-static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
++static int usb_resume_interface(struct usb_device *udev,
++ struct usb_interface *intf, int reset_resume)
+ {
+ struct usb_driver *driver;
+ int status = 0;
+
+- if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+- is_active(intf))
++ if (udev->state == USB_STATE_NOTATTACHED || is_active(intf))
+ goto done;
+
+ /* Don't let autoresume interfere with unbinding */
+@@ -1151,7 +1151,7 @@ static int usb_suspend_both(struct usb_d
+ if (udev->actconfig) {
+ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+- status = usb_suspend_interface(intf, msg);
++ status = usb_suspend_interface(udev, intf, msg);
+ if (status != 0)
+ break;
+ }
+@@ -1163,7 +1163,7 @@ static int usb_suspend_both(struct usb_d
+ if (status != 0) {
+ while (--i >= 0) {
+ intf = udev->actconfig->interface[i];
+- usb_resume_interface(intf, 0);
++ usb_resume_interface(udev, intf, 0);
+ }
+
+ /* Try another autosuspend when the interfaces aren't busy */
+@@ -1276,7 +1276,7 @@ static int usb_resume_both(struct usb_de
+ if (status == 0 && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+- usb_resume_interface(intf, udev->reset_resume);
++ usb_resume_interface(udev, intf, udev->reset_resume);
+ }
+ }
+
diff --git a/usb.current/usb-defer-set-interface-for-suspended-devices.patch b/usb.current/usb-defer-set-interface-for-suspended-devices.patch
new file mode 100644
index 00000000000000..34182fb8969ac9
--- /dev/null
+++ b/usb.current/usb-defer-set-interface-for-suspended-devices.patch
@@ -0,0 +1,103 @@
+From stern+48acf28e@rowland.harvard.edu Tue Aug 12 11:34:06 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 12 Aug 2008 14:33:59 -0400 (EDT)
+Subject: USB: Defer Set-Interface for suspended devices
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0808121430030.2248-100000@iolanthe.rowland.org>
+
+
+This patch (as1128) fixes one of the problems related to the new PM
+infrastructure. We are not allowed to register new child devices
+during the middle of a system sleep transition, but unbinding a USB
+driver causes the core to automatically install altsetting 0 and
+thereby create new endpoint pseudo-devices.
+
+The patch fixes this problem (and the related problem that installing
+altsetting 0 will fail if the device is suspended) by deferring the
+Set-Interface call until some later time when it is legal and can
+succeed. Possible later times are: when a new driver is being probed
+for the interface, and when the interface is being resumed.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/driver.c | 31 ++++++++++++++++++++++++++++---
+ include/linux/usb.h | 3 +++
+ 2 files changed, 31 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -230,6 +230,13 @@ static int usb_probe_interface(struct de
+ */
+ intf->pm_usage_cnt = !(driver->supports_autosuspend);
+
++ /* Carry out a deferred switch to altsetting 0 */
++ if (intf->needs_altsetting0) {
++ usb_set_interface(udev, intf->altsetting[0].
++ desc.bInterfaceNumber, 0);
++ intf->needs_altsetting0 = 0;
++ }
++
+ error = driver->probe(intf, id);
+ if (error) {
+ mark_quiesced(intf);
+@@ -266,8 +273,17 @@ static int usb_unbind_interface(struct d
+
+ driver->disconnect(intf);
+
+- /* reset other interface state */
+- usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
++ /* Reset other interface state.
++ * We cannot do a Set-Interface if the device is suspended or
++ * if it is prepared for a system sleep (since installing a new
++ * altsetting means creating new endpoint device entries).
++ * When either of these happens, defer the Set-Interface.
++ */
++ if (!error && intf->dev.power.status == DPM_ON)
++ usb_set_interface(udev, intf->altsetting[0].
++ desc.bInterfaceNumber, 0);
++ else
++ intf->needs_altsetting0 = 1;
+ usb_set_intfdata(intf, NULL);
+
+ intf->condition = USB_INTERFACE_UNBOUND;
+@@ -975,8 +991,17 @@ static int usb_resume_interface(struct u
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+- if (intf->condition == USB_INTERFACE_UNBOUND)
++ if (intf->condition == USB_INTERFACE_UNBOUND) {
++
++ /* Carry out a deferred switch to altsetting 0 */
++ if (intf->needs_altsetting0 &&
++ intf->dev.power.status == DPM_ON) {
++ usb_set_interface(udev, intf->altsetting[0].
++ desc.bInterfaceNumber, 0);
++ intf->needs_altsetting0 = 0;
++ }
+ goto done;
++ }
+
+ /* Don't resume if the interface is marked for rebinding */
+ if (intf->needs_binding)
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -110,6 +110,8 @@ enum usb_interface_condition {
+ * @sysfs_files_created: sysfs attributes exist
+ * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
+ * capability during autosuspend.
++ * @needs_altsetting0: flag set when a set-interface request for altsetting 0
++ * has been deferred.
+ * @needs_binding: flag set when the driver should be re-probed or unbound
+ * following a reset or suspend operation it doesn't support.
+ * @dev: driver model's view of this device
+@@ -162,6 +164,7 @@ struct usb_interface {
+ unsigned is_active:1; /* the interface is not suspended */
+ unsigned sysfs_files_created:1; /* the sysfs attributes exist */
+ unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
++ unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */
+ unsigned needs_binding:1; /* needs delayed unbind/rebind */
+
+ struct device dev; /* interface specific device info */
diff --git a/usb.current/usb-don-t-rebind-before-complete-callback.patch b/usb.current/usb-don-t-rebind-before-complete-callback.patch
new file mode 100644
index 00000000000000..dfee12fb4994d2
--- /dev/null
+++ b/usb.current/usb-don-t-rebind-before-complete-callback.patch
@@ -0,0 +1,92 @@
+From linux-usb-owner@vger.kernel.org Tue Aug 12 11:34:22 2008
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Tue, 12 Aug 2008 14:34:14 -0400 (EDT)
+Subject: USB: Don't rebind before "complete" callback
+To: Greg KH <greg@kroah.com>
+Cc: USB list <linux-usb@vger.kernel.org>
+Message-ID: <Pine.LNX.4.44L0.0808121431290.2248-100000@iolanthe.rowland.org>
+
+
+This patch (as1130) fixes an incompatibility between the new PM
+infrastructure and USB power management. We are not allowed to call
+drivers' probe routines during a system sleep transition between the
+"prepare" and "complete" callbacks, but that's exactly what we do when
+a driver doesn't have full suspend/resume support. Such drivers are
+unbound during the "suspend" call and reprobed during the "resume" call.
+
+The patch causes the reprobe step to be skipped if the "complete"
+callback hasn't been issued yet, i.e., if the interface's
+dev.power.status field is not equal to DPM_ON. Thus during the
+"resume" callback nothing bad will happen, and during the final
+"complete" callback the reprobing will occur as desired.
+
+This fixes the problem reported in Bugzilla #11263.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/driver.c | 30 +++++++++---------------------
+ 1 file changed, 9 insertions(+), 21 deletions(-)
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -814,7 +814,8 @@ void usb_forced_unbind_intf(struct usb_i
+ * The caller must hold @intf's device's lock, but not its pm_mutex
+ * and not @intf->dev.sem.
+ *
+- * FIXME: The caller must block system sleep transitions.
++ * Note: Rebinds will be skipped if a system sleep transition is in
++ * progress and the PM "complete" callback hasn't occurred yet.
+ */
+ void usb_rebind_intf(struct usb_interface *intf)
+ {
+@@ -830,10 +831,12 @@ void usb_rebind_intf(struct usb_interfac
+ }
+
+ /* Try to rebind the interface */
+- intf->needs_binding = 0;
+- rc = device_attach(&intf->dev);
+- if (rc < 0)
+- dev_warn(&intf->dev, "rebind failed: %d\n", rc);
++ if (intf->dev.power.status == DPM_ON) {
++ intf->needs_binding = 0;
++ rc = device_attach(&intf->dev);
++ if (rc < 0)
++ dev_warn(&intf->dev, "rebind failed: %d\n", rc);
++ }
+ }
+
+ #ifdef CONFIG_PM
+@@ -845,7 +848,6 @@ void usb_rebind_intf(struct usb_interfac
+ * or rebind interfaces that have been unbound, according to @action.
+ *
+ * The caller must hold @udev's device lock.
+- * FIXME: For rebinds, the caller must block system sleep transitions.
+ */
+ static void do_unbind_rebind(struct usb_device *udev, int action)
+ {
+@@ -867,22 +869,8 @@ static void do_unbind_rebind(struct usb_
+ }
+ break;
+ case DO_REBIND:
+- if (intf->needs_binding) {
+-
+- /* FIXME: The next line is needed because we are going to probe
+- * the interface, but as far as the PM core is concerned the
+- * interface is still suspended. The problem wouldn't exist
+- * if we could rebind the interface during the interface's own
+- * resume() call, but at the time the usb_device isn't locked!
+- *
+- * The real solution will be to carry this out during the device's
+- * complete() callback. Until that is implemented, we have to
+- * use this hack.
+- */
+-// intf->dev.power.sleeping = 0;
+-
++ if (intf->needs_binding)
+ usb_rebind_intf(intf);
+- }
+ break;
+ }
+ }