/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Björn Stenberg * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "config.h" #include "gcc_extensions.h" #include "storage.h" #include "disk.h" #include "fat.h" #include "lcd.h" #include "rtc.h" #include "debug.h" #include "led.h" #include "kernel.h" #include "button.h" #include "tree.h" #include "filetypes.h" #include "panic.h" #include "menu.h" #include "system.h" #include "usb.h" #include "powermgmt.h" #include "adc.h" #include "i2c.h" #ifndef DEBUG #include "serial.h" #endif #include "audio.h" #include "mp3_playback.h" #include "thread.h" #include "settings.h" #include "backlight.h" #include "status.h" #include "debug_menu.h" #include "font.h" #include "language.h" #include "wps.h" #include "playlist.h" #include "core_alloc.h" #include "rolo.h" #include "screens.h" #include "usb_screen.h" #include "power.h" #include "talk.h" #include "plugin.h" #include "misc.h" #include "dircache.h" #ifdef HAVE_TAGCACHE #include "tagcache.h" #include "tagtree.h" #endif #include "lang.h" #include "string.h" #include "splash.h" #include "eeprom_settings.h" #include "scrobbler.h" #include "icon.h" #include "viewport.h" #include "skin_engine/skin_engine.h" #include "statusbar-skinned.h" #include "bootchart.h" #include "logdiskf.h" #if (CONFIG_PLATFORM & PLATFORM_ANDROID) #include "notification.h" #endif #include "shortcuts.h" #ifdef IPOD_ACCESSORY_PROTOCOL #include "iap.h" #endif #if (CONFIG_CODEC == SWCODEC) #include "audio_thread.h" #include "playback.h" #include "tdspeed.h" #endif #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && !defined(SIMULATOR) #include "pcm_record.h" #endif #ifdef BUTTON_REC #define SETTINGS_RESET BUTTON_REC #elif (CONFIG_KEYPAD == GIGABEAT_PAD) #define SETTINGS_RESET BUTTON_A #endif #if CONFIG_TUNER #include "radio.h" #endif #if (CONFIG_STORAGE & STORAGE_MMC) #include "ata_mmc.h" #endif #ifdef HAVE_REMOTE_LCD #include "lcd-remote.h" #endif #if CONFIG_USBOTG == USBOTG_ISP1362 #include "isp1362.h" #endif #if CONFIG_USBOTG == USBOTG_M5636 #include "m5636.h" #endif #ifdef HAVE_HARDWARE_CLICK #include "piezo.h" #endif #if (CONFIG_PLATFORM & PLATFORM_NATIVE) #define MAIN_NORETURN_ATTR NORETURN_ATTR #else /* gcc adds an implicit 'return 0;' at the end of main(), causing a warning * with noreturn attribute */ #define MAIN_NORETURN_ATTR #endif #if (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) #ifdef SIMULATOR #include "sim_tasks.h" #endif #include "system-sdl.h" #define HAVE_ARGV_MAIN /* Don't use SDL_main on windows -> no more stdio redirection */ #if defined(WIN32) #undef main #endif #endif /*#define AUTOROCK*/ /* define this to check for "autostart.rock" on boot */ static void init(void); /* main(), and various functions called by main() and init() may be * be INIT_ATTR. These functions must not be called after the final call * to root_menu() at the end of main() * see definition of INIT_ATTR in config.h */ #ifdef HAVE_ARGV_MAIN int main(int argc, char *argv[]) INIT_ATTR MAIN_NORETURN_ATTR ; int main(int argc, char *argv[]) { sys_handle_argv(argc, argv); #else int main(void) INIT_ATTR MAIN_NORETURN_ATTR; int main(void) { #endif CHART(">init"); init(); CHART("root_menu"); root_menu(); } static int init_dircache(bool preinit) INIT_ATTR; static int init_dircache(bool preinit) { #ifdef HAVE_DIRCACHE int result = 0; bool clear = false; if (preinit) dircache_init(); if (!global_settings.dircache) return 0; # ifdef HAVE_EEPROM_SETTINGS if (firmware_settings.initialized && firmware_settings.disk_clean && preinit) { result = dircache_load(); if (result < 0) { firmware_settings.disk_clean = false; if (global_status.dircache_size <= 0) { /* This will be in default language, settings are not applied yet. Not really any easy way to fix that. */ splash(0, str(LANG_SCANNING_DISK)); clear = true; } dircache_build(global_status.dircache_size); } } else # endif { if (preinit) return -1; if (!dircache_is_enabled() && !dircache_is_initializing()) { if (global_status.dircache_size <= 0) { splash(0, str(LANG_SCANNING_DISK)); clear = true; } result = dircache_build(global_status.dircache_size); } if (result < 0) { /* Initialization of dircache failed. Manual action is * necessary to enable dircache again. */ splashf(0, "Dircache failed, disabled. Result: %d", result); global_settings.dircache = false; } } if (clear) { backlight_on(); show_logo(); global_status.dircache_size = dircache_get_cache_size(); status_save(); } return result; #else (void)preinit; return 0; #endif } #ifdef HAVE_TAGCACHE static void init_tagcache(void) INIT_ATTR; static void init_tagcache(void) { bool clear = false; #if 0 /* CONFIG_CODEC == SWCODEC */ long talked_tick = 0; #endif tagcache_init(); while (!tagcache_is_initialized()) { int ret = tagcache_get_commit_step(); if (ret > 0) { #if 0 /* FIXME: Audio isn't even initialized yet! */ /* CONFIG_CODEC == SWCODEC */ /* hwcodec can't use voice here, as the database commit * uses the audio buffer. */ if(global_settings.talk_menu && (talked_tick == 0 || TIME_AFTER(current_tick, talked_tick+7*HZ))) { talked_tick = current_tick; talk_id(LANG_TAGCACHE_INIT, false); talk_number(ret, true); talk_id(VOICE_OF, true); talk_number(tagcache_get_max_commit_step(), true); } #endif #ifdef HAVE_LCD_BITMAP if (lang_is_rtl()) { splashf(0, "[%d/%d] %s", ret, tagcache_get_max_commit_step(), str(LANG_TAGCACHE_INIT)); } else { splashf(0, "%s [%d/%d]", str(LANG_TAGCACHE_INIT), ret, tagcache_get_max_commit_step()); } #else lcd_double_height(false); lcd_putsf(0, 1, " DB [%d/%d]", ret, tagcache_get_max_commit_step()); lcd_update(); #endif clear = true; } sleep(HZ/4); } tagtree_init(); if (clear) { backlight_on(); show_logo(); } } #endif #if (CONFIG_PLATFORM & PLATFORM_HOSTED) static void init(void) { system_init(); core_allocator_init(); kernel_init(); #ifdef APPLICATION paths_init(); #endif enable_irq(); lcd_init(); #ifdef HAVE_REMOTE_LCD lcd_remote_init(); #endif #ifdef HAVE_LCD_BITMAP FOR_NB_SCREENS(i) global_status.font_id[i] = FONT_SYSFIXED; font_init(); #endif show_logo(); button_init(); powermgmt_init(); backlight_init(); #ifdef SIMULATOR sim_tasks_init(); #endif #if (CONFIG_PLATFORM & PLATFORM_ANDROID) notification_init(); #endif lang_init(core_language_builtin, language_strings, LANG_LAST_INDEX_IN_ARRAY); #ifdef DEBUG debug_init(); #endif #if CONFIG_TUNER radio_init(); #endif /* Keep the order of this 3 (viewportmanager handles statusbars) * Must be done before any code uses the multi-screen API */ gui_syncstatusbar_init(&statusbars); gui_sync_skin_init(); sb_skin_init(); viewportmanager_init(); storage_init(); #if CONFIG_CODEC == SWCODEC pcm_init(); dsp_init(); #endif settings_reset(); settings_load(SETTINGS_ALL); settings_apply(true); init_dircache(true); init_dircache(false); #ifdef HAVE_TAGCACHE init_tagcache(); #endif tree_mem_init(); filetype_init(); playlist_init(); shortcuts_init(); #if CONFIG_CODEC != SWCODEC mp3_init( global_settings.volume, global_settings.bass, global_settings.treble, global_settings.balance, global_settings.loudness, global_settings.avc, global_settings.channel_config, global_settings.stereo_width, global_settings.mdb_strength, global_settings.mdb_harmonics, global_settings.mdb_center, global_settings.mdb_shape, global_settings.mdb_enable, global_settings.superbass); #endif /* CONFIG_CODEC != SWCODEC */ if (global_settings.audioscrobbler) scrobbler_init(); audio_init(); settings_apply_skins(); } #else static void init(void) INIT_ATTR; static void init(void) { int rc; bool mounted = false; #if CONFIG_CHARGING && (CONFIG_CPU == SH7034) /* if nobody initialized ATA before, I consider this a cold start */ bool coldstart = (PACR2 & 0x4000) != 0; /* starting from Flash */ #endif system_init(); core_allocator_init(); kernel_init(); #ifdef HAVE_ADJUSTABLE_CPU_FREQ set_cpu_frequency(CPUFREQ_NORMAL); #ifdef CPU_COLDFIRE coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS); #endif cpu_boost(true); #endif i2c_init(); power_init(); enable_irq(); #ifdef CPU_ARM enable_fiq(); #endif /* current_tick should be ticking by now */ CHART("ticking"); lcd_init(); #ifdef HAVE_REMOTE_LCD lcd_remote_init(); #endif #ifdef HAVE_LCD_BITMAP FOR_NB_SCREENS(i) global_status.font_id[i] = FONT_SYSFIXED; font_init(); #endif settings_reset(); CHART(">show_logo"); show_logo(); CHART("settings_load(RTC)"); settings_load(SETTINGS_RTC); /* early load parts of global_settings */ CHART(" CHARGING_MONITOR) powermgmt_init(); #endif #if CONFIG_TUNER radio_init(); #endif #ifdef HAVE_HARDWARE_CLICK piezo_init(); #endif /* Keep the order of this 3 (viewportmanager handles statusbars) * Must be done before any code uses the multi-screen API */ CHART(">gui_syncstatusbar_init"); gui_syncstatusbar_init(&statusbars); CHART("sb_skin_init"); sb_skin_init(); CHART("gui_sync_wps_init"); gui_sync_skin_init(); CHART("viewportmanager_init"); viewportmanager_init(); CHART("storage_init"); rc = storage_init(); CHART("eeprom_settings_init"); eeprom_settings_init(); CHART("disk_mount_all"); rc = disk_mount_all(); CHART("settings_load(ALL)"); settings_load(SETTINGS_ALL); CHART("init_dircache(true)"); rc = init_dircache(true); CHART("settings_apply(true)"); settings_apply(true); CHART("init_dircache(false)"); init_dircache(false); CHART("init_tagcache"); init_tagcache(); CHART("eeprom_settings_store"); eeprom_settings_store(); CHART("audio_init"); audio_init(); CHART("check_bootfile(false)"); #endif CHART("settings_apply_skins"); } #ifdef CPU_PP void cop_main(void) MAIN_NORETURN_ATTR; void cop_main(void) { /* This is the entry point for the coprocessor Anyone not running an upgraded bootloader will never reach this point, so it should not be assumed that the coprocessor be usable even on platforms which support it. A kernel thread is initially setup on the coprocessor and immediately destroyed for purposes of continuity. The cop sits idle until at least one thread exists on it. */ #if NUM_CORES > 1 system_init(); kernel_init(); /* This should never be reached */ #endif while(1) { sleep_core(COP); } } #endif /* CPU_PP */ #endif /* SIMULATOR */