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 <device-node.h>
27 #include "predefine.h"
28 #include "device-handler.h"
29 #include "device-notifier.h"
33 #include "display/poll.h"
34 #include "display/setting.h"
35 #include "proc/proc-handler.h"
36 #include "config-parser.h"
37 #include "power-supply.h"
40 #define POPUP_KEY_CONTENT "_SYSPOPUP_CONTENT_"
42 #define PREDEF_BATTERY_CF_OPENED "battery_cf_opened"
43 #define SIGNAL_CHARGEERR_RESPONSE "ChargeErrResponse"
44 #define SIGNAL_TEMP_GOOD "TempGood"
46 #define ABNORMAL_CHECK_TIMER_INTERVAL 60
48 #define METHOD_FULL_NOTI_ON "BatteryFullNotiOn"
49 #define METHOD_FULL_NOTI_OFF "BatteryFullNotiOff"
50 #define METHOD_CHARGE_NOTI_ON "BatteryChargeNotiOn"
52 #define SIOP_DISABLE "memory/private/sysman/siop_disable"
55 #define BATTERY_CHECK_TIMER_INTERVAL (0.5)
58 #define DEVICE_NOTIFIER "/usr/bin/sys_device_noti"
59 #define BATT_CHARGE_NOTI "0"
60 #define BATT_FULL_NOTI "2"
68 static Ecore_Timer *power_timer = NULL;
69 static Ecore_Timer *abnormal_timer = NULL;
70 extern int battery_power_off_act(void *data);
72 static void pm_check_and_change(int bInserted)
75 if (old != bInserted) {
77 predefine_pm_change_state(LCD_NORMAL);
81 int check_lowbat_charge_device(int bInserted)
83 static int bChargeDeviceInserted = 0;
88 struct popup_data *params;
89 static const struct device_ops *apps = NULL;
91 pm_check_and_change(bInserted);
93 if (battery.charge_now)
94 bChargeDeviceInserted = 1;
96 } else if (bInserted == 0) {
97 if (!battery.charge_now && bChargeDeviceInserted == 1) {
98 bChargeDeviceInserted = 0;
99 //low bat popup during charging device removing
100 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state) == 0) {
101 if(bat_state < VCONFKEY_SYSMAN_BAT_NORMAL
102 || bat_state == VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF) {
104 apps = find_device("apps");
108 if(bat_state == VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
110 else if (bat_state == VCONFKEY_SYSMAN_BAT_POWER_OFF)
114 params = malloc(sizeof(struct popup_data));
115 if (params == NULL) {
119 params->name = "lowbat-syspopup";
120 params->key = POPUP_KEY_CONTENT;
121 params->value = value;
122 _I("%s %s %s(%x)", params->name, params->key, params->value, params);
124 apps->init((void *)params);
128 _E("failed to get vconf key");
137 static int changed_battery_cf(int argc, char **argv)
140 struct popup_data *params;
141 static const struct device_ops *apps = NULL;
145 present_status = atoi(argv[0]);
148 apps = find_device("apps");
152 params = malloc(sizeof(struct popup_data));
153 if (params == NULL) {
157 params->name = "lowbat-syspopup";
158 params->key = POPUP_KEY_CONTENT;
159 params->value = "battdisconnect";
160 if (apps->init == NULL || apps->exit == NULL)
162 if (present_status == PRESENT_ABNORMAL)
163 apps->init((void *)params);
165 apps->exit((void *)params);
171 int check_abnormal_popup(void)
173 int ret = HEALTH_BAD;
180 static void abnormal_popup_timer_init(void)
182 if (abnormal_timer == NULL)
184 ecore_timer_del(abnormal_timer);
185 abnormal_timer = NULL;
186 _I("delete health timer");
189 static void health_status_broadcast(void)
191 broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
192 SIGNAL_TEMP_GOOD, NULL, NULL);
195 static int clean_health_popup(void)
197 struct popup_data *params;
198 static const struct device_ops *apps = NULL;
201 apps = find_device("apps");
205 params = malloc(sizeof(struct popup_data));
206 if (params == NULL) {
210 params->name = "lowbat-syspopup";
211 params->key = POPUP_KEY_CONTENT;
213 apps->exit((void *)params);
214 health_status_broadcast();
221 static void health_timer_reset(void)
223 abnormal_timer = NULL;
226 static Eina_Bool health_timer_cb(void *data)
228 health_timer_reset();
230 if (battery.health == HEALTH_GOOD)
233 _I("popup - Battery health status is not good");
234 vconf_set_int(SIOP_DISABLE, 1);
235 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_BAD);
236 pm_change_internal(getpid(), LCD_NORMAL);
237 pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
238 if (battery.temp == TEMP_LOW)
239 battery_charge_err_low_act(NULL);
240 else if (battery.temp == TEMP_HIGH)
241 battery_charge_err_high_act(NULL);
245 static void abnormal_popup_edbus_signal_handler(void *data, DBusMessage *msg)
247 if (battery.health == HEALTH_GOOD)
249 _I("restart health timer");
250 abnormal_timer = ecore_timer_add(ABNORMAL_CHECK_TIMER_INTERVAL,
251 health_timer_cb, NULL);
252 if (abnormal_timer == NULL)
253 _E("Fail to add abnormal check timer");
258 static void full_noti_cb(void *data, DBusMessage *msg, DBusError *err)
266 dbus_error_init(&r_err);
267 ret = dbus_message_get_args(msg, &r_err, DBUS_TYPE_INT32, &id, DBUS_TYPE_INVALID);
269 _E("no message [%s:%s]", r_err.name, r_err.message);
270 dbus_error_free(&r_err);
275 _D("Inserted battery full noti : %d", noti_id);
278 static int send_full_noti(enum charge_full_type state)
282 char params[BUFF_MAX];
283 snprintf(params, sizeof(params), "%s %d", BATT_FULL_NOTI, state);
284 launch_evenif_exist(DEVICE_NOTIFIER, params);
292 for (retry = RETRY_MAX; retry > 0 ;retry--) {
293 ret = dbus_method_async_with_reply(POPUP_BUS_NAME,
295 POPUP_INTERFACE_BATTERY,
297 NULL, NULL, full_noti_cb, -1, NULL);
299 _D("Created battery full noti");
303 _E("Failed to call dbus method (err: %d)", ret);
305 case CHARGING_NOT_FULL:
308 snprintf(str_id, sizeof(str_id), "%d", noti_id);
310 for (retry = RETRY_MAX; retry > 0 ;retry--) {
311 ret = dbus_method_async(POPUP_BUS_NAME,
313 POPUP_INTERFACE_BATTERY,
314 METHOD_FULL_NOTI_OFF,
317 _D("Deleted battery full noti");
322 _E("Failed to call dbus method (err: %d)", ret);
329 int send_charge_noti(void)
333 launch_evenif_exist(DEVICE_NOTIFIER, BATT_CHARGE_NOTI);
337 for (retry = RETRY_MAX; retry > 0 ;retry--) {
338 ret = dbus_method_async(POPUP_BUS_NAME,
340 POPUP_INTERFACE_BATTERY,
341 METHOD_CHARGE_NOTI_ON,
344 _D("Created battery charge noti");
348 _E("Failed to call dbus method (err: %d)", ret);
353 void battery_noti(enum battery_noti_type type, enum battery_noti_status status)
355 static int charge = CHARGER_DISCHARGING;
356 static int full = CHARGING_NOT_FULL;
359 if (type == DEVICE_NOTI_BATT_FULL && status == DEVICE_NOTI_ON &&
360 full == CHARGING_NOT_FULL) {
361 ret = send_full_noti(CHARGING_FULL);
363 full = CHARGING_FULL;
364 } else if (type == DEVICE_NOTI_BATT_FULL && status == DEVICE_NOTI_OFF &&
365 full == CHARGING_FULL) {
366 ret = send_full_noti(CHARGING_NOT_FULL);
368 full = CHARGING_NOT_FULL;
369 } else if (type == DEVICE_NOTI_BATT_CHARGE &&
370 battery.charge_now == CHARGER_CHARGING &&
371 charge == CHARGER_DISCHARGING) {
372 if (full == CHARGING_FULL) {
373 ret = send_full_noti(CHARGING_NOT_FULL);
375 full = CHARGING_NOT_FULL;
379 charge = battery.charge_now;
382 static void noti_batt_full(void)
384 char params[BUFF_MAX];
385 static int bat_full_noti = 0;
387 if (!battery.charge_full && bat_full_noti == 1) {
388 battery_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
390 /* off the full charge state */
391 device_notify(DEVICE_NOTIFIER_FULLBAT, (void*)false);
393 if (battery.charge_full && bat_full_noti == 0) {
394 battery_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
396 /* turn on LCD, if battery is full charged */
397 pm_change_internal(getpid(), LCD_NORMAL);
398 /* on the full charge state */
399 device_notify(DEVICE_NOTIFIER_FULLBAT, (void*)true);
403 static void check_power_supply(int state)
407 char params[BUFF_MAX];
409 check_lowbat_charge_device(state);
410 if (update_pm_setting)
411 update_pm_setting(SETTING_CHARGING, state);
413 ret = device_get_property(DEVICE_TYPE_POWER,
414 PROP_POWER_INSUSPEND_CHARGING_SUPPORT, &val);
416 if (ret != 0 || val == 1) {
417 _D("fail to check charger insuspend");
422 pm_unlock_internal(INTERNAL_LOCK_TA, LCD_OFF, STAY_CUR_STATE);
424 pm_lock_internal(INTERNAL_LOCK_TA, LCD_OFF, STAY_CUR_STATE, 0);
426 _I("ta device %d", state);
428 sync_cradle_status();
431 static void update_present(enum battery_noti_status status)
433 static int old = DEVICE_NOTI_OFF;
434 char params[BUFF_MAX];
438 _I("charge %d present %d", battery.charge_now, battery.present);
440 pm_change_internal(getpid(), LCD_NORMAL);
441 if (status == DEVICE_NOTI_ON)
442 snprintf(params, sizeof(params), "%d", PRESENT_ABNORMAL);
444 snprintf(params, sizeof(params), "%d", PRESENT_NORMAL);
445 notify_action(PREDEF_BATTERY_CF_OPENED, 1, params);
448 static void update_health(enum battery_noti_status status)
450 static int old = DEVICE_NOTI_OFF;
454 _I("charge %d health %d", battery.charge_now, battery.health);
456 pm_change_internal(getpid(), LCD_NORMAL);
457 if (status == DEVICE_NOTI_ON) {
458 _I("popup - Battery health status is not good");
459 vconf_set_int(SIOP_DISABLE, 1);
460 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_BAD);
461 pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
462 if (battery.temp == TEMP_LOW)
463 battery_charge_err_low_act(NULL);
464 else if (battery.temp == TEMP_HIGH)
465 battery_charge_err_high_act(NULL);
467 vconf_set_int(SIOP_DISABLE, 0);
468 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_GOOD);
469 pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
470 clean_health_popup();
471 abnormal_popup_timer_init();
475 static void update_ovp(enum battery_noti_status status)
477 static int old = DEVICE_NOTI_OFF;
481 _I("charge %d ovp %d", battery.charge_now, battery.ovp);
483 pm_change_internal(getpid(), LCD_NORMAL);
484 if (status == DEVICE_NOTI_ON)
485 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_ABNORMAL);
487 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_NORMAL);
490 static void check_battery_status(void)
492 static int old = DEVICE_CHANGE_NORMAL;
495 if (battery.charge_now == CHARGER_ABNORMAL &&
496 (battery.health == HEALTH_BAD || battery.present == PRESENT_ABNORMAL))
497 status = DEVICE_CHANGE_ABNORMAL;
498 else if (battery.ovp == OVP_ABNORMAL)
499 status = DEVICE_CHANGE_ABNORMAL;
501 status = DEVICE_CHANGE_NORMAL;
506 if (battery.charge_now == CHARGER_ABNORMAL) {
507 if (battery.health == HEALTH_BAD) {
508 update_health(DEVICE_NOTI_ON);
510 } else if (battery.present == PRESENT_ABNORMAL) {
511 update_present(DEVICE_NOTI_ON);
515 if (battery.ovp == OVP_ABNORMAL) {
516 update_ovp(DEVICE_NOTI_ON);
520 if (battery.charge_now != CHARGER_ABNORMAL &&
521 status == DEVICE_CHANGE_NORMAL) {
522 update_health(DEVICE_NOTI_OFF);
523 update_ovp(DEVICE_NOTI_OFF);
524 update_present(DEVICE_NOTI_OFF);
528 static void check_online(void)
530 static int old_online;
532 if (battery.online > POWER_SUPPLY_TYPE_BATTERY &&
533 old_online == VCONFKEY_SYSMAN_CHARGER_DISCONNECTED) {
534 old_online = VCONFKEY_SYSMAN_CHARGER_CONNECTED;
535 vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
536 power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
537 extcon_set_count(EXTCON_TA);
538 check_power_supply(old_online);
539 } else if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
540 old_online == VCONFKEY_SYSMAN_CHARGER_CONNECTED) {
541 old_online = VCONFKEY_SYSMAN_CHARGER_DISCONNECTED;
542 vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
543 power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
544 check_power_supply(old_online);
548 static void charge_cb(struct main_data *ad)
552 static int present_status = PRESENT_NORMAL;
554 lowbat_monitor(NULL);
556 if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_NOW, &battery.charge_now) != 0 ||
557 device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CAPACITY, &battery.capacity) != 0)
558 _E("fail to get battery node value");
560 if (battery.charge_now > 0)
561 battery.charge_now = CHARGER_CHARGING;
563 battery.charge_now = CHARGER_DISCHARGING;
565 if (battery.charge_now != CHARGER_CHARGING && battery.capacity == 0) {
566 _I("target will be shut down");
567 battery_power_off_act(NULL);
571 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_PRESENT, &val);
573 battery.present = PRESENT_NORMAL;
574 _E("fail to get battery present value");
578 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_HEALTH, &val);
580 battery.health = HEALTH_GOOD;
581 battery.ovp = OVP_NORMAL;
582 _E("failed to get battery health status");
585 if (val != BATTERY_GOOD)
586 _I("Battery health status is not good (%d)", val);
587 if (val == BATTERY_OVERHEAT) {
588 battery.health = HEALTH_BAD;
589 battery.charge_now = CHARGER_ABNORMAL;
590 battery.temp = TEMP_HIGH;
591 } else if (val == BATTERY_COLD) {
592 battery.health = HEALTH_BAD;
593 battery.charge_now = CHARGER_ABNORMAL;
594 battery.temp = TEMP_LOW;
596 battery.health = HEALTH_GOOD;
599 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_FULL, &val);
601 battery.charge_full = val;
603 check_battery_status();
604 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, (void*)battery.charge_now);
607 static int load_uevent(struct parse_result *result, void *user_data)
609 struct battery_status *info = user_data;
614 if (MATCH(result->name, CHARGE_STATUS)) {
615 if (strstr(result->value, "Charging")) {
616 info->charge_now = CHARGER_CHARGING;
617 info->charge_full = CHARGING_NOT_FULL;
618 } else if (strstr(result->value, "Discharging")) {
619 info->charge_now = CHARGER_DISCHARGING;
620 info->charge_full = CHARGING_NOT_FULL;
621 } else if (strstr(result->value, "Full")) {
622 info->charge_now = CHARGER_DISCHARGING;
623 info->charge_full = CHARGING_FULL;
624 } else if (strstr(result->value, "Not charging")) {
625 info->charge_now = CHARGER_ABNORMAL;
626 info->charge_full = CHARGING_NOT_FULL;
629 else if (MATCH(result->name, CAPACITY))
630 info->capacity = atoi(result->value);
634 static void power_load_uevent(void)
637 ret = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
639 _E("Failed to load %s, %d Use default value!", POWER_SUPPLY_UEVENT, ret);
642 void power_supply(void *data)
646 static int old_charge;
648 if (old_charge != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
649 old_charge = battery.charge_now;
650 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, old_charge);
651 power_supply_broadcast(CHARGE_NOW_SIGNAL, old_charge);
654 lowbat_monitor(data);
657 check_battery_status();
658 device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
659 device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, (void*)battery.charge_now);
662 void power_supply_status_init(void)
665 static int charge_now = -1;
666 static int charge_full = -1;
667 static int capacity = -1;
670 battery.health = HEALTH_GOOD;
671 battery.ovp = OVP_NORMAL;
672 battery.present = PRESENT_NORMAL;
673 battery.temp = TEMP_LOW;
675 if (charge_now == battery.charge_now &&
676 charge_full == battery.charge_full &&
677 capacity == battery.capacity)
680 if (charge_now != battery.charge_now ||
681 charge_full != battery.charge_full ||
682 capacity != battery.capacity)
683 _I("charging %d full %d capacity %d", battery.charge_now, battery.charge_full, battery.capacity);
685 if (charge_now != battery.charge_now) {
686 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
687 power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now);
689 if (capacity != battery.capacity)
690 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
692 charge_now = battery.charge_now;
693 charge_full = battery.charge_full;
694 capacity = battery.capacity;
697 static Eina_Bool power_supply_update(void *data)
699 power_supply_status_init();
703 void power_supply_timer_start(void)
705 _D("battery init timer during booting");
706 power_timer = ecore_timer_add(BATTERY_CHECK_TIMER_INTERVAL,
707 power_supply_update, NULL);
708 if (power_timer == NULL)
709 _E("fail to add battery init timer during booting");
712 void power_supply_timer_stop(void)
714 _D("battery init timer during booting");
717 ecore_timer_del(power_timer);
721 void power_supply_broadcast(char *sig, int status)
724 static char sig_old[32];
728 if (strcmp(sig_old, sig) == 0 && old == status)
731 _D("%s %d", sig, status);
734 snprintf(sig_old, sizeof(sig_old), "%s", sig);
735 snprintf(str_status, sizeof(str_status), "%d", status);
738 broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
742 static DBusMessage *dbus_get_charger_status(E_DBus_Object *obj, DBusMessage *msg)
744 DBusMessageIter iter;
748 if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &ret) < 0) {
749 _E("vconf_get_int() failed");
752 reply = dbus_message_new_method_return(msg);
753 dbus_message_iter_init_append(reply, &iter);
754 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
758 static DBusMessage *dbus_get_charge_now(E_DBus_Object *obj, DBusMessage *msg)
760 DBusMessageIter iter;
764 ret = battery.charge_now;
766 reply = dbus_message_new_method_return(msg);
767 dbus_message_iter_init_append(reply, &iter);
768 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
772 static DBusMessage *dbus_get_charge_level(E_DBus_Object *obj, DBusMessage *msg)
774 DBusMessageIter iter;
778 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &ret) < 0) {
779 _E("vconf_get_int() failed");
783 reply = dbus_message_new_method_return(msg);
784 dbus_message_iter_init_append(reply, &iter);
785 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
789 static const struct edbus_method edbus_methods[] = {
790 { CHARGER_STATUS_SIGNAL, NULL, "i", dbus_get_charger_status },
791 { CHARGE_NOW_SIGNAL, NULL, "i", dbus_get_charge_now },
792 { CHARGE_LEVEL_SIGNAL, NULL, "i", dbus_get_charge_level },
795 int power_supply_init(void *data)
798 ret = register_edbus_method(DEVICED_PATH_BATTERY, edbus_methods, ARRAY_SIZE(edbus_methods));
800 _E("fail to init edbus method(%d)", ret);
801 ret = register_edbus_signal_handler(DEVICED_PATH_SYSNOTI,
802 DEVICED_INTERFACE_SYSNOTI, SIGNAL_CHARGEERR_RESPONSE,
803 abnormal_popup_edbus_signal_handler);
805 _E("fail to init edbus signal(%d)", ret);
807 register_action(PREDEF_BATTERY_CF_OPENED, changed_battery_cf,
810 /* for simple noti change cb */
811 emulator_add_callback("device_charge_chgdet", (void *)charge_cb, data);
812 power_supply_status_init();