Alan's idea about syspending the whole bus at once

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

 



Hi,

Alan, I took your idea of just suspending the bus. It seems to me
that we cannot do that unconditionally, as for some drivers like
btusb simply continuing transmission is wrong. But with a flag it
is a fascinating idea, because we cannot resume faster than by
doing nothing.
So this is the first draft. Comments?

	Regards
		Oliver

--

commit 830f311a62c7f38d354dab024cb95e153569c326
Author: Oliver Neukum <oliver@xxxxxxxxxx>
Date:   Sun Dec 20 13:26:23 2009 +0100

    usb:support for transparently to drivers putting the system to sleep
    
    Some drivers can afford to ignore a system sleep seeing it only as
    a pause in IO, which is resumed automatically as the root hub is woken.
    Such drivers can tell usbcore that it need not tell them of upcoming
    system sleep
    
    Signed-off-by: Oliver Neukum <oliver@xxxxxxxxxx>

diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 391cccc..1cf08fb 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -2170,6 +2170,7 @@ struct uvc_driver uvc_driver = {
 		.reset_resume	= uvc_reset_resume,
 		.id_table	= uvc_ids,
 		.supports_autosuspend = 1,
+		.supports_transparent_suspend = 1,
 	},
 };
 
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 60a45f1..b755e7f 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1114,18 +1114,20 @@ static int usb_resume_interface(struct usb_device *udev,
 		}
 	} else {
 		if (driver->resume) {
-			status = driver->resume(intf);
-			if (status)
-				dev_err(&intf->dev, "%s error %d\n",
+			if (!intf->transparently_suspended) {
+				status = driver->resume(intf);
+				if (status)
+					dev_err(&intf->dev, "%s error %d\n",
 						"resume", status);
+			}
 		} else {
 			intf->needs_binding = 1;
 			dev_warn(&intf->dev, "no %s for driver %s?\n",
 					"resume", driver->name);
 		}
 	}
-
 done:
+	intf->transparently_suspended = 0;
 	dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
 	if (status == 0 && intf->condition == USB_INTERFACE_BOUND)
 		mark_active(intf);
@@ -1250,14 +1252,17 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 {
 	int			status = 0;
 	int			i = 0;
+	int			wakeup;
 	struct usb_interface	*intf;
 	struct usb_device	*parent = udev->parent;
+	struct usb_driver	*driver;
 
 	if (udev->state == USB_STATE_NOTATTACHED ||
 			udev->state == USB_STATE_SUSPENDED)
 		goto done;
 
-	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+	wakeup = device_may_wakeup(&udev->dev);;
+	udev->do_remote_wakeup = wakeup; 
 
 	if (msg.event & PM_EVENT_AUTO) {
 		status = autosuspend_check(udev, 0);
@@ -1269,9 +1274,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 	if (udev->actconfig) {
 		for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
 			intf = udev->actconfig->interface[i];
-			status = usb_suspend_interface(udev, intf, msg);
-			if (status != 0)
-				break;
+			driver = to_usb_driver(intf->dev.driver);
+			/*
+			 * an interface may do transparent suspend
+			 * if the driver requests it and doesn't
+			 * need remote wakeup, as buggy devices
+			 * crash if IO is done after remote wakeup
+			 * is enabled
+			 */
+			if (!(msg.event & PM_EVENT_AUTO) &&
+			!wakeup &&
+			driver && driver->supports_transparent_suspend &&
+			!(udev->quirks & USB_QUIRK_RESET_RESUME)) {
+				intf->transparently_suspended = 1;
+			} else {
+				status = usb_suspend_interface(udev, intf, msg);
+				if (status != 0)
+					break;
+			}
 		}
 	}
 	if (status == 0)
diff --git a/include/linux/usb.h b/include/linux/usb.h
index e101a2d..b0d2c94 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -189,6 +189,7 @@ struct usb_interface {
 	unsigned ep_devs_created:1;	/* endpoint "devices" exist */
 	unsigned unregistering:1;	/* unregistration is in progress */
 	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
+	unsigned transparently_suspended:1; /* the driver hasn't been told the system sleeps */
 	unsigned needs_altsetting0:1;	/* switch to altsetting 0 is pending */
 	unsigned needs_binding:1;	/* needs delayed unbind/rebind */
 	unsigned reset_running:1;
@@ -835,6 +836,8 @@ struct usbdrv_wrap {
  *	added to this driver by preventing the sysfs file from being created.
  * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
  *	for interfaces bound to this driver.
+ * @supports_transparent_suspend: if set to 1 usbcore may not notify
+ *	the driver about system sleep
  * @soft_unbind: if set to 1, the USB core will not kill URBs and disable
  *	endpoints before calling the driver's disconnect method.
  *
@@ -877,6 +880,7 @@ struct usb_driver {
 	struct usbdrv_wrap drvwrap;
 	unsigned int no_dynamic_id:1;
 	unsigned int supports_autosuspend:1;
+	unsigned int supports_transparent_suspend:1;
 	unsigned int soft_unbind:1;
 };
 #define	to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
--
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