Fix warnings from r31453
[maemo-rb.git] / firmware / powermgmt.c
blob4d554d6d3c2334121b66b94762522edcf7fa4f2f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese
11 * Revisions copyright (C) 2005 by Gerald Van Baren
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "config.h"
23 #include "system.h"
24 #include "kernel.h"
25 #include "thread.h"
26 #include "debug.h"
27 #include "adc.h"
28 #include "string.h"
29 #include "storage.h"
30 #include "power.h"
31 #include "audio.h"
32 #include "mp3_playback.h"
33 #include "usb.h"
34 #include "powermgmt.h"
35 #include "backlight.h"
36 #include "lcd.h"
37 #include "rtc.h"
38 #if CONFIG_TUNER
39 #include "fmradio.h"
40 #endif
41 #include "sound.h"
42 #ifdef HAVE_LCD_BITMAP
43 #include "font.h"
44 #endif
45 #include "logf.h"
46 #include "lcd-remote.h"
47 #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
48 #include <time.h>
49 #endif
51 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5)) && !defined (SIMULATOR)
52 #include "lcd-remote-target.h"
53 #endif
54 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) \
55 && !defined (SIMULATOR)
56 #include "pcf50606.h"
57 #endif
59 /** Shared by sim **/
60 int last_sent_battery_level = 100;
61 /* battery level (0-100%) */
62 int battery_percent = -1;
63 void send_battery_level_event(void);
65 static bool sleeptimer_active = false;
66 static long sleeptimer_endtick;
67 /* Whether an active sleep timer should be restarted when a key is pressed */
68 static bool sleeptimer_key_restarts = false;
69 /* The number of seconds the sleep timer was last set to */
70 static unsigned int sleeptimer_duration = 0;
72 #if CONFIG_CHARGING
73 /* State of the charger input as seen by the power thread */
74 enum charger_input_state_type charger_input_state;
75 /* Power inputs as seen by the power thread */
76 unsigned int power_thread_inputs;
77 #if CONFIG_CHARGING >= CHARGING_MONITOR
78 /* Charging state (mode) as seen by the power thread */
79 enum charge_state_type charge_state = DISCHARGING;
80 #endif
81 #endif /* CONFIG_CHARGING */
83 static int shutdown_timeout = 0;
85 void handle_auto_poweroff(void);
86 static int poweroff_timeout = 0;
87 static long last_event_tick = 0;
89 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
91 * Average battery voltage and charger voltage, filtered via a digital
92 * exponential filter (aka. exponential moving average, scaled):
93 * avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N.
95 static unsigned int avgbat;
96 /* filtered battery voltage, millivolts */
97 static unsigned int battery_millivolts;
98 /* default value, mAh */
99 static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
102 #if BATTERY_TYPES_COUNT > 1
103 static int battery_type = 0;
104 #else
105 #define battery_type 0
106 #endif
108 /* Power history: power_history[0] is the newest sample */
109 unsigned short power_history[POWER_HISTORY_LEN] = {0};
111 #if CONFIG_CPU == JZ4732 /* FIXME! */
112 static char power_stack[DEFAULT_STACK_SIZE + POWERMGMT_DEBUG_STACK];
113 #else
114 static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
115 #endif
116 static const char power_thread_name[] = "power";
118 static int powermgmt_est_runningtime_min = -1;
120 static int voltage_to_battery_level(int battery_millivolts);
121 static void battery_status_update(void);
123 #ifdef CURRENT_NORMAL /*only used if we have run current*/
124 static int runcurrent(void);
125 #endif
127 void battery_read_info(int *voltage, int *level)
129 int millivolts = battery_adc_voltage();
131 if (voltage)
132 *voltage = millivolts;
134 if (level)
135 *level = voltage_to_battery_level(millivolts);
138 #if BATTERY_TYPES_COUNT > 1
139 void set_battery_type(int type)
141 if (type != battery_type) {
142 if ((unsigned)type >= BATTERY_TYPES_COUNT)
143 type = 0;
145 battery_type = type;
146 battery_status_update(); /* recalculate the battery status */
149 #endif
151 void set_battery_capacity(int capacity)
153 if (capacity > BATTERY_CAPACITY_MAX)
154 capacity = BATTERY_CAPACITY_MAX;
155 if (capacity < BATTERY_CAPACITY_MIN)
156 capacity = BATTERY_CAPACITY_MIN;
158 battery_capacity = capacity;
160 battery_status_update(); /* recalculate the battery status */
163 int get_battery_capacity(void)
165 return battery_capacity;
168 int battery_time(void)
170 return powermgmt_est_runningtime_min;
173 /* Returns battery level in percent */
174 int battery_level(void)
176 #ifdef HAVE_BATTERY_SWITCH
177 if ((power_input_status() & POWER_INPUT_BATTERY) == 0)
178 return -1;
179 #endif
180 return battery_percent;
183 /* Returns filtered battery voltage [millivolts] */
184 unsigned int battery_voltage(void)
186 return battery_millivolts;
189 /* Tells if the battery level is safe for disk writes */
190 bool battery_level_safe(void)
192 #if defined(NO_LOW_BATTERY_SHUTDOWN)
193 return true;
194 #elif defined(HAVE_BATTERY_SWITCH)
195 /* Cannot rely upon the battery reading to be valid and the
196 * device could be powered externally. */
197 return input_millivolts() > battery_level_dangerous[battery_type];
198 #else
199 return battery_millivolts > battery_level_dangerous[battery_type];
200 #endif
203 /* look into the percent_to_volt_* table and get a realistic battery level */
204 static int voltage_to_percent(int voltage, const short* table)
206 if (voltage <= table[0]) {
207 return 0;
209 else if (voltage >= table[10]) {
210 return 100;
212 else {
213 /* search nearest value */
214 int i = 0;
216 while (i < 10 && table[i+1] < voltage)
217 i++;
219 /* interpolate linear between the smaller and greater value */
220 /* Tens digit, 10% per entry, ones digit: interpolated */
221 return i*10 + (voltage - table[i])*10 / (table[i+1] - table[i]);
225 /* update battery level and estimated runtime, called once per minute or
226 * when battery capacity / type settings are changed */
227 static int voltage_to_battery_level(int battery_millivolts)
229 int level;
231 #if CONFIG_CHARGING >= CHARGING_MONITOR
232 if (charging_state()) {
233 /* battery level is defined to be < 100% until charging is finished */
234 level = voltage_to_percent(battery_millivolts,
235 percent_to_volt_charge);
236 if (level > 99)
237 level = 99;
239 else
240 #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */
242 /* DISCHARGING or error state */
243 level = voltage_to_percent(battery_millivolts,
244 percent_to_volt_discharge[battery_type]);
247 return level;
250 static void battery_status_update(void)
252 int level = voltage_to_battery_level(battery_millivolts);
254 #ifdef CURRENT_NORMAL /*don't try to estimate run or charge
255 time without normal current defined*/
256 /* calculate estimated remaining running time */
257 #if CONFIG_CHARGING >= CHARGING_MONITOR
258 if (charging_state()) {
259 /* charging: remaining charging time */
260 powermgmt_est_runningtime_min = (100 - level)*battery_capacity*60
261 / 100 / (CURRENT_MAX_CHG - runcurrent());
263 else
264 #endif
266 /* discharging: remaining running time */
267 if (battery_millivolts > percent_to_volt_discharge[0][0]) {
268 /* linear extrapolation */
269 powermgmt_est_runningtime_min = (level + battery_percent)*60
270 * battery_capacity / 200 / runcurrent();
272 if (0 > powermgmt_est_runningtime_min) {
273 powermgmt_est_runningtime_min = 0;
275 #else
276 powermgmt_est_runningtime_min=-1;
277 #endif
279 battery_percent = level;
280 send_battery_level_event();
283 #ifdef CURRENT_NORMAL /*check that we have a current defined in a config file*/
286 * Estimate how much current we are drawing just to run.
288 static int runcurrent(void)
290 int current = CURRENT_NORMAL;
292 #ifndef BOOTLOADER
293 if (usb_inserted()
294 #ifdef HAVE_USB_POWER
295 #if (CURRENT_USB < CURRENT_NORMAL)
296 || usb_powered()
297 #else
298 && !usb_powered()
299 #endif
300 #endif
302 current = CURRENT_USB;
305 #if defined(HAVE_BACKLIGHT)
306 if (backlight_get_current_timeout() == 0) /* LED always on */
307 current += CURRENT_BACKLIGHT;
308 #endif
310 #if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
311 if (audio_status() & AUDIO_STATUS_RECORD)
312 current += CURRENT_RECORD;
313 #endif
315 #ifdef HAVE_SPDIF_POWER
316 if (spdif_powered())
317 current += CURRENT_SPDIF_OUT;
318 #endif
320 #ifdef HAVE_REMOTE_LCD
321 if (remote_detect())
322 current += CURRENT_REMOTE;
323 #endif
325 #if defined(HAVE_ATA_POWER_OFF) && defined(CURRENT_ATA)
326 if (ide_powered())
327 current += CURRENT_ATA;
328 #endif
330 #endif /* BOOTLOADER */
332 return current;
335 #endif /* CURRENT_NORMAL */
337 /* Check to see whether or not we've received an alarm in the last second */
338 #ifdef HAVE_RTC_ALARM
339 static void power_thread_rtc_process(void)
341 if (rtc_check_alarm_flag())
342 rtc_enable_alarm(false);
344 #endif
346 /* switch off unit if battery level is too low for reliable operation */
347 bool query_force_shutdown(void)
349 #if defined(NO_LOW_BATTERY_SHUTDOWN)
350 return false;
351 #elif defined(HAVE_BATTERY_SWITCH)
352 /* Cannot rely upon the battery reading to be valid and the
353 * device could be powered externally. */
354 return input_millivolts() < battery_level_shutoff[battery_type];
355 #else
356 return battery_millivolts < battery_level_shutoff[battery_type];
357 #endif
360 #if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
362 * Reset the battery voltage filter to a new value and update the
363 * status.
365 void reset_battery_filter(int millivolts)
367 avgbat = millivolts * BATT_AVE_SAMPLES;
368 battery_millivolts = millivolts;
369 battery_status_update();
371 #endif /* HAVE_BATTERY_SWITCH */
373 /** Generic charging algorithms for common charging types **/
374 #if CONFIG_CHARGING == 0 || CONFIG_CHARGING == CHARGING_SIMPLE
375 static inline void powermgmt_init_target(void)
377 /* Nothing to do */
380 static inline void charging_algorithm_step(void)
382 /* Nothing to do */
385 static inline void charging_algorithm_close(void)
387 /* Nothing to do */
389 #elif CONFIG_CHARGING == CHARGING_MONITOR
391 * Monitor CHARGING/DISCHARGING state.
393 static inline void powermgmt_init_target(void)
395 /* Nothing to do */
398 static inline void charging_algorithm_step(void)
400 switch (charger_input_state)
402 case CHARGER_PLUGGED:
403 case CHARGER:
404 if (charging_state()) {
405 charge_state = CHARGING;
406 break;
408 /* Fallthrough */
409 case CHARGER_UNPLUGGED:
410 case NO_CHARGER:
411 charge_state = DISCHARGING;
412 break;
416 static inline void charging_algorithm_close(void)
418 /* Nothing to do */
420 #endif /* CONFIG_CHARGING == * */
422 #if CONFIG_CHARGING
423 /* Shortcut function calls - compatibility, simplicity. */
425 /* Returns true if any power input is capable of charging. */
426 bool charger_inserted(void)
428 return power_thread_inputs & POWER_INPUT_CHARGER;
431 /* Returns true if any power input is connected - charging-capable
432 * or not. */
433 bool power_input_present(void)
435 return power_thread_inputs & POWER_INPUT;
439 * Detect charger inserted. Return true if the state is transistional.
441 static inline bool detect_charger(unsigned int pwr)
444 * Detect charger plugged/unplugged transitions. On a plugged or
445 * unplugged event, we return immediately, run once through the main
446 * loop (including the subroutines), and end up back here where we
447 * transition to the appropriate steady state charger on/off state.
449 if (pwr & POWER_INPUT_CHARGER) {
450 switch (charger_input_state)
452 case NO_CHARGER:
453 case CHARGER_UNPLUGGED:
454 charger_input_state = CHARGER_PLUGGED;
455 break;
457 case CHARGER_PLUGGED:
458 queue_broadcast(SYS_CHARGER_CONNECTED, 0);
459 last_sent_battery_level = 0;
460 charger_input_state = CHARGER;
461 break;
463 case CHARGER:
464 /* Steady state */
465 return false;
468 else { /* charger not inserted */
469 switch (charger_input_state)
471 case NO_CHARGER:
472 /* Steady state */
473 return false;
475 case CHARGER_UNPLUGGED:
476 queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
477 last_sent_battery_level = 100;
478 charger_input_state = NO_CHARGER;
479 break;
481 case CHARGER_PLUGGED:
482 case CHARGER:
483 charger_input_state = CHARGER_UNPLUGGED;
484 break;
488 /* Transitional state */
489 return true;
491 #endif /* CONFIG_CHARGING */
494 * Monitor the presence of a charger and perform critical frequent steps
495 * such as running the battery voltage filter.
497 static inline void power_thread_step(void)
499 /* If the power off timeout expires, the main thread has failed
500 to shut down the system, and we need to force a power off */
501 if (shutdown_timeout) {
502 shutdown_timeout -= POWER_THREAD_STEP_TICKS;
504 if (shutdown_timeout <= 0)
505 power_off();
508 #ifdef HAVE_RTC_ALARM
509 power_thread_rtc_process();
510 #endif
513 * Do a digital exponential filter. We don't sample the battery if
514 * the disk is spinning unless we are in USB mode (the disk will most
515 * likely always be spinning in USB mode) or charging.
517 if (!storage_disk_is_active() || usb_inserted()
518 #if CONFIG_CHARGING >= CHARGING_MONITOR
519 || charger_input_state == CHARGER
520 #endif
522 avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES;
524 * battery_millivolts is the millivolt-scaled filtered battery value.
526 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
528 /* update battery status every time an update is available */
529 battery_status_update();
531 else if (battery_percent < 8) {
533 * If battery is low, observe voltage during disk activity.
534 * Shut down if voltage drops below shutoff level and we are not
535 * using NiMH or Alkaline batteries.
537 battery_millivolts = (battery_adc_voltage() +
538 battery_millivolts + 1) / 2;
540 /* update battery status every time an update is available */
541 battery_status_update();
543 if (!shutdown_timeout && query_force_shutdown()) {
544 sys_poweroff();
546 else {
547 avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
550 } /* power_thread_step */
552 static void power_thread(void)
554 long next_power_hist;
556 /* Delay reading the first battery level */
557 #ifdef MROBE_100
558 while (battery_adc_voltage() > 4200) /* gives false readings initially */
559 #endif
561 sleep(HZ/100);
564 #if CONFIG_CHARGING
565 /* Initialize power input status before calling other routines. */
566 power_thread_inputs = power_input_status();
567 #endif
569 /* initialize the voltages for the exponential filter */
570 avgbat = battery_adc_voltage() + 15;
572 #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
573 /* The battery voltage is usually a little lower directly after
574 turning on, because the disk was used heavily. Raise it by 5% */
575 #if CONFIG_CHARGING
576 if (!charger_inserted()) /* only if charger not connected */
577 #endif
579 avgbat += (percent_to_volt_discharge[battery_type][6] -
580 percent_to_volt_discharge[battery_type][5]) / 2;
582 #endif /* HAVE_DISK_STORAGE */
584 avgbat = avgbat * BATT_AVE_SAMPLES;
585 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
586 power_history[0] = battery_millivolts;
588 #if CONFIG_CHARGING
589 if (charger_inserted()) {
590 battery_percent = voltage_to_percent(battery_millivolts,
591 percent_to_volt_charge);
593 else
594 #endif
596 battery_percent = voltage_to_percent(battery_millivolts,
597 percent_to_volt_discharge[battery_type]);
598 battery_percent += battery_percent < 100;
601 powermgmt_init_target();
603 next_power_hist = current_tick + HZ*60;
605 while (1)
607 #if CONFIG_CHARGING
608 unsigned int pwr = power_input_status();
609 #ifdef HAVE_BATTERY_SWITCH
610 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
611 sleep(HZ/10);
612 reset_battery_filter(battery_adc_voltage());
614 #endif
615 power_thread_inputs = pwr;
617 if (!detect_charger(pwr))
618 #endif /* CONFIG_CHARGING */
620 /* Steady state */
621 sleep(POWER_THREAD_STEP_TICKS);
623 /* Do common power tasks */
624 power_thread_step();
627 /* Perform target tasks */
628 charging_algorithm_step();
630 if (TIME_BEFORE(current_tick, next_power_hist))
631 continue;
633 /* increment to ensure there is a record for every minute
634 * rather than go forward from the current tick */
635 next_power_hist += HZ*60;
637 /* rotate the power history */
638 memmove(&power_history[1], &power_history[0],
639 sizeof(power_history) - sizeof(power_history[0]));
641 /* insert new value at the start, in millivolts 8-) */
642 power_history[0] = battery_millivolts;
644 handle_auto_poweroff();
646 } /* power_thread */
648 void powermgmt_init(void)
650 create_thread(power_thread, power_stack, sizeof(power_stack), 0,
651 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
652 IF_COP(, CPU));
655 /* Various hardware housekeeping tasks relating to shutting down the player */
656 void shutdown_hw(void)
658 charging_algorithm_close();
659 audio_stop();
661 if (battery_level_safe()) { /* do not save on critical battery */
662 #ifdef HAVE_LCD_BITMAP
663 font_unload_all();
664 #endif
666 /* Commit pending writes if needed. Even though we don't do write caching,
667 things like flash translation layers may need this to commit scattered
668 pages to there final locations. So far only used for iPod Nano 2G. */
669 #ifdef HAVE_STORAGE_FLUSH
670 storage_flush();
671 #endif
673 if (storage_disk_is_active())
674 storage_spindown(1);
677 #if CONFIG_CODEC == SWCODEC
678 audiohw_close();
679 #else
680 mp3_shutdown();
681 #endif
683 /* If HD is still active we try to wait for spindown, otherwise the
684 shutdown_timeout in power_thread_step will force a power off */
685 while (storage_disk_is_active())
686 sleep(HZ/10);
688 #ifndef HAVE_LCD_COLOR
689 lcd_set_contrast(0);
690 #endif
691 #ifdef HAVE_REMOTE_LCD
692 lcd_remote_set_contrast(0);
693 #endif
694 #ifdef HAVE_LCD_SHUTDOWN
695 lcd_shutdown();
696 #endif
698 /* Small delay to make sure all HW gets time to flush. Especially
699 eeprom chips are quite slow and might be still writing the last
700 byte. */
701 sleep(HZ/4);
702 power_off();
704 #endif /* PLATFORM_NATIVE */
706 void set_poweroff_timeout(int timeout)
708 poweroff_timeout = timeout;
711 void reset_poweroff_timer(void)
713 last_event_tick = current_tick;
714 if (sleeptimer_active && sleeptimer_key_restarts)
715 set_sleep_timer(sleeptimer_duration);
718 void sys_poweroff(void)
720 #ifndef BOOTLOADER
721 logf("sys_poweroff()");
722 /* If the main thread fails to shut down the system, we will force a
723 power off after an 20 second timeout - 28 seconds if recording */
724 if (shutdown_timeout == 0) {
725 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
726 pcf50606_reset_timeout(); /* Reset timer on first attempt only */
727 #endif
728 #ifdef HAVE_RECORDING
729 if (audio_status() & AUDIO_STATUS_RECORD)
730 shutdown_timeout += HZ*8;
731 #endif
732 #ifdef IPOD_NANO2G
733 /* The FTL alone may take half a minute to shut down cleanly. */
734 shutdown_timeout += HZ*60;
735 #else
736 shutdown_timeout += HZ*20;
737 #endif
740 queue_broadcast(SYS_POWEROFF, 0);
741 #endif /* BOOTLOADER */
744 void cancel_shutdown(void)
746 logf("cancel_shutdown()");
748 #if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
749 /* TODO: Move some things to target/ tree */
750 if (shutdown_timeout)
751 pcf50606_reset_timeout();
752 #endif
754 shutdown_timeout = 0;
757 /* Send system battery level update events on reaching certain significant
758 levels. This must be called after battery_percent has been updated. */
759 void send_battery_level_event(void)
761 static const int levels[] = { 5, 15, 30, 50, 0 };
762 const int *level = levels;
764 while (*level)
766 if (battery_percent <= *level && last_sent_battery_level > *level) {
767 last_sent_battery_level = *level;
768 queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level);
769 break;
772 level++;
776 void set_sleep_timer(int seconds)
778 if (seconds) {
779 sleeptimer_active = true;
780 sleeptimer_endtick = current_tick + seconds * HZ;
782 else {
783 sleeptimer_active = false;
784 sleeptimer_endtick = 0;
786 sleeptimer_duration = seconds;
789 int get_sleep_timer(void)
791 if (sleeptimer_active && (sleeptimer_endtick >= current_tick))
792 return (sleeptimer_endtick - current_tick) / HZ;
793 else
794 return 0;
797 void set_keypress_restarts_sleep_timer(bool enable)
799 sleeptimer_key_restarts = enable;
802 static void handle_sleep_timer(void)
804 #ifndef BOOTLOADER
805 if (!sleeptimer_active)
806 return;
808 /* Handle sleeptimer */
809 if (TIME_AFTER(current_tick, sleeptimer_endtick)) {
810 if (usb_inserted()
811 #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING)
812 || charger_input_state != NO_CHARGER
813 #endif
815 DEBUGF("Sleep timer timeout. Stopping...\n");
816 audio_pause();
817 set_sleep_timer(0);
818 backlight_off(); /* Nighty, nighty... */
820 else {
821 DEBUGF("Sleep timer timeout. Shutting off...\n");
822 sys_poweroff();
825 #endif /* BOOTLOADER */
829 * We shut off in the following cases:
830 * 1) The unit is idle, not playing music
831 * 2) The unit is playing music, but is paused
832 * 3) The battery level has reached shutdown limit
834 * We do not shut off in the following cases:
835 * 1) The USB is connected
836 * 2) The charger is connected
837 * 3) We are recording, or recording with pause
838 * 4) The radio is playing
840 void handle_auto_poweroff(void)
842 long timeout = poweroff_timeout*60*HZ;
843 int audio_stat = audio_status();
844 long tick = current_tick;
847 * Inhibit shutdown as long as the charger is plugged in. If it is
848 * unplugged, wait for a timeout period and then shut down.
850 if (audio_stat == AUDIO_STATUS_PLAY
851 #if CONFIG_CHARGING
852 || charger_input_state == CHARGER
853 #endif
855 last_event_tick = current_tick;
858 #if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
859 if (!shutdown_timeout && query_force_shutdown()) {
860 backlight_on();
861 sys_poweroff();
863 #endif
865 if (timeout &&
866 #if CONFIG_TUNER
867 !(get_radio_status() & FMRADIO_PLAYING) &&
868 #endif
869 !usb_inserted() &&
870 (audio_stat == 0 ||
871 (audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE) &&
872 !sleeptimer_active))) {
874 if (TIME_AFTER(tick, last_event_tick + timeout)
875 #if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
876 && TIME_AFTER(tick, storage_last_disk_activity() + timeout)
877 #endif
879 sys_poweroff();
881 } else
882 handle_sleep_timer();