diff options
author | David Brownell <david-b@pacbell.net> | 2005-09-12 22:39:34 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 12:52:50 -0400 |
commit | 0ac85241ebc7bf6b86ab498960cc121d53ef69ae (patch) | |
tree | 8b5d9d5a3e475c49d771d1a4bd597ea561331ff7 | |
parent | 2a7ff1feda9f5cd6463744239ec5e661ee7d5f01 (diff) |
[PATCH] driver model wakeup flags
This is a refresh of an earlier patch to add "wakeup" support to the
PM core model. This provides per-device bus-neutral control of the
use of wakeup events.
* "struct device_pm_info" has two bits that are initialized as
part of setting up the enclosing struct device:
- "can_wakeup", reflecting hardware capabilities
- "may_wakeup", the policy setting (when CONFIG_PM)
* There's a writeable sysfs "wakeup" file, with one of two values:
- "enabled", when the policy is to allow wakeup
- "disabled", when the policy is not to allow it
- "" if the device can't currently issue wakeups
By default, wakeup is enabled on all devices that support it. If its
driver doesn't support it ... treat it as a bug. :)
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/base/core.c | 1 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 73 | ||||
-rw-r--r-- | include/linux/pm.h | 26 |
3 files changed, 99 insertions, 1 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 6ab73f5c799a..31109193e2c4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -225,6 +225,7 @@ void device_initialize(struct device *dev) | |||
225 | klist_children_put); | 225 | klist_children_put); |
226 | INIT_LIST_HEAD(&dev->dma_pools); | 226 | INIT_LIST_HEAD(&dev->dma_pools); |
227 | init_MUTEX(&dev->sem); | 227 | init_MUTEX(&dev->sem); |
228 | device_init_wakeup(dev, 0); | ||
228 | } | 229 | } |
229 | 230 | ||
230 | /** | 231 | /** |
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 8d04fb435c17..89c57875f3e5 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -48,8 +48,81 @@ static ssize_t state_store(struct device * dev, struct device_attribute *attr, c | |||
48 | static DEVICE_ATTR(state, 0644, state_show, state_store); | 48 | static DEVICE_ATTR(state, 0644, state_show, state_store); |
49 | 49 | ||
50 | 50 | ||
51 | /* | ||
52 | * wakeup - Report/change current wakeup option for device | ||
53 | * | ||
54 | * Some devices support "wakeup" events, which are hardware signals | ||
55 | * used to activate devices from suspended or low power states. Such | ||
56 | * devices have one of three values for the sysfs power/wakeup file: | ||
57 | * | ||
58 | * + "enabled\n" to issue the events; | ||
59 | * + "disabled\n" not to do so; or | ||
60 | * + "\n" for temporary or permanent inability to issue wakeup. | ||
61 | * | ||
62 | * (For example, unconfigured USB devices can't issue wakeups.) | ||
63 | * | ||
64 | * Familiar examples of devices that can issue wakeup events include | ||
65 | * keyboards and mice (both PS2 and USB styles), power buttons, modems, | ||
66 | * "Wake-On-LAN" Ethernet links, GPIO lines, and more. Some events | ||
67 | * will wake the entire system from a suspend state; others may just | ||
68 | * wake up the device (if the system as a whole is already active). | ||
69 | * Some wakeup events use normal IRQ lines; other use special out | ||
70 | * of band signaling. | ||
71 | * | ||
72 | * It is the responsibility of device drivers to enable (or disable) | ||
73 | * wakeup signaling as part of changing device power states, respecting | ||
74 | * the policy choices provided through the driver model. | ||
75 | * | ||
76 | * Devices may not be able to generate wakeup events from all power | ||
77 | * states. Also, the events may be ignored in some configurations; | ||
78 | * for example, they might need help from other devices that aren't | ||
79 | * active, or which may have wakeup disabled. Some drivers rely on | ||
80 | * wakeup events internally (unless they are disabled), keeping | ||
81 | * their hardware in low power modes whenever they're unused. This | ||
82 | * saves runtime power, without requiring system-wide sleep states. | ||
83 | */ | ||
84 | |||
85 | static const char enabled[] = "enabled"; | ||
86 | static const char disabled[] = "disabled"; | ||
87 | |||
88 | static ssize_t | ||
89 | wake_show(struct device * dev, struct device_attribute *attr, char * buf) | ||
90 | { | ||
91 | return sprintf(buf, "%s\n", device_can_wakeup(dev) | ||
92 | ? (device_may_wakeup(dev) ? enabled : disabled) | ||
93 | : ""); | ||
94 | } | ||
95 | |||
96 | static ssize_t | ||
97 | wake_store(struct device * dev, struct device_attribute *attr, | ||
98 | const char * buf, size_t n) | ||
99 | { | ||
100 | char *cp; | ||
101 | int len = n; | ||
102 | |||
103 | if (!device_can_wakeup(dev)) | ||
104 | return -EINVAL; | ||
105 | |||
106 | cp = memchr(buf, '\n', n); | ||
107 | if (cp) | ||
108 | len = cp - buf; | ||
109 | if (len == sizeof enabled - 1 | ||
110 | && strncmp(buf, enabled, sizeof enabled - 1) == 0) | ||
111 | device_set_wakeup_enable(dev, 1); | ||
112 | else if (len == sizeof disabled - 1 | ||
113 | && strncmp(buf, disabled, sizeof disabled - 1) == 0) | ||
114 | device_set_wakeup_enable(dev, 0); | ||
115 | else | ||
116 | return -EINVAL; | ||
117 | return n; | ||
118 | } | ||
119 | |||
120 | static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store); | ||
121 | |||
122 | |||
51 | static struct attribute * power_attrs[] = { | 123 | static struct attribute * power_attrs[] = { |
52 | &dev_attr_state.attr, | 124 | &dev_attr_state.attr, |
125 | &dev_attr_wakeup.attr, | ||
53 | NULL, | 126 | NULL, |
54 | }; | 127 | }; |
55 | static struct attribute_group pm_attr_group = { | 128 | static struct attribute_group pm_attr_group = { |
diff --git a/include/linux/pm.h b/include/linux/pm.h index 5cfb07648eca..7897cf500c51 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h | |||
@@ -219,7 +219,9 @@ typedef struct pm_message { | |||
219 | 219 | ||
220 | struct dev_pm_info { | 220 | struct dev_pm_info { |
221 | pm_message_t power_state; | 221 | pm_message_t power_state; |
222 | unsigned can_wakeup:1; | ||
222 | #ifdef CONFIG_PM | 223 | #ifdef CONFIG_PM |
224 | unsigned should_wakeup:1; | ||
223 | pm_message_t prev_state; | 225 | pm_message_t prev_state; |
224 | void * saved_state; | 226 | void * saved_state; |
225 | atomic_t pm_users; | 227 | atomic_t pm_users; |
@@ -236,13 +238,35 @@ extern void device_resume(void); | |||
236 | 238 | ||
237 | #ifdef CONFIG_PM | 239 | #ifdef CONFIG_PM |
238 | extern int device_suspend(pm_message_t state); | 240 | extern int device_suspend(pm_message_t state); |
239 | #else | 241 | |
242 | #define device_set_wakeup_enable(dev,val) \ | ||
243 | ((dev)->power.should_wakeup = !!(val)) | ||
244 | #define device_may_wakeup(dev) \ | ||
245 | (device_can_wakeup(dev) && (dev)->power.should_wakeup) | ||
246 | |||
247 | #else /* !CONFIG_PM */ | ||
248 | |||
240 | static inline int device_suspend(pm_message_t state) | 249 | static inline int device_suspend(pm_message_t state) |
241 | { | 250 | { |
242 | return 0; | 251 | return 0; |
243 | } | 252 | } |
253 | |||
254 | #define device_set_wakeup_enable(dev,val) do{}while(0) | ||
255 | #define device_may_wakeup(dev) (0) | ||
256 | |||
244 | #endif | 257 | #endif |
245 | 258 | ||
259 | /* changes to device_may_wakeup take effect on the next pm state change. | ||
260 | * by default, devices should wakeup if they can. | ||
261 | */ | ||
262 | #define device_can_wakeup(dev) \ | ||
263 | ((dev)->power.can_wakeup) | ||
264 | #define device_init_wakeup(dev,val) \ | ||
265 | do { \ | ||
266 | device_can_wakeup(dev) = !!(val); \ | ||
267 | device_set_wakeup_enable(dev,val); \ | ||
268 | } while(0) | ||
269 | |||
246 | #endif /* __KERNEL__ */ | 270 | #endif /* __KERNEL__ */ |
247 | 271 | ||
248 | #endif /* _LINUX_PM_H */ | 272 | #endif /* _LINUX_PM_H */ |