summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorJörg Hohensohn <hohensoh@rockbox.org>2004-12-28 22:16:07 +0000
committerJörg Hohensohn <hohensoh@rockbox.org>2004-12-28 22:16:07 +0000
commitda848576312800dc229624e928d132d0702c1854 (patch)
tree38cd01b8a9c1069a1de734e0f7eb478436715573 /firmware
parentae45d970d874217b779071b414dcd5edbf5647da (diff)
downloadrockbox-da848576312800dc229624e928d132d0702c1854.tar.gz
rockbox-da848576312800dc229624e928d132d0702c1854.tar.bz2
rockbox-da848576312800dc229624e928d132d0702c1854.zip
prepared to mount multiple partitions into one logical file system (most useful for Ondio, internal memory + external MMC)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5514 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/common/dir.c83
-rw-r--r--firmware/common/disk.c26
-rw-r--r--firmware/common/file.c3
-rw-r--r--firmware/drivers/ata.c11
-rw-r--r--firmware/drivers/ata_mmc.c32
-rw-r--r--firmware/drivers/fat.c734
-rw-r--r--firmware/export/ata.h19
-rw-r--r--firmware/export/disk.h4
-rw-r--r--firmware/export/fat.h23
-rw-r--r--firmware/include/dir.h4
-rw-r--r--firmware/test/fat/main.c4
-rw-r--r--firmware/test/i2c/main.c641
-rw-r--r--firmware/usb.c27
13 files changed, 1291 insertions, 320 deletions
diff --git a/firmware/common/dir.c b/firmware/common/dir.c
index 1bad9327f6..5fa5f9db6e 100644
--- a/firmware/common/dir.c
+++ b/firmware/common/dir.c
@@ -23,11 +23,48 @@
#include "fat.h"
#include "dir.h"
#include "debug.h"
+#include "atoi.h"
#define MAX_OPEN_DIRS 8
static DIR opendirs[MAX_OPEN_DIRS];
+#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 = ":MMC";
+#else
+static const char* vol_names = ":HD";
+#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;
+
+ if (name[1] == vol_names[0] ) /* a colon identifies our volumes */
+ {
+ const char* temp;
+ temp = name + 1 + strlen(vol_names); /* 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 */
+
+
DIR* opendir(const char* name)
{
char namecopy[MAX_PATH];
@@ -35,6 +72,9 @@ DIR* opendir(const char* name)
char* end;
struct fat_direntry entry;
int dd;
+#ifdef HAVE_MULTIVOLUME
+ int volume;
+#endif
/* find a free dir descriptor */
for ( dd=0; dd<MAX_OPEN_DIRS; dd++ )
@@ -55,15 +95,21 @@ DIR* opendir(const char* name)
return NULL;
}
- if ( fat_opendir(&(opendirs[dd].fatdir), 0, NULL) < 0 ) {
+#ifdef HAVE_MULTIVOLUME
+ /* try to extract a heading volume name, if present */
+ volume = strip_volume(name, namecopy);
+ opendirs[dd].volumecounter = 0;
+#else
+ strncpy(namecopy,name,sizeof(namecopy)); /* just copy */
+ namecopy[sizeof(namecopy)-1] = '\0';
+#endif
+
+ if ( fat_opendir(IF_MV2(volume,) &(opendirs[dd].fatdir), 0, NULL) < 0 ) {
DEBUGF("Failed opening root dir\n");
opendirs[dd].busy = false;
return NULL;
}
- strncpy(namecopy,name,sizeof(namecopy));
- namecopy[sizeof(namecopy)-1] = 0;
-
for ( part = strtok_r(namecopy, "/", &end); part;
part = strtok_r(NULL, "/", &end)) {
/* scan dir for name */
@@ -76,7 +122,8 @@ DIR* opendir(const char* name)
if ( (entry.attr & FAT_ATTR_DIRECTORY) &&
(!strcasecmp(part, entry.name)) ) {
opendirs[dd].parent_dir = opendirs[dd].fatdir;
- if ( fat_opendir(&(opendirs[dd].fatdir),
+ if ( fat_opendir(IF_MV2(volume,)
+ &(opendirs[dd].fatdir),
entry.firstcluster,
&(opendirs[dd].parent_dir)) < 0 ) {
DEBUGF("Failed opening dir '%s' (%d)\n",
@@ -84,6 +131,9 @@ DIR* opendir(const char* name)
opendirs[dd].busy = false;
return NULL;
}
+#ifdef HAVE_MULTIVOLUME
+ opendirs[dd].volumecounter = -1; /* n.a. to subdirs */
+#endif
break;
}
}
@@ -102,7 +152,28 @@ struct dirent* readdir(DIR* dir)
{
struct fat_direntry entry;
struct dirent* theent = &(dir->theent);
-
+#ifdef HAVE_MULTIVOLUME
+ /* Volumes (secondary file systems) get inserted into the root directory
+ of the first volume, since we have no separate top level. */
+ if (dir->volumecounter >= 0 /* on a root dir */
+ && dir->volumecounter < NUM_VOLUMES /* in range */
+ && dir->fatdir.file.volume == 0) /* at volume 0 */
+ { /* fake special directories, which don't really exist, but
+ will get redirected upon opendir() */
+ while (++dir->volumecounter < NUM_VOLUMES)
+ {
+ if (fat_ismounted(dir->volumecounter))
+ {
+ memset(theent, 0, sizeof(*theent));
+ theent->attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME;
+ snprintf(theent->d_name, sizeof(theent->d_name),
+ "%s%d", vol_names, dir->volumecounter);
+ return theent;
+ }
+ }
+ }
+#endif
+ /* normal directory entry fetching follows here */
if (fat_getnext(&(dir->fatdir),&entry) < 0)
return NULL;
diff --git a/firmware/common/disk.c b/firmware/common/disk.c
index b85f460a69..cfe15984f9 100644
--- a/firmware/common/disk.c
+++ b/firmware/common/disk.c
@@ -41,12 +41,22 @@
static struct partinfo part[8];
-struct partinfo* disk_init(void)
+struct partinfo* disk_init(IF_MV_NONVOID(int drive))
{
int i;
unsigned char sector[512];
+#ifdef HAVE_MULTIVOLUME
+ /* For each drive, start at a different position, in order not to destroy
+ the first entry of drive 0.
+ That one is needed to calculate config sector position. */
+ struct partinfo* pinfo = &part[drive*4];
+ if ((size_t)drive >= sizeof(part)/sizeof(*part)/4)
+ return NULL; /* out of space in table */
+#else
+ struct partinfo* pinfo = part;
+#endif
- ata_read_sectors(0,1,&sector);
+ ata_read_sectors(IF_MV2(drive,) 0,1,&sector);
/* check that the boot sector is initialized */
if ( (sector[510] != 0x55) ||
@@ -58,20 +68,20 @@ struct partinfo* disk_init(void)
/* parse partitions */
for ( i=0; i<4; i++ ) {
unsigned char* ptr = sector + 0x1be + 16*i;
- part[i].type = ptr[4];
- part[i].start = BYTES2INT32(ptr, 8);
- part[i].size = BYTES2INT32(ptr, 12);
+ pinfo[i].type = ptr[4];
+ pinfo[i].start = BYTES2INT32(ptr, 8);
+ pinfo[i].size = BYTES2INT32(ptr, 12);
DEBUGF("Part%d: Type %02x, start: %08x size: %08x\n",
- i,part[i].type,part[i].start,part[i].size);
+ i,pinfo[i].type,pinfo[i].start,pinfo[i].size);
/* extended? */
- if ( part[i].type == 5 ) {
+ if ( pinfo[i].type == 5 ) {
/* not handled yet */
}
}
- return part;
+ return pinfo;
}
struct partinfo* disk_partinfo(int partition)
diff --git a/firmware/common/file.c b/firmware/common/file.c
index 81b5a194c0..6714b9982c 100644
--- a/firmware/common/file.c
+++ b/firmware/common/file.c
@@ -132,7 +132,8 @@ int open(const char* pathname, int flags)
/* scan dir for name */
while ((entry = readdir(dir))) {
if ( !strcasecmp(name, entry->d_name) ) {
- fat_open(entry->startcluster,
+ fat_open(IF_MV2(dir->fatdir.file.volume,)
+ entry->startcluster,
&(file->fatfile),
&(dir->fatdir));
file->size = file->trunc ? 0 : entry->size;
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 9a0476f5cc..349ba077dd 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -310,7 +310,8 @@ static void copy_read_sectors(unsigned char* buf, int wordcount)
#endif
}
-int ata_read_sectors(unsigned long start,
+int ata_read_sectors(IF_MV((int drive,))
+ unsigned long start,
int incount,
void* inbuf)
{
@@ -576,7 +577,8 @@ static void copy_write_sectors(const unsigned char* buf, int wordcount)
#endif
}
-int ata_write_sectors(unsigned long start,
+int ata_write_sectors(IF_MV((int drive,))
+ unsigned long start,
int count,
const void* buf)
{
@@ -669,6 +671,8 @@ int ata_write_sectors(unsigned long start,
return ret;
}
+/* schedule a single sector write, executed with the the next spinup
+ (volume 0 only, used for config sector) */
extern void ata_delayed_write(unsigned long sector, const void* buf)
{
memcpy(delayed_sector, buf, SECTOR_SIZE);
@@ -676,12 +680,13 @@ extern void ata_delayed_write(unsigned long sector, const void* buf)
delayed_write = true;
}
+/* write the delayed sector to volume 0 */
extern void ata_flush(void)
{
if ( delayed_write ) {
DEBUGF("ata_flush()\n");
delayed_write = false;
- ata_write_sectors(delayed_sector_num, 1, delayed_sector);
+ ata_write_sectors(IF_MV2(0,) delayed_sector_num, 1, delayed_sector);
}
}
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index a61d28cb07..d75309547f 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -608,17 +608,24 @@ static int send_single_sector(const unsigned char *buf, int timeout)
return ret;
}
-int ata_read_sectors(unsigned long start,
- int incount,
- void* inbuf)
+int ata_read_sectors(
+#ifdef HAVE_MULTIVOLUME
+ int drive,
+#endif
+ unsigned long start,
+ int incount,
+ void* inbuf)
{
int ret = 0;
int i;
unsigned long addr;
unsigned char response;
void *inbuf_prev = NULL;
- tCardInfo *card = &card_info[current_card];
-
+ tCardInfo *card;
+#ifdef HAVE_MULTIVOLUME
+ current_card = drive;
+#endif
+ card = &card_info[current_card];
addr = start * SECTOR_SIZE;
mutex_lock(&mmc_mutex);
@@ -663,7 +670,11 @@ int ata_read_sectors(unsigned long start,
return ret;
}
-int ata_write_sectors(unsigned long start,
+int ata_write_sectors(
+#ifdef HAVE_MULTIVOLUME
+ int drive,
+#endif
+ unsigned long start,
int count,
const void* buf)
{
@@ -671,7 +682,11 @@ int ata_write_sectors(unsigned long start,
int i;
unsigned long addr;
unsigned char response;
- tCardInfo *card = &card_info[current_card];
+ tCardInfo *card;
+#ifdef HAVE_MULTIVOLUME
+ current_card = drive;
+#endif
+ card = &card_info[current_card];
if (start == 0)
panicf("Writing on sector 0\n");
@@ -733,12 +748,13 @@ extern void ata_delayed_write(unsigned long sector, const void* buf)
delayed_write = true;
}
+/* write the delayed sector to volume 0 */
extern void ata_flush(void)
{
if ( delayed_write ) {
DEBUGF("ata_flush()\n");
delayed_write = false;
- ata_write_sectors(delayed_sector_num, 1, delayed_sector);
+ ata_write_sectors(IF_MV2(0,) delayed_sector_num, 1, delayed_sector);
}
}
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index 9519ea9825..f0865eb985 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -219,17 +219,21 @@ struct bpb
bool is_fat16; /* true if we mounted a FAT16 partition, false if FAT32 */
unsigned int rootdirsectors; /* fixed # of sectors occupied by root dir */
#endif /* #ifdef HAVE_FAT16SUPPORT */
+#ifdef HAVE_MULTIVOLUME
+ int drive; /* on which physical device is this located */
+ bool mounted; /* flag if this volume is mounted */
+#endif
};
-static struct bpb fat_bpb;
+static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
-static int update_fsinfo(void);
-static int first_sector_of_cluster(int cluster);
-static int bpb_is_sane(void);
-static void *cache_fat_sector(int secnum);
+static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb));
+static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb));
+static int first_sector_of_cluster(IF_MV2(struct bpb* fat_bpb,) int cluster);
+static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,) int secnum);
static int create_dos_name(const unsigned char *name, unsigned char *newname);
-static unsigned int find_free_cluster(unsigned int start);
-static int transfer( unsigned int start, int count, char* buf, bool write );
+static unsigned int find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned int start);
+static int transfer(IF_MV2(struct bpb* fat_bpb,) unsigned int start, int count, char* buf, bool write );
#define FAT_CACHE_SIZE 0x20
#define FAT_CACHE_MASK (FAT_CACHE_SIZE-1)
@@ -239,26 +243,35 @@ struct fat_cache_entry
int secnum;
bool inuse;
bool dirty;
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_vol ; /* shared cache for all volumes */
+#endif
};
static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE];
static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
-static int sec2cluster(unsigned int sec)
+static int sec2cluster(IF_MV2(struct bpb* fat_bpb,) unsigned int sec)
{
- if ( sec < fat_bpb.firstdatasector )
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
+ if ( sec < fat_bpb->firstdatasector )
{
DEBUGF( "sec2cluster() - Bad sector number (%d)\n", sec);
return -1;
}
- return ((sec - fat_bpb.firstdatasector) / fat_bpb.bpb_secperclus) + 2;
+ return ((sec - fat_bpb->firstdatasector) / fat_bpb->bpb_secperclus) + 2;
}
-static int cluster2sec(int cluster)
+static int cluster2sec(IF_MV2(struct bpb* fat_bpb,) int cluster)
{
- int max_cluster = fat_bpb.totalsectors -
- fat_bpb.firstdatasector / fat_bpb.bpb_secperclus + 1;
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
+ int max_cluster = fat_bpb->totalsectors -
+ fat_bpb->firstdatasector / fat_bpb->bpb_secperclus + 1;
if(cluster > max_cluster)
{
@@ -267,109 +280,141 @@ static int cluster2sec(int cluster)
return -1;
}
- return first_sector_of_cluster(cluster);
+ return first_sector_of_cluster(IF_MV2(fat_bpb,) cluster);
}
-static int first_sector_of_cluster(int cluster)
+static int first_sector_of_cluster(IF_MV2(struct bpb* fat_bpb,) int cluster)
{
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
#ifdef HAVE_FAT16SUPPORT
/* negative clusters (FAT16 root dir) don't get the 2 offset */
int zerocluster = cluster < 0 ? 0 : 2;
#else
const int zerocluster = 2;
#endif
- return (cluster - zerocluster) * fat_bpb.bpb_secperclus + fat_bpb.firstdatasector;
+ return (cluster - zerocluster) * fat_bpb->bpb_secperclus + fat_bpb->firstdatasector;
}
-int fat_startsector(void)
+int fat_startsector(IF_MV_NONVOID(int volume))
{
- return fat_bpb.startsector;
+#ifndef HAVE_MULTIVOLUME
+ const int volume = 0;
+#endif
+ struct bpb* fat_bpb = &fat_bpbs[volume];
+ return fat_bpb->startsector;
}
-void fat_size(unsigned int* size, unsigned int* free)
+void fat_size(IF_MV2(int volume,) unsigned int* size, unsigned int* free)
{
+#ifndef HAVE_MULTIVOLUME
+ const int volume = 0;
+#endif
+ struct bpb* fat_bpb = &fat_bpbs[volume];
if (size)
- *size = fat_bpb.dataclusters * fat_bpb.bpb_secperclus / 2;
+ *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2;
if (free)
- *free = fat_bpb.fsinfo.freecount * fat_bpb.bpb_secperclus / 2;
+ *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2;
}
-int fat_mount(int startsector)
+void fat_init(void)
{
- unsigned char buf[SECTOR_SIZE];
- int rc;
- int datasec;
unsigned int i;
-
+ /* mark the FAT cache as unused */
for(i = 0;i < FAT_CACHE_SIZE;i++)
{
fat_cache[i].secnum = 8; /* We use a "safe" sector just in case */
fat_cache[i].inuse = false;
fat_cache[i].dirty = false;
+#ifdef HAVE_MULTIVOLUME
+ fat_cache[i].fat_vol = NULL;
+#endif
+ }
+#ifdef HAVE_MULTIVOLUME
+ /* mark the possible volumes as not mounted */
+ for (i=0; i<NUM_VOLUMES;i++)
+ {
+ fat_bpbs[i].mounted = false;
}
+#endif
+}
+
+int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) int startsector)
+{
+#ifndef HAVE_MULTIVOLUME
+ const int volume = 0;
+#endif
+ struct bpb* fat_bpb = &fat_bpbs[volume];
+ unsigned char buf[SECTOR_SIZE];
+ int rc;
+ int datasec;
/* Read the sector */
- rc = ata_read_sectors(startsector,1,buf);
+ rc = ata_read_sectors(IF_MV2(drive,) startsector,1,buf);
if(rc)
{
DEBUGF( "fat_mount() - Couldn't read BPB (error code %d)\n", rc);
return rc * 10 - 1;
}
- memset(&fat_bpb, 0, sizeof(struct bpb));
- fat_bpb.startsector = startsector;
-
- fat_bpb.bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
- fat_bpb.bpb_secperclus = buf[BPB_SECPERCLUS];
- fat_bpb.bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT);
- fat_bpb.bpb_numfats = buf[BPB_NUMFATS];
- fat_bpb.bpb_totsec16 = BYTES2INT16(buf,BPB_TOTSEC16);
- fat_bpb.bpb_media = buf[BPB_MEDIA];
- fat_bpb.bpb_fatsz16 = BYTES2INT16(buf,BPB_FATSZ16);
- fat_bpb.bpb_fatsz32 = BYTES2INT32(buf,BPB_FATSZ32);
- fat_bpb.bpb_totsec32 = BYTES2INT32(buf,BPB_TOTSEC32);
- fat_bpb.last_word = BYTES2INT16(buf,BPB_LAST_WORD);
+ memset(fat_bpb, 0, sizeof(struct bpb));
+ fat_bpb->startsector = startsector;
+#ifdef HAVE_MULTIVOLUME
+ fat_bpb->drive = drive;
+#endif
+
+ fat_bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC);
+ fat_bpb->bpb_secperclus = buf[BPB_SECPERCLUS];
+ fat_bpb->bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT);
+ fat_bpb->bpb_numfats = buf[BPB_NUMFATS];
+ fat_bpb->bpb_totsec16 = BYTES2INT16(buf,BPB_TOTSEC16);
+ fat_bpb->bpb_media = buf[BPB_MEDIA];
+ fat_bpb->bpb_fatsz16 = BYTES2INT16(buf,BPB_FATSZ16);
+ fat_bpb->bpb_fatsz32 = BYTES2INT32(buf,BPB_FATSZ32);
+ fat_bpb->bpb_totsec32 = BYTES2INT32(buf,BPB_TOTSEC32);
+ fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD);
/* calculate a few commonly used values */
- if (fat_bpb.bpb_fatsz16 != 0)
- fat_bpb.fatsize = fat_bpb.bpb_fatsz16;
+ if (fat_bpb->bpb_fatsz16 != 0)
+ fat_bpb->fatsize = fat_bpb->bpb_fatsz16;
else
- fat_bpb.fatsize = fat_bpb.bpb_fatsz32;
+ fat_bpb->fatsize = fat_bpb->bpb_fatsz32;
- if (fat_bpb.bpb_totsec16 != 0)
- fat_bpb.totalsectors = fat_bpb.bpb_totsec16;
+ if (fat_bpb->bpb_totsec16 != 0)
+ fat_bpb->totalsectors = fat_bpb->bpb_totsec16;
else
- fat_bpb.totalsectors = fat_bpb.bpb_totsec32;
+ fat_bpb->totalsectors = fat_bpb->bpb_totsec32;
#ifdef HAVE_FAT16SUPPORT
- fat_bpb.bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
- fat_bpb.rootdirsectors = ((fat_bpb.bpb_rootentcnt * 32)
- + (fat_bpb.bpb_bytspersec - 1)) / fat_bpb.bpb_bytspersec;
+ fat_bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT);
+ fat_bpb->rootdirsectors = ((fat_bpb->bpb_rootentcnt * 32)
+ + (fat_bpb->bpb_bytspersec - 1)) / fat_bpb->bpb_bytspersec;
#endif /* #ifdef HAVE_FAT16SUPPORT */
- fat_bpb.firstdatasector = fat_bpb.bpb_rsvdseccnt
+ fat_bpb->firstdatasector = fat_bpb->bpb_rsvdseccnt
#ifdef HAVE_FAT16SUPPORT
- + fat_bpb.rootdirsectors
+ + fat_bpb->rootdirsectors
#endif
- + fat_bpb.bpb_numfats * fat_bpb.fatsize;
+ + fat_bpb->bpb_numfats * fat_bpb->fatsize;
/* Determine FAT type */
- datasec = fat_bpb.totalsectors - fat_bpb.firstdatasector;
- fat_bpb.dataclusters = datasec / fat_bpb.bpb_secperclus;
+ datasec = fat_bpb->totalsectors - fat_bpb->firstdatasector;
+ fat_bpb->dataclusters = datasec / fat_bpb->bpb_secperclus;
#ifdef TEST_FAT
/*
we are sometimes testing with "illegally small" fat32 images,
so we don't use the proper fat32 test case for test code
*/
- if ( fat_bpb.bpb_fatsz16 )
+ if ( fat_bpb->bpb_fatsz16 )
#else
- if ( fat_bpb.dataclusters < 65525 )
+ if ( fat_bpb->dataclusters < 65525 )
#endif
{ /* FAT16 */
#ifdef HAVE_FAT16SUPPORT
- fat_bpb.is_fat16 = true;
- if (fat_bpb.dataclusters < 4085)
+ fat_bpb->is_fat16 = true;
+ if (fat_bpb->dataclusters < 4085)
{ /* FAT12 */
DEBUGF("This is FAT12. Go away!\n");
return -2;
@@ -381,26 +426,26 @@ int fat_mount(int startsector)
}
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{ /* FAT16 specific part of BPB */
int dirclusters;
- fat_bpb.rootdirsector = fat_bpb.bpb_rsvdseccnt
- + fat_bpb.bpb_numfats * fat_bpb.bpb_fatsz16;
- dirclusters = ((fat_bpb.rootdirsectors + fat_bpb.bpb_secperclus - 1)
- / fat_bpb.bpb_secperclus); /* rounded up, to full clusters */
+ fat_bpb->rootdirsector = fat_bpb->bpb_rsvdseccnt
+ + fat_bpb->bpb_numfats * fat_bpb->bpb_fatsz16;
+ dirclusters = ((fat_bpb->rootdirsectors + fat_bpb->bpb_secperclus - 1)
+ / fat_bpb->bpb_secperclus); /* rounded up, to full clusters */
/* I assign negative pseudo cluster numbers for the root directory,
their range is counted upward until -1. */
- fat_bpb.bpb_rootclus = 0 - dirclusters; /* backwards, before the data */
+ fat_bpb->bpb_rootclus = 0 - dirclusters; /* backwards, before the data */
}
else
#endif /* #ifdef HAVE_FAT16SUPPORT */
{ /* FAT32 specific part of BPB */
- fat_bpb.bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
- fat_bpb.bpb_fsinfo = BYTES2INT16(buf,BPB_FSINFO);
- fat_bpb.rootdirsector = cluster2sec(fat_bpb.bpb_rootclus);
+ fat_bpb->bpb_rootclus = BYTES2INT32(buf,BPB_ROOTCLUS);
+ fat_bpb->bpb_fsinfo = BYTES2INT16(buf,BPB_FSINFO);
+ fat_bpb->rootdirsector = cluster2sec(IF_MV2(fat_bpb,) fat_bpb->bpb_rootclus);
}
- rc = bpb_is_sane();
+ rc = bpb_is_sane(IF_MV(fat_bpb));
if (rc < 0)
{
DEBUGF( "fat_mount() - BPB is not sane\n");
@@ -408,59 +453,68 @@ int fat_mount(int startsector)
}
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{
- fat_bpb.fsinfo.freecount = 0xffffffff; /* force recalc below */
- fat_bpb.fsinfo.nextfree = 0xffffffff;
+ fat_bpb->fsinfo.freecount = 0xffffffff; /* force recalc below */
+ fat_bpb->fsinfo.nextfree = 0xffffffff;
}
else
#endif /* #ifdef HAVE_FAT16SUPPORT */
{
/* Read the fsinfo sector */
- rc = ata_read_sectors(startsector + fat_bpb.bpb_fsinfo, 1, buf);
+ rc = ata_read_sectors(IF_MV2(drive,)
+ startsector + fat_bpb->bpb_fsinfo, 1, buf);
if (rc < 0)
{
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_bpb->fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
+ fat_bpb->fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
}
/* calculate freecount if unset */
- if ( fat_bpb.fsinfo.freecount == 0xffffffff )
+ if ( fat_bpb->fsinfo.freecount == 0xffffffff )
{
- fat_recalc_free();
+ fat_recalc_free(IF_MV(volume));
}
- LDEBUGF("Freecount: %d\n",fat_bpb.fsinfo.freecount);
- LDEBUGF("Nextfree: 0x%x\n",fat_bpb.fsinfo.nextfree);
- LDEBUGF("Cluster count: 0x%x\n",fat_bpb.dataclusters);
- LDEBUGF("Sectors per cluster: %d\n",fat_bpb.bpb_secperclus);
- LDEBUGF("FAT sectors: 0x%x\n",fat_bpb.fatsize);
+ LDEBUGF("Freecount: %d\n",fat_bpb->fsinfo.freecount);
+ LDEBUGF("Nextfree: 0x%x\n",fat_bpb->fsinfo.nextfree);
+ LDEBUGF("Cluster count: 0x%x\n",fat_bpb->dataclusters);
+ LDEBUGF("Sectors per cluster: %d\n",fat_bpb->bpb_secperclus);
+ LDEBUGF("FAT sectors: 0x%x\n",fat_bpb->fatsize);
+
+#ifdef HAVE_MULTIVOLUME
+ fat_bpb->mounted = true;
+#endif
return 0;
}
-void fat_recalc_free(void)
+void fat_recalc_free(IF_MV_NONVOID(int volume))
{
+#ifndef HAVE_MULTIVOLUME
+ const int volume = 0;
+#endif
+ struct bpb* fat_bpb = &fat_bpbs[volume];
int free = 0;
unsigned i;
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{
- for (i = 0; i<fat_bpb.fatsize; i++) {
+ for (i = 0; i<fat_bpb->fatsize; i++) {
unsigned int j;
- unsigned short* fat = cache_fat_sector(i);
+ unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) i);
for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
unsigned int c = i * CLUSTERS_PER_FAT16_SECTOR + j;
- if ( c > fat_bpb.dataclusters+1 ) /* nr 0 is unused */
+ if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
break;
if (SWAB16(fat[j]) == 0x0000) {
free++;
- if ( fat_bpb.fsinfo.nextfree == 0xffffffff )
- fat_bpb.fsinfo.nextfree = c;
+ if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
+ fat_bpb->fsinfo.nextfree = c;
}
}
}
@@ -468,116 +522,153 @@ void fat_recalc_free(void)
else
#endif /* #ifdef HAVE_FAT16SUPPORT */
{
- for (i = 0; i<fat_bpb.fatsize; i++) {
+ for (i = 0; i<fat_bpb->fatsize; i++) {
unsigned int j;
- unsigned int* fat = cache_fat_sector(i);
+ unsigned int* fat = cache_fat_sector(IF_MV2(fat_bpb,) i);
for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
unsigned int c = i * CLUSTERS_PER_FAT_SECTOR + j;
- if ( c > fat_bpb.dataclusters+1 ) /* nr 0 is unused */
+ if ( c > fat_bpb->dataclusters+1 ) /* nr 0 is unused */
break;
if (!(SWAB32(fat[j]) & 0x0fffffff)) {
free++;
- if ( fat_bpb.fsinfo.nextfree == 0xffffffff )
- fat_bpb.fsinfo.nextfree = c;
+ if ( fat_bpb->fsinfo.nextfree == 0xffffffff )
+ fat_bpb->fsinfo.nextfree = c;
}
}
}
}
- fat_bpb.fsinfo.freecount = free;
- update_fsinfo();
+ fat_bpb->fsinfo.freecount = free;
+ update_fsinfo(IF_MV(fat_bpb));
}
-static int bpb_is_sane(void)
+static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb))
{
- if(fat_bpb.bpb_bytspersec != 512)
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
+ if(fat_bpb->bpb_bytspersec != 512)
{
DEBUGF( "bpb_is_sane() - Error: sector size is not 512 (%d)\n",
- fat_bpb.bpb_bytspersec);
+ fat_bpb->bpb_bytspersec);
return -1;
}
- if(fat_bpb.bpb_secperclus * fat_bpb.bpb_bytspersec > 128*1024)
+ if(fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec > 128*1024)
{
DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
"(%d * %d = %d)\n",
- fat_bpb.bpb_bytspersec, fat_bpb.bpb_secperclus,
- fat_bpb.bpb_bytspersec * fat_bpb.bpb_secperclus);
+ fat_bpb->bpb_bytspersec, fat_bpb->bpb_secperclus,
+ fat_bpb->bpb_bytspersec * fat_bpb->bpb_secperclus);
return -2;
}
- if(fat_bpb.bpb_numfats != 2)
+ if(fat_bpb->bpb_numfats != 2)
{
DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n",
- fat_bpb.bpb_numfats);
+ fat_bpb->bpb_numfats);
}
- if(fat_bpb.bpb_media != 0xf0 && fat_bpb.bpb_media < 0xf8)
+ if(fat_bpb->bpb_media != 0xf0 && fat_bpb->bpb_media < 0xf8)
{
DEBUGF( "bpb_is_sane() - Warning: Non-standard "
"media type (0x%02x)\n",
- fat_bpb.bpb_media);
+ fat_bpb->bpb_media);
}
- if(fat_bpb.last_word != 0xaa55)
+ if(fat_bpb->last_word != 0xaa55)
{
DEBUGF( "bpb_is_sane() - Error: Last word is not "
- "0xaa55 (0x%04x)\n", fat_bpb.last_word);
+ "0xaa55 (0x%04x)\n", fat_bpb->last_word);
return -3;
}
- if (fat_bpb.fsinfo.freecount >
- (fat_bpb.totalsectors - fat_bpb.firstdatasector)/
- fat_bpb.bpb_secperclus)
+ if (fat_bpb->fsinfo.freecount >
+ (fat_bpb->totalsectors - fat_bpb->firstdatasector)/
+ fat_bpb->bpb_secperclus)
{
DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
- "(0x%04x)\n", fat_bpb.fsinfo.freecount);
+ "(0x%04x)\n", fat_bpb->fsinfo.freecount);
return -4;
}
return 0;
}
-static void *cache_fat_sector(int fatsector)
+static void flush_fat_sector(struct fat_cache_entry *fce,
+ unsigned char *sectorbuf)
{
- int secnum = fatsector + fat_bpb.bpb_rsvdseccnt;
+ int rc;
+ int secnum;
+
+ /* With multivolume, use only the FAT info from the cached sector! */
+#ifdef HAVE_MULTIVOLUME
+ secnum = fce->secnum + fce->fat_vol->startsector;
+#else
+ secnum = fce->secnum + fat_bpbs[0].startsector;
+#endif
+
+ /* Write to the first FAT */
+ rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
+ secnum, 1,
+ sectorbuf);
+ if(rc < 0)
+ {
+ panicf("cache_fat_sector() - Could not write sector %d"
+ " (error %d)\n",
+ secnum, rc);
+ }
+#ifdef HAVE_MULTIVOLUME
+ if(fce->fat_vol->bpb_numfats > 1)
+#else
+ if(fat_bpbs[0].bpb_numfats > 1)
+#endif
+ {
+ /* Write to the second FAT */
+#ifdef HAVE_MULTIVOLUME
+ secnum += fce->fat_vol->fatsize;
+#else
+ secnum += fat_bpbs[0].fatsize;
+#endif
+ rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,)
+ secnum, 1, sectorbuf);
+ if(rc < 0)
+ {
+ panicf("cache_fat_sector() - Could not write sector %d"
+ " (error %d)\n",
+ secnum, rc);
+ }
+ }
+ fce->dirty = false;
+}
+
+static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,) int fatsector)
+{
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
+ int secnum = fatsector + fat_bpb->bpb_rsvdseccnt;
int cache_index = secnum & FAT_CACHE_MASK;
struct fat_cache_entry *fce = &fat_cache[cache_index];
unsigned char *sectorbuf = &fat_cache_sectors[cache_index][0];
int rc;
/* Delete the cache entry if it isn't the sector we want */
- if(fce->inuse && fce->secnum != secnum)
+ if(fce->inuse && (fce->secnum != secnum
+#ifdef HAVE_MULTIVOLUME
+ || fce->fat_vol != fat_bpb
+#endif
+ ))
{
/* Write back if it is dirty */
if(fce->dirty)
{
- rc = ata_write_sectors(fce->secnum+fat_bpb.startsector, 1,
- sectorbuf);
- if(rc < 0)
- {
- panicf("cache_fat_sector() - Could not write sector %d"
- " (error %d)\n",
- secnum, rc);
- }
- if(fat_bpb.bpb_numfats > 1)
- {
- /* Write to the second FAT */
- rc = ata_write_sectors(fce->secnum+fat_bpb.startsector+
- fat_bpb.fatsize, 1, sectorbuf);
- if(rc < 0)
- {
- panicf("cache_fat_sector() - Could not write sector %d"
- " (error %d)\n",
- secnum + fat_bpb.fatsize, rc);
- }
- }
+ flush_fat_sector(fce, sectorbuf);
}
- fce->secnum = 8; /* Normally an unused sector */
- fce->dirty = false;
fce->inuse = false;
}
/* Load the sector if it is not cached */
if(!fce->inuse)
{
- rc = ata_read_sectors(secnum + fat_bpb.startsector,1,
+ rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
+ secnum + fat_bpb->startsector,1,
sectorbuf);
if(rc < 0)
{
@@ -587,26 +678,32 @@ static void *cache_fat_sector(int fatsector)
}
fce->inuse = true;
fce->secnum = secnum;
+#ifdef HAVE_MULTIVOLUME
+ fce->fat_vol = fat_bpb;
+#endif
}
return sectorbuf;
}
-static unsigned int find_free_cluster(unsigned int startcluster)
+static unsigned int find_free_cluster(IF_MV2(struct bpb* fat_bpb,) unsigned int startcluster)
{
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
unsigned int sector;
unsigned int offset;
unsigned int i;
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{
sector = startcluster / CLUSTERS_PER_FAT16_SECTOR;
offset = startcluster % CLUSTERS_PER_FAT16_SECTOR;
- for (i = 0; i<fat_bpb.fatsize; i++) {
+ for (i = 0; i<fat_bpb->fatsize; i++) {
unsigned int j;
- unsigned int nr = (i + sector) % fat_bpb.fatsize;
- unsigned short* fat = cache_fat_sector(nr);
+ unsigned int nr = (i + sector) % fat_bpb->fatsize;
+ unsigned short* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr);
if ( !fat )
break;
for (j = 0; j < CLUSTERS_PER_FAT16_SECTOR; j++) {
@@ -615,10 +712,10 @@ static unsigned int find_free_cluster(unsigned int startcluster)
unsigned int c = nr * CLUSTERS_PER_FAT16_SECTOR + k;
/* Ignore the reserved clusters 0 & 1, and also
cluster numbers out of bounds */
- if ( c < 2 || c > fat_bpb.dataclusters+1 )
+ if ( c < 2 || c > fat_bpb->dataclusters+1 )
continue;
LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
- fat_bpb.fsinfo.nextfree = c;
+ fat_bpb->fsinfo.nextfree = c;
return c;
}
}
@@ -631,10 +728,10 @@ static unsigned int find_free_cluster(unsigned int startcluster)
sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
- for (i = 0; i<fat_bpb.fatsize; i++) {
+ for (i = 0; i<fat_bpb->fatsize; i++) {
unsigned int j;
- unsigned int nr = (i + sector) % fat_bpb.fatsize;
- unsigned int* fat = cache_fat_sector(nr);
+ unsigned int nr = (i + sector) % fat_bpb->fatsize;
+ unsigned int* fat = cache_fat_sector(IF_MV2(fat_bpb,) nr);
if ( !fat )
break;
for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
@@ -643,10 +740,10 @@ static unsigned int find_free_cluster(unsigned int startcluster)
unsigned int c = nr * CLUSTERS_PER_FAT_SECTOR + k;
/* Ignore the reserved clusters 0 & 1, and also
cluster numbers out of bounds */
- if ( c < 2 || c > fat_bpb.dataclusters+1 )
+ if ( c < 2 || c > fat_bpb->dataclusters+1 )
continue;
LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
- fat_bpb.fsinfo.nextfree = c;
+ fat_bpb->fsinfo.nextfree = c;
return c;
}
}
@@ -658,10 +755,13 @@ static unsigned int find_free_cluster(unsigned int startcluster)
return 0; /* 0 is an illegal cluster number */
}
-static int update_fat_entry(unsigned int entry, unsigned int val)
+static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned int entry, unsigned int val)
{
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{
int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
@@ -677,24 +777,24 @@ static int update_fat_entry(unsigned int entry, unsigned int val)
if ( entry < 2 )
panicf("Updating reserved FAT entry %d.\n",entry);
- sec = cache_fat_sector(sector);
+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector);
if (!sec)
{
DEBUGF( "update_entry() - Could not cache sector %d\n", sector);
return -1;
}
- fat_cache[(sector + fat_bpb.bpb_rsvdseccnt) & FAT_CACHE_MASK].dirty = true;
+ fat_cache[(sector + fat_bpb->bpb_rsvdseccnt) & FAT_CACHE_MASK].dirty = true;
if ( val ) {
- if (SWAB16(sec[offset]) == 0x0000 && fat_bpb.fsinfo.freecount > 0)
- fat_bpb.fsinfo.freecount--;
+ if (SWAB16(sec[offset]) == 0x0000 && fat_bpb->fsinfo.freecount > 0)
+ fat_bpb->fsinfo.freecount--;
}
else {
if (SWAB16(sec[offset]))
- fat_bpb.fsinfo.freecount++;
+ fat_bpb->fsinfo.freecount++;
}
- LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb.fsinfo.freecount);
+ LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);
sec[offset] = SWAB16(val);
}
@@ -713,25 +813,25 @@ static int update_fat_entry(unsigned int entry, unsigned int val)
if ( entry < 2 )
panicf("Updating reserved FAT entry %d.\n",entry);
- sec = cache_fat_sector(sector);
+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector);
if (!sec)
{
DEBUGF( "update_entry() - Could not cache sector %d\n", sector);
return -1;
}
- fat_cache[(sector + fat_bpb.bpb_rsvdseccnt) & FAT_CACHE_MASK].dirty = true;
+ fat_cache[(sector + fat_bpb->bpb_rsvdseccnt) & FAT_CACHE_MASK].dirty = true;
if ( val ) {
if (!(SWAB32(sec[offset]) & 0x0fffffff) &&
- fat_bpb.fsinfo.freecount > 0)
- fat_bpb.fsinfo.freecount--;
+ fat_bpb->fsinfo.freecount > 0)
+ fat_bpb->fsinfo.freecount--;
}
else {
if (SWAB32(sec[offset]) & 0x0fffffff)
- fat_bpb.fsinfo.freecount++;
+ fat_bpb->fsinfo.freecount++;
}
- LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb.fsinfo.freecount);
+ LDEBUGF("update_fat_entry: %d free clusters\n", fat_bpb->fsinfo.freecount);
/* don't change top 4 bits */
sec[offset] &= SWAB32(0xf0000000);
@@ -741,16 +841,19 @@ static int update_fat_entry(unsigned int entry, unsigned int val)
return 0;
}
-static int read_fat_entry(unsigned int entry)
+static int read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned int entry)
{
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{
int sector = entry / CLUSTERS_PER_FAT16_SECTOR;
int offset = entry % CLUSTERS_PER_FAT16_SECTOR;
unsigned short* sec;
- sec = cache_fat_sector(sector);
+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector);
if (!sec)
{
DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
@@ -766,7 +869,7 @@ static int read_fat_entry(unsigned int entry)
int offset = entry % CLUSTERS_PER_FAT_SECTOR;
unsigned int* sec;
- sec = cache_fat_sector(sector);
+ sec = cache_fat_sector(IF_MV2(fat_bpb,) sector);
if (!sec)
{
DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector);
@@ -777,20 +880,23 @@ static int read_fat_entry(unsigned int entry)
}
}
-static int get_next_cluster(int cluster)
+static int get_next_cluster(IF_MV2(struct bpb* fat_bpb,) int cluster)
{
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
int next_cluster;
int eof_mark = FAT_EOF_MARK;
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{
eof_mark &= 0xFFFF; /* only 16 bit */
if (cluster < 0) /* FAT16 root dir */
return cluster + 1; /* don't use the FAT */
}
#endif
- next_cluster = read_fat_entry(cluster);
+ next_cluster = read_fat_entry(IF_MV2(fat_bpb,) cluster);
/* is this last cluster in chain? */
if ( next_cluster >= eof_mark )
@@ -799,31 +905,36 @@ static int get_next_cluster(int cluster)
return next_cluster;
}
-static int update_fsinfo(void)
+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 int* intptr;
int rc;
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
return 0; /* FAT16 has no FsInfo */
#endif /* #ifdef HAVE_FAT16SUPPORT */
/* update fsinfo */
- rc = ata_read_sectors(fat_bpb.startsector + fat_bpb.bpb_fsinfo, 1,fsinfo);
+ rc = ata_read_sectors(IF_MV2(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);
return rc * 10 - 1;
}
intptr = (int*)&(fsinfo[FSINFO_FREECOUNT]);
- *intptr = SWAB32(fat_bpb.fsinfo.freecount);
+ *intptr = SWAB32(fat_bpb->fsinfo.freecount);
intptr = (int*)&(fsinfo[FSINFO_NEXTFREE]);
- *intptr = SWAB32(fat_bpb.fsinfo.nextfree);
+ *intptr = SWAB32(fat_bpb->fsinfo.nextfree);
- rc = ata_write_sectors(fat_bpb.startsector + fat_bpb.bpb_fsinfo,1,fsinfo);
+ rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
+ fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo);
if (rc < 0)
{
DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc);
@@ -833,48 +944,24 @@ static int update_fsinfo(void)
return 0;
}
-static int flush_fat(void)
+static int flush_fat(IF_MV_NONVOID(struct bpb* fat_bpb))
{
int i;
int rc;
unsigned char *sec;
- int secnum;
LDEBUGF("flush_fat()\n");
for(i = 0;i < FAT_CACHE_SIZE;i++)
{
- if(fat_cache[i].inuse && fat_cache[i].dirty)
+ struct fat_cache_entry *fce = &fat_cache[i];
+ if(fce->inuse && fce->dirty)
{
- secnum = fat_cache[i].secnum + fat_bpb.startsector;
- LDEBUGF("Flushing FAT sector %x\n", secnum);
sec = fat_cache_sectors[i];
-
- /* Write to the first FAT */
- rc = ata_write_sectors(secnum, 1, sec);
- if(rc)
- {
- DEBUGF( "flush_fat() - Couldn't write"
- " sector %d (error %d)\n", secnum, rc);
- return rc * 10 - 1;
- }
-
- if(fat_bpb.bpb_numfats > 1 )
- {
- /* Write to the second FAT */
- rc = ata_write_sectors(secnum + fat_bpb.fatsize, 1, sec);
- if (rc)
- {
- DEBUGF( "flush_fat() - Couldn't write"
- " sector %d (error %d)\n",
- secnum + fat_bpb.fatsize, rc);
- return rc * 10 - 2;
- }
- }
- fat_cache[i].dirty = false;
+ flush_fat_sector(fce, sec);
}
}
- rc = update_fsinfo();
+ rc = update_fsinfo(IF_MV(fat_bpb));
if (rc < 0)
return rc * 10 - 3;
@@ -1108,6 +1195,11 @@ static int add_dir_entry(struct fat_dir* dir,
bool is_directory,
bool dotdir)
{
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
unsigned char buf[SECTOR_SIZE];
unsigned char shortname[16];
int rc;
@@ -1122,6 +1214,10 @@ static int add_dir_entry(struct fat_dir* dir,
LDEBUGF( "add_dir_entry(%s,%x)\n",
name, file->firstcluster);
+#ifdef HAVE_MULTIVOLUME
+ file->volume = dir->file.volume; /* inherit the volume, to make sure */
+#endif
+
/* The "." and ".." directory entries must not be long names */
if(dotdir) {
int i;
@@ -1173,7 +1269,7 @@ static int add_dir_entry(struct fat_dir* dir,
rc = fat_readwrite(&dir->file, 1, buf, true);
if (rc < 1)
return rc * 10 - 3;
- } while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus);
+ } while (dir->file.sectornum < (int)fat_bpb->bpb_secperclus);
}
if (rc < 0) {
DEBUGF( "add_dir_entry() - Couldn't read dir"
@@ -1277,7 +1373,7 @@ static int add_dir_entry(struct fat_dir* dir,
if (rc < 1)
return rc * 10 - 9;
memset(buf, 0, sizeof buf);
- } while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus);
+ } while (dir->file.sectornum < (int)fat_bpb->bpb_secperclus);
}
else
{
@@ -1288,7 +1384,7 @@ static int add_dir_entry(struct fat_dir* dir,
if (rc < 1)
return rc * 10 - 9; /* Same error code as above, can't be
more than -9 */
- } while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus);
+ } while (dir->file.sectornum < (int)fat_bpb->bpb_secperclus);
}
}
@@ -1368,7 +1464,7 @@ static int update_short_entry( struct fat_file* file, int size, int attr )
file->firstcluster, file->direntry, size);
/* create a temporary file handle for the dir holding this file */
- rc = fat_open(file->dircluster, &dir, NULL);
+ rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
if (rc < 0)
return rc * 10 - 1;
@@ -1445,7 +1541,8 @@ static int parse_direntry(struct fat_direntry *de, const unsigned char *buf)
return 1;
}
-int fat_open(unsigned int startcluster,
+int fat_open(IF_MV2(int volume,)
+ unsigned int startcluster,
struct fat_file *file,
const struct fat_dir* dir)
{
@@ -1455,6 +1552,15 @@ int fat_open(unsigned int startcluster,
file->clusternum = 0;
file->sectornum = 0;
file->eof = false;
+#ifdef HAVE_MULTIVOLUME
+ file->volume = volume;
+ /* fixme: remove error check when done */
+ if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
+ {
+ LDEBUGF("fat_open() illegal volume %d\n", volume);
+ return -1;
+ }
+#endif
/* remember where the file's dir entry is located */
if ( dir ) {
@@ -1469,19 +1575,26 @@ int fat_open(unsigned int startcluster,
#ifdef HAVE_FAT16SUPPORT
/* special function to open the FAT16 root dir,
which may not be on cluster boundary */
-int fat_open_root(struct fat_file *file)
+static int fat_open_root(IF_MV2(int volume,)
+ struct fat_file *file)
{
int dirclusters;
- file->firstcluster = fat_bpb.bpb_rootclus;
- file->lastcluster = fat_bpb.bpb_rootclus;
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[volume];
+ file->volume = volume;
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
+ file->firstcluster = fat_bpb->bpb_rootclus;
+ file->lastcluster = fat_bpb->bpb_rootclus;
file->lastsector = 0;
file->clusternum = 0;
- dirclusters = 0 - fat_bpb.bpb_rootclus; /* bpb_rootclus is the negative */
- file->sectornum = (dirclusters * fat_bpb.bpb_secperclus)
- - fat_bpb.rootdirsectors; /* cluster sectors minus real sectors */
+ dirclusters = 0 - fat_bpb->bpb_rootclus; /* bpb_rootclus is the negative */
+ file->sectornum = (dirclusters * fat_bpb->bpb_secperclus)
+ - fat_bpb->rootdirsectors; /* cluster sectors minus real sectors */
file->eof = false;
- LDEBUGF("fat_open_root(), sector %d\n", cluster2sec(fat_bpb.bpb_rootclus));
+ LDEBUGF("fat_open_root(), sector %d\n", cluster2sec(fat_bpb->bpb_rootclus));
return 0;
}
#endif /* #ifdef HAVE_FAT16SUPPORT */
@@ -1510,6 +1623,11 @@ int fat_create_dir(const char* name,
struct fat_dir* newdir,
struct fat_dir* dir)
{
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[dir->file.volume];
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
unsigned char buf[SECTOR_SIZE];
int i;
int sector;
@@ -1527,17 +1645,17 @@ int fat_create_dir(const char* name,
return rc * 10 - 1;
/* Allocate a new cluster for the directory */
- newdir->file.firstcluster = find_free_cluster(fat_bpb.fsinfo.nextfree);
+ newdir->file.firstcluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
if(newdir->file.firstcluster == 0)
return -1;
- update_fat_entry(newdir->file.firstcluster, FAT_EOF_MARK);
+ update_fat_entry(IF_MV2(fat_bpb,) newdir->file.firstcluster, FAT_EOF_MARK);
/* Clear the entire cluster */
memset(buf, 0, sizeof buf);
- sector = cluster2sec(newdir->file.firstcluster);
- for(i = 0;i < (int)fat_bpb.bpb_secperclus;i++) {
- rc = transfer( sector + i, 1, buf, true );
+ sector = cluster2sec(IF_MV2(fat_bpb,) newdir->file.firstcluster);
+ for(i = 0;i < (int)fat_bpb->bpb_secperclus;i++) {
+ rc = transfer(IF_MV2(fat_bpb,) sector + i, 1, buf, true );
if (rc < 0)
return rc * 10 - 2;
}
@@ -1555,7 +1673,7 @@ int fat_create_dir(const char* name,
return rc * 10 - 4;
/* The root cluster is cluster 0 in the ".." entry */
- if(dir->file.firstcluster == fat_bpb.bpb_rootclus)
+ if(dir->file.firstcluster == fat_bpb->bpb_rootclus)
dummyfile.firstcluster = 0;
else
dummyfile.firstcluster = dir->file.firstcluster;
@@ -1564,7 +1682,7 @@ int fat_create_dir(const char* name,
/* Set the firstcluster field in the direntry */
update_short_entry(&newdir->file, 0, FAT_ATTR_DIRECTORY);
- rc = flush_fat();
+ rc = flush_fat(IF_MV(fat_bpb));
if (rc < 0)
return rc * 10 - 5;
@@ -1576,15 +1694,18 @@ int fat_truncate(const struct fat_file *file)
/* truncate trailing clusters */
int next;
int last = file->lastcluster;
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#endif
LDEBUGF("fat_truncate(%x, %x)\n", file->firstcluster, last);
- for ( last = get_next_cluster(last); last; last = next ) {
- next = get_next_cluster(last);
- update_fat_entry(last,0);
+ for ( last = get_next_cluster(IF_MV2(fat_bpb,) last); last; last = next ) {
+ next = get_next_cluster(IF_MV2(fat_bpb,) last);
+ update_fat_entry(IF_MV2(fat_bpb,) last,0);
}
if (file->lastcluster)
- update_fat_entry(file->lastcluster,FAT_EOF_MARK);
+ update_fat_entry(IF_MV2(fat_bpb,) file->lastcluster,FAT_EOF_MARK);
return 0;
}
@@ -1592,12 +1713,15 @@ int fat_truncate(const struct fat_file *file)
int fat_closewrite(struct fat_file *file, int size, int attr)
{
int rc;
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#endif
LDEBUGF("fat_closewrite(size=%d)\n",size);
if (!size) {
/* empty file */
if ( file->firstcluster ) {
- update_fat_entry(file->firstcluster, 0);
+ update_fat_entry(IF_MV2(fat_bpb,) file->firstcluster, 0);
file->firstcluster = 0;
}
}
@@ -1608,21 +1732,26 @@ int fat_closewrite(struct fat_file *file, int size, int attr)
return rc * 10 - 1;
}
- flush_fat();
+ flush_fat(IF_MV(fat_bpb));
#ifdef TEST_FAT
if ( file->firstcluster ) {
/* debug */
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
int count = 0;
int len;
int next;
for ( next = file->firstcluster; next;
- next = get_next_cluster(next) )
+ next = get_next_cluster(IF_MV2(fat_bpb,) next) )
LDEBUGF("cluster %d: %x\n", count++, next);
- len = count * fat_bpb.bpb_secperclus * SECTOR_SIZE;
+ len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
LDEBUGF("File is %d clusters (chainlen=%d, size=%d)\n",
count, len, size );
- if ( len > size + fat_bpb.bpb_secperclus * SECTOR_SIZE)
+ if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
panicf("Cluster chain is too long\n");
if ( len < size )
panicf("Cluster chain is too short\n");
@@ -1632,17 +1761,18 @@ int fat_closewrite(struct fat_file *file, int size, int attr)
return 0;
}
-static int free_direntries(int dircluster, int startentry, int numentries)
+static int free_direntries(struct fat_file* file)
{
unsigned char buf[SECTOR_SIZE];
struct fat_file dir;
- unsigned int entry = startentry - numentries + 1;
+ int numentries = file->direntries;
+ unsigned int entry = file->direntry - numentries + 1;
unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
int i;
int rc;
/* create a temporary file handle for the dir holding this file */
- rc = fat_open(dircluster, &dir, NULL);
+ rc = fat_open(IF_MV2(file->volume,) file->dircluster, &dir, NULL);
if (rc < 0)
return rc * 10 - 1;
@@ -1698,19 +1828,20 @@ int fat_remove(struct fat_file* file)
{
int next, last = file->firstcluster;
int rc;
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#endif
LDEBUGF("fat_remove(%x)\n",last);
while ( last ) {
- next = get_next_cluster(last);
- update_fat_entry(last,0);
+ next = get_next_cluster(IF_MV2(fat_bpb,) last);
+ update_fat_entry(IF_MV2(fat_bpb,) last,0);
last = next;
}
if ( file->dircluster ) {
- rc = free_direntries(file->dircluster,
- file->direntry,
- file->direntries);
+ rc = free_direntries(file);
if (rc < 0)
return rc * 10 - 1;
}
@@ -1718,7 +1849,7 @@ int fat_remove(struct fat_file* file)
file->firstcluster = 0;
file->dircluster = 0;
- rc = flush_fat();
+ rc = flush_fat(IF_MV(fat_bpb));
if (rc < 0)
return rc * 10 - 2;
@@ -1734,6 +1865,9 @@ int fat_rename(struct fat_file* file,
int rc;
struct fat_dir olddir;
struct fat_file newfile = *file;
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#endif
if ( !file->dircluster ) {
DEBUGF("File has no dir cluster!\n");
@@ -1741,7 +1875,7 @@ int fat_rename(struct fat_file* file,
}
/* create a temporary file handle */
- rc = fat_opendir(&olddir, file->dircluster, NULL);
+ rc = fat_opendir(IF_MV2(file->volume,) &olddir, file->dircluster, NULL);
if (rc < 0)
return rc * 10 - 2;
@@ -1756,11 +1890,11 @@ int fat_rename(struct fat_file* file,
return rc * 10 - 4;
/* remove old name */
- rc = free_direntries(file->dircluster, file->direntry, file->direntries);
+ rc = free_direntries(file);
if (rc < 0)
return rc * 10 - 5;
- rc = flush_fat();
+ rc = flush_fat(IF_MV(fat_bpb));
if (rc < 0)
return rc * 10 - 6;
@@ -1771,19 +1905,24 @@ static int next_write_cluster(struct fat_file* file,
int oldcluster,
int* newsector)
{
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
int cluster = 0;
int sector;
LDEBUGF("next_write_cluster(%x,%x)\n",file->firstcluster, oldcluster);
if (oldcluster)
- cluster = get_next_cluster(oldcluster);
+ cluster = get_next_cluster(IF_MV2(fat_bpb,) oldcluster);
if (!cluster) {
if (oldcluster > 0)
- cluster = find_free_cluster(oldcluster+1);
+ cluster = find_free_cluster(IF_MV2(fat_bpb,) oldcluster+1);
else if (oldcluster == 0)
- cluster = find_free_cluster(fat_bpb.fsinfo.nextfree);
+ cluster = find_free_cluster(IF_MV2(fat_bpb,) fat_bpb->fsinfo.nextfree);
#ifdef HAVE_FAT16SUPPORT
else /* negative, pseudo-cluster of the root dir */
return 0; /* impossible to append something to the root */
@@ -1791,14 +1930,14 @@ static int next_write_cluster(struct fat_file* file,
if (cluster) {
if (oldcluster)
- update_fat_entry(oldcluster, cluster);
+ update_fat_entry(IF_MV2(fat_bpb,) oldcluster, cluster);
else
file->firstcluster = cluster;
- update_fat_entry(cluster, FAT_EOF_MARK);
+ update_fat_entry(IF_MV2(fat_bpb,) cluster, FAT_EOF_MARK);
}
else {
#ifdef TEST_FAT
- if (fat_bpb.fsinfo.freecount>0)
+ if (fat_bpb->fsinfo.freecount>0)
panicf("There is free space, but find_free_cluster() "
"didn't find it!\n");
#endif
@@ -1806,7 +1945,7 @@ static int next_write_cluster(struct fat_file* file,
return 0;
}
}
- sector = cluster2sec(cluster);
+ sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
if (sector<0)
return 0;
@@ -1814,30 +1953,36 @@ static int next_write_cluster(struct fat_file* file,
return cluster;
}
-static int transfer( unsigned int start, int count, char* buf, bool write )
+static int transfer(IF_MV2(struct bpb* fat_bpb,)
+ unsigned int start, int count, char* buf, bool write )
{
+#ifndef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
int rc;
LDEBUGF("transfer(s=%x, c=%x, %s)\n",
- start+ fat_bpb.startsector, count, write?"write":"read");
+ start+ fat_bpb->startsector, count, write?"write":"read");
if (write) {
unsigned int firstallowed;
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
- firstallowed = fat_bpb.rootdirsector;
+ if (fat_bpb->is_fat16)
+ firstallowed = fat_bpb->rootdirsector;
else
#endif
- firstallowed = fat_bpb.firstdatasector;
+ firstallowed = fat_bpb->firstdatasector;
if (start < firstallowed)
panicf("Write %d before data\n", firstallowed - start);
- if (start + count > fat_bpb.totalsectors)
+ if (start + count > fat_bpb->totalsectors)
panicf("Write %d after data\n",
- start + count - fat_bpb.totalsectors);
- rc = ata_write_sectors(start + fat_bpb.startsector, count, buf);
+ start + count - fat_bpb->totalsectors);
+ rc = ata_write_sectors(IF_MV2(fat_bpb->drive,)
+ start + fat_bpb->startsector, count, buf);
}
else
- rc = ata_read_sectors(start + fat_bpb.startsector, count, buf);
+ rc = ata_read_sectors(IF_MV2(fat_bpb->drive,)
+ start + fat_bpb->startsector, count, buf);
if (rc < 0) {
DEBUGF( "transfer() - Couldn't %s sector %x"
" (error code %d)\n",
@@ -1851,6 +1996,11 @@ static int transfer( unsigned int start, int count, char* buf, bool write )
int fat_readwrite( struct fat_file *file, int sectorcount,
void* buf, bool write )
{
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
int cluster = file->lastcluster;
int sector = file->lastsector;
int clusternum = file->clusternum;
@@ -1871,13 +2021,13 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
/* find sequential sectors and write them all at once */
for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
numsec++;
- if ( numsec > (int)fat_bpb.bpb_secperclus || !cluster ) {
+ if ( numsec > (int)fat_bpb->bpb_secperclus || !cluster ) {
int oldcluster = cluster;
if (write)
cluster = next_write_cluster(file, cluster, &sector);
else {
- cluster = get_next_cluster(cluster);
- sector = cluster2sec(cluster);
+ cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
+ sector = cluster2sec(IF_MV2(fat_bpb,) cluster);
}
clusternum++;
@@ -1902,7 +2052,7 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
sector++;
else {
/* look up first sector of file */
- sector = cluster2sec(file->firstcluster);
+ sector = cluster2sec(IF_MV2(fat_bpb,) file->firstcluster);
numsec=1;
}
}
@@ -1913,7 +2063,7 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
if ( ((sector != first) && (sector != last+1)) || /* not sequential */
(last-first+1 == 256) ) { /* max 256 sectors per ata request */
int count = last - first + 1;
- rc = transfer( first, count, buf, write );
+ rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
if (rc < 0)
return rc * 10 - 1;
@@ -1925,7 +2075,7 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
(!eof))
{
int count = sector - first + 1;
- rc = transfer( first, count, buf, write );
+ rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write );
if (rc < 0)
return rc * 10 - 2;
}
@@ -1949,6 +2099,11 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
int fat_seek(struct fat_file *file, unsigned int seeksector )
{
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[file->volume];
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
int clusternum=0, numclusters=0, sectornum=0, sector=0;
int cluster = file->firstcluster;
int i;
@@ -1958,8 +2113,8 @@ int fat_seek(struct fat_file *file, unsigned int seeksector )
/* we need to find the sector BEFORE the requested, since
the file struct stores the last accessed sector */
seeksector--;
- numclusters = clusternum = seeksector / fat_bpb.bpb_secperclus;
- sectornum = seeksector % fat_bpb.bpb_secperclus;
+ numclusters = clusternum = seeksector / fat_bpb->bpb_secperclus;
+ sectornum = seeksector % fat_bpb->bpb_secperclus;
if (file->clusternum && clusternum >= file->clusternum)
{
@@ -1968,7 +2123,7 @@ int fat_seek(struct fat_file *file, unsigned int seeksector )
}
for (i=0; i<numclusters; i++) {
- cluster = get_next_cluster(cluster);
+ cluster = get_next_cluster(IF_MV2(fat_bpb,) cluster);
if (!cluster) {
DEBUGF("Seeking beyond the end of the file! "
"(sector %d, cluster %d)\n", seeksector, i);
@@ -1976,7 +2131,7 @@ int fat_seek(struct fat_file *file, unsigned int seeksector )
}
}
- sector = cluster2sec(cluster) + sectornum;
+ sector = cluster2sec(IF_MV2(fat_bpb,) cluster) + sectornum;
}
else {
sectornum = -1;
@@ -1992,9 +2147,21 @@ int fat_seek(struct fat_file *file, unsigned int seeksector )
return 0;
}
-int fat_opendir(struct fat_dir *dir, unsigned int startcluster,
+int fat_opendir(IF_MV2(int volume,)
+ struct fat_dir *dir, unsigned int startcluster,
const struct fat_dir *parent_dir)
{
+#ifdef HAVE_MULTIVOLUME
+ struct bpb* fat_bpb = &fat_bpbs[volume];
+ /* fixme: remove error check when done */
+ if (volume >= NUM_VOLUMES || !fat_bpbs[volume].mounted)
+ {
+ LDEBUGF("fat_open() illegal volume %d\n", volume);
+ return -1;
+ }
+#else
+ struct bpb* fat_bpb = &fat_bpbs[0];
+#endif
int rc;
dir->entry = 0;
@@ -2003,15 +2170,15 @@ int fat_opendir(struct fat_dir *dir, unsigned int startcluster,
if (startcluster == 0)
{
#ifdef HAVE_FAT16SUPPORT
- if (fat_bpb.is_fat16)
+ if (fat_bpb->is_fat16)
{ /* FAT16 has the root dir outside of the data area */
- return fat_open_root(&dir->file);
+ return fat_open_root(IF_MV2(volume,) &dir->file);
}
#endif
- startcluster = sec2cluster(fat_bpb.rootdirsector);
+ startcluster = sec2cluster(IF_MV2(fat_bpb,) fat_bpb->rootdirsector);
}
- rc = fat_open(startcluster, &dir->file, parent_dir);
+ rc = fat_open(IF_MV2(volume,) startcluster, &dir->file, parent_dir);
if(rc)
{
DEBUGF( "fat_opendir() - Couldn't open dir"
@@ -2196,7 +2363,18 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
return 0;
}
-int fat_get_cluster_size(void)
+int fat_get_cluster_size(IF_MV_NONVOID(int volume))
+{
+#ifndef HAVE_MULTIVOLUME
+ const int volume = 0;
+#endif
+ struct bpb* fat_bpb = &fat_bpbs[volume];
+ return fat_bpb->bpb_secperclus * SECTOR_SIZE;
+}
+
+#ifdef HAVE_MULTIVOLUME
+bool fat_ismounted(int volume)
{
- return fat_bpb.bpb_secperclus * SECTOR_SIZE;
+ return (volume<NUM_VOLUMES && fat_bpbs[volume].mounted);
}
+#endif
diff --git a/firmware/export/ata.h b/firmware/export/ata.h
index 06de33a8f2..fb604a120d 100644
--- a/firmware/export/ata.h
+++ b/firmware/export/ata.h
@@ -20,6 +20,21 @@
#define __ATA_H__
#include <stdbool.h>
+#include "config.h" /* for HAVE_MULTIVOLUME or not */
+
+/* FixMe: These macros are a bit nasty and perhaps misplaced here.
+ We'll get rid of them once decided on how to proceed with multivolume. */
+#ifdef HAVE_MULTIVOLUME
+#define IF_MV(x) x /* optional volume/drive parameter */
+#define IF_MV2(x,y) x,y /* same, for a list of arguments */
+#define IF_MV_NONVOID(x) x /* for prototype with sole volume parameter */
+#define NUM_VOLUMES 2
+#else /* empty definitions if no multi-volume */
+#define IF_MV(x)
+#define IF_MV2(x,y)
+#define IF_MV_NONVOID(x) void
+#define NUM_VOLUMES 1
+#endif
/*
ata_spindown() time values:
@@ -41,8 +56,8 @@ extern bool ata_disk_is_active(void);
extern int ata_hard_reset(void);
extern int ata_soft_reset(void);
extern int ata_init(void);
-extern int ata_read_sectors(unsigned long start, int count, void* buf);
-extern int ata_write_sectors(unsigned long start, int count, const void* buf);
+extern int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf);
+extern int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf);
extern void ata_delayed_write(unsigned long sector, const void* buf);
extern void ata_flush(void);
extern void ata_spin(void);
diff --git a/firmware/export/disk.h b/firmware/export/disk.h
index 7a9697aa13..70b73c6547 100644
--- a/firmware/export/disk.h
+++ b/firmware/export/disk.h
@@ -19,6 +19,8 @@
#ifndef _DISK_H_
#define _DISK_H_
+#include "ata.h" /* for volume definitions */
+
struct partinfo {
unsigned long start; /* first sector (LBA) */
unsigned long size; /* number of sectors */
@@ -30,7 +32,7 @@ struct partinfo {
#define PARTITION_TYPE_FAT16 0x06
/* returns a pointer to an array of 8 partinfo structs */
-struct partinfo* disk_init(void);
+struct partinfo* disk_init(IF_MV_NONVOID(int volume));
struct partinfo* disk_partinfo(int partition);
#endif
diff --git a/firmware/export/fat.h b/firmware/export/fat.h
index 6f9c9c5d11..7150d2b09f 100644
--- a/firmware/export/fat.h
+++ b/firmware/export/fat.h
@@ -21,6 +21,7 @@
#define FAT_H
#include <stdbool.h>
+#include "ata.h" /* for volume definitions */
#define SECTOR_SIZE 512
@@ -45,6 +46,7 @@ struct fat_direntry
#define FAT_ATTR_VOLUME_ID 0x08
#define FAT_ATTR_DIRECTORY 0x10
#define FAT_ATTR_ARCHIVE 0x20
+#define FAT_ATTR_VOLUME 0x40 /* this is a volume, not a real directory */
struct fat_file
{
@@ -57,6 +59,9 @@ struct fat_file
unsigned int direntries; /* number of dir entries used by this file */
unsigned int dircluster; /* first cluster of dir */
bool eof;
+#ifdef HAVE_MULTIVOLUME
+ int volume; /* file resides on which volume */
+#endif
};
struct fat_dir
@@ -69,14 +74,16 @@ struct fat_dir
};
-extern int fat_mount(int startsector);
-extern void fat_size(unsigned int* size, unsigned int* free);
-extern void fat_recalc_free(void);
+extern void fat_init(void);
+extern int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) int startsector);
+extern void fat_size(IF_MV2(int volume,) unsigned int* size, unsigned int* free); // public for info
+extern void fat_recalc_free(IF_MV_NONVOID(int volume)); // public for debug info screen
extern int fat_create_dir(const char* name,
struct fat_dir* newdir,
struct fat_dir* dir);
-extern int fat_startsector(void);
-extern int fat_open(unsigned int cluster,
+extern int fat_startsector(IF_MV_NONVOID(int volume)); // public for config sector
+extern int fat_open(IF_MV2(int volume,)
+ unsigned int cluster,
struct fat_file* ent,
const struct fat_dir* dir);
extern int fat_create_file(const char* name,
@@ -93,9 +100,11 @@ extern int fat_rename(struct fat_file* file,
const unsigned char* newname,
int size, int attr);
-extern int fat_opendir(struct fat_dir *ent, unsigned int currdir,
+extern int fat_opendir(IF_MV2(int volume,)
+ struct fat_dir *ent, unsigned int currdir,
const struct fat_dir *parent_dir);
extern int fat_getnext(struct fat_dir *ent, struct fat_direntry *entry);
-extern int fat_get_cluster_size(void);
+extern int fat_get_cluster_size(IF_MV_NONVOID(int volume));
+extern bool fat_ismounted(int volume);
#endif
diff --git a/firmware/include/dir.h b/firmware/include/dir.h
index 00c6664872..5c157e4696 100644
--- a/firmware/include/dir.h
+++ b/firmware/include/dir.h
@@ -30,6 +30,7 @@
#define ATTR_VOLUME_ID 0x08
#define ATTR_DIRECTORY 0x10
#define ATTR_ARCHIVE 0x20
+#define ATTR_VOLUME 0x40 /* this is a volume, not a real directory */
struct dirent {
unsigned char d_name[MAX_PATH];
@@ -52,6 +53,9 @@ typedef struct {
struct fat_dir fatdir;
struct fat_dir parent_dir;
struct dirent theent;
+#ifdef HAVE_MULTIVOLUME
+ int volumecounter; /* running counter for faked volume entries */
+#endif
} DIR;
#else /* SIMULATOR */
diff --git a/firmware/test/fat/main.c b/firmware/test/fat/main.c
index 5607414bcb..5420199f92 100644
--- a/firmware/test/fat/main.c
+++ b/firmware/test/fat/main.c
@@ -677,7 +677,7 @@ int main(int argc, char *argv[])
#endif
) {
DEBUGF("*** Mounting at block %ld\n",pinfo[i].start);
- rc = fat_mount(pinfo[i].start);
+ rc = fat_mount(IF_MV2(0,) IF_MV2(0,) pinfo[i].start);
if(rc) {
DEBUGF("mount: %d",rc);
return -1;
@@ -686,7 +686,7 @@ int main(int argc, char *argv[])
}
}
if ( i==4 ) {
- if(fat_mount(0)) {
+ if(fat_mount(IF_MV2(0,) IF_MV2(0,) 0)) {
DEBUGF("No FAT32 partition!");
return -1;
}
diff --git a/firmware/test/i2c/main.c b/firmware/test/i2c/main.c
index 34d3dc68e2..4419dde171 100644
--- a/firmware/test/i2c/main.c
+++ b/firmware/test/i2c/main.c
@@ -1,639 +1,1278 @@
/***************************************************************************
+
* __________ __ ___.
+
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
+
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+
* \/ \/ \/ \/ \/
+
* $Id$
+
*
+
* Copyright (C) 2002 by Linus Nielsen Feltzing
+
*
+
* 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 <stdio.h>
+
#include <stdlib.h>
+
#include <stdbool.h>
+
#include <string.h>
+
#include "i2c.h"
+
#include "mas.h"
+
#include "dac.h"
+
#include "sh7034.h"
+
#include "system.h"
+
#include "debug.h"
+
#include "kernel.h"
+
#include "thread.h"
+
#include "ata.h"
+
#include "disk.h"
+
#include "fat.h"
+
#include "file.h"
+
#include "dir.h"
+
#include "panic.h"
+
+
#ifndef MIN
+
#define MIN(a, b) (((a)<(b))?(a):(b))
+
#endif
+
+
#define MPEG_PLAY 1
+
#define MPEG_STOP 2
+
#define MPEG_PAUSE 3
+
#define MPEG_RESUME 4
+
#define MPEG_NEED_DATA 100
+
+
#define MP3_LOW_WATER 0x30000
+
#define MP3_CHUNK_SIZE 0x20000
+
+
unsigned int bass_table[] =
+
{
+
0,
+
0x800, /* 1dB */
+
0x10000, /* 2dB */
+
0x17c00, /* 3dB */
+
0x1f800, /* 4dB */
+
0x27000, /* 5dB */
+
0x2e400, /* 6dB */
+
0x35800, /* 7dB */
+
0x3c000, /* 8dB */
+
0x42800, /* 9dB */
+
0x48800, /* 10dB */
+
0x4e400, /* 11dB */
+
0x53800, /* 12dB */
+
0x58800, /* 13dB */
+
0x5d400, /* 14dB */
+
0x61800 /* 15dB */
+
};
+
+
unsigned int treble_table[] =
+
{
+
0,
+
0x5400, /* 1dB */
+
0xac00, /* 2dB */
+
0x10400, /* 3dB */
+
0x16000, /* 4dB */
+
0x1c000, /* 5dB */
+
0x22400, /* 6dB */
+
0x28400, /* 7dB */
+
0x2ec00, /* 8dB */
+
0x35400, /* 9dB */
+
0x3c000, /* 10dB */
+
0x42c00, /* 11dB */
+
0x49c00, /* 12dB */
+
0x51800, /* 13dB */
+
0x58400, /* 14dB */
+
0x5f800 /* 15dB */
+
};
+
+
unsigned char fliptable[] =
+
{
+
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+
};
+
+
extern unsigned int stack[];
+
/* Place the MP3 data right after the stack */
+
+
#define MP3BUF_LEN 0x100000 /* 1 Mbyte */
+
+
unsigned char *mp3buf = (unsigned char *)stack;
+
+
char *tracks[100];
+
int num_tracks;
+
+
int mp3buf_write;
+
int mp3buf_read;
+
int last_dma_chunk_size;
+
+
bool dma_on; /* The DMA is active */
+
bool playing; /* We are playing an MP3 stream */
+
bool filling; /* We are filling the buffer with data from disk */
+
+
struct event_queue mpeg_queue;
+
+
static void mas_poll_start(unsigned int interval_in_ms);
+
void mpeg_thread(void);
+
+
void reset_mp3_buffer(void)
+
{
+
mp3buf_read = 0;
+
mp3buf_write = 0;
+
}
+
+
void setup_sci0(void)
+
{
+
/* PB15 is I/O, PB14 is IRQ6, PB12 is SCK0 */
+
PBCR1 = (PBCR1 & 0x0cff) | 0x1200;
+
+
/* Set PB12 to output */
+
PBIOR |= 0x1000;
+
+
/* Disable serial port */
+
SCR0 = 0x00;
+
+
/* Synchronous, no prescale */
+
SMR0 = 0x80;
+
+
/* Set baudrate 1Mbit/s */
+
BRR0 = 0x03;
+
+
/* use SCK as serial clock output */
+
SCR0 = 0x01;
+
+
/* Clear FER and PER */
+
SSR0 &= 0xe7;
+
+
/* Set interrupt ITU2 and SCI0 priority to 0 */
+
IPRD &= 0x0ff0;
+
+
/* set IRQ6 and IRQ7 to edge detect */
+
ICR |= 0x03;
+
+
/* set PB15 and PB14 to inputs */
+
PBIOR &= 0x7fff;
+
PBIOR &= 0xbfff;
+
+
/* set IRQ6 prio 8 and IRQ7 prio 0 */
+
IPRB = ( IPRB & 0xff00 ) | 0x0080;
+
+
/* Enable End of DMA interrupt at prio 8 */
+
IPRC = (IPRC & 0xf0ff) | 0x0800;
+
+
/* Enable Tx (only!) */
+
SCR0 |= 0x20;
+
}
+
+
+
void init_dma(void)
+
{
+
SAR3 = (unsigned int) mp3buf + mp3buf_read;
+
DAR3 = 0x5FFFEC3;
+
CHCR3 &= ~0x0002; /* Clear interrupt */
+
CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */
+
last_dma_chunk_size = MIN(65536, mp3buf_write - mp3buf_read);
+
DTCR3 = last_dma_chunk_size & 0xffff;
+
DMAOR = 0x0001; /* Enable DMA */
+
CHCR3 |= 0x0001; /* Enable DMA IRQ */
+
}
+
+
void start_dma(void)
+
{
+
SCR0 |= 0x80;
+
dma_on = true;
+
}
+
+
void stop_dma(void)
+
{
+
SCR0 &= 0x7f;
+
dma_on = false;
+
}
+
+
void dma_tick(void)
+
{
+
/* Start DMA if it isn't running */
+
if(playing && !dma_on)
+
{
+
if(PBDR & 0x4000)
+
{
+
if(!(SCR0 & 0x80))
+
start_dma();
+
}
+
}
+
}
+
+
void bitswap(unsigned char *data, int length)
+
{
+
int i;
+
for(i = 0;i < length;i++)
+
{
+
data[i] = fliptable[data[i]];
+
}
+
}
+
+
int main(void)
+
{
+
char buf[40];
+
char str[32];
+
int i=0;
+
DIR *d;
+
struct dirent *dent;
+
char *tmp;
+
int volume, bass, treble;
+
unsigned short frame_count;
+
+
/* Clear it all! */
+
SSR1 &= ~(SCI_RDRF | SCI_ORER | SCI_PER | SCI_FER);
+
+
/* This enables the serial Rx interrupt, to be able to exit into the
+
debugger when you hit CTRL-C */
+
SCR1 |= 0x40;
+
SCR1 &= ~0x80;
+
+
IPRE |= 0xf000; /* Highest priority */
+
+
i2c_init();
+
+
dma_on = true;
+
+
kernel_init();
+
+
set_irq_level(0);
+
+
setup_sci0();
+
+
i=mas_readmem(MAS_BANK_D1,0xff6,(unsigned long*)buf,2);
+
if (i) {
+
debugf("Error - mas_readmem() returned %d\n", i);
+
while(1);
+
}
+
+
i = buf[0] | buf[1] << 8;
+
debugf("MAS version: %x\n", i);
+
i = buf[4] | buf[5] << 8;
+
debugf("MAS revision: %x\n", i);
+
+
i=mas_readmem(MAS_BANK_D1,0xff9,(unsigned long*)buf,7);
+
if (i) {
+
debugf("Error - mas_readmem() returned %d\n", i);
+
while(1);
+
}
+
+
for(i = 0;i < 7;i++)
+
{
+
str[i*2+1] = buf[i*4];
+
str[i*2] = buf[i*4+1];
+
}
+
str[i*2] = 0;
+
debugf("Description: %s\n", str);
+
+
i=mas_writereg(0x3b, 0x20);
+
if (i < 0) {
+
debugf("Error - mas_writereg() returned %d\n", i);
+
while(1);
+
}
+
+
i = mas_run(1);
+
if (i < 0) {
+
debugf("Error - mas_run() returned %d\n", i);
+
while(1);
+
}
+
+
i = ata_init();
+
debugf("ata_init() returned %d\n", i);
+
+
i = disk_init();
+
debugf("disk_init() returned %d\n", i);
+
+
debugf("part[0] starts at sector %d\n", part[0].start);
+
- i = fat_mount(part[0].start);
+
+ i = fat_mount(IF_MV2(0,) IF_MV2(0,) part[0].start);
+
debugf("fat_mount() returned %d\n", i);
+
+
num_tracks = 0;
+
if((d = opendir("/")))
+
{
+
while((dent = readdir(d)))
+
{
+
debugf("%s\n", dent->d_name);
+
i = strlen(dent->d_name);
+
tmp = dent->d_name + i - 4;
+
debugf("%s\n", tmp);
+
if(!stricmp(tmp, ".mp3"))
+
{
+
tmp = malloc(i+1);
+
if(tmp)
+
{
+
debugf("Adding track %s\n", dent->d_name);
+
snprintf(tmp, i+1, "/%s", dent->d_name);
+
tracks[num_tracks++] = tmp;
+
}
+
else
+
{
+
panicf("Out of memory\n");
+
}
+
}
+
}
+
closedir(d);
+
}
+
+
debugf("Number of tracks: %d\n");
+
+
queue_init(&mpeg_queue);
+
+
create_thread(mpeg_thread, stack - 0x2000, 0x4000);
+
+
mas_poll_start(2);
+
+
debugf("let's play...\n");
+
+
queue_post(&mpeg_queue, MPEG_PLAY, 0);
+
+
volume = 0x2c;
+
+
if(dac_config(0x04) < 0)
+
debugf("DAC write failed\n");
+
+
if(dac_volume(volume) < 0)
+
debugf("DAC write failed\n");
+
+
bass = 12;
+
treble = 8;
+
+
mas_writereg(MAS_REG_KPRESCALE, 0xe9400);
+
mas_writereg(MAS_REG_KBASS, bass_table[bass]);
+
mas_writereg(MAS_REG_KTREBLE, treble_table[treble]);
+
+
while(1)
+
{
+
sleep(HZ*4);
+
}
+
}
+
+
#pragma interrupt
+
void IRQ6(void)
+
{
+
stop_dma();
+
}
+
+
#pragma interrupt
+
void DEI3(void)
+
{
+
int unplayed_space_left;
+
int space_until_end_of_buffer;
+
+
if(playing)
+
{
+
mp3buf_read += last_dma_chunk_size;
+
if(mp3buf_read >= MP3BUF_LEN)
+
mp3buf_read = 0;
+
+
unplayed_space_left = mp3buf_write - mp3buf_read;
+
if(unplayed_space_left < 0)
+
unplayed_space_left = MP3BUF_LEN + unplayed_space_left;
+
+
space_until_end_of_buffer = MP3BUF_LEN - mp3buf_read;
+
+
if(!filling && unplayed_space_left < MP3_LOW_WATER)
+
{
+
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
+
}
+
+
if(unplayed_space_left)
+
{
+
last_dma_chunk_size = MIN(65536, unplayed_space_left);
+
last_dma_chunk_size = MIN(last_dma_chunk_size, space_until_end_of_buffer);
+
DTCR3 = last_dma_chunk_size & 0xffff;
+
SAR3 = (unsigned int)mp3buf + mp3buf_read;
+
}
+
else
+
{
+
debugf("No more MP3 data. Stopping.\n");
+
CHCR3 = 0; /* Stop DMA interrupt */
+
}
+
}
+
+
CHCR3 &= ~0x0002; /* Clear DMA interrupt */
+
}
+
+
static void mas_poll_start(unsigned int interval_in_ms)
+
{
+
unsigned int count;
+
+
count = FREQ / 1000 / 8 * interval_in_ms;
+
+
if(count > 0xffff)
+
{
+
panicf("Error! The MAS poll interval is too long (%d ms)\n",
+
interval_in_ms);
+
return;
+
}
+
+
/* We are using timer 1 */
+
+
TSTR &= ~0x02; /* Stop the timer */
+
TSNC &= ~0x02; /* No synchronization */
+
TMDR &= ~0x02; /* Operate normally */
+
+
TCNT1 = 0; /* Start counting at 0 */
+
GRA1 = count;
+
TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
+
+
/* Enable interrupt on level 2 */
+
IPRC = (IPRC & ~0x000f) | 0x0002;
+
+
TSR1 &= ~0x02;
+
TIER1 = 0xf9; /* Enable GRA match interrupt */
+
+
TSTR |= 0x02; /* Start timer 2 */
+
}
+
+
#pragma interrupt
+
void IMIA1(void)
+
{
+
dma_tick();
+
TSR1 &= ~0x01;
+
}
+
+
int track_index = 0;
+
char *peek_next_track(int index)
+
{
+
if(track_index < num_tracks)
+
return tracks[track_index+index];
+
else
+
return NULL;
+
}
+
+
void next_track(void)
+
{
+
track_index++;
+
}
+
+
int mpeg_file = -1;
+
+
int new_file(void)
+
{
+
char *trackname;
+
+
trackname = peek_next_track(0);
+
+
debugf("playing %s\n", trackname);
+
mpeg_file = open(trackname, O_RDONLY);
+
if(mpeg_file < 0)
+
{
+
debugf("Couldn't open file\n");
+
return -1;
+
}
+
return 0;
+
}
+
+
void mpeg_thread(void)
+
{
+
struct event ev;
+
int len;
+
int free_space_left;
+
int amount_to_read;
+
bool play_pending;
+
+
play_pending = false;
+
playing = false;
+
+
while(1)
+
{
+
debugf("S\n");
+
queue_wait(&mpeg_queue, &ev);
+
switch(ev.id)
+
{
+
case MPEG_PLAY:
+
/* Stop the current stream */
+
play_pending = false;
+
playing = false;
+
stop_dma();
+
+
reset_mp3_buffer();
+
+
new_file();
+
+
/* Make it read more data */
+
filling = true;
+
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
+
+
/* Tell the file loading code that we want to start playing
+
as soon as we have some data */
+
play_pending = true;
+
break;
+
+
case MPEG_STOP:
+
/* Stop the current stream */
+
playing = false;
+
stop_dma();
+
break;
+
+
case MPEG_PAUSE:
+
/* Stop the current stream */
+
playing = false;
+
stop_dma();
+
break;
+
+
case MPEG_RESUME:
+
/* Stop the current stream */
+
playing = true;
+
start_dma();
+
break;
+
+
case MPEG_NEED_DATA:
+
free_space_left = mp3buf_read - mp3buf_write;
+
+
/* We interpret 0 as "empty buffer" */
+
if(free_space_left <= 0)
+
free_space_left = MP3BUF_LEN + free_space_left;
+
+
if(free_space_left <= MP3_CHUNK_SIZE)
+
{
+
debugf("0\n");
+
ata_spindown(-1);
+
filling = false;
+
break;;
+
}
+
+
amount_to_read = MIN(MP3_CHUNK_SIZE, free_space_left);
+
amount_to_read = MIN(MP3BUF_LEN - mp3buf_write, amount_to_read);
+
+
/* Read in a few seconds worth of MP3 data. We don't want to
+
read too large chunks because the bitswapping will take
+
too much time. We must keep the DMA happy and also give
+
the other threads a chance to run. */
+
debugf("R\n");
+
len = read(mpeg_file, mp3buf+mp3buf_write, amount_to_read);
+
if(len)
+
{
+
debugf("B\n");
+
bitswap(mp3buf + mp3buf_write, len);
+
+
mp3buf_write += len;
+
if(mp3buf_write >= MP3BUF_LEN)
+
{
+
mp3buf_write = 0;
+
debugf("W\n");
+
}
+
+
/* Tell ourselves that we want more data */
+
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
+
+
/* And while we're at it, see if we have startet playing
+
yet. If not, do it. */
+
if(play_pending)
+
{
+
play_pending = false;
+
playing = true;
+
+
init_dma();
+
start_dma();
+
}
+
}
+
else
+
{
+
close(mpeg_file);
+
+
/* Make sure that the write pointer is at a word
+
boundary */
+
mp3buf_write &= 0xfffffffe;
+
+
next_track();
+
if(new_file() < 0)
+
{
+
/* No more data to play */
+
debugf("Finished playing\n");
+
playing = false;
+
ata_spindown(-1);
+
filling = false;
+
}
+
else
+
{
+
/* Tell ourselves that we want more data */
+
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
+
}
+
}
+
break;
+
}
+
}
+
}
+
+
/* Newlib trap honeypot */
+
void __trap34(void)
+
{
+
debugf("newlib trap34\n");
+
while(1);
+
}
+
diff --git a/firmware/usb.c b/firmware/usb.c
index e27c003154..ab8e080c45 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -157,17 +157,38 @@ static void usb_slave_mode(bool on)
panicf("ata: %d",rc);
}
- pinfo = disk_init();
+ pinfo = disk_init(IF_MV(0));
if (!pinfo)
panicf("disk: NULL");
+ fat_init();
for ( i=0; i<4; i++ ) {
- rc = fat_mount(pinfo[i].start);
+ rc = fat_mount(IF_MV2(0,) IF_MV2(0,) pinfo[i].start);
if (!rc)
- break;
+ break; /* only one partition gets mounted as of now */
}
if (i==4)
panicf("mount: %d",rc);
+#ifdef HAVE_MULTIVOLUME
+ /* mount partition on the optional volume */
+#ifdef HAVE_MMC
+ if (mmc_detect()) /* for Ondio, only if card detected */
+#endif
+ {
+ pinfo = disk_init(1);
+ if (pinfo)
+ {
+ for ( i=0; i<4; i++ ) {
+ if (!fat_mount(1, 1, pinfo[i].start))
+ break; /* only one partition gets mounted as of now */
+ }
+
+ if ( i==4 ) {
+ rc = fat_mount(1, 1, 0);
+ }
+ }
+ }
+#endif /* #ifdef HAVE_MULTIVOLUME */
}
}