Initialize Tizen 2.3
[framework/system/deviced.git] / src / battery / lowbat-handler.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 <stdbool.h>
21 #include <assert.h>
22 #include <limits.h>
23 #include <vconf.h>
24 #include <fcntl.h>
25
26 #include "battery.h"
27 #include "config.h"
28 #include "core/log.h"
29 #include "core/launch.h"
30 #include "core/noti.h"
31 #include "core/queue.h"
32 #include "core/data.h"
33 #include "core/devices.h"
34 #include "core/device-handler.h"
35 #include "core/device-notifier.h"
36 #include "core/common.h"
37 #include "core/list.h"
38 #include "device-node.h"
39 #include "display/setting.h"
40 #include "display/poll.h"
41 #include "core/edbus-handler.h"
42 #include "core/power-supply.h"
43
44 #define PREDEF_LOWBAT                   "lowbat"
45 #define PREDEF_LOWBAT_CHANGE_FREQ       "lowbat_change_freq"
46
47 #define CHARGE_POWERSAVE_FREQ_ACT       "charge_powersave_freq_act"
48 #define CHARGE_RELEASE_FREQ_ACT         "charge_release_freq_act"
49
50
51 #define BATTERY_CHARGING        65535
52 #define BATTERY_UNKNOWN         -1
53 #define BATTERY_FULL            100
54
55 #define WARNING_LOW_BAT_ACT             "warning_low_bat_act"
56 #define CRITICAL_LOW_BAT_ACT            "critical_low_bat_act"
57 #define POWER_OFF_BAT_ACT               "power_off_bat_act"
58 #define CHARGE_BAT_ACT                  "charge_bat_act"
59 #define CHARGE_CHECK_ACT                        "charge_check_act"
60 #define CHARGE_ERROR_ACT                        "charge_error_act"
61 #define CHARGE_ERROR_LOW_ACT                    "charge_error_low_act"
62 #define CHARGE_ERROR_HIGH_ACT                   "charge_error_high_act"
63 #define CHARGE_ERROR_OVP_ACT                    "charge_error_ovp_act"
64 #define WAITING_INTERVAL        10
65
66 #define LOWBAT_CPU_CTRL_ID      "id6"
67 #define LOWBAT_CPU_FREQ_RATE    (0.7)
68
69 #define LOWBAT_POPUP_NAME "lowbat-syspopup"
70 #define LOWBAT_EXEC_PATH                PREFIX"/bin/lowbatt-popup"
71
72 struct popup_data {
73         char *name;
74         char *key;
75         char *value;
76 };
77
78 struct lowbat_process_entry {
79         int old;
80         int now;
81         int (*func) (void *data);
82 };
83
84 static int cur_bat_state = BATTERY_UNKNOWN;
85 static int cur_bat_capacity = -1;
86
87 static int lowbat_popup_option = 0;
88 static int lowbat_freq = -1;
89 static struct battery_config_info battery_info;
90
91 static dd_list *lpe = NULL;
92 static int scenario_count = 0;
93
94 static int lowbat_initialized(void *data)
95 {
96         static int status;
97
98         if (!data)
99                 return status;
100
101         status = *(int *)data;
102         return status;
103 }
104
105 int lowbat_scenario(int old, int now, void *data)
106 {
107         dd_list *n;
108         struct lowbat_process_entry *scenario;
109         int found = 0;
110
111         DD_LIST_FOREACH(lpe, n, scenario) {
112                 if (old != scenario->old || now != scenario->now)
113                         continue;
114                 if (!scenario->func)
115                         continue;
116                 scenario->func(data);
117                 found = 1;
118                 break;
119         }
120         return found;
121 }
122
123 int lowbat_add_scenario(int old, int now, int (*func)(void *data))
124 {
125         struct lowbat_process_entry *scenario;
126
127         _I("%d %d, %x", old, now, func);
128
129         if (!func) {
130                 _E("invalid func address!");
131                 return -EINVAL;
132         }
133
134         scenario = malloc(sizeof(struct lowbat_process_entry));
135         if (!scenario) {
136                 _E("Fail to malloc for notifier!");
137                 return -ENOMEM;
138         }
139
140         scenario->old = old;
141         scenario->now = now;
142         scenario->func = func;
143
144         DD_LIST_APPEND(lpe, scenario);
145         scenario_count++;
146         return 0;
147 }
148
149 static void print_lowbat_state(unsigned int bat_percent)
150 {
151 #if 0
152         int i;
153         for (i = 0; i < BAT_MON_SAMPLES; i++)
154                 _D("\t%d", recent_bat_percent[i]);
155 #endif
156 }
157
158 int battery_check_act(void *data)
159 {
160         notify_action(PREDEF_LOWBAT, 1, CHARGE_CHECK_ACT);
161         return 0;
162 }
163
164 int battery_warning_low_act(void *data)
165 {
166         notify_action(PREDEF_LOWBAT, 1, WARNING_LOW_BAT_ACT);
167         return 0;
168 }
169
170 int battery_critical_low_act(void *data)
171 {
172         notify_action(PREDEF_LOWBAT, 1, CRITICAL_LOW_BAT_ACT);
173         return 0;
174 }
175
176 int battery_power_off_act(void *data)
177 {
178         vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, VCONFKEY_SYSMAN_POWER_OFF_DIRECT);
179         return 0;
180 }
181
182 int battery_charge_err_act(void *data)
183 {
184         notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_ACT);
185         return 0;
186 }
187
188 int battery_charge_err_low_act(void *data)
189 {
190         notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_LOW_ACT);
191         return 0;
192 }
193
194 int battery_charge_err_high_act(void *data)
195 {
196         notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_HIGH_ACT);
197         return 0;
198 }
199
200 int battery_charge_err_ovp_act(void *data)
201 {
202         notify_action(PREDEF_LOWBAT, 1, CHARGE_ERROR_OVP_ACT);
203         return 0;
204 }
205
206 static int battery_charge_act(void *data)
207 {
208 #ifdef NOUSE
209         int val;
210         char argstr[128];
211
212         /* instead of adding action to the queue, execute it right here */
213         if (device_get_property(DEVTYPE_JACK, JACK_PROP_TA_ONLINE, &val) == 0
214             && val == 1) {
215                 snprintf(argstr, 128, "-t 4");
216                 launch_after_kill_if_exist(LOWBAT_EXEC_PATH, argstr);
217         }
218 #endif
219         return 0;
220 }
221
222 static void lowbat_scenario_init(void)
223 {
224         lowbat_add_scenario(battery_info.normal, battery_info.warning, battery_warning_low_act);
225         lowbat_add_scenario(battery_info.warning, battery_info.critical, battery_warning_low_act);
226         lowbat_add_scenario(battery_info.critical, battery_info.poweroff, battery_critical_low_act);
227         lowbat_add_scenario(battery_info.poweroff, battery_info.realoff, battery_power_off_act);
228         lowbat_add_scenario(battery_info.normal, battery_info.critical, battery_warning_low_act);
229         lowbat_add_scenario(battery_info.warning, battery_info.poweroff, battery_critical_low_act);
230         lowbat_add_scenario(battery_info.critical, battery_info.realoff, battery_power_off_act);
231         lowbat_add_scenario(battery_info.normal, battery_info.poweroff, battery_critical_low_act);
232         lowbat_add_scenario(battery_info.warning, battery_info.realoff, battery_power_off_act);
233         lowbat_add_scenario(battery_info.normal, battery_info.realoff, battery_power_off_act);
234         lowbat_add_scenario(battery_info.realoff, battery_info.realoff, battery_power_off_act);
235         lowbat_add_scenario(battery_info.realoff, battery_info.normal, battery_check_act);
236         lowbat_add_scenario(battery_info.realoff, battery_info.warning, battery_check_act);
237         lowbat_add_scenario(battery_info.realoff, battery_info.critical, battery_check_act);
238         lowbat_add_scenario(battery_info.realoff, battery_info.poweroff, battery_check_act);
239 }
240
241 static void change_lowbat_level(int bat_percent)
242 {
243         int prev, now;
244
245         if (cur_bat_capacity == bat_percent)
246                 return;
247
248         if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, &prev) < 0) {
249                 _E("vconf_get_int() failed");
250                 return;
251         }
252
253
254         if (bat_percent > BATTERY_LEVEL_CHECK_FULL) {
255                 now = VCONFKEY_SYSMAN_BAT_LEVEL_FULL;
256         } else if (bat_percent > BATTERY_LEVEL_CHECK_HIGH) {
257                 now = VCONFKEY_SYSMAN_BAT_LEVEL_HIGH;
258         } else if (bat_percent > BATTERY_LEVEL_CHECK_LOW) {
259                 now = VCONFKEY_SYSMAN_BAT_LEVEL_LOW;
260         } else if (bat_percent > BATTERY_LEVEL_CHECK_CRITICAL) {
261                 now = VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL;
262         } else {
263                 now = VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY;
264         }
265
266         if (prev != now)
267                 vconf_set_int(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS, now);
268 }
269
270 static int lowbat_process(int bat_percent, void *ad)
271 {
272         int new_bat_capacity;
273         int new_bat_state;
274         int vconf_state = -1;
275         int i, ret = 0;
276         int status = -1;
277         bool low_bat = false;
278         bool full_bat = false;
279         int extreme = 0;
280         int result = 0;
281
282         new_bat_capacity = bat_percent;
283         if (new_bat_capacity < 0)
284                 return -EINVAL;
285         change_lowbat_level(new_bat_capacity);
286         pm_lock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, STAY_CUR_STATE, 0);
287
288         if (new_bat_capacity != cur_bat_capacity) {
289                 _D("[BAT_MON] cur = %d new = %d", cur_bat_capacity, new_bat_capacity);
290                 if (vconf_set_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, new_bat_capacity) == 0)
291                         cur_bat_capacity = new_bat_capacity;
292         }
293
294         if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &vconf_state) < 0) {
295                 _E("vconf_get_int() failed");
296                 result = -EIO;
297                 goto exit;
298         }
299
300         if (new_bat_capacity <= battery_info.realoff) {
301                 if (battery.charge_now) {
302                         new_bat_state = battery_info.poweroff;
303                         if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
304                                 status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
305                 } else {
306                         new_bat_state = battery_info.realoff;
307                         if (vconf_state != VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF)
308                                 status = VCONFKEY_SYSMAN_BAT_REAL_POWER_OFF;
309                 }
310         } else if (new_bat_capacity <= battery_info.poweroff) {
311                 new_bat_state = battery_info.poweroff;
312                 if (vconf_state != VCONFKEY_SYSMAN_BAT_POWER_OFF)
313                         status = VCONFKEY_SYSMAN_BAT_POWER_OFF;
314         } else if (new_bat_capacity <= battery_info.critical) {
315                 new_bat_state = battery_info.critical;
316                 if (vconf_state != VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
317                         status = VCONFKEY_SYSMAN_BAT_CRITICAL_LOW;
318         } else if (new_bat_capacity <= battery_info.warning) {
319                 new_bat_state = battery_info.warning;
320                 if (vconf_state != VCONFKEY_SYSMAN_BAT_WARNING_LOW)
321                         status = VCONFKEY_SYSMAN_BAT_WARNING_LOW;
322         } else {
323                 new_bat_state = battery_info.normal;
324                 if (new_bat_capacity == BATTERY_FULL) {
325                         if (battery.charge_full) {
326                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_FULL)
327                                         status = VCONFKEY_SYSMAN_BAT_FULL;
328                                 full_bat = true;
329                         } else {
330                                 if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
331                                         status = VCONFKEY_SYSMAN_BAT_NORMAL;
332                         }
333                 } else {
334                         if (vconf_state != VCONFKEY_SYSMAN_BAT_NORMAL)
335                                 status = VCONFKEY_SYSMAN_BAT_NORMAL;
336                 }
337         }
338
339
340         if (status != -1) {
341                 ret = vconf_set_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, status);
342                 power_supply_broadcast(CHARGE_LEVEL_SIGNAL, status);
343                 if (update_pm_setting)
344                         update_pm_setting(SETTING_LOW_BATT, status);
345         }
346
347         if (ret < 0) {
348                 result = -EIO;
349                 goto exit;
350         }
351
352         if (vconf_get_int(VCONFKEY_PM_KEY_IGNORE, &extreme) == 0 && extreme == TRUE &&
353             (status > VCONFKEY_SYSMAN_BAT_POWER_OFF && status <= VCONFKEY_SYSMAN_BAT_FULL))
354                 if (vconf_set_int(VCONFKEY_PM_KEY_IGNORE, FALSE) == 0)
355                         _I("release key ignore");
356
357         if (new_bat_capacity <= battery_info.warning)
358                 low_bat = true;
359
360         device_notify(DEVICE_NOTIFIER_LOWBAT, (void*)low_bat);
361
362         if (cur_bat_state == new_bat_state && new_bat_state > battery_info.realoff)
363                 goto exit;
364
365         if (cur_bat_state == BATTERY_UNKNOWN)
366                 cur_bat_state = battery_info.normal;
367         result = lowbat_scenario(cur_bat_state, new_bat_state, NULL);
368         if (result)
369                 _I("cur_bat_state %d, new_bat_state %d", cur_bat_state, new_bat_state);
370         cur_bat_state = new_bat_state;
371 exit:
372         pm_unlock_internal(INTERNAL_LOCK_BATTERY, LCD_OFF, PM_SLEEP_MARGIN);
373
374         return result;
375 }
376
377 static int lowbat_read()
378 {
379         int bat_percent, r;
380
381         r = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_CAPACITY, &bat_percent);
382         if (r < 0)
383                 return r;
384
385         return bat_percent;
386 }
387
388 static void change_lowbat_cpu_freq(int bat_percent)
389 {
390         static int init_cpu_freq = 0;
391         static int power_save = 0;
392         if (cur_bat_capacity == bat_percent)
393                 return;
394
395         if (bat_percent > battery_info.poweroff && init_cpu_freq == 0) {
396                 init_cpu_freq = 1;
397                 notify_action(PREDEF_LOWBAT_CHANGE_FREQ, 1, CHARGE_RELEASE_FREQ_ACT);
398                 return;
399         }
400
401         if (bat_percent <= battery_info.poweroff && power_save == 0) {
402                 power_save = 1;
403                 notify_action(PREDEF_LOWBAT_CHANGE_FREQ, 1, CHARGE_POWERSAVE_FREQ_ACT);
404         } else if (power_save == 1) {
405                 power_save = 0;
406                 notify_action(PREDEF_LOWBAT_CHANGE_FREQ, 1, CHARGE_RELEASE_FREQ_ACT);
407         }
408 }
409
410 static int check_lowbat_percent(int *pct)
411 {
412         int bat_percent;
413
414         bat_percent = lowbat_read();
415         if (bat_percent < 0) {
416                 _E("[BATMON] Cannot read battery gage. stop read fuel gage");
417                 return -ENODEV;
418         }
419         if (bat_percent > 100)
420                 bat_percent = 100;
421         change_lowbat_level(bat_percent);
422         change_lowbat_cpu_freq(bat_percent);
423         *pct = bat_percent;
424         return 0;
425 }
426
427 void lowbat_monitor(void *data)
428 {
429         int bat_percent, r;
430
431         r = lowbat_initialized(NULL);
432         if (!r)
433                 return;
434
435         if (data == NULL) {
436                 r = check_lowbat_percent(&bat_percent);
437                 if (r < 0)
438                         return;
439         } else
440                 bat_percent = *(int *)data;
441         print_lowbat_state(bat_percent);
442         lowbat_process(bat_percent, NULL);
443 }
444
445 /* for debugging (request by kernel) */
446 static int check_battery()
447 {
448         int r;
449         int ret = -1;
450
451         if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_PRESENT, &ret) < 0) {
452                 _E("FAIL: device_get_property(): [BATMON] battery check : %d", ret);
453         }
454         _D("[BATMON] battery check : %d", ret);
455
456         return ret;
457 }
458
459 static int booting_done(void *data)
460 {
461         static int done = 0;
462
463         if (data == NULL)
464                 goto out;
465         done = (int)data;
466         if (!done)
467                 goto out;
468         _I("booting done");
469 out:
470         return done;
471 }
472
473 int lowbat_action(int argc, char **argv)
474 {
475         int ret, state=0;
476         char argstr[128];
477         char* option = NULL;
478         char *value;
479         static int launched_poweroff = 0;
480         pid_t pid;
481         struct popup_data *params;
482         static const struct device_ops *apps = NULL;
483
484         if (argc < 1)
485                 return -1;
486
487         if (strcmp(argv[0], POWER_OFF_BAT_ACT))
488                 launched_poweroff = 0;
489
490         if (!strcmp(argv[0], CRITICAL_LOW_BAT_ACT)) {
491                 value = "extreme";
492                 lowbat_popup_option = LOWBAT_OPT_CHECK;
493         } else if (!strcmp(argv[0], WARNING_LOW_BAT_ACT)) {
494                 if (is_factory_mode() == 1)
495                         return 0;
496                 value = "warning";
497                 lowbat_popup_option = LOWBAT_OPT_WARNING;
498         } else if (!strcmp(argv[0], POWER_OFF_BAT_ACT)) {
499                 value = "poweroff";
500                 lowbat_popup_option = LOWBAT_OPT_POWEROFF;
501         } else if (!strcmp(argv[0], CHARGE_ERROR_ACT)) {
502                 value = "chargeerr";
503                 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
504         } else if (!strcmp(argv[0], CHARGE_ERROR_LOW_ACT)) {
505                 value = "chargeerrlow";
506                 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
507         } else if (!strcmp(argv[0], CHARGE_ERROR_HIGH_ACT)) {
508                 value = "chargeerrhigh";
509                 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
510         } else if (!strcmp(argv[0], CHARGE_ERROR_OVP_ACT)) {
511                 value = "chargeerrovp";
512                 lowbat_popup_option = LOWBAT_OPT_CHARGEERR;
513         } else if (!strcmp(argv[0], CHARGE_CHECK_ACT)) {
514                 launched_poweroff = 0;
515                 return 0;
516         } else
517                 return -1;
518         _D("%s", value);
519         ret = vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &state);
520         if (state == 1 || ret != 0 || booting_done(NULL)) {
521
522                 if (launched_poweroff == 1) {
523                         _I("will be foreced power off");
524                         do_poweroff(0, NULL);
525                         return 0;
526                 }
527
528                 if (lowbat_popup_option == LOWBAT_OPT_POWEROFF)
529                         launched_poweroff = 1;
530
531                 pid = predefine_get_pid(LOWBAT_EXEC_PATH);
532                 if (pid > 0) {
533                         _I("pre launched %s destroy", LOWBAT_EXEC_PATH);
534                         kill(pid, SIGTERM);
535                 }
536                 if (apps == NULL) {
537                         apps = find_device("apps");
538                         if (apps == NULL)
539                                 return 0;
540                 }
541                 params = malloc(sizeof(struct popup_data));
542                 if (params == NULL) {
543                         _E("Malloc failed");
544                         return -1;
545                 }
546                 pm_change_internal(getpid(), LCD_NORMAL);
547                 params->name = LOWBAT_POPUP_NAME;
548                 params->key = POPUP_KEY_CONTENT;
549                 params->value = strdup(value);
550                 apps->init((void *)params);
551                 free(params->value);
552                 free(params);
553         } else {
554                 _D("boot-animation running yet");
555         }
556
557         return 0;
558 }
559
560 static int check_power_save_mode(void)
561 {
562         int ret = 0;
563         int power_saving_cpu_stat = -1;
564
565         ret = vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_CPU,
566                         &power_saving_cpu_stat);
567         if (ret < 0) {
568                 _E("failed to get vconf key");
569                 return ret;
570         }
571
572         if (power_saving_cpu_stat == 1)
573                 ret = 1;
574         return ret;
575 }
576
577 int change_freq_action(int argc, char **argv)
578 {
579         int val = 0;
580
581         if (argc < 1)
582                 return -1;
583
584         if (!strcmp(argv[0], CHARGE_POWERSAVE_FREQ_ACT))
585                 val = 1;
586         device_notify(DEVICE_NOTIFIER_PMQOS_LOWBAT, (void*)val);
587         return 0;
588 }
589
590 static int lowbat_monitor_init(void *data)
591 {
592         int status = 1;
593
594         lowbat_initialized(&status);
595         unregister_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
596         battery_config_load(&battery_info);
597         _I("%d %d %d %d %d", battery_info.normal, battery_info.warning,
598                 battery_info.critical, battery_info.poweroff, battery_info.realoff);
599         lowbat_scenario_init();
600         register_action(PREDEF_LOWBAT, lowbat_action, NULL, NULL);
601         register_action(PREDEF_LOWBAT_CHANGE_FREQ, change_freq_action, NULL, NULL);
602         lowbat_process(battery.capacity, NULL);
603         return 0;
604 }
605
606 static void lowbat_init(void *data)
607 {
608         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
609         register_notifier(DEVICE_NOTIFIER_POWER_SUPPLY, lowbat_monitor_init);
610 }
611
612 static void lowbat_exit(void *data)
613 {
614         int status = 0;
615
616         lowbat_initialized(&status);
617         unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
618 }
619
620 static const struct device_ops lowbat_device_ops = {
621         .priority = DEVICE_PRIORITY_NORMAL,
622         .name     = "lowbat",
623         .init     = lowbat_init,
624         .exit    = lowbat_exit,
625 };
626
627 DEVICE_OPS_REGISTER(&lowbat_device_ops)