ar71xx: add support for the Buffalo WHR-HP-GN board
[openwrt.git] / target / linux / goldfish / patches-2.6.30 / 0069-PM-Add-user-space-wake-lock-api.patch
1 From 48e1af2bdd11204f11b3770a6c8d3eee64aee2e8 Mon Sep 17 00:00:00 2001
2 From: =?utf-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= <arve@android.com>
3 Date: Thu, 9 Oct 2008 21:01:46 -0700
4 Subject: [PATCH 069/134] PM: Add user-space wake lock api.
5
6 This adds /sys/power/wake_lock and /sys/power/wake_unlock.
7 Writing a string to wake_lock creates a wake lock the
8 first time is sees a string and locks it. Optionally, the
9 string can be followed by a timeout.
10 To unlock the wake lock, write the same string to wake_unlock.
11 ---
12 kernel/power/Kconfig | 10 ++
13 kernel/power/Makefile | 1 +
14 kernel/power/main.c | 9 ++
15 kernel/power/power.h | 11 ++
16 kernel/power/userwakelock.c | 218 +++++++++++++++++++++++++++++++++++++++++++
17 5 files changed, 249 insertions(+), 0 deletions(-)
18 create mode 100644 kernel/power/userwakelock.c
19
20 --- a/kernel/power/Kconfig
21 +++ b/kernel/power/Kconfig
22 @@ -138,6 +138,16 @@ config WAKELOCK_STAT
23 ---help---
24 Report wake lock stats in /proc/wakelocks
25
26 +config USER_WAKELOCK
27 + bool "Userspace wake locks"
28 + depends on WAKELOCK
29 + default y
30 + ---help---
31 + User-space wake lock api. Write "lockname" or "lockname timeout"
32 + to /sys/power/wake_lock lock and if needed create a wake lock.
33 + Write "lockname" to /sys/power/wake_unlock to unlock a user wake
34 + lock.
35 +
36 config EARLYSUSPEND
37 bool "Early suspend"
38 depends on WAKELOCK
39 --- a/kernel/power/Makefile
40 +++ b/kernel/power/Makefile
41 @@ -7,6 +7,7 @@ obj-$(CONFIG_PM) += main.o
42 obj-$(CONFIG_PM_SLEEP) += console.o
43 obj-$(CONFIG_FREEZER) += process.o
44 obj-$(CONFIG_WAKELOCK) += wakelock.o
45 +obj-$(CONFIG_USER_WAKELOCK) += userwakelock.o
46 obj-$(CONFIG_EARLYSUSPEND) += earlysuspend.o
47 obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o
48
49 --- a/kernel/power/main.c
50 +++ b/kernel/power/main.c
51 @@ -595,6 +595,11 @@ pm_trace_store(struct kobject *kobj, str
52 power_attr(pm_trace);
53 #endif /* CONFIG_PM_TRACE */
54
55 +#ifdef CONFIG_USER_WAKELOCK
56 +power_attr(wake_lock);
57 +power_attr(wake_unlock);
58 +#endif
59 +
60 static struct attribute * g[] = {
61 &state_attr.attr,
62 #ifdef CONFIG_PM_TRACE
63 @@ -603,6 +608,10 @@ static struct attribute * g[] = {
64 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
65 &pm_test_attr.attr,
66 #endif
67 +#ifdef CONFIG_USER_WAKELOCK
68 + &wake_lock_attr.attr,
69 + &wake_unlock_attr.attr,
70 +#endif
71 NULL,
72 };
73
74 --- a/kernel/power/power.h
75 +++ b/kernel/power/power.h
76 @@ -231,6 +231,17 @@ extern struct wake_lock main_wake_lock;
77 extern suspend_state_t requested_suspend_state;
78 #endif
79
80 +#ifdef CONFIG_USER_WAKELOCK
81 +ssize_t wake_lock_show(struct kobject *kobj, struct kobj_attribute *attr,
82 + char *buf);
83 +ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,
84 + const char *buf, size_t n);
85 +ssize_t wake_unlock_show(struct kobject *kobj, struct kobj_attribute *attr,
86 + char *buf);
87 +ssize_t wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr,
88 + const char *buf, size_t n);
89 +#endif
90 +
91 #ifdef CONFIG_EARLYSUSPEND
92 /* kernel/power/earlysuspend.c */
93 void request_suspend_state(suspend_state_t state);
94 --- /dev/null
95 +++ b/kernel/power/userwakelock.c
96 @@ -0,0 +1,218 @@
97 +/* kernel/power/userwakelock.c
98 + *
99 + * Copyright (C) 2005-2008 Google, Inc.
100 + *
101 + * This software is licensed under the terms of the GNU General Public
102 + * License version 2, as published by the Free Software Foundation, and
103 + * may be copied, distributed, and modified under those terms.
104 + *
105 + * This program is distributed in the hope that it will be useful,
106 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
107 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
108 + * GNU General Public License for more details.
109 + *
110 + */
111 +
112 +#include <linux/ctype.h>
113 +#include <linux/module.h>
114 +#include <linux/wakelock.h>
115 +
116 +#include "power.h"
117 +
118 +enum {
119 + DEBUG_FAILURE = BIT(0),
120 + DEBUG_ERROR = BIT(1),
121 + DEBUG_NEW = BIT(2),
122 + DEBUG_ACCESS = BIT(3),
123 + DEBUG_LOOKUP = BIT(4),
124 +};
125 +static int debug_mask = DEBUG_FAILURE;
126 +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
127 +
128 +static DEFINE_MUTEX(tree_lock);
129 +
130 +struct user_wake_lock {
131 + struct rb_node node;
132 + struct wake_lock wake_lock;
133 + char name[0];
134 +};
135 +struct rb_root user_wake_locks;
136 +
137 +static struct user_wake_lock *lookup_wake_lock_name(
138 + const char *buf, int allocate, long *timeoutptr)
139 +{
140 + struct rb_node **p = &user_wake_locks.rb_node;
141 + struct rb_node *parent = NULL;
142 + struct user_wake_lock *l;
143 + int diff;
144 + u64 timeout;
145 + int name_len;
146 + const char *arg;
147 +
148 + /* Find length of lock name and start of optional timeout string */
149 + arg = buf;
150 + while (*arg && !isspace(*arg))
151 + arg++;
152 + name_len = arg - buf;
153 + if (!name_len)
154 + goto bad_arg;
155 + while (isspace(*arg))
156 + arg++;
157 +
158 + /* Process timeout string */
159 + if (timeoutptr && *arg) {
160 + timeout = simple_strtoull(arg, (char **)&arg, 0);
161 + while (isspace(*arg))
162 + arg++;
163 + if (*arg)
164 + goto bad_arg;
165 + /* convert timeout from nanoseconds to jiffies > 0 */
166 + timeout += (NSEC_PER_SEC / HZ) - 1;
167 + do_div(timeout, (NSEC_PER_SEC / HZ));
168 + if (timeout <= 0)
169 + timeout = 1;
170 + *timeoutptr = timeout;
171 + } else if (*arg)
172 + goto bad_arg;
173 + else if (timeoutptr)
174 + *timeoutptr = 0;
175 +
176 + /* Lookup wake lock in rbtree */
177 + while (*p) {
178 + parent = *p;
179 + l = rb_entry(parent, struct user_wake_lock, node);
180 + diff = strncmp(buf, l->name, name_len);
181 + if (!diff && l->name[name_len])
182 + diff = -1;
183 + if (debug_mask & DEBUG_ERROR)
184 + pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",
185 + name_len, buf, l->name, diff);
186 +
187 + if (diff < 0)
188 + p = &(*p)->rb_left;
189 + else if (diff > 0)
190 + p = &(*p)->rb_right;
191 + else
192 + return l;
193 + }
194 +
195 + /* Allocate and add new wakelock to rbtree */
196 + if (!allocate) {
197 + if (debug_mask & DEBUG_ERROR)
198 + pr_info("lookup_wake_lock_name: %.*s not found\n",
199 + name_len, buf);
200 + return ERR_PTR(-EINVAL);
201 + }
202 + l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);
203 + if (l == NULL) {
204 + if (debug_mask & DEBUG_FAILURE)
205 + pr_err("lookup_wake_lock_name: failed to allocate "
206 + "memory for %.*s\n", name_len, buf);
207 + return ERR_PTR(-ENOMEM);
208 + }
209 + memcpy(l->name, buf, name_len);
210 + if (debug_mask & DEBUG_NEW)
211 + pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);
212 + wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);
213 + rb_link_node(&l->node, parent, p);
214 + rb_insert_color(&l->node, &user_wake_locks);
215 + return l;
216 +
217 +bad_arg:
218 + if (debug_mask & DEBUG_ERROR)
219 + pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",
220 + name_len, buf, arg);
221 + return ERR_PTR(-EINVAL);
222 +}
223 +
224 +ssize_t wake_lock_show(
225 + struct kobject *kobj, struct kobj_attribute *attr, char *buf)
226 +{
227 + char *s = buf;
228 + char *end = buf + PAGE_SIZE;
229 + struct rb_node *n;
230 + struct user_wake_lock *l;
231 +
232 + mutex_lock(&tree_lock);
233 +
234 + for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
235 + l = rb_entry(n, struct user_wake_lock, node);
236 + if (wake_lock_active(&l->wake_lock))
237 + s += scnprintf(s, end - s, "%s ", l->name);
238 + }
239 + s += scnprintf(s, end - s, "\n");
240 +
241 + mutex_unlock(&tree_lock);
242 + return (s - buf);
243 +}
244 +
245 +ssize_t wake_lock_store(
246 + struct kobject *kobj, struct kobj_attribute *attr,
247 + const char *buf, size_t n)
248 +{
249 + long timeout;
250 + struct user_wake_lock *l;
251 +
252 + mutex_lock(&tree_lock);
253 + l = lookup_wake_lock_name(buf, 1, &timeout);
254 + if (IS_ERR(l)) {
255 + n = PTR_ERR(l);
256 + goto bad_name;
257 + }
258 +
259 + if (debug_mask & DEBUG_ACCESS)
260 + pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
261 +
262 + if (timeout)
263 + wake_lock_timeout(&l->wake_lock, timeout);
264 + else
265 + wake_lock(&l->wake_lock);
266 +bad_name:
267 + mutex_unlock(&tree_lock);
268 + return n;
269 +}
270 +
271 +
272 +ssize_t wake_unlock_show(
273 + struct kobject *kobj, struct kobj_attribute *attr, char *buf)
274 +{
275 + char *s = buf;
276 + char *end = buf + PAGE_SIZE;
277 + struct rb_node *n;
278 + struct user_wake_lock *l;
279 +
280 + mutex_lock(&tree_lock);
281 +
282 + for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
283 + l = rb_entry(n, struct user_wake_lock, node);
284 + if (!wake_lock_active(&l->wake_lock))
285 + s += scnprintf(s, end - s, "%s ", l->name);
286 + }
287 + s += scnprintf(s, end - s, "\n");
288 +
289 + mutex_unlock(&tree_lock);
290 + return (s - buf);
291 +}
292 +
293 +ssize_t wake_unlock_store(
294 + struct kobject *kobj, struct kobj_attribute *attr,
295 + const char *buf, size_t n)
296 +{
297 + struct user_wake_lock *l;
298 +
299 + mutex_lock(&tree_lock);
300 + l = lookup_wake_lock_name(buf, 0, NULL);
301 + if (IS_ERR(l)) {
302 + n = PTR_ERR(l);
303 + goto not_found;
304 + }
305 +
306 + if (debug_mask & DEBUG_ACCESS)
307 + pr_info("wake_unlock_store: %s\n", l->name);
308 +
309 + wake_unlock(&l->wake_lock);
310 +not_found:
311 + mutex_unlock(&tree_lock);
312 + return n;
313 +}
314 +
This page took 0.080608 seconds and 5 git commands to generate.