4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <device-node.h>
25 #include <eventsystem.h>
26 #include <hw/battery.h>
29 #include "core/devices.h"
30 #include "core/device-notifier.h"
31 #include "core/udev.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"
42 #include "extcon/extcon.h"
44 #ifndef VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL
45 #define VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL "db/setting/blockmode_wearable"
48 #ifndef VCONFKEY_SETAPPL_THEATER_MODE_ENABLE
49 #define VCONFKEY_SETAPPL_THEATER_MODE_ENABLE "db/setting/theater_mode_enable"
52 #ifndef VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE
53 #define VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE "db/setting/goodnight_mode_enable"
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"
66 #define REMOVE_POPUP "remove_battery_popups"
67 #define DISCONNECT_POPUP "battdisconnect"
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
75 #define SIGNAL_CHARGEERR_RESPONSE "ChargeErrResponse"
76 #define SIGNAL_TEMP_GOOD "TempGood"
78 #define ABNORMAL_CHECK_TIMER_INTERVAL 60
80 #define METHOD_FULL_NOTI_ON "BatteryFullNotiOn"
81 #define METHOD_FULL_NOTI_OFF "BatteryFullNotiOff"
82 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
84 #define CHARGER_CHARGE_ON_NODE "/sys/class/power_supply/battery/chg_on"
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
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,
98 struct battery_status battery;
99 struct battery_status old_battery;
101 static int online_status;
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;
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);
117 static struct battery_device *battery_dev;
119 static int load_uevent(struct parse_result *result, void *user_data);
120 static int event_handler_state_changed(void *data);
122 static int lowbat_execute(void *data)
124 static const struct device_ops *lowbat_ops;
126 FIND_DEVICE_INT(lowbat_ops, "lowbat");
127 return device_execute(lowbat_ops, data);
130 static int power_supply_broadcast_str(char *sig, char *status)
132 static char old_sig[32];
133 static char old_status[32];
137 if (!sig || !status) {
138 _E("there is no signal name");
142 if (strncmp(old_sig, sig, strlen(sig)) == 0 && strncmp(old_status, status, strlen(status)) == 0)
145 snprintf(old_sig, sizeof(old_sig), "%s", sig);
146 snprintf(old_status, sizeof(old_status), "%s", status);
150 ret = dbus_handle_emit_dbus_signal(NULL,
151 DEVICED_PATH_BATTERY,
152 DEVICED_INTERFACE_BATTERY,
154 g_variant_new("(s)", str));
162 static void pm_check_and_change(int bInserted)
166 if (old == bInserted)
169 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
172 static void abnormal_popup_timer_init(void)
174 if (abnormal_timer == 0)
176 g_source_remove(abnormal_timer);
178 _I("Delete health timer.");
181 static void health_status_broadcast(void)
183 dbus_handle_emit_dbus_signal(NULL,
184 DEVICED_PATH_BATTERY,
185 DEVICED_INTERFACE_BATTERY,
191 static void health_timer_reset(void)
196 static gboolean health_timer_cb(void *data)
198 health_timer_reset();
200 if (battery.health != HEALTH_LOW && battery.health != HEALTH_HIGH)
201 return G_SOURCE_REMOVE;
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;
217 static void abnormal_popup_dbus_signal_handler(GDBusConnection *conn,
226 if (battery.health == HEALTH_GOOD)
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.");
235 static void full_noti_cb(GVariant *var, void *user_data, GError *err)
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));
248 _D("Inserted battery full noti(%d).", noti_id);
251 g_variant_unref(var);
254 static void noti_off_cb(GVariant *var, void *user_data, GError *err)
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));
263 _D("Noti off: %d", ret);
266 g_variant_unref(var);
269 int check_power_supply_noti(void)
273 if (vconf_get_bool("db/setting/blockmode_wearable", &block) != 0)
280 static int send_full_noti(enum charge_full_type state)
286 noti = check_power_supply_noti();
293 for (retry = RETRY_MAX; retry > 0; retry--) {
294 ret = dbus_handle_method_async_with_reply(POPUP_BUS_NAME,
296 POPUP_INTERFACE_NOTI,
298 NULL, NULL, full_noti_cb, -1, NULL);
300 _D("Created battery full noti.");
304 _E("Failed to call dbus method: %d", ret);
306 case CHARGING_NOT_FULL:
309 for (retry = RETRY_MAX; retry > 0; retry--) {
310 ret = dbus_handle_method_async_with_reply_var(POPUP_BUS_NAME,
312 POPUP_INTERFACE_NOTI,
313 METHOD_FULL_NOTI_OFF,
314 g_variant_new("(i)", noti_id),
315 noti_off_cb, -1, NULL);
317 _D("Deleted battery full noti.");
322 _E("Failed to call dbus method: %d", ret);
328 static void charge_noti_on(GVariant *var, void *user_data, GError *err)
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));
340 _D("Inserted battery charge noti: %d", id);
343 g_variant_unref(var);
346 static int send_charge_noti(void)
351 for (retry = RETRY_MAX; retry > 0; retry--) {
352 ret = dbus_handle_method_async_with_reply(POPUP_BUS_NAME,
354 POPUP_INTERFACE_NOTI,
355 METHOD_CHARGE_NOTI_ON,
356 NULL, NULL, charge_noti_on, -1, NULL);
358 _I("Created battery charge noti.");
362 _E("Failed to call dbus method: %d", ret);
366 static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
368 static int charger = CHARGER_DISCHARGING;
369 static int full = CHARGING_NOT_FULL;
372 if (type == DEVICE_NOTI_BATT_CHARGE) {
373 if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
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);
382 full = CHARGING_FULL;
383 } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
384 ret = send_full_noti(CHARGING_NOT_FULL);
386 full = CHARGING_NOT_FULL;
391 int power_supply_broadcast(char *sig, int status)
394 static char sig_old[32];
399 _E("There is no signal name.");
402 if (strncmp(sig_old, sig, strlen(sig)) == 0 && old == status) {
403 _D("Skip broadcasting same signal(%s) and status(%d).", sig, status);
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);
415 if (strncmp(sig, CHARGE_NOW_SIGNAL, strlen(CHARGE_NOW_SIGNAL)) == 0) {
416 _I("Skip signal while charger disabled.");
421 snprintf(sig_old, sizeof(sig_old), "%s", sig);
423 ret = dbus_handle_emit_dbus_signal(NULL,
424 DEVICED_PATH_BATTERY,
425 DEVICED_INTERFACE_BATTERY,
427 g_variant_new("(i)", status));
434 static void noti_batt_full(void)
436 static int bat_full_noti;
439 if (!battery.charge_full && bat_full_noti == 1) {
440 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
442 /* off the full charge state */
443 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
445 if (battery.charge_full && bat_full_noti == 0) {
446 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
448 /* turn on LCD, if battery is full charged */
449 noti = check_power_supply_noti();
451 battery_pm_change_internal(INTERNAL_LOCK_BATTERY_FULL, LCD_NORMAL);
455 /* on the full charge state */
456 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
460 static void check_power_supply(int state)
462 pm_check_and_change(state);
463 if (disp_plgn.update_pm_setting)
464 disp_plgn.update_pm_setting(SETTING_CHARGING, state);
467 static void charger_state_send_system_event(int state)
472 case CHARGE_STATUS_CHARGING:
473 str = EVT_VAL_BATTERY_CHARGER_CHARGING;
475 case CHARGE_STATUS_FULL:
476 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
477 CRITICAL_LOG("Battery %s", str);
479 case CHARGE_STATUS_DISCHARGING:
480 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
482 case CHARGE_STATUS_CONNECTED:
483 str = EVT_VAL_BATTERY_CHARGER_CONNECTED;
484 CRITICAL_LOG("Battery %s", str);
486 case CHARGE_STATUS_DISCONNECTED:
487 str = EVT_VAL_BATTERY_CHARGER_DISCONNECTED;
488 CRITICAL_LOG("Battery %s", str);
491 _E("Invalid parameter: %d", state);
495 _D("System_event: %s", str);
497 event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str);
500 int changed_battery_cf(int status)
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);
507 static void update_present(enum battery_noti_status status)
510 CRITICAL_LOG("Charge(%d) present(%d, old: %d)", battery.charge_now, battery.present, old_battery.present);
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);
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);
524 changed_battery_cf(battery.present);
527 void remove_health_popup(void)
531 ret = launch_system_app(APP_REMOVE, 2, APP_KEY_TYPE, REMOVE_POPUP);
533 _E("Failed to launch remove battery popup(%d)", ret);
536 static void update_health(enum battery_noti_status status)
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);
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);
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);
562 change_health_popup_timer(status);
563 health_status_broadcast();
564 abnormal_popup_timer_init();
565 remove_health_popup();
569 void update_health_popup_relaunch(void)
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)
579 update_health_popup_relaunch_time((HEALTH_POPUP_RELAUNCH_TIMEOUT - delta));
582 static void update_ovp(enum battery_noti_status status)
584 static int old = DEVICE_NOTI_OFF;
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");
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);
598 static void check_abnormal_status(void)
600 if (battery.health == HEALTH_LOW || battery.health == HEALTH_HIGH)
601 update_health_popup_relaunch();
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);
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);
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);
621 static bool update_online(void)
625 bool broadcast = false;
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);
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);
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);
655 if (old_battery.charge_status != battery.charge_status)
656 charger_state_send_system_event(battery.charge_status);
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;
669 battery.online_type = CHARGER_TYPE_WIRE;
674 static void check_charge_status(const char *env_value)
678 if (env_value == NULL)
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;
691 battery.charge_status = CHARGE_STATUS_UNKNOWN;
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;
706 battery.charge_full = CHARGING_NOT_FULL;
707 battery.charge_now = CHARGER_DISCHARGING;
711 static void check_health_status(const char *env_value)
715 if (env_value == NULL) {
716 battery.health = HEALTH_GOOD;
720 snprintf(battery.health_s, sizeof(battery.health_s), "%s", env_value);
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;
732 battery.health = HEALTH_NO_OPT;
735 static void check_misc_status(const char *env_value)
737 if (env_value == NULL) {
738 battery.misc = MISC_NONE;
741 battery.misc = atoi(env_value);
744 static void check_freq_strength_status(const char *env_value)
746 if (env_value == NULL) {
747 battery.freq_strength = 0;
750 battery.freq_strength = atoi(env_value);
753 static void check_online_status(const char *env_value)
755 if (env_value == NULL)
757 battery.online = atoi(env_value);
760 static void check_present_status(const char *env_value)
762 if (env_value == NULL) {
763 battery.present = PRESENT_NORMAL;
766 battery.present = atoi(env_value);
769 static void check_capacity_status(const char *env_value)
771 if (env_value == NULL)
773 battery.capacity = atoi(env_value);
776 static void update_capacity_full(void)
781 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY ||
783 old >= battery.capacity) {
784 old = battery.capacity;
787 delta = battery.capacity - old;
788 old = battery.capacity;
789 extcon_update_count(EXTCON_BATTERY_FULL, delta);
792 static void update_battery_cycle(void)
794 static int first = 1;
800 extcon_update_count(EXTCON_BATTERY_CYCLE, 0);
804 if (battery.online > POWER_SUPPLY_TYPE_BATTERY ||
806 old <= battery.capacity) {
807 old = battery.capacity;
810 delta = old - battery.capacity;
811 old = battery.capacity;
812 extcon_update_count(EXTCON_BATTERY_CYCLE, delta);
815 static void process_power_supply(void *data)
817 bool broadcasted = true;
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);
827 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
829 if (power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now) < 0)
834 if (old_battery.charge_full != battery.charge_full)
835 if (power_supply_broadcast(CHARGE_FULL_SIGNAL, battery.charge_full) < 0)
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)
844 if (old_battery.capacity != battery.capacity) {
845 ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
847 _E("Failed to set vconf value for battery capacity: %d", vconf_get_ext_errno());
849 if (power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity) < 0)
852 battery.charging_level = lowbat_execute(data);
854 if (update_online()) {
855 ret = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, online_status);
857 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
859 if (power_supply_broadcast(CHARGER_STATUS_SIGNAL, online_status) < 0)
863 if (old_battery.online_type != battery.online_type) {
864 if (power_supply_broadcast(CHARGER_TYPE_SIGNAL, battery.online_type) < 0)
868 if (old_battery.misc != battery.misc)
869 if (power_supply_broadcast(CHARGE_MISC_EVENT_SIGNAL, battery.misc) < 0)
872 if (old_battery.freq_strength != battery.freq_strength)
873 if (power_supply_broadcast(CHARGE_FREQ_STRENGTH_SIGNAL, battery.freq_strength) < 0)
876 if (old_battery.charge_full != battery.charge_full)
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)",
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);
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;
905 old_battery.misc = battery.misc;
906 old_battery.freq_strength = battery.freq_strength;
908 check_abnormal_status();
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;
915 update_capacity_full();
916 update_battery_cycle();
918 if (disp_plgn.pm_unlock_internal)
919 disp_plgn.pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
923 static void uevent_power_handler(struct udev_device *dev)
925 struct udev_list_entry *list_entry;
926 const char *env_name;
927 const char *env_value;
928 bool matched = false;
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);
937 if (!strncmp(env_name, CHARGE_NAME, sizeof(CHARGE_NAME))) {
938 env_value = udev_list_entry_get_value(list_entry);
941 if (!strncmp(env_value, BATTERY_NAME,
942 sizeof(BATTERY_NAME))) {
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);
965 ret = booting_done(NULL);
967 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
968 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
970 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
973 process_power_supply(&battery.capacity);
976 static int battery_state(struct battery_info *info)
978 static struct battery_status prev_status;
981 memcpy(&prev_status, &battery, sizeof(battery));
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)
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;
1004 _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%d) Pres(%d) Curr(%d,%d)",
1006 battery.charge_now == CHARGER_CHARGING ? "Charging"
1007 : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
1015 info->current_average);
1019 static void battery_changed(struct battery_info *info, void *data)
1024 (void)battery_state(NULL);
1029 snprintf(battery.status_s, sizeof(battery.status_s),
1030 "%s", info->status);
1031 check_charge_status(info->status);
1033 battery.status_s[0] = '\0';
1036 snprintf(battery.health_s, sizeof(battery.health_s),
1037 "%s", info->health);
1038 check_health_status(info->health);
1040 battery.health_s[0] = '\0';
1042 if (info->power_source)
1043 snprintf(battery.power_source_s, sizeof(battery.power_source_s),
1044 "%s", info->power_source);
1046 battery.power_source_s[0] = '\0';
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;
1056 ret = battery_state(info);
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);
1066 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
1069 battery.health = HEALTH_GOOD;
1070 battery.present = PRESENT_NORMAL;
1073 process_power_supply(&battery.capacity);
1077 static void power_supply_status_init(void)
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);
1088 r = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
1090 _E("Failed to load %s, %d Use default value.", POWER_SUPPLY_UEVENT, r);
1093 battery.health = HEALTH_GOOD;
1094 battery.present = PRESENT_NORMAL;
1095 process_power_supply(&battery.capacity);
1099 static gboolean power_supply_update(void *data)
1101 power_supply_status_init();
1102 return G_SOURCE_CONTINUE;
1105 static void power_supply_timer_start(void)
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.");
1113 _I("Started battery init timer during booting.");
1116 static void power_supply_timer_stop(void)
1118 if (power_timer == 0)
1120 _I("Stop battery init timer during booting.");
1121 g_source_remove(power_timer);
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)
1131 ret = vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &status);
1133 _E("Failed to get vconf value for charger status: %d", vconf_get_ext_errno());
1136 return g_variant_new("(i)", status);
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)
1143 int type = battery.online_type;
1145 return g_variant_new("(i)", type);
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)
1156 g_variant_get(param, "(i)", &val);
1158 if (val != CHARGER_ENABLED && val != CHARGER_DISABLED) {
1159 _E("There is no valid input: %d", battery.charger_charging);
1163 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY) {
1164 _E("There is no charger(%d) input(%d).", battery.online, battery.charger_charging);
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);
1176 _I("Skip change status with %d (ret %d prev %d)", val, ret, battery.charger_charging);
1179 return g_variant_new("(i)", ret);
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)
1188 ret = battery.charge_now;
1190 return g_variant_new("(i)", ret);
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)
1199 ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &val);
1201 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
1205 return g_variant_new("(i)", val);
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)
1214 ret = battery.capacity;
1216 return g_variant_new("(i)", ret);
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)
1227 return g_variant_new("(i)", ret);
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)
1236 ret = battery.charge_full;
1238 return g_variant_new("(i)", ret);
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)
1247 str = battery.health_s;
1249 return g_variant_new("(s)", str);
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)
1260 return g_variant_new("(i)", ret);
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)
1268 return g_variant_new("(i)", battery.freq_strength);
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)
1281 g_variant_get(param, "(sissssss)", &type_str,
1292 _E("Message is invalid.");
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);
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]);
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" :
1317 _I("%s(%d) %s(f:%d n:%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d)",
1321 battery.charge_full,
1332 battery.freq_strength);
1334 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
1335 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
1337 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
1339 process_power_supply(&battery.capacity);
1350 return g_variant_new("(i)", ret);
1353 static void battery_get_info(struct battery_info *info, void *data)
1355 struct battery_info *bat = data;
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;
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)
1376 struct battery_info info = {0, };
1378 if (battery_dev && battery_dev->get_current_state) {
1379 ret = battery_dev->get_current_state(battery_get_info, &info);
1381 _E("Failed to get battery info: %d", ret);
1383 battery_changed(&info, NULL);
1386 free(info.power_source);
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;
1395 str = POWER_SOURCE_NONE;
1396 snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
1398 battery.current_now = -1; /* Not supported */
1399 battery.current_average = -1; /* Not supported */
1403 return g_variant_new("(isssiiiiiiii)", ret,
1406 battery.power_source_s,
1410 battery.current_now,
1411 battery.current_average,
1412 battery.voltage_now,
1413 battery.voltage_average,
1414 battery.temperature);
1417 static void update_battery_props(void)
1419 if (config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery) < 0)
1420 _E("Failed to check power supply uevent.");
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)
1427 update_battery_props();
1429 return g_variant_new("(iiiiii)",
1431 battery.temperature,
1432 battery.voltage_now,
1433 battery.voltage_average,
1434 battery.current_now,
1435 battery.current_average);
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}
1455 static const dbus_interface_u dbus_interface = {
1457 .name = DEVICED_INTERFACE_BATTERY,
1458 .methods = dbus_methods,
1459 .nr_methods = ARRAY_SIZE(dbus_methods),
1462 static int booting_done(void *data)
1465 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_START;
1469 done = *(int *)data;
1473 power_supply_timer_stop();
1474 event_handler_state_changed((void *)&state);
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);
1485 unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
1490 static gboolean update_health_pm_status(void *data)
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);
1498 return G_SOURCE_REMOVE;
1501 static void change_health_popup_timer(enum battery_noti_status status)
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.");
1508 _I("Turn off after %d sec by abnormal health condition.", HEALTH_POPUP_TERMINATE_TIMEOUT);
1511 health_popup_timer_init(__func__);
1514 static void launch_health_popup(void)
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);
1532 bool battery_do_not_disturb(void)
1537 if (display_changed(NULL) == S_LCDOFF) {
1538 r = vconf_get_bool(VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL, &block);
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);
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);
1546 _E("Failed to set vconf value for goodnight mode enable: %d", vconf_get_ext_errno());
1550 _I("Skip lcd and popup(block %d).", block);
1557 static int battery_pm_change_internal(int pid, int s_bits)
1559 if (battery_do_not_disturb())
1562 if (disp_plgn.pm_change_internal)
1563 disp_plgn.pm_change_internal(pid, s_bits);
1568 static gboolean change_health_pm_normal(void *data)
1570 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
1571 return G_SOURCE_REMOVE;
1574 static void update_health_popup_relaunch_time(int timeout)
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.");
1584 _D("Relaunch timeout with %d sec.", timeout);
1587 static void health_popup_timer_init(const char *func)
1589 if (health_popup_timer == 0)
1592 g_source_remove(health_popup_timer);
1593 health_popup_timer = 0;
1594 _D("init by %s", func);
1597 static int display_changed(void *data)
1599 static enum state_t old;
1600 static enum state_t state;
1605 state = *(int *)data;
1607 if (battery.health != HEALTH_LOW && battery.health != HEALTH_HIGH)
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);
1618 launch_health_popup();
1625 static int load_uevent(struct parse_result *result, void *user_data)
1627 struct battery_status *info = user_data;
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;
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);
1666 static int power_supply_probe(void *data)
1668 struct hw_info *info;
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 */
1683 _E("Failed to open battery device: open(NULL)");
1687 ret = info->open(info, NULL, (struct hw_common**)&battery_dev);
1689 _E("Failed to get battery device structure: %d", ret);
1693 if (!battery_dev || !battery_dev->get_current_state) {
1694 _E("get_current_state() is not supported by the Battery HAL.");
1698 _I("Battery device structure load success.");
1703 * Set battery vconf as -ENOTSUP
1704 * These vconf key used by runtime-info and capi-system-device.
1706 r = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
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);
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);
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);
1719 static void add_power_supply_handler(void)
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);
1729 ret = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
1731 _E("Failed to load %s, %d Use default value!", POWER_SUPPLY_UEVENT, ret);
1733 /* register power subsystem */
1734 register_kernel_uevent_control(&uh);
1738 static void remove_power_supply_handler(void)
1741 battery_dev->unregister_changed_event(battery_changed);
1743 unregister_kernel_uevent_control(&uh);
1746 static int event_handler_state_changed(void *data)
1748 static device_notifier_state_e old = DEVICE_NOTIFIER_STATE_STOP;
1749 device_notifier_state_e state = *(device_notifier_state_e *)data;
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();
1764 static void power_supply_init(void *data)
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;
1774 /* process check battery timer until booting done */
1775 power_supply_timer_start();
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);
1781 ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
1783 _E("Failed to init dbus method: %d", ret);
1786 ret = subscribe_dbus_signal(NULL, DEVICED_PATH_SYSNOTI,
1787 DEVICED_INTERFACE_SYSNOTI, SIGNAL_CHARGEERR_RESPONSE, abnormal_popup_dbus_signal_handler, NULL, NULL);
1789 _E("Failed to init dbus signal: %d", ret);
1792 static void power_supply_exit(void *data)
1794 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_STOP;
1796 unregister_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1798 event_handler_state_changed((void *)&state);
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,
1808 DEVICE_OPS_REGISTER(&power_supply_ops)