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