diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2009-12-07 13:01:37 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:25 -0500 |
| commit | 8e4ceb38eb5bbaef22fc00abe9bc11e26bea2ab5 (patch) | |
| tree | 7cb5fee6c50add1094aed430d46afeb2c7689b51 | |
| parent | 9af23624ae2c7978313b46e58fdc4ca5d8b799f5 (diff) | |
USB: prepare for changover to Runtime PM framework
This patch (as1303) revises the USB Power Management infrastructure to
make it compatible with the new driver-model Runtime PM framework:
Drivers are no longer allowed to access intf->pm_usage_cnt
directly; the PM framework manages its own usage counters.
usb_autopm_set_interface() is eliminated, because it directly
sets intf->pm_usage_cnt.
usb_autopm_enable() and usb_autopm_disable() are eliminated,
because they call usb_autopm_set_interface().
usb_autopm_get_interface_no_resume() and
usb_autopm_put_interface_no_suspend() are added. They
correspond to pm_runtime_get_noresume() and
pm_runtime_put_noidle() in the PM framework.
The power/level attribute no longer accepts "suspend", only
"on" and "auto". The PM framework doesn't allow devices to be
forced into a suspended mode.
The hub driver contains the only code that violates the new
guidelines. It is updated to use the new interface routines instead.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | Documentation/usb/power-management.txt | 60 | ||||
| -rw-r--r-- | drivers/usb/core/driver.c | 31 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 45 | ||||
| -rw-r--r-- | drivers/usb/core/sysfs.c | 25 | ||||
| -rw-r--r-- | include/linux/usb.h | 26 |
5 files changed, 74 insertions, 113 deletions
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt index 8817368203d6..c7c1dc2f8017 100644 --- a/Documentation/usb/power-management.txt +++ b/Documentation/usb/power-management.txt | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | Alan Stern <stern@rowland.harvard.edu> | 3 | Alan Stern <stern@rowland.harvard.edu> |
| 4 | 4 | ||
| 5 | October 5, 2007 | 5 | November 10, 2009 |
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | 8 | ||
| @@ -123,9 +123,9 @@ relevant attribute files are: wakeup, level, and autosuspend. | |||
| 123 | 123 | ||
| 124 | power/level | 124 | power/level |
| 125 | 125 | ||
| 126 | This file contains one of three words: "on", "auto", | 126 | This file contains one of two words: "on" or "auto". |
| 127 | or "suspend". You can write those words to the file | 127 | You can write those words to the file to change the |
| 128 | to change the device's setting. | 128 | device's setting. |
| 129 | 129 | ||
| 130 | "on" means that the device should be resumed and | 130 | "on" means that the device should be resumed and |
| 131 | autosuspend is not allowed. (Of course, system | 131 | autosuspend is not allowed. (Of course, system |
| @@ -134,10 +134,10 @@ relevant attribute files are: wakeup, level, and autosuspend. | |||
| 134 | "auto" is the normal state in which the kernel is | 134 | "auto" is the normal state in which the kernel is |
| 135 | allowed to autosuspend and autoresume the device. | 135 | allowed to autosuspend and autoresume the device. |
| 136 | 136 | ||
| 137 | "suspend" means that the device should remain | 137 | (In kernels up to 2.6.32, you could also specify |
| 138 | suspended, and autoresume is not allowed. (But remote | 138 | "suspend", meaning that the device should remain |
| 139 | wakeup may still be allowed, since it is controlled | 139 | suspended and autoresume was not allowed. This |
| 140 | separately by the power/wakeup attribute.) | 140 | setting is no longer supported.) |
| 141 | 141 | ||
| 142 | power/autosuspend | 142 | power/autosuspend |
| 143 | 143 | ||
| @@ -313,13 +313,14 @@ three of the methods listed above. In addition, a driver indicates | |||
| 313 | that it supports autosuspend by setting the .supports_autosuspend flag | 313 | that it supports autosuspend by setting the .supports_autosuspend flag |
| 314 | in its usb_driver structure. It is then responsible for informing the | 314 | in its usb_driver structure. It is then responsible for informing the |
| 315 | USB core whenever one of its interfaces becomes busy or idle. The | 315 | USB core whenever one of its interfaces becomes busy or idle. The |
| 316 | driver does so by calling these five functions: | 316 | driver does so by calling these six functions: |
| 317 | 317 | ||
| 318 | int usb_autopm_get_interface(struct usb_interface *intf); | 318 | int usb_autopm_get_interface(struct usb_interface *intf); |
| 319 | void usb_autopm_put_interface(struct usb_interface *intf); | 319 | void usb_autopm_put_interface(struct usb_interface *intf); |
| 320 | int usb_autopm_set_interface(struct usb_interface *intf); | ||
| 321 | int usb_autopm_get_interface_async(struct usb_interface *intf); | 320 | int usb_autopm_get_interface_async(struct usb_interface *intf); |
| 322 | void usb_autopm_put_interface_async(struct usb_interface *intf); | 321 | void usb_autopm_put_interface_async(struct usb_interface *intf); |
| 322 | void usb_autopm_get_interface_no_resume(struct usb_interface *intf); | ||
| 323 | void usb_autopm_put_interface_no_suspend(struct usb_interface *intf); | ||
| 323 | 324 | ||
| 324 | The functions work by maintaining a counter in the usb_interface | 325 | The functions work by maintaining a counter in the usb_interface |
| 325 | structure. When intf->pm_usage_count is > 0 then the interface is | 326 | structure. When intf->pm_usage_count is > 0 then the interface is |
| @@ -331,11 +332,13 @@ considered to be idle, and the kernel may autosuspend the device. | |||
| 331 | associated with the device itself rather than any of its interfaces. | 332 | associated with the device itself rather than any of its interfaces. |
| 332 | This field is used only by the USB core.) | 333 | This field is used only by the USB core.) |
| 333 | 334 | ||
| 334 | The driver owns intf->pm_usage_count; it can modify the value however | 335 | Drivers must not modify intf->pm_usage_count directly; its value |
| 335 | and whenever it likes. A nice aspect of the non-async usb_autopm_* | 336 | should be changed only be using the functions listed above. Drivers |
| 336 | routines is that the changes they make are protected by the usb_device | 337 | are responsible for insuring that the overall change to pm_usage_count |
| 337 | structure's PM mutex (udev->pm_mutex); however drivers may change | 338 | during their lifetime balances out to 0 (it may be necessary for the |
| 338 | pm_usage_count without holding the mutex. Drivers using the async | 339 | disconnect method to call usb_autopm_put_interface() one or more times |
| 340 | to fulfill this requirement). The first two routines use the PM mutex | ||
| 341 | in struct usb_device for mutual exclusion; drivers using the async | ||
| 339 | routines are responsible for their own synchronization and mutual | 342 | routines are responsible for their own synchronization and mutual |
| 340 | exclusion. | 343 | exclusion. |
| 341 | 344 | ||
| @@ -347,11 +350,6 @@ exclusion. | |||
| 347 | attempts an autosuspend if the new value is <= 0 and the | 350 | attempts an autosuspend if the new value is <= 0 and the |
| 348 | device isn't suspended. | 351 | device isn't suspended. |
| 349 | 352 | ||
| 350 | usb_autopm_set_interface() leaves pm_usage_count alone. | ||
| 351 | It attempts an autoresume if the value is > 0 and the device | ||
| 352 | is suspended, and it attempts an autosuspend if the value is | ||
| 353 | <= 0 and the device isn't suspended. | ||
| 354 | |||
| 355 | usb_autopm_get_interface_async() and | 353 | usb_autopm_get_interface_async() and |
| 356 | usb_autopm_put_interface_async() do almost the same things as | 354 | usb_autopm_put_interface_async() do almost the same things as |
| 357 | their non-async counterparts. The differences are: they do | 355 | their non-async counterparts. The differences are: they do |
| @@ -360,13 +358,11 @@ exclusion. | |||
| 360 | such as an URB's completion handler, but when they return the | 358 | such as an URB's completion handler, but when they return the |
| 361 | device will not generally not yet be in the desired state. | 359 | device will not generally not yet be in the desired state. |
| 362 | 360 | ||
| 363 | There also are a couple of utility routines drivers can use: | 361 | usb_autopm_get_interface_no_resume() and |
| 364 | 362 | usb_autopm_put_interface_no_suspend() merely increment or | |
| 365 | usb_autopm_enable() sets pm_usage_cnt to 0 and then calls | 363 | decrement the pm_usage_count value; they do not attempt to |
| 366 | usb_autopm_set_interface(), which will attempt an autosuspend. | 364 | carry out an autoresume or an autosuspend. Hence they can be |
| 367 | 365 | called in an atomic context. | |
| 368 | usb_autopm_disable() sets pm_usage_cnt to 1 and then calls | ||
| 369 | usb_autopm_set_interface(), which will attempt an autoresume. | ||
| 370 | 366 | ||
| 371 | The conventional usage pattern is that a driver calls | 367 | The conventional usage pattern is that a driver calls |
| 372 | usb_autopm_get_interface() in its open routine and | 368 | usb_autopm_get_interface() in its open routine and |
| @@ -400,11 +396,11 @@ though, setting this flag won't cause the kernel to autoresume it. | |||
| 400 | Normally a driver would set this flag in its probe method, at which | 396 | Normally a driver would set this flag in its probe method, at which |
| 401 | time the device is guaranteed not to be autosuspended.) | 397 | time the device is guaranteed not to be autosuspended.) |
| 402 | 398 | ||
| 403 | The usb_autopm_* routines have to run in a sleepable process context; | 399 | The synchronous usb_autopm_* routines have to run in a sleepable |
| 404 | they must not be called from an interrupt handler or while holding a | 400 | process context; they must not be called from an interrupt handler or |
| 405 | spinlock. In fact, the entire autosuspend mechanism is not well geared | 401 | while holding a spinlock. In fact, the entire autosuspend mechanism |
| 406 | toward interrupt-driven operation. However there is one thing a | 402 | is not well geared toward interrupt-driven operation. However there |
| 407 | driver can do in an interrupt handler: | 403 | is one thing a driver can do in an interrupt handler: |
| 408 | 404 | ||
| 409 | usb_mark_last_busy(struct usb_device *udev); | 405 | usb_mark_last_busy(struct usb_device *udev); |
| 410 | 406 | ||
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 8016a296010e..7a05bab73960 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
| @@ -948,8 +948,6 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg) | |||
| 948 | 948 | ||
| 949 | done: | 949 | done: |
| 950 | dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); | 950 | dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); |
| 951 | if (status == 0) | ||
| 952 | udev->autoresume_disabled = 0; | ||
| 953 | return status; | 951 | return status; |
| 954 | } | 952 | } |
| 955 | 953 | ||
| @@ -1280,11 +1278,6 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) | |||
| 1280 | 1278 | ||
| 1281 | /* Propagate the resume up the tree, if necessary */ | 1279 | /* Propagate the resume up the tree, if necessary */ |
| 1282 | if (udev->state == USB_STATE_SUSPENDED) { | 1280 | if (udev->state == USB_STATE_SUSPENDED) { |
| 1283 | if ((msg.event & PM_EVENT_AUTO) && | ||
| 1284 | udev->autoresume_disabled) { | ||
| 1285 | status = -EPERM; | ||
| 1286 | goto done; | ||
| 1287 | } | ||
| 1288 | if (parent) { | 1281 | if (parent) { |
| 1289 | status = usb_autoresume_device(parent); | 1282 | status = usb_autoresume_device(parent); |
| 1290 | if (status == 0) { | 1283 | if (status == 0) { |
| @@ -1638,8 +1631,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf) | |||
| 1638 | 1631 | ||
| 1639 | if (intf->condition == USB_INTERFACE_UNBOUND) | 1632 | if (intf->condition == USB_INTERFACE_UNBOUND) |
| 1640 | status = -ENODEV; | 1633 | status = -ENODEV; |
| 1641 | else if (udev->autoresume_disabled) | ||
| 1642 | status = -EPERM; | ||
| 1643 | else { | 1634 | else { |
| 1644 | atomic_inc(&intf->pm_usage_cnt); | 1635 | atomic_inc(&intf->pm_usage_cnt); |
| 1645 | if (atomic_read(&intf->pm_usage_cnt) > 0 && | 1636 | if (atomic_read(&intf->pm_usage_cnt) > 0 && |
| @@ -1652,28 +1643,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf) | |||
| 1652 | } | 1643 | } |
| 1653 | EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); | 1644 | EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); |
| 1654 | 1645 | ||
| 1655 | /** | ||
| 1656 | * usb_autopm_set_interface - set a USB interface's autosuspend state | ||
| 1657 | * @intf: the usb_interface whose state should be set | ||
| 1658 | * | ||
| 1659 | * This routine sets the autosuspend state of @intf's device according | ||
| 1660 | * to @intf's usage counter, which the caller must have set previously. | ||
| 1661 | * If the counter is <= 0, the device is autosuspended (if it isn't | ||
| 1662 | * already suspended and if nothing else prevents the autosuspend). If | ||
| 1663 | * the counter is > 0, the device is autoresumed (if it isn't already | ||
| 1664 | * awake). | ||
| 1665 | */ | ||
| 1666 | int usb_autopm_set_interface(struct usb_interface *intf) | ||
| 1667 | { | ||
| 1668 | int status; | ||
| 1669 | |||
| 1670 | status = usb_autopm_do_interface(intf, 0); | ||
| 1671 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", | ||
| 1672 | __func__, status, atomic_read(&intf->pm_usage_cnt)); | ||
| 1673 | return status; | ||
| 1674 | } | ||
| 1675 | EXPORT_SYMBOL_GPL(usb_autopm_set_interface); | ||
| 1676 | |||
| 1677 | #else | 1646 | #else |
| 1678 | 1647 | ||
| 1679 | void usb_autosuspend_work(struct work_struct *work) | 1648 | void usb_autosuspend_work(struct work_struct *work) |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5413d712cae0..b38fd6730e2a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -71,6 +71,7 @@ struct usb_hub { | |||
| 71 | 71 | ||
| 72 | unsigned mA_per_port; /* current for each child */ | 72 | unsigned mA_per_port; /* current for each child */ |
| 73 | 73 | ||
| 74 | unsigned init_done:1; | ||
| 74 | unsigned limited_power:1; | 75 | unsigned limited_power:1; |
| 75 | unsigned quiescing:1; | 76 | unsigned quiescing:1; |
| 76 | unsigned disconnected:1; | 77 | unsigned disconnected:1; |
| @@ -375,12 +376,13 @@ static void kick_khubd(struct usb_hub *hub) | |||
| 375 | { | 376 | { |
| 376 | unsigned long flags; | 377 | unsigned long flags; |
| 377 | 378 | ||
| 378 | /* Suppress autosuspend until khubd runs */ | ||
| 379 | atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1); | ||
| 380 | |||
| 381 | spin_lock_irqsave(&hub_event_lock, flags); | 379 | spin_lock_irqsave(&hub_event_lock, flags); |
| 382 | if (!hub->disconnected && list_empty(&hub->event_list)) { | 380 | if (!hub->disconnected && list_empty(&hub->event_list)) { |
| 383 | list_add_tail(&hub->event_list, &hub_event_list); | 381 | list_add_tail(&hub->event_list, &hub_event_list); |
| 382 | |||
| 383 | /* Suppress autosuspend until khubd runs */ | ||
| 384 | usb_autopm_get_interface_no_resume( | ||
| 385 | to_usb_interface(hub->intfdev)); | ||
| 384 | wake_up(&khubd_wait); | 386 | wake_up(&khubd_wait); |
| 385 | } | 387 | } |
| 386 | spin_unlock_irqrestore(&hub_event_lock, flags); | 388 | spin_unlock_irqrestore(&hub_event_lock, flags); |
| @@ -665,7 +667,7 @@ int usb_remove_device(struct usb_device *udev) | |||
| 665 | } | 667 | } |
| 666 | 668 | ||
| 667 | enum hub_activation_type { | 669 | enum hub_activation_type { |
| 668 | HUB_INIT, HUB_INIT2, HUB_INIT3, | 670 | HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */ |
| 669 | HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, | 671 | HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, |
| 670 | }; | 672 | }; |
| 671 | 673 | ||
| @@ -710,8 +712,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
| 710 | msecs_to_jiffies(delay)); | 712 | msecs_to_jiffies(delay)); |
| 711 | 713 | ||
| 712 | /* Suppress autosuspend until init is done */ | 714 | /* Suppress autosuspend until init is done */ |
| 713 | atomic_set(&to_usb_interface(hub->intfdev)-> | 715 | usb_autopm_get_interface_no_resume( |
| 714 | pm_usage_cnt, 1); | 716 | to_usb_interface(hub->intfdev)); |
| 715 | return; /* Continues at init2: below */ | 717 | return; /* Continues at init2: below */ |
| 716 | } else { | 718 | } else { |
| 717 | hub_power_on(hub, true); | 719 | hub_power_on(hub, true); |
| @@ -818,6 +820,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
| 818 | } | 820 | } |
| 819 | init3: | 821 | init3: |
| 820 | hub->quiescing = 0; | 822 | hub->quiescing = 0; |
| 823 | hub->init_done = 1; | ||
| 821 | 824 | ||
| 822 | status = usb_submit_urb(hub->urb, GFP_NOIO); | 825 | status = usb_submit_urb(hub->urb, GFP_NOIO); |
| 823 | if (status < 0) | 826 | if (status < 0) |
| @@ -827,6 +830,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
| 827 | 830 | ||
| 828 | /* Scan all ports that need attention */ | 831 | /* Scan all ports that need attention */ |
| 829 | kick_khubd(hub); | 832 | kick_khubd(hub); |
| 833 | |||
| 834 | /* Allow autosuspend if it was suppressed */ | ||
| 835 | if (type <= HUB_INIT3) | ||
| 836 | usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); | ||
| 830 | } | 837 | } |
| 831 | 838 | ||
| 832 | /* Implement the continuations for the delays above */ | 839 | /* Implement the continuations for the delays above */ |
| @@ -854,6 +861,11 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) | |||
| 854 | int i; | 861 | int i; |
| 855 | 862 | ||
| 856 | cancel_delayed_work_sync(&hub->init_work); | 863 | cancel_delayed_work_sync(&hub->init_work); |
| 864 | if (!hub->init_done) { | ||
| 865 | hub->init_done = 1; | ||
| 866 | usb_autopm_put_interface_no_suspend( | ||
| 867 | to_usb_interface(hub->intfdev)); | ||
| 868 | } | ||
| 857 | 869 | ||
| 858 | /* khubd and related activity won't re-trigger */ | 870 | /* khubd and related activity won't re-trigger */ |
| 859 | hub->quiescing = 1; | 871 | hub->quiescing = 1; |
| @@ -1176,7 +1188,10 @@ static void hub_disconnect(struct usb_interface *intf) | |||
| 1176 | 1188 | ||
| 1177 | /* Take the hub off the event list and don't let it be added again */ | 1189 | /* Take the hub off the event list and don't let it be added again */ |
| 1178 | spin_lock_irq(&hub_event_lock); | 1190 | spin_lock_irq(&hub_event_lock); |
| 1179 | list_del_init(&hub->event_list); | 1191 | if (!list_empty(&hub->event_list)) { |
| 1192 | list_del_init(&hub->event_list); | ||
| 1193 | usb_autopm_put_interface_no_suspend(intf); | ||
| 1194 | } | ||
| 1180 | hub->disconnected = 1; | 1195 | hub->disconnected = 1; |
| 1181 | spin_unlock_irq(&hub_event_lock); | 1196 | spin_unlock_irq(&hub_event_lock); |
| 1182 | 1197 | ||
| @@ -3235,7 +3250,7 @@ static void hub_events(void) | |||
| 3235 | * disconnected while waiting for the lock to succeed. */ | 3250 | * disconnected while waiting for the lock to succeed. */ |
| 3236 | usb_lock_device(hdev); | 3251 | usb_lock_device(hdev); |
| 3237 | if (unlikely(hub->disconnected)) | 3252 | if (unlikely(hub->disconnected)) |
| 3238 | goto loop; | 3253 | goto loop2; |
| 3239 | 3254 | ||
| 3240 | /* If the hub has died, clean up after it */ | 3255 | /* If the hub has died, clean up after it */ |
| 3241 | if (hdev->state == USB_STATE_NOTATTACHED) { | 3256 | if (hdev->state == USB_STATE_NOTATTACHED) { |
| @@ -3384,11 +3399,15 @@ static void hub_events(void) | |||
| 3384 | } | 3399 | } |
| 3385 | } | 3400 | } |
| 3386 | 3401 | ||
| 3387 | loop_autopm: | 3402 | loop_autopm: |
| 3388 | /* Allow autosuspend if we're not going to run again */ | 3403 | /* Balance the usb_autopm_get_interface() above */ |
| 3389 | if (list_empty(&hub->event_list)) | 3404 | usb_autopm_put_interface_no_suspend(intf); |
| 3390 | usb_autopm_enable(intf); | 3405 | loop: |
| 3391 | loop: | 3406 | /* Balance the usb_autopm_get_interface_no_resume() in |
| 3407 | * kick_khubd() and allow autosuspend. | ||
| 3408 | */ | ||
| 3409 | usb_autopm_put_interface(intf); | ||
| 3410 | loop2: | ||
| 3392 | usb_unlock_device(hdev); | 3411 | usb_unlock_device(hdev); |
| 3393 | kref_put(&hub->kref, hub_release); | 3412 | kref_put(&hub->kref, hub_release); |
| 3394 | 3413 | ||
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index ae763974be25..15477008b631 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
| @@ -327,7 +327,6 @@ static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR, | |||
| 327 | 327 | ||
| 328 | static const char on_string[] = "on"; | 328 | static const char on_string[] = "on"; |
| 329 | static const char auto_string[] = "auto"; | 329 | static const char auto_string[] = "auto"; |
| 330 | static const char suspend_string[] = "suspend"; | ||
| 331 | 330 | ||
| 332 | static ssize_t | 331 | static ssize_t |
| 333 | show_level(struct device *dev, struct device_attribute *attr, char *buf) | 332 | show_level(struct device *dev, struct device_attribute *attr, char *buf) |
| @@ -335,13 +334,8 @@ show_level(struct device *dev, struct device_attribute *attr, char *buf) | |||
| 335 | struct usb_device *udev = to_usb_device(dev); | 334 | struct usb_device *udev = to_usb_device(dev); |
| 336 | const char *p = auto_string; | 335 | const char *p = auto_string; |
| 337 | 336 | ||
| 338 | if (udev->state == USB_STATE_SUSPENDED) { | 337 | if (udev->state != USB_STATE_SUSPENDED && udev->autosuspend_disabled) |
| 339 | if (udev->autoresume_disabled) | 338 | p = on_string; |
| 340 | p = suspend_string; | ||
| 341 | } else { | ||
| 342 | if (udev->autosuspend_disabled) | ||
| 343 | p = on_string; | ||
| 344 | } | ||
| 345 | return sprintf(buf, "%s\n", p); | 339 | return sprintf(buf, "%s\n", p); |
| 346 | } | 340 | } |
| 347 | 341 | ||
| @@ -353,7 +347,7 @@ set_level(struct device *dev, struct device_attribute *attr, | |||
| 353 | int len = count; | 347 | int len = count; |
| 354 | char *cp; | 348 | char *cp; |
| 355 | int rc = 0; | 349 | int rc = 0; |
| 356 | int old_autosuspend_disabled, old_autoresume_disabled; | 350 | int old_autosuspend_disabled; |
| 357 | 351 | ||
| 358 | cp = memchr(buf, '\n', count); | 352 | cp = memchr(buf, '\n', count); |
| 359 | if (cp) | 353 | if (cp) |
| @@ -361,7 +355,6 @@ set_level(struct device *dev, struct device_attribute *attr, | |||
| 361 | 355 | ||
| 362 | usb_lock_device(udev); | 356 | usb_lock_device(udev); |
| 363 | old_autosuspend_disabled = udev->autosuspend_disabled; | 357 | old_autosuspend_disabled = udev->autosuspend_disabled; |
| 364 | old_autoresume_disabled = udev->autoresume_disabled; | ||
| 365 | 358 | ||
| 366 | /* Setting the flags without calling usb_pm_lock is a subject to | 359 | /* Setting the flags without calling usb_pm_lock is a subject to |
| 367 | * races, but who cares... | 360 | * races, but who cares... |
| @@ -369,28 +362,18 @@ set_level(struct device *dev, struct device_attribute *attr, | |||
| 369 | if (len == sizeof on_string - 1 && | 362 | if (len == sizeof on_string - 1 && |
| 370 | strncmp(buf, on_string, len) == 0) { | 363 | strncmp(buf, on_string, len) == 0) { |
| 371 | udev->autosuspend_disabled = 1; | 364 | udev->autosuspend_disabled = 1; |
| 372 | udev->autoresume_disabled = 0; | ||
| 373 | rc = usb_external_resume_device(udev, PMSG_USER_RESUME); | 365 | rc = usb_external_resume_device(udev, PMSG_USER_RESUME); |
| 374 | 366 | ||
| 375 | } else if (len == sizeof auto_string - 1 && | 367 | } else if (len == sizeof auto_string - 1 && |
| 376 | strncmp(buf, auto_string, len) == 0) { | 368 | strncmp(buf, auto_string, len) == 0) { |
| 377 | udev->autosuspend_disabled = 0; | 369 | udev->autosuspend_disabled = 0; |
| 378 | udev->autoresume_disabled = 0; | ||
| 379 | rc = usb_external_resume_device(udev, PMSG_USER_RESUME); | 370 | rc = usb_external_resume_device(udev, PMSG_USER_RESUME); |
| 380 | 371 | ||
| 381 | } else if (len == sizeof suspend_string - 1 && | ||
| 382 | strncmp(buf, suspend_string, len) == 0) { | ||
| 383 | udev->autosuspend_disabled = 0; | ||
| 384 | udev->autoresume_disabled = 1; | ||
| 385 | rc = usb_external_suspend_device(udev, PMSG_USER_SUSPEND); | ||
| 386 | |||
| 387 | } else | 372 | } else |
| 388 | rc = -EINVAL; | 373 | rc = -EINVAL; |
| 389 | 374 | ||
| 390 | if (rc) { | 375 | if (rc) |
| 391 | udev->autosuspend_disabled = old_autosuspend_disabled; | 376 | udev->autosuspend_disabled = old_autosuspend_disabled; |
| 392 | udev->autoresume_disabled = old_autoresume_disabled; | ||
| 393 | } | ||
| 394 | usb_unlock_device(udev); | 377 | usb_unlock_device(udev); |
| 395 | return (rc < 0 ? rc : count); | 378 | return (rc < 0 ? rc : count); |
| 396 | } | 379 | } |
diff --git a/include/linux/usb.h b/include/linux/usb.h index 4b6f6db544ee..6af3581e1114 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
| @@ -432,7 +432,6 @@ struct usb_tt; | |||
| 432 | * @do_remote_wakeup: remote wakeup should be enabled | 432 | * @do_remote_wakeup: remote wakeup should be enabled |
| 433 | * @reset_resume: needs reset instead of resume | 433 | * @reset_resume: needs reset instead of resume |
| 434 | * @autosuspend_disabled: autosuspend disabled by the user | 434 | * @autosuspend_disabled: autosuspend disabled by the user |
| 435 | * @autoresume_disabled: autoresume disabled by the user | ||
| 436 | * @skip_sys_resume: skip the next system resume | 435 | * @skip_sys_resume: skip the next system resume |
| 437 | * @wusb_dev: if this is a Wireless USB device, link to the WUSB | 436 | * @wusb_dev: if this is a Wireless USB device, link to the WUSB |
| 438 | * specific data for the device. | 437 | * specific data for the device. |
| @@ -516,7 +515,6 @@ struct usb_device { | |||
| 516 | unsigned do_remote_wakeup:1; | 515 | unsigned do_remote_wakeup:1; |
| 517 | unsigned reset_resume:1; | 516 | unsigned reset_resume:1; |
| 518 | unsigned autosuspend_disabled:1; | 517 | unsigned autosuspend_disabled:1; |
| 519 | unsigned autoresume_disabled:1; | ||
| 520 | unsigned skip_sys_resume:1; | 518 | unsigned skip_sys_resume:1; |
| 521 | #endif | 519 | #endif |
| 522 | struct wusb_dev *wusb_dev; | 520 | struct wusb_dev *wusb_dev; |
| @@ -542,22 +540,20 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); | |||
| 542 | 540 | ||
| 543 | /* USB autosuspend and autoresume */ | 541 | /* USB autosuspend and autoresume */ |
| 544 | #ifdef CONFIG_USB_SUSPEND | 542 | #ifdef CONFIG_USB_SUSPEND |
| 545 | extern int usb_autopm_set_interface(struct usb_interface *intf); | ||
| 546 | extern int usb_autopm_get_interface(struct usb_interface *intf); | 543 | extern int usb_autopm_get_interface(struct usb_interface *intf); |
| 547 | extern void usb_autopm_put_interface(struct usb_interface *intf); | 544 | extern void usb_autopm_put_interface(struct usb_interface *intf); |
| 548 | extern int usb_autopm_get_interface_async(struct usb_interface *intf); | 545 | extern int usb_autopm_get_interface_async(struct usb_interface *intf); |
| 549 | extern void usb_autopm_put_interface_async(struct usb_interface *intf); | 546 | extern void usb_autopm_put_interface_async(struct usb_interface *intf); |
| 550 | 547 | ||
| 551 | static inline void usb_autopm_enable(struct usb_interface *intf) | 548 | static inline void usb_autopm_get_interface_no_resume( |
| 549 | struct usb_interface *intf) | ||
| 552 | { | 550 | { |
| 553 | atomic_set(&intf->pm_usage_cnt, 0); | 551 | atomic_inc(&intf->pm_usage_cnt); |
| 554 | usb_autopm_set_interface(intf); | ||
| 555 | } | 552 | } |
| 556 | 553 | static inline void usb_autopm_put_interface_no_suspend( | |
| 557 | static inline void usb_autopm_disable(struct usb_interface *intf) | 554 | struct usb_interface *intf) |
| 558 | { | 555 | { |
| 559 | atomic_set(&intf->pm_usage_cnt, 1); | 556 | atomic_dec(&intf->pm_usage_cnt); |
| 560 | usb_autopm_set_interface(intf); | ||
| 561 | } | 557 | } |
| 562 | 558 | ||
| 563 | static inline void usb_mark_last_busy(struct usb_device *udev) | 559 | static inline void usb_mark_last_busy(struct usb_device *udev) |
| @@ -567,12 +563,8 @@ static inline void usb_mark_last_busy(struct usb_device *udev) | |||
| 567 | 563 | ||
| 568 | #else | 564 | #else |
| 569 | 565 | ||
| 570 | static inline int usb_autopm_set_interface(struct usb_interface *intf) | ||
| 571 | { return 0; } | ||
| 572 | |||
| 573 | static inline int usb_autopm_get_interface(struct usb_interface *intf) | 566 | static inline int usb_autopm_get_interface(struct usb_interface *intf) |
| 574 | { return 0; } | 567 | { return 0; } |
| 575 | |||
| 576 | static inline int usb_autopm_get_interface_async(struct usb_interface *intf) | 568 | static inline int usb_autopm_get_interface_async(struct usb_interface *intf) |
| 577 | { return 0; } | 569 | { return 0; } |
| 578 | 570 | ||
| @@ -580,9 +572,11 @@ static inline void usb_autopm_put_interface(struct usb_interface *intf) | |||
| 580 | { } | 572 | { } |
| 581 | static inline void usb_autopm_put_interface_async(struct usb_interface *intf) | 573 | static inline void usb_autopm_put_interface_async(struct usb_interface *intf) |
| 582 | { } | 574 | { } |
| 583 | static inline void usb_autopm_enable(struct usb_interface *intf) | 575 | static inline void usb_autopm_get_interface_no_resume( |
| 576 | struct usb_interface *intf) | ||
| 584 | { } | 577 | { } |
| 585 | static inline void usb_autopm_disable(struct usb_interface *intf) | 578 | static inline void usb_autopm_put_interface_no_suspend( |
| 579 | struct usb_interface *intf) | ||
| 586 | { } | 580 | { } |
| 587 | static inline void usb_mark_last_busy(struct usb_device *udev) | 581 | static inline void usb_mark_last_busy(struct usb_device *udev) |
| 588 | { } | 582 | { } |
