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