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 <asinghal@codeaurora.org>
diff --git a/kernel/power/main.c b/kernel/power/main.c
index ff29679..6aeabf9 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -15,6 +15,8 @@
#include "power.h"
+#define MAX_BUF 100
+
DEFINE_MUTEX(pm_mutex);
#ifdef CONFIG_PM_SLEEP
@@ -23,6 +25,10 @@
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);
@@ -67,6 +73,72 @@
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;
@@ -313,7 +385,9 @@
power_attr(wake_unlock);
#endif
-static struct attribute * g[] = {
+static struct attribute *g[] = {
+ &touch_event_attr.attr,
+ &touch_event_timer_attr.attr,
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
@@ -358,6 +432,11 @@
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;