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