tizen 2.3 release
[framework/system/deviced.git] / src / core / power-supply.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <vconf.h>
23 #include <Ecore.h>
24 #include <device-node.h>
25 #include <journal/system.h>
26 #include "devices.h"
27 #include "device-handler.h"
28 #include "device-notifier.h"
29 #include "udev.h"
30 #include "log.h"
31 #include "display/poll.h"
32 #include "display/setting.h"
33 #include "proc/proc-handler.h"
34 #include "config-parser.h"
35 #include "power-supply.h"
36 #include "sleep/sleep.h"
37
38 #define BUFF_MAX                255
39 #define POPUP_KEY_CONTENT               "_SYSPOPUP_CONTENT_"
40
41 #define SIGNAL_CHARGEERR_RESPONSE       "ChargeErrResponse"
42 #define SIGNAL_TEMP_GOOD                "TempGood"
43
44 #define ABNORMAL_CHECK_TIMER_INTERVAL   60
45
46 #define METHOD_FULL_NOTI_ON             "BatteryFullNotiOn"
47 #define METHOD_FULL_NOTI_OFF    "BatteryFullNotiOff"
48 #define METHOD_CHARGE_NOTI_ON   "BatteryChargeNotiOn"
49
50 #define SIOP_DISABLE    "memory/private/sysman/siop_disable"
51
52 #define RETRY_MAX 5
53 #define BATTERY_CHECK_TIMER_INTERVAL    (0.5)
54
55 #ifdef MICRO_DD
56 #define DEVICE_NOTIFIER "/usr/bin/sys_device_noti"
57 #define BATT_CHARGE_NOTI "0"
58 #define BATT_FULL_NOTI   "2"
59 #endif
60
61 enum power_supply_init_type {
62         POWER_SUPPLY_NOT_READY = 0,
63         POWER_SUPPLY_INITIALIZED = 1,
64 };
65
66 struct popup_data {
67         char *name;
68         char *key;
69         char *value;
70 };
71
72 static int alert_popup = 0;
73 static Ecore_Timer *power_timer = NULL;
74 static Ecore_Timer *abnormal_timer = NULL;
75 extern int battery_power_off_act(void *data);
76
77 static void pm_check_and_change(int bInserted)
78 {
79         static int old = -1;
80         if (old != bInserted) {
81                 old = bInserted;
82                 internal_pm_change_state(LCD_NORMAL);
83         }
84 }
85
86 int check_lowbat_charge_device(int bInserted)
87 {
88         static int bChargeDeviceInserted = 0;
89         int val = -1;
90         int bat_state = -1;
91         int ret = -1;
92         char *value;
93         struct popup_data *params;
94         static const struct device_ops *apps = NULL;
95
96         pm_check_and_change(bInserted);
97         if (bInserted == 1) {
98                 if (battery.charge_now)
99                         bChargeDeviceInserted = 1;
100                 return 0;
101         } else if (bInserted == 0) {
102                 if (!battery.charge_now && bChargeDeviceInserted == 1) {
103                         bChargeDeviceInserted = 0;
104                         //low bat popup during charging device removing
105                         if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state) == 0) {
106                                 if(bat_state < VCONFKEY_SYSMAN_BAT_NORMAL
107                                                 || bat_state == VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF) {
108                                         FIND_DEVICE_INT(apps, "apps");
109
110                                         if(bat_state == VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
111                                                 value = "poweroff";
112                                         else
113                                                 value = "warning";
114                                         params = malloc(sizeof(struct popup_data));
115                                         if (params == NULL) {
116                                                 _E("Malloc failed");
117                                                 return -1;
118                                         }
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);
123                                         if (apps->init)
124                                                 apps->init((void *)params);
125                                         free(params);
126                                 }
127                         } else {
128                                 _E("failed to get vconf key");
129                                 return -1;
130                         }
131                 }
132                 return 0;
133         }
134         return -1;
135 }
136
137 static int changed_battery_cf(enum present_type status)
138 {
139         struct popup_data *params;
140         static const struct device_ops *apps = NULL;
141
142         FIND_DEVICE_INT(apps, "apps");
143         params = malloc(sizeof(struct popup_data));
144         if (params == NULL) {
145                 _E("Malloc failed");
146                 return -ENOMEM;
147         }
148         params->name = "lowbat-syspopup";
149         params->key = POPUP_KEY_CONTENT;
150         params->value = "battdisconnect";
151         if (apps->init == NULL || apps->exit == NULL)
152                 goto out;
153         if (status == PRESENT_ABNORMAL)
154                 apps->init((void *)params);
155         else
156                 apps->exit((void *)params);
157 out:
158         free(params);
159         return 0;
160 }
161
162 int check_abnormal_popup(void)
163 {
164         int ret = HEALTH_BAD;
165
166         if (abnormal_timer)
167                 ret =  HEALTH_GOOD;
168         return ret;
169 }
170
171 static void abnormal_popup_timer_init(void)
172 {
173         if (abnormal_timer == NULL)
174                 return;
175         ecore_timer_del(abnormal_timer);
176         abnormal_timer = NULL;
177         _I("delete health timer");
178 }
179
180 static void health_status_broadcast(void)
181 {
182         broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
183             SIGNAL_TEMP_GOOD, NULL, NULL);
184 }
185
186 static int clean_health_popup(void)
187 {
188         struct popup_data *params;
189         static const struct device_ops *apps = NULL;
190
191         FIND_DEVICE_INT(apps, "apps");
192         params = malloc(sizeof(struct popup_data));
193         if (params == NULL) {
194                 _E("Malloc failed");
195                 return -ENOMEM;
196         }
197         params->name = "lowbat-syspopup";
198         params->key = POPUP_KEY_CONTENT;
199         if (apps->exit)
200                 apps->exit((void *)params);
201         health_status_broadcast();
202 out:
203         free(params);
204         return 0;
205
206 }
207
208 static void health_timer_reset(void)
209 {
210         abnormal_timer = NULL;
211 }
212
213 static Eina_Bool health_timer_cb(void *data)
214 {
215         health_timer_reset();
216
217         if (battery.health == HEALTH_GOOD)
218                 return EINA_FALSE;
219
220         _I("popup - Battery health status is not good");
221         vconf_set_int(SIOP_DISABLE, 1);
222         device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_BAD);
223         pm_change_internal(getpid(), LCD_NORMAL);
224         pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
225         if (battery.temp == TEMP_LOW)
226                 battery_charge_err_low_act(NULL);
227         else if (battery.temp == TEMP_HIGH)
228                 battery_charge_err_high_act(NULL);
229         return EINA_FALSE;
230 }
231
232 static void abnormal_popup_edbus_signal_handler(void *data, DBusMessage *msg)
233 {
234         if (battery.health == HEALTH_GOOD)
235                 return;
236         _I("restart health timer");
237         abnormal_timer = ecore_timer_add(ABNORMAL_CHECK_TIMER_INTERVAL,
238                                                 health_timer_cb, NULL);
239         if (abnormal_timer == NULL)
240                 _E("Fail to add abnormal check timer");
241 }
242
243 static int noti_id;
244
245 static void full_noti_cb(void *data, DBusMessage *msg, DBusError *err)
246 {
247         DBusError r_err;
248         int ret, id;
249
250         if (!msg)
251                 return;
252
253         dbus_error_init(&r_err);
254         ret = dbus_message_get_args(msg, &r_err, DBUS_TYPE_INT32, &id, DBUS_TYPE_INVALID);
255         if (!ret) {
256                 _E("no message [%s:%s]", r_err.name, r_err.message);
257                 dbus_error_free(&r_err);
258                 return;
259         }
260
261         noti_id = id;
262         _D("Inserted battery full noti : %d", noti_id);
263 }
264
265 static int check_noti(void)
266 {
267 #ifdef MICRO_DD
268         int r_disturb, s_disturb, r_block, s_block;
269         r_disturb = vconf_get_int("memory/shealth/sleep/do_not_disturb", &s_disturb);
270         r_block = vconf_get_bool("db/setting/blockmode_wearable", &s_block);
271         if ((r_disturb != 0 && r_block != 0) ||
272             (s_disturb == 0 && s_block == 0)) {
273             return 1;
274         }
275         return 0;
276 #else
277         return 1;
278 #endif
279 }
280
281 static int send_full_noti(enum charge_full_type state)
282 {
283         int ret = 0;
284         int noti;
285         int retry;
286         char str_id[32];
287         char *arr[1];
288
289         noti = check_noti();
290
291         if (!noti)
292                 return noti;
293
294         switch (state) {
295         case CHARGING_FULL:
296                 for (retry = RETRY_MAX; retry > 0 ;retry--) {
297                         ret = dbus_method_async_with_reply(POPUP_BUS_NAME,
298                                         POPUP_PATH_BATTERY,
299                                         POPUP_INTERFACE_BATTERY,
300                                         METHOD_FULL_NOTI_ON,
301                                         NULL, NULL, full_noti_cb, -1, NULL);
302                         if (ret == 0) {
303                                 _D("Created battery full noti");
304                                 return ret;
305                         }
306                 }
307                 _E("Failed to call dbus method (err: %d)", ret);
308         break;
309         case CHARGING_NOT_FULL:
310                 if (noti_id <= 0)
311                         return -EPERM;
312                 snprintf(str_id, sizeof(str_id), "%d", noti_id);
313                 arr[0] = str_id;
314                 for (retry = RETRY_MAX; retry > 0 ;retry--) {
315                         ret = dbus_method_async(POPUP_BUS_NAME,
316                                         POPUP_PATH_BATTERY,
317                                         POPUP_INTERFACE_BATTERY,
318                                         METHOD_FULL_NOTI_OFF,
319                                         "i", arr);
320                         if (ret == 0) {
321                                 _D("Deleted battery full noti");
322                                 noti_id = 0;
323                                 return ret;
324                         }
325                 }
326                 _E("Failed to call dbus method (err: %d)", ret);
327         break;
328         }
329         return ret;
330 }
331
332 int send_charge_noti(void)
333 {
334         int ret = 0;
335         int retry;
336
337         for (retry = RETRY_MAX; retry > 0 ;retry--) {
338                 ret = dbus_method_async(POPUP_BUS_NAME,
339                                 POPUP_PATH_BATTERY,
340                                 POPUP_INTERFACE_BATTERY,
341                                 METHOD_CHARGE_NOTI_ON,
342                                 NULL, NULL);
343                 if (ret == 0) {
344                         _D("Created battery charge noti");
345                         return ret;
346                 }
347         }
348         _E("Failed to call dbus method (err: %d)", ret);
349         return ret;
350 }
351
352 void battery_noti(enum battery_noti_type type, enum battery_noti_status status)
353 {
354         static int charge = CHARGER_DISCHARGING;
355         static int full = CHARGING_NOT_FULL;
356         int ret, i;
357
358         if (type == DEVICE_NOTI_BATT_FULL && status == DEVICE_NOTI_ON &&
359             full == CHARGING_NOT_FULL) {
360                 if (charge == CHARGER_DISCHARGING)
361                         send_charge_noti();
362                 ret = send_full_noti(CHARGING_FULL);
363                 if (ret == 0)
364                         full = CHARGING_FULL;
365         } else if (type == DEVICE_NOTI_BATT_FULL && status == DEVICE_NOTI_OFF &&
366             full == CHARGING_FULL) {
367                 ret = send_full_noti(CHARGING_NOT_FULL);
368                 if (ret == 0)
369                         full = CHARGING_NOT_FULL;
370         } else if (type == DEVICE_NOTI_BATT_CHARGE &&
371             battery.charge_now == CHARGER_CHARGING &&
372             charge == CHARGER_DISCHARGING) {
373                 if (full == CHARGING_FULL) {
374                         ret = send_full_noti(CHARGING_NOT_FULL);
375                         if (ret == 0)
376                                 full = CHARGING_NOT_FULL;
377                 }
378                 send_charge_noti();
379         }
380         charge = battery.charge_now;
381 }
382
383 static void noti_batt_full(void)
384 {
385         char params[BUFF_MAX];
386         static int bat_full_noti = 0;
387         int r_disturb, s_disturb, r_block, s_block;
388
389         r_disturb = vconf_get_int("memory/shealth/sleep/do_not_disturb", &s_disturb);
390         r_block = vconf_get_bool("db/setting/blockmode_wearable", &s_block);
391         if (!battery.charge_full && bat_full_noti == 1) {
392                 battery_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
393                 bat_full_noti = 0;
394                 /* off the full charge state */
395                 device_notify(DEVICE_NOTIFIER_FULLBAT, (void*)false);
396         }
397         if (battery.charge_full && bat_full_noti == 0) {
398                 battery_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
399                 bat_full_noti = 1;
400                 /* turn on LCD, if battery is full charged */
401                 if ((r_disturb != 0 && r_block != 0) ||
402                     (s_disturb == 0 && s_block == 0))
403                         pm_change_internal(getpid(), LCD_NORMAL);
404                 else
405                         _I("block LCD");
406                 /* on the full charge state */
407                 device_notify(DEVICE_NOTIFIER_FULLBAT, (void*)true);
408         }
409 }
410
411 static void check_power_supply(int state)
412 {
413         int ret = -1;
414         int val = 0;
415         char params[BUFF_MAX];
416
417         check_lowbat_charge_device(state);
418         if (update_pm_setting)
419                 update_pm_setting(SETTING_CHARGING, state);
420
421         ret = device_get_property(DEVICE_TYPE_POWER,
422                 PROP_POWER_INSUSPEND_CHARGING_SUPPORT, &val);
423
424         if (ret != 0 || val == 1) {
425                 _D("fail to check charger insuspend");
426                 goto out;
427         }
428
429         if (state == 0)
430                 pm_unlock_internal(INTERNAL_LOCK_TA, LCD_OFF, STAY_CUR_STATE);
431         else
432                 pm_lock_internal(INTERNAL_LOCK_TA, LCD_OFF, STAY_CUR_STATE, 0);
433 out:
434         _I("ta device %d(capacity %d)", state, battery.capacity);
435
436         sync_cradle_status();
437 }
438
439 static void update_present(enum battery_noti_status status)
440 {
441         static int old = DEVICE_NOTI_OFF;
442         enum present_type present;
443
444         if (old == status)
445                 return;
446         _I("charge %d present %d", battery.charge_now, battery.present);
447         old = status;
448         pm_change_internal(getpid(), LCD_NORMAL);
449         if (status == DEVICE_NOTI_ON)
450                 present = PRESENT_ABNORMAL;
451         else
452                 present = PRESENT_NORMAL;
453         changed_battery_cf(present);
454 }
455
456 static void update_health(enum battery_noti_status status)
457 {
458         static int old = DEVICE_NOTI_OFF;
459
460         if (old == status)
461                 return;
462         _I("charge %d health %d", battery.charge_now, battery.health);
463         old = status;
464
465         if (alert_popup && status == DEVICE_NOTI_ON) {
466                 _I("silent health popup");
467                 return;
468         }
469
470         pm_change_internal(getpid(), LCD_NORMAL);
471         if (status == DEVICE_NOTI_ON) {
472                 _I("popup - Battery health status is not good");
473                 vconf_set_int(SIOP_DISABLE, 1);
474                 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_BAD);
475                 pm_lock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, STAY_CUR_STATE, 0);
476                 if (battery.temp == TEMP_LOW)
477                         battery_charge_err_low_act(NULL);
478                 else if (battery.temp == TEMP_HIGH)
479                         battery_charge_err_high_act(NULL);
480         } else {
481                 vconf_set_int(SIOP_DISABLE, 0);
482                 device_notify(DEVICE_NOTIFIER_BATTERY_HEALTH, (void *)HEALTH_GOOD);
483                 pm_unlock_internal(INTERNAL_LOCK_POPUP, LCD_DIM, PM_SLEEP_MARGIN);
484                 clean_health_popup();
485                 abnormal_popup_timer_init();
486         }
487 }
488
489 static void update_ovp(enum battery_noti_status status)
490 {
491         static int old = DEVICE_NOTI_OFF;
492
493         if (old == status)
494                 return;
495         _I("charge %d ovp %d", battery.charge_now, battery.ovp);
496         old = status;
497         pm_change_internal(getpid(), LCD_NORMAL);
498         if (status == DEVICE_NOTI_ON)
499                 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_ABNORMAL);
500         else
501                 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_NORMAL);
502 }
503
504 static void check_battery_status(void)
505 {
506         static int old = DEVICE_CHANGE_NORMAL;
507         int status;
508
509         if (battery.charge_now == CHARGER_ABNORMAL &&
510             (battery.health == HEALTH_BAD || battery.present == PRESENT_ABNORMAL))
511                 status = DEVICE_CHANGE_ABNORMAL;
512         else if (battery.ovp == OVP_ABNORMAL)
513                 status = DEVICE_CHANGE_ABNORMAL;
514         else
515                 status = DEVICE_CHANGE_NORMAL;
516         if (old == status)
517                 return;
518         old = status;
519
520         if (battery.charge_now == CHARGER_ABNORMAL) {
521                 if (battery.health == HEALTH_BAD) {
522                         update_health(DEVICE_NOTI_ON);
523                         return;
524                 } else if (battery.present == PRESENT_ABNORMAL) {
525                         update_present(DEVICE_NOTI_ON);
526                         return;
527                 }
528         }
529         if (battery.ovp == OVP_ABNORMAL) {
530                 update_ovp(DEVICE_NOTI_ON);
531                 return;
532         }
533
534         if (battery.charge_now != CHARGER_ABNORMAL &&
535             status == DEVICE_CHANGE_NORMAL) {
536                 update_health(DEVICE_NOTI_OFF);
537                 update_ovp(DEVICE_NOTI_OFF);
538                 update_present(DEVICE_NOTI_OFF);
539         }
540 }
541
542 static void check_online(void)
543 {
544         static int old_online;
545
546         if (battery.online > POWER_SUPPLY_TYPE_BATTERY &&
547             old_online == VCONFKEY_SYSMAN_CHARGER_DISCONNECTED) {
548                 old_online = VCONFKEY_SYSMAN_CHARGER_CONNECTED;
549                 vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
550                 power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
551                 extcon_set_count(EXTCON_TA);
552                 check_power_supply(old_online);
553         } else if (battery.online <= POWER_SUPPLY_TYPE_BATTERY &&
554             old_online == VCONFKEY_SYSMAN_CHARGER_CONNECTED) {
555                 old_online = VCONFKEY_SYSMAN_CHARGER_DISCONNECTED;
556                 vconf_set_int(VCONFKEY_SYSMAN_CHARGER_STATUS, old_online);
557                 power_supply_broadcast(CHARGER_STATUS_SIGNAL, old_online);
558                 check_power_supply(old_online);
559         }
560 }
561
562 static int load_uevent(struct parse_result *result, void *user_data)
563 {
564         struct battery_status *info = user_data;
565
566         if (!info)
567                 return -EINVAL;
568
569         if (MATCH(result->name, CHARGE_STATUS)) {
570                 if (strstr(result->value, "Charging")) {
571                         info->charge_now = CHARGER_CHARGING;
572                         info->charge_full = CHARGING_NOT_FULL;
573                 } else if (strstr(result->value, "Discharging")) {
574                         info->charge_now = CHARGER_DISCHARGING;
575                         info->charge_full = CHARGING_NOT_FULL;
576                 } else if (strstr(result->value, "Full")) {
577                         info->charge_now = CHARGER_DISCHARGING;
578                         info->charge_full = CHARGING_FULL;
579                 } else if (strstr(result->value, "Not charging")) {
580                         info->charge_now = CHARGER_ABNORMAL;
581                         info->charge_full = CHARGING_NOT_FULL;
582                 }
583         }
584         else if (MATCH(result->name, CAPACITY))
585                 info->capacity = atoi(result->value);
586         return 0;
587 }
588
589 static void power_load_uevent(void)
590 {
591         int ret;
592         static int initialized = POWER_SUPPLY_NOT_READY;
593
594         if (initialized == POWER_SUPPLY_INITIALIZED)
595                 return;
596         ret = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
597         if (ret < 0)
598                 _E("Failed to load %s, %d Use default value!", POWER_SUPPLY_UEVENT, ret);
599         else
600                 initialized = POWER_SUPPLY_INITIALIZED;
601 }
602
603 static int sleep_execute(void *data)
604 {
605         static const struct device_ops *ops = NULL;
606
607         FIND_DEVICE_INT(ops, DEVICE_SLEEP_OPS);
608         return ops->execute(data);
609 }
610
611 void power_supply(void *data)
612 {
613         int ret;
614         int status = POWER_SUPPLY_STATUS_DISCHARGING;
615         static struct battery_status old;
616
617         if (old.charge_now != battery.charge_now || battery.charge_now == CHARGER_ABNORMAL) {
618                 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
619                 power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now);
620         }
621
622         if (old.capacity != battery.capacity)
623                 journal_system_battery_level(battery.capacity);
624         if (old.online != battery.online ||
625             old.charge_now != battery.charge_now ||
626             old.charge_full != battery.charge_full) {
627                 switch (battery.charge_now)
628                 {
629                 case CHARGER_ABNORMAL:
630                         status = POWER_SUPPLY_STATUS_NOT_CHARGING;
631                         break;
632                 case CHARGER_DISCHARGING:
633                         if (battery.charge_full == CHARGING_FULL)
634                                 status = POWER_SUPPLY_STATUS_FULL;
635                         else
636                                 status = POWER_SUPPLY_STATUS_DISCHARGING;
637                         break;
638                 case CHARGER_CHARGING:
639                         status = POWER_SUPPLY_STATUS_CHARGING;
640                         break;
641                 }
642                 journal_system_power_supply_status(battery.online, status);
643         }
644
645         lowbat_monitor(data);
646         check_online();
647         if (old.charge_full != battery.charge_full) {
648                 noti_batt_full();
649         }
650
651         old.capacity = battery.capacity;
652         old.online = battery.online;
653         old.charge_now = battery.charge_now;
654         old.charge_full = battery.charge_full;
655
656         check_battery_status();
657         device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
658         device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, (void*)battery.charge_now);
659         if (battery.online > POWER_SUPPLY_TYPE_BATTERY)
660                 sleep_execute(NULL);
661 }
662
663 void power_supply_status_init(void)
664 {
665         int ret, val;
666         static int charge_now = -1;
667         static int charge_full = -1;
668         static int capacity = -1;
669
670         power_load_uevent();
671         battery.health = HEALTH_GOOD;
672         battery.ovp = OVP_NORMAL;
673         battery.present = PRESENT_NORMAL;
674         battery.temp = TEMP_LOW;
675
676         if (charge_now == battery.charge_now &&
677             charge_full == battery.charge_full &&
678             capacity == battery.capacity)
679                 return;
680
681         if (charge_now != battery.charge_now ||
682             charge_full != battery.charge_full ||
683             capacity != battery.capacity)
684                 _I("charging %d full %d capacity %d", battery.charge_now, battery.charge_full, battery.capacity);
685
686         if (charge_now != battery.charge_now) {
687                 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, battery.charge_now);
688                 power_supply_broadcast(CHARGE_NOW_SIGNAL, battery.charge_now);
689         }
690         if (capacity != battery.capacity)
691                 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
692
693         charge_now = battery.charge_now;
694         charge_full = battery.charge_full;
695         capacity =  battery.capacity;
696 }
697
698 static Eina_Bool power_supply_update(void *data)
699 {
700         power_supply_status_init();
701         return EINA_TRUE;
702 }
703
704 void power_supply_timer_start(void)
705 {
706         _D("battery init timer during booting");
707         power_timer = ecore_timer_add(BATTERY_CHECK_TIMER_INTERVAL,
708                                 power_supply_update, NULL);
709         if (power_timer == NULL)
710             _E("fail to add battery init timer during booting");
711 }
712
713 void power_supply_timer_stop(void)
714 {
715     _D("battery init timer during booting");
716         if (!power_timer)
717                 return;
718         ecore_timer_del(power_timer);
719         power_timer = NULL;
720 }
721
722 void power_supply_broadcast(char *sig, int status)
723 {
724         static int old = 0;
725         static char sig_old[32];
726         char *arr[1];
727         char str_status[32];
728
729         if (strcmp(sig_old, sig) == 0 && old == status)
730                 return;
731
732         _D("%s %d", sig, status);
733
734         old = status;
735         snprintf(sig_old, sizeof(sig_old), "%s", sig);
736         snprintf(str_status, sizeof(str_status), "%d", status);
737         arr[0] = str_status;
738
739         broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
740                         sig, "i", arr);
741 }
742
743 static DBusMessage *dbus_get_charger_status(E_DBus_Object *obj, DBusMessage *msg)
744 {
745         DBusMessageIter iter;
746         DBusMessage *reply;
747         int ret;
748
749         if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &ret) < 0) {
750                 _E("vconf_get_int() failed");
751                 ret = -EIO;
752         }
753         reply = dbus_message_new_method_return(msg);
754         dbus_message_iter_init_append(reply, &iter);
755         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
756         return reply;
757 }
758
759 static DBusMessage *dbus_get_charge_now(E_DBus_Object *obj, DBusMessage *msg)
760 {
761         DBusMessageIter iter;
762         DBusMessage *reply;
763         int ret;
764
765         ret = battery.charge_now;
766
767         reply = dbus_message_new_method_return(msg);
768         dbus_message_iter_init_append(reply, &iter);
769         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
770         return reply;
771 }
772
773 static DBusMessage *dbus_get_charge_level(E_DBus_Object *obj, DBusMessage *msg)
774 {
775         DBusMessageIter iter;
776         DBusMessage *reply;
777         int ret;
778
779         if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &ret) < 0) {
780                 _E("vconf_get_int() failed");
781                 ret = -EIO;
782         }
783
784         reply = dbus_message_new_method_return(msg);
785         dbus_message_iter_init_append(reply, &iter);
786         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
787         return reply;
788 }
789
790 static DBusMessage *dbus_get_percent(E_DBus_Object *obj, DBusMessage *msg)
791 {
792         DBusMessageIter iter;
793         DBusMessage *reply;
794         int ret;
795
796         ret = battery.capacity;
797
798         reply = dbus_message_new_method_return(msg);
799         dbus_message_iter_init_append(reply, &iter);
800         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
801         return reply;
802 }
803
804 static DBusMessage *dbus_get_percent_raw(E_DBus_Object *obj, DBusMessage *msg)
805 {
806         DBusMessageIter iter;
807         DBusMessage *reply;
808         int ret, val;
809
810         ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CAPACITY_RAW, &val);
811         if (ret < 0)
812                 goto out;
813
814         if (val > 10000)
815                 val = 10000;
816
817         ret = val;
818
819 out:
820         reply = dbus_message_new_method_return(msg);
821         dbus_message_iter_init_append(reply, &iter);
822         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
823         return reply;
824 }
825
826 static DBusMessage *dbus_is_full(E_DBus_Object *obj, DBusMessage *msg)
827 {
828         DBusMessageIter iter;
829         DBusMessage *reply;
830         int ret;
831
832         ret = battery.charge_full;
833
834         reply = dbus_message_new_method_return(msg);
835         dbus_message_iter_init_append(reply, &iter);
836         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
837         return reply;
838 }
839
840 static DBusMessage *dbus_get_health(E_DBus_Object *obj, DBusMessage *msg)
841 {
842         DBusMessageIter iter;
843         DBusMessage *reply;
844         int ret;
845
846         ret = battery.health;
847
848         reply = dbus_message_new_method_return(msg);
849         dbus_message_iter_init_append(reply, &iter);
850         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
851         return reply;
852 }
853
854 static const struct edbus_method edbus_methods[] = {
855         { CHARGER_STATUS_SIGNAL,      NULL, "i", dbus_get_charger_status },
856         { CHARGE_NOW_SIGNAL,          NULL, "i", dbus_get_charge_now },
857         { CHARGE_LEVEL_SIGNAL,        NULL, "i", dbus_get_charge_level },
858         { CHARGE_CAPACITY_SIGNAL,     NULL, "i", dbus_get_percent },
859         { CHARGE_CAPACITY_LAW_SIGNAL, NULL, "i", dbus_get_percent_raw },
860         { CHARGE_FULL_SIGNAL,         NULL, "i", dbus_is_full },
861         { CHARGE_HEALTH_SIGNAL,       NULL, "i", dbus_get_health },
862 };
863
864 static int alert_popup_cb(keynode_t *key_nodes, void *data)
865 {
866         alert_popup = vconf_keynode_get_bool(key_nodes);
867         _D("changed alert popup %d", alert_popup);
868         return alert_popup;
869 }
870
871 int power_supply_init(void *data)
872 {
873         int ret;
874
875         ret = vconf_get_bool(VCONFKEY_TESTMODE_TEMP_ALERT_POPUP, &alert_popup);
876         if (ret < 0)
877                 _E("fail to get alert popup status");
878         vconf_notify_key_changed(VCONFKEY_TESTMODE_TEMP_ALERT_POPUP, (void *)alert_popup_cb, NULL);
879
880         ret = register_edbus_method(DEVICED_PATH_BATTERY, edbus_methods, ARRAY_SIZE(edbus_methods));
881         if (ret < 0)
882                 _E("fail to init edbus method(%d)", ret);
883         ret = register_edbus_signal_handler(DEVICED_PATH_SYSNOTI,
884                         DEVICED_INTERFACE_SYSNOTI, SIGNAL_CHARGEERR_RESPONSE,
885                         abnormal_popup_edbus_signal_handler);
886         if (ret < 0)
887                 _E("fail to init edbus signal(%d)", ret);
888
889         /* for simple noti change cb */
890         power_supply_status_init();
891         power_supply(NULL);
892         return ret;
893 }