diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2008-11-25 16:39:18 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-07 13:00:03 -0500 |
commit | 65bfd2967c906ca322a4bb69a285fe0de8916ac6 (patch) | |
tree | ddd3293f945613d0d27ec1dbd36030c079fb9492 /drivers/usb/core/driver.c | |
parent | 4ec06d629628b6e5c7ff50d349a26ef5c35696e3 (diff) |
USB: Enhance usage of pm_message_t
This patch (as1177) modifies the USB core suspend and resume
routines. The resume functions now will take a pm_message_t argument,
so they will know what sort of resume is occurring. The new argument
is also passed to the port suspend/resume and bus suspend/resume
routines (although they don't use it for anything but debugging).
In addition, special pm_message_t values are used for user-initiated,
device-initiated (i.e., remote wakeup), and automatic suspend/resume.
By testing these values, drivers can tell whether or not a particular
suspend was an autosuspend. Unfortunately, they can't do the same for
resumes -- not until the pm_message_t argument is also passed to the
drivers' resume methods. That will require a bigger change.
IMO, the whole Power Management framework should have been set up this
way in the first place.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r-- | drivers/usb/core/driver.c | 61 |
1 files changed, 34 insertions, 27 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 0226e019326..41c06025506 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -922,7 +922,7 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) | |||
922 | } | 922 | } |
923 | 923 | ||
924 | /* Caller has locked udev's pm_mutex */ | 924 | /* Caller has locked udev's pm_mutex */ |
925 | static int usb_resume_device(struct usb_device *udev) | 925 | static int usb_resume_device(struct usb_device *udev, pm_message_t msg) |
926 | { | 926 | { |
927 | struct usb_device_driver *udriver; | 927 | struct usb_device_driver *udriver; |
928 | int status = 0; | 928 | int status = 0; |
@@ -940,7 +940,7 @@ static int usb_resume_device(struct usb_device *udev) | |||
940 | udev->reset_resume = 1; | 940 | udev->reset_resume = 1; |
941 | 941 | ||
942 | udriver = to_usb_device_driver(udev->dev.driver); | 942 | udriver = to_usb_device_driver(udev->dev.driver); |
943 | status = udriver->resume(udev); | 943 | status = udriver->resume(udev, msg); |
944 | 944 | ||
945 | done: | 945 | done: |
946 | dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); | 946 | dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); |
@@ -969,7 +969,7 @@ static int usb_suspend_interface(struct usb_device *udev, | |||
969 | status = driver->suspend(intf, msg); | 969 | status = driver->suspend(intf, msg); |
970 | if (status == 0) | 970 | if (status == 0) |
971 | mark_quiesced(intf); | 971 | mark_quiesced(intf); |
972 | else if (!udev->auto_pm) | 972 | else if (!(msg.event & PM_EVENT_AUTO)) |
973 | dev_err(&intf->dev, "%s error %d\n", | 973 | dev_err(&intf->dev, "%s error %d\n", |
974 | "suspend", status); | 974 | "suspend", status); |
975 | } else { | 975 | } else { |
@@ -987,7 +987,7 @@ static int usb_suspend_interface(struct usb_device *udev, | |||
987 | 987 | ||
988 | /* Caller has locked intf's usb_device's pm_mutex */ | 988 | /* Caller has locked intf's usb_device's pm_mutex */ |
989 | static int usb_resume_interface(struct usb_device *udev, | 989 | static int usb_resume_interface(struct usb_device *udev, |
990 | struct usb_interface *intf, int reset_resume) | 990 | struct usb_interface *intf, pm_message_t msg, int reset_resume) |
991 | { | 991 | { |
992 | struct usb_driver *driver; | 992 | struct usb_driver *driver; |
993 | int status = 0; | 993 | int status = 0; |
@@ -1138,10 +1138,9 @@ static inline int autosuspend_check(struct usb_device *udev, int reschedule) | |||
1138 | * all the interfaces which were suspended are resumed so that they remain | 1138 | * all the interfaces which were suspended are resumed so that they remain |
1139 | * in the same state as the device. | 1139 | * in the same state as the device. |
1140 | * | 1140 | * |
1141 | * If an autosuspend is in progress (@udev->auto_pm is set), the routine | 1141 | * If an autosuspend is in progress the routine checks first to make sure |
1142 | * checks first to make sure that neither the device itself or any of its | 1142 | * that neither the device itself or any of its active interfaces is in use |
1143 | * active interfaces is in use (pm_usage_cnt is greater than 0). If they | 1143 | * (pm_usage_cnt is greater than 0). If they are, the autosuspend fails. |
1144 | * are, the autosuspend fails. | ||
1145 | * | 1144 | * |
1146 | * If the suspend succeeds, the routine recursively queues an autosuspend | 1145 | * If the suspend succeeds, the routine recursively queues an autosuspend |
1147 | * request for @udev's parent device, thereby propagating the change up | 1146 | * request for @udev's parent device, thereby propagating the change up |
@@ -1176,7 +1175,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
1176 | 1175 | ||
1177 | udev->do_remote_wakeup = device_may_wakeup(&udev->dev); | 1176 | udev->do_remote_wakeup = device_may_wakeup(&udev->dev); |
1178 | 1177 | ||
1179 | if (udev->auto_pm) { | 1178 | if (msg.event & PM_EVENT_AUTO) { |
1180 | status = autosuspend_check(udev, 0); | 1179 | status = autosuspend_check(udev, 0); |
1181 | if (status < 0) | 1180 | if (status < 0) |
1182 | goto done; | 1181 | goto done; |
@@ -1196,13 +1195,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
1196 | 1195 | ||
1197 | /* If the suspend failed, resume interfaces that did get suspended */ | 1196 | /* If the suspend failed, resume interfaces that did get suspended */ |
1198 | if (status != 0) { | 1197 | if (status != 0) { |
1198 | pm_message_t msg2; | ||
1199 | |||
1200 | msg2.event = msg.event ^ (PM_EVENT_SUSPEND | PM_EVENT_RESUME); | ||
1199 | while (--i >= 0) { | 1201 | while (--i >= 0) { |
1200 | intf = udev->actconfig->interface[i]; | 1202 | intf = udev->actconfig->interface[i]; |
1201 | usb_resume_interface(udev, intf, 0); | 1203 | usb_resume_interface(udev, intf, msg2, 0); |
1202 | } | 1204 | } |
1203 | 1205 | ||
1204 | /* Try another autosuspend when the interfaces aren't busy */ | 1206 | /* Try another autosuspend when the interfaces aren't busy */ |
1205 | if (udev->auto_pm) | 1207 | if (msg.event & PM_EVENT_AUTO) |
1206 | autosuspend_check(udev, status == -EBUSY); | 1208 | autosuspend_check(udev, status == -EBUSY); |
1207 | 1209 | ||
1208 | /* If the suspend succeeded then prevent any more URB submissions, | 1210 | /* If the suspend succeeded then prevent any more URB submissions, |
@@ -1232,6 +1234,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
1232 | /** | 1234 | /** |
1233 | * usb_resume_both - resume a USB device and its interfaces | 1235 | * usb_resume_both - resume a USB device and its interfaces |
1234 | * @udev: the usb_device to resume | 1236 | * @udev: the usb_device to resume |
1237 | * @msg: Power Management message describing this state transition | ||
1235 | * | 1238 | * |
1236 | * This is the central routine for resuming USB devices. It calls the | 1239 | * This is the central routine for resuming USB devices. It calls the |
1237 | * the resume method for @udev and then calls the resume methods for all | 1240 | * the resume method for @udev and then calls the resume methods for all |
@@ -1257,7 +1260,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) | |||
1257 | * | 1260 | * |
1258 | * This routine can run only in process context. | 1261 | * This routine can run only in process context. |
1259 | */ | 1262 | */ |
1260 | static int usb_resume_both(struct usb_device *udev) | 1263 | static int usb_resume_both(struct usb_device *udev, pm_message_t msg) |
1261 | { | 1264 | { |
1262 | int status = 0; | 1265 | int status = 0; |
1263 | int i; | 1266 | int i; |
@@ -1273,14 +1276,15 @@ static int usb_resume_both(struct usb_device *udev) | |||
1273 | 1276 | ||
1274 | /* Propagate the resume up the tree, if necessary */ | 1277 | /* Propagate the resume up the tree, if necessary */ |
1275 | if (udev->state == USB_STATE_SUSPENDED) { | 1278 | if (udev->state == USB_STATE_SUSPENDED) { |
1276 | if (udev->auto_pm && udev->autoresume_disabled) { | 1279 | if ((msg.event & PM_EVENT_AUTO) && |
1280 | udev->autoresume_disabled) { | ||
1277 | status = -EPERM; | 1281 | status = -EPERM; |
1278 | goto done; | 1282 | goto done; |
1279 | } | 1283 | } |
1280 | if (parent) { | 1284 | if (parent) { |
1281 | status = usb_autoresume_device(parent); | 1285 | status = usb_autoresume_device(parent); |
1282 | if (status == 0) { | 1286 | if (status == 0) { |
1283 | status = usb_resume_device(udev); | 1287 | status = usb_resume_device(udev, msg); |
1284 | if (status || udev->state == | 1288 | if (status || udev->state == |
1285 | USB_STATE_NOTATTACHED) { | 1289 | USB_STATE_NOTATTACHED) { |
1286 | usb_autosuspend_device(parent); | 1290 | usb_autosuspend_device(parent); |
@@ -1303,15 +1307,16 @@ static int usb_resume_both(struct usb_device *udev) | |||
1303 | /* We can't progagate beyond the USB subsystem, | 1307 | /* We can't progagate beyond the USB subsystem, |
1304 | * so if a root hub's controller is suspended | 1308 | * so if a root hub's controller is suspended |
1305 | * then we're stuck. */ | 1309 | * then we're stuck. */ |
1306 | status = usb_resume_device(udev); | 1310 | status = usb_resume_device(udev, msg); |
1307 | } | 1311 | } |
1308 | } else if (udev->reset_resume) | 1312 | } else if (udev->reset_resume) |
1309 | status = usb_resume_device(udev); | 1313 | status = usb_resume_device(udev, msg); |
1310 | 1314 | ||
1311 | if (status == 0 && udev->actconfig) { | 1315 | if (status == 0 && udev->actconfig) { |
1312 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { | 1316 | for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { |
1313 | intf = udev->actconfig->interface[i]; | 1317 | intf = udev->actconfig->interface[i]; |
1314 | usb_resume_interface(udev, intf, udev->reset_resume); | 1318 | usb_resume_interface(udev, intf, msg, |
1319 | udev->reset_resume); | ||
1315 | } | 1320 | } |
1316 | } | 1321 | } |
1317 | 1322 | ||
@@ -1339,13 +1344,13 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt) | |||
1339 | udev->last_busy = jiffies; | 1344 | udev->last_busy = jiffies; |
1340 | if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { | 1345 | if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { |
1341 | if (udev->state == USB_STATE_SUSPENDED) | 1346 | if (udev->state == USB_STATE_SUSPENDED) |
1342 | status = usb_resume_both(udev); | 1347 | status = usb_resume_both(udev, PMSG_AUTO_RESUME); |
1343 | if (status != 0) | 1348 | if (status != 0) |
1344 | udev->pm_usage_cnt -= inc_usage_cnt; | 1349 | udev->pm_usage_cnt -= inc_usage_cnt; |
1345 | else if (inc_usage_cnt) | 1350 | else if (inc_usage_cnt) |
1346 | udev->last_busy = jiffies; | 1351 | udev->last_busy = jiffies; |
1347 | } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) { | 1352 | } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) { |
1348 | status = usb_suspend_both(udev, PMSG_SUSPEND); | 1353 | status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); |
1349 | } | 1354 | } |
1350 | usb_pm_unlock(udev); | 1355 | usb_pm_unlock(udev); |
1351 | return status; | 1356 | return status; |
@@ -1469,13 +1474,14 @@ static int usb_autopm_do_interface(struct usb_interface *intf, | |||
1469 | udev->last_busy = jiffies; | 1474 | udev->last_busy = jiffies; |
1470 | if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { | 1475 | if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { |
1471 | if (udev->state == USB_STATE_SUSPENDED) | 1476 | if (udev->state == USB_STATE_SUSPENDED) |
1472 | status = usb_resume_both(udev); | 1477 | status = usb_resume_both(udev, |
1478 | PMSG_AUTO_RESUME); | ||
1473 | if (status != 0) | 1479 | if (status != 0) |
1474 | intf->pm_usage_cnt -= inc_usage_cnt; | 1480 | intf->pm_usage_cnt -= inc_usage_cnt; |
1475 | else | 1481 | else |
1476 | udev->last_busy = jiffies; | 1482 | udev->last_busy = jiffies; |
1477 | } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { | 1483 | } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { |
1478 | status = usb_suspend_both(udev, PMSG_SUSPEND); | 1484 | status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); |
1479 | } | 1485 | } |
1480 | } | 1486 | } |
1481 | usb_pm_unlock(udev); | 1487 | usb_pm_unlock(udev); |
@@ -1700,6 +1706,7 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg) | |||
1700 | /** | 1706 | /** |
1701 | * usb_external_resume_device - external resume of a USB device and its interfaces | 1707 | * usb_external_resume_device - external resume of a USB device and its interfaces |
1702 | * @udev: the usb_device to resume | 1708 | * @udev: the usb_device to resume |
1709 | * @msg: Power Management message describing this state transition | ||
1703 | * | 1710 | * |
1704 | * This routine handles external resume requests: ones not generated | 1711 | * This routine handles external resume requests: ones not generated |
1705 | * internally by a USB driver (autoresume) but rather coming from the user | 1712 | * internally by a USB driver (autoresume) but rather coming from the user |
@@ -1708,13 +1715,13 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg) | |||
1708 | * | 1715 | * |
1709 | * The caller must hold @udev's device lock. | 1716 | * The caller must hold @udev's device lock. |
1710 | */ | 1717 | */ |
1711 | int usb_external_resume_device(struct usb_device *udev) | 1718 | int usb_external_resume_device(struct usb_device *udev, pm_message_t msg) |
1712 | { | 1719 | { |
1713 | int status; | 1720 | int status; |
1714 | 1721 | ||
1715 | usb_pm_lock(udev); | 1722 | usb_pm_lock(udev); |
1716 | udev->auto_pm = 0; | 1723 | udev->auto_pm = 0; |
1717 | status = usb_resume_both(udev); | 1724 | status = usb_resume_both(udev, msg); |
1718 | udev->last_busy = jiffies; | 1725 | udev->last_busy = jiffies; |
1719 | usb_pm_unlock(udev); | 1726 | usb_pm_unlock(udev); |
1720 | if (status == 0) | 1727 | if (status == 0) |
@@ -1727,7 +1734,7 @@ int usb_external_resume_device(struct usb_device *udev) | |||
1727 | return status; | 1734 | return status; |
1728 | } | 1735 | } |
1729 | 1736 | ||
1730 | int usb_suspend(struct device *dev, pm_message_t message) | 1737 | int usb_suspend(struct device *dev, pm_message_t msg) |
1731 | { | 1738 | { |
1732 | struct usb_device *udev; | 1739 | struct usb_device *udev; |
1733 | 1740 | ||
@@ -1746,10 +1753,10 @@ int usb_suspend(struct device *dev, pm_message_t message) | |||
1746 | } | 1753 | } |
1747 | 1754 | ||
1748 | udev->skip_sys_resume = 0; | 1755 | udev->skip_sys_resume = 0; |
1749 | return usb_external_suspend_device(udev, message); | 1756 | return usb_external_suspend_device(udev, msg); |
1750 | } | 1757 | } |
1751 | 1758 | ||
1752 | int usb_resume(struct device *dev) | 1759 | int usb_resume(struct device *dev, pm_message_t msg) |
1753 | { | 1760 | { |
1754 | struct usb_device *udev; | 1761 | struct usb_device *udev; |
1755 | 1762 | ||
@@ -1761,7 +1768,7 @@ int usb_resume(struct device *dev) | |||
1761 | */ | 1768 | */ |
1762 | if (udev->skip_sys_resume) | 1769 | if (udev->skip_sys_resume) |
1763 | return 0; | 1770 | return 0; |
1764 | return usb_external_resume_device(udev); | 1771 | return usb_external_resume_device(udev, msg); |
1765 | } | 1772 | } |
1766 | 1773 | ||
1767 | #endif /* CONFIG_PM */ | 1774 | #endif /* CONFIG_PM */ |