Initialize Tizen 2.3
[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
26 #include "devices.h"
27 #include "predefine.h"
28 #include "device-handler.h"
29 #include "device-notifier.h"
30 #include "udev.h"
31 #include "log.h"
32 #include "emulator.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"
38
39 #define BUFF_MAX                255
40 #define POPUP_KEY_CONTENT               "_SYSPOPUP_CONTENT_"
41
42 #define PREDEF_BATTERY_CF_OPENED        "battery_cf_opened"
43 #define SIGNAL_CHARGEERR_RESPONSE       "ChargeErrResponse"
44 #define SIGNAL_TEMP_GOOD                "TempGood"
45
46 #define ABNORMAL_CHECK_TIMER_INTERVAL   60
47
48 #define METHOD_FULL_NOTI_ON             "BatteryFullNotiOn"
49 #define METHOD_FULL_NOTI_OFF    "BatteryFullNotiOff"
50 #define METHOD_CHARGE_NOTI_ON   "BatteryChargeNotiOn"
51
52 #define SIOP_DISABLE    "memory/private/sysman/siop_disable"
53
54 #define RETRY_MAX 5
55 #define BATTERY_CHECK_TIMER_INTERVAL    (0.5)
56
57 #ifdef MICRO_DD
58 #define DEVICE_NOTIFIER "/usr/bin/sys_device_noti"
59 #define BATT_CHARGE_NOTI "0"
60 #define BATT_FULL_NOTI   "2"
61 #endif
62 struct popup_data {
63         char *name;
64         char *key;
65         char *value;
66 };
67
68 static Ecore_Timer *power_timer = NULL;
69 static Ecore_Timer *abnormal_timer = NULL;
70 extern int battery_power_off_act(void *data);
71
72 static void pm_check_and_change(int bInserted)
73 {
74         static int old = -1;
75         if (old != bInserted) {
76                 old = bInserted;
77                 predefine_pm_change_state(LCD_NORMAL);
78         }
79 }
80
81 int check_lowbat_charge_device(int bInserted)
82 {
83         static int bChargeDeviceInserted = 0;
84         int val = -1;
85         int bat_state = -1;
86         int ret = -1;
87         char *value;
88         struct popup_data *params;
89         static const struct device_ops *apps = NULL;
90
91         pm_check_and_change(bInserted);
92         if (bInserted == 1) {
93                 if (battery.charge_now)
94                         bChargeDeviceInserted = 1;
95                 return 0;
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) {
103                                         if (apps == NULL) {
104                                                 apps = find_device("apps");
105                                                 if (apps == NULL)
106                                                         return 0;
107                                         }
108                                         if(bat_state == VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
109                                                 value = "poweroff";
110                                         else if (bat_state == VCONFKEY_SYSMAN_BAT_POWER_OFF)
111                                                 value = "extreme";
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(int argc, char **argv)
138 {
139         int present_status;
140         struct popup_data *params;
141         static const struct device_ops *apps = NULL;
142
143         if (argc != 1)
144                 return -EINVAL;
145         present_status = atoi(argv[0]);
146
147         if (apps == NULL) {
148                 apps = find_device("apps");
149                 if (apps == NULL)
150                         return 0;
151         }
152         params = malloc(sizeof(struct popup_data));
153         if (params == NULL) {
154                 _E("Malloc failed");
155                 return -ENOMEM;
156         }
157         params->name = "lowbat-syspopup";
158         params->key = POPUP_KEY_CONTENT;
159         params->value = "battdisconnect";
160         if (apps->init == NULL || apps->exit == NULL)
161                 goto out;
162         if (present_status == PRESENT_ABNORMAL)
163                 apps->init((void *)params);
164         else
165                 apps->exit((void *)params);
166 out:
167         free(params);
168         return 0;
169 }
170
171 int check_abnormal_popup(void)
172 {
173         int ret = HEALTH_BAD;
174
175         if (abnormal_timer)
176                 ret =  HEALTH_GOOD;
177         return ret;
178 }
179
180 static void abnormal_popup_timer_init(void)
181 {
182         if (abnormal_timer == NULL)
183                 return;
184         ecore_timer_del(abnormal_timer);
185         abnormal_timer = NULL;
186         _I("delete health timer");
187 }
188
189 static void health_status_broadcast(void)
190 {
191         broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
192             SIGNAL_TEMP_GOOD, NULL, NULL);
193 }
194
195 static int clean_health_popup(void)
196 {
197         struct popup_data *params;
198         static const struct device_ops *apps = NULL;
199
200         if (apps == NULL) {
201                 apps = find_device("apps");
202                 if (apps == NULL)
203                         return 0;
204         }
205         params = malloc(sizeof(struct popup_data));
206         if (params == NULL) {
207                 _E("Malloc failed");
208                 return -ENOMEM;
209         }
210         params->name = "lowbat-syspopup";
211         params->key = POPUP_KEY_CONTENT;
212         if (apps->exit)
213                 apps->exit((void *)params);
214         health_status_broadcast();
215 out:
216         free(params);
217         return 0;
218
219 }
220
221 static void health_timer_reset(void)
222 {
223         abnormal_timer = NULL;
224 }
225
226 static Eina_Bool health_timer_cb(void *data)
227 {
228         health_timer_reset();
229
230         if (battery.health == HEALTH_GOOD)
231                 return EINA_FALSE;
232
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);
242         return EINA_FALSE;
243 }
244
245 static void abnormal_popup_edbus_signal_handler(void *data, DBusMessage *msg)
246 {
247         if (battery.health == HEALTH_GOOD)
248                 return;
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");
254 }
255
256 static int noti_id;
257
258 static void full_noti_cb(void *data, DBusMessage *msg, DBusError *err)
259 {
260         DBusError r_err;
261         int ret, id;
262
263         if (!msg)
264                 return;
265
266         dbus_error_init(&r_err);
267         ret = dbus_message_get_args(msg, &r_err, DBUS_TYPE_INT32, &id, DBUS_TYPE_INVALID);
268         if (!ret) {
269                 _E("no message [%s:%s]", r_err.name, r_err.message);
270                 dbus_error_free(&r_err);
271                 return;
272         }
273
274         noti_id = id;
275         _D("Inserted battery full noti : %d", noti_id);
276 }
277
278 static int send_full_noti(enum charge_full_type state)
279 {
280         int ret = 0;
281 #ifdef MICRO_DD
282         char params[BUFF_MAX];
283         snprintf(params, sizeof(params), "%s %d", BATT_FULL_NOTI, state);
284         launch_evenif_exist(DEVICE_NOTIFIER, params);
285 #else
286         int retry;
287         char str_id[32];
288         char *arr[1];
289
290         switch (state) {
291         case CHARGING_FULL:
292                 for (retry = RETRY_MAX; retry > 0 ;retry--) {
293                         ret = dbus_method_async_with_reply(POPUP_BUS_NAME,
294                                         POPUP_PATH_BATTERY,
295                                         POPUP_INTERFACE_BATTERY,
296                                         METHOD_FULL_NOTI_ON,
297                                         NULL, NULL, full_noti_cb, -1, NULL);
298                         if (ret == 0) {
299                                 _D("Created battery full noti");
300                                 return ret;
301                         }
302                 }
303                 _E("Failed to call dbus method (err: %d)", ret);
304         break;
305         case CHARGING_NOT_FULL:
306                 if (noti_id <= 0)
307                         return -EPERM;
308                 snprintf(str_id, sizeof(str_id), "%d", noti_id);
309                 arr[0] = str_id;
310                 for (retry = RETRY_MAX; retry > 0 ;retry--) {
311                         ret = dbus_method_async(POPUP_BUS_NAME,
312                                         POPUP_PATH_BATTERY,
313                                         POPUP_INTERFACE_BATTERY,
314                                         METHOD_FULL_NOTI_OFF,
315                                         "i", arr);
316                         if (ret == 0) {
317                                 _D("Deleted battery full noti");
318                                 noti_id = 0;
319                                 return ret;
320                         }
321                 }
322                 _E("Failed to call dbus method (err: %d)", ret);
323         break;
324         }
325 #endif
326         return ret;
327 }
328
329 int send_charge_noti(void)
330 {
331         int ret = 0;
332 #ifdef MICRO_DD
333         launch_evenif_exist(DEVICE_NOTIFIER, BATT_CHARGE_NOTI);
334 #else
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 #endif
350         return ret;
351 }
352
353 void battery_noti(enum battery_noti_type type, enum battery_noti_status status)
354 {
355         static int charge = CHARGER_DISCHARGING;
356         static int full = CHARGING_NOT_FULL;
357         int ret, i;
358
359         if (type == DEVICE_NOTI_BATT_FULL && status == DEVICE_NOTI_ON &&
360             full == CHARGING_NOT_FULL) {
361                 ret = send_full_noti(CHARGING_FULL);
362                 if (ret == 0)
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);
367                 if (ret == 0)
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);
374                         if (ret == 0)
375                                 full = CHARGING_NOT_FULL;
376                 }
377                 send_charge_noti();
378         }
379         charge = battery.charge_now;
380 }
381
382 static void noti_batt_full(void)
383 {
384         char params[BUFF_MAX];
385         static int bat_full_noti = 0;
386
387         if (!battery.charge_full && bat_full_noti == 1) {
388                 battery_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_OFF);
389                 bat_full_noti = 0;
390                 /* off the full charge state */
391                 device_notify(DEVICE_NOTIFIER_FULLBAT, (void*)false);
392         }
393         if (battery.charge_full && bat_full_noti == 0) {
394                 battery_noti(DEVICE_NOTI_BATT_FULL, DEVICE_NOTI_ON);
395                 bat_full_noti = 1;
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);
400         }
401 }
402
403 static void check_power_supply(int state)
404 {
405         int ret = -1;
406         int val = 0;
407         char params[BUFF_MAX];
408
409         check_lowbat_charge_device(state);
410         if (update_pm_setting)
411                 update_pm_setting(SETTING_CHARGING, state);
412
413         ret = device_get_property(DEVICE_TYPE_POWER,
414                 PROP_POWER_INSUSPEND_CHARGING_SUPPORT, &val);
415
416         if (ret != 0 || val == 1) {
417                 _D("fail to check charger insuspend");
418                 goto out;
419         }
420
421         if (state == 0)
422                 pm_unlock_internal(INTERNAL_LOCK_TA, LCD_OFF, STAY_CUR_STATE);
423         else
424                 pm_lock_internal(INTERNAL_LOCK_TA, LCD_OFF, STAY_CUR_STATE, 0);
425 out:
426         _I("ta device %d", state);
427
428         sync_cradle_status();
429 }
430
431 static void update_present(enum battery_noti_status status)
432 {
433         static int old = DEVICE_NOTI_OFF;
434         char params[BUFF_MAX];
435
436         if (old == status)
437                 return;
438         _I("charge %d present %d", battery.charge_now, battery.present);
439         old = status;
440         pm_change_internal(getpid(), LCD_NORMAL);
441         if (status == DEVICE_NOTI_ON)
442                 snprintf(params, sizeof(params), "%d", PRESENT_ABNORMAL);
443         else
444                 snprintf(params, sizeof(params), "%d", PRESENT_NORMAL);
445         notify_action(PREDEF_BATTERY_CF_OPENED, 1, params);
446 }
447
448 static void update_health(enum battery_noti_status status)
449 {
450         static int old = DEVICE_NOTI_OFF;
451
452         if (old == status)
453                 return;
454         _I("charge %d health %d", battery.charge_now, battery.health);
455         old = status;
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);
466         } else {
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();
472         }
473 }
474
475 static void update_ovp(enum battery_noti_status status)
476 {
477         static int old = DEVICE_NOTI_OFF;
478
479         if (old == status)
480                 return;
481         _I("charge %d ovp %d", battery.charge_now, battery.ovp);
482         old = status;
483         pm_change_internal(getpid(), LCD_NORMAL);
484         if (status == DEVICE_NOTI_ON)
485                 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_ABNORMAL);
486         else
487                 device_notify(DEVICE_NOTIFIER_BATTERY_OVP, (void *)OVP_NORMAL);
488 }
489
490 static void check_battery_status(void)
491 {
492         static int old = DEVICE_CHANGE_NORMAL;
493         int status;
494
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;
500         else
501                 status = DEVICE_CHANGE_NORMAL;
502         if (old == status)
503                 return;
504         old = status;
505
506         if (battery.charge_now == CHARGER_ABNORMAL) {
507                 if (battery.health == HEALTH_BAD) {
508                         update_health(DEVICE_NOTI_ON);
509                         return;
510                 } else if (battery.present == PRESENT_ABNORMAL) {
511                         update_present(DEVICE_NOTI_ON);
512                         return;
513                 }
514         }
515         if (battery.ovp == OVP_ABNORMAL) {
516                 update_ovp(DEVICE_NOTI_ON);
517                 return;
518         }
519
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);
525         }
526 }
527
528 static void check_online(void)
529 {
530         static int old_online;
531
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);
545         }
546 }
547
548 static void charge_cb(struct main_data *ad)
549 {
550         int val = -1;
551         int ret;
552         static int present_status = PRESENT_NORMAL;
553
554         lowbat_monitor(NULL);
555
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");
559
560         if (battery.charge_now > 0)
561                 battery.charge_now = CHARGER_CHARGING;
562         else
563                 battery.charge_now = CHARGER_DISCHARGING;
564
565         if (battery.charge_now != CHARGER_CHARGING && battery.capacity == 0) {
566                 _I("target will be shut down");
567                 battery_power_off_act(NULL);
568                 return;
569         }
570
571         ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_PRESENT, &val);
572         if (ret != 0) {
573                 battery.present = PRESENT_NORMAL;
574                 _E("fail to get battery present value");
575                 goto check_health;
576         }
577 check_health:
578         ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_HEALTH, &val);
579         if (ret != 0) {
580                 battery.health = HEALTH_GOOD;
581                 battery.ovp = OVP_NORMAL;
582                 _E("failed to get battery health status");
583                 goto check_full;
584         }
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;
595         } else {
596                 battery.health = HEALTH_GOOD;
597         }
598 check_full:
599         ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CHARGE_FULL, &val);
600         if (ret == 0)
601                 battery.charge_full = val;
602         noti_batt_full();
603         check_battery_status();
604         device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, (void*)battery.charge_now);
605 }
606
607 static int load_uevent(struct parse_result *result, void *user_data)
608 {
609         struct battery_status *info = user_data;
610
611         if (!info)
612                 return -EINVAL;
613
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;
627                 }
628         }
629         else if (MATCH(result->name, CAPACITY))
630                 info->capacity = atoi(result->value);
631         return 0;
632 }
633
634 static void power_load_uevent(void)
635 {
636         int ret;
637         ret = config_parse(POWER_SUPPLY_UEVENT, load_uevent, &battery);
638         if (ret < 0)
639                 _E("Failed to load %s, %d Use default value!", POWER_SUPPLY_UEVENT, ret);
640 }
641
642 void power_supply(void *data)
643 {
644         int ret;
645
646         static int old_charge;
647
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);
652         }
653
654         lowbat_monitor(data);
655         check_online();
656         noti_batt_full();
657         check_battery_status();
658         device_notify(DEVICE_NOTIFIER_POWER_SUPPLY, NULL);
659         device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, (void*)battery.charge_now);
660 }
661
662 void power_supply_status_init(void)
663 {
664         int ret, val;
665         static int charge_now = -1;
666         static int charge_full = -1;
667         static int capacity = -1;
668
669         power_load_uevent();
670         battery.health = HEALTH_GOOD;
671         battery.ovp = OVP_NORMAL;
672         battery.present = PRESENT_NORMAL;
673         battery.temp = TEMP_LOW;
674
675         if (charge_now == battery.charge_now &&
676             charge_full == battery.charge_full &&
677             capacity == battery.capacity)
678                 return;
679
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);
684
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);
688         }
689         if (capacity != battery.capacity)
690                 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, battery.capacity);
691
692         charge_now = battery.charge_now;
693         charge_full = battery.charge_full;
694         capacity =  battery.capacity;
695 }
696
697 static Eina_Bool power_supply_update(void *data)
698 {
699         power_supply_status_init();
700         return EINA_TRUE;
701 }
702
703 void power_supply_timer_start(void)
704 {
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");
710 }
711
712 void power_supply_timer_stop(void)
713 {
714     _D("battery init timer during booting");
715         if (!power_timer)
716                 return;
717         ecore_timer_del(power_timer);
718         power_timer = NULL;
719 }
720
721 void power_supply_broadcast(char *sig, int status)
722 {
723         static int old = 0;
724         static char sig_old[32];
725         char *arr[1];
726         char str_status[32];
727
728         if (strcmp(sig_old, sig) == 0 && old == status)
729                 return;
730
731         _D("%s %d", sig, status);
732
733         old = status;
734         snprintf(sig_old, sizeof(sig_old), "%s", sig);
735         snprintf(str_status, sizeof(str_status), "%d", status);
736         arr[0] = str_status;
737
738         broadcast_edbus_signal(DEVICED_PATH_BATTERY, DEVICED_INTERFACE_BATTERY,
739                         sig, "i", arr);
740 }
741
742 static DBusMessage *dbus_get_charger_status(E_DBus_Object *obj, DBusMessage *msg)
743 {
744         DBusMessageIter iter;
745         DBusMessage *reply;
746         int ret;
747
748         if (vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS, &ret) < 0) {
749                 _E("vconf_get_int() failed");
750                 ret = -EIO;
751         }
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);
755         return reply;
756 }
757
758 static DBusMessage *dbus_get_charge_now(E_DBus_Object *obj, DBusMessage *msg)
759 {
760         DBusMessageIter iter;
761         DBusMessage *reply;
762         int ret;
763
764         ret = battery.charge_now;
765
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);
769         return reply;
770 }
771
772 static DBusMessage *dbus_get_charge_level(E_DBus_Object *obj, DBusMessage *msg)
773 {
774         DBusMessageIter iter;
775         DBusMessage *reply;
776         int ret;
777
778         if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &ret) < 0) {
779                 _E("vconf_get_int() failed");
780                 ret = -EIO;
781         }
782
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);
786         return reply;
787 }
788
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 },
793 };
794
795 int power_supply_init(void *data)
796 {
797         int ret;
798         ret = register_edbus_method(DEVICED_PATH_BATTERY, edbus_methods, ARRAY_SIZE(edbus_methods));
799         if (ret < 0)
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);
804         if (ret < 0)
805                 _E("fail to init edbus signal(%d)", ret);
806
807         register_action(PREDEF_BATTERY_CF_OPENED, changed_battery_cf,
808                 NULL, NULL);
809
810         /* for simple noti change cb */
811         emulator_add_callback("device_charge_chgdet", (void *)charge_cb, data);
812         power_supply_status_init();
813         power_supply(NULL);
814         return ret;
815 }