diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 724bab90ab..ce3140be63 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -53,6 +53,8 @@ #include "tagcache.h" #include "lcd-remote.h" #include "crc32.h" +#include "eeprom_24cxx.h" +#include "logf.h" #ifdef HAVE_LCD_BITMAP #include "widgets.h" @@ -1952,6 +1954,22 @@ bool dbg_save_roms(void) close(fd); } system_memory_guard(oldmode); + +#ifdef HAVE_EEPROM + fd = creat("/internal_eeprom.bin", O_WRONLY); + if (fd >= 0) + { + char buf[EEPROM_SIZE]; + + if (!eeprom_24cxx_read(0, buf, sizeof buf)) + gui_syncsplash(HZ*3, true, "Eeprom read failure!"); + else + write(fd, buf, sizeof buf); + + close(fd); + } +#endif + return false; } #endif /* CPU */ diff --git a/apps/main.c b/apps/main.c index b725d0252f..907e1126cf 100644 --- a/apps/main.c +++ b/apps/main.c @@ -65,6 +65,7 @@ #include "lang.h" #include "string.h" #include "splash.h" +#include "eeprom_settings.h" #if (CONFIG_CODEC == SWCODEC) #include "playback.h" @@ -108,35 +109,30 @@ void app_main(void) browse_root(); } -#ifdef HAVE_DIRCACHE -void init_dircache(void) +int init_dircache(void) { - int result; - bool clear = false; +#ifdef HAVE_DIRCACHE + int result = 0; dircache_init(); if (global_settings.dircache) { - if (global_settings.dircache_size == 0) +# ifdef HAVE_EEPROM + if (firmware_settings.initialized && firmware_settings.disk_clean) { - gui_syncsplash(0, true, str(LANG_DIRCACHE_BUILDING)); - clear = true; + if (dircache_load(DIRCACHE_FILE) == 0) + return 0; } +# endif result = dircache_build(global_settings.dircache_size); - if (result < 0) - gui_syncsplash(0, true, "Failed! Result: %d", result); - - if (clear) - { - backlight_on(); - show_logo(); - } } -} + + return result; #else -# define init_dircache(...) + return 0; #endif +} void init_tagcache(void) { @@ -376,6 +372,10 @@ void init(void) } } +#ifdef HAVE_EEPROM + eeprom_settings_init(); +#endif + settings_calc_config_sector(); #if defined(SETTINGS_RESET) || (CONFIG_KEYPAD == IPOD_4G_PAD) @@ -395,11 +395,21 @@ void init(void) settings_load(SETTINGS_ALL); + init_dircache(); + gui_sync_wps_init(); settings_apply(); - init_dircache(); + //init_dircache(); init_tagcache(); +#ifdef HAVE_EEPROM + if (firmware_settings.initialized) + { + /* In case we crash. */ + firmware_settings.disk_clean = false; + eeprom_settings_store(); + } +#endif status_init(); playlist_init(); tree_init(); diff --git a/apps/misc.c b/apps/misc.c index ff05819a4d..b0c315af98 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -49,6 +49,7 @@ #include "ata_mmc.h" #endif #include "tree.h" +#include "eeprom_settings.h" #ifdef HAVE_LCD_BITMAP #include "bmp.h" @@ -484,13 +485,6 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) #else int i; - if (tagcache_get_commit_step() > 0) - { - cancel_shutdown(); - gui_syncsplash(HZ, true, str(LANG_TAGCACHE_BUSY)); - return false; - } - #if defined(CONFIG_CHARGING) && !defined(HAVE_POWEROFF_WHILE_CHARGING) if(!charger_inserted()) #endif @@ -498,11 +492,26 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) FOR_NB_SCREENS(i) screens[i].clear_display(); gui_syncsplash(0, true, str(LANG_SHUTTINGDOWN)); + + if (!tagcache_prepare_shutdown()) + { + cancel_shutdown(); + gui_syncsplash(HZ, true, str(LANG_TAGCACHE_BUSY)); + return false; + } + if (callback != NULL) callback(parameter); system_flush(); - +#ifdef HAVE_EEPROM + if (firmware_settings.initialized) + { + firmware_settings.disk_clean = true; + firmware_settings.bl_version = 0; + eeprom_settings_store(); + } +#endif shutdown_hw(); } #endif diff --git a/apps/tagcache.c b/apps/tagcache.c index 1485ed8e51..4812198167 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -70,6 +70,7 @@ #include "buffer.h" #include "atoi.h" #include "crc32.h" +#include "eeprom_settings.h" /* Tag Cache thread. */ static struct event_queue tagcache_queue; @@ -152,6 +153,13 @@ struct ramcache_header { int entry_count[TAG_COUNT]; /* Number of entries in the indices. */ }; +# ifdef HAVE_EEPROM +struct statefile_header { + struct ramcache_header *hdr; + struct tagcache_stat stat; +}; +# endif + /* Pointer to allocated ramcache_header */ static struct ramcache_header *hdr; #endif @@ -2795,6 +2803,85 @@ static bool allocate_tagcache(void) return true; } +# ifdef HAVE_EEPROM +static bool tagcache_dumpload(void) +{ + struct statefile_header shdr; + int fd, rc; + long offpos; + int i; + + fd = open(TAGCACHE_STATEFILE, O_RDONLY); + if (fd < 0) + { + logf("no tagcache statedump"); + return false; + } + + /* Check the statefile memory placement */ + hdr = buffer_alloc(0); + rc = read(fd, &shdr, sizeof(struct statefile_header)); + if (rc != sizeof(struct statefile_header) + /* || (long)hdr != (long)shdr.hdr */) + { + logf("incorrect statefile"); + hdr = NULL; + close(fd); + return false; + } + + offpos = (long)hdr - (long)shdr.hdr; + + /* Lets allocate real memory and load it */ + hdr = buffer_alloc(shdr.stat.ramcache_allocated); + rc = read(fd, hdr, shdr.stat.ramcache_allocated); + close(fd); + + if (rc != shdr.stat.ramcache_allocated) + { + logf("read failure!"); + hdr = NULL; + return false; + } + + memcpy(&stat, &shdr.stat, sizeof(struct tagcache_stat)); + + /* Now fix the pointers */ + hdr->indices = (struct index_entry *)((long)hdr->indices + offpos); + for (i = 0; i < TAG_COUNT; i++) + hdr->tags[i] += offpos; + + return true; +} + +static bool tagcache_dumpsave(void) +{ + struct statefile_header shdr; + int fd; + + if (!stat.ramcache) + return false; + + fd = open(TAGCACHE_STATEFILE, O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) + { + logf("failed to create a statedump"); + return false; + } + + /* Create the header */ + shdr.hdr = hdr; + memcpy(&shdr.stat, &stat, sizeof(struct tagcache_stat)); + write(fd, &shdr, sizeof(struct statefile_header)); + + /* And dump the data too */ + write(fd, hdr, stat.ramcache_allocated); + close(fd); + + return true; +} +# endif + static bool load_tagcache(void) { struct tagcache_header *tch; @@ -3250,8 +3337,15 @@ static void tagcache_thread(void) free_tempbuf(); #ifdef HAVE_TC_RAMCACHE +# ifdef HAVE_EEPROM + if (firmware_settings.initialized && firmware_settings.disk_clean) + check_done = tagcache_dumpload(); + + remove(TAGCACHE_STATEFILE); +# endif + /* Allocate space for the tagcache if found on disk. */ - if (global_settings.tagcache_ram) + if (global_settings.tagcache_ram && !stat.ramcache) allocate_tagcache(); #endif @@ -3330,6 +3424,19 @@ static void tagcache_thread(void) } } +bool tagcache_prepare_shutdown(void) +{ + if (tagcache_get_commit_step() > 0) + return false; + +#ifdef HAVE_EEPROM + if (stat.ramcache) + tagcache_dumpsave(); +#endif + + return true; +} + static int get_progress(void) { int total_count = -1; diff --git a/apps/tagcache.h b/apps/tagcache.h index 450c21c26e..d5ce772904 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -64,6 +64,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title, #define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/tagcache_idx.tcd" #define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/tagcache_%d.tcd" #define TAGCACHE_FILE_CHANGELOG ROCKBOX_DIR "/tagcache_changelog.txt" +#define TAGCACHE_STATEFILE ROCKBOX_DIR "/tagcache_state.tcd" /* Flags */ #define FLAG_DELETED 0x0001 /* Entry has been removed from db */ @@ -149,6 +150,7 @@ bool tagcache_modify_numeric_entry(struct tagcache_search *tcs, struct tagcache_stat* tagcache_get_stat(void); int tagcache_get_commit_step(void); +bool tagcache_prepare_shutdown(void); #ifdef HAVE_TC_RAMCACHE bool tagcache_is_ramcache(void); diff --git a/apps/tree.c b/apps/tree.c index 7543ceb3f7..fde4da0e04 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -64,6 +64,7 @@ #include "tagcache.h" #include "yesno.h" #include "gwps-common.h" +#include "eeprom_settings.h" /* gui api */ #include "list.h" @@ -1367,8 +1368,13 @@ void tree_flush(void) #ifdef HAVE_DIRCACHE if (global_settings.dircache) { - if (dircache_is_enabled()) +# ifdef HAVE_EEPROM + if (dircache_is_enabled() && firmware_settings.initialized) + { global_settings.dircache_size = dircache_get_cache_size(); + dircache_save(DIRCACHE_FILE); + } +# endif dircache_disable(); } else @@ -1382,6 +1388,7 @@ void tree_flush(void) void tree_restore(void) { #ifdef HAVE_DIRCACHE + remove(DIRCACHE_FILE); if (global_settings.dircache) { /* Print "Scanning disk..." to the display. */ diff --git a/firmware/SOURCES b/firmware/SOURCES index 8e2ca740ab..480c7ce630 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -145,6 +145,10 @@ drivers/mas.c #ifdef IRIVER_H300_SERIES drivers/pcf50606.c #endif +#ifdef HAVE_EEPROM +drivers/eeprom_24cxx.c +eeprom_settings.c +#endif #ifdef IPOD_ARCH drivers/pcf50605.c #endif diff --git a/firmware/common/crc32.c b/firmware/common/crc32.c index 18ee6ac710..21fefac07f 100644 --- a/firmware/common/crc32.c +++ b/firmware/common/crc32.c @@ -21,8 +21,10 @@ /* Tool function to calculate a CRC32 across some buffer */ /* third argument is either 0xFFFFFFFF to start or value from last piece */ -unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32) +unsigned crc_32(const void *src, unsigned len, unsigned crc32) { + const unsigned char *buf = (const unsigned char *)src; + /* CCITT standard polynomial 0x04C11DB7 */ static const unsigned crc32_lookup[16] = { /* lookup table for 4 bits at a time is affordable */ diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 6167aa3933..d2c77a2e25 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c @@ -402,7 +402,7 @@ static struct dircache_entry* dircache_get_entry(const char *path, return cache_entry; } -#if 0 +#if 1 /** * Function to load the internal cache structure from disk to initialize * the dircache really fast and little disk access. @@ -423,32 +423,41 @@ int dircache_load(const char *path) if (fd < 0) return -2; - dircache_root = (struct dircache_entry *)(((long)audiobuf & ~0x03) + 0x04); bytes_read = read(fd, &maindata, sizeof(struct dircache_maindata)); if (bytes_read != sizeof(struct dircache_maindata) - || (long)maindata.root_entry != (long)dircache_root || maindata.size <= 0) { + logf("Dircache file header error"); close(fd); return -3; } + dircache_root = buffer_alloc(0); + if ((long)maindata.root_entry != (long)dircache_root) + { + logf("Position missmatch"); + close(fd); + return -4; + } + + dircache_root = buffer_alloc(maindata.size + DIRCACHE_RESERVE); entry_count = maindata.entry_count; bytes_read = read(fd, dircache_root, MIN(DIRCACHE_LIMIT, maindata.size)); close(fd); if (bytes_read != maindata.size) + { + logf("Dircache read failed"); return -6; + } /* Cache successfully loaded. */ dircache_size = maindata.size; + allocated_size = dircache_size + DIRCACHE_RESERVE; + reserve_used = 0; logf("Done, %d KiB used", dircache_size / 1024); dircache_initialized = true; memset(fd_bindings, 0, sizeof(fd_bindings)); - - /* We have to long align the audiobuf to keep the buffer access fast. */ - audiobuf += (long)((dircache_size & ~0x03) + 0x04); - audiobuf += DIRCACHE_RESERVE; return 0; } @@ -472,7 +481,7 @@ int dircache_save(const char *path) return -1; logf("Saving directory cache"); - fd = open(path, O_WRONLY | O_CREAT); + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC); maindata.magic = DIRCACHE_MAGIC; maindata.size = dircache_size; @@ -484,6 +493,7 @@ int dircache_save(const char *path) if (bytes_written != sizeof(struct dircache_maindata)) { close(fd); + logf("dircache: write failed #1"); return -2; } @@ -491,8 +501,11 @@ int dircache_save(const char *path) bytes_written = write(fd, dircache_root, dircache_size); close(fd); if (bytes_written != dircache_size) + { + logf("dircache: write failed #2"); return -3; - + } + return 0; } #endif /* #if 0 */ @@ -616,6 +629,7 @@ int dircache_build(int last_size) return -3; logf("Building directory cache"); + /* Background build, dircache has been previously allocated */ if (dircache_size > 0) { thread_enabled = true; diff --git a/firmware/drivers/eeprom_24cxx.c b/firmware/drivers/eeprom_24cxx.c index 4f7362ec82..33c02f1bc8 100644 --- a/firmware/drivers/eeprom_24cxx.c +++ b/firmware/drivers/eeprom_24cxx.c @@ -308,7 +308,7 @@ bool eeprom_24cxx_read_byte(unsigned int address, char *c) bool eeprom_24cxx_write_byte(unsigned int address, char c) { int ret; - int count = 10; + int count = 100; if (address >= EEPROM_SIZE) { @@ -318,10 +318,6 @@ bool eeprom_24cxx_write_byte(unsigned int address, char c) do { ret = sw_i2c_write_byte(address, c); - if (ret < 0) - { - logf("EEPROM Fail: %d/%d", ret, address); - } } while (ret < 0 && count--) ; if (ret < 0) diff --git a/firmware/eeprom_settings.c b/firmware/eeprom_settings.c new file mode 100644 index 0000000000..43f519d3fa --- /dev/null +++ b/firmware/eeprom_settings.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Miika Pekkarinen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "eeprom_settings.h" +#include "eeprom_24cxx.h" +#include "crc32.h" + +#include "string.h" +#include "logf.h" + +struct eeprom_settings firmware_settings; + +static void reset_config(void) +{ + memset(&firmware_settings, 0, sizeof(struct eeprom_settings)); + firmware_settings.version = EEPROM_SETTINGS_VERSION; + firmware_settings.initialized = true; + firmware_settings.boot_disk = false; + firmware_settings.bl_version = 0; +} + +bool eeprom_settings_init(void) +{ + bool ret; + uint32_t sum; + + eeprom_24cxx_init(); + + /* Check if player has been flashed. */ + if (!detect_flashed_rockbox()) + { + memset(&firmware_settings, 0, sizeof(struct eeprom_settings)); + firmware_settings.initialized = false; + logf("Rockbox in flash is required"); + return false; + } + + ret = eeprom_24cxx_read(0, &firmware_settings, + sizeof(struct eeprom_settings)); + + if (!ret) + { + memset(&firmware_settings, 0, sizeof(struct eeprom_settings)); + firmware_settings.initialized = false; + return false; + } + + sum = crc_32(&firmware_settings, sizeof(struct eeprom_settings)-4, + 0xffffffff); + + if (firmware_settings.checksum != sum) + { + logf("Checksum mismatch"); + reset_config(); + return true; + } + + if (firmware_settings.version != EEPROM_SETTINGS_VERSION) + { + logf("Version mismatch"); + reset_config(); + return true; + } + +#ifndef BOOTLOADER + if (firmware_settings.bl_version < EEPROM_SETTINGS_BL_MINVER) + { + logf("Too old bootloader: %d", firmware_settings.bl_version); + reset_config(); + return true; + } +#endif + + return true; +} + +bool eeprom_settings_store(void) +{ + bool ret; + uint32_t sum; + + if (!firmware_settings.initialized || !detect_flashed_rockbox()) + { + logf("Rockbox in flash is required"); + return false; + } + + /* Update the checksum. */ + sum = crc_32(&firmware_settings, sizeof(struct eeprom_settings)-4, + 0xffffffff); + firmware_settings.checksum = sum; + ret = eeprom_24cxx_write(0, &firmware_settings, + sizeof(struct eeprom_settings)); + + if (!ret) + firmware_settings.initialized = false; + + return ret; +} + diff --git a/firmware/export/config-h100.h b/firmware/export/config-h100.h index 6d204c3d66..7310dfa42f 100644 --- a/firmware/export/config-h100.h +++ b/firmware/export/config-h100.h @@ -123,7 +123,10 @@ #define BOOTFILE_EXT "iriver" #define BOOTFILE "rockbox." BOOTFILE_EXT -#endif +/* Define this if there is an EEPROM chip */ +#define HAVE_EEPROM + +#endif /* !SIMULATOR */ /* Define this for S/PDIF input available */ #define HAVE_SPDIF_IN @@ -134,3 +137,4 @@ /* Define this if you can control the S/PDIF power */ #define HAVE_SPDIF_POWER #define SPDIF_POWER_INVERTED + diff --git a/firmware/export/config-h120.h b/firmware/export/config-h120.h index 5635a92b51..ca618139e9 100644 --- a/firmware/export/config-h120.h +++ b/firmware/export/config-h120.h @@ -118,7 +118,14 @@ #define BOOTFILE_EXT "iriver" #define BOOTFILE "rockbox." BOOTFILE_EXT -#endif +#define BOOTLOADER_ENTRYPOINT 0x001F0000 +#define FLASH_ENTRYPOINT 0x00001000 +#define FLASH_MAGIC 0xfbfbfbf1 + +/* Define this if there is an EEPROM chip */ +#define HAVE_EEPROM + +#endif /* !SIMULATOR */ /* Define this for S/PDIF input available */ #define HAVE_SPDIF_IN @@ -128,3 +135,4 @@ /* Define this if you can control the S/PDIF power */ #define HAVE_SPDIF_POWER + diff --git a/firmware/export/eeprom_settings.h b/firmware/export/eeprom_settings.h new file mode 100644 index 0000000000..a3515bd69e --- /dev/null +++ b/firmware/export/eeprom_settings.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 by Miika Pekkarinen + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _EEPROM_SETTINGS_H_ +#define _EEPROM_SETTINGS_H_ + +#include +#include "inttypes.h" + +#define EEPROM_SETTINGS_VERSION 0x24c01001 +#define EEPROM_SETTINGS_BL_MINVER 7 + +struct eeprom_settings +{ + long version; /* Settings version number */ + bool initialized; /* Is eeprom_settings ready to be used */ + bool disk_clean; /* Is disk intact from last reboot */ + bool boot_disk; /* Load firmware from disk (default=FLASH) */ + uint8_t bl_version; /* Installed bootloader version */ + + /* This must be the last entry */ + uint32_t checksum; /* Checksum of this structure */ +}; + +extern struct eeprom_settings firmware_settings; + +bool detect_flashed_rockbox(void); +bool eeprom_settings_init(void); +bool eeprom_settings_store(void); + +#endif + diff --git a/firmware/export/system.h b/firmware/export/system.h index dae5d95794..1b326e1b8b 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h @@ -45,6 +45,14 @@ static inline void udelay(unsigned usecs) } #endif +struct flash_header { + unsigned long magic; + unsigned long length; + char version[32]; +}; + +bool detect_flashed_rockbox(void); + #ifdef HAVE_ADJUSTABLE_CPU_FREQ #define FREQ cpu_frequency void set_cpu_frequency(long frequency); diff --git a/firmware/include/crc32.h b/firmware/include/crc32.h index 5e998ab1b9..a2b7ae2f0a 100644 --- a/firmware/include/crc32.h +++ b/firmware/include/crc32.h @@ -19,7 +19,7 @@ #ifndef _CRC32_H #define _CRC32_H -unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32); +unsigned crc_32(const void *src, unsigned len, unsigned crc32); #endif diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index 4bccd4e211..a8e641e1ed 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c @@ -993,8 +993,8 @@ void sys_poweroff(void) { logf("sys_poweroff()"); /* If the main thread fails to shut down the system, we will force a - power off after an 8 second timeout */ - shutdown_timeout = HZ*8; + power off after an 20 second timeout */ + shutdown_timeout = HZ*20; queue_post(&button_queue, SYS_POWEROFF, NULL); } diff --git a/firmware/system.c b/firmware/system.c index 1874c0480e..bb09dbcd59 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -24,6 +24,8 @@ #include "system.h" #include "kernel.h" #include "timer.h" +#include "inttypes.h" +#include "string.h" #ifndef SIMULATOR long cpu_frequency = CPU_FREQ; @@ -76,6 +78,25 @@ void cpu_idle_mode(bool on_off) #endif +#if defined(IRIVER_H100_SERIES) && !defined(SIMULATOR) +bool detect_flashed_rockbox(void) +{ + struct flash_header hdr; + uint8_t *src = (uint8_t *)FLASH_ENTRYPOINT; + + memcpy(&hdr, src, sizeof(struct flash_header)); + if (hdr.magic != FLASH_MAGIC) + return false; + + return true; +} +#else +bool detect_flashed_rockbox(void) +{ + return false; +} +#endif + #if CONFIG_CPU == TCC730 void* volatile interrupt_vector[16] __attribute__ ((section(".idata")));