modifications to new generic autosuspend code
Oliver Neukum <[email protected]>
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Alan,
here are the changes I made to adapt the HID suspend code to the new
model. Basically I just changed the simple flag to a callback that allows
to know whether the flag has been checked and allow several independently
removable sources of business.
Regards
Oliver
--------
--- linux-2.6.20/drivers/usb/core/driver.c 2007-02-06 14:14:48.000000000 +0100
+++ linux-stern/drivers/usb/core/driver.c 2007-02-15 16:04:57.000000000 +0100
@@ -942,21 +942,48 @@
#ifdef CONFIG_USB_SUSPEND
+static int is_interface_busy(struct usb_interface *intf)
+{
+ struct usb_driver *drv = to_usb_driver(intf->dev.driver);
+
+ if (!drv)
+ return 0;
+ if (!drv->check_busy)
+ return 0;
+
+ return (drv->check_busy)(intf);
+}
+
/* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int starting)
{
int i;
+ unsigned delay;
struct usb_interface *intf;
- /* For autosuspend, fail fast if anything is in use.
- * Also fail if any interfaces require remote wakeup but it
- * isn't available. */
+ /* For autosuspend, fail fast if anything is in use or autosuspend
+ * is disabled. Also fail if any interfaces require remote wakeup
+ * but it isn't available.
+ */
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->pm_usage_cnt > 0)
return -EBUSY;
+ if (!udev->autosuspend_delay)
+ return -EPERM;
+
+ /* starting is non-zero when the autosuspend timer is first started,
+ * in which case we should return the maximum delay needed.
+ * It is zero when the timer expires, in which case we should return
+ * 0 if it is okay to autosuspend now, otherwise the next timer
+ * delay value.
+ */
+ delay = (starting ? udev->autosuspend_delay : 0);
+
if (udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
+ if (!intf->autosuspend_delay)
+ return -EPERM;
if (!is_active(intf))
continue;
if (intf->pm_usage_cnt > 0)
@@ -967,6 +994,29 @@
"for autosuspend\n");
return -EOPNOTSUPP;
}
+ if (starting || is_interface_busy(intf))
+ delay = max(delay, intf->autosuspend_delay);
+ }
+ }
+ return delay;
+}
+
+/* Internal routine to check whether we need to autoresume a device. */
+static int autosuspend_recheck(struct usb_device *udev)
+{
+ int i;
+ struct usb_interface *intf;
+
+ /* There's a race between the test of the USB_IF_DEVICE_BUSY flag
+ * above and the completion of an URB (when a driver would set the
+ * flag). If the flag gets set after the decision to start an
+ * autosuspend has been made, we need to go back and autoresume
+ * the device. */
+ if (udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ if (is_interface_busy(intf))
+ return 1;
}
}
return 0;
--- linux-2.6.20/include/linux/usb.h 2007-02-06 14:14:57.000000000 +0100
+++ linux-stern/include/linux/usb.h 2007-02-15 13:41:21.000000000 +0100
@@ -804,6 +812,8 @@
void (*pre_reset) (struct usb_interface *intf);
void (*post_reset) (struct usb_interface *intf);
+ int (*check_busy) (struct usb_interface *intf);
+
const struct usb_device_id *id_table;
struct usb_dynids dynids;
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel