diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-08-20 13:07:31 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-08-20 13:07:31 -0700 |
| commit | 0fadf3ad444c16aae5fd9256d4bd3f285f89c297 (patch) | |
| tree | e0ba850b8af629d6ed0d7763271417a477dbb38c /usb.current | |
| parent | 96299169f566ff0059bbcabb7555dbcf4ddc7f69 (diff) | |
| download | patches-0fadf3ad444c16aae5fd9256d4bd3f285f89c297.tar.gz | |
move some usb patches to usb.current
Diffstat (limited to 'usb.current')
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; + } + } |
