4 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <sys/types.h>
33 #include <libsyscommon/libgdbus.h>
34 #include <libsyscommon/ini-parser.h>
37 #include "shared/devices.h"
38 #include "shared/common.h"
39 #include "shared/device-notifier.h"
41 #include "display/display-dpms.h"
42 #include "display/display.h"
43 #include "power-boot.h"
44 #include "power-suspend.h"
46 #define POWER_CONF_FILE "/etc/deviced/power.conf"
48 static int mainlock_status = POWER_UNLOCK;
49 static int vital_service;
50 static bool vital_sleep;
51 static int vital_support = -2;
55 typedef struct _pm_history {
57 enum pm_log_type log_type;
61 static int max_history_count = MAX_LOG_COUNT;
62 static pm_history pm_history_log[MAX_LOG_COUNT] = {{0, }, };
63 static int history_count = 0;
65 static const char history_string[PM_LOG_MAX][15] = {
66 "PRESS", "LONG PRESS", "RELEASE", "LCD ON", "LCD ON COMPL", "LCD ON FAIL",
67 "LCD DIM", "LCD DIM FAIL", "LCD OFF", "LCD OFF COMPL", "LCD OFF FAIL",
70 bool timeout_sleep_support = false;
72 void pm_history_init()
74 memset(pm_history_log, 0x0, sizeof(pm_history_log));
76 max_history_count = MAX_LOG_COUNT;
79 void pm_history_save(enum pm_log_type log_type, int code)
84 pm_history_log[history_count].time = now;
85 pm_history_log[history_count].log_type = log_type;
86 pm_history_log[history_count].keycode = code;
89 if (history_count >= max_history_count)
93 void pm_history_print(int fd, int count)
95 int start_index, index, i;
100 if (count <= 0 || count > max_history_count)
103 start_index = (history_count - count + max_history_count)
106 for (i = 0; i < count; i++) {
107 index = (start_index + i) % max_history_count;
109 if (pm_history_log[index].time == 0)
112 if (pm_history_log[index].log_type >= PM_LOG_MAX)
114 ctime_r(&pm_history_log[index].time, time_buf);
115 time_buf[strlen(time_buf) - 1] = 0;
116 snprintf(buf, sizeof(buf), "[%3d] %15s %3d %s\n",
118 history_string[pm_history_log[index].log_type],
119 pm_history_log[index].keycode,
121 ret_val = write(fd, buf, strlen(buf));
123 _E("Write() failed: %d", errno);
128 bool vital_mode(void)
133 static int vital_mode_support(void)
135 if (vital_support < 0) {
138 fp = fopen(FREEZER_VITAL_WAKEUP_CGROUP, "r");
140 _E("%s open failed", FREEZER_VITAL_WAKEUP_CGROUP);
141 /* read max 2 times to check if this file exist */
148 return vital_support;
151 int suspend_other_process(int type)
155 if (vital_service == type)
158 if (type == VITAL_WAKEUP && vital_service > VITAL_SLEEP)
161 vital_service = type;
163 if (!vital_mode_support())
166 if (type == VITAL_SLEEP) {
167 gdbus_call_sync_with_reply_timeout(RESOURCED_BUS_NAME,
168 RESOURCED_PATH_FREEZER,
169 RESOURCED_INTERFACE_FREEZER,
171 g_variant_new("(s)", "sleep"),
173 SET_SUSPEND_TIME*1000);
175 } else if (type == VITAL_WAKEUP) {
176 ret = gdbus_call_async(RESOURCED_BUS_NAME,
177 RESOURCED_PATH_FREEZER,
178 RESOURCED_INTERFACE_FREEZER,
180 g_variant_new("(s)", "wakeup"));
181 } else if (type == VITAL_EXIT) {
182 ret = gdbus_call_async(RESOURCED_BUS_NAME,
183 RESOURCED_PATH_FREEZER,
184 RESOURCED_INTERFACE_FREEZER,
186 g_variant_new("(s)", "exit"));
192 int vital_state_changed(void *data)
199 if (type == VITAL_EXIT)
200 suspend_other_process(VITAL_EXIT);
209 _I("system suspend");
210 ret_val = sys_set_str(POWER_STATE_PATH, "mem");
211 _I("System resume: %d", ret_val);
215 int power_enable_autosleep(void)
217 _I("System autosleep enabled.");
218 return sys_set_str(POWER_AUTOSLEEP_PATH, "mem");
221 int power_disable_autosleep(void)
223 _I("System autosleep disabled.");
224 return sys_set_str(POWER_AUTOSLEEP_PATH, "off");
227 int power_acquire_wakelock(void)
229 if (mainlock_status == POWER_LOCK)
232 _I("system power lock");
233 suspend_other_process(VITAL_WAKEUP);
234 mainlock_status = POWER_LOCK;
236 return sys_set_str(POWER_LOCK_PATH, "mainlock");
239 int pm_get_power_lock(void)
241 return mainlock_status;
244 int pm_get_power_lock_support(void)
246 static int power_lock_support = -1;
249 if (power_lock_support >= 0)
252 ret_val = sys_check_node(POWER_LOCK_PATH);
254 power_lock_support = false;
256 power_lock_support = true;
258 _I("System power lock: %s",
259 (power_lock_support ? "support" : "not support"));
262 return power_lock_support;
265 int power_release_wakelock(void)
267 if (mainlock_status == POWER_UNLOCK)
270 _I("system power unlock");
271 suspend_other_process(VITAL_SLEEP);
272 mainlock_status = POWER_UNLOCK;
274 return sys_set_str(POWER_UNLOCK_PATH, "mainlock");
277 int check_wakeup_src(void)
280 * return wackeup source. user input or device interrupts? (EVENT_DEVICE or EVENT_INPUT)
285 int get_wakeup_count(int *cnt)
293 ret_val = sys_get_int(POWER_WAKEUP_PATH, &wakeup_count);
301 int set_wakeup_count(int cnt)
305 ret_val = sys_set_int(POWER_WAKEUP_PATH, cnt);
312 static int load_sleep_config(struct parse_result *result, void *user_data)
314 if (!MATCH(result->section, "PowerState"))
317 if (MATCH(result->name, "TimeoutSleepSupport") && MATCH(result->value, "yes")) {
318 timeout_sleep_support = true;
319 _D("timeout_sleep_support=%d", timeout_sleep_support);
325 void power_suspend_init(void)
329 retval = config_parse(POWER_CONF_FILE, load_sleep_config, NULL);
331 _E("Failed to load sleep config: %d", retval);