power: introduce eventlock for iot-headless 56/268956/8
authorYoungjae Cho <y0.cho@samsung.com>
Wed, 5 Jan 2022 07:44:15 +0000 (16:44 +0900)
committeryoungjae cho <y0.cho@samsung.com>
Thu, 6 Jan 2022 05:33:15 +0000 (05:33 +0000)
eventlock is another wakelock for guaranteeing subroutine of an event
not to go to sleep regardless of power state. Therefore, the eventlock
works independently of mainlock, which is affected by power state.
The previous templock, which was for key event, has changed to eventlock.

Change-Id: Ie6ac4cf2de6989845b2e64eefe06002147736da2
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
plugins/iot-headless/power/power-event-lock.c [new file with mode: 0644]
plugins/iot-headless/power/power-event-lock.h [new file with mode: 0644]
plugins/iot-headless/power/power-state-manager.c

diff --git a/plugins/iot-headless/power/power-event-lock.c b/plugins/iot-headless/power/power-event-lock.c
new file mode 100644 (file)
index 0000000..0e75814
--- /dev/null
@@ -0,0 +1,133 @@
+#include <glib.h>
+#include <stdint.h>
+#include <linux/input.h>
+
+#include "shared/bitmap.h"
+#include "shared/device-notifier.h"
+#include "shared/log.h"
+#include "power-event-lock.h"
+
+/* eventlock is another wakelock than mainlock.
+ *
+ * The eventlock works independently of mainlock, which is controlled by
+ * power state. The main purpose of eventlock is to prevent the subroutine
+ * of an event from going to sleep regardless of the power state. */
+#define EVENT_LOCK              "eventlock"
+#define EVENT_LOCK_MARGIN_MS    1000
+
+enum eventlock_type {
+       EL_MIN,
+       /* On receiving key event, expands EL_KEY to EL_KEY_* according to keycode */
+       EL_KEY,
+       EL_KEY_POWER = EL_KEY,
+       EL_KEY_BLUETOOTH,
+       /* add eventlock type here */
+       EL_MAX,
+};
+
+static struct dd_bitmap *eventlock;
+static int notifier_id[EL_MAX][2];
+
+static void event_wake_lock(enum eventlock_type type)
+{
+       int setcount;
+
+       if (type <= EL_MIN || type >= EL_MAX)
+               return;
+
+       set_bit(eventlock, type);
+       setcount = count_set_bit(eventlock);
+
+       _D("Set eventlock of type=%d, current number of eventlock=%d", type, setcount);
+
+       if (setcount == 1) {
+               sys_set_str("/sys/power/wake_lock", EVENT_LOCK);
+               _D("Acquired eventlock");
+       }
+}
+
+static void event_wake_unlock(enum eventlock_type type)
+{
+       int setcount;
+
+       if (type <= EL_MIN || type >= EL_MAX)
+               return;
+
+       clear_bit(eventlock, type);
+       setcount = count_set_bit(eventlock);
+
+       _D("Unset eventlock of type=%d, current number of eventlock=%d", type, setcount);
+
+       if (setcount == 0) {
+               sys_set_str("/sys/power/wake_unlock", EVENT_LOCK);
+               _D("Released eventlock");
+       }
+}
+
+static enum eventlock_type expand_key_eventlock_type(int keycode)
+{
+       if (keycode == KEY_POWER)
+               return EL_KEY_POWER;
+       if (keycode == KEY_BLUETOOTH)
+               return EL_KEY_BLUETOOTH;
+       /* add mapping for keycode to eventlock_type here */
+
+       return EL_MAX;
+}
+
+static int power_event_lock_callback(void *data, void *udata)
+{
+       enum eventlock_type type = (enum eventlock_type)(intptr_t) udata;
+
+       if (type == EL_KEY) {
+               /* On receiving key event, expand EL_KEY to EL_KEY_* according to the keycode */
+               int keycode = (int)(intptr_t) data;
+               type = expand_key_eventlock_type(keycode);
+       }
+
+       event_wake_lock(type);
+
+       return 0;
+}
+
+static int power_event_unlock_callback(void *data, void *udata)
+{
+       enum eventlock_type type = (enum eventlock_type)(intptr_t) udata;
+
+       if (type == EL_KEY) {
+               /* On receiving key event, expand EL_KEY to EL_KEY_* according to the keycode */
+               int keycode = (int)(intptr_t) data;
+               type = expand_key_eventlock_type(keycode);
+       }
+
+       event_wake_unlock(type);
+
+       return 0;
+}
+
+static void register_power_event_lock_controller(enum eventlock_type type,
+       enum device_notifier_type lock_notify,
+       enum device_notifier_type unlock_notify)
+{
+       /* Acquiring lock must be followed by all the other notifiers, therefore
+        * give a large enough number as priority to make it be at the head of notifier list.
+        * On the other hand, releasing lock must follow all the other notifiers, therefore
+        * give a small enough number as priority to make it be at the tail of notifier list. */
+       notifier_id[type][0] = register_notifier_udata_priority(lock_notify,
+               power_event_lock_callback, (void *)(intptr_t) type, NULL, 1000);
+       notifier_id[type][1] = register_notifier_udata_priority(unlock_notify,
+               power_event_unlock_callback, (void *)(intptr_t) type, NULL, -1000);
+}
+
+void power_event_lock_init(void)
+{
+       eventlock = init_bitmap(EL_MAX);
+       if (!eventlock) {
+               _E("Failed to init event lock bitmap");
+               return;
+       }
+
+       register_power_event_lock_controller(EL_KEY,
+               DEVICE_NOTIFIER_KEY_PRESS,
+               DEVICE_NOTIFIER_KEY_RELEASE);
+}
diff --git a/plugins/iot-headless/power/power-event-lock.h b/plugins/iot-headless/power/power-event-lock.h
new file mode 100644 (file)
index 0000000..f7906c5
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __POWER_EVENT_LOCK_H__
+#define __POWER_EVENT_LOCK_H__
+
+void power_event_lock_init(void);
+
+#endif //__POWER_EVENT_LOCK_H__
+
index 959ed9c..5232c20 100644 (file)
 #include "power-state-manager.h"
 #include "power-dbus.h"
 #include "power-state-wait.h"
