kernel/main: fix calling sysfs_notify from atomic context
Sysfs_notify takes a mutex and therefore cannot be called from atomic
context like interrupt handler in this case. Use a workqueue to schedule
the work instead.
Change-Id: I0a5230fe379aa51f1065df4af9b27f471aa22440
Signed-off-by: Amar Singhal <asinghal@codeaurora.org>
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 6aeabf9..9b279cc 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -12,6 +12,7 @@
#include <linux/string.h>
#include <linux/resume-trace.h>
#include <linux/workqueue.h>
+#include <linux/hrtimer.h>
#include "power.h"
@@ -25,8 +26,11 @@
static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
-static struct hrtimer in_ev_timer;
-static int input_processed;
+static void touch_event_fn(struct work_struct *work);
+static DECLARE_WORK(touch_event_struct, touch_event_fn);
+
+static struct hrtimer tc_ev_timer;
+static int tc_ev_processed;
static ktime_t touch_evt_timer_val;
int register_pm_notifier(struct notifier_block *nb)
@@ -77,7 +81,7 @@
touch_event_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- if (input_processed == 0)
+ if (tc_ev_processed == 0)
return snprintf(buf, strnlen("touch_event", MAX_BUF) + 1,
"touch_event");
else
@@ -91,13 +95,13 @@
const char *buf, size_t n)
{
- hrtimer_cancel(&in_ev_timer);
- input_processed = 0;
+ hrtimer_cancel(&tc_ev_timer);
+ tc_ev_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);
+ hrtimer_start(&tc_ev_timer, touch_evt_timer_val, HRTIMER_MODE_REL);
/* wakeup the userspace poll */
sysfs_notify(kobj, NULL, "touch_event");
@@ -131,11 +135,20 @@
power_attr(touch_event_timer);
-static enum hrtimer_restart input_event_stop(struct hrtimer *hrtimer)
+static void touch_event_fn(struct work_struct *work)
{
/* wakeup the userspace poll */
- input_processed = 1;
+ tc_ev_processed = 1;
sysfs_notify(power_kobj, NULL, "touch_event");
+
+ return;
+}
+
+static enum hrtimer_restart tc_ev_stop(struct hrtimer *hrtimer)
+{
+
+ schedule_work(&touch_event_struct);
+
return HRTIMER_NORESTART;
}
@@ -434,8 +447,9 @@
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;
+ hrtimer_init(&tc_ev_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ tc_ev_timer.function = &tc_ev_stop;
+ tc_ev_processed = 1;
power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj)