1 /* kernel/power/userwakelock.c
2 *
3 * Copyright (C) 2005-2008 Google, Inc.
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16 #include <linux/ctype.h>
17 #include <linux/module.h>
18 #include <linux/wakelock.h>
19
20 #include "power.h"
21
22 enum {
23 DEBUG_FAILURE = BIT(0),
24 DEBUG_ERROR = BIT(1),
25 DEBUG_NEW = BIT(2),
26 DEBUG_ACCESS = BIT(3),
27 DEBUG_LOOKUP = BIT(4),
28 };
29 static int debug_mask = DEBUG_FAILURE;
30 module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
31
32 static DEFINE_MUTEX(tree_lock);
33
34 struct user_wake_lock {
35 struct rb_node node;
36 struct wake_lock wake_lock;
37 char name[0];
38 };
39 struct rb_root user_wake_locks;
40
lookup_wake_lock_name(const char * buf,int allocate,long * timeoutptr)41 static struct user_wake_lock *lookup_wake_lock_name(
42 const char *buf, int allocate, long *timeoutptr)
43 {
44 struct rb_node **p = &user_wake_locks.rb_node;
45 struct rb_node *parent = NULL;
46 struct user_wake_lock *l;
47 int diff;
48 u64 timeout;
49 int name_len;
50 const char *arg;
51
52 /* Find length of lock name and start of optional timeout string */
53 arg = buf;
54 while (*arg && !isspace(*arg))
55 arg++;
56 name_len = arg - buf;
57 if (!name_len)
58 goto bad_arg;
59 while (isspace(*arg))
60 arg++;
61
62 /* Process timeout string */
63 if (timeoutptr && *arg) {
64 timeout = simple_strtoull(arg, (char **)&arg, 0);
65 while (isspace(*arg))
66 arg++;
67 if (*arg)
68 goto bad_arg;
69 /* convert timeout from nanoseconds to jiffies > 0 */
70 timeout += (NSEC_PER_SEC / HZ) - 1;
71 do_div(timeout, (NSEC_PER_SEC / HZ));
72 if (timeout <= 0)
73 timeout = 1;
74 *timeoutptr = timeout;
75 } else if (*arg)
76 goto bad_arg;
77 else if (timeoutptr)
78 *timeoutptr = 0;
79
80 /* Lookup wake lock in rbtree */
81 while (*p) {
82 parent = *p;
83 l = rb_entry(parent, struct user_wake_lock, node);
84 diff = strncmp(buf, l->name, name_len);
85 if (!diff && l->name[name_len])
86 diff = -1;
87 if (debug_mask & DEBUG_ERROR)
88 pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",
89 name_len, buf, l->name, diff);
90
91 if (diff < 0)
92 p = &(*p)->rb_left;
93 else if (diff > 0)
94 p = &(*p)->rb_right;
95 else
96 return l;
97 }
98
99 /* Allocate and add new wakelock to rbtree */
100 if (!allocate) {
101 if (debug_mask & DEBUG_ERROR)
102 pr_info("lookup_wake_lock_name: %.*s not found\n",
103 name_len, buf);
104 return ERR_PTR(-EINVAL);
105 }
106 l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);
107 if (l == NULL) {
108 if (debug_mask & DEBUG_FAILURE)
109 pr_err("lookup_wake_lock_name: failed to allocate "
110 "memory for %.*s\n", name_len, buf);
111 return ERR_PTR(-ENOMEM);
112 }
113 memcpy(l->name, buf, name_len);
114 if (debug_mask & DEBUG_NEW)
115 pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);
116 wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);
117 rb_link_node(&l->node, parent, p);
118 rb_insert_color(&l->node, &user_wake_locks);
119 return l;
120
121 bad_arg:
122 if (debug_mask & DEBUG_ERROR)
123 pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",
124 name_len, buf, arg);
125 return ERR_PTR(-EINVAL);
126 }
127
wake_lock_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)128 ssize_t wake_lock_show(
129 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
130 {
131 char *s = buf;
132 char *end = buf + PAGE_SIZE;
133 struct rb_node *n;
134 struct user_wake_lock *l;
135
136 mutex_lock(&tree_lock);
137
138 for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
139 l = rb_entry(n, struct user_wake_lock, node);
140 if (wake_lock_active(&l->wake_lock))
141 s += scnprintf(s, end - s, "%s ", l->name);
142 }
143 s += scnprintf(s, end - s, "\n");
144
145 mutex_unlock(&tree_lock);
146 return (s - buf);
147 }
148
wake_lock_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t n)149 ssize_t wake_lock_store(
150 struct kobject *kobj, struct kobj_attribute *attr,
151 const char *buf, size_t n)
152 {
153 long timeout;
154 struct user_wake_lock *l;
155
156 mutex_lock(&tree_lock);
157 l = lookup_wake_lock_name(buf, 1, &timeout);
158 if (IS_ERR(l)) {
159 n = PTR_ERR(l);
160 goto bad_name;
161 }
162
163 if (debug_mask & DEBUG_ACCESS)
164 pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);
165
166 if (timeout)
167 wake_lock_timeout(&l->wake_lock, timeout);
168 else
169 wake_lock(&l->wake_lock);
170 bad_name:
171 mutex_unlock(&tree_lock);
172 return n;
173 }
174
175
wake_unlock_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)176 ssize_t wake_unlock_show(
177 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
178 {
179 char *s = buf;
180 char *end = buf + PAGE_SIZE;
181 struct rb_node *n;
182 struct user_wake_lock *l;
183
184 mutex_lock(&tree_lock);
185
186 for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {
187 l = rb_entry(n, struct user_wake_lock, node);
188 if (!wake_lock_active(&l->wake_lock))
189 s += scnprintf(s, end - s, "%s ", l->name);
190 }
191 s += scnprintf(s, end - s, "\n");
192
193 mutex_unlock(&tree_lock);
194 return (s - buf);
195 }
196
wake_unlock_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t n)197 ssize_t wake_unlock_store(
198 struct kobject *kobj, struct kobj_attribute *attr,
199 const char *buf, size_t n)
200 {
201 struct user_wake_lock *l;
202
203 mutex_lock(&tree_lock);
204 l = lookup_wake_lock_name(buf, 0, NULL);
205 if (IS_ERR(l)) {
206 n = PTR_ERR(l);
207 goto not_found;
208 }
209
210 if (debug_mask & DEBUG_ACCESS)
211 pr_info("wake_unlock_store: %s\n", l->name);
212
213 wake_unlock(&l->wake_lock);
214 not_found:
215 mutex_unlock(&tree_lock);
216 return n;
217 }
218
219