197fabe9ad62146c567ca16d614b7b7860818593
[platform/core/system/deviced.git] / src / battery / power-supply.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 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 <stdbool.h>
22 #include <vconf.h>
23 #include <bundle.h>
24 #include <eventsystem.h>
25 #include <hal/device/hal-battery.h>
26 #include <sys/stat.h>
27 #include <libsyscommon/ini-parser.h>
28
29 #include "shared/devices.h"
30 #include "shared/device-notifier.h"
31 #include "core/udev.h"
32 #include "core/log.h"
33 #include "display/poll.h"
34 #include "display/setting.h"
35 #include "shared/eventsystem.h"
36 #include "shared/plugin.h"
37 #include "shared/apps.h"
38 #include "display/core.h"
39 #include "display/display-ops.h"
40 #include "power-supply.h"
41 #include "battery.h"
42 #include "battery-ops.h"
43 #include "extcon/extcon.h"
44 #include "lowbat-handler.h"
45
46 #ifndef VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL
47 #define VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL "db/setting/blockmode_wearable"
48 #endif
49
50 #ifndef VCONFKEY_SETAPPL_THEATER_MODE_ENABLE
51 #define VCONFKEY_SETAPPL_THEATER_MODE_ENABLE "db/setting/theater_mode_enable"
52 #endif
53
54 #ifndef VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE
55 #define VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE "db/setting/goodnight_mode_enable"
56 #endif
57
58 #define BATTERY_NAME        "battery"
59 #define CHARGEFULL_NAME     "Full"
60 #define CHARGENOW_NAME      "Charging"
61 #define DISCHARGE_NAME      "Discharging"
62 #define NOTCHARGE_NAME      "Not charging"
63 #define OVERHEAT_NAME       "Overheat"
64 #define TEMPCOLD_NAME       "Cold"
65 #define OVERVOLT_NAME       "Over voltage"
66 #define GOOD_NAME           "Good"
67
68 #define CHARGER_WIRELESS_TYPE_BT    10
69 #define CHARGER_WIRELESS_TYPE_3G    22
70 #define CHARGER_INCOMPATIBLE_TYPE   11
71 #define CHARGER_D2D_TYPE            110
72 #define WIRELESS_CHARGER_CONNECTED  2
73
74 #define SIGNAL_TEMP_GOOD          "TempGood"
75
76 #define METHOD_FULL_NOTI_ON   "BatteryFullNotiOn"
77 #define METHOD_FULL_NOTI_OFF  "BatteryFullNotiOff"
78 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
79
80 #define CHARGER_CHARGE_ON_NODE "/sys/class/power_supply/battery/chg_on"
81
82 #define RETRY_MAX 5
83 #define BATTERY_CHECK_TIMER_INTERVAL 500  /* 0.5 second */
84 #define LCD_DIM_TIME_IN_BATTERY_HEALTH  10000   /* ms */
85
86 static struct display_plugin *disp_plgn;
87 static struct battery_plugin *battery_plgn;
88
89 static struct battery_status battery;
90 struct battery_status old_battery;
91 static int noti_id;
92 static int abnormal_health_popup_timer;
93 static bool launching_health_popup;
94
95 static guint power_timer;
96 static device_notifier_state_e old_state = -1;
97
98 bool battery_initialized;
99
100 bool battery_do_not_disturb(void);
101 int battery_pm_change_internal(int pid, int s_bits);
102 static int delayed_init_done(void *data);
103 static void update_health(enum battery_noti_status status);
104 static int load_uevent(struct parse_result *result, void *user_data);
105 static int event_handler_state_changed(void *data);
106 static void power_supply_exit(void *data);
107
108 inline struct battery_status *get_var_battery_status(void)
109 {
110         return &battery;
111 }
112
113 static int lowbat_execute(void *data)
114 {
115         static const struct device_ops *lowbat_ops;
116
117         FIND_DEVICE_INT(lowbat_ops, "lowbat");
118         return device_execute(lowbat_ops, data);
119 }
120
121 static int power_supply_broadcast_str(char *sig, char *status)
122 {
123         static char old_sig[32];
124         static char old_status[32];
125         char *str;
126         int ret;
127
128         if (!sig || !status) {
129                 _E("there is no signal name");
130                 return -EINVAL;
131         }
132
133         if (strncmp(old_sig, sig, strlen(sig)) == 0 && strncmp(old_status, status, strlen(status)) == 0)
134                 return 0;
135
136         snprintf(old_sig, sizeof(old_sig), "%s", sig);
137         snprintf(old_status, sizeof(old_status), "%s", status);
138
139         str = status;
140
141         ret = gdbus_signal_emit(NULL,
142                                                 DEVICED_PATH_BATTERY,
143                                                 DEVICED_INTERFACE_BATTERY,
144                                                 sig,
145                                                 g_variant_new("(s)", str));
146
147         if (ret == 0)
148                 return 1;
149         else
150                 return ret;
151 }
152
153 static void pm_check_and_change(int bInserted)
154 {
155         static int old = -1;
156
157         if (old == bInserted)
158                 return;
159         old = bInserted;
160         battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
161 }
162
163 static void health_status_broadcast(void)
164 {
165         gdbus_signal_emit(NULL,
166                 DEVICED_PATH_BATTERY,
167                 DEVICED_INTERFACE_BATTERY,
168                 SIGNAL_TEMP_GOOD,
169                 NULL);
170 }
171
172 static void full_noti_cb(GVariant *var, void *user_data, GError *err)
173 {
174         int id = 0;
175
176         if (!var)
177                 return;
178
179         if (!g_variant_get_safe(var, "(i)", &id)) {
180                 _E("Failed to notify full: no message(%s)", g_variant_get_type_string(var));
181                 goto out;
182         }
183
184         noti_id = id;
185         _D("Inserted battery full noti(%d).", noti_id);
186
187 out:
188         g_variant_unref(var);
189 }
190
191 static void noti_off_cb(GVariant *var, void *user_data, GError *err)
192 {
193         int val = 0;
194
195         if (!g_variant_get_safe(var, "(i)", &val)) {
196                 _E("Failed to off notification: no message(%s)", g_variant_get_type_string(var));
197                 goto out;
198         }
199
200         _D("Noti off: %d", val);
201
202 out:
203         g_variant_unref(var);
204 }
205
206 static int send_full_noti(enum charge_full_type state)
207 {
208         int ret = 0;
209         int noti = 0;
210         int retry;
211
212         if (battery_plgn->check_power_supply_noti)
213                 noti = battery_plgn->check_power_supply_noti();
214
215         if (!noti)
216                 return ret;
217
218         switch (state) {
219         case CHARGING_FULL:
220                 for (retry = RETRY_MAX; retry > 0; retry--) {
221                         ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
222                                         POPUP_PATH_NOTI,
223                                         POPUP_INTERFACE_NOTI,
224                                         METHOD_FULL_NOTI_ON,
225                                         NULL, full_noti_cb, -1, NULL);
226                         if (ret == 0) {
227                                 _D("Created battery full noti.");
228                                 return ret;
229                         }
230                 }
231                 _E("Failed to call dbus method: %d", ret);
232                 break;
233         case CHARGING_NOT_FULL:
234                 if (noti_id <= 0)
235                         return -EPERM;
236                 for (retry = RETRY_MAX; retry > 0; retry--) {
237                         ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
238                                         POPUP_PATH_NOTI,
239                                         POPUP_INTERFACE_NOTI,
240                                         METHOD_FULL_NOTI_OFF,
241                                         g_variant_new("(i)", noti_id),
242                                         noti_off_cb, -1, NULL);
243                         if (ret == 0) {
244                                 _D("Deleted battery full noti.");
245                                 noti_id = 0;
246                                 return ret;
247                         }
248                 }
249                 _E("Failed to call dbus method: %d", ret);
250                 break;
251         }
252         return ret;
253 }
254
255 static void charge_noti_on(GVariant *var, void *user_data, GError *err)
256 {
257         int id = 0;
258
259         if (!var)
260                 return;
261
262         if (!g_variant_get_safe(var, "(i)", &id)) {
263                 _E("Failed to notify charge: no message(%s)", g_variant_get_type_string(var));
264                 goto out;
265         }
266
267         _D("Inserted battery charge noti: %d", id);
268
269 out:
270         g_variant_unref(var);
271 }
272
273 static int send_charge_noti(void)
274 {
275         int ret = 0;
276         int retry;
277
278         for (retry = RETRY_MAX; retry > 0; retry--) {
279                 ret = gdbus_call_async_with_reply(POPUP_BUS_NAME,
280                                 POPUP_PATH_NOTI,
281                                 POPUP_INTERFACE_NOTI,
282                                 METHOD_CHARGE_NOTI_ON,
283                                 NULL, charge_noti_on, -1, NULL);
284                 if (ret == 0) {
285                         _I("Created battery charge noti.");
286                         return ret;
287                 }
288         }
289         _E("Failed to call dbus method: %d", ret);
290         return ret;
291 }
292
293 static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
294 {
295         static int charger = CHARGER_DISCHARGING;
296         static int full = CHARGING_NOT_FULL;
297         int ret_val;
298
299         if (type == DEVICE_NOTI_BATT_CHARGE) {
300                 if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
301                         send_charge_noti();
302                         charger = CHARGER_CHARGING;
303                 } else if (status == DEVICE_NOTI_OFF && charger == CHARGER_CHARGING)
304                         charger = CHARGER_DISCHARGING;
305         } else if (type == DEVICE_NOTI_BATT_FULL) {
306                 if (status == DEVICE_NOTI_ON && full == CHARGING_NOT_FULL) {
307                         ret_val = send_full_noti(CHARGING_FULL);
308                         if (ret_val == 0)
309                                 full = CHARGING_FULL;
310                 } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
311                         ret_val = send_full_noti(CHARGING_NOT_FULL);
312                         if (ret_val == 0)
313                                 full = CHARGING_NOT_FULL;
314                 }
315         }
316 }
317
318 int power_supply_broadcast(char *sig, int status)
319 {
320         static int old;
321         static char sig_old[32];
322         int ret;
323
324         if (!sig) {
325                 _E("There is no signal name.");
326                 return -EINVAL;
327         }
328         if (strncmp(sig_old, sig, strlen(sig)) == 0 && old == status) {
329                 _D("Skip broadcasting same signal(%s) and status(%d).", sig, status);
330                 return 0;
331         }
332
333         old = status;
334
335         snprintf(sig_old, sizeof(sig_old), "%s", sig);
336
337         ret = gdbus_signal_emit(NULL,
338                                                 DEVICED_PATH_BATTERY,
339                                                 DEVICED_INTERFACE_BATTERY,
340                                                 sig,
341                                                 g_variant_new("(i)", status));
342         if (ret == 0)
343                 return 1;
344         else
345                 return ret;
346 }
347
348 static void noti_batt_full(void)
349 {
350         static int bat_full_noti;
351
352         if (!battery.charge_full && bat_full_noti == 1) {
353                 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
354                 bat_full_noti = 0;
355                 /* off the full charge state */
356                 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
357         }
358         if (battery.charge_full && bat_full_noti == 0) {
359                 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
360                 bat_full_noti = 1;
361                 /* turn on LCD, if battery is fully charged */
362                 if (battery_plgn->check_power_supply_noti && battery_plgn->check_power_supply_noti()) {
363                         battery_pm_change_internal(INTERNAL_LOCK_BATTERY_FULL, LCD_NORMAL);
364                 } else
365                         _I("Block LCD.");
366
367                 /* on the full charge state */
368                 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
369         }
370 }
371
372 static void check_power_supply(int state)
373 {
374         pm_check_and_change(state);
375         if (disp_plgn->update_pm_setting)
376                 disp_plgn->update_pm_setting(SETTING_CHARGING, state);
377 }
378
379 static void charger_state_send_system_event(int state)
380 {
381         const char *str;
382
383         switch (state) {
384         case CHARGING_STATUS_CHARGING:
385                 str = EVT_VAL_BATTERY_CHARGER_CHARGING;
386                 break;
387         case CHARGING_STATUS_FULL:
388                 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
389                 CRITICAL_LOG("Battery charger: %s", str);
390                 break;
391         case CHARGING_STATUS_DISCHARGING:
392                 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
393                 CRITICAL_LOG("Battery charger: %s", str);
394                 break;
395         default:
396                 _E("Invalid parameter: %d", state);
397                 return;
398         }
399
400         event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str);
401 }
402
403 static void update_present(enum battery_noti_status status)
404 {
405
406         CRITICAL_LOG("Charge(%d) present(%d, old: %d)", battery.charge_now, battery.present, old_battery.present);
407
408         old_battery.present = battery.present;
409         if (status == DEVICE_NOTI_ON) {
410                 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
411                 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
412                 if (disp_plgn->pm_lock_internal)
413                         disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
414         } else {
415                 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
416                 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
417                 if (disp_plgn->pm_unlock_internal)
418                         disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
419         }
420         if (battery_plgn->changed_battery_cf)
421                 battery_plgn->changed_battery_cf(battery.present);
422 }
423
424 static void launch_health_popup(void)
425 {
426         if (launching_health_popup)
427                 return;
428
429         launching_health_popup = true;
430
431         device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
432         battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
433         battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
434         if (disp_plgn->pm_unlock_internal)
435                 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
436         if (disp_plgn->pm_lock_internal)
437                 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
438         if (battery.health == HEALTH_LOW)
439                 battery_charge_err_low_act(NULL);
440         else if (battery.health == HEALTH_HIGH)
441                 battery_charge_err_high_act(NULL);
442
443         launching_health_popup = false;
444 }
445
446 /* Warning popup for every 1 minutes until
447  * battery health returns to normal. */
448 static gboolean health_popup_cb(void *data)
449 {
450         launch_health_popup();
451         battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
452         return G_SOURCE_CONTINUE;
453 }
454
455 static void update_health(enum battery_noti_status status)
456 {
457         _I("Charge(%d) health(%d, old: %d)", battery.charge_now, battery.health, old_battery.health);
458
459         old_battery.health = battery.health;
460         if (status == DEVICE_NOTI_ON) {
461                 CRITICAL_LOG("Popup: Battery health status is not good, %s.", battery.health_s);
462                 launch_health_popup();
463                 if (!abnormal_health_popup_timer)
464                         abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
465         } else {
466                 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
467                 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
468                 if (disp_plgn->pm_unlock_internal) {
469                         disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
470                         disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
471                 }
472                 health_status_broadcast();
473                 if (abnormal_health_popup_timer) {
474                         CRITICAL_LOG("Battery health returned to normal. Stop abnormal popup.");
475                         g_source_remove(abnormal_health_popup_timer);
476                         abnormal_health_popup_timer = 0;
477                 }
478                 if (battery_plgn->remove_health_popup)
479                         battery_plgn->remove_health_popup();
480         }
481 }
482
483 void relaunch_health_popup(void)
484 {
485         if (launching_health_popup)
486                 return;
487
488         launching_health_popup = true;
489
490         if (abnormal_health_popup_timer)
491                 g_source_remove(abnormal_health_popup_timer);
492
493         if (disp_plgn->pm_unlock_internal)
494                 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
495         if (disp_plgn->pm_lock_internal)
496                 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
497         if (battery.health == HEALTH_LOW)
498                 battery_charge_err_low_act(NULL);
499         else if (battery.health == HEALTH_HIGH)
500                 battery_charge_err_high_act(NULL);
501
502         abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
503
504         launching_health_popup = false;
505 }
506
507 static void check_abnormal_status(void)
508 {
509         if (old_battery.health != HEALTH_LOW && old_battery.health != HEALTH_HIGH &&
510             (battery.health == HEALTH_LOW || battery.health == HEALTH_HIGH))
511                 update_health(DEVICE_NOTI_ON);
512         else if ((old_battery.health == HEALTH_LOW || old_battery.health == HEALTH_HIGH) &&
513                 battery.health != HEALTH_LOW && battery.health != HEALTH_HIGH)
514                 update_health(DEVICE_NOTI_OFF);
515
516         if (old_battery.present != PRESENT_ABNORMAL && battery.present == PRESENT_ABNORMAL)
517                 update_present(DEVICE_NOTI_ON);
518         else if (battery.present != PRESENT_ABNORMAL && old_battery.present == PRESENT_ABNORMAL)
519                 update_present(DEVICE_NOTI_OFF);
520
521         if (old_battery.health != HEALTH_OVP && battery.health == HEALTH_OVP) {
522                 if (battery_plgn->update_ovp)
523                         battery_plgn->update_ovp(DEVICE_NOTI_ON);
524         } else if (battery.health != HEALTH_OVP && old_battery.health == HEALTH_OVP) {
525                 if (battery_plgn->update_ovp)
526                         battery_plgn->update_ovp(DEVICE_NOTI_OFF);
527         }
528 }
529
530 static void check_charging_status(const char *env_value)
531 {
532         int len;
533
534         if (env_value == NULL)
535                 return;
536
537         len = strlen(env_value);
538         if (strncmp(env_value, CHARGEFULL_NAME, len) == 0)
539                 battery.charging_status = CHARGING_STATUS_FULL;
540         else if (strncmp(env_value, CHARGENOW_NAME, len) == 0)
541                 battery.charging_status = CHARGING_STATUS_CHARGING;
542         else if (strncmp(env_value, DISCHARGE_NAME, len) == 0)
543                 battery.charging_status = CHARGING_STATUS_DISCHARGING;
544         else if (strncmp(env_value, NOTCHARGE_NAME, len) == 0)
545                 battery.charging_status = CHARGING_STATUS_NOT_CHARGING;
546         else
547                 battery.charging_status = CHARGING_STATUS_UNKNOWN;
548
549         if (battery.charging_status == CHARGING_STATUS_FULL) {
550                 battery.charge_full = CHARGING_FULL;
551                 battery.charge_now = CHARGER_DISCHARGING;
552         } else if (battery.charging_status == CHARGING_STATUS_CHARGING) {
553                 battery.charge_full = CHARGING_NOT_FULL;
554                 battery.charge_now = CHARGER_CHARGING;
555         } else if (battery.charging_status == CHARGING_STATUS_DISCHARGING) {
556                 battery.charge_full = CHARGING_NOT_FULL;
557                 battery.charge_now = CHARGER_DISCHARGING;
558         } else if (battery.charging_status == CHARGING_STATUS_NOT_CHARGING) {
559                 battery.charge_full = CHARGING_NOT_FULL;
560                 battery.charge_now = CHARGER_ABNORMAL;
561         } else {
562                 battery.charge_full = CHARGING_NOT_FULL;
563                 battery.charge_now = CHARGER_DISCHARGING;
564         }
565 }
566
567 static void check_health_status(const char *env_value)
568 {
569         int len;
570
571         if (env_value == NULL) {
572                 battery.health = HEALTH_GOOD;
573                 return;
574         }
575
576         snprintf(battery.health_s, sizeof(battery.health_s), "%s", env_value);
577
578         len = strlen(env_value);
579         if (strncmp(env_value, OVERHEAT_NAME, len) == 0)
580                 battery.health = HEALTH_HIGH;
581         else if (strncmp(env_value, TEMPCOLD_NAME, len) == 0)
582                 battery.health = HEALTH_LOW;
583         else if (strncmp(env_value, OVERVOLT_NAME, len) == 0)
584                 battery.health = HEALTH_OVP;
585         else if (strncmp(env_value, GOOD_NAME, len) == 0)
586                 battery.health = HEALTH_GOOD;
587         else
588                 battery.health = HEALTH_NO_OPT;
589 }
590
591 static void check_power_source(const char *env_value)
592 {
593         int maxlen = sizeof(battery.power_source_s);
594
595         if (!env_value)
596                 return;
597
598         snprintf(battery.power_source_s, maxlen, "%s", env_value);
599         battery.power_source_s[maxlen - 1] = '\0';
600
601         if (strncmp(battery.power_source_s, "ac", sizeof("ac")) == 0) {
602                 battery.online_type = CHARGER_TYPE_AC;
603         } else if (strncmp(battery.power_source_s, "usb", sizeof("usb")) == 0) {
604                 battery.online_type = CHARGER_TYPE_USB;
605         } else if (strncmp(battery.power_source_s, "wireless", sizeof("wireless")) == 0) {
606                 battery.online_type = CHARGER_TYPE_WIRELESS;
607         } else {
608                 battery.online_type = CHARGER_TYPE_NONE;
609         }
610 }
611
612 static void check_misc_status(const char *env_value)
613 {
614         if (env_value == NULL) {
615                 battery.misc = MISC_NONE;
616                 return;
617         }
618         battery.misc = atoi(env_value);
619 }
620
621 static void process_power_supply(void *data)
622 {
623         bool broadcasted = true;
624         int ret_lock = -1;
625         int ret_val;
626
627         if (disp_plgn->pm_lock_internal)
628                 ret_lock = disp_plgn->pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
629
630         if (old_battery.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
631                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
632                 if (ret_val < 0)
633                         _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
634
635                 if (power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now) < 0)
636                         broadcasted = false;
637         }
638
639         if (!strcmp(old_battery.status_s, CHARGEFULL_NAME) &&
640                 !strcmp(battery.status_s, CHARGENOW_NAME)) {
641                 battery_pm_change_internal(INTERNAL_LOCK_BATTERY, LCD_NORMAL);
642         }
643
644         if (old_battery.charge_full != battery.charge_full)
645                 if (power_supply_broadcast(CHARGE_FULL_SIGNAL, battery.charge_full) < 0)
646                         broadcasted = false;
647
648         if (strncmp(old_battery.health_s, battery.health_s, strlen(battery.health_s))) {
649                 snprintf(old_battery.health_s, sizeof(old_battery.health_s), "%s", battery.health_s);
650                 if (power_supply_broadcast_str(CHARGE_HEALTH_SIGNAL, battery.health_s) < 0)
651                         broadcasted = false;
652         }
653
654         if (old_battery.capacity != battery.capacity) {
655                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
656                 if (ret_val < 0)
657                         _E("Failed to set vconf value for battery capacity: %d", vconf_get_ext_errno());
658
659                 if (power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity) < 0)
660                         broadcasted = false;
661         }
662
663         (void)lowbat_execute(data);
664
665         if (old_battery.charger_connected != battery.charger_connected) {
666                 check_power_supply(battery.charger_connected);
667                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, battery.charger_connected);
668                 if (ret_val < 0)
669                         _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
670                 if (battery.charger_connected == 0) {
671                         CRITICAL_LOG("Battery charger disconnected");
672                         event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, EVT_VAL_BATTERY_CHARGER_CONNECTED);
673                         device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, NULL);
674                 } else if (battery.charger_connected == 1) {
675                         CRITICAL_LOG("Battery charger connected");
676                         event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, EVT_VAL_BATTERY_CHARGER_DISCONNECTED);
677                         device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, NULL);
678                 } else {
679                         _E("Invalid charger connected");
680                 }
681         }
682
683         if (old_battery.charging_status != battery.charging_status)
684                 charger_state_send_system_event(battery.charging_status);
685
686         if (old_battery.online_type != battery.online_type) {
687                 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_TYPE, battery.online_type);
688                 if (ret_val < 0)
689                         _E("Failed to set vconf value for charger type: %d", vconf_get_ext_errno());
690
691                 if (power_supply_broadcast(CHARGER_TYPE_SIGNAL, battery.online_type) < 0)
692                 broadcasted = false;
693         }
694
695         if (old_battery.misc != battery.misc)
696                 if (power_supply_broadcast(CHARGE_MISC_EVENT_SIGNAL, battery.misc) < 0)
697                         broadcasted = false;
698
699         if (old_battery.charge_full != battery.charge_full)
700                 noti_batt_full();
701
702         if (old_battery.charge_now != battery.charge_now ||
703             old_battery.charge_full != battery.charge_full ||
704             old_battery.capacity != battery.capacity ||
705             old_battery.health != battery.health ||
706                 old_battery.misc != battery.misc ||
707                 old_battery.online_type != battery.online_type)
708                 _I("Signal(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
709                         broadcasted,
710                         CHARGER_STATUS_SIGNAL, battery.charger_connected,
711                         CHARGER_TYPE_SIGNAL, battery.online_type,
712                         CHARGE_NOW_SIGNAL, battery.charge_now,
713                         CHARGE_FULL_SIGNAL, battery.charge_full,
714                         CHARGE_CAPACITY_SIGNAL, battery.capacity,
715                         CHARGE_LEVEL_SIGNAL, battery.capacity_level,
716                         CHARGE_MISC_EVENT_SIGNAL, battery.misc,
717                         CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
718
719         old_battery.capacity = battery.capacity;
720         old_battery.capacity_level = battery.capacity_level;
721         old_battery.charger_connected = battery.charger_connected;
722         old_battery.online_type = battery.online_type;
723         old_battery.charging_status = battery.charging_status;
724         old_battery.charge_full = battery.charge_full;
725
726         old_battery.misc = battery.misc;
727         snprintf(old_battery.status_s, sizeof(old_battery.status_s), "%s", battery.status_s);
728
729         check_abnormal_status();
730
731         device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
732         if (old_battery.charge_now != battery.charge_now) {
733                 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, &battery.charge_now);
734                 old_battery.charge_now = battery.charge_now;
735         }
736
737         if (disp_plgn->pm_unlock_internal) {
738                 if (ret_lock == 0) {
739                         disp_plgn->pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
740                 }
741         }
742 }
743
744 static int battery_state(struct battery_info *info)
745 {
746         static struct battery_status prev_status;
747
748         if (!info) {
749                 memcpy(&prev_status, &battery, sizeof(battery));
750                 return 0;
751         }
752
753         if (battery.capacity != 0 && prev_status.capacity == battery.capacity &&
754                 prev_status.charging_status == battery.charging_status &&
755                 prev_status.online_type == battery.online_type &&
756                 prev_status.charge_full == battery.charge_full &&
757                 prev_status.charge_now == battery.charge_now &&
758                 prev_status.health == battery.health &&
759                 prev_status.present == battery.present &&
760                 prev_status.current_now == battery.current_now &&
761                 prev_status.current_average == battery.current_average &&
762                 prev_status.charger_connected == battery.charger_connected)
763                 return 0;
764
765         prev_status.capacity = battery.capacity;
766         prev_status.charging_status = battery.charging_status;
767         prev_status.charge_full = battery.charge_full;
768         prev_status.charge_now = battery.charge_now;
769         prev_status.health = battery.health;
770         prev_status.present = battery.present;
771         prev_status.charger_connected = battery.charger_connected;
772
773         _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%d) Pres(%d) Curr(%d,%d)",
774                         info->status,
775                         battery.charge_now == CHARGER_CHARGING ? "Charging"
776                                 : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
777                         info->power_source,
778                         info->online,
779                         info->capacity,
780                         info->health,
781                         battery.health,
782                         info->present,
783                         info->current_now,
784                         info->current_average);
785         return 1;
786 }
787
788 static void battery_disable_module(int value)
789 {
790         int retval;
791         static const struct invalidate_list {
792                 const char *vconfkey;
793                 int *member;
794         } list[] = {
795                 { VCONFKEY_SYSMAN_BATTERY_CAPACITY, &old_battery.capacity },
796                 { VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &old_battery.capacity_level },
797                 { VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, &old_battery.charge_now },
798                 { VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, NULL },
799         };
800
801         _D("Invalidate battery value to %d", value);
802
803         for (int i = 0; i < ARRAY_SIZE(list); ++i) {
804                 if (list[i].vconfkey) {
805                         retval = vconf_set_int(list[i].vconfkey, value);
806                         if (retval == 0)
807                                 _D("Set vconf %s to %d", list[i].vconfkey, value);
808                         else
809                                 _E("Failed to set %s to %d, %d", list[i].vconfkey, value, retval);
810                 }
811                 if (list[i].member)
812                         *(list[i].member) = value;
813         }
814
815         power_supply_exit(NULL);
816 }
817
818 static void battery_changed(struct battery_info *info, void *data)
819 {
820         int ret_val;
821
822         if (!info) {
823                 (void)battery_state(NULL);
824                 return;
825         }
826
827         if (info->status) {
828                 snprintf(battery.status_s, sizeof(battery.status_s),
829                                 "%s", info->status);
830                 check_charging_status(info->status);
831         } else
832                 battery.status_s[0] = '\0';
833
834         if (info->health) {
835                 snprintf(battery.health_s, sizeof(battery.health_s),
836                                 "%s", info->health);
837                 check_health_status(info->health);
838         } else
839                 battery.health_s[0] = '\0';
840
841         if (info->power_source)
842                 check_power_source(info->power_source);
843         else
844                 battery.power_source_s[0] = '\0';
845
846         battery.charger_connected = info->online;
847         battery.present = info->present;
848         battery.capacity = info->capacity;
849         battery.current_now = info->current_now;
850         battery.current_average = info->current_average;
851         battery.temperature = info->temperature;
852         battery.voltage_now = info->voltage_now;
853         battery.voltage_average = info->voltage_average;
854
855         battery_initialized = true;
856
857         ret_val = battery_state(info);
858         if (ret_val != 1)
859                 return;
860
861         ret_val = delayed_init_done(NULL);
862         if (ret_val) {
863                 /* If the same notification is requested repeatedly, it is ignored by power_supply_noti().
864                  * A notification will be triggered only when charging_status changes between
865                  * CHARGING_STATUS_CHARGING/FULL <-> CHARGING_STATUS_DISCHARGING. */
866                 if (battery.charging_status == CHARGING_STATUS_CHARGING || battery.charging_status == CHARGING_STATUS_FULL)
867                         power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
868                 else if (battery.charging_status == CHARGING_STATUS_DISCHARGING)
869                         power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
870         }
871
872         if (ret_val == 0) {
873                 battery.health = HEALTH_GOOD;
874                 battery.present = PRESENT_NORMAL;
875         }
876
877         if (battery.present) {
878                 process_power_supply(&battery.capacity);
879         } else {
880                 CRITICAL_LOG_E("Battery disconnected. Disable the battery module.");
881                 battery_disable_module(-ENODEV);
882         }
883 }
884
885 static gboolean power_supply_update_during_booting(void *data)
886 {
887         int retval;
888
889         retval = hal_device_battery_get_current_state(battery_changed, NULL);
890         if (retval == -ENODEV) {
891                 CRITICAL_LOG_E("There is no battery detected. Disable the battery module.");
892                 battery_disable_module(retval);
893                 return G_SOURCE_REMOVE;
894         }
895
896         return G_SOURCE_CONTINUE;
897 }
898
899 static void power_supply_timer_start(void)
900 {
901         _D("Battery init timer during booting.");
902         power_timer = g_timeout_add(BATTERY_CHECK_TIMER_INTERVAL,
903                                 power_supply_update_during_booting, NULL);
904         if (power_timer == 0)
905                 _E("Failed to add battery init timer during booting.");
906         else
907                 _I("Started battery init timer during booting.");
908 }
909
910 static GVariant *dbus_get_charger_status(GDBusConnection *conn,
911         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
912         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
913 {
914         int ret_val, status;
915
916         ret_val = vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &status);
917         if (ret_val < 0) {
918                 _E("Failed to get vconf value for charger status: %d", vconf_get_ext_errno());
919                 status = -EIO;
920         }
921         return g_variant_new("(i)", status);
922 }
923
924 static GVariant *dbus_get_charger_type(GDBusConnection *conn,
925         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
926         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
927 {
928         int type = battery.online_type;
929
930         return g_variant_new("(i)", type);
931 }
932
933 static GVariant *dbus_get_charge_now(GDBusConnection *conn,
934         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
935         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
936 {
937         int ret;
938
939         ret = battery.charge_now;
940
941         return g_variant_new("(i)", ret);
942 }
943
944 static GVariant *dbus_get_charge_level(GDBusConnection *conn,
945         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
946         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
947 {
948         int ret, val;
949
950         ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &val);
951         if (ret < 0) {
952                 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
953                 val = -EIO;
954         }
955
956         return g_variant_new("(i)", val);
957 }
958
959 static GVariant *dbus_get_percent(GDBusConnection *conn,
960         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
961         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
962 {
963         int ret;
964
965         ret = battery.capacity;
966
967         return g_variant_new("(i)", ret);
968 }
969
970 static GVariant *dbus_get_percent_raw(GDBusConnection *conn,
971         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
972         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
973 {
974         int ret;
975
976         ret = -ENOTSUP;
977
978         return g_variant_new("(i)", ret);
979 }
980
981 static GVariant *dbus_is_full(GDBusConnection *conn,
982         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
983         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
984 {
985         int ret;
986
987         ret = battery.charge_full;
988
989         return g_variant_new("(i)", ret);
990 }
991
992 static GVariant *dbus_get_health(GDBusConnection *conn,
993         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
994         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
995 {
996         const char *str;
997
998         str = battery.health_s;
999
1000         return g_variant_new("(s)", str);
1001 }
1002
1003 static GVariant *dbus_get_misc(GDBusConnection *conn,
1004         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1005         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1006 {
1007         int ret;
1008
1009         ret = battery.misc;
1010
1011         return g_variant_new("(i)", ret);
1012 }
1013
1014
1015 static GVariant *dbus_get_power_supply_handler(GDBusConnection *conn,
1016         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1017         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1018 {
1019         /* This method is for getting battery state after battery modification
1020          * by battery test driver. At this point, restore uevent buffering, which
1021          * had been disabled by test driver. */
1022         lowbat_enable_uevent_buffering();
1023
1024         return g_variant_new("(iiiiiiisiiiii)", 0,
1025                                 battery.capacity,
1026                                 battery.charging_status,
1027                                 battery.health,
1028                                 battery.charger_connected,
1029                                 battery.present,
1030                                 battery.misc,
1031                                 battery.power_source_s,
1032                                 battery.voltage_now,
1033                                 battery.voltage_average,
1034                                 battery.current_now,
1035                                 battery.current_average,
1036                                 battery.temperature);
1037 }
1038
1039 static GVariant *dbus_power_supply_handler(GDBusConnection *conn,
1040         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1041         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1042 {
1043         pid_t pid;
1044         int ret = 0, argc = 0;
1045         int charger_connected;
1046         char *type_str;
1047         char *argv[13];
1048         struct battery_info info = {0, };
1049
1050         g_variant_get(param, "(sisssisssssssss)", &type_str,
1051                                 &argc,
1052                                 &argv[0],
1053                                 &argv[1],
1054                                 &argv[2],
1055                                 &charger_connected,
1056                                 &argv[4],
1057                                 &argv[5],
1058                                 &argv[6],
1059                                 &argv[7],
1060                                 &argv[8],
1061                                 &argv[9],
1062                                 &argv[10],
1063                                 &argv[11],
1064                                 &argv[12]);
1065
1066         if (argc < 0) {
1067                 _E("Message is invalid.");
1068                 ret = -EINVAL;
1069                 goto out;
1070         }
1071
1072         pid = gdbus_connection_get_sender_pid(conn, sender);
1073         if (pid == -1 || kill(pid, 0) == -1) {
1074                 _E("Process(%d) does not exist, dbus ignored.", pid);
1075                 ret = -ESRCH;
1076                 goto out;
1077         }
1078
1079         /* The battery change triggered by this dbus must be processed
1080          * within a single subroutine as the objective of this method call is mostly
1081          * for the testing. Therefore, do not buffering the mocked uevent so that make
1082          * the test driver can get the changed battery result without waiting */
1083         lowbat_disable_uevent_buffering();
1084
1085         info.capacity = atoi(argv[0]);
1086         info.status = strdup(argv[1]);
1087         info.health = strdup(argv[2]);
1088         info.online = charger_connected;
1089         info.present = atoi(argv[4]);
1090         check_misc_status(argv[5]);
1091         info.power_source = strdup(argv[7]);
1092         info.voltage_now = atoi(argv[8]);
1093         info.voltage_average = atoi(argv[9]);
1094         info.current_now = atoi(argv[10]);
1095         info.current_average = atoi(argv[11]);
1096         info.temperature = atoi(argv[12]);
1097         _D("C(%d) S(%s) H(%s) O(%d) P(%d) SRC(%s) Vol(%d %d) Cur(%d %d) T(%d)",
1098                 info.capacity, info.status, info.health, info.online, info.present, info.power_source, info.voltage_now, info.voltage_average, info.current_now, info.current_average, info.temperature);
1099
1100         battery_changed(&info, NULL);
1101
1102 out:
1103         g_free(type_str);
1104         g_free(argv[0]);
1105         g_free(argv[1]);
1106         g_free(argv[2]);
1107         g_free(argv[4]);
1108         g_free(argv[5]);
1109         g_free(argv[6]);
1110         g_free(argv[7]);
1111         g_free(argv[8]);
1112         g_free(argv[9]);
1113         g_free(argv[10]);
1114         g_free(argv[11]);
1115         g_free(argv[12]);
1116
1117         free(info.status);
1118         free(info.health);
1119         free(info.power_source);
1120
1121         return g_variant_new("(i)", ret);
1122 }
1123
1124 static void battery_get_info(struct battery_info *info, void *data)
1125 {
1126         struct battery_info *bat = data;
1127
1128         if (!info || !bat)
1129                 return;
1130
1131         bat->status = strdup(info->status);
1132         bat->health = strdup(info->health);
1133         bat->power_source = strdup(info->power_source);
1134         bat->online = info->online;
1135         bat->present = info->present;
1136         bat->capacity = info->capacity;
1137         bat->current_now = info->current_now;
1138         bat->current_average = info->current_average;
1139         bat->temperature = info->temperature;
1140         bat->voltage_now = info->voltage_now;
1141         bat->voltage_average = info->voltage_average;
1142 }
1143
1144 static GVariant *dbus_get_battery_info(GDBusConnection *conn,
1145         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1146         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1147 {
1148         int ret = 0, val;
1149         const char *str;
1150         struct battery_info info = {0, };
1151
1152         if (old_state == DEVICE_NOTIFIER_STATE_STOP)
1153                 goto out;
1154
1155         if (battery_initialized)
1156                 goto out;
1157
1158         ret = hal_device_battery_get_current_state(battery_get_info, &info);
1159         if (ret != -ENODEV) {
1160                 if (ret < 0)
1161                         _E("Failed to get battery info: %d", ret);
1162
1163                 battery_changed(&info, NULL);
1164                 free(info.status);
1165                 free(info.health);
1166                 free(info.power_source);
1167         } else {
1168                 if (vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val) == 0 &&
1169                         val != VCONFKEY_SYSMAN_USB_DISCONNECTED)
1170                         str = POWER_SOURCE_USB;
1171                 else if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &val) == 0 &&
1172                         val == VCONFKEY_SYSMAN_CHARGER_CONNECTED)
1173                         str = POWER_SOURCE_AC;
1174                 else
1175                         str = POWER_SOURCE_NONE;
1176                 snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
1177
1178                 battery.current_now = -1; /* Not supported */
1179                 battery.current_average = -1; /* Not supported */
1180                 ret = 0;
1181         }
1182
1183 out:
1184         return g_variant_new("(isssiiiiiiii)", ret,
1185                                 battery.status_s,
1186                                 battery.health_s,
1187                                 battery.power_source_s,
1188                                 battery.charger_connected,
1189                                 battery.present,
1190                                 battery.capacity,
1191                                 battery.current_now,
1192                                 battery.current_average,
1193                                 battery.voltage_now,
1194                                 battery.voltage_average,
1195                                 battery.temperature);
1196 }
1197
1198 static void update_battery_props(void)
1199 {
1200         if (config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery) < 0)
1201                 _E("Failed to check power supply uevent.");
1202 }
1203
1204 static GVariant *dbus_get_battery_props(GDBusConnection *conn,
1205         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1206         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1207 {
1208         update_battery_props();
1209
1210         return g_variant_new("(iiiiii)",
1211                                         battery.capacity,
1212                                         battery.temperature,
1213                                         battery.voltage_now,
1214                                         battery.voltage_average,
1215                                         battery.current_now,
1216                                         battery.current_average);
1217 }
1218
1219 static const dbus_method_s dbus_methods[] = {
1220         { CHARGER_STATUS_SIGNAL,      NULL, "i", dbus_get_charger_status },
1221         { CHARGE_NOW_SIGNAL,          NULL, "i", dbus_get_charge_now },
1222         { CHARGE_LEVEL_SIGNAL,         NULL, "i", dbus_get_charge_level },
1223         { CHARGE_CAPACITY_SIGNAL,     NULL, "i", dbus_get_percent },
1224         { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
1225         { CHARGE_FULL_SIGNAL,         NULL, "i", dbus_is_full },
1226         { CHARGE_HEALTH_SIGNAL,        NULL, "s", dbus_get_health },
1227         { POWER_SUBSYSTEM,      "sisssisssssssss", "i", dbus_power_supply_handler },
1228         { GET_POWER_SUBSYSTEM,      NULL, "iiiiiiisiiiii", dbus_get_power_supply_handler },
1229         { "GetBatteryInfo",           NULL, "isssiiiiiiii", dbus_get_battery_info },
1230         { CHARGER_TYPE_SIGNAL,         NULL, "i", dbus_get_charger_type },
1231         { CHARGE_BATTERY_PROPERTIES,   NULL, "iiiiii", dbus_get_battery_props },
1232         { CHARGE_MISC_EVENT_SIGNAL,    NULL, "i", dbus_get_misc },
1233 };
1234
1235 static const dbus_interface_u dbus_interface = {
1236         .oh = NULL,
1237         .name = DEVICED_INTERFACE_BATTERY,
1238         .methods = dbus_methods,
1239         .nr_methods = ARRAY_SIZE(dbus_methods),
1240 };
1241
1242 static int delayed_init_done(void *data)
1243 {
1244         static int done;
1245         int retval;
1246         device_notifier_state_e state = DEVICE_NOTIFIER_STATE_START;
1247
1248         if (data == NULL)
1249                 return done;
1250         done = *(int *)data;
1251         if (done == 0)
1252                 return done;
1253
1254         if (power_timer) {
1255                 g_source_remove(power_timer);
1256                 power_timer = 0;
1257         }
1258
1259         /* check battery has been initialized */
1260         retval = hal_device_battery_get_current_state(battery_changed, NULL);
1261         if (retval == -ENODEV) {
1262                 CRITICAL_LOG_E("Failed to initialize battery state, %d. Disable the battery module.", retval);
1263                 battery_disable_module(retval);
1264                 return done;
1265         }
1266
1267         event_handler_state_changed((void *)&state);
1268
1269         _I("booting done %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
1270                         CHARGER_STATUS_SIGNAL, battery.charger_connected,
1271                         CHARGE_NOW_SIGNAL, battery.charge_now,
1272                         CHARGE_FULL_SIGNAL, battery.charge_full,
1273                         CHARGE_CAPACITY_SIGNAL, battery.capacity,
1274                         CHARGE_LEVEL_SIGNAL, battery.capacity_level,
1275                         CHARGE_MISC_EVENT_SIGNAL, battery.misc,
1276                         CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
1277
1278         unregister_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1279
1280         return done;
1281 }
1282
1283 bool battery_do_not_disturb(void)
1284 {
1285         int block = 0, theater = 0, night = 0;
1286         int r;
1287
1288         if (battery_plgn->display_changed) {
1289                 if (battery_plgn->display_changed(NULL) == S_LCDOFF) {
1290                         r = vconf_get_bool(VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL, &block);
1291                         if (r < 0)
1292                                 _E("Failed to set vconf value for blockmode wearable: %d", vconf_get_ext_errno());
1293                         r = vconf_get_bool(VCONFKEY_SETAPPL_THEATER_MODE_ENABLE, &theater);
1294                         if (r < 0)
1295                                 _E("Failed to set vconf value for theator mode enable: %d", vconf_get_ext_errno());
1296                         r = vconf_get_bool(VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE, &night);
1297                         if (r < 0)
1298                                 _E("Failed to set vconf value for goodnight mode enable: %d", vconf_get_ext_errno());
1299                 }
1300         }
1301
1302         if (block != 0 || theater != 0 || night != 0) {
1303                 _I("Skip lcd and popup(block %d theater %d night %d).", block, theater, night);
1304                 return true;
1305         }
1306
1307         return false;
1308 }
1309
1310 int battery_pm_change_internal(int pid, int s_bits)
1311 {
1312         if (battery_do_not_disturb())
1313                 return 0;
1314
1315         if (disp_plgn->pm_change_internal)
1316                 disp_plgn->pm_change_internal(pid, s_bits);
1317
1318         return 0;
1319 }
1320
1321 static int load_uevent(struct parse_result *result, void *user_data)
1322 {
1323         struct battery_status *info = user_data;
1324
1325         if (!info)
1326                 return -EINVAL;
1327
1328         if (MATCH(result->name, CHARGE_STATUS)) {
1329                 if (strstr(result->value, "Charging")) {
1330                         info->charge_now = CHARGER_CHARGING;
1331                         info->charge_full = CHARGING_NOT_FULL;
1332                 } else if (strstr(result->value, "Discharging")) {
1333                         info->charge_now = CHARGER_DISCHARGING;
1334                         info->charge_full = CHARGING_NOT_FULL;
1335                 } else if (strstr(result->value, "Full")) {
1336                         info->charge_now = CHARGER_DISCHARGING;
1337                         info->charge_full = CHARGING_FULL;
1338                 } else if (strstr(result->value, "Not charging")) {
1339                         info->charge_now = CHARGER_ABNORMAL;
1340                         info->charge_full = CHARGING_NOT_FULL;
1341                 }
1342                 snprintf(info->status_s, sizeof(info->status_s), "%s", result->value);
1343         } else if (MATCH(result->name, CAPACITY)) {
1344                 info->capacity = atoi(result->value);
1345         } else if (MATCH(result->name, TEMPERATURE)) {
1346                 info->temperature = atoi(result->value) / 10;
1347         } else if (MATCH(result->name, VOLTAGE_NOW)) {
1348                 info->voltage_now = atoi(result->value);
1349         } else if (MATCH(result->name, VOLTAGE_AVG)) {
1350                 info->voltage_average = atoi(result->value);
1351         } else if (MATCH(result->name, CURRENT_NOW)) {
1352                 info->current_now = atoi(result->value);
1353         } else if (MATCH(result->name, CURRENT_AVG)) {
1354                 info->current_average = atoi(result->value);
1355         } else if (MATCH(result->name, CHARGE_HEALTH)) {
1356                 snprintf(info->health_s, sizeof(info->health_s), "%s", result->value);
1357         }
1358
1359         return 0;
1360 }
1361
1362 static int power_supply_probe(void *data)
1363 {
1364         int ret_val, r;
1365
1366
1367         ret_val = hal_device_battery_get_backend();
1368         if (ret_val < 0) {
1369                 _E("There is no HAL for battery.");
1370                 if (access(POWER_PATH, R_OK) == 0)
1371                         return 0; /* Just power_supply uevent is used */
1372
1373                 goto out;
1374         }
1375
1376         _I("Battery device structure load success.");
1377         return 0;
1378
1379 out:
1380         /**
1381          * Set battery vconf as -ENOTSUP
1382          * These vconf key used by runtime-info and capi-system-device.
1383          */
1384         r = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
1385         if (r < 0)
1386                 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
1387         r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, -ENOTSUP);
1388         if (r < 0)
1389                 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
1390         r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, -ENOTSUP);
1391         if (r < 0)
1392                 _E("Failed to set vconf value for battery level status: %d", vconf_get_ext_errno());
1393         _I("There is no battery device: %d", ret_val);
1394         return -ENODEV;
1395 }
1396
1397 static void add_power_supply_handler(void)
1398 {
1399         hal_device_battery_register_changed_event(battery_changed, NULL);
1400         hal_device_battery_get_current_state(battery_changed, NULL);
1401 }
1402
1403 static void remove_power_supply_handler(void)
1404 {
1405         hal_device_battery_unregister_changed_event(battery_changed);
1406 }
1407
1408 static int event_handler_state_changed(void *data)
1409 {
1410         device_notifier_state_e state = *(device_notifier_state_e *)data;
1411
1412         if (old_state == state)
1413                 return 0;
1414
1415         old_state = state;
1416
1417         if (state == DEVICE_NOTIFIER_STATE_START)
1418                 add_power_supply_handler();
1419         else if (state == DEVICE_NOTIFIER_STATE_STOP)
1420                 remove_power_supply_handler();
1421
1422         return 0;
1423 }
1424
1425 static void power_supply_init(void *data)
1426 {
1427         int ret_dbus;
1428
1429         memset(&battery, 0, sizeof(struct battery_status));
1430         memset(&old_battery, 0, sizeof(struct battery_status));
1431         battery.misc = MISC_NONE;
1432         battery.charger_connected = -1;
1433
1434         /* It will be true on initializing battery structure */
1435         battery_initialized = false;
1436
1437         /* process check battery timer until booting done */
1438         power_supply_timer_start();
1439
1440         register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1441         register_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1442
1443         ret_dbus = gdbus_add_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
1444         if (ret_dbus < 0)
1445                 _E("Failed to init dbus method: %d", ret_dbus);
1446
1447         battery_ops_init((void *)battery_plgn);
1448 }
1449
1450 static void power_supply_exit(void *data)
1451 {
1452         device_notifier_state_e state = DEVICE_NOTIFIER_STATE_STOP;
1453
1454         unregister_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
1455         unregister_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1456
1457         event_handler_state_changed((void *)&state);
1458
1459         battery_ops_exit(NULL);
1460 }
1461
1462 static const struct device_ops power_supply_ops = {
1463         DECLARE_NAME_LEN("power_supply"),
1464         .probe    = power_supply_probe,
1465         .init     = power_supply_init,
1466         .exit     = power_supply_exit,
1467 };
1468
1469 DEVICE_OPS_REGISTER(&power_supply_ops)
1470
1471 static void __CONSTRUCTOR__ initialize(void)
1472 {
1473         disp_plgn = get_var_display_plugin();
1474         if (!disp_plgn)
1475                 _E("Failed to get display plugin variable.");
1476
1477         battery_plgn = get_var_battery_plugin();
1478         if (!battery_plgn)
1479                 _E("Failed to get battery plugin variable.");
1480 }