-
-/* Temporal wakelock of powerkey input */
-#define KEY_PRESSED_TEMPORAL_LOCK    "templock"
-#define TEMPORAL_LOCK_WAKE_MARGIN    1000 /* milisecond */
+#include "power-event-lock.h"
 
 #define EVENT_TYPE_SLEEP    0
 #define EVENT_TYPE_WAKEUP   1
 
-static guint keypress_temporal_timer_id;
-
 char *psm_name[PSM_MAX] = {
        [PSM_NORMAL] = "PSM_NORMAL",
        [PSM_SLEEP] = "PSM_SLEEP",
@@ -31,50 +26,6 @@ char *psm_name[PSM_MAX] = {
 static guint64 state_transition_counter = 0;
 static enum psm_state current;
 
-static gboolean temporal_lock_expired_cb(void *data)
-{
-       sys_set_str("/sys/power/wake_unlock", KEY_PRESSED_TEMPORAL_LOCK);
-       keypress_temporal_timer_id = 0;
-
-       return G_SOURCE_REMOVE;
-}
-
-static int acquire_temporal_lock(void *data)
-{
-       int keycode = (int)(intptr_t) data;
-
-       if (keycode != KEY_POWER)
-               return 0;
-
-       if (keypress_temporal_timer_id) {
-               g_source_remove(keypress_temporal_timer_id);
-               keypress_temporal_timer_id = 0;
-       }
-
-       sys_set_str("/sys/power/wake_lock", KEY_PRESSED_TEMPORAL_LOCK);
-
-       return 0;
-}
-
-static int release_temporal_lock(void * data)
-{
-       int keycode = (int)(intptr_t) data;
-
-       if (keycode != KEY_POWER)
-               return 0;
-
-       if (keypress_temporal_timer_id) {
-               g_source_remove(keypress_temporal_timer_id);
-               keypress_temporal_timer_id = 0;
-       }
-
-       /* templock margin */
-       keypress_temporal_timer_id = g_timeout_add(TEMPORAL_LOCK_WAKE_MARGIN,
-               temporal_lock_expired_cb, NULL);
-
-       return 0;
-}
-
 static void psm_wake_unlock(void)
 {
        /* for PSM_NORMAL, PSM_POWEROFF, do not wake unlock */
@@ -235,11 +186,10 @@ void power_state_manager_init(void *data)
        device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL);
        device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
 
-       register_notifier(DEVICE_NOTIFIER_KEY_PRESS, acquire_temporal_lock);
-       register_notifier(DEVICE_NOTIFIER_KEY_RELEASE, release_temporal_lock);
        register_notifier(DEVICE_NOTIFIER_INPUT_TRANSITION_STATE, psm_transition_state_cb);
 
        power_plugin_dbus_init(NULL);
+       power_event_lock_init();
 }
 
 static const struct device_ops power_state_manager_device_ops = {