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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
9af23624ae
commit
8e4ceb38eb
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Alan Stern <stern@rowland.harvard.edu>
|
Alan Stern <stern@rowland.harvard.edu>
|
||||||
|
|
||||||
October 5, 2007
|
November 10, 2009
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -123,9 +123,9 @@ relevant attribute files are: wakeup, level, and autosuspend.
|
|||||||
|
|
||||||
power/level
|
power/level
|
||||||
|
|
||||||
This file contains one of three words: "on", "auto",
|
This file contains one of two words: "on" or "auto".
|
||||||
or "suspend". You can write those words to the file
|
You can write those words to the file to change the
|
||||||
to change the device's setting.
|
device's setting.
|
||||||
|
|
||||||
"on" means that the device should be resumed and
|
"on" means that the device should be resumed and
|
||||||
autosuspend is not allowed. (Of course, system
|
autosuspend is not allowed. (Of course, system
|
||||||
@@ -134,10 +134,10 @@ relevant attribute files are: wakeup, level, and autosuspend.
|
|||||||
"auto" is the normal state in which the kernel is
|
"auto" is the normal state in which the kernel is
|
||||||
allowed to autosuspend and autoresume the device.
|
allowed to autosuspend and autoresume the device.
|
||||||
|
|
||||||
"suspend" means that the device should remain
|
(In kernels up to 2.6.32, you could also specify
|
||||||
suspended, and autoresume is not allowed. (But remote
|
"suspend", meaning that the device should remain
|
||||||
wakeup may still be allowed, since it is controlled
|
suspended and autoresume was not allowed. This
|
||||||
separately by the power/wakeup attribute.)
|
setting is no longer supported.)
|
||||||
|
|
||||||
power/autosuspend
|
power/autosuspend
|
||||||
|
|
||||||
@@ -313,13 +313,14 @@ three of the methods listed above. In addition, a driver indicates
|
|||||||
that it supports autosuspend by setting the .supports_autosuspend flag
|
that it supports autosuspend by setting the .supports_autosuspend flag
|
||||||
in its usb_driver structure. It is then responsible for informing the
|
in its usb_driver structure. It is then responsible for informing the
|
||||||
USB core whenever one of its interfaces becomes busy or idle. The
|
USB core whenever one of its interfaces becomes busy or idle. The
|
||||||
driver does so by calling these five functions:
|
driver does so by calling these six functions:
|
||||||
|
|
||||||
int usb_autopm_get_interface(struct usb_interface *intf);
|
int usb_autopm_get_interface(struct usb_interface *intf);
|
||||||
void usb_autopm_put_interface(struct usb_interface *intf);
|
void usb_autopm_put_interface(struct usb_interface *intf);
|
||||||
int usb_autopm_set_interface(struct usb_interface *intf);
|
|
||||||
int usb_autopm_get_interface_async(struct usb_interface *intf);
|
int usb_autopm_get_interface_async(struct usb_interface *intf);
|
||||||
void usb_autopm_put_interface_async(struct usb_interface *intf);
|
void usb_autopm_put_interface_async(struct usb_interface *intf);
|
||||||
|
void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
|
||||||
|
void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
|
||||||
|
|
||||||
The functions work by maintaining a counter in the usb_interface
|
The functions work by maintaining a counter in the usb_interface
|
||||||
structure. When intf->pm_usage_count is > 0 then the interface is
|
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.
|
|||||||
associated with the device itself rather than any of its interfaces.
|
associated with the device itself rather than any of its interfaces.
|
||||||
This field is used only by the USB core.)
|
This field is used only by the USB core.)
|
||||||
|
|
||||||
The driver owns intf->pm_usage_count; it can modify the value however
|
Drivers must not modify intf->pm_usage_count directly; its value
|
||||||
and whenever it likes. A nice aspect of the non-async usb_autopm_*
|
should be changed only be using the functions listed above. Drivers
|
||||||
routines is that the changes they make are protected by the usb_device
|
are responsible for insuring that the overall change to pm_usage_count
|
||||||
structure's PM mutex (udev->pm_mutex); however drivers may change
|
during their lifetime balances out to 0 (it may be necessary for the
|
||||||
pm_usage_count without holding the mutex. Drivers using the async
|
disconnect method to call usb_autopm_put_interface() one or more times
|
||||||
|
to fulfill this requirement). The first two routines use the PM mutex
|
||||||
|
in struct usb_device for mutual exclusion; drivers using the async
|
||||||
routines are responsible for their own synchronization and mutual
|
routines are responsible for their own synchronization and mutual
|
||||||
exclusion.
|
exclusion.
|
||||||
|
|
||||||
@@ -347,11 +350,6 @@ exclusion.
|
|||||||
attempts an autosuspend if the new value is <= 0 and the
|
attempts an autosuspend if the new value is <= 0 and the
|
||||||
device isn't suspended.
|
device isn't suspended.
|
||||||
|
|
||||||
usb_autopm_set_interface() leaves pm_usage_count alone.
|
|
||||||
It attempts an autoresume if the value is > 0 and the device
|
|
||||||
is suspended, and it attempts an autosuspend if the value is
|
|
||||||
<= 0 and the device isn't suspended.
|
|
||||||
|
|
||||||
usb_autopm_get_interface_async() and
|
usb_autopm_get_interface_async() and
|
||||||
usb_autopm_put_interface_async() do almost the same things as
|
usb_autopm_put_interface_async() do almost the same things as
|
||||||
their non-async counterparts. The differences are: they do
|
their non-async counterparts. The differences are: they do
|
||||||
@@ -360,13 +358,11 @@ exclusion.
|
|||||||
such as an URB's completion handler, but when they return the
|
such as an URB's completion handler, but when they return the
|
||||||
device will not generally not yet be in the desired state.
|
device will not generally not yet be in the desired state.
|
||||||
|
|
||||||
There also are a couple of utility routines drivers can use:
|
usb_autopm_get_interface_no_resume() and
|
||||||
|
usb_autopm_put_interface_no_suspend() merely increment or
|
||||||
usb_autopm_enable() sets pm_usage_cnt to 0 and then calls
|
decrement the pm_usage_count value; they do not attempt to
|
||||||
usb_autopm_set_interface(), which will attempt an autosuspend.
|
carry out an autoresume or an autosuspend. Hence they can be
|
||||||
|
called in an atomic context.
|
||||||
usb_autopm_disable() sets pm_usage_cnt to 1 and then calls
|
|
||||||
usb_autopm_set_interface(), which will attempt an autoresume.
|
|
||||||
|
|
||||||
The conventional usage pattern is that a driver calls
|
The conventional usage pattern is that a driver calls
|
||||||
usb_autopm_get_interface() in its open routine and
|
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.
|
|||||||
Normally a driver would set this flag in its probe method, at which
|
Normally a driver would set this flag in its probe method, at which
|
||||||
time the device is guaranteed not to be autosuspended.)
|
time the device is guaranteed not to be autosuspended.)
|
||||||
|
|
||||||
The usb_autopm_* routines have to run in a sleepable process context;
|
The synchronous usb_autopm_* routines have to run in a sleepable
|
||||||
they must not be called from an interrupt handler or while holding a
|
process context; they must not be called from an interrupt handler or
|
||||||
spinlock. In fact, the entire autosuspend mechanism is not well geared
|
while holding a spinlock. In fact, the entire autosuspend mechanism
|
||||||
toward interrupt-driven operation. However there is one thing a
|
is not well geared toward interrupt-driven operation. However there
|
||||||
driver can do in an interrupt handler:
|
is one thing a driver can do in an interrupt handler:
|
||||||
|
|
||||||
usb_mark_last_busy(struct usb_device *udev);
|
usb_mark_last_busy(struct usb_device *udev);
|
||||||
|
|
||||||
|
@@ -948,8 +948,6 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
||||||
if (status == 0)
|
|
||||||
udev->autoresume_disabled = 0;
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1280,11 +1278,6 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
|
|||||||
|
|
||||||
/* Propagate the resume up the tree, if necessary */
|
/* Propagate the resume up the tree, if necessary */
|
||||||
if (udev->state == USB_STATE_SUSPENDED) {
|
if (udev->state == USB_STATE_SUSPENDED) {
|
||||||
if ((msg.event & PM_EVENT_AUTO) &&
|
|
||||||
udev->autoresume_disabled) {
|
|
||||||
status = -EPERM;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
status = usb_autoresume_device(parent);
|
status = usb_autoresume_device(parent);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
@@ -1638,8 +1631,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
|
|||||||
|
|
||||||
if (intf->condition == USB_INTERFACE_UNBOUND)
|
if (intf->condition == USB_INTERFACE_UNBOUND)
|
||||||
status = -ENODEV;
|
status = -ENODEV;
|
||||||
else if (udev->autoresume_disabled)
|
|
||||||
status = -EPERM;
|
|
||||||
else {
|
else {
|
||||||
atomic_inc(&intf->pm_usage_cnt);
|
atomic_inc(&intf->pm_usage_cnt);
|
||||||
if (atomic_read(&intf->pm_usage_cnt) > 0 &&
|
if (atomic_read(&intf->pm_usage_cnt) > 0 &&
|
||||||
@@ -1652,28 +1643,6 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
|
EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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_vdbg(&intf->dev, "%s: status %d cnt %d\n",
|
|
||||||
__func__, status, atomic_read(&intf->pm_usage_cnt));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void usb_autosuspend_work(struct work_struct *work)
|
void usb_autosuspend_work(struct work_struct *work)
|
||||||
|
@@ -71,6 +71,7 @@ struct usb_hub {
|
|||||||
|
|
||||||
unsigned mA_per_port; /* current for each child */
|
unsigned mA_per_port; /* current for each child */
|
||||||
|
|
||||||
|
unsigned init_done:1;
|
||||||
unsigned limited_power:1;
|
unsigned limited_power:1;
|
||||||
unsigned quiescing:1;
|
unsigned quiescing:1;
|
||||||
unsigned disconnected:1;
|
unsigned disconnected:1;
|
||||||
@@ -375,12 +376,13 @@ static void kick_khubd(struct usb_hub *hub)
|
|||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* Suppress autosuspend until khubd runs */
|
|
||||||
atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&hub_event_lock, flags);
|
spin_lock_irqsave(&hub_event_lock, flags);
|
||||||
if (!hub->disconnected && list_empty(&hub->event_list)) {
|
if (!hub->disconnected && list_empty(&hub->event_list)) {
|
||||||
list_add_tail(&hub->event_list, &hub_event_list);
|
list_add_tail(&hub->event_list, &hub_event_list);
|
||||||
|
|
||||||
|
/* Suppress autosuspend until khubd runs */
|
||||||
|
usb_autopm_get_interface_no_resume(
|
||||||
|
to_usb_interface(hub->intfdev));
|
||||||
wake_up(&khubd_wait);
|
wake_up(&khubd_wait);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&hub_event_lock, flags);
|
spin_unlock_irqrestore(&hub_event_lock, flags);
|
||||||
@@ -665,7 +667,7 @@ int usb_remove_device(struct usb_device *udev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum hub_activation_type {
|
enum hub_activation_type {
|
||||||
HUB_INIT, HUB_INIT2, HUB_INIT3,
|
HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */
|
||||||
HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
|
HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -710,8 +712,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||||||
msecs_to_jiffies(delay));
|
msecs_to_jiffies(delay));
|
||||||
|
|
||||||
/* Suppress autosuspend until init is done */
|
/* Suppress autosuspend until init is done */
|
||||||
atomic_set(&to_usb_interface(hub->intfdev)->
|
usb_autopm_get_interface_no_resume(
|
||||||
pm_usage_cnt, 1);
|
to_usb_interface(hub->intfdev));
|
||||||
return; /* Continues at init2: below */
|
return; /* Continues at init2: below */
|
||||||
} else {
|
} else {
|
||||||
hub_power_on(hub, true);
|
hub_power_on(hub, true);
|
||||||
@@ -818,6 +820,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||||||
}
|
}
|
||||||
init3:
|
init3:
|
||||||
hub->quiescing = 0;
|
hub->quiescing = 0;
|
||||||
|
hub->init_done = 1;
|
||||||
|
|
||||||
status = usb_submit_urb(hub->urb, GFP_NOIO);
|
status = usb_submit_urb(hub->urb, GFP_NOIO);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
@@ -827,6 +830,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||||||
|
|
||||||
/* Scan all ports that need attention */
|
/* Scan all ports that need attention */
|
||||||
kick_khubd(hub);
|
kick_khubd(hub);
|
||||||
|
|
||||||
|
/* Allow autosuspend if it was suppressed */
|
||||||
|
if (type <= HUB_INIT3)
|
||||||
|
usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implement the continuations for the delays above */
|
/* Implement the continuations for the delays above */
|
||||||
@@ -854,6 +861,11 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
cancel_delayed_work_sync(&hub->init_work);
|
cancel_delayed_work_sync(&hub->init_work);
|
||||||
|
if (!hub->init_done) {
|
||||||
|
hub->init_done = 1;
|
||||||
|
usb_autopm_put_interface_no_suspend(
|
||||||
|
to_usb_interface(hub->intfdev));
|
||||||
|
}
|
||||||
|
|
||||||
/* khubd and related activity won't re-trigger */
|
/* khubd and related activity won't re-trigger */
|
||||||
hub->quiescing = 1;
|
hub->quiescing = 1;
|
||||||
@@ -1176,7 +1188,10 @@ static void hub_disconnect(struct usb_interface *intf)
|
|||||||
|
|
||||||
/* Take the hub off the event list and don't let it be added again */
|
/* Take the hub off the event list and don't let it be added again */
|
||||||
spin_lock_irq(&hub_event_lock);
|
spin_lock_irq(&hub_event_lock);
|
||||||
|
if (!list_empty(&hub->event_list)) {
|
||||||
list_del_init(&hub->event_list);
|
list_del_init(&hub->event_list);
|
||||||
|
usb_autopm_put_interface_no_suspend(intf);
|
||||||
|
}
|
||||||
hub->disconnected = 1;
|
hub->disconnected = 1;
|
||||||
spin_unlock_irq(&hub_event_lock);
|
spin_unlock_irq(&hub_event_lock);
|
||||||
|
|
||||||
@@ -3235,7 +3250,7 @@ static void hub_events(void)
|
|||||||
* disconnected while waiting for the lock to succeed. */
|
* disconnected while waiting for the lock to succeed. */
|
||||||
usb_lock_device(hdev);
|
usb_lock_device(hdev);
|
||||||
if (unlikely(hub->disconnected))
|
if (unlikely(hub->disconnected))
|
||||||
goto loop;
|
goto loop2;
|
||||||
|
|
||||||
/* If the hub has died, clean up after it */
|
/* If the hub has died, clean up after it */
|
||||||
if (hdev->state == USB_STATE_NOTATTACHED) {
|
if (hdev->state == USB_STATE_NOTATTACHED) {
|
||||||
@@ -3384,11 +3399,15 @@ static void hub_events(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_autopm:
|
loop_autopm:
|
||||||
/* Allow autosuspend if we're not going to run again */
|
/* Balance the usb_autopm_get_interface() above */
|
||||||
if (list_empty(&hub->event_list))
|
usb_autopm_put_interface_no_suspend(intf);
|
||||||
usb_autopm_enable(intf);
|
loop:
|
||||||
loop:
|
/* Balance the usb_autopm_get_interface_no_resume() in
|
||||||
|
* kick_khubd() and allow autosuspend.
|
||||||
|
*/
|
||||||
|
usb_autopm_put_interface(intf);
|
||||||
|
loop2:
|
||||||
usb_unlock_device(hdev);
|
usb_unlock_device(hdev);
|
||||||
kref_put(&hub->kref, hub_release);
|
kref_put(&hub->kref, hub_release);
|
||||||
|
|
||||||
|
@@ -327,7 +327,6 @@ static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
|
|||||||
|
|
||||||
static const char on_string[] = "on";
|
static const char on_string[] = "on";
|
||||||
static const char auto_string[] = "auto";
|
static const char auto_string[] = "auto";
|
||||||
static const char suspend_string[] = "suspend";
|
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
show_level(struct device *dev, struct device_attribute *attr, char *buf)
|
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)
|
|||||||
struct usb_device *udev = to_usb_device(dev);
|
struct usb_device *udev = to_usb_device(dev);
|
||||||
const char *p = auto_string;
|
const char *p = auto_string;
|
||||||
|
|
||||||
if (udev->state == USB_STATE_SUSPENDED) {
|
if (udev->state != USB_STATE_SUSPENDED && udev->autosuspend_disabled)
|
||||||
if (udev->autoresume_disabled)
|
|
||||||
p = suspend_string;
|
|
||||||
} else {
|
|
||||||
if (udev->autosuspend_disabled)
|
|
||||||
p = on_string;
|
p = on_string;
|
||||||
}
|
|
||||||
return sprintf(buf, "%s\n", p);
|
return sprintf(buf, "%s\n", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +347,7 @@ set_level(struct device *dev, struct device_attribute *attr,
|
|||||||
int len = count;
|
int len = count;
|
||||||
char *cp;
|
char *cp;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int old_autosuspend_disabled, old_autoresume_disabled;
|
int old_autosuspend_disabled;
|
||||||
|
|
||||||
cp = memchr(buf, '\n', count);
|
cp = memchr(buf, '\n', count);
|
||||||
if (cp)
|
if (cp)
|
||||||
@@ -361,7 +355,6 @@ set_level(struct device *dev, struct device_attribute *attr,
|
|||||||
|
|
||||||
usb_lock_device(udev);
|
usb_lock_device(udev);
|
||||||
old_autosuspend_disabled = udev->autosuspend_disabled;
|
old_autosuspend_disabled = udev->autosuspend_disabled;
|
||||||
old_autoresume_disabled = udev->autoresume_disabled;
|
|
||||||
|
|
||||||
/* Setting the flags without calling usb_pm_lock is a subject to
|
/* Setting the flags without calling usb_pm_lock is a subject to
|
||||||
* races, but who cares...
|
* races, but who cares...
|
||||||
@@ -369,28 +362,18 @@ set_level(struct device *dev, struct device_attribute *attr,
|
|||||||
if (len == sizeof on_string - 1 &&
|
if (len == sizeof on_string - 1 &&
|
||||||
strncmp(buf, on_string, len) == 0) {
|
strncmp(buf, on_string, len) == 0) {
|
||||||
udev->autosuspend_disabled = 1;
|
udev->autosuspend_disabled = 1;
|
||||||
udev->autoresume_disabled = 0;
|
|
||||||
rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
|
rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
|
||||||
|
|
||||||
} else if (len == sizeof auto_string - 1 &&
|
} else if (len == sizeof auto_string - 1 &&
|
||||||
strncmp(buf, auto_string, len) == 0) {
|
strncmp(buf, auto_string, len) == 0) {
|
||||||
udev->autosuspend_disabled = 0;
|
udev->autosuspend_disabled = 0;
|
||||||
udev->autoresume_disabled = 0;
|
|
||||||
rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
|
rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
|
||||||
|
|
||||||
} else if (len == sizeof suspend_string - 1 &&
|
|
||||||
strncmp(buf, suspend_string, len) == 0) {
|
|
||||||
udev->autosuspend_disabled = 0;
|
|
||||||
udev->autoresume_disabled = 1;
|
|
||||||
rc = usb_external_suspend_device(udev, PMSG_USER_SUSPEND);
|
|
||||||
|
|
||||||
} else
|
} else
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
|
|
||||||
if (rc) {
|
if (rc)
|
||||||
udev->autosuspend_disabled = old_autosuspend_disabled;
|
udev->autosuspend_disabled = old_autosuspend_disabled;
|
||||||
udev->autoresume_disabled = old_autoresume_disabled;
|
|
||||||
}
|
|
||||||
usb_unlock_device(udev);
|
usb_unlock_device(udev);
|
||||||
return (rc < 0 ? rc : count);
|
return (rc < 0 ? rc : count);
|
||||||
}
|
}
|
||||||
|
@@ -432,7 +432,6 @@ struct usb_tt;
|
|||||||
* @do_remote_wakeup: remote wakeup should be enabled
|
* @do_remote_wakeup: remote wakeup should be enabled
|
||||||
* @reset_resume: needs reset instead of resume
|
* @reset_resume: needs reset instead of resume
|
||||||
* @autosuspend_disabled: autosuspend disabled by the user
|
* @autosuspend_disabled: autosuspend disabled by the user
|
||||||
* @autoresume_disabled: autoresume disabled by the user
|
|
||||||
* @skip_sys_resume: skip the next system resume
|
* @skip_sys_resume: skip the next system resume
|
||||||
* @wusb_dev: if this is a Wireless USB device, link to the WUSB
|
* @wusb_dev: if this is a Wireless USB device, link to the WUSB
|
||||||
* specific data for the device.
|
* specific data for the device.
|
||||||
@@ -516,7 +515,6 @@ struct usb_device {
|
|||||||
unsigned do_remote_wakeup:1;
|
unsigned do_remote_wakeup:1;
|
||||||
unsigned reset_resume:1;
|
unsigned reset_resume:1;
|
||||||
unsigned autosuspend_disabled:1;
|
unsigned autosuspend_disabled:1;
|
||||||
unsigned autoresume_disabled:1;
|
|
||||||
unsigned skip_sys_resume:1;
|
unsigned skip_sys_resume:1;
|
||||||
#endif
|
#endif
|
||||||
struct wusb_dev *wusb_dev;
|
struct wusb_dev *wusb_dev;
|
||||||
@@ -542,22 +540,20 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
|
|||||||
|
|
||||||
/* USB autosuspend and autoresume */
|
/* USB autosuspend and autoresume */
|
||||||
#ifdef CONFIG_USB_SUSPEND
|
#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 int usb_autopm_get_interface(struct usb_interface *intf);
|
||||||
extern void usb_autopm_put_interface(struct usb_interface *intf);
|
extern void usb_autopm_put_interface(struct usb_interface *intf);
|
||||||
extern int usb_autopm_get_interface_async(struct usb_interface *intf);
|
extern int usb_autopm_get_interface_async(struct usb_interface *intf);
|
||||||
extern void usb_autopm_put_interface_async(struct usb_interface *intf);
|
extern void usb_autopm_put_interface_async(struct usb_interface *intf);
|
||||||
|
|
||||||
static inline void usb_autopm_enable(struct usb_interface *intf)
|
static inline void usb_autopm_get_interface_no_resume(
|
||||||
|
struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
atomic_set(&intf->pm_usage_cnt, 0);
|
atomic_inc(&intf->pm_usage_cnt);
|
||||||
usb_autopm_set_interface(intf);
|
|
||||||
}
|
}
|
||||||
|
static inline void usb_autopm_put_interface_no_suspend(
|
||||||
static inline void usb_autopm_disable(struct usb_interface *intf)
|
struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
atomic_set(&intf->pm_usage_cnt, 1);
|
atomic_dec(&intf->pm_usage_cnt);
|
||||||
usb_autopm_set_interface(intf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void usb_mark_last_busy(struct usb_device *udev)
|
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)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int usb_autopm_set_interface(struct usb_interface *intf)
|
|
||||||
{ return 0; }
|
|
||||||
|
|
||||||
static inline int usb_autopm_get_interface(struct usb_interface *intf)
|
static inline int usb_autopm_get_interface(struct usb_interface *intf)
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
static inline int usb_autopm_get_interface_async(struct usb_interface *intf)
|
static inline int usb_autopm_get_interface_async(struct usb_interface *intf)
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
@@ -580,9 +572,11 @@ static inline void usb_autopm_put_interface(struct usb_interface *intf)
|
|||||||
{ }
|
{ }
|
||||||
static inline void usb_autopm_put_interface_async(struct usb_interface *intf)
|
static inline void usb_autopm_put_interface_async(struct usb_interface *intf)
|
||||||
{ }
|
{ }
|
||||||
static inline void usb_autopm_enable(struct usb_interface *intf)
|
static inline void usb_autopm_get_interface_no_resume(
|
||||||
|
struct usb_interface *intf)
|
||||||
{ }
|
{ }
|
||||||
static inline void usb_autopm_disable(struct usb_interface *intf)
|
static inline void usb_autopm_put_interface_no_suspend(
|
||||||
|
struct usb_interface *intf)
|
||||||
{ }
|
{ }
|
||||||
static inline void usb_mark_last_busy(struct usb_device *udev)
|
static inline void usb_mark_last_busy(struct usb_device *udev)
|
||||||
{ }
|
{ }
|
||||||
|
Reference in New Issue
Block a user