summaryrefslogtreecommitdiff
path: root/firmware/common/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/common/disk.c')
-rw-r--r--firmware/common/disk.c451
1 files changed, 297 insertions, 154 deletions
diff --git a/firmware/common/disk.c b/firmware/common/disk.c
index 5a55a3b6ac..3a2d27e0d7 100644
--- a/firmware/common/disk.c
+++ b/firmware/common/disk.c
@@ -19,14 +19,25 @@
*
****************************************************************************/
#include <stdio.h>
+#include <string.h>
+#include "config.h"
#include "kernel.h"
#include "storage.h"
#include "debug.h"
-#include "fat.h"
-#include "dir.h" /* for release_dirs() */
-#include "file.h" /* for release_files() */
+#include "disk_cache.h"
+#include "fileobj_mgr.h"
+#include "dir.h"
+#include "dircache_redirect.h"
#include "disk.h"
-#include <string.h>
+
+#ifndef CONFIG_DEFAULT_PARTNUM
+#define CONFIG_DEFAULT_PARTNUM 0
+#endif
+
+#define disk_reader_lock() file_internal_lock_READER()
+#define disk_reader_unlock() file_internal_unlock_READER()
+#define disk_writer_lock() file_internal_lock_WRITER()
+#define disk_writer_unlock() file_internal_unlock_WRITER()
/* Partition table entry layout:
-----------------------
@@ -42,11 +53,18 @@
12-15: nr of sectors in partition
*/
-#define BYTES2INT32(array,pos) \
- ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
- ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
+#define BYTES2INT32(array, pos) \
+ (((uint32_t)array[pos+0] << 0) | \
+ ((uint32_t)array[pos+1] << 8) | \
+ ((uint32_t)array[pos+2] << 16) | \
+ ((uint32_t)array[pos+3] << 24))
+
+#define BYTES2INT16(array, pos) \
+ (((uint32_t)array[pos+0] << 0) | \
+ ((uint32_t)array[pos+1] << 8))
-static const unsigned char fat_partition_types[] = {
+static const unsigned char fat_partition_types[] =
+{
0x0b, 0x1b, /* FAT32 + hidden variant */
0x0c, 0x1c, /* FAT32 (LBA) + hidden variant */
#ifdef HAVE_FAT16SUPPORT
@@ -56,159 +74,135 @@ static const unsigned char fat_partition_types[] = {
#endif
};
-static struct partinfo part[NUM_DRIVES*4]; /* space for 4 partitions on 2 drives */
-static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */
-static struct mutex disk_mutex;
+/* space for 4 partitions on 2 drives */
+static struct partinfo part[NUM_DRIVES*4];
+/* mounted to which drive (-1 if none) */
+static int vol_drive[NUM_VOLUMES];
+
+static int get_free_volume(void)
+{
+ for (int i = 0; i < NUM_VOLUMES; i++)
+ {
+ if (vol_drive[i] == -1) /* unassigned? */
+ return i;
+ }
+
+ return -1; /* none found */
+}
#ifdef MAX_LOG_SECTOR_SIZE
-static int disk_sector_multiplier[NUM_DRIVES] = {[0 ... NUM_DRIVES-1] = 1};
+static int disk_sector_multiplier[NUM_DRIVES] =
+ { [0 ... NUM_DRIVES-1] = 1 };
int disk_get_sector_multiplier(IF_MD_NONVOID(int drive))
{
- #ifdef HAVE_MULTIDRIVE
- return disk_sector_multiplier[drive];
- #else
- return disk_sector_multiplier[0];
- #endif
+ if (!CHECK_DRV(drive))
+ return 0;
+
+ disk_reader_lock();
+ int multiplier = disk_sector_multiplier[IF_MD_DRV(drive)];
+ disk_reader_unlock();
+ return multiplier;
}
-#endif
+#endif /* MAX_LOG_SECTOR_SIZE */
-struct partinfo* disk_init(IF_MD_NONVOID(int drive))
+bool disk_init(IF_MD_NONVOID(int drive))
{
- int i;
-#ifdef HAVE_MULTIDRIVE
- /* 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;
- const int drive = 0;
- (void)drive;
-#endif
+ if (!CHECK_DRV(drive))
+ return false; /* out of space in table */
- unsigned char* sector = fat_get_sector_buffer();
- storage_read_sectors(IF_MD(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;
- }
+ unsigned char *sector = dc_get_buffer();
+ if (!sector)
+ return false;
- /* parse partitions */
- for ( i=0; i<4; i++ ) {
- unsigned char* ptr = sector + 0x1be + 16*i;
- pinfo[i].type = ptr[4];
- pinfo[i].start = BYTES2INT32(ptr, 8);
- pinfo[i].size = BYTES2INT32(ptr, 12);
+ memset(sector, 0, SECTOR_SIZE);
+ storage_read_sectors(IF_MD(drive,) 0, 1, sector);
- DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n",
- i,pinfo[i].type,pinfo[i].start,pinfo[i].size);
+ bool init = false;
- /* extended? */
- if ( pinfo[i].type == 5 ) {
- /* not handled yet */
- }
- }
- fat_release_sector_buffer();
- return pinfo;
-}
+ /* check that the boot sector is initialized */
+ if (BYTES2INT16(sector, 510) == 0xaa55)
+ {
+ /* 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[IF_MD_DRV(drive)*4];
-struct partinfo* disk_partinfo(int partition)
-{
- return &part[partition];
-}
+ disk_writer_lock();
-void disk_init_subsystem(void)
-{
- mutex_init(&disk_mutex);
-}
+ /* parse partitions */
+ for (int i = 0; i < 4; i++)
+ {
+ unsigned char* ptr = sector + 0x1be + 16*i;
+ pinfo[i].type = ptr[4];
+ pinfo[i].start = BYTES2INT32(ptr, 8);
+ pinfo[i].size = BYTES2INT32(ptr, 12);
-int disk_mount_all(void)
-{
- int mounted=0;
- int i;
-
-#ifdef HAVE_HOTSWAP
- mutex_lock(&disk_mutex);
-#endif
+ DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n",
+ i,pinfo[i].type,pinfo[i].start,pinfo[i].size);
- fat_init(); /* reset all mounted partitions */
- for (i=0; i<NUM_VOLUMES; i++)
- vol_drive[i] = -1; /* mark all as unassigned */
+ /* extended? */
+ if ( pinfo[i].type == 5 )
+ {
+ /* not handled yet */
+ }
+ }
-#ifndef HAVE_MULTIDRIVE
- mounted = disk_mount(0);
-#else
- for(i=0;i<NUM_DRIVES;i++)
+ disk_writer_unlock();
+
+ init = true;
+ }
+ else
{
-#ifdef HAVE_HOTSWAP
- if (storage_present(i))
-#endif
- mounted += disk_mount(i);
+ DEBUGF("Bad boot sector signature\n");
}
-#endif
-#ifdef HAVE_HOTSWAP
- mutex_unlock(&disk_mutex);
-#endif
- return mounted;
+ dc_release_buffer(sector);
+ return init;
}
-static int get_free_volume(void)
+bool disk_partinfo(int partition, struct partinfo *info)
{
- int i;
- for (i=0; i<NUM_VOLUMES; i++)
- {
- if (vol_drive[i] == -1) /* unassigned? */
- return i;
- }
+ if (partition < 0 || partition >= (int)ARRAYLEN(part) || !info)
+ return false;
- return -1; /* none found */
+ disk_reader_lock();
+ *info = part[partition];
+ disk_reader_unlock();
+ return true;
}
int disk_mount(int drive)
{
int mounted = 0; /* reset partition-on-drive flag */
- int volume;
- struct partinfo* pinfo;
-#ifdef HAVE_HOTSWAP
- mutex_lock(&disk_mutex);
-#endif
+ disk_writer_lock();
- volume = get_free_volume();
- pinfo = disk_init(IF_MD(drive));
-#ifdef MAX_LOG_SECTOR_SIZE
- disk_sector_multiplier[drive] = 1;
-#endif
+ int volume = get_free_volume();
- if (pinfo == NULL)
+ if (!disk_init(IF_MD(drive)))
{
-#ifdef HAVE_HOTSWAP
- mutex_unlock(&disk_mutex);
-#endif
+ disk_writer_unlock();
return 0;
}
-#if defined(TOSHIBA_GIGABEAT_S)
- int i = 1; /* For the Gigabeat S, we mount the second partition */
-#else
- int i = 0;
+
+ struct partinfo *pinfo = &part[IF_MD_DRV(drive)*4];
+#ifdef MAX_LOG_SECTOR_SIZE
+ disk_sector_multiplier[IF_MD_DRV(drive)] = 1;
#endif
- for (; volume != -1 && i<4 && mounted<NUM_VOLUMES_PER_DRIVE; i++)
+
+ for (int i = CONFIG_DEFAULT_PARTNUM;
+ volume != -1 && i < 4 && mounted < NUM_VOLUMES_PER_DRIVE;
+ i++)
{
if (memchr(fat_partition_types, pinfo[i].type,
sizeof(fat_partition_types)) == NULL)
continue; /* not an accepted partition type */
-#ifdef MAX_LOG_SECTOR_SIZE
- int j;
-
- for (j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1)
+ bool success = false;
+
+ #ifdef MAX_LOG_SECTOR_SIZE
+ for (int j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1)
{
if (!fat_mount(IF_MV(volume,) IF_MD(drive,) pinfo[i].start * j))
{
@@ -218,93 +212,242 @@ int disk_mount(int drive)
vol_drive[volume] = drive; /* remember the drive for this volume */
volume = get_free_volume(); /* prepare next entry */
disk_sector_multiplier[drive] = j;
+ success = true;
break;
}
}
-#else
+ #else /* ndef MAX_LOG_SECTOR_SIZE */
if (!fat_mount(IF_MV(volume,) IF_MD(drive,) pinfo[i].start))
{
mounted++;
vol_drive[volume] = drive; /* remember the drive for this volume */
volume = get_free_volume(); /* prepare next entry */
+ success = true;
}
-#endif
+ #endif /* MAX_LOG_SECTOR_SIZE */
+
+ if (success)
+ volume_onmount_internal(IF_MV(volume));
}
if (mounted == 0 && volume != -1) /* none of the 4 entries worked? */
{ /* try "superfloppy" mode */
DEBUGF("No partition found, trying to mount sector 0.\n");
+
if (!fat_mount(IF_MV(volume,) IF_MD(drive,) 0))
{
-#ifdef MAX_LOG_SECTOR_SIZE
- disk_sector_multiplier[drive] = fat_get_bytes_per_sector(IF_MV(volume))/SECTOR_SIZE;
-#endif
+ #ifdef MAX_LOG_SECTOR_SIZE
+ disk_sector_multiplier[drive] =
+ fat_get_bytes_per_sector(IF_MV(volume)) / SECTOR_SIZE;
+ #endif
mounted = 1;
vol_drive[volume] = drive; /* remember the drive for this volume */
+ volume_onmount_internal(IF_MV(volume));
}
}
-#ifdef HAVE_HOTSWAP
- mutex_unlock(&disk_mutex);
-#endif
+
+ disk_writer_unlock();
+ return mounted;
+}
+
+int disk_mount_all(void)
+{
+ int mounted = 0;
+
+ disk_writer_lock();
+
+ /* reset all mounted partitions */
+ volume_onunmount_internal(IF_MV(-1));
+ fat_init();
+
+ for (int i = 0; i < NUM_VOLUMES; i++)
+ vol_drive[i] = -1; /* mark all as unassigned */
+
+ for (int i = 0; i < NUM_DRIVES; i++)
+ {
+ #ifdef HAVE_HOTSWAP
+ if (storage_present(i))
+ #endif
+ mounted += disk_mount(i);
+ }
+
+ disk_writer_unlock();
return mounted;
}
int disk_unmount(int drive)
{
+ if (!CHECK_DRV(drive))
+ return 0;
+
int unmounted = 0;
- int i;
-#ifdef HAVE_HOTSWAP
- mutex_lock(&disk_mutex);
-#endif
- for (i=0; i<NUM_VOLUMES; i++)
+
+ disk_writer_lock();
+
+ for (int i = 0; i < NUM_VOLUMES; i++)
{
if (vol_drive[i] == drive)
{ /* force releasing resources */
vol_drive[i] = -1; /* mark unused */
+
+ volume_onunmount_internal(IF_MV(i));
+ fat_unmount(IF_MV(i));
+
unmounted++;
- release_files(i);
- release_dirs(i);
- fat_unmount(i, false);
}
}
-#ifdef HAVE_HOTSWAP
- mutex_unlock(&disk_mutex);
-#endif
+ disk_writer_unlock();
return unmounted;
}
int disk_unmount_all(void)
{
-#ifndef HAVE_MULTIDRIVE
- return disk_unmount(0);
-#else /* HAVE_MULTIDRIVE */
int unmounted = 0;
- int i;
- for (i = 0; i < NUM_DRIVES; i++)
+
+ disk_writer_lock();
+
+ volume_onunmount_internal(IF_MV(-1));
+
+ for (int i = 0; i < NUM_DRIVES; i++)
{
-#ifdef HAVE_HOTSWAP
+ #ifdef HAVE_HOTSWAP
if (storage_present(i))
-#endif
+ #endif
unmounted += disk_unmount(i);
}
+ disk_writer_unlock();
return unmounted;
-#endif /* HAVE_MULTIDRIVE */
+}
+
+bool disk_present(IF_MD_NONVOID(int drive))
+{
+ int rc = -1;
+
+ if (CHECK_DRV(drive))
+ {
+ void *sector = dc_get_buffer();
+ if (sector)
+ {
+ rc = storage_read_sectors(IF_MD(drive,) 0, 1, sector);
+ dc_release_buffer(sector);
+ }
+ }
+
+ return rc == 0;
+}
+
+
+/** Volume-centric functions **/
+
+void volume_recalc_free(IF_MV_NONVOID(int volume))
+{
+ if (!CHECK_VOL(volume))
+ return;
+
+ /* FIXME: this is crummy but the only way to ensure a correct freecount
+ if other threads are writing and changing the fsinfo; it is possible
+ to get multiple threads calling here and also writing and get correct
+ freespace counts, however a bit complicated to do; if thou desireth I
+ shall implement the concurrent version -- jethead71 */
+ disk_writer_lock();
+ fat_recalc_free(IF_MV(volume));
+ disk_writer_unlock();
+}
+
+unsigned int volume_get_cluster_size(IF_MV_NONVOID(int volume))
+{
+ if (!CHECK_VOL(volume))
+ return 0;
+
+ disk_reader_lock();
+ unsigned int clustersize = fat_get_cluster_size(IF_MV(volume));
+ disk_reader_unlock();
+ return clustersize;
+}
+
+void volume_size(IF_MV(int volume,) unsigned long *sizep, unsigned long *freep)
+{
+ disk_reader_lock();
+
+ if (!CHECK_VOL(volume) || !fat_size(IF_MV(volume,) sizep, freep))
+ {
+ if (freep) *sizep = 0;
+ if (freep) *freep = 0;
+ }
+
+ disk_reader_unlock();
+}
+
+#if defined (HAVE_HOTSWAP) || defined (HAVE_MULTIDRIVE) \
+ || defined (HAVE_DIRCACHE)
+enum volume_info_type
+{
+#ifdef HAVE_HOTSWAP
+ VP_REMOVABLE,
+ VP_PRESENT,
+#endif
+#if defined (HAVE_MULTIDRIVE) || defined (HAVE_DIRCACHE)
+ VP_DRIVE,
+#endif
+};
+
+static int volume_properties(int volume, enum volume_info_type infotype)
+{
+ int res = -1;
+
+ disk_reader_lock();
+
+ if (CHECK_VOL(volume))
+ {
+ int vd = vol_drive[volume];
+ switch (infotype)
+ {
+ #ifdef HAVE_HOTSWAP
+ case VP_REMOVABLE:
+ res = storage_removable(vd) ? 1 : 0;
+ break;
+ case VP_PRESENT:
+ res = storage_present(vd) ? 1 : 0;
+ break;
+ #endif
+ #if defined(HAVE_MULTIDRIVE) || defined(HAVE_DIRCACHE)
+ case VP_DRIVE:
+ res = vd;
+ break;
+ #endif
+ }
+ }
+
+ disk_reader_unlock();
+ return res;
}
#ifdef HAVE_HOTSWAP
bool volume_removable(int volume)
{
- if(vol_drive[volume] == -1)
- return false;
- return storage_removable(vol_drive[volume]);
+ return volume_properties(volume, VP_REMOVABLE) > 0;
}
bool volume_present(int volume)
{
- if(vol_drive[volume] == -1)
- return false;
- return storage_present(vol_drive[volume]);
+ return volume_properties(volume, VP_PRESENT) > 0;
}
-#endif
+#endif /* HAVE_HOTSWAP */
+
+#ifdef HAVE_MULTIDRIVE
+int volume_drive(int volume)
+{
+ return volume_properties(volume, VP_DRIVE);
+}
+#endif /* HAVE_MULTIDRIVE */
+
+#ifdef HAVE_DIRCACHE
+bool volume_ismounted(IF_MV_NONVOID(int volume))
+{
+ return volume_properties(IF_MV_VOL(volume), VP_DRIVE) >= 0;
+}
+#endif /* HAVE_DIRCACHE */
+
+#endif /* HAVE_HOTSWAP || HAVE_MULTIDRIVE || HAVE_DIRCACHE */