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 "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 REMOVE_POPUP "remove_battery_popups"
68 #define DISCONNECT_POPUP "battdisconnect"
70 #define CHARGER_WIRELESS_TYPE_BT 10
71 #define CHARGER_WIRELESS_TYPE_3G 22
72 #define CHARGER_INCOMPATIBLE_TYPE 11
73 #define CHARGER_D2D_TYPE 110
74 #define WIRELESS_CHARGER_CONNECTED 2
76 #define SIGNAL_CHARGEERR_RESPONSE "ChargeErrResponse"
77 #define SIGNAL_TEMP_GOOD "TempGood"
79 #define ABNORMAL_CHECK_TIMER_INTERVAL 60
81 #define METHOD_FULL_NOTI_ON "BatteryFullNotiOn"
82 #define METHOD_FULL_NOTI_OFF "BatteryFullNotiOff"
83 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
85 #define CHARGER_CHARGE_ON_NODE "/sys/class/power_supply/battery/chg_on"
88 #define BATTERY_CHECK_TIMER_INTERVAL 500 /* 0.5 second */
89 #define LCD_DIM_TIME_IN_BATTERY_HEALTH 10000 /* ms */
91 static void uevent_power_handler(struct udev_device *dev);
92 static const struct uevent_handler uh = {
93 .subsystem = POWER_SUBSYSTEM,
94 .uevent_func = uevent_power_handler,
97 struct battery_status battery;
98 struct battery_status old_battery;
100 static int online_status;
101 static int abnormal_health_popup_timer;
103 static guint power_timer;
104 struct battery_plugin battery_plgn;
106 bool battery_do_not_disturb(void);
107 static int battery_pm_change_internal(int pid, int s_bits);
108 static int display_changed(void *data);
109 static int booting_done(void *data);
110 static void update_health(enum battery_noti_status status);
112 static struct battery_device *battery_dev;
114 static int load_uevent(struct parse_result *result, void *user_data);
115 static int event_handler_state_changed(void *data);
117 static int lowbat_execute(void *data)
119 static const struct device_ops *lowbat_ops;
121 FIND_DEVICE_INT(lowbat_ops, "lowbat");
122 return device_execute(lowbat_ops, data);
125 static int power_supply_broadcast_str(char *sig, char *status)
127 static char old_sig[32];
128 static char old_status[32];
132 if (!sig || !status) {
133 _E("there is no signal name");
137 if (strncmp(old_sig, sig, strlen(sig)) == 0 && strncmp(old_status, status, strlen(status)) == 0)
140 snprintf(old_sig, sizeof(old_sig), "%s", sig);
141 snprintf(old_status, sizeof(old_status), "%s", status);
145 ret = dbus_handle_emit_dbus_signal(NULL,
146 DEVICED_PATH_BATTERY,
147 DEVICED_INTERFACE_BATTERY,
149 g_variant_new("(s)", str));
157 static void pm_check_and_change(int bInserted)
161 if (old == bInserted)
164 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
167 static void health_status_broadcast(void)
169 dbus_handle_emit_dbus_signal(NULL,
170 DEVICED_PATH_BATTERY,
171 DEVICED_INTERFACE_BATTERY,
176 static void full_noti_cb(GVariant *var, void *user_data, GError *err)
183 if (!dh_get_param_from_var(var, "(i)", &id)) {
184 _E("Failed to notify full: no message(%s)", g_variant_get_type_string(var));
189 _D("Inserted battery full noti(%d).", noti_id);
192 g_variant_unref(var);
195 static void noti_off_cb(GVariant *var, void *user_data, GError *err)
199 if (!dh_get_param_from_var(var, "(i)", &ret)) {
200 _E("Failed to off notification: no message(%s)", g_variant_get_type_string(var));
204 _D("Noti off: %d", ret);
207 g_variant_unref(var);
210 int check_power_supply_noti(void)
214 if (vconf_get_bool("db/setting/blockmode_wearable", &block) != 0)
221 static int send_full_noti(enum charge_full_type state)
227 noti = check_power_supply_noti();
234 for (retry = RETRY_MAX; retry > 0; retry--) {
235 ret = dbus_handle_method_async_with_reply(POPUP_BUS_NAME,
237 POPUP_INTERFACE_NOTI,
239 NULL, NULL, full_noti_cb, -1, NULL);
241 _D("Created battery full noti.");
245 _E("Failed to call dbus method: %d", ret);
247 case CHARGING_NOT_FULL:
250 for (retry = RETRY_MAX; retry > 0; retry--) {
251 ret = dbus_handle_method_async_with_reply_var(POPUP_BUS_NAME,
253 POPUP_INTERFACE_NOTI,
254 METHOD_FULL_NOTI_OFF,
255 g_variant_new("(i)", noti_id),
256 noti_off_cb, -1, NULL);
258 _D("Deleted battery full noti.");
263 _E("Failed to call dbus method: %d", ret);
269 static void charge_noti_on(GVariant *var, void *user_data, GError *err)
276 if (!dh_get_param_from_var(var, "(i)", &id)) {
277 _E("Failed to notify charge: no message(%s)", g_variant_get_type_string(var));
281 _D("Inserted battery charge noti: %d", id);
284 g_variant_unref(var);
287 static int send_charge_noti(void)
292 for (retry = RETRY_MAX; retry > 0; retry--) {
293 ret = dbus_handle_method_async_with_reply(POPUP_BUS_NAME,
295 POPUP_INTERFACE_NOTI,
296 METHOD_CHARGE_NOTI_ON,
297 NULL, NULL, charge_noti_on, -1, NULL);
299 _I("Created battery charge noti.");
303 _E("Failed to call dbus method: %d", ret);
307 static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
309 static int charger = CHARGER_DISCHARGING;
310 static int full = CHARGING_NOT_FULL;
313 if (type == DEVICE_NOTI_BATT_CHARGE) {
314 if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
316 charger = CHARGER_CHARGING;
317 } else if (status == DEVICE_NOTI_OFF && charger == CHARGER_CHARGING)
318 charger = CHARGER_DISCHARGING;
319 } else if (type == DEVICE_NOTI_BATT_FULL) {
320 if (status == DEVICE_NOTI_ON && full == CHARGING_NOT_FULL) {
321 ret = send_full_noti(CHARGING_FULL);
323 full = CHARGING_FULL;
324 } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
325 ret = send_full_noti(CHARGING_NOT_FULL);
327 full = CHARGING_NOT_FULL;
332 int power_supply_broadcast(char *sig, int status)
335 static char sig_old[32];
340 _E("There is no signal name.");
343 if (strncmp(sig_old, sig, strlen(sig)) == 0 && old == status) {
344 _D("Skip broadcasting same signal(%s) and status(%d).", sig, status);
350 if (battery.charger_charging == CHARGER_DISABLED) {
351 ret = sys_get_int(CHARGER_CHARGE_ON_NODE, &chg_on);
352 if (ret == 0 && battery.charger_charging != chg_on) {
353 ret = sys_set_int(CHARGER_CHARGE_ON_NODE, battery.charger_charging);
354 _I("%s to change status with %d", ((ret == 0) ? "success" : "fail"), battery.charger_charging);
356 if (strncmp(sig, CHARGE_NOW_SIGNAL, strlen(CHARGE_NOW_SIGNAL)) == 0) {
357 _I("Skip signal while charger disabled.");
362 snprintf(sig_old, sizeof(sig_old), "%s", sig);
364 ret = dbus_handle_emit_dbus_signal(NULL,
365 DEVICED_PATH_BATTERY,
366 DEVICED_INTERFACE_BATTERY,
368 g_variant_new("(i)", status));
375 static void noti_batt_full(void)
377 static int bat_full_noti;
380 if (!battery.charge_full && bat_full_noti == 1) {
381 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
383 /* off the full charge state */
384 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
386 if (battery.charge_full && bat_full_noti == 0) {
387 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
389 /* turn on LCD, if battery is full charged */
390 noti = check_power_supply_noti();
392 battery_pm_change_internal(INTERNAL_LOCK_BATTERY_FULL, LCD_NORMAL);
396 /* on the full charge state */
397 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
401 static void check_power_supply(int state)
403 pm_check_and_change(state);
404 if (disp_plgn.update_pm_setting)
405 disp_plgn.update_pm_setting(SETTING_CHARGING, state);
408 static void charger_state_send_system_event(int state)
413 case CHARGE_STATUS_CHARGING:
414 str = EVT_VAL_BATTERY_CHARGER_CHARGING;
416 case CHARGE_STATUS_FULL:
417 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
418 CRITICAL_LOG("Battery %s", str);
420 case CHARGE_STATUS_DISCHARGING:
421 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
423 case CHARGE_STATUS_CONNECTED:
424 str = EVT_VAL_BATTERY_CHARGER_CONNECTED;
425 CRITICAL_LOG("Battery %s", str);
427 case CHARGE_STATUS_DISCONNECTED:
428 str = EVT_VAL_BATTERY_CHARGER_DISCONNECTED;
429 CRITICAL_LOG("Battery %s", str);
432 _E("Invalid parameter: %d", state);
436 _D("System_event: %s", str);
438 event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str);
441 int changed_battery_cf(int status)
443 if (status == PRESENT_ABNORMAL)
444 return launch_system_app(APP_ABNORMAL, 2, APP_KEY_TYPE, DISCONNECT_POPUP);
445 return launch_system_app(APP_REMOVE, 2, APP_KEY_TYPE, REMOVE_POPUP);
448 static void update_present(enum battery_noti_status status)
451 CRITICAL_LOG("Charge(%d) present(%d, old: %d)", battery.charge_now, battery.present, old_battery.present);
453 old_battery.present = battery.present;
454 if (status == DEVICE_NOTI_ON) {
455 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
456 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
457 if (disp_plgn.pm_lock_internal)
458 disp_plgn.pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
460 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
461 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&battery.present);
462 if (disp_plgn.pm_unlock_internal)
463 disp_plgn.pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
465 changed_battery_cf(battery.present);
468 void remove_health_popup(void)
472 ret = launch_system_app(APP_REMOVE, 2, APP_KEY_TYPE, REMOVE_POPUP);
474 _E("Failed to launch remove battery popup(%d)", ret);
477 static void launch_health_popup(void)
479 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
480 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
481 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_DIM);
482 if (disp_plgn.pm_unlock_internal)
483 disp_plgn.pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
484 if (disp_plgn.pm_lock_internal)
485 disp_plgn.pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, LCD_DIM_TIME_IN_BATTERY_HEALTH);
486 if (battery.health == HEALTH_LOW)
487 battery_charge_err_low_act(NULL);
488 else if (battery.health == HEALTH_HIGH)
489 battery_charge_err_high_act(NULL);
492 /* Warning popup for every 1 minutes until
493 * battery health returns to normal. */
494 static gboolean health_popup_cb(void *data)
496 launch_health_popup();
497 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
498 return G_SOURCE_CONTINUE;
501 static void update_health(enum battery_noti_status status)
503 _I("Charge(%d) health(%d, old: %d)", battery.charge_now, battery.health, old_battery.health);
505 old_battery.health = battery.health;
506 if (status == DEVICE_NOTI_ON) {
507 CRITICAL_LOG("Popup: Battery health status is not good, %s.", battery.health_s);
508 launch_health_popup();
509 if (!abnormal_health_popup_timer)
510 abnormal_health_popup_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL, health_popup_cb, NULL);
512 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
513 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
514 if (disp_plgn.pm_unlock_internal) {
515 disp_plgn.pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
516 disp_plgn.pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_OFF, PM_SLEEP_MARGIN);
518 health_status_broadcast();
519 if (abnormal_health_popup_timer) {
520 CRITICAL_LOG("Battery health returned to normal. Stop abnormal popup.");
521 g_source_remove(abnormal_health_popup_timer);
522 abnormal_health_popup_timer = 0;
524 remove_health_popup();
528 static void update_ovp(enum battery_noti_status status)
530 static int old = DEVICE_NOTI_OFF;
536 _I("Charge(%d) ovp(%d, old: %d) with lcd(%s)", battery.charge_now, battery.health,
537 old_battery.health, (status == DEVICE_NOTI_ON) ? "dim" : "normal");
539 old_battery.health = battery.health;
540 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)&battery.health);
541 battery_pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
544 static void check_abnormal_status(void)
546 if (old_battery.health != HEALTH_LOW && old_battery.health != HEALTH_HIGH &&
547 (battery.health == HEALTH_LOW || battery.health == HEALTH_HIGH))
548 update_health(DEVICE_NOTI_ON);
549 else if ((old_battery.health == HEALTH_LOW || old_battery.health == HEALTH_HIGH) &&
550 battery.health != HEALTH_LOW && battery.health != HEALTH_HIGH)
551 update_health(DEVICE_NOTI_OFF);
553 if (old_battery.present != PRESENT_ABNORMAL && battery.present == PRESENT_ABNORMAL)
554 update_present(DEVICE_NOTI_ON);
555 else if (battery.present != PRESENT_ABNORMAL && old_battery.present == PRESENT_ABNORMAL)
556 update_present(DEVICE_NOTI_OFF);
558 if (old_battery.health != HEALTH_OVP && battery.health == HEALTH_OVP)
559 update_ovp(DEVICE_NOTI_ON);
560 else if (battery.health != HEALTH_OVP && old_battery.health == HEALTH_OVP)
561 update_ovp(DEVICE_NOTI_OFF);
564 static bool update_online(void)
568 bool broadcast = false;
570 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
571 battery.charger_charging == CHARGER_DISABLED) {
572 battery.charger_charging = CHARGER_ENABLED;
573 ret = sys_get_int(CHARGER_CHARGE_ON_NODE, &chg_on);
574 if (ret == 0 && battery.charger_charging != chg_on) {
575 ret = sys_set_int(CHARGER_CHARGE_ON_NODE, battery.charger_charging);
576 _I("%s to change status with %d", ((ret == 0) ? "success" : "fail"), battery.charger_charging);
580 if (battery.online > POWER_SUPPLY_TYPE_BATTERY &&
581 online_status == VCONFKEY_SYSMAN_CHARGER_DISCONNECTED) {
582 online_status = VCONFKEY_SYSMAN_CHARGER_CONNECTED;
583 extcon_update_count(EXTCON_TA, 1);
584 check_power_supply(online_status);
585 charger_state_send_system_event(CHARGE_STATUS_CONNECTED);
586 if (old_battery.charge_status != battery.charge_status)
587 charger_state_send_system_event(battery.charge_status);
589 } else if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
590 online_status == VCONFKEY_SYSMAN_CHARGER_CONNECTED) {
591 online_status = VCONFKEY_SYSMAN_CHARGER_DISCONNECTED;
592 check_power_supply(online_status);
593 if (old_battery.charge_status != battery.charge_status)
594 charger_state_send_system_event(battery.charge_status);
595 charger_state_send_system_event(CHARGE_STATUS_DISCONNECTED);
598 if (old_battery.charge_status != battery.charge_status)
599 charger_state_send_system_event(battery.charge_status);
602 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY)
603 battery.online_type = CHARGER_TYPE_NONE;
604 else if (battery.online == CHARGER_WIRELESS_TYPE_BT ||
605 battery.online == CHARGER_WIRELESS_TYPE_3G)
606 battery.online_type = CHARGER_TYPE_WIRELESS;
607 else if (battery.online == CHARGER_INCOMPATIBLE_TYPE)
608 battery.online_type = CHARGER_TYPE_INCOMPATIBLE;
609 else if (battery.online == CHARGER_D2D_TYPE)
610 battery.online_type = CHARGER_TYPE_D2D;
612 battery.online_type = CHARGER_TYPE_WIRE;
617 static void check_charge_status(const char *env_value)
621 if (env_value == NULL)
624 len = strlen(env_value);
625 if (strncmp(env_value, CHARGEFULL_NAME, len) == 0)
626 battery.charge_status = CHARGE_STATUS_FULL;
627 else if (strncmp(env_value, CHARGENOW_NAME, len) == 0)
628 battery.charge_status = CHARGE_STATUS_CHARGING;
629 else if (strncmp(env_value, DISCHARGE_NAME, len) == 0)
630 battery.charge_status = CHARGE_STATUS_DISCHARGING;
631 else if (strncmp(env_value, NOTCHARGE_NAME, len) == 0)
632 battery.charge_status = CHARGE_STATUS_NOT_CHARGING;
634 battery.charge_status = CHARGE_STATUS_UNKNOWN;
636 if (battery.charge_status == CHARGE_STATUS_FULL) {
637 battery.charge_full = CHARGING_FULL;
638 battery.charge_now = CHARGER_DISCHARGING;
639 } else if (battery.charge_status == CHARGE_STATUS_CHARGING) {
640 battery.charge_full = CHARGING_NOT_FULL;
641 battery.charge_now = CHARGER_CHARGING;
642 } else if (battery.charge_status == CHARGE_STATUS_DISCHARGING) {
643 battery.charge_full = CHARGING_NOT_FULL;
644 battery.charge_now = CHARGER_DISCHARGING;
645 } else if (battery.charge_status == CHARGE_STATUS_NOT_CHARGING) {
646 battery.charge_full = CHARGING_NOT_FULL;
647 battery.charge_now = CHARGER_ABNORMAL;
649 battery.charge_full = CHARGING_NOT_FULL;
650 battery.charge_now = CHARGER_DISCHARGING;
654 static void check_health_status(const char *env_value)
658 if (env_value == NULL) {
659 battery.health = HEALTH_GOOD;
663 snprintf(battery.health_s, sizeof(battery.health_s), "%s", env_value);
665 len = strlen(env_value);
666 if (strncmp(env_value, OVERHEAT_NAME, len) == 0)
667 battery.health = HEALTH_HIGH;
668 else if (strncmp(env_value, TEMPCOLD_NAME, len) == 0)
669 battery.health = HEALTH_LOW;
670 else if (strncmp(env_value, OVERVOLT_NAME, len) == 0)
671 battery.health = HEALTH_OVP;
672 else if (strncmp(env_value, GOOD_NAME, len) == 0)
673 battery.health = HEALTH_GOOD;
675 battery.health = HEALTH_NO_OPT;
678 static void check_misc_status(const char *env_value)
680 if (env_value == NULL) {
681 battery.misc = MISC_NONE;
684 battery.misc = atoi(env_value);
687 static void check_freq_strength_status(const char *env_value)
689 if (env_value == NULL) {
690 battery.freq_strength = 0;
693 battery.freq_strength = atoi(env_value);
696 static void check_online_status(const char *env_value)
698 if (env_value == NULL)
700 battery.online = atoi(env_value);
703 static void check_present_status(const char *env_value)
705 if (env_value == NULL) {
706 battery.present = PRESENT_NORMAL;
709 battery.present = atoi(env_value);
712 static void check_capacity_status(const char *env_value)
714 if (env_value == NULL)
716 battery.capacity = atoi(env_value);
719 static void update_capacity_full(void)
724 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY ||
726 old >= battery.capacity) {
727 old = battery.capacity;
730 delta = battery.capacity - old;
731 old = battery.capacity;
732 extcon_update_count(EXTCON_BATTERY_FULL, delta);
735 static void update_battery_cycle(void)
737 static int first = 1;
743 extcon_update_count(EXTCON_BATTERY_CYCLE, 0);
747 if (battery.online > POWER_SUPPLY_TYPE_BATTERY ||
749 old <= battery.capacity) {
750 old = battery.capacity;
753 delta = old - battery.capacity;
754 old = battery.capacity;
755 extcon_update_count(EXTCON_BATTERY_CYCLE, delta);
758 static void process_power_supply(void *data)
760 bool broadcasted = true;
764 _D("process_power_supply()");
765 if (disp_plgn.pm_lock_internal) {
766 lock = disp_plgn.pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
767 if (old_battery.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
768 ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
770 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
772 if (power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now) < 0)
777 /* Comment out below code because it doesn't work.
778 "battery.status_s" is updated by uevent, POWER_SUPPLY_STATUS.
779 And it's always "Full" after target is fully charged, even though the target internally repeats charging and discharging.
780 So, to compare old_battery.status_s and battery.status_s is meaningless.
782 //if (!strcmp(old_battery.status_s, CHARGEFULL_NAME) &&
783 // !strcmp(battery.status_s, CHARGENOW_NAME)) {
784 // battery_pm_change_internal(INTERNAL_LOCK_BATTERY, LCD_NORMAL);
787 if (old_battery.charge_full != battery.charge_full)
788 if (power_supply_broadcast(CHARGE_FULL_SIGNAL, battery.charge_full) < 0)
791 if (strncmp(old_battery.health_s, battery.health_s, strlen(battery.health_s))) {
792 snprintf(old_battery.health_s, sizeof(old_battery.health_s), "%s", battery.health_s);
793 if (power_supply_broadcast_str(CHARGE_HEALTH_SIGNAL, battery.health_s) < 0)
797 if (old_battery.capacity != battery.capacity) {
798 ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
800 _E("Failed to set vconf value for battery capacity: %d", vconf_get_ext_errno());
802 if (power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity) < 0)
806 (void)lowbat_execute(data);
808 if (update_online()) {
809 ret = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, online_status);
811 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
813 if (power_supply_broadcast(CHARGER_STATUS_SIGNAL, online_status) < 0)
817 if (old_battery.online_type != battery.online_type) {
818 ret = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_TYPE, battery.online_type);
820 _E("Failed to set vconf value for charger type: %d", vconf_get_ext_errno());
822 if (power_supply_broadcast(CHARGER_TYPE_SIGNAL, battery.online_type) < 0)
826 if (old_battery.misc != battery.misc)
827 if (power_supply_broadcast(CHARGE_MISC_EVENT_SIGNAL, battery.misc) < 0)
830 if (old_battery.freq_strength != battery.freq_strength)
831 if (power_supply_broadcast(CHARGE_FREQ_STRENGTH_SIGNAL, battery.freq_strength) < 0)
834 if (old_battery.charge_full != battery.charge_full)
837 if (old_battery.charge_now != battery.charge_now ||
838 old_battery.charge_full != battery.charge_full ||
839 old_battery.capacity != battery.capacity ||
840 old_battery.health != battery.health ||
841 old_battery.misc != battery.misc ||
842 old_battery.freq_strength != battery.freq_strength ||
843 old_battery.online_type != battery.online_type)
844 _I("Signal(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s) %s(%d)",
846 CHARGER_STATUS_SIGNAL, online_status,
847 CHARGER_TYPE_SIGNAL, battery.online_type,
848 CHARGE_NOW_SIGNAL, battery.charge_now,
849 CHARGE_FULL_SIGNAL, battery.charge_full,
850 CHARGE_CAPACITY_SIGNAL, battery.capacity,
851 CHARGE_LEVEL_SIGNAL, battery.charging_level,
852 CHARGE_MISC_EVENT_SIGNAL, battery.misc,
853 CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s,
854 CHARGE_FREQ_STRENGTH_SIGNAL, battery.freq_strength);
856 old_battery.capacity = battery.capacity;
857 old_battery.charging_level = battery.charging_level;
858 old_battery.online = battery.online;
859 old_battery.online_type = battery.online_type;
860 old_battery.charge_status = battery.charge_status;
861 old_battery.charge_full = battery.charge_full;
863 old_battery.misc = battery.misc;
864 old_battery.freq_strength = battery.freq_strength;
865 snprintf(old_battery.status_s, sizeof(old_battery.status_s), "%s", battery.status_s);
867 check_abnormal_status();
869 device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
870 if (old_battery.charge_now != battery.charge_now) {
871 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, &battery.charge_now);
872 old_battery.charge_now = battery.charge_now;
874 update_capacity_full();
875 update_battery_cycle();
877 if (disp_plgn.pm_unlock_internal)
878 disp_plgn.pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
882 static void uevent_power_handler(struct udev_device *dev)
884 struct udev_list_entry *list_entry;
885 const char *env_name;
886 const char *env_value;
887 bool matched = false;
890 udev_list_entry_foreach(list_entry,
891 udev_device_get_properties_list_entry(dev)) {
892 env_name = udev_list_entry_get_name(list_entry);
896 if (!strncmp(env_name, CHARGE_NAME, sizeof(CHARGE_NAME))) {
897 env_value = udev_list_entry_get_value(list_entry);
900 if (!strncmp(env_value, BATTERY_NAME,
901 sizeof(BATTERY_NAME))) {
911 env_value = udev_device_get_property_value(dev, CHARGE_STATUS);
912 check_charge_status(env_value);
913 env_value = udev_device_get_property_value(dev, CHARGE_ONLINE);
914 check_online_status(env_value);
915 env_value = udev_device_get_property_value(dev, CHARGE_HEALTH);
916 check_health_status(env_value);
917 env_value = udev_device_get_property_value(dev, CHARGE_MISC_EVENT);
918 check_misc_status(env_value);
919 env_value = udev_device_get_property_value(dev, CHARGE_PRESENT);
920 check_present_status(env_value);
921 env_value = udev_device_get_property_value(dev, CAPACITY);
922 check_capacity_status(env_value);
924 ret = booting_done(NULL);
926 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
927 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
929 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
932 process_power_supply(&battery.capacity);
935 static int battery_state(struct battery_info *info)
937 static struct battery_status prev_status;
940 memcpy(&prev_status, &battery, sizeof(battery));
944 if (battery.capacity != 0 && prev_status.capacity == battery.capacity &&
945 prev_status.charge_status == battery.charge_status &&
946 prev_status.charge_full == battery.charge_full &&
947 prev_status.charge_now == battery.charge_now &&
948 prev_status.health == battery.health &&
949 prev_status.present == battery.present &&
950 prev_status.online == battery.online &&
951 prev_status.freq_strength == battery.freq_strength)
954 prev_status.capacity = battery.capacity;
955 prev_status.charge_status = battery.charge_status;
956 prev_status.charge_full = battery.charge_full;
957 prev_status.charge_now = battery.charge_now;
958 prev_status.health = battery.health;
959 prev_status.present = battery.present;
960 prev_status.online = battery.online;
961 prev_status.freq_strength = battery.freq_strength;
963 _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%d) Pres(%d) Curr(%d,%d)",
965 battery.charge_now == CHARGER_CHARGING ? "Charging"
966 : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
974 info->current_average);
978 static void battery_changed(struct battery_info *info, void *data)
983 (void)battery_state(NULL);
988 snprintf(battery.status_s, sizeof(battery.status_s),
990 check_charge_status(info->status);
992 battery.status_s[0] = '\0';
995 snprintf(battery.health_s, sizeof(battery.health_s),
997 check_health_status(info->health);
999 battery.health_s[0] = '\0';
1001 if (info->power_source)
1002 snprintf(battery.power_source_s, sizeof(battery.power_source_s),
1003 "%s", info->power_source);
1005 battery.power_source_s[0] = '\0';
1007 battery.online = info->online;
1008 battery.present = info->present;
1009 battery.capacity = info->capacity;
1010 battery.current_now = info->current_now;
1011 battery.current_average = info->current_average;
1012 battery.temperature = info->temperature;
1013 battery.freq_strength = info->freq_strength;
1015 ret = battery_state(info);
1019 ret = booting_done(NULL);
1021 /* If the same notification is requested repeatedly, it is ignored by power_supply_noti().
1022 * A notification will be triggered only when charge_status changes between
1023 * CHARGE_STATUS_CHARGING/FULL <-> CHARGE_STATUS_DISCHARGING. */
1024 if (battery.charge_status == CHARGE_STATUS_CHARGING || battery.charge_status == CHARGE_STATUS_FULL)
1025 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
1026 else if (battery.charge_status == CHARGE_STATUS_DISCHARGING)
1027 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
1031 battery.health = HEALTH_GOOD;
1032 battery.present = PRESENT_NORMAL;
1035 process_power_supply(&battery.capacity);
1039 static void power_supply_status_init(void)
1043 if (battery_dev && battery_dev->get_current_state) {
1044 r = battery_dev->get_current_state(battery_changed, NULL);
1045 if (r < 0 || battery.capacity < 0) {
1046 _E("Failed to get battery capacity (capa: %d, ret: %d)", battery.capacity, r);
1050 r = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
1052 _E("Failed to load %s, %d Use default value.", POWER_SUPPLY_UEVENT, r);
1055 battery.health = HEALTH_GOOD;
1056 battery.present = PRESENT_NORMAL;
1057 process_power_supply(&battery.capacity);
1061 static gboolean power_supply_update(void *data)
1063 power_supply_status_init();
1064 return G_SOURCE_CONTINUE;
1067 static void power_supply_timer_start(void)
1069 _D("Battery init timer during booting.");
1070 power_timer = g_timeout_add(BATTERY_CHECK_TIMER_INTERVAL,
1071 power_supply_update, NULL);
1072 if (power_timer == 0)
1073 _E("Failed to add battery init timer during booting.");
1075 _I("Started battery init timer during booting.");
1078 static void power_supply_timer_stop(void)
1080 if (power_timer == 0)
1082 _I("Stop battery init timer during booting.");
1083 g_source_remove(power_timer);
1087 static GVariant *dbus_get_charger_status(GDBusConnection *conn,
1088 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1089 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1093 ret = vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &status);
1095 _E("Failed to get vconf value for charger status: %d", vconf_get_ext_errno());
1098 return g_variant_new("(i)", status);
1101 static GVariant *dbus_get_charger_type(GDBusConnection *conn,
1102 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1103 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1105 int type = battery.online_type;
1107 return g_variant_new("(i)", type);
1110 static GVariant *dbus_charger_charging(GDBusConnection *conn,
1111 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1112 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1118 g_variant_get(param, "(i)", &val);
1120 if (val != CHARGER_ENABLED && val != CHARGER_DISABLED) {
1121 _E("There is no valid input: %d", battery.charger_charging);
1125 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY) {
1126 _E("There is no charger(%d) input(%d).", battery.online, battery.charger_charging);
1130 ret = sys_get_int(CHARGER_CHARGE_ON_NODE, &chg_on);
1131 if (ret == 0 && val != chg_on) {
1132 battery.charger_charging = val;
1133 ret = sys_set_int(CHARGER_CHARGE_ON_NODE, battery.charger_charging);
1134 CRITICAL_LOG("chg_on changed to %d %s", battery.charger_charging,
1135 (ret == 0) ? "success" : "fail");
1136 _I("%s to change status with %d.", ((ret == 0) ? "success" : "fail"), battery.charger_charging);
1138 _I("Skip change status with %d (ret %d prev %d)", val, ret, battery.charger_charging);
1141 return g_variant_new("(i)", ret);
1144 static GVariant *dbus_get_charge_now(GDBusConnection *conn,
1145 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1146 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1150 ret = battery.charge_now;
1152 return g_variant_new("(i)", ret);
1155 static GVariant *dbus_get_charge_level(GDBusConnection *conn,
1156 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1157 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1161 ret = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &val);
1163 _E("Failed to get vconf value for battery status low: %d", vconf_get_ext_errno());
1167 return g_variant_new("(i)", val);
1170 static GVariant *dbus_get_percent(GDBusConnection *conn,
1171 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1172 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1176 ret = battery.capacity;
1178 return g_variant_new("(i)", ret);
1181 static GVariant *dbus_get_percent_raw(GDBusConnection *conn,
1182 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1183 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1189 return g_variant_new("(i)", ret);
1192 static GVariant *dbus_is_full(GDBusConnection *conn,
1193 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1194 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1198 ret = battery.charge_full;
1200 return g_variant_new("(i)", ret);
1203 static GVariant *dbus_get_health(GDBusConnection *conn,
1204 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1205 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1209 str = battery.health_s;
1211 return g_variant_new("(s)", str);
1214 static GVariant *dbus_get_misc(GDBusConnection *conn,
1215 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1216 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1222 return g_variant_new("(i)", ret);
1226 static GVariant *dbus_get_freq_strength(GDBusConnection *conn,
1227 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1228 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1230 return g_variant_new("(i)", battery.freq_strength);
1233 static GVariant *dbus_power_supply_handler(GDBusConnection *conn,
1234 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1235 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1243 g_variant_get(param, "(sisssssss)", &type_str,
1254 _E("Message is invalid.");
1259 pid = dbus_connection_get_sender_pid(conn, sender);
1260 if (kill(pid, 0) == -1) {
1261 _E("Process(%d) does not exist, dbus ignored.", pid);
1265 check_capacity_status(argv[0]);
1266 check_charge_status(argv[1]);
1267 check_health_status(argv[2]);
1268 check_online_status(argv[3]);
1269 check_present_status(argv[4]);
1270 check_misc_status(argv[5]);
1271 check_freq_strength_status(argv[6]);
1273 battery_changed(NULL, NULL);
1274 snprintf(battery.status_s, sizeof(battery.status_s), "%s",
1275 (battery.charge_now == CHARGER_CHARGING) ? "Charging" :
1276 (battery.charge_now == CHARGER_ABNORMAL) ? "Not Charging" :
1277 (battery.charge_full == CHARGING_FULL) ? "Full" :
1279 _I("%s(%d) %s(f:%d n:%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d)",
1283 battery.charge_full,
1294 battery.freq_strength);
1296 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
1297 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
1299 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
1301 process_power_supply(&battery.capacity);
1312 return g_variant_new("(i)", ret);
1315 static void battery_get_info(struct battery_info *info, void *data)
1317 struct battery_info *bat = data;
1322 bat->status = strdup(info->status);
1323 bat->health = strdup(info->health);
1324 bat->power_source = strdup(info->power_source);
1325 bat->online = info->online;
1326 bat->present = info->present;
1327 bat->capacity = info->capacity;
1328 bat->current_now = info->current_now;
1329 bat->current_average = info->current_average;
1332 static GVariant *dbus_get_battery_info(GDBusConnection *conn,
1333 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1334 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1338 struct battery_info info = {0, };
1340 if (battery_dev && battery_dev->get_current_state) {
1341 ret = battery_dev->get_current_state(battery_get_info, &info);
1343 _E("Failed to get battery info: %d", ret);
1345 battery_changed(&info, NULL);
1348 free(info.power_source);
1350 if (vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val) == 0 &&
1351 val != VCONFKEY_SYSMAN_USB_DISCONNECTED)
1352 str = POWER_SOURCE_USB;
1353 else if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &val) == 0 &&
1354 val == VCONFKEY_SYSMAN_CHARGER_CONNECTED)
1355 str = POWER_SOURCE_AC;
1357 str = POWER_SOURCE_NONE;
1358 snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
1360 battery.current_now = -1; /* Not supported */
1361 battery.current_average = -1; /* Not supported */
1365 return g_variant_new("(isssiiiiiiii)", ret,
1368 battery.power_source_s,
1372 battery.current_now,
1373 battery.current_average,
1374 battery.voltage_now,
1375 battery.voltage_average,
1376 battery.temperature);
1379 static void update_battery_props(void)
1381 if (config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery) < 0)
1382 _E("Failed to check power supply uevent.");
1385 static GVariant *dbus_get_battery_props(GDBusConnection *conn,
1386 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1387 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1389 update_battery_props();
1391 return g_variant_new("(iiiiii)",
1393 battery.temperature,
1394 battery.voltage_now,
1395 battery.voltage_average,
1396 battery.current_now,
1397 battery.current_average);
1400 static const dbus_method_s dbus_methods[] = {
1401 { CHARGER_STATUS_SIGNAL, NULL, "i", dbus_get_charger_status },
1402 { CHARGE_NOW_SIGNAL, NULL, "i", dbus_get_charge_now },
1403 { CHARGE_LEVEL_SIGNAL, NULL, "i", dbus_get_charge_level },
1404 { CHARGE_CAPACITY_SIGNAL, NULL, "i", dbus_get_percent },
1405 { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
1406 { CHARGE_FULL_SIGNAL, NULL, "i", dbus_is_full },
1407 { CHARGE_HEALTH_SIGNAL, NULL, "s", dbus_get_health },
1408 { POWER_SUBSYSTEM, "sisssssss", "i", dbus_power_supply_handler },
1409 { "GetBatteryInfo", NULL, "isssiiiiiiii", dbus_get_battery_info },
1410 { CHARGER_TYPE_SIGNAL, NULL, "i", dbus_get_charger_type },
1411 { "ChargerCharging", "i", "i", dbus_charger_charging },
1412 { CHARGE_BATTERY_PROPERTIES, NULL, "iiiiii", dbus_get_battery_props },
1413 { CHARGE_MISC_EVENT_SIGNAL, NULL, "i", dbus_get_misc },
1414 { CHARGE_FREQ_STRENGTH_SIGNAL, NULL, "i", dbus_get_freq_strength},
1417 static const dbus_interface_u dbus_interface = {
1419 .name = DEVICED_INTERFACE_BATTERY,
1420 .methods = dbus_methods,
1421 .nr_methods = ARRAY_SIZE(dbus_methods),
1424 static int booting_done(void *data)
1427 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_START;
1431 done = *(int *)data;
1435 power_supply_timer_stop();
1436 event_handler_state_changed((void *)&state);
1438 _I("booting done %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d) %s(%d : %s)",
1439 CHARGER_STATUS_SIGNAL, online_status,
1440 CHARGE_NOW_SIGNAL, battery.charge_now,
1441 CHARGE_FULL_SIGNAL, battery.charge_full,
1442 CHARGE_CAPACITY_SIGNAL, battery.capacity,
1443 CHARGE_LEVEL_SIGNAL, battery.charging_level,
1444 CHARGE_MISC_EVENT_SIGNAL, battery.misc,
1445 CHARGE_HEALTH_SIGNAL, battery.health, battery.health_s);
1447 unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
1452 bool battery_do_not_disturb(void)
1457 if (display_changed(NULL) == S_LCDOFF) {
1458 r = vconf_get_bool(VCONFKEY_SETAPPL_BLOCKMODE_WEARABLE_BOOL, &block);
1460 _E("Failed to set vconf value for blockmode wearable: %d", vconf_get_ext_errno());
1461 r = vconf_get_bool(VCONFKEY_SETAPPL_THEATER_MODE_ENABLE, &block);
1463 _E("Failed to set vconf value for theator mode enable: %d", vconf_get_ext_errno());
1464 r = vconf_get_bool(VCONFKEY_SETAPPL_GOODNIGHT_MODE_ENABLE, &block);
1466 _E("Failed to set vconf value for goodnight mode enable: %d", vconf_get_ext_errno());
1470 _I("Skip lcd and popup(block %d).", block);
1477 static int battery_pm_change_internal(int pid, int s_bits)
1479 if (battery_do_not_disturb())
1482 if (disp_plgn.pm_change_internal)
1483 disp_plgn.pm_change_internal(pid, s_bits);
1488 static int display_changed(void *data)
1490 static enum state_t state;
1495 state = *(int *)data;
1500 static int load_uevent(struct parse_result *result, void *user_data)
1502 struct battery_status *info = user_data;
1507 if (MATCH(result->name, CHARGE_STATUS)) {
1508 if (strstr(result->value, "Charging")) {
1509 info->charge_now = CHARGER_CHARGING;
1510 info->charge_full = CHARGING_NOT_FULL;
1511 } else if (strstr(result->value, "Discharging")) {
1512 info->charge_now = CHARGER_DISCHARGING;
1513 info->charge_full = CHARGING_NOT_FULL;
1514 } else if (strstr(result->value, "Full")) {
1515 info->charge_now = CHARGER_DISCHARGING;
1516 info->charge_full = CHARGING_FULL;
1517 } else if (strstr(result->value, "Not charging")) {
1518 info->charge_now = CHARGER_ABNORMAL;
1519 info->charge_full = CHARGING_NOT_FULL;
1521 snprintf(info->status_s, sizeof(info->status_s), "%s", result->value);
1522 } else if (MATCH(result->name, CAPACITY)) {
1523 info->capacity = atoi(result->value);
1524 } else if (MATCH(result->name, TEMPERATURE)) {
1525 info->temperature = atoi(result->value);
1526 } else if (MATCH(result->name, VOLTAGE_NOW)) {
1527 info->voltage_now = atoi(result->value);
1528 } else if (MATCH(result->name, VOLTAGE_AVG)) {
1529 info->voltage_average = atoi(result->value);
1530 } else if (MATCH(result->name, CURRENT_NOW)) {
1531 info->current_now = atoi(result->value);
1532 } else if (MATCH(result->name, CURRENT_AVG)) {
1533 info->current_average = atoi(result->value);
1534 } else if (MATCH(result->name, CHARGE_HEALTH)) {
1535 snprintf(info->health_s, sizeof(info->health_s), "%s", result->value);
1541 static int power_supply_probe(void *data)
1543 struct hw_info *info;
1549 ret = hw_get_info(BATTERY_HARDWARE_DEVICE_ID,
1550 (const struct hw_info **)&info);
1551 if (ret < 0) { /* There is no HAL for battery */
1552 if (access(POWER_PATH, R_OK) == 0)
1553 return 0; /* Just power_supply uevent is used */
1558 _E("Failed to open battery device: open(NULL)");
1562 ret = info->open(info, NULL, (struct hw_common**)&battery_dev);
1564 _E("Failed to get battery device structure: %d", ret);
1568 if (!battery_dev || !battery_dev->get_current_state) {
1569 _E("get_current_state() is not supported by the Battery HAL.");
1573 _I("Battery device structure load success.");
1578 * Set battery vconf as -ENOTSUP
1579 * These vconf key used by runtime-info and capi-system-device.
1581 r = vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
1583 _E("Failed to set vconf value for charger status: %d", vconf_get_ext_errno());
1584 r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, -ENOTSUP);
1586 _E("Failed to set vconf value for battery charge now: %d", vconf_get_ext_errno());
1587 r = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, -ENOTSUP);
1589 _E("Failed to set vconf value for battery level status: %d", vconf_get_ext_errno());
1590 _I("There is no battery device: %d", ret);
1594 static void add_power_supply_handler(void)
1599 if (battery_dev->register_changed_event)
1600 battery_dev->register_changed_event(battery_changed, NULL);
1601 if (battery_dev->get_current_state)
1602 battery_dev->get_current_state(battery_changed, NULL);
1604 ret = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
1606 _E("Failed to load %s, %d Use default value!", POWER_SUPPLY_UEVENT, ret);
1608 /* register power subsystem */
1609 register_kernel_uevent_control(&uh);
1613 static void remove_power_supply_handler(void)
1616 battery_dev->unregister_changed_event(battery_changed);
1618 unregister_kernel_uevent_control(&uh);
1621 static int event_handler_state_changed(void *data)
1623 static device_notifier_state_e old = DEVICE_NOTIFIER_STATE_STOP;
1624 device_notifier_state_e state = *(device_notifier_state_e *)data;
1631 if (state == DEVICE_NOTIFIER_STATE_START)
1632 add_power_supply_handler();
1633 else if (state == DEVICE_NOTIFIER_STATE_STOP)
1634 remove_power_supply_handler();
1639 static void power_supply_init(void *data)
1643 memset(&battery, 0, sizeof(struct battery_status));
1644 memset(&old_battery, 0, sizeof(struct battery_status));
1645 battery.charger_charging = CHARGER_ENABLED;
1646 battery.misc = MISC_NONE;
1647 battery.freq_strength = 0;
1649 /* process check battery timer until booting done */
1650 power_supply_timer_start();
1652 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
1653 register_notifier(DEVICE_NOTIFIER_LCD, display_changed);
1654 register_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1656 ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
1658 _E("Failed to init dbus method: %d", ret);
1661 _E("Failed to init dbus signal: %d", ret);
1663 battery_ops_init((void *)&battery_plgn);
1666 static void power_supply_exit(void *data)
1668 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_STOP;
1670 unregister_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1672 event_handler_state_changed((void *)&state);
1674 battery_ops_exit(NULL);
1677 static const struct device_ops power_supply_ops = {
1678 DECLARE_NAME_LEN("power_supply"),
1679 .probe = power_supply_probe,
1680 .init = power_supply_init,
1681 .exit = power_supply_exit,
1684 DEVICE_OPS_REGISTER(&power_supply_ops)