power: apply wait callback mechanism to all state transitions
[platform/core/system/deviced.git] / plugins / iot-headless / power / power-state-manager.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <linux/input.h>
4 #include <libsyscommon/libgdbus.h>
5 #include <libsyscommon/list.h>
6 #include <device/power-internal.h>
7
8 #include "shared/devices.h"
9 #include "shared/device-notifier.h"
10 #include "shared/log.h"
11 #include "power-state-manager.h"
12 #include "power-dbus.h"
13 #include "power-state-wait.h"
14
15 /* Temporal wakelock of powerkey input */
16 #define KEY_PRESSED_TEMPORAL_LOCK    "templock"
17 #define TEMPORAL_LOCK_WAKE_MARGIN    1000 /* milisecond */
18
19 #define EVENT_TYPE_SLEEP    0
20 #define EVENT_TYPE_WAKEUP   1
21
22 static guint keypress_temporal_timer_id;
23
24 char *psm_name[PSM_MAX] = {
25         [PSM_NORMAL] = "PSM_NORMAL",
26         [PSM_SLEEP] = "PSM_SLEEP",
27         [PSM_POWEROFF] = "PSM_POWEROFF",
28         [PSM_REBOOT] = "PSM_REBOOT",
29 };
30
31 static guint64 state_transition_counter = 0;
32 static enum psm_state current;
33
34 static gboolean temporal_lock_expired_cb(void *data)
35 {
36         sys_set_str("/sys/power/wake_unlock", KEY_PRESSED_TEMPORAL_LOCK);
37         keypress_temporal_timer_id = 0;
38
39         return G_SOURCE_REMOVE;
40 }
41
42 static int acquire_temporal_lock(void *data)
43 {
44         int keycode = (int)(intptr_t) data;
45
46         if (keycode != KEY_POWER)
47                 return 0;
48
49         if (keypress_temporal_timer_id) {
50                 g_source_remove(keypress_temporal_timer_id);
51                 keypress_temporal_timer_id = 0;
52         }
53
54         sys_set_str("/sys/power/wake_lock", KEY_PRESSED_TEMPORAL_LOCK);
55
56         return 0;
57 }
58
59 static int release_temporal_lock(void * data)
60 {
61         int keycode = (int)(intptr_t) data;
62
63         if (keycode != KEY_POWER)
64                 return 0;
65
66         if (keypress_temporal_timer_id) {
67                 g_source_remove(keypress_temporal_timer_id);
68                 keypress_temporal_timer_id = 0;
69         }
70
71         /* templock margin */
72         keypress_temporal_timer_id = g_timeout_add(TEMPORAL_LOCK_WAKE_MARGIN,
73                 temporal_lock_expired_cb, NULL);
74
75         return 0;
76 }
77
78 static void psm_wake_unlock(void)
79 {
80         /* for PSM_NORMAL, PSM_POWEROFF, do not wake unlock */
81         if (current != PSM_SLEEP) {
82                 _E("Ignore sleep wait done, current=%s", psm_name[current]);
83                 return;
84         }
85
86         device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL);
87 }
88
89 static void psm_trigger_poweroff(void)
90 {
91         const struct device_ops *power_device;
92
93         power_device = find_device("power");
94         if (check_default(power_device))
95                 return;
96
97         if (power_device->execute) {
98                 device_notify(DEVICE_NOTIFIER_REQUEST_DISABLE_AUTOSLEEP, NULL);
99                 power_device->execute("poweroff");
100         }
101 }
102
103 static void broadcast_transition_info(const struct trans_info *ti)
104 {
105         // mapping deviced state to capi signame
106         static const char *capi_signame[PSM_MAX] = {
107                 [PSM_NORMAL] = SIGNAME_CHANGE_STATE_TO_NORMAL,
108                 [PSM_SLEEP] = SIGNAME_CHANGE_STATE_TO_SLEEP,
109                 [PSM_POWEROFF] = SIGNAME_CHANGE_STATE_TO_POWEROFF,
110                 [PSM_REBOOT] = SIGNAME_CHANGE_STATE_TO_REBOOT,
111         };
112
113         // mapping deviced state to capi state
114         static const guint64 capi_state[PSM_MAX] = {
115                 [PSM_NORMAL] = POWER_STATE_NORMAL,
116                 [PSM_SLEEP] = POWER_STATE_SLEEP,
117                 [PSM_POWEROFF] = POWER_STATE_POWEROFF,
118                 [PSM_REBOOT] = POWER_STATE_REBOOT,
119         };
120
121         gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, capi_signame[ti->next],
122                 g_variant_new("(ttti)", capi_state[ti->curr], capi_state[ti->next], state_transition_counter, ti->reason));
123 }
124
125 static void psm_transition_normal_to_normal(const struct trans_info *ti)
126 {
127         broadcast_transition_info(ti);
128         update_change_state_wait(state_transition_counter, ti, NULL);
129 }
130
131 static void psm_transition_normal_to_sleep(const struct trans_info *ti)
132 {
133         int waiting;
134
135         current = PSM_SLEEP;
136
137         broadcast_transition_info(ti);
138         waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock);
139         if (waiting > 0) {
140                 _D("Defer wake unlock");
141                 return;
142         }
143
144         psm_wake_unlock();
145 }
146
147 static void psm_transition_sleep_to_normal(const struct trans_info *ti)
148 {
149         current = PSM_NORMAL;
150
151         broadcast_transition_info(ti);
152         device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
153         update_change_state_wait(state_transition_counter, ti, NULL);
154 }
155
156 static void psm_transition_sleep_to_sleep(const struct trans_info *ti)
157 {
158         int waiting;
159
160         broadcast_transition_info(ti);
161         device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
162         waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock);
163         if (waiting > 0) {
164                 _D("Defer wake unlock");
165                 return;
166         }
167
168         psm_wake_unlock();
169 }
170
171 static void psm_transition_normal_to_poweroff(const struct trans_info *ti)
172 {
173         int waiting;
174
175         current = PSM_POWEROFF;
176
177         broadcast_transition_info(ti);
178         waiting = update_change_state_wait(state_transition_counter, ti, psm_trigger_poweroff);
179         if (waiting > 0) {
180                 _D("Defer poweroff");
181                 return;
182         }
183
184         psm_trigger_poweroff();
185 }
186
187 static int psm_transition_state_cb(void *data)
188 {
189         GList *action_list, *elem;
190         const struct trans_info *ti = NULL;
191         enum psm_state next;
192
193         if (!data)
194                 return 0;
195
196         action_list = (GList *) data;
197
198         /* look for transition defined on the current state */
199         SYS_G_LIST_FOREACH(action_list, elem, ti) {
200                 if (ti->curr == current)
201                         break;
202         }
203
204         if (!ti)
205                 return 0;
206
207         next = ti->next;
208
209         _D("Transition power state: %s -> %s, reason=%d",
210                 psm_name[current], psm_name[next], ti->reason);
211
212         /* transition */
213         ++state_transition_counter;
214         if (current == PSM_NORMAL) {
215                 if (next == PSM_NORMAL)
216                         psm_transition_normal_to_normal(ti);
217                 else if (next == PSM_SLEEP)
218                         psm_transition_normal_to_sleep(ti);
219                 else if (next == PSM_POWEROFF)
220                         psm_transition_normal_to_poweroff(ti);
221         } else if (current == PSM_SLEEP) {
222                 if (next == PSM_NORMAL)
223                         psm_transition_sleep_to_normal(ti);
224                 else if (next == PSM_SLEEP)
225                         psm_transition_sleep_to_sleep(ti);
226         }
227
228         return 0;
229 }
230
231 void power_state_manager_init(void *data)
232 {
233         /* initialize state */
234         current = PSM_NORMAL;
235         device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL);
236         device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL);
237
238         register_notifier(DEVICE_NOTIFIER_KEY_PRESS, acquire_temporal_lock);
239         register_notifier(DEVICE_NOTIFIER_KEY_RELEASE, release_temporal_lock);
240         register_notifier(DEVICE_NOTIFIER_INPUT_TRANSITION_STATE, psm_transition_state_cb);
241
242         power_plugin_dbus_init(NULL);
243 }
244
245 static const struct device_ops power_state_manager_device_ops = {
246         DECLARE_NAME_LEN("power-control-plugin"),
247         .init              = power_state_manager_init,
248         .disable_auto_init = true, /* initialized by core power module */
249 };
250
251 DEVICE_OPS_REGISTER(&power_state_manager_device_ops)