c5abfd1bf8420e47a8488c068c875858e0b9af84
[platform/core/system/deviced.git] / src / power / power-control.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <limits.h>
29 #include <math.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <dlfcn.h>
33 #include <libsyscommon/dbus-system.h>
34
35 #include "core/log.h"
36 #include "core/devices.h"
37 #include "core/common.h"
38 #include "core/device-notifier.h"
39 #include "vconf.h"
40 #include "display/display-dpms.h"
41 #include "display/display.h"
42 #include "power/boot.h"
43 #include "power-control.h"
44
45 static int mainlock_status = POWER_UNLOCK;
46 static int vital_service;
47 static bool vital_sleep;
48 static int vital_support = -2;
49
50 #ifdef ENABLE_PM_LOG
51
52 typedef struct _pm_history {
53         time_t time;
54         enum pm_log_type log_type;
55         int keycode;
56 } pm_history;
57
58 static int max_history_count = MAX_LOG_COUNT;
59 static pm_history pm_history_log[MAX_LOG_COUNT] = {{0, }, };
60 static int history_count = 0;
61
62 static const char history_string[PM_LOG_MAX][15] = {
63         "PRESS", "LONG PRESS", "RELEASE", "LCD ON", "LCD ON COMPL", "LCD ON FAIL",
64         "LCD DIM", "LCD DIM FAIL", "LCD OFF", "LCD OFF COMPL", "LCD OFF FAIL",
65         "LCD FAIL", "SLEEP"};
66
67 void pm_history_init()
68 {
69         memset(pm_history_log, 0x0, sizeof(pm_history_log));
70         history_count = 0;
71         max_history_count = MAX_LOG_COUNT;
72 }
73
74 void pm_history_save(enum pm_log_type log_type, int code)
75 {
76         time_t now;
77
78         time(&now);
79         pm_history_log[history_count].time = now;
80         pm_history_log[history_count].log_type = log_type;
81         pm_history_log[history_count].keycode = code;
82         history_count++;
83
84         if (history_count >= max_history_count)
85                 history_count = 0;
86 }
87
88 void pm_history_print(int fd, int count)
89 {
90         int start_index, index, i;
91         int ret;
92         char buf[255];
93         char time_buf[30];
94
95         if (count <= 0 || count > max_history_count)
96                 return;
97
98         start_index = (history_count - count + max_history_count)
99                     % max_history_count;
100
101         for (i = 0; i < count; i++) {
102                 index = (start_index + i) % max_history_count;
103
104                 if (pm_history_log[index].time == 0)
105                         continue;
106
107                 if (pm_history_log[index].log_type >= PM_LOG_MAX)
108                         continue;
109                 ctime_r(&pm_history_log[index].time, time_buf);
110                 time_buf[strlen(time_buf) - 1] = 0;
111                 snprintf(buf, sizeof(buf), "[%3d] %15s %3d %s\n",
112                         index,
113                         history_string[pm_history_log[index].log_type],
114                         pm_history_log[index].keycode,
115                         time_buf);
116                 ret = write(fd, buf, strlen(buf));
117                 if (ret < 0)
118                         _E("Write() failed: %d", errno);
119         }
120 }
121 #endif
122
123 bool vital_mode(void)
124 {
125         return vital_sleep;
126 }
127
128 static int vital_mode_support(void)
129 {
130         if (vital_support < 0) {
131                 FILE *fp;
132
133                 fp = fopen(FREEZER_VITAL_WAKEUP_CGROUP, "r");
134                 if (fp == NULL) {
135                         _E("%s open failed", FREEZER_VITAL_WAKEUP_CGROUP);
136                         /* read max 2 times to check if this file exist */
137                         vital_support++;
138                         return 0;
139                 }
140                 vital_support = 1;
141                 fclose(fp);
142         }
143         return vital_support;
144 }
145
146 int suspend_other_process(int type)
147 {
148         int ret = 0;
149
150         if (vital_service == type)
151                 return ret;
152
153         if (type == VITAL_WAKEUP && vital_service > VITAL_SLEEP)
154                 return ret;
155
156         vital_service = type;
157
158         if (!vital_mode_support())
159                 return ret;
160
161         if (type == VITAL_SLEEP) {
162                 dbus_handle_method_sync_with_reply_var_timeout(RESOURCED_BUS_NAME,
163                                                 RESOURCED_PATH_FREEZER,
164                                                 RESOURCED_INTERFACE_FREEZER,
165                                                 "SetSuspend",
166                                                 g_variant_new("(s)", "sleep"),
167                                                 NULL,
168                                                 SET_SUSPEND_TIME*1000);
169                 vital_sleep = true;
170         } else if (type == VITAL_WAKEUP) {
171                 ret = dbus_handle_method_async_var(RESOURCED_BUS_NAME,
172                                                 RESOURCED_PATH_FREEZER,
173                                                 RESOURCED_INTERFACE_FREEZER,
174                                                 "SetSuspend",
175                                                 g_variant_new("(s)", "wakeup"));
176         } else if (type == VITAL_EXIT) {
177                 ret = dbus_handle_method_async_var(RESOURCED_BUS_NAME,
178                                                 RESOURCED_PATH_FREEZER,
179                                                 RESOURCED_INTERFACE_FREEZER,
180                                                 "SetSuspend",
181                                                 g_variant_new("(s)", "exit"));
182                 vital_sleep = false;
183         }
184         return ret;
185 }
186
187 int vital_state_changed(void *data)
188 {
189         int type;
190
191         assert(data);
192
193         type = *(int *)data;
194         if (type == VITAL_EXIT)
195                 suspend_other_process(VITAL_EXIT);
196
197         return 0;
198 }
199
200 int pm_suspend(void)
201 {
202         int ret;
203
204         _I("system suspend");
205         ret = sys_set_str(POWER_STATE_PATH, "mem");
206         _I("System resume: %d", ret);
207         return 0;
208 }
209
210 int pm_enable_autosleep(void)
211 {
212         _I("System autosleep enabled.");
213         return sys_set_str(POWER_AUTOSLEEP_PATH, "mem");
214 }
215
216 int pm_power_lock(void)
217 {
218         _I("system power lock");
219         suspend_other_process(VITAL_WAKEUP);
220         mainlock_status = POWER_LOCK;
221
222         return sys_set_str(POWER_LOCK_PATH, "mainlock");
223 }
224
225 int pm_get_power_lock(void)
226 {
227         return mainlock_status;
228 }
229
230 int pm_get_power_lock_support(void)
231 {
232         static int power_lock_support = -1;
233         int ret;
234
235         if (power_lock_support >= 0)
236                 goto out;
237
238         ret = sys_check_node(POWER_LOCK_PATH);
239         if (ret < 0)
240                 power_lock_support = false;
241         else
242                 power_lock_support = true;
243
244         _I("System power lock: %s",
245                         (power_lock_support ? "support" : "not support"));
246
247 out:
248         return power_lock_support;
249 }
250
251 int pm_power_unlock(void)
252 {
253         _I("system power unlock");
254         suspend_other_process(VITAL_SLEEP);
255         mainlock_status = POWER_UNLOCK;
256
257         return sys_set_str(POWER_UNLOCK_PATH, "mainlock");
258 }
259
260 int check_wakeup_src(void)
261 {
262         /*  TODO if nedded.
263          * return wackeup source. user input or device interrupts? (EVENT_DEVICE or EVENT_INPUT)
264          */
265         return EVENT_DEVICE;
266 }
267
268 int get_wakeup_count(int *cnt)
269 {
270         int ret;
271         int wakeup_count;
272
273         if (!cnt)
274                 return -EINVAL;
275
276         ret = sys_get_int(POWER_WAKEUP_PATH, &wakeup_count);
277         if (ret < 0)
278                 return ret;
279
280         *cnt = wakeup_count;
281         return 0;
282 }
283
284 int set_wakeup_count(int cnt)
285 {
286         int ret;
287
288         ret = sys_set_int(POWER_WAKEUP_PATH, cnt);
289         if (ret < 0)
290                 return ret;
291
292         return 0;
293 }