[PATCH stable] USB: fix remote wakeup settings during system sleep

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch (as1363b) changes the way USB remote wakeup is handled
during system sleeps.  It won't be enabled unless an interface driver
specifically needs it.  Also, it won't be enabled during the FREEZE or
QUIESCE phases of hibernation, when the system doesn't respond to
wakeup events anyway.

This will fix problems people have reported with certain USB webcams
that generate wakeup requests when they shouldn't, and as a result
cause system suspends to fail.  See

	https://bugs.launchpad.net/ubuntu/+source/linux/+bug/515109

This is a backport of commit 5f677f1d45b2bf08085bbba7394392dfa586fa8e.  
Some of the functionality had to be removed, but it should still fix 
the webcam problem.

Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>

---

On Mon, 26 Apr 2010, Greg KH wrote:

> Alan, this doesn't apply to the .33 kernel tree, and I don't see how to
> fit it in.  Care to make up a backport that I can use?

Here is the promised backport.



Index: 2.6.33/drivers/usb/core/driver.c
===================================================================
--- 2.6.33.orig/drivers/usb/core/driver.c
+++ 2.6.33/drivers/usb/core/driver.c
@@ -1257,9 +1257,8 @@ static int usb_suspend_both(struct usb_d
 			udev->state == USB_STATE_SUSPENDED)
 		goto done;
 
-	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
-
 	if (msg.event & PM_EVENT_AUTO) {
+		udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 		status = autosuspend_check(udev, 0);
 		if (status < 0)
 			goto done;
@@ -1791,6 +1790,34 @@ int usb_external_resume_device(struct us
 	return status;
 }
 
+static void choose_wakeup(struct usb_device *udev, pm_message_t msg)
+{
+	int			w, i;
+	struct usb_interface	*intf;
+
+	/* Remote wakeup is needed only when we actually go to sleep.
+	 * For things like FREEZE and QUIESCE, if the device is already
+	 * autosuspended then its current wakeup setting is okay.
+	 */
+	if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) {
+		udev->do_remote_wakeup = 0;
+		return;
+	}
+
+	/* If remote wakeup is permitted, see whether any interface drivers
+	 * actually want it.
+	 */
+	w = 0;
+	if (device_may_wakeup(&udev->dev) && udev->actconfig) {
+		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+			intf = udev->actconfig->interface[i];
+			w |= intf->needs_remote_wakeup;
+		}
+	}
+
+	udev->do_remote_wakeup = w;
+}
+
 int usb_suspend(struct device *dev, pm_message_t msg)
 {
 	struct usb_device	*udev;
@@ -1810,6 +1837,7 @@ int usb_suspend(struct device *dev, pm_m
 	}
 
 	udev->skip_sys_resume = 0;
+	choose_wakeup(udev, msg);
 	return usb_external_suspend_device(udev, msg);
 }
 



--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux