Root/target/linux/goldfish/patches-2.6.30/0069-PM-Add-user-space-wake-lock-api.patch

1From 48e1af2bdd11204f11b3770a6c8d3eee64aee2e8 Mon Sep 17 00:00:00 2001
2From: =?utf-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= <arve@android.com>
3Date: Thu, 9 Oct 2008 21:01:46 -0700
4Subject: [PATCH 069/134] PM: Add user-space wake lock api.
5
6This adds /sys/power/wake_lock and /sys/power/wake_unlock.
7Writing a string to wake_lock creates a wake lock the
8first time is sees a string and locks it. Optionally, the
9string can be followed by a timeout.
10To 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+
315

Archive Download this file



interactive