0069-PM-Add-user-space-wake-lock-api.patch 8.4 KB

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