aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-10-30 17:06:45 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-01 17:23:29 -0500
commitaf4f76066d0fcb215ae389b8839d7ae37ce0e28b (patch)
tree3d3ea0546de3dec1a340752d35831c1cbbd178fa
parent0c1ac4f25f894f9df0ffe9b912c165fb6a185a3c (diff)
USB: autosuspend code consolidation
This patch (as813) gathers together common code for USB interface autosuspend/autoresume. It also adds some simple checking at the time an autosuspend request is made, to see whether the request will fail. This way we don't add a workqueue entry when it would end up doing nothing. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/driver.c112
1 files changed, 67 insertions, 45 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 401d76f13419..ca0e40ed2b72 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -940,6 +940,36 @@ done:
940 return status; 940 return status;
941} 941}
942 942
943/* Internal routine to check whether we may autosuspend a device. */
944static int autosuspend_check(struct usb_device *udev)
945{
946 int i;
947 struct usb_interface *intf;
948
949 /* For autosuspend, fail fast if anything is in use.
950 * Also fail if any interfaces require remote wakeup but it
951 * isn't available. */
952 udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
953 if (udev->pm_usage_cnt > 0)
954 return -EBUSY;
955 if (udev->actconfig) {
956 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
957 intf = udev->actconfig->interface[i];
958 if (!is_active(intf))
959 continue;
960 if (intf->pm_usage_cnt > 0)
961 return -EBUSY;
962 if (intf->needs_remote_wakeup &&
963 !udev->do_remote_wakeup) {
964 dev_dbg(&udev->dev, "remote wakeup needed "
965 "for autosuspend\n");
966 return -EOPNOTSUPP;
967 }
968 }
969 }
970 return 0;
971}
972
943/** 973/**
944 * usb_suspend_both - suspend a USB device and its interfaces 974 * usb_suspend_both - suspend a USB device and its interfaces
945 * @udev: the usb_device to suspend 975 * @udev: the usb_device to suspend
@@ -991,28 +1021,10 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
991 1021
992 udev->do_remote_wakeup = device_may_wakeup(&udev->dev); 1022 udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
993 1023
994 /* For autosuspend, fail fast if anything is in use.
995 * Also fail if any interfaces require remote wakeup but it
996 * isn't available. */
997 if (udev->auto_pm) { 1024 if (udev->auto_pm) {
998 if (udev->pm_usage_cnt > 0) 1025 status = autosuspend_check(udev);
999 return -EBUSY; 1026 if (status < 0)
1000 if (udev->actconfig) { 1027 return status;
1001 for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
1002 intf = udev->actconfig->interface[i];
1003 if (!is_active(intf))
1004 continue;
1005 if (intf->pm_usage_cnt > 0)
1006 return -EBUSY;
1007 if (intf->needs_remote_wakeup &&
1008 !udev->do_remote_wakeup) {
1009 dev_dbg(&udev->dev,
1010 "remote wakeup needed for autosuspend\n");
1011 return -EOPNOTSUPP;
1012 }
1013 }
1014 i = 0;
1015 }
1016 } 1028 }
1017 1029
1018 /* Suspend all the interfaces and then udev itself */ 1030 /* Suspend all the interfaces and then udev itself */
@@ -1151,7 +1163,7 @@ void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt)
1151{ 1163{
1152 usb_pm_lock(udev); 1164 usb_pm_lock(udev);
1153 udev->pm_usage_cnt -= dec_usage_cnt; 1165 udev->pm_usage_cnt -= dec_usage_cnt;
1154 if (udev->pm_usage_cnt <= 0) 1166 if (autosuspend_check(udev) == 0)
1155 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, 1167 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
1156 USB_AUTOSUSPEND_DELAY); 1168 USB_AUTOSUSPEND_DELAY);
1157 usb_pm_unlock(udev); 1169 usb_pm_unlock(udev);
@@ -1200,6 +1212,33 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt)
1200 return status; 1212 return status;
1201} 1213}
1202 1214
1215/* Internal routine to adjust an interface's usage counter and change
1216 * its device's autosuspend state.
1217 */
1218static int usb_autopm_do_interface(struct usb_interface *intf,
1219 int inc_usage_cnt)
1220{
1221 struct usb_device *udev = interface_to_usbdev(intf);
1222 int status = 0;
1223
1224 usb_pm_lock(udev);
1225 if (intf->condition == USB_INTERFACE_UNBOUND)
1226 status = -ENODEV;
1227 else {
1228 intf->pm_usage_cnt += inc_usage_cnt;
1229 if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
1230 udev->auto_pm = 1;
1231 status = usb_resume_both(udev);
1232 if (status != 0)
1233 intf->pm_usage_cnt -= inc_usage_cnt;
1234 } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
1235 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
1236 USB_AUTOSUSPEND_DELAY);
1237 }
1238 usb_pm_unlock(udev);
1239 return status;
1240}
1241
1203/** 1242/**
1204 * usb_autopm_put_interface - decrement a USB interface's PM-usage counter 1243 * usb_autopm_put_interface - decrement a USB interface's PM-usage counter
1205 * @intf: the usb_interface whose counter should be decremented 1244 * @intf: the usb_interface whose counter should be decremented
@@ -1233,17 +1272,11 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt)
1233 */ 1272 */
1234void usb_autopm_put_interface(struct usb_interface *intf) 1273void usb_autopm_put_interface(struct usb_interface *intf)
1235{ 1274{
1236 struct usb_device *udev = interface_to_usbdev(intf); 1275 int status;
1237 1276
1238 usb_pm_lock(udev); 1277 status = usb_autopm_do_interface(intf, -1);
1239 if (intf->condition != USB_INTERFACE_UNBOUND && 1278 // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
1240 --intf->pm_usage_cnt <= 0) { 1279 // __FUNCTION__, status, intf->pm_usage_cnt);
1241 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
1242 USB_AUTOSUSPEND_DELAY);
1243 }
1244 usb_pm_unlock(udev);
1245 // dev_dbg(&intf->dev, "%s: cnt %d\n",
1246 // __FUNCTION__, intf->pm_usage_cnt);
1247} 1280}
1248EXPORT_SYMBOL_GPL(usb_autopm_put_interface); 1281EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
1249 1282
@@ -1280,20 +1313,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
1280 */ 1313 */
1281int usb_autopm_get_interface(struct usb_interface *intf) 1314int usb_autopm_get_interface(struct usb_interface *intf)
1282{ 1315{
1283 struct usb_device *udev = interface_to_usbdev(intf); 1316 int status;
1284 int status;
1285 1317
1286 usb_pm_lock(udev); 1318 status = usb_autopm_do_interface(intf, 1);
1287 if (intf->condition == USB_INTERFACE_UNBOUND)
1288 status = -ENODEV;
1289 else {
1290 ++intf->pm_usage_cnt;
1291 udev->auto_pm = 1;
1292 status = usb_resume_both(udev);
1293 if (status != 0)
1294 --intf->pm_usage_cnt;
1295 }
1296 usb_pm_unlock(udev);
1297 // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", 1319 // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
1298 // __FUNCTION__, status, intf->pm_usage_cnt); 1320 // __FUNCTION__, status, intf->pm_usage_cnt);
1299 return status; 1321 return status;