8da70cb124dbe9899fc88f68ec06a73479212426
[platform/core/system/deviced.git] / src / power / power-event-lock.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2022 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 #include <glib.h>
20 #include <stdint.h>
21 #include <linux/input.h>
22 #include <libsyscommon/ini-parser.h>
23 #include <libsyscommon/bitmap.h>
24 #include <libsyscommon/file.h>
25
26 #include "shared/device-notifier.h"
27 #include "shared/log.h"
28 #include "power-event-lock.h"
29
30 #define BATTERY_CONF_FILE    "/etc/deviced/battery.conf"
31
32 /* eventlock is another wakelock than mainlock.
33  *
34  * The eventlock works independently of mainlock, which is controlled by
35  * power state. The main purpose of eventlock is to prevent the subroutine
36  * of an event from going to sleep regardless of the power state. */
37 #define EVENT_LOCK           "eventlock"
38
39 static struct syscommon_bitmap *eventlock;
40 static int notifier_id[EL_MAX][2];
41
42 void event_wake_lock(enum eventlock_type type)
43 {
44         int setcount;
45
46         if (type <= EL_MIN || type >= EL_MAX)
47                 return;
48
49         syscommon_bitmap_set_bit(eventlock, type);
50         setcount = syscommon_bitmap_count_set_bit(eventlock);
51
52         _I("Set eventlock of type=%d, current number of eventlock=%d", type, setcount);
53
54         if (setcount == 1) {
55                 sys_set_str("/sys/power/wake_lock", EVENT_LOCK);
56                 _I("Acquired eventlock");
57         }
58 }
59
60 void event_wake_unlock(enum eventlock_type type)
61 {
62         int setcount;
63
64         if (type <= EL_MIN || type >= EL_MAX)
65                 return;
66
67         syscommon_bitmap_clear_bit(eventlock, type);
68         setcount = syscommon_bitmap_count_set_bit(eventlock);
69
70         _I("Unset eventlock of type=%d, current number of eventlock=%d", type, setcount);
71
72         if (setcount == 0) {
73                 sys_set_str("/sys/power/wake_unlock", EVENT_LOCK);
74                 _I("Released eventlock");
75         }
76 }
77
78 static enum eventlock_type expand_key_eventlock_type(int keycode)
79 {
80         if (keycode == KEY_POWER)
81                 return EL_KEY_POWER;
82         if (keycode == KEY_BLUETOOTH)
83                 return EL_KEY_BLUETOOTH;
84         /* add mapping for keycode to eventlock_type here */
85
86         return EL_MAX;
87 }
88
89 static int power_event_lock_callback(void *data, void *udata)
90 {
91         enum eventlock_type type = (enum eventlock_type)(intptr_t) udata;
92
93         if (type == EL_KEY) {
94                 /* On receiving key event, expand EL_KEY to EL_KEY_* according to the keycode */
95                 int keycode = (int)(intptr_t) data;
96                 type = expand_key_eventlock_type(keycode);
97         }
98
99         event_wake_lock(type);
100
101         return 0;
102 }
103
104 static int power_event_unlock_callback(void *data, void *udata)
105 {
106         enum eventlock_type type = (enum eventlock_type)(intptr_t) udata;
107
108         if (type == EL_KEY) {
109                 /* On receiving key event, expand EL_KEY to EL_KEY_* according to the keycode */
110                 int keycode = (int)(intptr_t) data;
111                 type = expand_key_eventlock_type(keycode);
112         }
113
114         event_wake_unlock(type);
115
116         return 0;
117 }
118
119 static void register_power_event_lock_controller(enum eventlock_type type,
120         enum device_notifier_type lock_notify,
121         enum device_notifier_type unlock_notify)
122 {
123         /* Acquiring lock must be followed by all the other notifiers, therefore
124          * give a large enough number as priority to make it be at the head of notifier list.
125          * On the other hand, releasing lock must follow all the other notifiers, therefore
126          * give a small enough number as priority to make it be at the tail of notifier list. */
127         notifier_id[type][0] = syscommon_notifier_subscribe_notify_udata_priority(lock_notify,
128                 power_event_lock_callback, (void *)(intptr_t) type, NULL, 1000);
129         notifier_id[type][1] = syscommon_notifier_subscribe_notify_udata_priority(unlock_notify,
130                 power_event_unlock_callback, (void *)(intptr_t) type, NULL, -1000);
131 }
132
133 static int check_charger_wakelock(struct parse_result *result, void *user_data)
134 {
135         if (MATCH(result->section, "ChargerWakelock")
136                 && MATCH(result->name, "ChargerWakeLockEnabled")
137                 && MATCH(result->value, "yes"))
138                 *(int *) user_data = 1;
139
140         return 0;
141 }
142
143 void power_event_lock_init(void)
144 {
145         int charger_wakelock = 0;
146
147         eventlock = syscommon_bitmap_init_bitmap(EL_MAX);
148         if (!eventlock) {
149                 _E("Failed to init event lock bitmap");
150                 return;
151         }
152
153         config_parse(BATTERY_CONF_FILE, check_charger_wakelock, &charger_wakelock);
154
155         /* general events, mostly defined by configuration file */
156         register_power_event_lock_controller(EL_EVENT_ACTION,
157                 DEVICE_NOTIFIER_EVENT_ACQUIRE_WAKELOCK,
158                 DEVICE_NOTIFIER_EVENT_RELEASE_WAKELOCK);
159
160         /* key input event */
161         register_power_event_lock_controller(EL_KEY,
162                 DEVICE_NOTIFIER_KEY_PRESS,
163                 DEVICE_NOTIFIER_KEY_RELEASE);
164
165         /* charger event */
166         if (charger_wakelock) {
167                 register_power_event_lock_controller(EL_CHARGER,
168                         DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED,
169                         DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED);
170         }
171 }