This adds /sys/power/wake_lock and /sys/power/wake_unlock.Writing a string to wake_lock creates a wake lock thefirst time is sees a string and locks it. Optionally, thestring can be followed by a timeout.To unlock the wake lock, write the same string to wake_unlock. Signed-off-by: Arve Hjønnevåg <arve@xxxxxxxxxxx>--- kernel/power/Kconfig | 10 ++ kernel/power/Makefile | 1 + kernel/power/main.c | 9 ++ kernel/power/power.h | 11 ++ kernel/power/userwakelock.c | 218 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 249 insertions(+), 0 deletions(-) create mode 100644 kernel/power/userwakelock.c diff --git a/kernel/power/Kconfig b/kernel/power/Kconfigindex 689abfe..aedea7e 100644--- a/kernel/power/Kconfig+++ b/kernel/power/Kconfig@@ -147,6 +147,16 @@ config DISABLE_SYS_POWER_STATE want to run user-space code that does not support wakelocks, do not enable this option since it removes the interface. +config USER_WAKELOCK+ bool "Userspace wake locks"+ depends on WAKELOCK+ default y+ ---help---+ User-space wake lock api. Write "lockname" or "lockname timeout"+ to /sys/power/wake_lock lock and if needed create a wake lock.+ Write "lockname" to /sys/power/wake_unlock to unlock a user wake+ lock.+ config EARLYSUSPEND bool "Early suspend" depends on WAKELOCKdiff --git a/kernel/power/Makefile b/kernel/power/Makefileindex 2f17e1d..d3467b3 100644--- a/kernel/power/Makefile+++ b/kernel/power/Makefile@@ -7,6 +7,7 @@ obj-y := main.o obj-$(CONFIG_PM_SLEEP) += console.o obj-$(CONFIG_FREEZER) += process.o obj-$(CONFIG_WAKELOCK) += wakelock.o+obj-$(CONFIG_USER_WAKELOCK) += userwakelock.o obj-$(CONFIG_EARLYSUSPEND) += earlysuspend.o obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o diff --git a/kernel/power/main.c b/kernel/power/main.cindex 676a8b0..a4065f3 100644--- a/kernel/power/main.c+++ b/kernel/power/main.c@@ -641,6 +641,11 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(pm_trace); #endif /* CONFIG_PM_TRACE */ +#ifdef CONFIG_USER_WAKELOCK+power_attr(wake_lock);+power_attr(wake_unlock);+#endif+ static struct attribute * g[] = { #ifndef CONFIG_DISABLE_SYS_POWER_STATE &state_attr.attr,@@ -654,6 +659,10 @@ static struct attribute * g[] = { #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG) &pm_test_attr.attr, #endif+#ifdef CONFIG_USER_WAKELOCK+ &wake_lock_attr.attr,+ &wake_unlock_attr.attr,+#endif NULL, }; diff --git a/kernel/power/power.h b/kernel/power/power.hindex acbb13a..1b01327 100644--- a/kernel/power/power.h+++ b/kernel/power/power.h@@ -232,6 +232,17 @@ extern suspend_state_t requested_suspend_state; extern bool ignore_suspend_wakelocks; #endif +#ifdef CONFIG_USER_WAKELOCK+ssize_t wake_lock_show(struct kobject *kobj, struct kobj_attribute *attr,+ char *buf);+ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,+ const char *buf, size_t n);+ssize_t wake_unlock_show(struct kobject *kobj, struct kobj_attribute *attr,+ char *buf);+ssize_t wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr,+ const char *buf, size_t n);+#endif+ #ifdef CONFIG_EARLYSUSPEND /* kernel/power/earlysuspend.c */ void request_suspend_state(suspend_state_t state);diff --git a/kernel/power/userwakelock.c b/kernel/power/userwakelock.cnew file mode 100644index 0000000..d7242d9--- /dev/null+++ b/kernel/power/userwakelock.c@@ -0,0 +1,218 @@+/* kernel/power/userwakelock.c+ *+ * Copyright (C) 2005-2008 Google, Inc.+ *+ * This software is licensed under the terms of the GNU General Public+ * License version 2, as published by the Free Software Foundation, and+ * may be copied, distributed, and modified under those terms.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU General Public License for more details.+ *+ */++#include <linux/ctype.h>+#include <linux/module.h>+#include <linux/wakelock.h>++#include "power.h"++enum {+ DEBUG_FAILURE = BIT(0),+ DEBUG_ERROR = BIT(1),+ DEBUG_NEW = BIT(2),+ DEBUG_ACCESS = BIT(3),+ DEBUG_LOOKUP = BIT(4),+};+static int debug_mask = DEBUG_FAILURE;+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);++static DEFINE_MUTEX(tree_lock);++struct user_wake_lock {+ struct rb_node node;+ struct wake_lock wake_lock;+ char name[0];+};+struct rb_root user_wake_locks;++static struct user_wake_lock *lookup_wake_lock_name(+ const char *buf, int allocate, long *timeoutptr)+{+ struct rb_node **p = &user_wake_locks.rb_node;+ struct rb_node *parent = NULL;+ struct user_wake_lock *l;+ int diff;+ u64 timeout;+ int name_len;+ const char *arg;++ /* Find length of lock name and start of optional timeout string */+ arg = buf;+ while (*arg && !isspace(*arg))+ arg++;+ name_len = arg - buf;+ if (!name_len)+ goto bad_arg;+ while (isspace(*arg))+ arg++;++ /* Process timeout string */+ if (timeoutptr && *arg) {+ timeout = simple_strtoull(arg, (char **)&arg, 0);+ while (isspace(*arg))+ arg++;+ if (*arg)+ goto bad_arg;+ /* convert timeout from nanoseconds to jiffies > 0 */+ timeout += (NSEC_PER_SEC / HZ) - 1;+ do_div(timeout, (NSEC_PER_SEC / HZ));+ if (timeout <= 0)+ timeout = 1;+ *timeoutptr = timeout;+ } else if (*arg)+ goto bad_arg;+ else if (timeoutptr)+ *timeoutptr = 0;++ /* Lookup wake lock in rbtree */+ while (*p) {+ parent = *p;+ l = rb_entry(parent, struct user_wake_lock, node);+ diff = strncmp(buf, l->name, name_len);+ if (!diff && l->name[name_len])+ diff = -1;+ if (debug_mask & DEBUG_ERROR)+ pr_info("lookup_wake_lock_name: compare %.*s %s %d\n",+ name_len, buf, l->name, diff);++ if (diff < 0)+ p = &(*p)->rb_left;+ else if (diff > 0)+ p = &(*p)->rb_right;+ else+ return l;+ }++ /* Allocate and add new wakelock to rbtree */+ if (!allocate) {+ if (debug_mask & DEBUG_ERROR)+ pr_info("lookup_wake_lock_name: %.*s not found\n",+ name_len, buf);+ return ERR_PTR(-EINVAL);+ }+ l = kzalloc(sizeof(*l) + name_len + 1, GFP_KERNEL);+ if (l == NULL) {+ if (debug_mask & DEBUG_FAILURE)+ pr_err("lookup_wake_lock_name: failed to allocate "+ "memory for %.*s\n", name_len, buf);+ return ERR_PTR(-ENOMEM);+ }+ memcpy(l->name, buf, name_len);+ if (debug_mask & DEBUG_NEW)+ pr_info("lookup_wake_lock_name: new wake lock %s\n", l->name);+ wake_lock_init(&l->wake_lock, WAKE_LOCK_SUSPEND, l->name);+ rb_link_node(&l->node, parent, p);+ rb_insert_color(&l->node, &user_wake_locks);+ return l;++bad_arg:+ if (debug_mask & DEBUG_ERROR)+ pr_info("lookup_wake_lock_name: wake lock, %.*s, bad arg, %s\n",+ name_len, buf, arg);+ return ERR_PTR(-EINVAL);+}++ssize_t wake_lock_show(+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)+{+ char *s = buf;+ char *end = buf + PAGE_SIZE;+ struct rb_node *n;+ struct user_wake_lock *l;++ mutex_lock(&tree_lock);++ for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {+ l = rb_entry(n, struct user_wake_lock, node);+ if (wake_lock_active(&l->wake_lock))+ s += scnprintf(s, end - s, "%s ", l->name);+ }+ s += scnprintf(s, end - s, "\n");++ mutex_unlock(&tree_lock);+ return (s - buf);+}++ssize_t wake_lock_store(+ struct kobject *kobj, struct kobj_attribute *attr,+ const char *buf, size_t n)+{+ long timeout;+ struct user_wake_lock *l;++ mutex_lock(&tree_lock);+ l = lookup_wake_lock_name(buf, 1, &timeout);+ if (IS_ERR(l)) {+ n = PTR_ERR(l);+ goto bad_name;+ }++ if (debug_mask & DEBUG_ACCESS)+ pr_info("wake_lock_store: %s, timeout %ld\n", l->name, timeout);++ if (timeout)+ wake_lock_timeout(&l->wake_lock, timeout);+ else+ wake_lock(&l->wake_lock);+bad_name:+ mutex_unlock(&tree_lock);+ return n;+}+++ssize_t wake_unlock_show(+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)+{+ char *s = buf;+ char *end = buf + PAGE_SIZE;+ struct rb_node *n;+ struct user_wake_lock *l;++ mutex_lock(&tree_lock);++ for (n = rb_first(&user_wake_locks); n != NULL; n = rb_next(n)) {+ l = rb_entry(n, struct user_wake_lock, node);+ if (!wake_lock_active(&l->wake_lock))+ s += scnprintf(s, end - s, "%s ", l->name);+ }+ s += scnprintf(s, end - s, "\n");++ mutex_unlock(&tree_lock);+ return (s - buf);+}++ssize_t wake_unlock_store(+ struct kobject *kobj, struct kobj_attribute *attr,+ const char *buf, size_t n)+{+ struct user_wake_lock *l;++ mutex_lock(&tree_lock);+ l = lookup_wake_lock_name(buf, 0, NULL);+ if (IS_ERR(l)) {+ n = PTR_ERR(l);+ goto not_found;+ }++ if (debug_mask & DEBUG_ACCESS)+ pr_info("wake_unlock_store: %s\n", l->name);++ wake_unlock(&l->wake_lock);+not_found:+ mutex_unlock(&tree_lock);+ return n;+}+-- 1.6.1 _______________________________________________linux-pm mailing listlinux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx://lists.linux-foundation.org/mailman/listinfo/linux-pm