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
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel