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