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