Oliver:

Here's an improved API for managing autosuspend calls.  It lets you do
what you want and it saves code space at the same time!

Your usb_autopm_enable() and usb_autopm_disable() routines can easily be 
implemented using this API as follows:

#define usb_autopm_enable(intf) do {            \
        (intf)->pm_usage_cnt = 0;               \
        usb_autopm_set_interface(intf); } while (0)

#define usb_autopm_disable(intf) do {           \
        (intf)->pm_usage_cnt = 1;               \
        usb_autopm_set_interface(intf); } while (0)

Yes, this does involve setting pm_usage_cnt outside the protection of
udev->pm_mutex, but I think that won't hurt anything.  The call to 
usb_autopm_set_interface() will do the right thing regardless.

What do you think of this approach?

Alan Stern



Index: usb-2.6/drivers/usb/core/driver.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/driver.c
+++ usb-2.6/drivers/usb/core/driver.c
@@ -1126,6 +1126,29 @@ int usb_resume_both(struct usb_device *u
 
 #ifdef CONFIG_USB_SUSPEND
 
+/* Internal routine to adjust a device's usage counter and change its
+ * autosuspend state.
+ */
+static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
+{
+       int     status;
+
+       usb_pm_lock(udev);
+       udev->pm_usage_cnt += inc_usage_cnt;
+       if (udev->pm_usage_cnt > 0) {
+               udev->auto_pm = 1;
+               status = usb_resume_both(udev);
+               if (status != 0)
+                       udev->pm_usage_cnt -= inc_usage_cnt;
+       } else {
+               queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+                               USB_AUTOSUSPEND_DELAY);
+               status = 0;
+       }
+       usb_pm_unlock(udev);
+       return status;
+}
+
 /**
  * usb_autosuspend_device - delayed autosuspend of a USB device and its 
interfaces
  * @udev: the usb_device to autosuspend
@@ -1153,14 +1176,11 @@ int usb_resume_both(struct usb_device *u
  */
 void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt)
 {
-       usb_pm_lock(udev);
-       udev->pm_usage_cnt -= dec_usage_cnt;
-       if (udev->pm_usage_cnt <= 0)
-               queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                               USB_AUTOSUSPEND_DELAY);
-       usb_pm_unlock(udev);
-       // dev_dbg(&udev->dev, "%s: cnt %d\n",
-       //              __FUNCTION__, udev->pm_usage_cnt);
+       int     status;
+
+       status = usb_autopm_do_device(udev, - dec_usage_cnt);
+       // dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
+       //              __FUNCTION__, status, udev->pm_usage_cnt);
 }
 
 /**
@@ -1192,18 +1212,39 @@ int usb_autoresume_device(struct usb_dev
 {
        int     status;
 
-       usb_pm_lock(udev);
-       udev->pm_usage_cnt += inc_usage_cnt;
-       udev->auto_pm = 1;
-       status = usb_resume_both(udev);
-       if (status != 0)
-               udev->pm_usage_cnt -= inc_usage_cnt;
-       usb_pm_unlock(udev);
+       status = usb_autopm_do_device(udev, inc_usage_cnt);
        // dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
        //              __FUNCTION__, status, udev->pm_usage_cnt);
        return status;
 }
 
+/* Internal routine to adjust an interface's usage counter and change
+ * its device's autosuspend state.
+ */
+static int usb_autopm_do_interface(struct usb_interface *intf,
+               int inc_usage_cnt)
+{
+       struct usb_device       *udev = interface_to_usbdev(intf);
+       int                     status = -ENODEV;
+
+       usb_pm_lock(udev);
+       if (intf->condition != USB_INTERFACE_UNBOUND) {
+               intf->pm_usage_cnt += inc_usage_cnt;
+               if (intf->pm_usage_cnt > 0) {
+                       udev->auto_pm = 1;
+                       status = usb_resume_both(udev);
+                       if (status != 0)
+                               intf->pm_usage_cnt -= inc_usage_cnt;
+               } else {
+                       queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+                                       USB_AUTOSUSPEND_DELAY);
+                       status = 0;
+               }
+       }
+       usb_pm_unlock(udev);
+       return status;
+}
+
 /**
  * usb_autopm_put_interface - decrement a USB interface's PM-usage counter
  * @intf: the usb_interface whose counter should be decremented
@@ -1237,17 +1278,11 @@ int usb_autoresume_device(struct usb_dev
  */
 void usb_autopm_put_interface(struct usb_interface *intf)
 {
-       struct usb_device       *udev = interface_to_usbdev(intf);
+       int     status;
 
-       usb_pm_lock(udev);
-       if (intf->condition != USB_INTERFACE_UNBOUND &&
-                       --intf->pm_usage_cnt <= 0) {
-               queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                               USB_AUTOSUSPEND_DELAY);
-       }
-       usb_pm_unlock(udev);
-       // dev_dbg(&intf->dev, "%s: cnt %d\n",
-       //              __FUNCTION__, intf->pm_usage_cnt);
+       status = usb_autopm_do_interface(intf, -1);
+       // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
+       //              __FUNCTION__, status, intf->pm_usage_cnt);
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 
@@ -1284,26 +1319,37 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interfa
  */
 int usb_autopm_get_interface(struct usb_interface *intf)
 {
-       struct usb_device       *udev = interface_to_usbdev(intf);
-       int                     status;
+       int     status;
 
-       usb_pm_lock(udev);
-       if (intf->condition == USB_INTERFACE_UNBOUND)
-               status = -ENODEV;
-       else {
-               ++intf->pm_usage_cnt;
-               udev->auto_pm = 1;
-               status = usb_resume_both(udev);
-               if (status != 0)
-                       --intf->pm_usage_cnt;
-       }
-       usb_pm_unlock(udev);
+       status = usb_autopm_do_interface(intf, 1);
        // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
        //              __FUNCTION__, status, intf->pm_usage_cnt);
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
 
+/**
+ * usb_autopm_set_interface - set a USB interface's autosuspend state
+ * @intf: the usb_interface whose state should be set
+ *
+ * This routine sets the autosuspend state of @intf's device according
+ * to @intf's usage counter, which the caller must have set previously.
+ * If the counter is <= 0, the device is autosuspended (if it isn't
+ * already suspended and if nothing else prevents the autosuspend).  If
+ * the counter is > 0, the device is autoresumed (if it isn't already
+ * awake).
+ */
+int usb_autopm_set_interface(struct usb_interface *intf)
+{
+       int     status;
+
+       status = usb_autopm_do_interface(intf, 0);
+       // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
+       //              __FUNCTION__, status, intf->pm_usage_cnt);
+       return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
+
 #endif /* CONFIG_USB_SUSPEND */
 
 static int usb_suspend(struct device *dev, pm_message_t message)
Index: usb-2.6/include/linux/usb.h
===================================================================
--- usb-2.6.orig/include/linux/usb.h
+++ usb-2.6/include/linux/usb.h
@@ -416,11 +416,18 @@ extern struct usb_device *usb_find_devic
 
 /* USB autosuspend and autoresume */
 #ifdef CONFIG_USB_SUSPEND
+extern int usb_autopm_set_interface(struct usb_interface *intf);
 extern int usb_autopm_get_interface(struct usb_interface *intf);
 extern void usb_autopm_put_interface(struct usb_interface *intf);
 
 #else
-#define usb_autopm_get_interface(intf)         0
+
+static inline int usb_autopm_set_interface(struct usb_interface *intf)
+{ return 0; }
+
+static inline int usb_autopm_get_interface(struct usb_interface *intf)
+{ return 0; }
+
 #define usb_autopm_put_interface(intf)         do {} while (0)
 #endif
 


-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to