Initial support and use for EEPROM memory on H120 & H140 players when

Rockbox firmware has been flashed over original firmware (not yet
possible to do). Dircache & tagcache serialization for fast bootup
without the need to scan disk when Rockbox is in flash.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10464 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Miika Pekkarinen 2006-08-05 20:19:10 +00:00
parent 85ba65d2a3
commit 954b732654
18 changed files with 422 additions and 48 deletions

View file

@ -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 */

View file

@ -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();

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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. */

View file

@ -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

View file

@ -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 */

View file

@ -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;

View file

@ -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)

116
firmware/eeprom_settings.c Normal file
View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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 <stdbool.h>
#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

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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")));