diff options
-rw-r--r-- | drivers/usb/core/driver.c | 102 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 1 | ||||
-rw-r--r-- | include/linux/usb.h | 8 |
4 files changed, 75 insertions, 37 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 593386eb974d..631f30582481 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -932,6 +932,7 @@ static int autosuspend_check(struct usb_device *udev) | |||
932 | { | 932 | { |
933 | int i; | 933 | int i; |
934 | struct usb_interface *intf; | 934 | struct usb_interface *intf; |
935 | long suspend_time; | ||
935 | 936 | ||
936 | /* For autosuspend, fail fast if anything is in use or autosuspend | 937 | /* For autosuspend, fail fast if anything is in use or autosuspend |
937 | * is disabled. Also fail if any interfaces require remote wakeup | 938 | * is disabled. Also fail if any interfaces require remote wakeup |
@@ -943,6 +944,7 @@ static int autosuspend_check(struct usb_device *udev) | |||
943 | if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled) | 944 | if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled) |
944 | return -EPERM; | 945 | return -EPERM; |
945 | 946 | ||
947 | suspend_time = udev->last_busy + udev->autosuspend_delay; | ||
946 | if (udev->actconfig) { | 948 | if (udev->actconfig) { |
947 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { | 949 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { |
948 | intf = udev->actconfig->interface[i]; | 950 | intf = udev->actconfig->interface[i]; |
@@ -958,6 +960,17 @@ static int autosuspend_check(struct usb_device *udev) | |||
958 | } | 960 | } |
959 | } | 961 | } |
960 | } | 962 | } |
963 | |||
964 | /* If everything is okay but the device hasn't been idle for long | ||
965 | * enough, queue a delayed autosuspend request. | ||
966 | */ | ||
967 | suspend_time -= jiffies; | ||
968 | if (suspend_time > 0) { | ||
969 | if (!timer_pending(&udev->autosuspend.timer)) | ||
970 | queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, | ||
971 | suspend_time); | ||
972 | return -EAGAIN; | ||
973 | } | ||
961 | return 0; | 974 | return 0; |
962 | } | 975 | } |
963 | 976 | ||
@@ -1010,19 +1023,18 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
1010 | struct usb_interface *intf; | 1023 | struct usb_interface *intf; |
1011 | struct usb_device *parent = udev->parent; | 1024 | struct usb_device *parent = udev->parent; |
1012 | 1025 | ||
1013 | cancel_delayed_work(&udev->autosuspend); | 1026 | if (udev->state == USB_STATE_NOTATTACHED || |
1014 | if (udev->state == USB_STATE_NOTATTACHED) | 1027 | udev->state == USB_STATE_SUSPENDED) |
1015 | return 0; | 1028 | goto done; |
1016 | if (udev->state == USB_STATE_SUSPENDED) | ||
1017 | return 0; | ||
1018 | 1029 | ||
1019 | udev->do_remote_wakeup = device_may_wakeup(&udev->dev); | 1030 | udev->do_remote_wakeup = device_may_wakeup(&udev->dev); |
1020 | 1031 | ||
1021 | if (udev->auto_pm) { | 1032 | if (udev->auto_pm) { |
1022 | status = autosuspend_check(udev); | 1033 | status = autosuspend_check(udev); |
1023 | if (status < 0) | 1034 | if (status < 0) |
1024 | return status; | 1035 | goto done; |
1025 | } | 1036 | } |
1037 | cancel_delayed_work(&udev->autosuspend); | ||
1026 | 1038 | ||
1027 | /* Suspend all the interfaces and then udev itself */ | 1039 | /* Suspend all the interfaces and then udev itself */ |
1028 | if (udev->actconfig) { | 1040 | if (udev->actconfig) { |
@@ -1047,6 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
1047 | } else if (parent) | 1059 | } else if (parent) |
1048 | usb_autosuspend_device(parent); | 1060 | usb_autosuspend_device(parent); |
1049 | 1061 | ||
1062 | done: | ||
1050 | // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); | 1063 | // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); |
1051 | return status; | 1064 | return status; |
1052 | } | 1065 | } |
@@ -1086,14 +1099,18 @@ static int usb_resume_both(struct usb_device *udev) | |||
1086 | struct usb_interface *intf; | 1099 | struct usb_interface *intf; |
1087 | struct usb_device *parent = udev->parent; | 1100 | struct usb_device *parent = udev->parent; |
1088 | 1101 | ||
1089 | if (udev->auto_pm && udev->autoresume_disabled) | ||
1090 | return -EPERM; | ||
1091 | cancel_delayed_work(&udev->autosuspend); | 1102 | cancel_delayed_work(&udev->autosuspend); |
1092 | if (udev->state == USB_STATE_NOTATTACHED) | 1103 | if (udev->state == USB_STATE_NOTATTACHED) { |
1093 | return -ENODEV; | 1104 | status = -ENODEV; |
1105 | goto done; | ||
1106 | } | ||
1094 | 1107 | ||
1095 | /* Propagate the resume up the tree, if necessary */ | 1108 | /* Propagate the resume up the tree, if necessary */ |
1096 | if (udev->state == USB_STATE_SUSPENDED) { | 1109 | if (udev->state == USB_STATE_SUSPENDED) { |
1110 | if (udev->auto_pm && udev->autoresume_disabled) { | ||
1111 | status = -EPERM; | ||
1112 | goto done; | ||
1113 | } | ||
1097 | if (parent) { | 1114 | if (parent) { |
1098 | status = usb_autoresume_device(parent); | 1115 | status = usb_autoresume_device(parent); |
1099 | if (status == 0) { | 1116 | if (status == 0) { |
@@ -1139,24 +1156,13 @@ static int usb_resume_both(struct usb_device *udev) | |||
1139 | } | 1156 | } |
1140 | } | 1157 | } |
1141 | 1158 | ||
1159 | done: | ||
1142 | // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); | 1160 | // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); |
1143 | return status; | 1161 | return status; |
1144 | } | 1162 | } |
1145 | 1163 | ||
1146 | #ifdef CONFIG_USB_SUSPEND | 1164 | #ifdef CONFIG_USB_SUSPEND |
1147 | 1165 | ||
1148 | /* usb_autosuspend_work - callback routine to autosuspend a USB device */ | ||
1149 | void usb_autosuspend_work(struct work_struct *work) | ||
1150 | { | ||
1151 | struct usb_device *udev = | ||
1152 | container_of(work, struct usb_device, autosuspend.work); | ||
1153 | |||
1154 | usb_pm_lock(udev); | ||
1155 | udev->auto_pm = 1; | ||
1156 | usb_suspend_both(udev, PMSG_SUSPEND); | ||
1157 | usb_pm_unlock(udev); | ||
1158 | } | ||
1159 | |||
1160 | /* Internal routine to adjust a device's usage counter and change | 1166 | /* Internal routine to adjust a device's usage counter and change |
1161 | * its autosuspend state. | 1167 | * its autosuspend state. |
1162 | */ | 1168 | */ |
@@ -1165,20 +1171,34 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt) | |||
1165 | int status = 0; | 1171 | int status = 0; |
1166 | 1172 | ||
1167 | usb_pm_lock(udev); | 1173 | usb_pm_lock(udev); |
1174 | udev->auto_pm = 1; | ||
1168 | udev->pm_usage_cnt += inc_usage_cnt; | 1175 | udev->pm_usage_cnt += inc_usage_cnt; |
1169 | WARN_ON(udev->pm_usage_cnt < 0); | 1176 | WARN_ON(udev->pm_usage_cnt < 0); |
1170 | if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { | 1177 | if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { |
1171 | udev->auto_pm = 1; | 1178 | if (udev->state == USB_STATE_SUSPENDED) |
1172 | status = usb_resume_both(udev); | 1179 | status = usb_resume_both(udev); |
1173 | if (status != 0) | 1180 | if (status != 0) |
1174 | udev->pm_usage_cnt -= inc_usage_cnt; | 1181 | udev->pm_usage_cnt -= inc_usage_cnt; |
1175 | } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) | 1182 | else if (inc_usage_cnt) |
1176 | queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, | 1183 | udev->last_busy = jiffies; |
1177 | udev->autosuspend_delay); | 1184 | } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) { |
1185 | if (inc_usage_cnt) | ||
1186 | udev->last_busy = jiffies; | ||
1187 | status = usb_suspend_both(udev, PMSG_SUSPEND); | ||
1188 | } | ||
1178 | usb_pm_unlock(udev); | 1189 | usb_pm_unlock(udev); |
1179 | return status; | 1190 | return status; |
1180 | } | 1191 | } |
1181 | 1192 | ||
1193 | /* usb_autosuspend_work - callback routine to autosuspend a USB device */ | ||
1194 | void usb_autosuspend_work(struct work_struct *work) | ||
1195 | { | ||
1196 | struct usb_device *udev = | ||
1197 | container_of(work, struct usb_device, autosuspend.work); | ||
1198 | |||
1199 | usb_autopm_do_device(udev, 0); | ||
1200 | } | ||
1201 | |||
1182 | /** | 1202 | /** |
1183 | * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces | 1203 | * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces |
1184 | * @udev: the usb_device to autosuspend | 1204 | * @udev: the usb_device to autosuspend |
@@ -1270,15 +1290,20 @@ static int usb_autopm_do_interface(struct usb_interface *intf, | |||
1270 | if (intf->condition == USB_INTERFACE_UNBOUND) | 1290 | if (intf->condition == USB_INTERFACE_UNBOUND) |
1271 | status = -ENODEV; | 1291 | status = -ENODEV; |
1272 | else { | 1292 | else { |
1293 | udev->auto_pm = 1; | ||
1273 | intf->pm_usage_cnt += inc_usage_cnt; | 1294 | intf->pm_usage_cnt += inc_usage_cnt; |
1274 | if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { | 1295 | if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { |
1275 | udev->auto_pm = 1; | 1296 | if (udev->state == USB_STATE_SUSPENDED) |
1276 | status = usb_resume_both(udev); | 1297 | status = usb_resume_both(udev); |
1277 | if (status != 0) | 1298 | if (status != 0) |
1278 | intf->pm_usage_cnt -= inc_usage_cnt; | 1299 | intf->pm_usage_cnt -= inc_usage_cnt; |
1279 | } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) | 1300 | else if (inc_usage_cnt) |
1280 | queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, | 1301 | udev->last_busy = jiffies; |
1281 | udev->autosuspend_delay); | 1302 | } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { |
1303 | if (inc_usage_cnt) | ||
1304 | udev->last_busy = jiffies; | ||
1305 | status = usb_suspend_both(udev, PMSG_SUSPEND); | ||
1306 | } | ||
1282 | } | 1307 | } |
1283 | usb_pm_unlock(udev); | 1308 | usb_pm_unlock(udev); |
1284 | return status; | 1309 | return status; |
@@ -1337,11 +1362,14 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface); | |||
1337 | * or @intf is unbound. A typical example would be a character-device | 1362 | * or @intf is unbound. A typical example would be a character-device |
1338 | * driver when its device file is opened. | 1363 | * driver when its device file is opened. |
1339 | * | 1364 | * |
1340 | * The routine increments @intf's usage counter. So long as the counter | 1365 | * |
1341 | * is greater than 0, autosuspend will not be allowed for @intf or its | 1366 | * The routine increments @intf's usage counter. (However if the |
1342 | * usb_device. When the driver is finished using @intf it should call | 1367 | * autoresume fails then the counter is re-decremented.) So long as the |
1343 | * usb_autopm_put_interface() to decrement the usage counter and queue | 1368 | * counter is greater than 0, autosuspend will not be allowed for @intf |
1344 | * a delayed autosuspend request (if the counter is <= 0). | 1369 | * or its usb_device. When the driver is finished using @intf it should |
1370 | * call usb_autopm_put_interface() to decrement the usage counter and | ||
1371 | * queue a delayed autosuspend request (if the counter is <= 0). | ||
1372 | * | ||
1345 | * | 1373 | * |
1346 | * Note that @intf->pm_usage_cnt is owned by the interface driver. The | 1374 | * Note that @intf->pm_usage_cnt is owned by the interface driver. The |
1347 | * core will not change its value other than the increment and decrement | 1375 | * core will not change its value other than the increment and decrement |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8bc3ce6d9666..40cf882293e6 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1306,6 +1306,7 @@ static void hcd_resume_work(struct work_struct *work) | |||
1306 | struct usb_device *udev = hcd->self.root_hub; | 1306 | struct usb_device *udev = hcd->self.root_hub; |
1307 | 1307 | ||
1308 | usb_lock_device(udev); | 1308 | usb_lock_device(udev); |
1309 | usb_mark_last_busy(udev); | ||
1309 | usb_external_resume_device(udev); | 1310 | usb_external_resume_device(udev); |
1310 | usb_unlock_device(udev); | 1311 | usb_unlock_device(udev); |
1311 | } | 1312 | } |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2a0b15e42bc7..bde29ab2b504 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1859,6 +1859,7 @@ static int remote_wakeup(struct usb_device *udev) | |||
1859 | usb_lock_device(udev); | 1859 | usb_lock_device(udev); |
1860 | if (udev->state == USB_STATE_SUSPENDED) { | 1860 | if (udev->state == USB_STATE_SUSPENDED) { |
1861 | dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); | 1861 | dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); |
1862 | usb_mark_last_busy(udev); | ||
1862 | status = usb_external_resume_device(udev); | 1863 | status = usb_external_resume_device(udev); |
1863 | } | 1864 | } |
1864 | usb_unlock_device(udev); | 1865 | usb_unlock_device(udev); |
diff --git a/include/linux/usb.h b/include/linux/usb.h index f9e4445d5b53..cfbd2bb8fa2c 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
@@ -398,6 +398,7 @@ struct usb_device { | |||
398 | struct delayed_work autosuspend; /* for delayed autosuspends */ | 398 | struct delayed_work autosuspend; /* for delayed autosuspends */ |
399 | struct mutex pm_mutex; /* protects PM operations */ | 399 | struct mutex pm_mutex; /* protects PM operations */ |
400 | 400 | ||
401 | unsigned long last_busy; /* time of last use */ | ||
401 | int autosuspend_delay; /* in jiffies */ | 402 | int autosuspend_delay; /* in jiffies */ |
402 | 403 | ||
403 | unsigned auto_pm:1; /* autosuspend/resume in progress */ | 404 | unsigned auto_pm:1; /* autosuspend/resume in progress */ |
@@ -443,6 +444,11 @@ static inline void usb_autopm_disable(struct usb_interface *intf) | |||
443 | usb_autopm_set_interface(intf); | 444 | usb_autopm_set_interface(intf); |
444 | } | 445 | } |
445 | 446 | ||
447 | static inline void usb_mark_last_busy(struct usb_device *udev) | ||
448 | { | ||
449 | udev->last_busy = jiffies; | ||
450 | } | ||
451 | |||
446 | #else | 452 | #else |
447 | 453 | ||
448 | static inline int usb_autopm_set_interface(struct usb_interface *intf) | 454 | static inline int usb_autopm_set_interface(struct usb_interface *intf) |
@@ -457,6 +463,8 @@ static inline void usb_autopm_enable(struct usb_interface *intf) | |||
457 | { } | 463 | { } |
458 | static inline void usb_autopm_disable(struct usb_interface *intf) | 464 | static inline void usb_autopm_disable(struct usb_interface *intf) |
459 | { } | 465 | { } |
466 | static inline void usb_mark_last_busy(struct usb_device *udev) | ||
467 | { } | ||
460 | #endif | 468 | #endif |
461 | 469 | ||
462 | /*-------------------------------------------------------------------------*/ | 470 | /*-------------------------------------------------------------------------*/ |