aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-09-12 22:39:34 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 12:52:50 -0400
commit0ac85241ebc7bf6b86ab498960cc121d53ef69ae (patch)
tree8b5d9d5a3e475c49d771d1a4bd597ea561331ff7
parent2a7ff1feda9f5cd6463744239ec5e661ee7d5f01 (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.c1
-rw-r--r--drivers/base/power/sysfs.c73
-rw-r--r--include/linux/pm.h26
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
48static DEVICE_ATTR(state, 0644, state_show, state_store); 48static 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
85static const char enabled[] = "enabled";
86static const char disabled[] = "disabled";
87
88static ssize_t
89wake_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
96static ssize_t
97wake_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
120static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
121
122
51static struct attribute * power_attrs[] = { 123static 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};
55static struct attribute_group pm_attr_group = { 128static 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
220struct dev_pm_info { 220struct 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
238extern int device_suspend(pm_message_t state); 240extern 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
240static inline int device_suspend(pm_message_t state) 249static 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 */