summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorMichael Sparmann <theseven@rockbox.org>2011-02-27 22:44:54 +0000
committerMichael Sparmann <theseven@rockbox.org>2011-02-27 22:44:54 +0000
commit1b5e31ed43d2c09ada6a1313b2a1de0b262e74c6 (patch)
treeb31aa2a0d8cd63e0306b39f0a9e599339d586659 /firmware
parent751303c2acf22f7fa431690efcddcc8cb0d3a84e (diff)
downloadrockbox-1b5e31ed43d2c09ada6a1313b2a1de0b262e74c6.tar.gz
rockbox-1b5e31ed43d2c09ada6a1313b2a1de0b262e74c6.zip
iPod Classic CE-ATA Support (Part 2 of 4: Remove on-stack sector buffers, and replace them with a single statically allocated sector buffer that's arbitrated amongst users)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29445 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/common/disk.c4
-rw-r--r--firmware/drivers/fat.c154
-rw-r--r--firmware/export/fat.h2
-rw-r--r--firmware/usb.c2
-rw-r--r--firmware/usbstack/usb_storage.c7
5 files changed, 141 insertions, 28 deletions
diff --git a/firmware/common/disk.c b/firmware/common/disk.c
index a23d51dbb8..3c1f01cc61 100644
--- a/firmware/common/disk.c
+++ b/firmware/common/disk.c
@@ -67,7 +67,6 @@ int disk_sector_multiplier = 1;
struct partinfo* disk_init(IF_MD_NONVOID(int drive))
{
int i;
- unsigned char sector[SECTOR_SIZE];
#ifdef HAVE_MULTIDRIVE
/* For each drive, start at a different position, in order not to destroy
the first entry of drive 0.
@@ -81,10 +80,12 @@ struct partinfo* disk_init(IF_MD_NONVOID(int drive))
(void)drive;
#endif
+ unsigned char* sector = fat_get_sector_buffer();
storage_read_sectors(IF_MD2(drive,) 0,1, sector);
/* check that the boot sector is initialized */
if ( (sector[510] != 0x55) ||
(sector[511] != 0xaa)) {
+ fat_release_sector_buffer();
DEBUGF("Bad boot sector signature\n");
return NULL;
}
@@ -104,6 +105,7 @@ struct partinfo* disk_init(IF_MD_NONVOID(int drive))
/* not handled yet */
}
}
+ fat_release_sector_buffer();
return pinfo;
}
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index 63f4151792..a4eb24ce7f 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -214,6 +214,9 @@ struct fat_cache_entry
static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE] CACHEALIGN_ATTR;
static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
static struct mutex cache_mutex SHAREDBSS_ATTR;
+static struct mutex tempbuf_mutex;
+static char fat_tempbuf[SECTOR_SIZE] CACHEALIGN_ATTR;
+static bool tempbuf_locked;
#if defined(HAVE_HOTSWAP) && !(CONFIG_STORAGE & STORAGE_MMC) /* A better condition ?? */
void fat_lock(void)
@@ -269,6 +272,8 @@ void fat_init(void)
{
initialized = true;
mutex_init(&cache_mutex);
+ mutex_init(&tempbuf_mutex);
+ tempbuf_locked = false;
}
#ifdef HAVE_PRIORITY_SCHEDULING
@@ -304,7 +309,6 @@ static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long starts
const int volume = 0;
#endif
struct bpb* fat_bpb = &fat_bpbs[volume];
- unsigned char buf[SECTOR_SIZE];
int rc;
int secmult;
long datasec;
@@ -312,10 +316,12 @@ static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long starts
int rootdirsectors;
#endif
+ unsigned char* buf = fat_get_sector_buffer();
/* Read the sector */
rc = storage_read_sectors(IF_MD2(drive,) startsector,1,buf);
if(rc)
{
+ fat_release_sector_buffer();
DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
return rc * 10 - 1;
}
@@ -354,7 +360,10 @@ static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long starts
#ifdef HAVE_FAT16SUPPORT
fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
if (!fat_bpb->bpb_bytspersec)
+ {
+ fat_release_sector_buffer();
return -2;
+ }
rootdirsectors = secmult * ((fat_bpb->bpb_rootentcnt * DIR_ENTRY_SIZE
+ fat_bpb->bpb_bytspersec - 1) / fat_bpb->bpb_bytspersec);
#endif /* #ifdef HAVE_FAT16SUPPORT */
@@ -370,7 +379,10 @@ static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long starts
if (fat_bpb->bpb_secperclus)
fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
else
- return -2;
+ {
+ fat_release_sector_buffer();
+ return -2;
+ }
#ifdef TEST_FAT
/*
@@ -386,10 +398,12 @@ static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long starts
fat_bpb->is_fat16 = true;
if (fat_bpb->dataclusters < 4085)
{ /* FAT12 */
+ fat_release_sector_buffer();
DEBUGF("This is FAT12. Go away!\n");
return -2;
}
#else /* #ifdef HAVE_FAT16SUPPORT */
+ fat_release_sector_buffer();
DEBUGF("This is not FAT32. Go away!\n");
return -2;
#endif /* #ifndef HAVE_FAT16SUPPORT */
@@ -421,6 +435,7 @@ static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long starts
rc = bpb_is_sane(IF_MV(fat_bpb));
if (rc < 0)
{
+ fat_release_sector_buffer();
DEBUGF( "fat_mount() - BPB is not sane\n");
return rc * 10 - 3;
}
@@ -439,15 +454,32 @@ static int fat_mount_internal(IF_MV2(int volume,) IF_MD2(int drive,) long starts
startsector + fat_bpb->bpb_fsinfo, 1, buf);
if (rc < 0)
{
+ fat_release_sector_buffer();
DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc);
return rc * 10 - 4;
}
fat_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
}
+ fat_release_sector_buffer();
return 0;
}
+void* fat_get_sector_buffer()
+{
+ mutex_lock(&tempbuf_mutex);
+ if (tempbuf_locked)
+ panicf("FAT: Tried to lock temporary sector buffer twice!");
+ tempbuf_locked = true;
+ return fat_tempbuf;
+}
+
+void fat_release_sector_buffer()
+{
+ tempbuf_locked = false;
+ mutex_unlock(&tempbuf_mutex);
+}
+
#ifdef MAX_LOG_SECTOR_SIZE
int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume))
{
@@ -961,7 +993,6 @@ static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
#ifndef HAVE_MULTIVOLUME
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
- unsigned char fsinfo[SECTOR_SIZE];
unsigned long* intptr;
int rc;
@@ -970,12 +1001,14 @@ static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
return 0; /* FAT16 has no FsInfo */
#endif /* #ifdef HAVE_FAT16SUPPORT */
+ unsigned char* fsinfo = fat_get_sector_buffer();
/* update fsinfo */
rc = storage_read_sectors(IF_MD2(fat_bpb->drive,)
fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo);
if (rc < 0)
{
- DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc);
+ fat_release_sector_buffer();
+ DEBUGF( "update_fsinfo() - Couldn't read FSInfo (error code %d)", rc);
return rc * 10 - 1;
}
intptr = (long*)&(fsinfo[FSINFO_FREECOUNT]);
@@ -986,9 +1019,10 @@ static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb))
rc = storage_write_sectors(IF_MD2(fat_bpb->drive,)
fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
+ fat_release_sector_buffer();
if (rc < 0)
{
- DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
+ DEBUGF( "update_fsinfo() - Couldn't write FSInfo (error code %d)", rc);
return rc * 10 - 2;
}
@@ -1128,8 +1162,7 @@ static int write_long_name(struct fat_file* file,
unsigned int numentries,
const unsigned char* name,
const unsigned char* shortname,
- bool is_directory,
- unsigned char *sector_buffer)
+ bool is_directory)
{
unsigned char* entry;
unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
@@ -1147,9 +1180,13 @@ static int write_long_name(struct fat_file* file,
if (rc<0)
return rc * 10 - 1;
- rc = fat_readwrite(file, 1, sector_buffer, false);
+ unsigned char* buf = fat_get_sector_buffer();
+ rc = fat_readwrite(file, 1, buf, false);
if (rc<1)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 2;
+ }
/* calculate shortname checksum */
for (i=11; i>0; i--)
@@ -1172,34 +1209,44 @@ static int write_long_name(struct fat_file* file,
/* update current sector */
rc = fat_seek(file, sector);
if (rc<0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 3;
+ }
- rc = fat_readwrite(file, 1, sector_buffer, true);
+ rc = fat_readwrite(file, 1, buf, true);
if (rc<1)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 4;
+ }
/* read next sector */
- rc = fat_readwrite(file, 1, sector_buffer, false);
+ rc = fat_readwrite(file, 1, buf, false);
if (rc<0) {
+ fat_release_sector_buffer();
LDEBUGF("Failed writing new sector: %d\n",rc);
return rc * 10 - 5;
}
if (rc==0)
/* end of dir */
- memset(sector_buffer, 0, SECTOR_SIZE);
+ memset(buf, 0, SECTOR_SIZE);
sector++;
idx = 0;
}
- entry = sector_buffer + idx * DIR_ENTRY_SIZE;
+ entry = buf + idx * DIR_ENTRY_SIZE;
/* verify this entry is free */
if (entry[0] && entry[0] != 0xe5 )
+ {
+ fat_release_sector_buffer();
panicf("Dir entry %d in sector %x is not free! "
"%02x %02x %02x %02x",
idx, sector,
entry[0], entry[1], entry[2], entry[3]);
+ }
memset(entry, 0, DIR_ENTRY_SIZE);
if ( i+1 < numentries ) {
@@ -1259,9 +1306,13 @@ static int write_long_name(struct fat_file* file,
/* update last sector */
rc = fat_seek(file, sector);
if (rc<0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 6;
+ }
- rc = fat_readwrite(file, 1, sector_buffer, true);
+ rc = fat_readwrite(file, 1, buf, true);
+ fat_release_sector_buffer();
if (rc<1)
return rc * 10 - 7;
@@ -1301,7 +1352,6 @@ static int add_dir_entry(struct fat_dir* dir,
#else
struct bpb* fat_bpb = &fat_bpbs[0];
#endif
- unsigned char buf[SECTOR_SIZE];
unsigned char shortname[12];
int rc;
unsigned int sector;
@@ -1342,12 +1392,16 @@ static int add_dir_entry(struct fat_dir* dir,
/ NAME_BYTES_PER_ENTRY + 1;
}
+ unsigned char* buf = fat_get_sector_buffer();
restart:
firstentry = -1;
rc = fat_seek(&dir->file, 0);
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 2;
+ }
/* step 1: search for free entries and check for duplicate shortname */
for (sector = 0; !done; sector++)
@@ -1356,6 +1410,7 @@ static int add_dir_entry(struct fat_dir* dir,
rc = fat_readwrite(&dir->file, 1, buf, false);
if (rc < 0) {
+ fat_release_sector_buffer();
DEBUGF( "add_dir_entry() - Couldn't read dir"
" (error code %d)\n", rc);
return rc * 10 - 3;
@@ -1412,25 +1467,35 @@ static int add_dir_entry(struct fat_dir* dir,
LDEBUGF("Adding new sector(s) to dir\n");
rc = fat_seek(&dir->file, sector);
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 4;
- memset(buf, 0, sizeof buf);
+ }
+ memset(buf, 0, SECTOR_SIZE);
/* we must clear whole clusters */
for (; (entries_found < entries_needed) ||
(dir->file.sectornum < (int)fat_bpb->bpb_secperclus); sector++)
{
if (sector >= (65536/DIR_ENTRIES_PER_SECTOR))
+ {
+ fat_release_sector_buffer();
return -5; /* dir too large -- FAT specification */
+ }
rc = fat_readwrite(&dir->file, 1, buf, true);
if (rc < 1) /* No more room or something went wrong */
+ {
+ fat_release_sector_buffer();
return rc * 10 - 6;
+ }
entries_found += DIR_ENTRIES_PER_SECTOR;
}
firstentry = sector * DIR_ENTRIES_PER_SECTOR - entries_found;
}
+ fat_release_sector_buffer();
/* step 3: add entry */
sector = firstentry / DIR_ENTRIES_PER_SECTOR;
@@ -1439,7 +1504,7 @@ static int add_dir_entry(struct fat_dir* dir,
rc = write_long_name(&dir->file, firstentry,
entries_needed, name,
- shortname, is_directory, buf);
+ shortname, is_directory);
if (rc < 0)
return rc * 10 - 7;
@@ -1559,10 +1624,7 @@ static void randomize_dos_name(unsigned char *name)
static int update_short_entry( struct fat_file* file, long size, int attr )
{
- unsigned char buf[SECTOR_SIZE];
int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
- unsigned char* entry =
- buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
unsigned long* sizeptr;
unsigned short* clusptr;
struct fat_file dir;
@@ -1580,12 +1642,21 @@ static int update_short_entry( struct fat_file* file, long size, int attr )
if (rc<0)
return rc * 10 - 2;
+ unsigned char* buf = fat_get_sector_buffer();
+ unsigned char* entry =
+ buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
rc = fat_readwrite(&dir, 1, buf, false);
if (rc < 1)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 3;
+ }
if (!entry[0] || entry[0] == 0xe5)
+ {
+ fat_release_sector_buffer();
panicf("Updating size on empty dir entry %d\n", file->direntry);
+ }
entry[FATDIR_ATTR] = attr & 0xFF;
@@ -1615,9 +1686,13 @@ static int update_short_entry( struct fat_file* file, long size, int attr )
rc = fat_seek( &dir, sector );
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 4;
+ }
rc = fat_readwrite(&dir, 1, buf, true);
+ fat_release_sector_buffer();
if (rc < 1)
return rc * 10 - 5;
@@ -1720,18 +1795,22 @@ int fat_create_file(const char* name,
/* noinline because this is only split out of fat_create_dir to make sure
* the sector buffer doesn't remain on the stack, to avoid nasty stack
- * overflows later on (when flush_fat() is called */
+ * overflows later on (when flush_fat() is called) */
static __attribute__((noinline)) int fat_clear_cluster(int sector,
struct bpb *fat_bpb)
{
- unsigned char buf[SECTOR_SIZE];
+ unsigned char* buf = fat_get_sector_buffer();
int i,rc;
- memset(buf, 0, sizeof buf);
+ memset(buf, 0, SECTOR_SIZE);
for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 2;
+ }
}
+ fat_release_sector_buffer();
return 0;
}
@@ -1878,7 +1957,6 @@ int fat_closewrite(struct fat_file *file, long size, int attr)
static int free_direntries(struct fat_file* file)
{
- unsigned char buf[SECTOR_SIZE];
struct fat_file dir;
int numentries = file->direntries;
unsigned int entry = file->direntry - numentries + 1;
@@ -1895,9 +1973,13 @@ static int free_direntries(struct fat_file* file)
if (rc < 0)
return rc * 10 - 2;
+ unsigned char* buf = fat_get_sector_buffer();
rc = fat_readwrite(&dir, 1, buf, false);
if (rc < 1)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 3;
+ }
for (i=0; i < numentries; i++) {
LDEBUGF("Clearing dir entry %d (%d/%d)\n",
@@ -1909,17 +1991,26 @@ static int free_direntries(struct fat_file* file)
/* flush this sector */
rc = fat_seek(&dir, sector);
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 4;
+ }
rc = fat_readwrite(&dir, 1, buf, true);
if (rc < 1)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 5;
+ }
if ( i+1 < numentries ) {
/* read next sector */
rc = fat_readwrite(&dir, 1, buf, false);
if (rc < 1)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 6;
+ }
}
sector++;
}
@@ -1929,12 +2020,19 @@ static int free_direntries(struct fat_file* file)
/* flush this sector */
rc = fat_seek(&dir, sector);
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 7;
+ }
rc = fat_readwrite(&dir, 1, buf, true);
if (rc < 1)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 8;
+ }
}
+ fat_release_sector_buffer();
return 0;
}
@@ -2021,7 +2119,6 @@ int fat_rename(struct fat_file* file,
/* if renaming a directory, update the .. entry to make sure
it points to its parent directory (we don't check if it was a move) */
if(FAT_ATTR_DIRECTORY == attr) {
- unsigned char buf[SECTOR_SIZE];
/* open the dir that was renamed, we re-use the olddir_file struct */
rc = fat_open(IF_MV2(file->volume,) newfile.firstcluster, &olddir_file, NULL);
if (rc < 0)
@@ -2032,9 +2129,13 @@ int fat_rename(struct fat_file* file,
if (rc < 0)
return rc * 10 - 7;
+ unsigned char* buf = fat_get_sector_buffer();
rc = fat_readwrite(&olddir_file, 1, buf, false);
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 8;
+ }
/* parent cluster is 0 if parent dir is the root - FAT spec (p.29) */
if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
@@ -2045,6 +2146,7 @@ int fat_rename(struct fat_file* file,
entry = buf + DIR_ENTRY_SIZE;
if(strncmp(".. ", entry, 11))
{
+ fat_release_sector_buffer();
/* .. entry must be second entry according to FAT spec (p.29) */
DEBUGF("Second dir entry is not double-dot!\n");
return rc * 10 - 9;
@@ -2058,9 +2160,13 @@ int fat_rename(struct fat_file* file,
/* write back this sector */
rc = fat_seek(&olddir_file, 0);
if (rc < 0)
+ {
+ fat_release_sector_buffer();
return rc * 10 - 7;
+ }
rc = fat_readwrite(&olddir_file, 1, buf, true);
+ fat_release_sector_buffer();
if (rc < 1)
return rc * 10 - 8;
}
diff --git a/firmware/export/fat.h b/firmware/export/fat.h
index 38ce6ee74d..15511076e2 100644
--- a/firmware/export/fat.h
+++ b/firmware/export/fat.h
@@ -134,5 +134,7 @@ extern int fat_opendir(IF_MV2(int volume,)
extern int fat_getnext(struct fat_dir *ent, struct fat_direntry *entry);
extern unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)); /* public for debug info screen */
extern bool fat_ismounted(int volume);
+extern void* fat_get_sector_buffer(void);
+extern void fat_release_sector_buffer(void);
#endif
diff --git a/firmware/usb.c b/firmware/usb.c
index ebbf0807eb..a794e2ac8a 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -77,7 +77,7 @@ static int usb_mmc_countdown = 0;
/* Make sure there's enough stack space for screendump */
#ifdef USB_FULL_INIT
-static long usb_stack[(DEFAULT_STACK_SIZE + SECTOR_SIZE + DUMP_BMP_LINESIZE)/sizeof(long)];
+static long usb_stack[(DEFAULT_STACK_SIZE + DUMP_BMP_LINESIZE)/sizeof(long)];
static const char usb_thread_name[] = "usb";
static unsigned int usb_thread_entry = 0;
static bool usb_monitor_enabled = false;
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c
index d8d6817ad2..6d407cccc5 100644
--- a/firmware/usbstack/usb_storage.c
+++ b/firmware/usbstack/usb_storage.c
@@ -27,6 +27,7 @@
#include "logf.h"
#include "storage.h"
#include "disk.h"
+#include "fat.h"
/* Needed to get at the audio buffer */
#include "audio.h"
#include "usb_storage.h"
@@ -358,8 +359,10 @@ static bool check_disk_present(IF_MD_NONVOID(int volume))
#ifdef USB_USE_RAMDISK
return true;
#else
- unsigned char sector[SECTOR_SIZE];
- return storage_read_sectors(IF_MD2(volume,)0,1,sector) == 0;
+ unsigned char* sector = fat_get_sector_buffer();
+ bool success = storage_read_sectors(IF_MD2(volume,)0,1,sector) == 0;
+ fat_release_sector_buffer();
+ return success;
#endif
}