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>
28 #include "core/devices.h"
29 #include "core/device-notifier.h"
30 #include "core/udev.h"
32 #include "core/config-parser.h"
33 #include "display/poll.h"
34 #include "display/setting.h"
35 #include "apps/apps.h"
36 #include "power-supply.h"
38 #include "extcon/extcon_count.h"
40 #define BATTERY_NAME "battery"
41 #define CHARGEFULL_NAME "Full"
42 #define CHARGENOW_NAME "Charging"
43 #define DISCHARGE_NAME "Discharging"
44 #define NOTCHARGE_NAME "Not charging"
45 #define OVERHEAT_NAME "Overheat"
46 #define TEMPCOLD_NAME "Cold"
47 #define OVERVOLT_NAME "Over voltage"
49 #define REMOVE_POPUP "remove_battery_popups"
53 #define SIGNAL_CHARGEERR_RESPONSE "ChargeErrResponse"
54 #define SIGNAL_TEMP_GOOD "TempGood"
56 #define ABNORMAL_CHECK_TIMER_INTERVAL 60
58 #define METHOD_FULL_NOTI_ON "BatteryFullNotiOn"
59 #define METHOD_FULL_NOTI_OFF "BatteryFullNotiOff"
60 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
63 #define BATTERY_CHECK_TIMER_INTERVAL (0.5)
65 enum power_supply_init_type {
66 POWER_SUPPLY_NOT_READY = 0,
67 POWER_SUPPLY_INITIALIZED = 1,
70 static void uevent_power_handler(struct udev_device *dev);
71 static const struct uevent_handler uh = {
72 .subsystem = POWER_SUBSYSTEM,
73 .uevent_func = uevent_power_handler,
76 struct battery_status battery;
77 struct battery_status old_battery;
79 static guint power_timer;
81 static int booting_done(void *data);
83 static struct battery_device *battery_dev;
85 static void lowbat_execute(void *data)
87 static const struct device_ops *lowbat_ops;
89 FIND_DEVICE_VOID(lowbat_ops, "lowbat");
90 device_execute(lowbat_ops, data);
93 static void pm_check_and_change(int bInserted)
100 pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
103 static int changed_battery_cf(enum present_type status)
107 if (status == PRESENT_ABNORMAL)
108 value = "battdisconnect";
110 value = "remove_battery_popups";
112 return launch_system_app(APP_DEFAULT,
113 2, APP_KEY_TYPE, value);
116 static void health_status_broadcast(void)
118 dbus_handle_broadcast_dbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
119 SIGNAL_TEMP_GOOD, NULL, NULL);
122 #ifdef TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE
123 static guint abnormal_timer;
125 static void abnormal_popup_timer_init(void)
127 if (abnormal_timer == NULL)
129 g_source_remove(abnormal_timer);
130 abnormal_timer = NULL;
131 _I("delete health timer");
134 static void health_timer_reset(void)
136 abnormal_timer = NULL;
139 static gboolean health_timer_cb(void *data)
141 int value = HEALTH_BAD;
143 health_timer_reset();
145 if (battery.health == HEALTH_GOOD)
146 return G_SOURCE_REMOVE;
148 _I("popup - Battery health status is not good");
149 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&value);
150 pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
151 pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
152 if (battery.temp == TEMP_LOW)
153 battery_charge_err_low_act(NULL);
154 else if (battery.temp == TEMP_HIGH)
155 battery_charge_err_high_act(NULL);
156 return G_SOURCE_REMOVE;
159 static void abnormal_popup_dbus_signal_handler(GDBusConnection *conn,
168 if (battery.health == HEALTH_GOOD)
170 _I("restart health timer");
171 abnormal_timer = g_timeout_add_seconds(ABNORMAL_CHECK_TIMER_INTERVAL,
172 health_timer_cb, NULL);
173 if (abnormal_timer == NULL)
174 _E("Fail to add abnormal check timer");
176 #endif /* TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE */
178 static void full_noti_cb(GVariant *var, void *user_data, GError *err)
185 if (!dh_get_param_from_var(var, "(i)", &id)) {
186 _E("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 int check_power_supply_noti(void)
200 int r_disturb, s_disturb, r_block, s_block;
201 r_disturb = vconf_get_int("memory/shealth/sleep/do_not_disturb", &s_disturb);
202 r_block = vconf_get_bool("db/setting/blockmode_wearable", &s_block);
203 if ((r_disturb != 0 && r_block != 0) ||
204 (s_disturb == 0 && s_block == 0)) {
213 static int send_full_noti(enum charge_full_type state)
219 noti = check_power_supply_noti();
226 for (retry = RETRY_MAX; retry > 0; retry--) {
227 ret = dbus_method_async_with_reply(POPUP_BUS_NAME,
229 POPUP_INTERFACE_NOTI,
231 NULL, NULL, full_noti_cb, -1, NULL);
233 _D("Created battery full noti");
237 _E("Failed to call dbus method (err: %d)", ret);
239 case CHARGING_NOT_FULL:
242 for (retry = RETRY_MAX; retry > 0; retry--) {
243 ret = dbus_method_async_var(POPUP_BUS_NAME,
245 POPUP_INTERFACE_NOTI,
246 METHOD_FULL_NOTI_OFF,
247 g_variant_new("(i)", noti_id));
249 _D("Deleted battery full noti");
254 _E("Failed to call dbus method (err: %d)", ret);
260 static int send_charge_noti(void)
265 for (retry = RETRY_MAX; retry > 0; retry--) {
266 ret = dbus_method_async(POPUP_BUS_NAME,
268 POPUP_INTERFACE_NOTI,
269 METHOD_CHARGE_NOTI_ON,
272 _D("Created battery charge noti");
276 _E("Failed to call dbus method (err: %d)", ret);
280 static void power_supply_noti(enum battery_noti_type type, enum battery_noti_status status)
282 static int charger = CHARGER_DISCHARGING;
283 static int full = CHARGING_NOT_FULL;
286 if (type == DEVICE_NOTI_BATT_CHARGE) {
287 if (status == DEVICE_NOTI_ON && charger == CHARGER_DISCHARGING) {
289 charger = CHARGER_CHARGING;
290 } else if (status == DEVICE_NOTI_OFF && charger == CHARGER_CHARGING) {
291 charger = CHARGER_DISCHARGING;
293 } else if (type == DEVICE_NOTI_BATT_FULL) {
294 if (status == DEVICE_NOTI_ON && full == CHARGING_NOT_FULL) {
295 ret = send_full_noti(CHARGING_FULL);
297 full = CHARGING_FULL;
298 } else if (status == DEVICE_NOTI_OFF && full == CHARGING_FULL) {
299 ret = send_full_noti(CHARGING_NOT_FULL);
301 full = CHARGING_NOT_FULL;
306 void power_supply_broadcast(char *sig, int status)
309 static char sig_old[32];
311 if (strcmp(sig_old, sig) == 0 && old == status)
314 _D("%s %d", sig, status);
317 snprintf(sig_old, sizeof(sig_old), "%s", sig);
318 /*snprintf(str_status, sizeof(str_status), "%d", status);
319 arr[0] = str_status;*/
321 dbus_handle_broadcast_dbus_signal_var(DEVICED_PATH_BATTERY,
322 DEVICED_INTERFACE_BATTERY,
324 g_variant_new("(i)", status));
328 static void noti_batt_full(void)
330 static int bat_full_noti;
333 if (!battery.charge_full && bat_full_noti == 1) {
334 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
336 /* off the full charge state */
337 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
339 if (battery.charge_full && bat_full_noti == 0) {
340 power_supply_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
342 /* turn on LCD, if battery is full charged */
343 noti = check_power_supply_noti();
345 pm_change_internal(INTERNAL_LOCK_BATTERY_FULL,
349 /* on the full charge state */
350 device_notify(DEVICE_NOTIFIER_FULLBAT, (void *)&bat_full_noti);
354 static void check_power_supply(int state)
356 pm_check_and_change(state);
357 if (update_pm_setting)
358 update_pm_setting(SETTING_CHARGING, state);
361 static void charger_state_send_system_event(int state)
367 case CHARGE_STATUS_CHARGING:
368 str = EVT_VAL_BATTERY_CHARGER_CHARGING;
370 case CHARGE_STATUS_FULL:
371 case CHARGE_STATUS_DISCHARGING:
372 str = EVT_VAL_BATTERY_CHARGER_DISCHARGING;
374 case CHARGE_STATUS_CONNECTED:
375 str = EVT_VAL_BATTERY_CHARGER_CONNECTED;
377 case CHARGE_STATUS_DISCONNECTED:
378 str = EVT_VAL_BATTERY_CHARGER_DISCONNECTED;
381 _E("invalid parameter(%d)", state);
385 _D("system_event(%s)", str);
388 bundle_add_str(b, EVT_KEY_BATTERY_CHARGER_STATUS, str);
389 eventsystem_send_system_event(SYS_EVENT_BATTERY_CHARGER_STATUS, b);
393 static void update_present(enum battery_noti_status status)
395 static int old = DEVICE_NOTI_OFF;
396 enum present_type present;
400 _I("charge %d present %d", battery.charge_now, battery.present);
402 pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
403 if (status == DEVICE_NOTI_ON) {
404 present = PRESENT_ABNORMAL;
405 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&present);
406 pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
408 present = PRESENT_NORMAL;
409 device_notify(DEVICE_NOTIFIER_BATTERY_PRESENT, (void *)&present);
410 pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
412 changed_battery_cf(present);
415 #ifdef TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE
416 static void update_health(enum battery_noti_status status)
418 static int old = DEVICE_NOTI_OFF;
422 _I("charge %d health %d", battery.charge_now, battery.health);
425 pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
426 if (status == DEVICE_NOTI_ON) {
427 _I("popup - Battery health status is not good");
428 pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
429 if (battery.temp == TEMP_LOW)
430 battery_charge_err_low_act(NULL);
431 else if (battery.temp == TEMP_HIGH)
432 battery_charge_err_high_act(NULL);
434 pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
435 abnormal_popup_timer_init();
436 launch_system_app(APP_DEFAULT, 2, APP_KEY_TYPE, REMOVE_POPUP);
439 #endif /* TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE */
441 static void update_ovp(enum battery_noti_status status)
443 static int old = DEVICE_NOTI_OFF;
448 _I("charge %d ovp %d", battery.charge_now, battery.ovp);
450 pm_change_internal(INTERNAL_LOCK_POPUP, LCD_NORMAL);
451 if (status == DEVICE_NOTI_ON)
452 value = OVP_ABNORMAL;
455 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)&value);
458 static void check_battery_status(void)
460 static int old = DEVICE_CHANGE_NORMAL;
463 if (battery.charge_now == CHARGER_ABNORMAL &&
464 (battery.health == HEALTH_BAD || battery.present == PRESENT_ABNORMAL))
465 status = DEVICE_CHANGE_ABNORMAL;
466 else if (battery.ovp == OVP_ABNORMAL)
467 status = DEVICE_CHANGE_ABNORMAL;
469 status = DEVICE_CHANGE_NORMAL;
474 if (battery.charge_now == CHARGER_ABNORMAL) {
475 if (battery.health == HEALTH_BAD) {
476 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
477 #ifdef TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE
478 update_health(DEVICE_NOTI_ON);
479 #endif /* TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE */
481 } else if (battery.present == PRESENT_ABNORMAL) {
482 update_present(DEVICE_NOTI_ON);
486 if (battery.ovp == OVP_ABNORMAL) {
487 update_ovp(DEVICE_NOTI_ON);
491 if (battery.charge_now != CHARGER_ABNORMAL &&
492 status == DEVICE_CHANGE_NORMAL) {
493 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)&battery.health);
494 health_status_broadcast();
495 #ifdef TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE
496 update_health(DEVICE_NOTI_OFF);
497 #endif /* TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE */
498 update_ovp(DEVICE_NOTI_OFF);
499 update_present(DEVICE_NOTI_OFF);
503 static void check_online(void)
505 static int old_online;
506 static int old_charge_status;
509 if (battery.charge_status == CHARGE_STATUS_FULL)
510 charge_status = CHARGE_STATUS_DISCHARGING;
512 charge_status = battery.charge_status;
514 if (battery.online > POWER_SUPPLY_TYPE_BATTERY &&
515 old_online == VCONFKEY_SYSMAN_CHARGER_DISCONNECTED) {
516 old_online = VCONFKEY_SYSMAN_CHARGER_CONNECTED;
517 vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
518 power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
519 extcon_get_count(EXTCON_TA);
520 extcon_set_count(EXTCON_TA, 1);
521 check_power_supply(old_online);
522 charger_state_send_system_event(CHARGE_STATUS_CONNECTED);
523 if (charge_status != old_charge_status)
524 charger_state_send_system_event(charge_status);
526 } else if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
527 old_online == VCONFKEY_SYSMAN_CHARGER_CONNECTED) {
528 old_online = VCONFKEY_SYSMAN_CHARGER_DISCONNECTED;
529 vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
530 power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
531 check_power_supply(old_online);
532 if (charge_status != old_charge_status)
533 charger_state_send_system_event(charge_status);
534 charger_state_send_system_event(CHARGE_STATUS_DISCONNECTED);
537 if (charge_status != old_charge_status)
538 charger_state_send_system_event(charge_status);
541 old_charge_status = charge_status;
544 static void check_charge_status(const char *env_value)
546 if (env_value == NULL)
549 _D("Charge Status(%s)", env_value);
551 if (strncmp(env_value, CHARGEFULL_NAME,
552 sizeof(CHARGEFULL_NAME)) == 0)
553 battery.charge_status = CHARGE_STATUS_FULL;
554 else if (strncmp(env_value, CHARGENOW_NAME,
555 sizeof(CHARGENOW_NAME)) == 0)
556 battery.charge_status = CHARGE_STATUS_CHARGING;
557 else if (strncmp(env_value, DISCHARGE_NAME,
558 sizeof(DISCHARGE_NAME)) == 0)
559 battery.charge_status = CHARGE_STATUS_DISCHARGING;
560 else if (strncmp(env_value, NOTCHARGE_NAME,
561 sizeof(NOTCHARGE_NAME)) == 0)
562 battery.charge_status = CHARGE_STATUS_NOT_CHARGING;
564 battery.charge_status = CHARGE_STATUS_UNKNOWN;
566 if (battery.charge_status == CHARGE_STATUS_FULL) {
567 battery.charge_full = CHARGING_FULL;
568 battery.charge_now = CHARGER_DISCHARGING;
569 } else if (battery.charge_status == CHARGE_STATUS_CHARGING) {
570 battery.charge_full = CHARGING_NOT_FULL;
571 battery.charge_now = CHARGER_CHARGING;
572 } else if (battery.charge_status == CHARGE_STATUS_DISCHARGING) {
573 battery.charge_full = CHARGING_NOT_FULL;
574 battery.charge_now = CHARGER_DISCHARGING;
575 } else if (battery.charge_status == CHARGE_STATUS_NOT_CHARGING) {
576 battery.charge_full = CHARGING_NOT_FULL;
577 battery.charge_now = CHARGER_ABNORMAL;
579 battery.charge_full = CHARGING_NOT_FULL;
580 battery.charge_now = CHARGER_DISCHARGING;
584 static void check_health_status(const char *env_value)
586 if (env_value == NULL) {
587 battery.health = HEALTH_GOOD;
588 battery.temp = TEMP_LOW;
589 battery.ovp = OVP_NORMAL;
592 if (strncmp(env_value, OVERHEAT_NAME,
593 sizeof(OVERHEAT_NAME)) == 0) {
594 battery.health = HEALTH_BAD;
595 battery.temp = TEMP_HIGH;
596 battery.ovp = OVP_NORMAL;
597 } else if (strncmp(env_value, TEMPCOLD_NAME,
598 sizeof(TEMPCOLD_NAME)) == 0) {
599 battery.health = HEALTH_BAD;
600 battery.temp = TEMP_LOW;
601 battery.ovp = OVP_NORMAL;
602 } else if (strncmp(env_value, OVERVOLT_NAME,
603 sizeof(OVERVOLT_NAME)) == 0) {
604 battery.health = HEALTH_GOOD;
605 battery.temp = TEMP_LOW;
606 battery.ovp = OVP_ABNORMAL;
608 battery.health = HEALTH_GOOD;
609 battery.temp = TEMP_LOW;
610 battery.ovp = OVP_NORMAL;
614 static void check_online_status(const char *env_value)
616 if (env_value == NULL)
618 battery.online = atoi(env_value);
621 static void check_present_status(const char *env_value)
623 if (env_value == NULL) {
624 battery.present = PRESENT_NORMAL;
627 battery.present = atoi(env_value);
630 static void check_capacity_status(const char *env_value)
632 if (env_value == NULL)
634 battery.capacity = atoi(env_value);
637 static void update_capacity_full(void)
642 if (battery.online <= POWER_SUPPLY_TYPE_BATTERY ||
644 old >= battery.capacity) {
645 old = battery.capacity;
648 delta = battery.capacity - old;
649 old = battery.capacity;
650 extcon_get_count(EXTCON_BATTERY_FULL);
651 extcon_set_count(EXTCON_BATTERY_FULL, delta);
654 static void process_power_supply(void *data)
656 if (old_battery.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
657 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
658 power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now);
661 lowbat_execute(data);
663 if (old_battery.charge_full != battery.charge_full)
666 old_battery.capacity = battery.capacity;
667 old_battery.online = battery.online;
668 old_battery.charge_status = battery.charge_status;
669 old_battery.charge_now = battery.charge_now;
670 old_battery.charge_full = battery.charge_full;
672 check_battery_status();
673 device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
674 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, &battery.charge_now);
675 update_capacity_full();
678 static void uevent_power_handler(struct udev_device *dev)
680 struct udev_list_entry *list_entry;
681 const char *env_name;
682 const char *env_value;
683 bool matched = false;
686 udev_list_entry_foreach(list_entry,
687 udev_device_get_properties_list_entry(dev)) {
688 env_name = udev_list_entry_get_name(list_entry);
692 if (!strncmp(env_name, CHARGE_NAME, sizeof(CHARGE_NAME))) {
693 env_value = udev_list_entry_get_value(list_entry);
696 if (!strncmp(env_value, BATTERY_NAME,
697 sizeof(BATTERY_NAME))) {
707 env_value = udev_device_get_property_value(dev, CHARGE_STATUS);
708 check_charge_status(env_value);
709 env_value = udev_device_get_property_value(dev, CHARGE_ONLINE);
710 check_online_status(env_value);
711 env_value = udev_device_get_property_value(dev, CHARGE_HEALTH);
712 check_health_status(env_value);
713 env_value = udev_device_get_property_value(dev, CHARGE_PRESENT);
714 check_present_status(env_value);
715 env_value = udev_device_get_property_value(dev, CAPACITY);
716 check_capacity_status(env_value);
718 ret = booting_done(NULL);
720 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
721 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
723 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
726 process_power_supply(&battery.capacity);
729 static void battery_state(struct battery_info *info)
734 _I("%s(%s) %s(%d) Capa(%d) Hth(%s,%s) Pres(%d) OVP(%s) Curr(%d,%d)",
736 battery.charge_now == CHARGER_CHARGING ? "Charging"
737 : (battery.charge_now == CHARGER_DISCHARGING ? "Discharging" : "Abnormal"),
742 battery.temp == TEMP_LOW ? "Low" : "High",
744 battery.ovp == OVP_NORMAL ? "X" : "O",
746 info->current_average);
749 static void battery_changed(struct battery_info *info, void *data)
757 snprintf(battery.status_s, sizeof(battery.status_s),
759 check_charge_status(info->status);
761 battery.status_s[0] = '\0';
764 snprintf(battery.health_s, sizeof(battery.health_s),
766 check_health_status(info->health);
768 battery.health_s[0] = '\0';
770 if (info->power_source)
771 snprintf(battery.power_source_s, sizeof(battery.power_source_s),
772 "%s", info->power_source);
774 battery.power_source_s[0] = '\0';
776 battery.online = info->online;
777 battery.present = info->present;
778 battery.capacity = info->capacity;
779 battery.current_now = info->current_now;
780 battery.current_average = info->current_average;
784 ret = booting_done(NULL);
786 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
787 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
789 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
792 process_power_supply(&battery.capacity);
796 static int lowbat_read(int *val)
803 r = sys_get_int("/sys/class/power_supply/battery/capacity", val);
810 static void battery_get_capacity(struct battery_info *info, void *data)
814 if (info && info->capacity >= 0)
815 *capa = info->capacity;
818 static void power_supply_status_init(void)
820 static int charge_now = -1;
821 static int charge_full = -1;
822 static int capacity = -1;
826 if (battery_dev && battery_dev->get_current_state) {
828 r = battery_dev->get_current_state(battery_get_capacity, &pct);
829 if (r < 0 || pct < 0) {
830 _E("Failed to get battery capacity (capa:%d, ret:%d)", pct, r);
834 r = lowbat_read(&pct);
836 _E("fail to read capacity data : %d", r);
841 battery.capacity = pct;
842 battery.health = HEALTH_GOOD;
843 battery.ovp = OVP_NORMAL;
844 battery.present = PRESENT_NORMAL;
845 battery.temp = TEMP_LOW;
847 if (charge_now == battery.charge_now &&
848 charge_full == battery.charge_full &&
849 capacity == battery.capacity)
852 _I("charging %d full %d capacity %d", battery.charge_now, battery.charge_full, battery.capacity);
854 if (charge_now != battery.charge_now) {
855 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
856 power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now);
858 if (capacity != battery.capacity) {
859 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
860 power_supply_broadcast(CHARGE_CAPACITY_SIGNAL, battery.capacity);
863 charge_now = battery.charge_now;
864 charge_full = battery.charge_full;
865 capacity = battery.capacity;
868 static gboolean power_supply_update(void *data)
870 power_supply_status_init();
871 return G_SOURCE_CONTINUE;
874 static void power_supply_timer_start(void)
876 _D("battery init timer during booting");
877 power_timer = g_timeout_add_seconds(BATTERY_CHECK_TIMER_INTERVAL,
878 power_supply_update, NULL);
879 if (power_timer == 0)
880 _E("fail to add battery init timer during booting");
883 static void power_supply_timer_stop(void)
885 _D("battery init timer during booting");
888 g_source_remove(power_timer);
892 static GVariant *dbus_get_charger_status(GDBusConnection *conn,
893 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
894 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
898 if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &ret) < 0) {
899 _E("vconf_get_int() failed");
902 return g_variant_new("(i)", ret);
905 static GVariant *dbus_get_charge_now(GDBusConnection *conn,
906 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
907 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
911 ret = battery.charge_now;
913 return g_variant_new("(i)", ret);
916 static GVariant *dbus_get_charge_level(GDBusConnection *conn,
917 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
918 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
922 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &ret) < 0) {
923 _E("vconf_get_int() failed");
927 return g_variant_new("(i)", ret);
930 static GVariant *dbus_get_percent(GDBusConnection *conn,
931 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
932 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
936 ret = battery.capacity;
938 return g_variant_new("(i)", ret);
941 static GVariant *dbus_get_percent_raw(GDBusConnection *conn,
942 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
943 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
949 return g_variant_new("(i)", ret);
952 static GVariant *dbus_is_full(GDBusConnection *conn,
953 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
954 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
958 ret = battery.charge_full;
960 return g_variant_new("(i)", ret);
963 static GVariant *dbus_get_health(GDBusConnection *conn,
964 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
965 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
969 ret = battery.health;
971 return g_variant_new("(i)", ret);
974 static GVariant *dbus_power_supply_handler(GDBusConnection *conn,
975 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
976 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
984 g_variant_get(param, "(sisssss)", &type_str,
993 _E("message is invalid!");
998 pid = dbus_connection_get_sender_pid(conn, sender);
999 if (kill(pid, 0) == -1) {
1000 _E("%d process does not exist, dbus ignored!", pid);
1004 check_capacity_status(argv[0]);
1005 check_charge_status(argv[1]);
1006 check_health_status(argv[2]);
1007 check_online_status(argv[3]);
1008 check_present_status(argv[4]);
1009 _I("%d %d %d %d %d %d %d %d",
1011 battery.charge_full,
1019 if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
1020 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_ON);
1022 power_supply_noti(DEVICE_NOTI_BATT_CHARGE, DEVICE_NOTI_OFF);
1024 process_power_supply(&battery.capacity);
1033 return g_variant_new("(i)", ret);
1036 static void battery_get_info(struct battery_info *info, void *data)
1038 struct battery_info *bat = data;
1043 bat->status = strdup(info->status);
1044 bat->health = strdup(info->health);
1045 bat->power_source = strdup(info->power_source);
1046 bat->online = info->online;
1047 bat->present = info->present;
1048 bat->capacity = info->capacity;
1049 bat->current_now = info->current_now;
1050 bat->current_average = info->current_average;
1053 static GVariant *dbus_get_battery_info(GDBusConnection *conn,
1054 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
1055 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
1059 struct battery_info info = { 0, };
1061 if (battery_dev && battery_dev->get_current_state) {
1062 ret = battery_dev->get_current_state(battery_get_info, &info);
1064 _E("Failed to get battery info (%d)", ret);
1066 battery_changed(&info, NULL);
1069 free(info.power_source);
1071 if (battery.charge_status == CHARGE_STATUS_FULL)
1072 str = CHARGEFULL_NAME;
1073 else if (battery.charge_status == CHARGE_STATUS_CHARGING)
1074 str = CHARGENOW_NAME;
1075 else if (battery.charge_status == CHARGE_STATUS_DISCHARGING)
1076 str = DISCHARGE_NAME;
1077 else if (battery.charge_status == CHARGE_STATUS_NOT_CHARGING)
1078 str = NOTCHARGE_NAME;
1081 snprintf(battery.status_s, sizeof(battery.status_s), "%s", str);
1083 if (battery.health == HEALTH_GOOD) {
1084 if (battery.temp == TEMP_LOW && battery.ovp == OVP_ABNORMAL)
1085 str = OVERVOLT_NAME;
1088 } else { /* HEALTH_BAD */
1089 if (battery.temp == TEMP_HIGH)
1090 str = OVERHEAT_NAME;
1092 str = TEMPCOLD_NAME;
1094 snprintf(battery.health_s, sizeof(battery.health_s), "%s", str);
1096 if (vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &val) == 0 &&
1097 val != VCONFKEY_SYSMAN_USB_DISCONNECTED)
1098 str = POWER_SOURCE_USB;
1099 else if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &val) == 0 &&
1100 val == VCONFKEY_SYSMAN_CHARGER_CONNECTED)
1101 str = POWER_SOURCE_AC;
1103 str = POWER_SOURCE_NONE;
1104 snprintf(battery.power_source_s, sizeof(battery.power_source_s), "%s", str);
1106 battery.current_now = -1; /* Not supported */
1107 battery.current_average = -1; /* Not supported */
1111 return g_variant_new("(isssiiiii)", ret,
1114 battery.power_source_s,
1118 battery.current_now,
1119 battery.current_average);
1122 static const dbus_method_s dbus_methods[] = {
1123 { CHARGER_STATUS_SIGNAL, NULL, "i", dbus_get_charger_status },
1124 { CHARGE_NOW_SIGNAL, NULL, "i", dbus_get_charge_now },
1125 { CHARGE_LEVEL_SIGNAL, NULL, "i", dbus_get_charge_level },
1126 { CHARGE_CAPACITY_SIGNAL, NULL, "i", dbus_get_percent },
1127 { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
1128 { CHARGE_FULL_SIGNAL, NULL, "i", dbus_is_full },
1129 { CHARGE_HEALTH_SIGNAL, NULL, "i", dbus_get_health },
1130 { POWER_SUBSYSTEM, "sisssss", "i", dbus_power_supply_handler },
1131 { "GetBatteryInfo", NULL, "isssiiiii", dbus_get_battery_info },
1132 /* Add methods here */
1135 static const dbus_interface_u dbus_interface = {
1137 .name = DEVICED_INTERFACE_BATTERY,
1138 .methods = dbus_methods,
1139 .nr_methods = ARRAY_SIZE(dbus_methods),
1142 static int booting_done(void *data)
1148 done = *(int *)data;
1154 power_supply_timer_stop();
1156 /* for simple noti change cb */
1157 power_supply_status_init();
1158 process_power_supply(NULL);
1163 static int display_changed(void *data)
1165 if (battery.charge_now != CHARGER_ABNORMAL)
1167 if (battery.health != HEALTH_BAD && battery.present != PRESENT_ABNORMAL)
1169 pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
1173 static int load_uevent(struct parse_result *result, void *user_data)
1175 struct battery_status *info = user_data;
1180 if (MATCH(result->name, CHARGE_STATUS)) {
1181 if (strstr(result->value, "Charging")) {
1182 info->charge_now = CHARGER_CHARGING;
1183 info->charge_full = CHARGING_NOT_FULL;
1184 } else if (strstr(result->value, "Discharging")) {
1185 info->charge_now = CHARGER_DISCHARGING;
1186 info->charge_full = CHARGING_NOT_FULL;
1187 } else if (strstr(result->value, "Full")) {
1188 info->charge_now = CHARGER_DISCHARGING;
1189 info->charge_full = CHARGING_FULL;
1190 } else if (strstr(result->value, "Not charging")) {
1191 info->charge_now = CHARGER_ABNORMAL;
1192 info->charge_full = CHARGING_NOT_FULL;
1194 snprintf(info->status_s, sizeof(info->status_s), "%s", result->value);
1195 } else if (MATCH(result->name, CAPACITY))
1196 info->capacity = atoi(result->value);
1197 else if (MATCH(result->name, CHARGE_HEALTH))
1198 snprintf(info->health_s, sizeof(info->health_s), "%s", result->value);
1202 static int power_supply_probe(void *data)
1204 struct hw_info *info;
1210 ret = hw_get_info(BATTERY_HARDWARE_DEVICE_ID,
1211 (const struct hw_info **)&info);
1213 if (ret < 0) { /* There is no HAL for battery */
1214 if (access(POWER_PATH, R_OK) == 0)
1215 return 0; /* Just power_supply uevent is used */
1220 _E("Failed to open battery device; open(NULL)");
1224 ret = info->open(info, NULL, (struct hw_common**)&battery_dev);
1226 _E("Failed to get battery device structure (%d)", ret);
1230 if (!battery_dev || !battery_dev->get_current_state) {
1231 _E("get_current_state() is not supported by the Battery HAL");
1235 _I("battery device structure load success");
1240 * Set battery vconf as -ENOTSUP
1241 * These vconf key used by runtime-info and capi-system-device.
1243 vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, -ENOTSUP);
1244 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, -ENOTSUP);
1245 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, -ENOTSUP);
1246 _I("There is no battery device(%d)", ret);
1250 static void add_power_supply_handler(void)
1255 if (battery_dev->register_changed_event)
1256 battery_dev->register_changed_event(battery_changed, NULL);
1257 if (battery_dev->get_current_state)
1258 battery_dev->get_current_state(battery_changed, NULL);
1260 ret = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
1262 _E("Failed to load %s, %d Use default value!", POWER_SUPPLY_UEVENT, ret);
1264 /* register power subsystem */
1265 register_kernel_uevent_control(&uh);
1269 static void remove_power_supply_handler(void)
1272 battery_dev->unregister_changed_event(battery_changed);
1274 unregister_kernel_uevent_control(&uh);
1277 static int event_handler_state_changed(void *data)
1279 static device_notifier_state_e old = DEVICE_NOTIFIER_STATE_STOP;
1280 device_notifier_state_e state = *(device_notifier_state_e *)data;
1287 if (state == DEVICE_NOTIFIER_STATE_START)
1288 add_power_supply_handler();
1289 else if (state == DEVICE_NOTIFIER_STATE_STOP)
1290 remove_power_supply_handler();
1295 static void power_supply_init(void *data)
1298 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_START;
1300 battery.capacity = -1;
1302 event_handler_state_changed((void *)&state);
1304 /* process check battery timer until booting done */
1305 power_supply_timer_start();
1307 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
1308 register_notifier(DEVICE_NOTIFIER_LCD, display_changed);
1309 register_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1311 ret = dbus_handle_add_dbus_object(NULL, DEVICED_PATH_BATTERY, &dbus_interface);
1313 _E("fail to init dbus method(%d)", ret);
1316 #ifdef TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE
1317 ret = subscribe_dbus_signal(NULL, DEVICED_PATH_SYSNOTI,
1318 DEVICED_INTERFACE_SYSNOTI, SIGNAL_CHARGEERR_RESPONSE, abnormal_popup_dbus_signal_handler, NULL, NULL);
1320 _E("fail to init dbus signal(%d)", ret);
1321 #endif /* TIZEN_FEATURE_BATTERY_OVER_TEMPERATURE */
1324 static void power_supply_exit(void *data)
1326 device_notifier_state_e state = DEVICE_NOTIFIER_STATE_STOP;
1328 unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
1329 unregister_notifier(DEVICE_NOTIFIER_LCD, display_changed);
1330 unregister_notifier(DEVICE_NOTIFIER_EVENT_HANDLER, event_handler_state_changed);
1332 event_handler_state_changed((void *)&state);
1335 static const struct device_ops power_supply_ops = {
1336 .name = "power_supply",
1337 .probe = power_supply_probe,
1338 .init = power_supply_init,
1339 .exit = power_supply_exit,
1342 DEVICE_OPS_REGISTER(&power_supply_ops)