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.
24 #include <eventsystem.h>
25 #include <hal/device/hal-battery.h>
27 #include <libsyscommon/ini-parser.h>
29 #include "core/devices.h"
30 #include "core/device-notifier.h"
31 #include "core/udev.h"
33 #include "display/poll.h"
34 #include "display/setting.h"
35 #include "shared/eventsystem.h"
36 #include "shared/plugin.h"
37 #include "display/core.h"
38 #include "display/display-ops.h"
39 #include "apps/apps.h"
40 #include "power-supply.h"
42 #include "battery-ops.h"
43 #include "extcon/extcon.h"
45 #ifndef VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL
46 #define VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL "db/setting/blockmode_wearable"
49 #ifndef VCONFKEY_SETAPPL_THEATER_MODE_ENABLE
50 #define VCONFKEY_SETAPPL_THEATER_MODE_ENABLE "db/setting/theater_mode_enable"
53 #ifndef VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE
54 #define VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE "db/setting/goodnight_mode_enable"
57 #define BATTERY_NAME "battery"
58 #define CHARGEFULL_NAME "Full"
59 #define CHARGENOW_NAME "Charging"
60 #define DISCHARGE_NAME "Discharging"
61 #define NOTCHARGE_NAME "Not charging"
62 #define OVERHEAT_NAME "Overheat"
63 #define TEMPCOLD_NAME "Cold"
64 #define OVERVOLT_NAME "Over voltage"
65 #define GOOD_NAME "Good"
67 #define CHARGER_WIRELESS_TYPE_BT 10
68 #define CHARGER_WIRELESS_TYPE_3G 22
69 #define CHARGER_INCOMPATIBLE_TYPE 11
70 #define CHARGER_D2D_TYPE 110
71 #define WIRELESS_CHARGER_CONNECTED 2
73 #define SIGNAL_TEMP_GOOD "TempGood"
75 #define METHOD_FULL_NOTI_ON "BatteryFullNotiOn"
76 #define METHOD_FULL_NOTI_OFF "BatteryFullNotiOff"
77 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
79 #define CHARGER_CHARGE_ON_NODE "/sys/class/power_supply/battery/chg_on"
82 #define BATTERY_CHECK_TIMER_INTERVAL 500 /* 0.5 second */
83 #define LCD_DIM_TIME_IN_BATTERY_HEALTH 10000 /* ms */
85 static struct display_plugin *disp_plgn;
86 static struct battery_plugin *battery_plgn;
88 static void uevent_power_handler(struct udev_device *dev);
89 static const struct uevent_handler uh = {
90 .subsystem = POWER_SUBSYSTEM,
91 .uevent_func = uevent_power_handler,
94 static struct battery_status battery;
95 struct battery_status old_battery;
97 static int online_status;
98 static int abnormal_health_popup_timer;
99 static bool launching_health_popup;
101 static guint power_timer;
102 static device_notifier_state_e old_state = -1;
104 bool battery_initialized;
106 bool battery_do_not_disturb(void);
107 int battery_pm_change_internal(int pid, int s_bits);
108 static int booting_done(void *data);
109 static void update_health(enum battery_noti_status status);
110 static bool battery_dev_available = false;
111 static int load_uevent(struct parse_result *result, void *user_data);
112 static int event_handler_state_changed(void *data);
114 inline struct battery_status *get_var_battery_status(void)
119 static int lowbat_execute(void *data)
121 static const struct device_ops *lowbat_ops;
123 FIND_DEVICE_INT(lowbat_ops, "lowbat");
124 return device_execute(lowbat_ops, data);
127 static int power_supply_broadcast_str(char *sig, char *status)
129 static char old_sig[32];
130 static char old_status[32];
134 if (!sig || !status) {
135 _E("there is no signal name");
139 if (strncmp(old_sig, sig, strlen(sig)) == 0 && strncmp(old_status, status, strlen(status)) == 0)
142 snprintf(old_sig, sizeof(old_sig), "%s", sig);
143 snprintf(old_status, sizeof(old_status), "%s", status);
147 ret = dbus_handle_emit_dbus_signal(NULL,
148 DEVICED_PATH_BATTERY,
149 DEVICED_INTERFACE_BATTERY,
151 g_variant_new("(s)", str));
159 static void pm_check_and_change(int bInserted)
163 if (old == bInserted)
166 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
169 static void health_status_broadcast(void)
171 dbus_handle_emit_dbus_signal(NULL,
172 DEVICED_PATH_BATTERY,
173 DEVICED_INTERFACE_BATTERY,
178 static void full_noti_cb(GVariant *var, void *user_data, GError *err)
185 if (!g_variant_get_safe(var, "(i)", &id)) {
186 _E("Failed to notify full: no message(%s)", g_variant_get_type_string(var));
191 _D("Inserted battery full noti(%d).", noti_id);
194 g_variant_unref(var);
197 static void noti_off_cb(GVariant *var, void *user_data, GError *err)
201 if (!g_variant_get_safe(var, "(i)", &val)) {
202 _E("Failed to off notification: no message(%s)", g_variant_get_type_string(var));
206 _D("Noti off: %d", val);
209 g_variant_unref(var);
212 static int send_full_noti(enum charge_full_type state)
218 if (battery_plgn->check_power_supply_noti)
219 noti = battery_plgn->check_power_supply_noti();
226 for (retry = RETRY_MAX; retry > 0; retry--) {
227 ret = dbus_handle_method_async_with_reply_var(POPUP_BUS_NAME,
229 POPUP_INTERFACE_NOTI,
231 NULL, full_noti_cb, -1, NULL);
233 _D("Created battery full noti.");
237 _E("Failed to call dbus method: %d", ret);
239 case CHARGING_NOT_FULL:
242 for (retry = RETRY_MAX; retry > 0; retry--) {
243 ret = dbus_handle_method_async_with_reply_var(POPUP_BUS_NAME,
245 POPUP_INTERFACE_NOTI,
246 METHOD_FULL_NOTI_OFF,
247 g_variant_new("(i)", noti_id),
248 noti_off_cb, -1, NULL);
250 _D("Deleted battery full noti.");
255 _E("Failed to call dbus method: %d", ret);
261 static void charge_noti_on(GVariant *var, void *user_data, GError *err)
268 if (!g_variant_get_safe(var, "(i)", &id)) {
269 _E("Failed to notify charge: no message(%s)", g_variant_get_type_string(var));
273 _D("Inserted battery charge noti: %d", id);
276 g_variant_unref(var);
279 static int send_charge_noti(void)
284 for (retry = RETRY_MAX; retry > 0; retry--) {
285 ret = dbus_handle_method_async_with_reply_var(POPUP_BUS_NAME,
287 POPUP_INTERFACE_NOTI,
288 METHOD_CHARGE_NOTI_ON,
289 NULL, charge_noti_on, -1, NULL);
291 _I("Created battery charge noti.");
295 _E("Failed to call dbus method: %d", ret);
299 static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
301 static int charger = CHARGER_DISCHARGING;
302 static int full = CHARGING_NOT_FULL;
305 if (type == DEVICE_NOTI_BATT_CHARGE) {
306 if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
308 charger = CHARGER_CHARGING;
309 } else if (status == DEVICE_NOTI_OFF && charger == CHARGER_CHARGING)
310 charger = CHARGER_DISCHARGING;
311 } else if (type == DEVICE_NOTI_BATT_FULL) {
312 if (status == DEVICE_NOTI_ON && full == CHARGING_NOT_FULL) {
313 ret_val = send_full_noti(CHARGING_FULL);
315 full = CHARGING_FULL;
316 } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
317 ret_val = send_full_noti(CHARGING_NOT_FULL);
319 full = CHARGING_NOT_FULL;
324 int power_supply_broadcast(char *sig, int status)
327 static char sig_old[32];
332 _E("There is no signal name.");
335 if (strncmp(sig_old, sig, strlen(sig)) == 0 && old == status) {
336 _D("Skip broadcasting same signal(%s) and status(%d).", sig, status);
342 if (battery.charger_charging == CHARGER_DISABLED) {
343 ret = sys_get_int(CHARGER_CHARGE_ON_NODE, &chg_on);
344 if (ret == 0 && battery.charger_charging != chg_on) {
345 ret = sys_set_int(CHARGER_CHARGE_ON_NODE, battery.charger_charging);
346 _I("%s to change status with %d", ((ret == 0) ? "success" : "fail"), battery.charger_charging);
348 if (strncmp(sig, CHARGE_NOW_SIGNAL, strlen(CHARGE_NOW_SIGNAL)) == 0) {
349 _I("Skip signal while charger disabled.");
354 snprintf(sig_old, sizeof(sig_old), "%s", sig);
356 ret = dbus_handle_emit_dbus_signal(NULL,
357 DEVICED_PATH_BATTERY,
358 DEVICED_INTERFACE_BATTERY,
360 g_variant_new("(i)", status));
367 static void noti_batt_full(void)
369 static int bat_full_noti;
371 if (!battery.charge_full && bat_full_noti == 1) {
372 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
374 /* off the full charge state */
375 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
377 if (battery.charge_full && bat_full_noti == 0) {
378 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
380 /* turn on LCD, if battery is fully charged */
381 if (battery_plgn->check_power_supply_noti && battery_plgn->check_power_supply_noti()) {
382 battery_pm_change_internal(INTERNAL_LOCK_BATTERY_FULL, LCD_NORMAL);
386 /* on the full charge state */
387 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
391 static void check_power_supply(int state)
393 pm_check_and_change(state);
394 if (disp_plgn->update_pm_setting)
395 disp_plgn->update_pm_setting(SETTING_CHARGING, state);
398 static void charger_state_send_system_event(int state)
403 case CHARGE_STATUS_CHARGING:
404 str = EVT_VAL_BATTERY_CHARGER_CHARGING;
406 case CHARGE_STATUS_FULL:
407 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
408 CRITICAL_LOG("Battery %s", str);
410 case CHARGE_STATUS_DISCHARGING:
411 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
413 case CHARGE_STATUS_CONNECTED:
414 str = EVT_VAL_BATTERY_CHARGER_CONNECTED;
415 CRITICAL_LOG("Battery %s", str);
417 case CHARGE_STATUS_DISCONNECTED:
418 str = EVT_VAL_BATTERY_CHARGER_DISCONNECTED;
419 CRITICAL_LOG("Battery %s", str);
422 _E("Invalid parameter: %d", state);
426 _D("System_event: %s", str);
428 event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str);
431 static void update_present(enum battery_noti_status status)
434 CRITICAL_LOG("Charge(%d) present(%d, old: %d)", battery.charge_now, battery.present, old_battery.present);
436 old_battery.present = battery.present;
437 if (status == DEVICE_NOTI_ON) {
438 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
439 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
440 if (disp_plgn->pm_lock_internal)
441 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
443 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
444 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
445 if (disp_plgn->pm_unlock_internal)
446 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
448 if (battery_plgn->changed_battery_cf)
449 battery_plgn->changed_battery_cf(battery.present);
452 static void launch_health_popup(void)
454 if (launching_health_popup)
457 launching_health_popup = true;
459 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
460 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
461 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
462 if (disp_plgn->pm_unlock_internal)
463 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
464 if (disp_plgn->pm_lock_internal)
465 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
466 if (battery.health == HEALTH_LOW)
467 battery_charge_err_low_act(NULL);
468 else if (battery.health == HEALTH_HIGH)
469 battery_charge_err_high_act(NULL);
471 launching_health_popup = false;
474 /* Warning popup for every 1 minutes until
475 * battery health returns to normal. */
476 static gboolean health_popup_cb(void *data)
478 launch_health_popup();
479 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
480 return G_SOURCE_CONTINUE;
483 static void update_health(enum battery_noti_status status)
485 _I("Charge(%d) health(%d, old: %d)", battery.charge_now, battery.health, old_battery.health);
487 old_battery.health = battery.health;
488 if (status == DEVICE_NOTI_ON) {
489 CRITICAL_LOG("Popup: Battery health status is not good, %s.", battery.health_s);
490 launch_health_popup();
491 if (!abnormal_health_popup_timer)
492 abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
494 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
495 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
496 if (disp_plgn->pm_unlock_internal) {
497 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
498 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
500 health_status_broadcast();
501 if (abnormal_health_popup_timer) {
502 CRITICAL_LOG("Battery health returned to normal. Stop abnormal popup.");
503 g_source_remove(abnormal_health_popup_timer);
504 abnormal_health_popup_timer = 0;
506 if (battery_plgn->remove_health_popup)
507 battery_plgn->remove_health_popup();
511 void relaunch_health_popup(void)
513 if (launching_health_popup)
516 launching_health_popup = true;
518 if (abnormal_health_popup_timer)
519 g_source_remove(abnormal_health_popup_timer);
521 if (disp_plgn->pm_unlock_internal)
522 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
523 if (disp_plgn->pm_lock_internal)
524 disp_plgn->pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
525 if (battery.health == HEALTH_LOW)
526 battery_charge_err_low_act(NULL);
527 else if (battery.health == HEALTH_HIGH)
528 battery_charge_err_high_act(NULL);
530 abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
532 launching_health_popup = false;
535 static void check_abnormal_status(void)
537 if (old_battery.health != HEALTH_LOW && old_battery.health != HEALTH_HIGH &&
538 (battery.health == HEALTH_LOW || battery.health == HEALTH_HIGH))
539 update_health(DEVICE_NOTI_ON);
540 else if ((old_battery.health == HEALTH_LOW || old_battery.health == HEALTH_HIGH) &&
541 battery.health != HEALTH_LOW && battery.health != HEALTH_HIGH)
542 update_health(DEVICE_NOTI_OFF);
544 if (old_battery.present != PRESENT_ABNORMAL && battery.present == PRESENT_ABNORMAL)
545 update_present(DEVICE_NOTI_ON);
546 else if (battery.present != PRESENT_ABNORMAL && old_battery.present == PRESENT_ABNORMAL)
547 update_present(DEVICE_NOTI_OFF);
549 if (old_battery.health != HEALTH_OVP && battery.health == HEALTH_OVP) {
550 if (battery_plgn->update_ovp)
551 battery_plgn->update_ovp(DEVICE_NOTI_ON);
552 } else if (battery.health != HEALTH_OVP && old_battery.health == HEALTH_OVP) {
553 if (battery_plgn->update_ovp)
554 battery_plgn->update_ovp(DEVICE_NOTI_OFF);
558 static bool update_online(void)
562 bool broadcast = false;
564 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
565 battery.charger_charging == CHARGER_DISABLED) {
566 battery.charger_charging = CHARGER_ENABLED;
567 ret_val = sys_get_int(CHARGER_CHARGE_ON_NODE, &chg_on);
568 if (ret_val == 0 && battery.charger_charging != chg_on) {
569 ret_val = sys_set_int(CHARGER_CHARGE_ON_NODE, battery.charger_charging);
570 _I("%s to change status with %d", ((ret_val == 0) ? "success" : "fail"), battery.charger_charging);
574 if (battery.online > POWER_SUPPLY_TYPE_BATTERY &&
575 online_status == VCONFKEY_SYSMAN_CHARGER_DISCONNECTED) {
576 online_status = VCONFKEY_SYSMAN_CHARGER_CONNECTED;
577 extcon_update_count(EXTCON_TA, 1);
578 check_power_supply(online_status);
579 charger_state_send_system_event(CHARGE_STATUS_CONNECTED);
580 if (old_battery.charge_status != battery.charge_status)
581 charger_state_send_system_event(battery.charge_status);
583 } else if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
584 online_status == VCONFKEY_SYSMAN_CHARGER_CONNECTED) {
585 online_status = VCONFKEY_SYSMAN_CHARGER_DISCONNECTED;
586 check_power_supply(online_status);
587 if (old_battery.charge_status != battery.charge_status)
588 charger_state_send_system_event(battery.charge_status);
589 charger_state_send_system_event(CHARGE_STATUS_DISCONNECTED);
592 if (old_battery.charge_status != battery.charge_status)
593 charger_state_send_system_event(battery.charge_status);
596 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY)
597 battery.online_type = CHARGER_TYPE_NONE;
598 else if (battery.online == CHARGER_WIRELESS_TYPE_BT ||
599 battery.online == CHARGER_WIRELESS_TYPE_3G)
600 battery.online_type = CHARGER_TYPE_WIRELESS;
601 else if (battery.online == CHARGER_INCOMPATIBLE_TYPE)
602 battery.online_type = CHARGER_TYPE_INCOMPATIBLE;
603 else if (battery.online == CHARGER_D2D_TYPE)
604 battery.online_type = CHARGER_TYPE_D2D;
606 battery.online_type = CHARGER_TYPE_WIRE;
611 static void check_charge_status(const char *env_value)
615 if (env_value == NULL)
618 len = strlen(env_value);
619 if (strncmp(env_value, CHARGEFULL_NAME, len) == 0)
620 battery.charge_status = CHARGE_STATUS_FULL;
621 else if (strncmp(env_value, CHARGENOW_NAME, len) == 0)
622 battery.charge_status = CHARGE_STATUS_CHARGING;
623 else if (strncmp(env_value, DISCHARGE_NAME, len) == 0)
624 battery.charge_status = CHARGE_STATUS_DISCHARGING;
625 else if (strncmp(env_value, NOTCHARGE_NAME, len) == 0)
626 battery.charge_status = CHARGE_STATUS_NOT_CHARGING;
628 battery.charge_status = CHARGE_STATUS_UNKNOWN;
630 if (battery.charge_status == CHARGE_STATUS_FULL) {
631 battery.charge_full = CHARGING_FULL;
632 battery.charge_now = CHARGER_DISCHARGING;
633 } else if (battery.charge_status == CHARGE_STATUS_CHARGING) {
634 battery.charge_full = CHARGING_NOT_FULL;
635 battery.charge_now = CHARGER_CHARGING;
636 } else if (battery.charge_status == CHARGE_STATUS_DISCHARGING) {
637 battery.charge_full = CHARGING_NOT_FULL;
638 battery.charge_now = CHARGER_DISCHARGING;
639 } else if (battery.charge_status == CHARGE_STATUS_NOT_CHARGING) {
640 battery.charge_full = CHARGING_NOT_FULL;
641 battery.charge_now = CHARGER_ABNORMAL;
643 battery.charge_full = CHARGING_NOT_FULL;
644 battery.charge_now = CHARGER_DISCHARGING;
648 static void check_health_status(const char *env_value)
652 if (env_value == NULL) {
653 battery.health = HEALTH_GOOD;
657 snprintf(battery.health_s, sizeof(battery.health_s), "%s", env_value);
659 len = strlen(env_value);
660 if (strncmp(env_value, OVERHEAT_NAME, len) == 0)
661 battery.health = HEALTH_HIGH;
662 else if (strncmp(env_value, TEMPCOLD_NAME, len) == 0)
663 battery.health = HEALTH_LOW;
664 else if (strncmp(env_value, OVERVOLT_NAME, len) == 0)
665 battery.health = HEALTH_OVP;
666 else if (strncmp(env_value, GOOD_NAME, len) == 0)
667 battery.health = HEALTH_GOOD;
669 battery.health = HEALTH_NO_OPT;
672 static void check_misc_status(const char *env_value)
674 if (env_value == NULL) {
675 battery.misc = MISC_NONE;
678 battery.misc = atoi(env_value);
681 static void check_online_status(const char *env_value)
683 if (env_value == NULL)
685 battery.online = atoi(env_value);
688 static void check_present_status(const char *env_value)
690 if (env_value == NULL) {
691 battery.present = PRESENT_NORMAL;
694 battery.present = atoi(env_value);
697 static void check_capacity_status(const char *env_value)
699 if (env_value == NULL)
701 battery.capacity = atoi(env_value);
704 static void check_temperature_status(const char *env_value)
706 if (env_value == NULL)
708 battery.temperature = atoi(env_value) / 10;
711 static void update_capacity_full(void)
716 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY ||
718 old >= battery.capacity) {
719 old = battery.capacity;
722 delta = battery.capacity - old;
723 old = battery.capacity;
724 extcon_update_count(EXTCON_BATTERY_FULL, delta);
727 static void update_battery_cycle(void)
729 static int first = 1;
735 extcon_update_count(EXTCON_BATTERY_CYCLE, 0);
739 if (battery.online > POWER_SUPPLY_TYPE_BATTERY ||
741 old <= battery.capacity) {
742 old = battery.capacity;
745 delta = old - battery.capacity;
746 old = battery.capacity;
747 extcon_update_count(EXTCON_BATTERY_CYCLE, delta);
750 static void process_power_supply(void *data)
752 bool broadcasted = true;
756 _D("process_power_supply()");
757 if (disp_plgn->pm_lock_internal) {
758 lock = disp_plgn->pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
759 if (old_battery.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
760 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
762 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
764 if (power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now) < 0)
769 if (!strcmp(old_battery.status_s, CHARGEFULL_NAME) &&
770 !strcmp(battery.status_s, CHARGENOW_NAME)) {
771 battery_pm_change_internal(INTERNAL_LOCK_BATTERY, LCD_NORMAL);
774 if (old_battery.charge_full != battery.charge_full)
775 if (power_supply_broadcast(CHARGE_FULL_SIGNAL, battery.charge_full) < 0)
778 if (strncmp(old_battery.health_s, battery.health_s, strlen(battery.health_s))) {
779 snprintf(old_battery.health_s, sizeof(old_battery.health_s), "%s", battery.health_s);
780 if (power_supply_broadcast_str(CHARGE_HEALTH_SIGNAL, battery.health_s) < 0)
784 if (old_battery.capacity != battery.capacity) {
785 ret_val = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
787 _E("Failed to set vconf value for battery capacity: %d", vconf_get_ext_errno());
789 if (power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity) < 0)
793 (void)lowbat_execute(data);
795 if (update_online()) {
796 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, online_status);
798 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
800 if (power_supply_broadcast(CHARGER_STATUS_SIGNAL, online_status) < 0)
804 if (old_battery.online_type != battery.online_type) {
805 ret_val = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_TYPE, battery.online_type);
807 _E("Failed to set vconf value for charger type: %d", vconf_get_ext_errno());
809 if (power_supply_broadcast(CHARGER_TYPE_SIGNAL, battery.online_type) < 0)
813 if (old_battery.misc != battery.misc)
814 if (power_supply_broadcast(CHARGE_MISC_EVENT_SIGNAL, battery.misc) < 0)
817 if (old_battery.freq_strength != battery.freq_strength)
818 if (power_supply_broadcast(CHARGE_FREQ_STRENGTH_SIGNAL, battery.freq_strength) < 0)
821 if (old_battery.charge_full != battery.charge_full)
824 if (old_battery.charge_now != battery.charge_now ||
825 old_battery.charge_full != battery.charge_full ||
826 old_battery.capacity != battery.capacity ||
827 old_battery.health != battery.health ||
828 old_battery.misc != battery.misc ||
829 old_battery.freq_strength != battery.freq_strength ||
830 old_battery.online_type != battery.online_type)
831 _I("Signal(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s) %s(%d)",
833 CHARGER_STATUS_SIGNAL, online_status,
834 CHARGER_TYPE_SIGNAL, battery.online_type,
835 CHARGE_NOW_SIGNAL, battery.charge_now,
836 CHARGE_FULL_SIGNAL, battery.charge_full,
837 CHARGE_CAPACITY_SIGNAL, battery.capacity,
838 CHARGE_LEVEL_SIGNAL, battery.charging_level,
839 CHARGE_MISC_EVENT_SIGNAL, battery.misc,
840 CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s,
841 CHARGE_FREQ_STRENGTH_SIGNAL, battery.freq_strength);
843 old_battery.capacity = battery.capacity;
844 old_battery.charging_level = battery.charging_level;
845 old_battery.online = battery.online;
846 old_battery.online_type = battery.online_type;
847 old_battery.charge_status = battery.charge_status;
848 old_battery.charge_full = battery.charge_full;
850 old_battery.misc = battery.misc;
851 old_battery.freq_strength = battery.freq_strength;
852 snprintf(old_battery.status_s, sizeof(old_battery.status_s), "%s", battery.status_s);
854 check_abnormal_status();
856 device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
857 if (old_battery.charge_now != battery.charge_now) {
858 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, &battery.charge_now);
859 old_battery.charge_now = battery.charge_now;
861 update_capacity_full();
862 update_battery_cycle();
864 if (disp_plgn->pm_unlock_internal)
865 disp_plgn->pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
869 static void uevent_power_handler(struct udev_device *dev)
871 struct udev_list_entry *list_entry;
872 const char *env_name;
873 const char *env_value;
874 bool matched = false;
877 udev_list_entry_foreach(list_entry,
878 udev_device_get_properties_list_entry(dev)) {
879 env_name = udev_list_entry_get_name(list_entry);
883 if (!strncmp(env_name, CHARGE_NAME, sizeof(CHARGE_NAME))) {
884 env_value = udev_list_entry_get_value(list_entry);
887 if (!strncmp(env_value, BATTERY_NAME,
888 sizeof(BATTERY_NAME))) {
898 env_value = udev_device_get_property_value(dev, CHARGE_STATUS);
899 check_charge_status(env_value);
900 env_value = udev_device_get_property_value(dev, CHARGE_ONLINE);
901 check_online_status(env_value);
902 env_value = udev_device_get_property_value(dev, CHARGE_HEALTH);
903 check_health_status(env_value);
904 env_value = udev_device_get_property_value(dev, CHARGE_MISC_EVENT);
905 check_misc_status(env_value);
906 env_value = udev_device_get_property_value(dev, CHARGE_PRESENT);
907 check_present_status(env_value);
908 env_value = udev_device_get_property_value(dev, CAPACITY);
909 check_capacity_status(env_value);
910 env_value = udev_device_get_property_value(dev, TEMPERATURE);
911 check_temperature_status(env_value);
913 battery_initialized = true;
915 ret_val = booting_done(NULL);
917 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
918 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
920 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
923 process_power_supply(&battery.capacity);
926 static int battery_state(struct battery_info *info)
928 static struct battery_status prev_status;
931 memcpy(&prev_status, &battery, sizeof(battery));
935 if (battery.capacity != 0 && prev_status.capacity == battery.capacity &&
936 prev_status.charge_status == battery.charge_status &&
937 prev_status.charge_full == battery.charge_full &&
938 prev_status.charge_now == battery.charge_now &&
939 prev_status.health == battery.health &&
940 prev_status.present == battery.present &&
941 prev_status.online == battery.online &&
942 prev_status.freq_strength == battery.freq_strength)
945 prev_status.capacity = battery.capacity;
946 prev_status.charge_status = battery.charge_status;
947 prev_status.charge_full = battery.charge_full;
948 prev_status.charge_now = battery.charge_now;
949 prev_status.health = battery.health;
950 prev_status.present = battery.present;
951 prev_status.online = battery.online;
952 prev_status.freq_strength = battery.freq_strength;
954 _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%d) Pres(%d) Curr(%d,%d)",
956 battery.charge_now == CHARGER_CHARGING ? "Charging"
957 : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
965 info->current_average);
969 static void battery_changed(struct battery_info *info, void *data)
974 (void)battery_state(NULL);
979 snprintf(battery.status_s, sizeof(battery.status_s),
981 check_charge_status(info->status);
983 battery.status_s[0] = '\0';
986 snprintf(battery.health_s, sizeof(battery.health_s),
988 check_health_status(info->health);
990 battery.health_s[0] = '\0';
992 if (info->power_source)
993 snprintf(battery.power_source_s, sizeof(battery.power_source_s),
994 "%s", info->power_source);
996 battery.power_source_s[0] = '\0';
998 battery.online = info->online;
999 battery.present = info->present;
1000 battery.capacity = info->capacity;
1001 battery.current_now = info->current_now;
1002 battery.current_average = info->current_average;
1003 battery.temperature = info->temperature;
1004 battery.voltage_now = info->voltage_now;
1005 battery.voltage_average = info->voltage_average;
1006 battery.freq_strength = info->freq_strength;
1008 battery_initialized = true;
1010 ret_val = battery_state(info);
1014 ret_val = booting_done(NULL);
1016 /* If the same notification is requested repeatedly, it is ignored by power_supply_noti().
1017 * A notification will be triggered only when charge_status changes between
1018 * CHARGE_STATUS_CHARGING/FULL <-> CHARGE_STATUS_DISCHARGING. */
1019 if (battery.charge_status == CHARGE_STATUS_CHARGING || battery.charge_status == CHARGE_STATUS_FULL)
1020 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
1021 else if (battery.charge_status == CHARGE_STATUS_DISCHARGING)
1022 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
1026 battery.health = HEALTH_GOOD;
1027 battery.present = PRESENT_NORMAL;
1030 process_power_supply(&battery.capacity);
1034 static void power_supply_status_init(void)
1038 r = hal_device_battery_get_current_state(battery_changed, NULL);
1039 if (battery_dev_available && (r != -ENODEV)) {
1040 if (r < 0 || battery.capacity < 0) {
1041 _E("Failed to get battery capacity (capa: %d, ret: %d)", battery.capacity, r);
1045 r = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
1047 _E("Failed to load %s, %d Use default value.", POWER_SUPPLY_UEVENT, r);
1050 battery.health = HEALTH_GOOD;
1051 battery.present = PRESENT_NORMAL;
1052 process_power_supply(&battery.capacity);
1056 static gboolean power_supply_update(void *data)
1058 power_supply_status_init();
1059 return G_SOURCE_CONTINUE;
1062 static void power_supply_timer_start(void)
1064 _D("Battery init timer during booting.");
1065 power_timer = g_timeout_add(BATTERY_CHECK_TIMER_INTERVAL,
1066 power_supply_update, NULL);
1067 if (power_timer == 0)
1068 _E("Failed to add battery init timer during booting.");
1070 _I("Started battery init timer during booting.");
1073 static void power_supply_timer_stop(void)
1075 if (power_timer == 0)
1077 _I("Stop battery init timer during booting.");
1078 g_source_remove(power_timer);
1082 static GVariant *dbus_get_charger_status(GDBusConnection *conn,
1083 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1084 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1086 int ret_val, status;
1088 ret_val = vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &status);
1090 _E("Failed to get vconf value for charger status: %d", vconf_get_ext_errno());
1093 return g_variant_new("(i)", status);
1096 static GVariant *dbus_get_charger_type(GDBusConnection *conn,
1097 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1098 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1100 int type = battery.online_type;
1102 return g_variant_new("(i)", type);
1105 static GVariant *dbus_charger_charging(GDBusConnection *conn,
1106 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1107 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1113 g_variant_get(param, "(i)", &val);
1115 if (val != CHARGER_ENABLED && val != CHARGER_DISABLED) {
1116 _E("There is no valid input: %d", battery.charger_charging);
1120 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY) {
1121 _E("There is no charger(%d) input(%d).", battery.online, battery.charger_charging);
1125 ret = sys_get_int(CHARGER_CHARGE_ON_NODE, &chg_on);
1126 if (ret == 0 && val != chg_on) {
1127 battery.charger_charging = val;
1128 ret = sys_set_int(CHARGER_CHARGE_ON_NODE, battery.charger_charging);
1129 CRITICAL_LOG("chg_on changed to %d %s", battery.charger_charging,
1130 (ret == 0) ? "success" : "fail");
1131 _I("%s to change status with %d.", ((ret == 0) ? "success" : "fail"), battery.charger_charging);
1133 _I("Skip change status with %d (ret %d prev %d)", val, ret, battery.charger_charging);
1136 return g_variant_new("(i)", ret);
1139 static GVariant *dbus_get_charge_now(GDBusConnection *conn,
1140 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1141 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1145 ret = battery.charge_now;
1147 return g_variant_new("(i)", ret);
1150 static GVariant *dbus_get_charge_level(GDBusConnection *conn,
1151 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1152 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1156 ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &val);
1158 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
1162 return g_variant_new("(i)", val);
1165 static GVariant *dbus_get_percent(GDBusConnection *conn,
1166 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1167 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1171 ret = battery.capacity;
1173 return g_variant_new("(i)", ret);
1176 static GVariant *dbus_get_percent_raw(GDBusConnection *conn,
1177 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1178 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1184 return g_variant_new("(i)", ret);
1187 static GVariant *dbus_is_full(GDBusConnection *conn,
1188 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1189 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1193 ret = battery.charge_full;
1195 return g_variant_new("(i)", ret);
1198 static GVariant *dbus_get_health(GDBusConnection *conn,
1199 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1200 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1204 str = battery.health_s;
1206 return g_variant_new("(s)", str);
1209 static GVariant *dbus_get_misc(GDBusConnection *conn,
1210 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1211 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1217 return g_variant_new("(i)", ret);
1221 static GVariant *dbus_get_freq_strength(GDBusConnection *conn,
1222 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1223 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1225 return g_variant_new("(i)", battery.freq_strength);
1228 static GVariant *dbus_get_power_supply_handler(GDBusConnection *conn,
1229 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1230 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1232 return g_variant_new("(iiiiiiiisiiiii)", 0,
1234 battery.charge_status,
1239 battery.freq_strength,
1240 battery.power_source_s,
1241 battery.voltage_now,
1242 battery.voltage_average,
1243 battery.current_now,
1244 battery.current_average,
1245 battery.temperature);
1248 static GVariant *dbus_power_supply_handler(GDBusConnection *conn,
1249 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1250 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1253 int ret = 0, argc = 0;
1256 struct battery_info info = {0, };
1258 g_variant_get(param, "(sisssssssssssss)", &type_str,
1275 _E("Message is invalid.");
1280 pid = dbus_connection_get_sender_pid(conn, sender);
1281 if (pid == -1 || kill(pid, 0) == -1) {
1282 _E("Process(%d) does not exist, dbus ignored.", pid);
1287 info.capacity = atoi(argv[0]);
1288 info.status = strdup(argv[1]);
1289 info.health = strdup(argv[2]);
1290 info.online = atoi(argv[3]);
1291 info.present = atoi(argv[4]);
1292 check_misc_status(argv[5]);
1293 info.freq_strength = atoi(argv[6]);
1294 info.power_source = strdup(argv[7]);
1295 info.voltage_now = atoi(argv[8]);
1296 info.voltage_average = atoi(argv[9]);
1297 info.current_now = atoi(argv[10]);
1298 info.current_average = atoi(argv[11]);
1299 info.temperature = atoi(argv[12]);
1300 _D("C(%d) S(%s) H(%s) O(%d) P(%d) F(%d) SRC(%s) Vol(%d %d) Cur(%d %d) T(%d)",
1301 info.capacity, info.status, info.health, info.online, info.present, info.freq_strength, info.power_source, info.voltage_now, info.voltage_average, info.current_now, info.current_average, info.temperature);
1303 if (battery_dev_available)
1304 battery_changed(&info, NULL);
1306 snprintf(battery.status_s, sizeof(battery.status_s), "%s",
1307 (battery.charge_now == CHARGER_CHARGING) ? "Charging" :
1308 (battery.charge_now == CHARGER_ABNORMAL) ? "Not Charging" :
1309 (battery.charge_full == CHARGING_FULL) ? "Full" :
1311 _I("%s(%d) %s(f:%d n:%d) %s(%d) %s(%d) %s(%d) %s(%d)",
1315 battery.charge_full,
1325 _I("%s(%d) %s(%s) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d)",
1327 battery.freq_strength,
1329 battery.power_source_s,
1331 battery.voltage_now,
1333 battery.voltage_average,
1335 battery.current_now,
1337 battery.current_average,
1339 battery.temperature);
1341 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
1342 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
1344 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
1346 process_power_supply(&battery.capacity);
1365 free(info.power_source);
1367 return g_variant_new("(i)", ret);
1370 static void battery_get_info(struct battery_info *info, void *data)
1372 struct battery_info *bat = data;
1377 bat->status = strdup(info->status);
1378 bat->health = strdup(info->health);
1379 bat->power_source = strdup(info->power_source);
1380 bat->online = info->online;
1381 bat->present = info->present;
1382 bat->capacity = info->capacity;
1383 bat->current_now = info->current_now;
1384 bat->current_average = info->current_average;
1385 bat->temperature = info->temperature;
1386 bat->voltage_now = info->voltage_now;
1387 bat->voltage_average = info->voltage_average;
1388 bat->freq_strength = info->freq_strength;
1391 static GVariant *dbus_get_battery_info(GDBusConnection *conn,
1392 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1393 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1397 struct battery_info info = {0, };
1399 if (old_state == DEVICE_NOTIFIER_STATE_STOP)
1402 if (battery_initialized)
1405 ret = hal_device_battery_get_current_state(battery_get_info, &info);
1406 if (battery_dev_available && (ret != -ENODEV)) {
1408 _E("Failed to get battery info: %d", ret);
1410 battery_changed(&info, NULL);
1413 free(info.power_source);
1415 if (vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val) == 0 &&
1416 val != VCONFKEY_SYSMAN_USB_DISCONNECTED)
1417 str = POWER_SOURCE_USB;
1418 else if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &val) == 0 &&
1419 val == VCONFKEY_SYSMAN_CHARGER_CONNECTED)
1420 str = POWER_SOURCE_AC;
1422 str = POWER_SOURCE_NONE;
1423 snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
1425 battery.current_now = -1; /* Not supported */
1426 battery.current_average = -1; /* Not supported */
1431 return g_variant_new("(isssiiiiiiii)", ret,
1434 battery.power_source_s,
1438 battery.current_now,
1439 battery.current_average,
1440 battery.voltage_now,
1441 battery.voltage_average,
1442 battery.temperature);
1445 static void update_battery_props(void)
1447 if (config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery) < 0)
1448 _E("Failed to check power supply uevent.");
1451 static GVariant *dbus_get_battery_props(GDBusConnection *conn,
1452 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1453 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1455 update_battery_props();
1457 return g_variant_new("(iiiiii)",
1459 battery.temperature,
1460 battery.voltage_now,
1461 battery.voltage_average,
1462 battery.current_now,
1463 battery.current_average);
1466 static const dbus_method_s dbus_methods[] = {
1467 { CHARGER_STATUS_SIGNAL, NULL, "i", dbus_get_charger_status },
1468 { CHARGE_NOW_SIGNAL, NULL, "i", dbus_get_charge_now },
1469 { CHARGE_LEVEL_SIGNAL, NULL, "i", dbus_get_charge_level },
1470 { CHARGE_CAPACITY_SIGNAL, NULL, "i", dbus_get_percent },
1471 { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
1472 { CHARGE_FULL_SIGNAL, NULL, "i", dbus_is_full },
1473 { CHARGE_HEALTH_SIGNAL, NULL, "s", dbus_get_health },
1474 { POWER_SUBSYSTEM, "sisssssssssssss", "i", dbus_power_supply_handler },
1475 { GET_POWER_SUBSYSTEM, NULL, "iiiiiiiisiiiii", dbus_get_power_supply_handler },
1476 { "GetBatteryInfo", NULL, "isssiiiiiiii", dbus_get_battery_info },
1477 { CHARGER_TYPE_SIGNAL, NULL, "i", dbus_get_charger_type },
1478 { "ChargerCharging", "i", "i", dbus_charger_charging },
1479 { CHARGE_BATTERY_PROPERTIES, NULL, "iiiiii", dbus_get_battery_props },
1480 { CHARGE_MISC_EVENT_SIGNAL, NULL, "i", dbus_get_misc },
1481 { CHARGE_FREQ_STRENGTH_SIGNAL, NULL, "i", dbus_get_freq_strength},
1484 static const dbus_interface_u dbus_interface = {
1486 .name = DEVICED_INTERFACE_BATTERY,
1487 .methods = dbus_methods,
1488 .nr_methods = ARRAY_SIZE(dbus_methods),
1491 static int booting_done(void *data)
1494 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_START;
1498 done = *(int *)data;
1502 power_supply_timer_stop();
1503 event_handler_state_changed((void *)&state);
1505 _I("booting done %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
1506 CHARGER_STATUS_SIGNAL, online_status,
1507 CHARGE_NOW_SIGNAL, battery.charge_now,
1508 CHARGE_FULL_SIGNAL, battery.charge_full,
1509 CHARGE_CAPACITY_SIGNAL, battery.capacity,
1510 CHARGE_LEVEL_SIGNAL, battery.charging_level,
1511 CHARGE_MISC_EVENT_SIGNAL, battery.misc,
1512 CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
1514 unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
1519 bool battery_do_not_disturb(void)
1521 int block = 0, theater = 0, night = 0;
1524 if (battery_plgn->display_changed) {
1525 if (battery_plgn->display_changed(NULL) == S_LCDOFF) {
1526 r = vconf_get_bool(VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL, &block);
1528 _E("Failed to set vconf value for blockmode wearable: %d", vconf_get_ext_errno());
1529 r = vconf_get_bool(VCONFKEY_SETAPPL_THEATER_MODE_ENABLE, &theater);
1531 _E("Failed to set vconf value for theator mode enable: %d", vconf_get_ext_errno());
1532 r = vconf_get_bool(VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE, &night);
1534 _E("Failed to set vconf value for goodnight mode enable: %d", vconf_get_ext_errno());
1538 if (block != 0 || theater != 0 || night != 0) {
1539 _I("Skip lcd and popup(block %d theater %d night %d).", block, theater, night);
1546 int battery_pm_change_internal(int pid, int s_bits)
1548 if (battery_do_not_disturb())
1551 if (disp_plgn->pm_change_internal)
1552 disp_plgn->pm_change_internal(pid, s_bits);
1557 static int load_uevent(struct parse_result *result, void *user_data)
1559 struct battery_status *info = user_data;
1564 if (MATCH(result->name, CHARGE_STATUS)) {
1565 if (strstr(result->value, "Charging")) {
1566 info->charge_now = CHARGER_CHARGING;
1567 info->charge_full = CHARGING_NOT_FULL;
1568 } else if (strstr(result->value, "Discharging")) {
1569 info->charge_now = CHARGER_DISCHARGING;
1570 info->charge_full = CHARGING_NOT_FULL;
1571 } else if (strstr(result->value, "Full")) {
1572 info->charge_now = CHARGER_DISCHARGING;
1573 info->charge_full = CHARGING_FULL;
1574 } else if (strstr(result->value, "Not charging")) {
1575 info->charge_now = CHARGER_ABNORMAL;
1576 info->charge_full = CHARGING_NOT_FULL;
1578 snprintf(info->status_s, sizeof(info->status_s), "%s", result->value);
1579 } else if (MATCH(result->name, CAPACITY)) {
1580 info->capacity = atoi(result->value);
1581 } else if (MATCH(result->name, TEMPERATURE)) {
1582 info->temperature = atoi(result->value) / 10;
1583 } else if (MATCH(result->name, VOLTAGE_NOW)) {
1584 info->voltage_now = atoi(result->value);
1585 } else if (MATCH(result->name, VOLTAGE_AVG)) {
1586 info->voltage_average = atoi(result->value);
1587 } else if (MATCH(result->name, CURRENT_NOW)) {
1588 info->current_now = atoi(result->value);
1589 } else if (MATCH(result->name, CURRENT_AVG)) {
1590 info->current_average = atoi(result->value);
1591 } else if (MATCH(result->name, CHARGE_HEALTH)) {
1592 snprintf(info->health_s, sizeof(info->health_s), "%s", result->value);
1598 static int power_supply_probe(void *data)
1603 if (battery_dev_available)
1606 ret_val = hal_device_battery_get_backend();
1608 _E("There is no HAL for battery.");
1609 battery_dev_available = false;
1610 if (access(POWER_PATH, R_OK) == 0)
1611 return 0; /* Just power_supply uevent is used */
1616 _I("Battery device structure load success.");
1617 battery_dev_available = true;
1622 * Set battery vconf as -ENOTSUP
1623 * These vconf key used by runtime-info and capi-system-device.
1625 r = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
1627 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
1628 r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, -ENOTSUP);
1630 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
1631 r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, -ENOTSUP);
1633 _E("Failed to set vconf value for battery level status: %d", vconf_get_ext_errno());
1634 _I("There is no battery device: %d", ret_val);
1638 static void add_power_supply_handler(void)
1642 if (battery_dev_available) {
1643 hal_device_battery_register_changed_event(battery_changed, NULL);
1644 hal_device_battery_get_current_state(battery_changed, NULL);
1646 ret_val = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
1648 _E("Failed to load %s, %d Use default value!", POWER_SUPPLY_UEVENT, ret_val);
1650 /* register power subsystem */
1651 register_kernel_uevent_control(&uh);
1655 static void remove_power_supply_handler(void)
1657 if (battery_dev_available)
1658 hal_device_battery_unregister_changed_event(battery_changed);
1660 unregister_kernel_uevent_control(&uh);
1663 static int event_handler_state_changed(void *data)
1665 device_notifier_state_e state = *(device_notifier_state_e *)data;
1667 if (old_state == state)
1672 if (state == DEVICE_NOTIFIER_STATE_START)
1673 add_power_supply_handler();
1674 else if (state == DEVICE_NOTIFIER_STATE_STOP)
1675 remove_power_supply_handler();
1680 static void power_supply_init(void *data)
1684 memset(&battery, 0, sizeof(struct battery_status));
1685 memset(&old_battery, 0, sizeof(struct battery_status));
1686 battery.charger_charging = CHARGER_ENABLED;
1687 battery.misc = MISC_NONE;
1688 battery.freq_strength = 0;
1690 /* It will be true on initializing battery structure */
1691 battery_initialized = false;
1693 /* process check battery timer until booting done */
1694 power_supply_timer_start();
1696 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
1697 register_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1699 ret_dbus = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
1701 _E("Failed to init dbus method: %d", ret_dbus);
1703 battery_ops_init((void *)battery_plgn);
1706 static void power_supply_exit(void *data)
1708 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_STOP;
1710 unregister_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1712 event_handler_state_changed((void *)&state);
1714 battery_ops_exit(NULL);
1715 battery_dev_available = false;
1718 static const struct device_ops power_supply_ops = {
1719 DECLARE_NAME_LEN("power_supply"),
1720 .probe = power_supply_probe,
1721 .init = power_supply_init,
1722 .exit = power_supply_exit,
1725 DEVICE_OPS_REGISTER(&power_supply_ops)
1727 static void __CONSTRUCTOR__ initialize(void)
1729 disp_plgn = get_var_display_plugin();
1731 _E("Failed to get display plugin variable.");
1733 battery_plgn = get_var_battery_plugin();
1735 _E("Failed to get battery plugin variable.");