Index: firmware/export/config.h =================================================================== --- firmware/export/config.h (revision 14314) +++ firmware/export/config.h (working copy) @@ -263,7 +263,7 @@ /* Enable the directory cache and tagcache in RAM if we have * plenty of RAM. Both features can be enabled independently. */ #if ((defined(MEMORYSIZE) && (MEMORYSIZE > 8)) || MEM > 8) && \ - !defined(BOOTLOADER) && !defined(SANSA_E200) + !defined(BOOTLOADER) #define HAVE_DIRCACHE #ifdef HAVE_TAGCACHE #define HAVE_TC_RAMCACHE Index: firmware/common/dircache.c =================================================================== --- firmware/common/dircache.c 2007-08-13 20:21:52.337798400 +0100 +++ firmware/common/dircache.c 2007-08-13 22:08:46.060278400 +0100 @@ -59,12 +59,31 @@ static char dircache_cur_path[MAX_PATH*2]; static struct event_queue dircache_queue; -static long dircache_stack[(DEFAULT_STACK_SIZE + 0x900)/sizeof(long)]; +static long dircache_stack[(DEFAULT_STACK_SIZE + 0xA00)/sizeof(long)]; static const char dircache_thread_name[] = "dircache"; static struct fdbind_queue fdbind_cache[MAX_PENDING_BINDINGS]; static int fdbind_idx = 0; +#ifdef HAVE_MULTIVOLUME + +/* how to name volumes, first char must be outside of legal file names, + a number gets appended to enumerate, if applicable */ +#ifdef HAVE_MMC +static const char* vol_names = ""; +#define VOL_ENUM_POS 4 /* position of %d, to avoid runtime calculation */ +#elif defined(HAVE_HOTSWAP) +static const char* vol_names = ""; +#define VOL_ENUM_POS 8 /* position of %d, to avoid runtime calculation */ +#else +static const char* vol_names = ""; +#define VOL_ENUM_POS 3 +#endif + +struct dircache_entry *append_position; + +#endif /* #ifdef HAVE_MULTIVOLUME */ + /* --- Internal cache structure control functions --- */ /** @@ -150,6 +169,10 @@ { case DIRCACHE_STOP: case SYS_USB_CONNECTED: +#ifdef HAVE_HOTSWAP + case SYS_HOTSWAP_EXTRACTED: + case SYS_HOTSWAP_INSERTED: +#endif /* Put the event back into the queue. */ queue_post(&dircache_queue, ev.id, ev.data); return true; @@ -161,7 +184,11 @@ /** * Internal function to iterate a path. */ +#ifdef SIMULATOR static int dircache_scan(struct travel_data *td) +#else +static int dircache_scan(IF_MV2(int volume,) struct travel_data *td) +#endif { #ifdef SIMULATOR while ( ( td->entry = readdir_uncached(td->dir) ) ) @@ -270,20 +297,33 @@ #ifdef SIMULATOR static int dircache_travel(DIR_UNCACHED *dir, struct dircache_entry *ce) #else -static int dircache_travel(struct fat_dir *dir, struct dircache_entry *ce) +static int dircache_travel(IF_MV2(int volume,) struct fat_dir *dir, struct dircache_entry *ce) #endif { int depth = 0; int result; memset(ce, 0, sizeof(struct dircache_entry)); + +#ifdef HAVE_MULTIVOLUME + if (volume > 0) + { + snprintf(ce->d_name, VOL_ENUM_POS + 3, vol_names, volume); + ce->name_len = VOL_ENUM_POS + 3; + ce->attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME; + ce->size = 0; + append_position = dircache_gen_next(ce); + ce = dircache_gen_down(ce); + } +#endif + dir_recursion[0].dir = dir; dir_recursion[0].ce = ce; dir_recursion[0].first = ce; do { //logf("=> %s", dircache_cur_path); - result = dircache_scan(&dir_recursion[depth]); + result = dircache_scan(IF_MV2(volume,) &dir_recursion[depth]); switch (result) { case 0: /* Leaving the current directory. */ /* Add the standard . and .. entries. */ @@ -530,6 +570,7 @@ remove(DIRCACHE_FILE); dircache_initializing = true; +#ifndef HAVE_MULTIVOLUME #ifdef SIMULATOR pdir = opendir_uncached("/"); if (pdir == NULL) @@ -560,6 +601,35 @@ return -2; } cpu_boost(false); +#else + memset(dircache_cur_path, 0, sizeof(dircache_cur_path)); + dircache_size = sizeof(struct dircache_entry); + + append_position = dircache_root; + + for (i = NUM_VOLUMES; i >= 0; i--) + { + if (fat_ismounted(i)) + { + if ( fat_opendir(IF_MV2(i,) &dir, 0, NULL) < 0 ) { + logf("Failed opening root dir"); + dircache_initializing = false; + return -3; + } + pdir = &dir; + cpu_boost(true); + if (dircache_travel(IF_MV2(i,) pdir, append_position) < 0) + { + logf("dircache_travel failed"); + cpu_boost(false); + dircache_size = 0; + dircache_initializing = false; + return -2; + } + cpu_boost(false); + } + } +#endif logf("Done, %ld KiB used", dircache_size / 1024); @@ -615,6 +685,15 @@ break ; #ifndef SIMULATOR +#ifdef HAVE_HOTSWAP + case SYS_HOTSWAP_EXTRACTED: + case SYS_HOTSWAP_INSERTED: + logf("Dircache hotswap rebuild."); + thread_enabled = true; + dircache_do_rebuild(); + thread_enabled = false; + break ; +#endif case SYS_USB_CONNECTED: usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&dircache_queue); Index: firmware/common/file.c =================================================================== --- firmware/common/file.c (revision 14314) +++ firmware/common/file.c (working copy) @@ -25,13 +25,57 @@ #include "debug.h" #include "dircache.h" #include "system.h" +#include "atoi.h" +#ifdef HAVE_MULTIVOLUME + +/* how to name volumes, first char must be outside of legal file names, + a number gets appended to enumerate, if applicable */ +#ifdef HAVE_MMC +static const char* vol_names = ""; +#define VOL_ENUM_POS 4 /* position of %d, to avoid runtime calculation */ +#elif defined(HAVE_HOTSWAP) +static const char* vol_names = ""; +#define VOL_ENUM_POS 8 /* position of %d, to avoid runtime calculation */ +#else +static const char* vol_names = ""; +#define VOL_ENUM_POS 3 +#endif + +/* returns on which volume this is, and copies the reduced name + (sortof a preprocessor for volume-decorated pathnames) */ +static int strip_volume(const char* name, char* namecopy) +{ + int volume = 0; + const char *temp = name; + + while (*temp == '/') /* skip all leading slashes */ + ++temp; + + if (*temp && !strncmp(temp, vol_names, VOL_ENUM_POS)) + { + temp += VOL_ENUM_POS; /* behind special name */ + volume = atoi(temp); /* number is following */ + temp = strchr(temp, '/'); /* search for slash behind */ + if (temp != NULL) + name = temp; /* use the part behind the volume */ + else + name = "/"; /* else this must be the root dir */ + } + + strncpy(namecopy, name, MAX_PATH); + namecopy[MAX_PATH-1] = '\0'; + + return volume; +} +#endif /* #ifdef HAVE_MULTIVOLUME */ + /* These functions provide a roughly POSIX-compatible file IO API. Since the fat32 driver only manages sectors, we maintain a one-sector cache for each open file. This way we can provide byte access without - having to re-read the sector each time. + having to re-read the sector each time. The penalty is the RAM used for the cache and slightly more complex code. */ @@ -113,8 +157,10 @@ file->busy = false; return -7; } - - fat_open(IF_MV2(unsupported at the moment,) + + int volume = strip_volume(pathname, pathnamecopy); + + fat_open(IF_MV2(volume,) ce->startcluster, &(file->fatfile), NULL);