Rockbox as an application: add get_user_file_path().
[kugel-rb.git] / apps / main.c
blob67cd6d2f0dad7045fcfa62a5a1eac9972a86f6d4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "config.h"
23 #include "storage.h"
24 #include "disk.h"
25 #include "fat.h"
26 #include "lcd.h"
27 #include "rtc.h"
28 #include "debug.h"
29 #include "led.h"
30 #include "kernel.h"
31 #include "button.h"
32 #include "tree.h"
33 #include "filetypes.h"
34 #include "panic.h"
35 #include "menu.h"
36 #include "system.h"
37 #include "usb.h"
38 #include "powermgmt.h"
39 #include "adc.h"
40 #include "i2c.h"
41 #ifndef DEBUG
42 #include "serial.h"
43 #endif
44 #include "audio.h"
45 #include "mp3_playback.h"
46 #include "thread.h"
47 #include "settings.h"
48 #include "backlight.h"
49 #include "status.h"
50 #include "debug_menu.h"
51 #include "font.h"
52 #include "language.h"
53 #include "wps.h"
54 #include "playlist.h"
55 #include "buffer.h"
56 #include "rolo.h"
57 #include "screens.h"
58 #include "usb_screen.h"
59 #include "power.h"
60 #include "talk.h"
61 #include "plugin.h"
62 #include "misc.h"
63 #include "dircache.h"
64 #ifdef HAVE_TAGCACHE
65 #include "tagcache.h"
66 #include "tagtree.h"
67 #endif
68 #include "lang.h"
69 #include "string.h"
70 #include "splash.h"
71 #include "eeprom_settings.h"
72 #include "scrobbler.h"
73 #include "icon.h"
74 #include "viewport.h"
75 #include "statusbar-skinned.h"
76 #include "bootchart.h"
78 #ifdef IPOD_ACCESSORY_PROTOCOL
79 #include "iap.h"
80 #endif
82 #if (CONFIG_CODEC == SWCODEC)
83 #include "playback.h"
84 #include "tdspeed.h"
85 #endif
86 #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR)
87 #include "pcm_record.h"
88 #endif
90 #ifdef BUTTON_REC
91 #define SETTINGS_RESET BUTTON_REC
92 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
93 #define SETTINGS_RESET BUTTON_A
94 #endif
96 #if CONFIG_TUNER
97 #include "radio.h"
98 #endif
99 #if (CONFIG_STORAGE & STORAGE_MMC)
100 #include "ata_mmc.h"
101 #endif
103 #ifdef HAVE_REMOTE_LCD
104 #include "lcd-remote.h"
105 #endif
107 #if CONFIG_USBOTG == USBOTG_ISP1362
108 #include "isp1362.h"
109 #endif
111 #if CONFIG_USBOTG == USBOTG_M5636
112 #include "m5636.h"
113 #endif
115 #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
116 #include "sim_tasks.h"
117 #endif
119 #ifdef HAVE_SDL
120 #include "system-sdl.h"
121 #endif
123 /*#define AUTOROCK*/ /* define this to check for "autostart.rock" on boot */
125 static void init(void);
127 #ifdef HAVE_SDL
128 #if defined(WIN32) && defined(main)
129 /* Don't use SDL_main on windows -> no more stdio redirection */
130 #undef main
131 #endif
132 int main(int argc, char *argv[])
134 #ifdef APPLICATION
135 paths_init();
136 #endif
137 sys_handle_argv(argc, argv);
138 #else
139 /* main(), and various functions called by main() and init() may be
140 * be INIT_ATTR. These functions must not be called after the final call
141 * to root_menu() at the end of main()
142 * see definition of INIT_ATTR in config.h */
143 int main(void) INIT_ATTR __attribute__((noreturn));
144 int main(void)
146 #endif
147 int i;
148 CHART(">init");
149 init();
150 CHART("<init");
151 FOR_NB_SCREENS(i)
153 screens[i].clear_display();
154 screens[i].update();
156 #ifdef HAVE_LCD_BITMAP
157 list_init();
158 #endif
159 tree_gui_init();
160 /* Keep the order of this 3
161 * Must be done before any code uses the multi-screen API */
162 #ifdef HAVE_USBSTACK
163 /* All threads should be created and public queues registered by now */
164 usb_start_monitoring();
165 #endif
167 #ifdef AUTOROCK
169 char filename[MAX_PATH];
170 const char *file = get_user_file_path(
171 #ifdef APPLICATION
172 ROCKBOX_DIR
173 #else
174 PLUGIN_APPS_DIR
175 #endif
176 "/autostart.rock", NEED_WRITE|IS_FILE, filename, sizeof(filename));
177 if(file_exists(file)) /* no complaint if it doesn't exist */
179 plugin_load(file, NULL); /* start if it does */
182 #endif /* #ifdef AUTOROCK */
184 global_status.last_volume_change = 0;
185 /* no calls INIT_ATTR functions after this point anymore!
186 * see definition of INIT_ATTR in config.h */
187 CHART(">root_menu");
188 root_menu();
191 static int init_dircache(bool preinit) INIT_ATTR;
192 static int init_dircache(bool preinit)
194 #ifdef HAVE_DIRCACHE
195 int result = 0;
196 bool clear = false;
198 if (preinit)
199 dircache_init();
201 if (!global_settings.dircache)
202 return 0;
204 # ifdef HAVE_EEPROM_SETTINGS
205 if (firmware_settings.initialized && firmware_settings.disk_clean
206 && preinit)
208 result = dircache_load();
210 if (result < 0)
212 firmware_settings.disk_clean = false;
213 if (global_status.dircache_size <= 0)
215 /* This will be in default language, settings are not
216 applied yet. Not really any easy way to fix that. */
217 splash(0, str(LANG_SCANNING_DISK));
218 clear = true;
221 dircache_build(global_status.dircache_size);
224 else
225 # endif
227 if (preinit)
228 return -1;
230 if (!dircache_is_enabled()
231 && !dircache_is_initializing())
233 if (global_status.dircache_size <= 0)
235 splash(0, str(LANG_SCANNING_DISK));
236 clear = true;
238 result = dircache_build(global_status.dircache_size);
241 if (result < 0)
243 /* Initialization of dircache failed. Manual action is
244 * necessary to enable dircache again.
246 splashf(0, "Dircache failed, disabled. Result: %d", result);
247 global_settings.dircache = false;
251 if (clear)
253 backlight_on();
254 show_logo();
255 global_status.dircache_size = dircache_get_cache_size();
256 status_save();
259 return result;
260 #else
261 (void)preinit;
262 return 0;
263 #endif
266 #ifdef HAVE_TAGCACHE
267 static void init_tagcache(void) INIT_ATTR;
268 static void init_tagcache(void)
270 bool clear = false;
271 #if CONFIG_CODEC == SWCODEC
272 long talked_tick = 0;
273 #endif
274 tagcache_init();
276 while (!tagcache_is_initialized())
278 int ret = tagcache_get_commit_step();
280 if (ret > 0)
282 #if CONFIG_CODEC == SWCODEC
283 /* hwcodec can't use voice here, as the database commit
284 * uses the audio buffer. */
285 if(global_settings.talk_menu
286 && (talked_tick == 0
287 || TIME_AFTER(current_tick, talked_tick+7*HZ)))
289 talked_tick = current_tick;
290 talk_id(LANG_TAGCACHE_INIT, false);
291 talk_number(ret, true);
292 talk_id(VOICE_OF, true);
293 talk_number(tagcache_get_max_commit_step(), true);
295 #endif
296 #ifdef HAVE_LCD_BITMAP
297 if (lang_is_rtl())
299 splashf(0, "[%d/%d] %s", ret, tagcache_get_max_commit_step(),
300 str(LANG_TAGCACHE_INIT));
302 else
304 splashf(0, "%s [%d/%d]", str(LANG_TAGCACHE_INIT), ret,
305 tagcache_get_max_commit_step());
307 #else
308 lcd_double_height(false);
309 lcd_putsf(0, 1, " DB [%d/%d]", ret,
310 tagcache_get_max_commit_step());
311 lcd_update();
312 #endif
313 clear = true;
315 sleep(HZ/4);
317 tagtree_init();
319 if (clear)
321 backlight_on();
322 show_logo();
325 #endif
327 #if (CONFIG_PLATFORM & PLATFORM_HOSTED)
329 static void init(void)
331 system_init();
332 kernel_init();
333 buffer_init();
334 enable_irq();
335 lcd_init();
336 #ifdef HAVE_REMOTE_LCD
337 lcd_remote_init();
338 #endif
339 font_init();
340 show_logo();
341 button_init();
342 backlight_init();
343 sim_tasks_init();
344 lang_init(core_language_builtin, language_strings,
345 LANG_LAST_INDEX_IN_ARRAY);
346 #ifdef DEBUG
347 debug_init();
348 #endif
349 /* Keep the order of this 3 (viewportmanager handles statusbars)
350 * Must be done before any code uses the multi-screen API */
351 gui_syncstatusbar_init(&statusbars);
352 gui_sync_wps_init();
353 sb_skin_init();
354 viewportmanager_init();
356 storage_init();
357 settings_reset();
358 settings_load(SETTINGS_ALL);
359 settings_apply(true);
360 init_dircache(true);
361 init_dircache(false);
362 #ifdef HAVE_TAGCACHE
363 init_tagcache();
364 #endif
365 sleep(HZ/2);
366 tree_mem_init();
367 filetype_init();
368 playlist_init();
369 theme_init_buffer();
371 #if CONFIG_CODEC != SWCODEC
372 mp3_init( global_settings.volume,
373 global_settings.bass,
374 global_settings.treble,
375 global_settings.balance,
376 global_settings.loudness,
377 global_settings.avc,
378 global_settings.channel_config,
379 global_settings.stereo_width,
380 global_settings.mdb_strength,
381 global_settings.mdb_harmonics,
382 global_settings.mdb_center,
383 global_settings.mdb_shape,
384 global_settings.mdb_enable,
385 global_settings.superbass);
387 /* audio_init must to know the size of voice buffer so init voice first */
388 talk_init();
389 #endif /* CONFIG_CODEC != SWCODEC */
391 scrobbler_init();
392 #if CONFIG_CODEC == SWCODEC
393 tdspeed_init();
394 #endif /* CONFIG_CODEC == SWCODEC */
396 audio_init();
397 button_clear_queue(); /* Empty the keyboard buffer */
399 settings_apply_skins();
402 #else
404 static void init(void) INIT_ATTR;
405 static void init(void)
407 int rc;
408 bool mounted = false;
409 #if CONFIG_CHARGING && (CONFIG_CPU == SH7034)
410 /* if nobody initialized ATA before, I consider this a cold start */
411 bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */
412 #endif
414 system_init();
415 kernel_init();
417 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
418 set_cpu_frequency(CPUFREQ_NORMAL);
419 #ifdef CPU_COLDFIRE
420 coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
421 #endif
422 cpu_boost(true);
423 #endif
425 buffer_init();
427 settings_reset();
429 i2c_init();
431 power_init();
433 enable_irq();
434 #ifdef CPU_ARM
435 enable_fiq();
436 #endif
437 /* current_tick should be ticking by now */
438 CHART("ticking");
440 lcd_init();
441 #ifdef HAVE_REMOTE_LCD
442 lcd_remote_init();
443 #endif
444 font_init();
446 CHART(">show_logo");
447 show_logo();
448 CHART("<show_logo");
449 lang_init(core_language_builtin, language_strings,
450 LANG_LAST_INDEX_IN_ARRAY);
452 #ifdef DEBUG
453 debug_init();
454 #else
455 #ifdef HAVE_SERIAL
456 serial_setup();
457 #endif
458 #endif
460 #if CONFIG_RTC
461 rtc_init();
462 #endif
463 #ifdef HAVE_RTC_RAM
464 CHART(">settings_load(RTC)");
465 settings_load(SETTINGS_RTC); /* early load parts of global_settings */
466 CHART("<settings_load(RTC)");
467 #endif
469 adc_init();
471 usb_init();
472 #if CONFIG_USBOTG == USBOTG_ISP1362
473 isp1362_init();
474 #elif CONFIG_USBOTG == USBOTG_M5636
475 m5636_init();
476 #endif
478 backlight_init();
480 button_init();
482 powermgmt_init();
484 #if CONFIG_TUNER
485 radio_init();
486 #endif
488 /* Keep the order of this 3 (viewportmanager handles statusbars)
489 * Must be done before any code uses the multi-screen API */
490 CHART(">gui_syncstatusbar_init");
491 gui_syncstatusbar_init(&statusbars);
492 CHART("<gui_syncstatusbar_init");
493 CHART(">sb_skin_init");
494 sb_skin_init();
495 CHART("<sb_skin_init");
496 CHART(">gui_sync_wps_init");
497 gui_sync_wps_init();
498 CHART("<gui_sync_wps_init");
499 CHART(">viewportmanager_init");
500 viewportmanager_init();
501 CHART("<viewportmanager_init");
503 #if CONFIG_CHARGING && (CONFIG_CPU == SH7034)
504 /* charger_inserted() can't be used here because power_thread()
505 hasn't checked power_input_status() yet */
506 if (coldstart && (power_input_status() & POWER_INPUT_MAIN_CHARGER)
507 && !global_settings.car_adapter_mode
508 #ifdef ATA_POWER_PLAYERSTYLE
509 && !ide_powered() /* relies on probing result from bootloader */
510 #endif
513 rc = charging_screen(); /* display a "charging" screen */
514 if (rc == 1) /* charger removed */
515 power_off();
516 /* "On" pressed or USB connected: proceed */
517 show_logo(); /* again, to provide better visual feedback */
519 #endif
522 disk_init_subsystem();
523 CHART(">storage_init");
524 rc = storage_init();
525 CHART("<storage_init");
526 if(rc)
528 #ifdef HAVE_LCD_BITMAP
529 lcd_clear_display();
530 lcd_putsf(0, 1, "ATA error: %d", rc);
531 lcd_puts(0, 3, "Press ON to debug");
532 lcd_update();
533 while(!(button_get(true) & BUTTON_REL)); /*DO NOT CHANGE TO ACTION SYSTEM */
534 dbg_ports();
535 #endif
536 panicf("ata: %d", rc);
539 #ifdef HAVE_EEPROM_SETTINGS
540 CHART(">eeprom_settings_init");
541 eeprom_settings_init();
542 CHART("<eeprom_settings_init");
543 #endif
545 #ifndef HAVE_USBSTACK
546 usb_start_monitoring();
547 while (usb_detect() == USB_INSERTED)
549 #ifdef HAVE_EEPROM_SETTINGS
550 firmware_settings.disk_clean = false;
551 #endif
552 /* enter USB mode early, before trying to mount */
553 if (button_get_w_tmo(HZ/10) == SYS_USB_CONNECTED)
554 #if (CONFIG_STORAGE & STORAGE_MMC)
555 if (!mmc_touched() ||
556 (mmc_remove_request() == SYS_HOTSWAP_EXTRACTED))
557 #endif
559 gui_usb_screen_run();
560 mounted = true; /* mounting done @ end of USB mode */
562 #ifdef HAVE_USB_POWER
563 if (usb_powered()) /* avoid deadlock */
564 break;
565 #endif
567 #endif
569 if (!mounted)
571 CHART(">disk_mount_all");
572 rc = disk_mount_all();
573 CHART("<disk_mount_all");
574 if (rc<=0)
576 lcd_clear_display();
577 lcd_puts(0, 0, "No partition");
578 lcd_puts(0, 1, "found.");
579 #ifdef HAVE_LCD_BITMAP
580 lcd_puts(0, 2, "Insert USB cable");
581 lcd_puts(0, 3, "and fix it.");
582 #endif
583 lcd_update();
585 while(button_get(true) != SYS_USB_CONNECTED) {};
586 gui_usb_screen_run();
587 system_reboot();
591 #if defined(SETTINGS_RESET) || (CONFIG_KEYPAD == IPOD_4G_PAD) || \
592 (CONFIG_KEYPAD == IRIVER_H10_PAD)
593 #ifdef SETTINGS_RESET
594 /* Reset settings if holding the reset button. (Rec on Archos,
595 A on Gigabeat) */
596 if ((button_status() & SETTINGS_RESET) == SETTINGS_RESET)
597 #else
598 /* Reset settings if the hold button is turned on */
599 if (button_hold())
600 #endif
602 splash(HZ*2, str(LANG_RESET_DONE_CLEAR));
603 settings_reset();
605 else
606 #endif
608 CHART(">settings_load(ALL)");
609 settings_load(SETTINGS_ALL);
610 CHART("<settings_load(ALL)");
613 CHART(">init_dircache(true)");
614 rc = init_dircache(true);
615 CHART("<init_dircache(true)");
616 if (rc < 0)
618 #ifdef HAVE_TAGCACHE
619 remove(TAGCACHE_STATEFILE);
620 #endif
623 CHART(">settings_apply(true)");
624 settings_apply(true);
625 CHART("<settings_apply(true)");
626 CHART(">init_dircache(false)");
627 init_dircache(false);
628 CHART("<init_dircache(false)");
629 #ifdef HAVE_TAGCACHE
630 CHART(">init_tagcache");
631 init_tagcache();
632 CHART("<init_tagcache");
633 #endif
635 #ifdef HAVE_EEPROM_SETTINGS
636 if (firmware_settings.initialized)
638 /* In case we crash. */
639 firmware_settings.disk_clean = false;
640 CHART(">eeprom_settings_store");
641 eeprom_settings_store();
642 CHART("<eeprom_settings_store");
644 #endif
645 playlist_init();
646 tree_mem_init();
647 filetype_init();
648 scrobbler_init();
649 #if CONFIG_CODEC == SWCODEC
650 tdspeed_init();
651 #endif /* CONFIG_CODEC == SWCODEC */
652 theme_init_buffer();
654 #if CONFIG_CODEC != SWCODEC
655 /* No buffer allocation (see buffer.c) may take place after the call to
656 audio_init() since the mpeg thread takes the rest of the buffer space */
657 mp3_init( global_settings.volume,
658 global_settings.bass,
659 global_settings.treble,
660 global_settings.balance,
661 global_settings.loudness,
662 global_settings.avc,
663 global_settings.channel_config,
664 global_settings.stereo_width,
665 global_settings.mdb_strength,
666 global_settings.mdb_harmonics,
667 global_settings.mdb_center,
668 global_settings.mdb_shape,
669 global_settings.mdb_enable,
670 global_settings.superbass);
672 /* audio_init must to know the size of voice buffer so init voice first */
673 talk_init();
674 #endif /* CONFIG_CODEC != SWCODEC */
676 CHART(">audio_init");
677 audio_init();
678 CHART("<audio_init");
680 #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR)
681 pcm_rec_init();
682 #endif
684 /* runtime database has to be initialized after audio_init() */
685 cpu_boost(false);
687 #if CONFIG_CHARGING
688 car_adapter_mode_init();
689 #endif
690 #ifdef IPOD_ACCESSORY_PROTOCOL
691 iap_setup(global_settings.serial_bitrate);
692 #endif
693 #ifdef HAVE_ACCESSORY_SUPPLY
694 accessory_supply_set(global_settings.accessory_supply);
695 #endif
696 #ifdef HAVE_LINEOUT_POWEROFF
697 lineout_set(global_settings.lineout_active);
698 #endif
699 #ifdef HAVE_HOTSWAP_STORAGE_AS_MAIN
700 CHART("<check_bootfile(false)");
701 check_bootfile(false); /* remember write time and filesize */
702 CHART(">check_bootfile(false)");
703 #endif
704 CHART("<settings_apply_skins");
705 settings_apply_skins();
706 CHART(">settings_apply_skins");
709 #ifdef CPU_PP
710 void __attribute__((noreturn)) cop_main(void)
712 /* This is the entry point for the coprocessor
713 Anyone not running an upgraded bootloader will never reach this point,
714 so it should not be assumed that the coprocessor be usable even on
715 platforms which support it.
717 A kernel thread is initially setup on the coprocessor and immediately
718 destroyed for purposes of continuity. The cop sits idle until at least
719 one thread exists on it. */
721 #if NUM_CORES > 1
722 system_init();
723 kernel_init();
724 /* This should never be reached */
725 #endif
726 while(1) {
727 sleep_core(COP);
730 #endif /* CPU_PP */
732 #endif /* SIMULATOR */