0ff4fc9eac541cfc99e67a2bffeb0161f0ea44b9
[platform/hal/backend/artik/device-artik.git] / hw / battery / battery.c
1 /*
2  * device-node
3  *
4  * Copyright (c) 2016 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 <string.h>
23 #include <errno.h>
24 #include <linux/limits.h>
25 #include <dirent.h>
26
27 #include <hw/battery.h>
28 #include "../shared.h"
29 #include "../udev.h"
30
31 #define BATTERY_ROOT_PATH "/sys/class/power_supply"
32
33 static struct uevent_data {
34         BatteryUpdated updated_cb;
35         void *data;
36 } udata = { 0, };
37
38 static int get_power_source(char **src)
39 {
40         int ret, val;
41
42         if (!src)
43                 return -EINVAL;
44
45         ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_AC"/online", &val);
46         if (ret >= 0 && val > 0) {
47                 *src = POWER_SOURCE_AC;
48                 return 0;
49         }
50
51         ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_USB"/online", &val);
52         if (ret >= 0 && val > 0) {
53                 *src = POWER_SOURCE_USB;
54                 return 0;
55         }
56
57         ret = sys_get_int(BATTERY_ROOT_PATH"/"POWER_SOURCE_WIRELESS"/online", &val);
58         if (ret >= 0 && val > 0) {
59                 *src = POWER_SOURCE_WIRELESS;
60                 return 0;
61         }
62
63         *src = POWER_SOURCE_NONE;
64
65         return 0;
66 }
67
68 static void remove_not_string(char *str)
69 {
70         char *t = str;
71
72         while(*t != '\0') {
73                 if (*t == '\r' ||
74                         *t == '\n' ||
75                         *t == '\x0a')
76                         *t = '\0';
77                 else
78                         t++;
79         }
80 }
81
82 static void uevent_delivered(struct udev_device *dev)
83 {
84         struct battery_info info;
85         char *val;
86         int ret;
87
88         _I("POWER_SUPPLY uevent is delivered");
89
90         if (!udata.updated_cb) {
91                 _E("POWER_SUPPLY callback is NULL");
92                 return;
93         }
94
95         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_NAME");
96         if (!val)
97                 return;
98         info.name = val;
99
100         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_STATUS");
101         if (!val)
102                 return;
103         info.status = val;
104
105         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_HEALTH");
106         if (!val)
107                 return;
108         info.health = val;
109
110         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_ONLINE");
111         if (!val)
112                 return;
113         info.online = atoi(val);
114
115         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_PRESENT");
116         if (!val)
117                 return;
118         info.present = atoi(val);
119
120         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CAPACITY");
121         if (!val)
122                 return;
123         info.capacity = atoi(val);
124
125         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_NOW");
126         if (!val)
127                 return;
128         info.current_now = atoi(val); /* uA */
129
130         val = (char *)udev_device_get_property_value(dev, "POWER_SUPPLY_CURRENT_AVG");
131         if (!val)
132                 return;
133         info.current_average = atoi(val); /* uA */
134
135         ret = get_power_source(&val);
136         if (ret < 0)
137                 return;
138         info.power_source = val;
139
140         udata.updated_cb(&info, udata.data);
141 }
142
143 static struct uevent_handler uh = {
144         .subsystem = "power_supply",
145         .uevent_func = uevent_delivered,
146 };
147
148 static int battery_register_changed_event(
149                 BatteryUpdated updated_cb, void *data)
150 {
151         int ret;
152
153         ret = uevent_control_kernel_start();
154         if (ret < 0) {
155                 _E("Failed to register uevent handler (%d)", ret);
156                 return ret;
157         }
158
159         ret = register_kernel_event_control(&uh);
160         if (ret < 0)
161                 _E("Failed to register kernel event control (%d)", ret);
162
163         if (udata.updated_cb == NULL) {
164                 udata.updated_cb = updated_cb;
165                 udata.data = data;
166         } else
167                 _E("update callback is already registered");
168
169         return ret;
170 }
171
172 static void battery_unregister_changed_event(
173                 BatteryUpdated updated_cb)
174 {
175         unregister_kernel_event_control(&uh);
176         uevent_control_kernel_stop();
177         udata.updated_cb = NULL;
178         udata.data = NULL;
179 }
180
181 static int battery_get_current_state(
182                 BatteryUpdated updated_cb, void *data)
183 {
184         int ret, val;
185         struct battery_info info;
186         char *path;
187         char status[32];
188         char health[32];
189         char *power_source;
190
191         if (!updated_cb)
192                 return -EINVAL;
193
194         info.name = BATTERY_HARDWARE_DEVICE_ID;
195
196         path = BATTERY_ROOT_PATH"/battery/status";
197         ret = sys_get_str(path, status, sizeof(status));
198         if (ret < 0) {
199                 _E("Failed to get value of (%s, %d)", path, ret);
200                 return ret;
201         }
202         remove_not_string(status);
203         info.status = status;
204
205         path = BATTERY_ROOT_PATH"/battery/health";
206         ret = sys_get_str(path, health, sizeof(health));
207         if (ret < 0) {
208                 _E("Failed to get value of (%s, %d)", path, ret);
209                 return ret;
210         }
211         remove_not_string(health);
212         info.health = health;
213
214         ret = get_power_source(&power_source);
215         if (ret < 0) {
216                 _E("Failed to get power source (%d)", ret);
217                 return ret;
218         }
219         remove_not_string(power_source);
220         info.power_source = power_source;
221
222         path = BATTERY_ROOT_PATH"/battery/online";
223         ret = sys_get_int(path, &val);
224         if (ret < 0) {
225                 _E("Failed to get value of (%s, %d)", path, ret);
226                 return ret;
227         }
228         info.online = val;
229
230         path = BATTERY_ROOT_PATH"/battery/present";
231         ret = sys_get_int(path, &val);
232         if (ret < 0) {
233                 _E("Failed to get value of (%s, %d)", path, ret);
234                 return ret;
235         }
236         info.present = val;
237
238         path = BATTERY_ROOT_PATH"/battery/capacity";
239         ret = sys_get_int(path, &val);
240         if (ret < 0) {
241                 _E("Failed to get value of (%s, %d)", path, ret);
242                 return ret;
243         }
244         info.capacity = val;
245
246         path = BATTERY_ROOT_PATH"/battery/current_now";
247         ret = sys_get_int(path, &val);
248         if (ret < 0) {
249                 _E("Failed to get value of (%s, %d)", path, ret);
250                 return ret;
251         }
252         info.current_now = val;
253
254         path = BATTERY_ROOT_PATH"/battery/current_avg";
255         ret = sys_get_int(path, &val);
256         if (ret < 0) {
257                 _E("Failed to get value of (%s, %d)", path, ret);
258                 return ret;
259         }
260         info.current_average = val;
261
262         updated_cb(&info, data);
263
264         return 0;
265 }
266
267 static int battery_open(struct hw_info *info,
268                 const char *id, struct hw_common **common)
269 {
270         struct battery_device *battery_dev;
271
272         if (!info || !common)
273                 return -EINVAL;
274
275         battery_dev = calloc(1, sizeof(struct battery_device));
276         if (!battery_dev)
277                 return -ENOMEM;
278
279         battery_dev->common.info = info;
280         battery_dev->register_changed_event
281                 = battery_register_changed_event;
282         battery_dev->unregister_changed_event
283                 = battery_unregister_changed_event;
284         battery_dev->get_current_state
285                 = battery_get_current_state;
286
287         *common = (struct hw_common *)battery_dev;
288         return 0;
289 }
290
291 static int battery_close(struct hw_common *common)
292 {
293         if (!common)
294                 return -EINVAL;
295
296         free(common);
297         return 0;
298 }
299
300 HARDWARE_MODULE_STRUCTURE = {
301         .magic = HARDWARE_INFO_TAG,
302         .hal_version = HARDWARE_INFO_VERSION,
303         .device_version = BATTERY_HARDWARE_DEVICE_VERSION,
304         .id = BATTERY_HARDWARE_DEVICE_ID,
305         .name = "battery",
306         .open = battery_open,
307         .close = battery_close,
308 };