From 6cc6e7bc61ce52855d7db2af795853efd378ef65 Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Mon, 27 Feb 2012 17:40:31 -0800 Subject: [PATCH] kernel/power: add pollable sysfs entries for touch events Provide userspace with a pollable sysfs entry that it can poll on waiting for touch event notifiction. Once it is woken up, the userspace can take action to change the power/performance characteristics of the device for the duration of the event. Change-Id: Iab84f729f2ea3a5352c4e5173f78544023a276c1 Signed-off-by: Amar Singhal (cherry picked from commit ac2a6d6453c50db7ba7c0b3aa328a3ba48a84abf) --- kernel/power/main.c | 81 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/kernel/power/main.c b/kernel/power/main.c index 7f3c91a634c..0b146e77c4b 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -18,6 +18,8 @@ #include "power.h" +#define MAX_BUF 100 + DEFINE_MUTEX(pm_mutex); #ifdef CONFIG_PM_SLEEP @@ -26,6 +28,10 @@ DEFINE_MUTEX(pm_mutex); static BLOCKING_NOTIFIER_HEAD(pm_chain_head); +static struct hrtimer in_ev_timer; +static int input_processed; +static ktime_t touch_evt_timer_val; + int register_pm_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&pm_chain_head, nb); @@ -71,6 +77,72 @@ static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(pm_async); +static ssize_t +touch_event_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + if (input_processed == 0) + return snprintf(buf, strnlen("touch_event", MAX_BUF) + 1, + "touch_event"); + else + return snprintf(buf, strnlen("null", MAX_BUF) + 1, + "null"); +} + +static ssize_t +touch_event_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + + hrtimer_cancel(&in_ev_timer); + input_processed = 0; + + /* set a timer to notify the userspace to stop processing + * touch event + */ + hrtimer_start(&in_ev_timer, touch_evt_timer_val, HRTIMER_MODE_REL); + + /* wakeup the userspace poll */ + sysfs_notify(kobj, NULL, "touch_event"); + + return n; +} + +power_attr(touch_event); + +static ssize_t +touch_event_timer_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, MAX_BUF, "%lld", touch_evt_timer_val.tv64); +} + +static ssize_t +touch_event_timer_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + touch_evt_timer_val = ktime_set(0, val*1000); + + return n; +} + +power_attr(touch_event_timer); + +static enum hrtimer_restart input_event_stop(struct hrtimer *hrtimer) +{ + /* wakeup the userspace poll */ + input_processed = 1; + sysfs_notify(power_kobj, NULL, "touch_event"); + return HRTIMER_NORESTART; +} + #ifdef CONFIG_PM_DEBUG int pm_test_level = TEST_NONE; @@ -405,7 +477,7 @@ power_attr(wake_lock); power_attr(wake_unlock); #endif -static struct attribute * g[] = { +static struct attribute *g[] = { &state_attr.attr, #ifdef CONFIG_PM_TRACE &pm_trace_attr.attr, @@ -414,6 +486,8 @@ static struct attribute * g[] = { #ifdef CONFIG_PM_SLEEP &pm_async_attr.attr, &wakeup_count_attr.attr, + &touch_event_attr.attr, + &touch_event_timer_attr.attr, #ifdef CONFIG_PM_DEBUG &pm_test_attr.attr, #endif @@ -450,6 +524,11 @@ static int __init pm_init(void) return error; hibernate_image_size_init(); hibernate_reserved_size_init(); + + touch_evt_timer_val = ktime_set(2, 0); + hrtimer_init(&in_ev_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + in_ev_timer.function = &input_event_stop; + power_kobj = kobject_create_and_add("power", NULL); if (!power_kobj) return -ENOMEM;