summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/test/fat/fat-bpb_sector.h211
-rw-r--r--firmware/test/fat/fat-fsi_sector.c105
-rw-r--r--firmware/test/fat/fat-fsi_sector.h80
-rw-r--r--firmware/test/fat/fat-mbr_sector.c65
-rw-r--r--firmware/test/fat/fat-mbr_sector.h69
-rw-r--r--firmware/test/fat/fat-partition.h161
-rw-r--r--firmware/test/fat/fat-volume.c355
-rw-r--r--firmware/test/fat/inlines.h1
-rw-r--r--firmware/test/fat/makefile19
-rw-r--r--firmware/test/fat/return_values.h7
-rw-r--r--firmware/test/fat/types.h19
11 files changed, 1083 insertions, 9 deletions
diff --git a/firmware/test/fat/fat-bpb_sector.h b/firmware/test/fat/fat-bpb_sector.h
new file mode 100644
index 0000000000..247f53115c
--- /dev/null
+++ b/firmware/test/fat/fat-bpb_sector.h
@@ -0,0 +1,211 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __LIBRARY_FAT_BPB_SECTOR_H__
+#define __LIBRARY_FAT_BPB_SECTOR_H__
+
+// [Alan]:
+// I would like to draw your attention about the fact that SH1
+// cannot use misaligned address access so you must be very cautious
+// with structures stored in FAT32 partition because they come from
+// PC world where misaligned address accesses are usual and not
+// problematic. To avoid such a trouble, I decide to use special
+// structures where fields are moved in such a way they can be
+// accessed by SH1. It is possible thanks to the callback mechanism
+// I use for reading or writing from/to an ATA device in ata.h/c.
+// So don't be puzzled if those structures seem odd compared
+// with the usual ones from PC world. I use this mechanism for structures
+// 'partition_info', 'mbr_sector' and 'fsi_sector' for instance, but
+// not for structure 'bpb_sector' which is too much complex to handle
+// that way, I think.
+// By the way, SH1 is big endian, not little endian as PC is.
+
+///////////////////////////////////////////////////////////////////////////////////
+// BPB SECTOR :
+///////////////
+//
+//
+
+struct __fat_bpb_sector /* Bios Parameters Block Sector */
+ {
+ // jmp_boot has two valid ways to look like in a FAT BPB.
+ // Either EBXX90 or E9XXXX.
+ // Not used by Rockbox.
+ unsigned char
+ jmp_boot[3];
+
+ // Creator system of the fat-drive.
+ // Usually looks like "MSWIN4.x".
+ char
+ oem_name[8];
+
+ // It should be 512 if you don't want any trouble
+ // with Rockbox firmware.
+ unsigned char
+ bytes_per_sector[2];
+
+ // Must be a power of two.
+ unsigned char
+ sectors_per_cluster[1];
+
+ // Number of reserved sectors in the reserved region of the volume
+ // starting at the first sector of the volume.
+ // Usually 32 for FAT32.
+ unsigned char
+ reserved_sectors[2];
+
+ // Number of FAT structures.
+ // This value should always be 2.
+ unsigned char
+ number_of_fats[1];
+
+ // For FAT32, this field must be set to zero.
+ // Not used by Rockbox.
+ unsigned char
+ number_of_root_entries[2];
+
+ // Must be zero for FAT32, since the real value
+ // can be found in total_sectors.
+ // Not used by Rockbox.
+ unsigned char
+ total_sectors_16[2];
+
+ // Not used by Rockbox.
+ unsigned char
+ media[1];
+
+ // In FAT32 this must be zero.
+ // Not used by Rockbox.
+ unsigned char
+ sectors_per_fat_16[2];
+
+ // Sectors per track used on this media.
+ // Not used by Rockbox.
+ unsigned char
+ sectors_per_track[2];
+
+ // Number of heads used on this media.
+ // Not used by Rockbox.
+ unsigned char
+ number_of_heads[2];
+
+ // Number of hidden sectors.
+ // Not used by Rockbox.
+ unsigned char
+ hidden_sectors[4];
+
+ // Number of total sectors.
+ // For FAT32 volumes, this must be specified.
+ unsigned char
+ total_sectors[4];
+
+ // Here follows FAT12/16 or FAT32 specific data. */
+
+ // This is the number of sectors for one FAT.
+ unsigned char
+ sectors_per_fat[4];
+
+ // Extended FAT32 flags follow.
+ unsigned char
+ flags[2];
+ // bits 15-8: reserved
+ // mirroring, bit 7:
+ // 0 -> FAT is mirrored at runtime into all FATs.
+ // 1 -> only the one specified in the following field
+ // is active.
+ // Rockbox always sets it.
+ // bits 7-4 : reserved
+ // active_fat, bits 3-0:
+ // this specifies the "active" FAT mentioned previously.
+
+ // This specifies the file system version.
+ // High byte is major number, low byte is minor.
+ // The current version is 0.0.
+ unsigned char
+ filesystem_version[2];
+
+ // This is set to the cluster number of the first cluster
+ // of the root directory. Usually 2, but not required.
+ unsigned char
+ root_cluster[4];
+
+ // This specifies the sector number of the 'FSINFO' structure
+ // in the reserved area.
+ unsigned char
+ filesystem_info[2];
+
+ // If zero, this specifies where the backup of bpb
+ // can be found.
+ // Usually 6.
+ // No value other than 6 is recommended by Microsoft.
+ unsigned char
+ backup_bpb[2];
+
+ // The following area should always be set to zero
+ // when the volume is initialised.
+ unsigned char
+ zeros[12];
+
+ // Drive number for BIOS.
+ // Not used by Rockbox.
+ unsigned char
+ drive_number[0];
+
+ // Reserved for Windows NT.
+ // Should always be set to 0.
+ unsigned char
+ reserved_for_nt[0];
+
+ // Extended boot signature.
+ // If this is 0x29, the following three fields are present.
+ unsigned char
+ boot_signature[0];
+
+ // Volume serial number.
+ unsigned char
+ volume_id[4];
+
+ // Volume label.
+ // This field must be updated when the volume label
+ // in the root directory is updated.
+ char
+ volume_label[11];
+
+ // One of the strings "FAT12", "FAT16" or "FAT32".
+ // This can not be used to determine the type of the FAT,
+ // but it should be updated when creating file systems.
+ char
+ filesystem_type[8];
+
+ char
+ reserved[420];
+
+ long
+ signature;
+ };
+
+static inline int __fat_get_bpb_sector (unsigned long partition_start,unsigned long lba,struct __fat_bpb_sector *bpb_sector)
+ { return ata_read_sectors (partition_start + lba,1,bpb_sector,0); }
+
+static inline int __fat_put_bpb_sector (unsigned long partition_start,unsigned long lba,struct __fat_bpb_sector *bpb_sector)
+ { return FAT_RETURN_SUCCESS && ata_write_sectors (partition_start + lba,1,bpb_sector,0); }
+
+//
+///////////////////////////////////////////////////////////////////////////////////
+
+#endif \ No newline at end of file
diff --git a/firmware/test/fat/fat-fsi_sector.c b/firmware/test/fat/fat-fsi_sector.c
new file mode 100644
index 0000000000..54863dc2a4
--- /dev/null
+++ b/firmware/test/fat/fat-fsi_sector.c
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * 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 <fat.h>
+#include "fat-fsi_sector.h"
+
+// [Alan]:
+// I would like to draw your attention about the fact that SH1
+// cannot use misaligned address access so you must be very cautious
+// with structures stored in FAT32 partition because they come from
+// PC world where misaligned address accesses are usual and not
+// problematic. To avoid such a trouble, I decide to use special
+// structures where fields are moved in such a way they can be
+// accessed by SH1. It is possible thanks to the callback mechanism
+// I use for reading or writing from/to an ATA device in ata.h/c.
+// So don't be puzzled if those structures seem odd compared
+// with the usual ones from PC world. I use this mechanism for structures
+// 'partition_info', 'mbr_sector' and 'fsi_sector' for instance, but
+// not for structure 'bpb_sector' which is too much complex to handle
+// that way, I think.
+// By the way, SH1 is big endian, not little endian as PC is.
+
+///////////////////////////////////////////////////////////////////////////////////
+// FSI SECTOR :
+///////////////
+//
+//
+
+int __fat_get_fsi_sector_callback (struct __fat_fsi_sector *fsi_sector)
+ {
+ short *data = fsi_sector->data,*end;
+ union { unsigned long si[2]; unsigned short hi[4]; unsigned char qi[8]; } words;
+ for (end = fsi_sector->end0; data < end; ++data)
+ *data = ata_get_word (0);
+#ifdef __little__
+ words.hi[0] = ata_get_word (0);
+ words.hi[1] = ata_get_word (0);
+ words.hi[2] = ata_get_word (0);
+ words.hi[3] = ata_get_word (0);
+#else
+ words.hi[1] = ata_get_word (0);
+ words.hi[0] = ata_get_word (0);
+ words.hi[3] = ata_get_word (0);
+ words.hi[2] = ata_get_word (0);
+#endif
+ for (end = fsi_sector->end1; data < end; ++data)
+ *data = ata_get_word (0);
+#ifdef __little__
+ fsi_sector->left_free_clusters = words.si[0];
+ fsi_sector->next_free_cluster = words.si[1];
+#else
+ fsi_sector->left_free_clusters = swawSI (words.si[0]);
+ fsi_sector->next_free_cluster = swawSI (words.si[1]);
+#endif
+ return ATA_RETURN_SUCCESS;
+ }
+
+int __fat_put_fsi_sector_callback (struct __fat_fsi_sector *fsi_sector)
+ {
+ short *data = fsi_sector->data,*end;
+ union { unsigned long si[2]; unsigned short hi[4]; unsigned char qi[8]; } words;
+#ifdef __little__
+ words.si[0] = swawSI (fsi_sector->left_free_clusters);
+ words.si[1] = swawSI (fsi_sector->next_free_cluster);
+#else
+ words.si[0] = swawSI (fsi_sector->left_free_clusters);
+ words.si[1] = swawSI (fsi_sector->next_free_cluster);
+#endif
+ for (end = fsi_sector->end0; data < end;)
+ ata_put_word (*data++);
+#ifdef __little__
+ ata_put_word (words.hi[0],0);
+ ata_put_word (words.hi[1],0);
+ ata_put_word (words.hi[2],0);
+ ata_put_word (words.hi[3],0);
+#else
+ ata_put_word (words.hi[1],0);
+ ata_put_word (words.hi[0],0);
+ ata_put_word (words.hi[3],0);
+ ata_put_word (words.hi[2],0);
+#endif
+ for (end = fsi_sector->end1; data < end;)
+ ata_put_word (*data++);
+ return ATA_RETURN_SUCCESS;
+ }
+
+//
+///////////////////////////////////////////////////////////////////////////////////
+
+#endif \ No newline at end of file
diff --git a/firmware/test/fat/fat-fsi_sector.h b/firmware/test/fat/fat-fsi_sector.h
new file mode 100644
index 0000000000..c329148bfa
--- /dev/null
+++ b/firmware/test/fat/fat-fsi_sector.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __LIBRARY_FAT_FSI_SECTOR_H__
+#define __LIBRARY_FAT_FSI_SECTOR_H__
+
+// [Alan]:
+// I would like to draw your attention about the fact that SH1
+// cannot use misaligned address access so you must be very cautious
+// with structures stored in FAT32 partition because they come from
+// PC world where misaligned address accesses are usual and not
+// problematic. To avoid such a trouble, I decide to use special
+// structures where fields are moved in such a way they can be
+// accessed by SH1. It is possible thanks to the callback mechanism
+// I use for reading or writing from/to an ATA device in ata.h/c.
+// So don't be puzzled if those structures seem odd compared
+// with the usual ones from PC world. I use this mechanism for structures
+// 'partition_info', 'mbr_sector' and 'fsi_sector' for instance, but
+// not for structure 'bpb_sector' which is too much complex to handle
+// that way, I think.
+// By the way, SH1 is big endian, not little endian as PC is.
+
+///////////////////////////////////////////////////////////////////////////////////
+// FSI SECTOR :
+///////////////
+//
+//
+
+struct __fat_fsi_sector /* File System Info Sector */
+ {
+ unsigned long
+ left_free_clusters;
+ unsigned long
+ next_free_cluster;
+ short
+ data[0];
+ long /* 0x61415252 - aARR */
+ fsi_signature0;
+ char
+ reserved0[480];
+ long /* 0x41617272 - Aarr */
+ fsi_signature1;
+ short
+ end0[0];
+ char
+ reserved1[12];
+ long /* 0x000055AA */
+ signature;
+ short
+ end1[0];
+ };
+
+int __fat_get_fsi_sector_callback (struct __fat_fsi_sector *fsi_sector);
+int __fat_put_fsi_sector_callback (struct __fat_fsi_sector *fsi_sector);
+
+static inline int __fat_get_fsi_sector (unsigned long partition_start,unsigned long lba,struct __fat_fsi_sector *fsi_sector)
+ { return ata_read_sectors (partition_start + lba,1,fsi_sector,(int(*)(void *))get_fsi_sector_callback); }
+
+static inline int __fat_put_fsi_sector (unsigned long partition_start,unsigned long lba,struct __fat_fsi_sector *fsi_sector)
+ { return ata_write_sectors (partition_start + lba,1,fsi_sector,(int(*)(void *))put_fsi_sector_callback); }
+
+//
+///////////////////////////////////////////////////////////////////////////////////
+
+#endif \ No newline at end of file
diff --git a/firmware/test/fat/fat-mbr_sector.c b/firmware/test/fat/fat-mbr_sector.c
new file mode 100644
index 0000000000..f6b510cea5
--- /dev/null
+++ b/firmware/test/fat/fat-mbr_sector.c
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * 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 <fat.h>
+#include "fat-mbr_sector.h"
+
+// [Alan]:
+// I would like to draw your attention about the fact that SH1
+// cannot use misaligned address access so you must be very cautious
+// with structures stored in FAT32 partition because they come from
+// PC world where misaligned address accesses are usual and not
+// problematic. To avoid such a trouble, I decide to use special
+// structures where fields are moved in such a way they can be
+// accessed by SH1. It is possible thanks to the callback mechanism
+// I use for reading or writing from/to an ATA device in ata.h/c.
+// So don't be puzzled if those structures seem odd compared
+// with the usual ones from PC world. I use this mechanism for structures
+// 'partition_info', 'mbr_sector' and 'fsi_sector' for instance, but
+// not for structure 'bpb_sector' which is too much complex to handle
+// that way, I think.
+// By the way, SH1 is big endian, not little endian as PC is.
+
+///////////////////////////////////////////////////////////////////////////////////
+// MBR SECTOR :
+///////////////
+//
+//
+
+int __fat_get_mbr_sector_callback (struct __fat_mbr_sector *mbr_sector)
+ {
+ short *data = mbr_sector->data,*end;
+ for (end = mbr_sector->end; data < end; ++data)
+ *data = ata_get_word (0);
+ __fat_get_partition_table (mbr_sector->partition_table);
+ mbr_sector->signature = HI(ATAR_DATA);
+ return FAT_RETURN_SUCCESS;
+ }
+
+int __fat_put_mbr_sector_callback (struct __fat_mbr_sector *mbr_sector)
+ {
+ short const *data = mbr_sector->data,*end;
+ for (end = mbr_sector->end; data < end;)
+ HI(ATAR_DATA) = *data++;
+ __fat_put_partition_table (mbr_sector->partition_table);
+ ata_put_word (mbr_sector->signature,0);
+ return FAT_RETURN_SUCCESS;
+ }
+
+//
+///////////////////////////////////////////////////////////////////////////////////
diff --git a/firmware/test/fat/fat-mbr_sector.h b/firmware/test/fat/fat-mbr_sector.h
new file mode 100644
index 0000000000..11f131e440
--- /dev/null
+++ b/firmware/test/fat/fat-mbr_sector.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __LIBRARY_FAT_MBR_SECTOR_H__
+#define __LIBRARY_FAT_MBR_SECTOR_H__
+#include "fat-partition.h"
+
+// [Alan]:
+// I would like to draw your attention about the fact that SH1
+// cannot use misaligned address access so you must be very cautious
+// with structures stored in FAT32 partition because they come from
+// PC world where misaligned address accesses are usual and not
+// problematic. To avoid such a trouble, I decide to use special
+// structures where fields are moved in such a way they can be
+// accessed by SH1. It is possible thanks to the callback mechanism
+// I use for reading or writing from/to an ATA device in ata.h/c.
+// So don't be puzzled if those structures seem odd compared
+// with the usual ones from PC world. I use this mechanism for structures
+// 'partition_info', 'mbr_sector' and 'fsi_sector' for instance, but
+// not for structure 'bpb_sector' which is too much complex to handle
+// that way, I think.
+// By the way, SH1 is big endian, not little endian as PC is.
+
+///////////////////////////////////////////////////////////////////////////////////
+// MBR SECTOR :
+///////////////
+//
+//
+
+struct __fat_mbr_sector /* Master Boot Record Sector */
+ {
+ struct
+ __fat_partition_info partition_table[4];
+ short
+ data[0x1BE/2];
+ short
+ end[0];
+ short
+ signature;
+ };
+
+int __fat_get_mbr_sector_callback (struct __fat_mbr_sector *mbr_sector);
+int __fat_put_mbr_sector_callback (struct __fat_mbr_sector *mbr_sector);
+
+static inline int __fat_get_mbr_sector (struct mbr_sector *__fat_mbr_sector)
+ { return ata_read_sectors (0,1,mbr_sector,(int(*)(void *))__fat_get_mbr_sector_callback); }
+
+static inline int __fat_put_mbr_sector (struct mbr_sector *__fat_mbr_sector)
+ { return ata_write_sectors (0,1,mbr_sector,(int(*)(void *))__fat_put_mbr_sector_callback); }
+
+//
+///////////////////////////////////////////////////////////////////////////////////
+
+#endif \ No newline at end of file
diff --git a/firmware/test/fat/fat-partition.h b/firmware/test/fat/fat-partition.h
new file mode 100644
index 0000000000..1b0e363efb
--- /dev/null
+++ b/firmware/test/fat/fat-partition.h
@@ -0,0 +1,161 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id:
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __LIBRARY_FAT_PARTITION_H__
+#define __LIBRARY_FAT_PARTITION_H__
+#include <ata/ata.h>
+
+// [Alan]:
+// I would like to draw your attention about the fact that SH1
+// cannot use misaligned address access so you must be very cautious
+// with structures stored in FAT32 partition because they come from
+// PC world where misaligned address accesses are usual and not
+// problematic. To avoid such a trouble, I decide to use special
+// structures where fields are moved in such a way they can be
+// accessed by SH1. It is possible thanks to the callback mechanism
+// I use for reading or writing from/to an ATA device in ata.h/c.
+// So don't be puzzled if those structures seem odd compared
+// with the usual ones from PC world. I use this mechanism for structures
+// 'partition_info', 'mbr_sector' and 'fsi_sector' for instance, but
+// not for structure 'bpb_sector' which is too much complex to handle
+// that way, I think.
+// By the way, SH1 is big endian, not little endian as PC is.
+
+///////////////////////////////////////////////////////////////////////////////////
+// PARTITION INFO :
+///////////////////
+//
+//
+
+struct __fat_partition_info
+ {
+ // Absolute start sector in this partition :
+ // start = start_cylinder * heads * sectors + start_head * sectors + start_sector - 1
+ unsigned long
+ start;
+
+ // Number of sectors in this partition :
+ // sectors = end_cylinder * heads * sectors + end_head * sectors + end_sector - start_sector
+ unsigned long
+ sectors;
+
+ // File system type.
+ // Must be a FAT32 file system type (0x0B or 0x0C)
+ // for Rockbox.
+ char
+ filesystem_type;
+
+ // Is this partition bootable ?
+ // Not used by Rockbox.
+ char
+ bootable;
+
+ // Not used by Rockbox.
+ unsigned char
+ start_head;
+
+ // Not used by Rockbox.
+ unsigned char
+ start_cylinder;
+
+ // Not used by Rockbox.
+ unsigned char
+ start_sector;
+
+ // Not used by Rockbox.
+ unsigned char
+ end_head;
+
+ // Not used by Rockbox.
+ unsigned char
+ end_cylinder;
+
+ // Not used by Rockbox.
+ unsigned char
+ end_sector;
+ };
+
+
+// load partition info into memory
+static inline void __fat_get_partition_info (struct partition_info *__fat_partition_info)
+ {
+ //
+ union { unsigned long si[4]; unsigned short hi[8]; unsigned char qi[16]; } words;
+ short *data = words.hi,*end;
+ for (end = data + 8; data < end; ++data)
+ *data = HI(ATAR_DATA);
+ partition_info->start = swawSI(words.si[2]);
+ partition_info->sectors = swawSI(words.si[3]);
+ partition_info->bootable = words.qi[1];
+ partition_info->filesystem_type = words.qi[5];
+ partition_info->start_head = words.qi[0];
+ partition_info->start_cylinder = words.qi[3];
+ partition_info->start_sector = words.qi[2];
+ partition_info->end_head = words.qi[4];
+ partition_info->end_cylinder = words.qi[7];
+ partition_info->end_sector = words.qi[6];
+ }
+
+// store partition info into harddisk
+static inline void __fat_put_partition_info (struct partition_info *__fat_partition_info)
+ {
+ union { unsigned long si[4]; short hi[8]; unsigned char qi[16]; } words;
+ short *data = words.hi,*end;
+ words.si[2] = swawSI(partition_info->start);
+ words.si[3] = swawSI(partition_info->sectors);
+ words.qi[1] = partition_info->bootable;
+ words.qi[5] = partition_info->filesystem_type;
+ words.qi[0] = partition_info->start_head;
+ words.qi[3] = partition_info->start_cylinder;
+ words.qi[2] = partition_info->start_sector;
+ words.qi[4] = partition_info->end_head;
+ words.qi[7] = partition_info->end_cylinder;
+ words.qi[6] = partition_info->end_sector;
+ for (end = data + 8; data < end;)
+ HI(ATAR_DATA) = *data++;
+ }
+
+//
+///////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////
+// PARTITION TABLE :
+////////////////////
+//
+//
+
+// load the partition table from a mbr sector
+static inline void __fat_get_partition_table (struct partition_info table[4])
+ {
+ struct partition_info *last;
+ for (last = table + 4; table < last;)
+ __fat_get_partition_info (table++);
+ }
+
+// store the partition table into a mbr sector
+static inline void __fat_put_partition_table (struct partition_info const table[4])
+ {
+ struct partition_info const *last;
+ for (last = table + 4; table < last;)
+ __fat_put_partition_info (table++);
+ }
+
+//
+///////////////////////////////////////////////////////////////////////////////////
+
+#endif \ No newline at end of file
diff --git a/firmware/test/fat/fat-volume.c b/firmware/test/fat/fat-volume.c
new file mode 100644
index 0000000000..dada78c4e6
--- /dev/null
+++ b/firmware/test/fat/fat-volume.c
@@ -0,0 +1,355 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id:
+ *
+ * Copyright (C) 2002 by Alan Korr
+ *
+ * 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.
+ *
+ ****************************************************************************/
+#define __LIBRARY_FAT_VOLUME_C__
+
+#include <fat.h>
+#include "fat-mbr_sector.h"
+#include "fat-bpb_sector.h"
+#include "fat-fsi_sector.h"
+
+///////////////////////////////////////////////////////////////////////////////////
+// FAT VOLUME :
+///////////////
+//
+//
+
+// check fsi sector integrity
+static int __fat_check_fsi_sector (struct fat_volume *volume,struct __fat_fsi_sector *fsi_sector,unsigned long lba)
+ {
+ int error;
+ if (!lba)
+ // no FSI sector
+ {
+ volume->next_free_cluster = 2;
+ return FAT_RETURN_SUCCESS;
+ }
+ if ((error = __fat_get_fsi_sector (volume->partition_start,lba,fsi_sector)) > 0)
+ {
+ if ((fsi_sector->signature != 0x0000AA55) ||
+ (fsi_sector->fsi_signature0 != 0x52524161) ||
+ (fsi_sector->fsi_signature1 != 0x72726141))
+ {
+ return FAT_RETURN_BAD_FSI;
+ }
+ if (fsi_sector->left_free_clusters == -1)
+ fsi_sector->next_free_cluster = 2;
+ else if (fsi_sector->next_free_cluster >= volume->sectors_per_fat)
+ return FAT_RETURN_BAD_FSI;
+ volume->next_free_cluster = fsi_sector->next_free_cluster;
+ fsi_sector->left_free_clusters = -1;
+ fsi_sector->next_free_cluster = 2;
+ error = __fat_put_fsi_sector (volume->partition_start,lba,fsi_sector)));
+ }
+ return error;
+ }
+
+static inline int bit_in_range (int value,int min,int max)
+ {
+ for (;min < max; min <<= 1)
+ if (value == min)
+ return 1;
+ return 0;
+ }
+
+// check bpb sector integrity
+static int __fat_check_bpb_sector (struct fat_volume *volume,struct __fat_bpb_sector *bpb_sector,struct __fat_fsi_sector *fsi_sector)
+ {
+ long unsigned bpb_lba = 0,fsi_lba;
+ long unsigned sectors_per_cluster,sectors_per_fat,sectors,reserved_sectors,total_sectors;
+ long unsigned first_cluster_of_root,first_sector_of_fat,first_sector_of_data;
+ long unsigned clusters_per_fat,bytes_per_sector;
+ int error,backup;
+ for (backup = 0; !backup ; backup = 1)
+ {
+ if ((error = __fat_get_bpb_sector (volume->partition_start,bpb_lba,bpb_sector)) > 0)
+ {
+ bytes_per_sector = peekHI (bpb_sector->bytes_per_sector );
+ sectors_per_cluster = peekQI (bpb_sector->sectors_per_cluster);
+ sectors_per_fat = peekSI (bpb_sector->sectors_per_fat );
+ sectors = peekQI (bpb_sector->number_of_fats ) * sectors_per_fat;
+ reserved_sectors = peekHI (bpb_sector->reserved_sectors );
+ total_sectors = peekSI (bpb_sector->total_sectors );
+ first_cluster_of_root = peekSI (bpb_sector->root_cluster );
+ first_sector_of_fat = reserved_sectors + volume->partition_start;
+ first_sector_of_data = first_sector_of_fat + sectors;
+ clusters_per_fat = (total_sectors - first_sector_of_data) / sectors_per_cluster;
+
+ if (!bpb_lba)
+ {
+ bpb_lba = peekHI(bpb_sector->backup_bpb);
+ if (bpb_lba == -1)
+ bpb_lba = 0;
+ }
+
+ if ((bpb_lba >= reserved_sectors) ||
+ (bpb_sector->signature != 0x000055AA) ||
+ (clusters_per_fat < 65525) ||
+ (bytes_per_sector != 512) ||
+ (!bit_in_range (sectors_per_cluster,1,128)) ||
+ (bytes_per_sector * sectors_per_cluster >= 32 KB) ||
+ (peekHI (bpb_sector->total_sectors_16)) ||
+ (peekHI (bpb_sector->sectors_per_fat_16)) ||
+ (peekHI (bpb_sector->number_of_root_entries)) ||
+ ((bpb_sector->media[0] != 0xF0) && (bpb_sector->media[0] < 0xF8)))
+ {
+ error = FAT_RETURN_BAD_BPB;
+ if (bpb_lba) // try with backup BPB sector ?
+ continue;
+ return error;
+ }
+ if ((signed char)bpb_sector->flags[0] >= 0)
+ {
+ bpb_sector->flags[0] = 0x80;
+ if (!backup && (error = __fat_put_bpb_sector (volume->partition_start,0,bpb_sector)) <= 0)
+ return error;
+ if ((error = __fat_put_bpb_sector (volume->partition_start,bpb_lba,bpb_sector)) <= 0)
+ return error;
+ }
+
+ volume->sectors_per_cluster = sectors_per_cluster;
+ volume->sectors_per_fat = sectors_per_fat;
+ volume->first_cluster_of_root = first_cluster_of_root;
+ volume->first_sector_of_fat = first_sector_of_fat;
+ volume->first_sector_of_data = first_sector_of_data;
+ volume->clusters_per_fat = clusters_per_fat;
+
+ fsi_lba = ((long)peekHI(bpb_sector->filesystem_info));
+ if (fsi_lba == -1)
+ fsi_lba = 0;
+ else if (fsi_lba >= reserved_sectors)
+ {
+ error = FAT_RETURN_BAD_FSI;
+ if (bpb_lba) // try with backup BPB sector ?
+ continue;
+ return error;
+ }
+
+ if (((error = __fat_check_fsi_sector (volume,fsi_sector,fsi_lba + (backup ? 0 : bpb_lba))) <= 0) && bpb_lba)
+ continue;
+
+ if (backup)
+ {
+ error = __fat_put_bpb_sector (volume,0,bpb_sector)) <= 0);
+ if (!error)
+ error = __fat_put_fsi_sector (volume,fsi_lba,fsi_sector)) <= 0);
+ }
+
+ break;
+ }
+ }
+ return error;
+ }
+
+static inline int __fat_compare_volume_name (char const *name,struct fat_volume *volume)
+ {
+ return !name ? -1 : strncpy (name,volume->name,11);
+ }
+
+static struct fat_volume *__fat_splay_volume (struct fat_volume *root,char const *name)
+ {
+ struct fat_volume *down;
+ struct fat_volume *less;
+ struct fat_volume *more;
+ struct fat_volume *head[2];
+ ((struct fat_volume *)head)->less =
+ ((struct fat_volume *)head)->more = 0;
+ less =
+ more = head;
+ while (1)
+ {
+ int sign = __fat_compare_volume_name (name,root);
+ if (sign < 0)
+ {
+ if ((down = root->less))
+ {
+ sign = __fat_compare_volume_name (name,down);
+ if (sign < 0)
+ {
+ root->less = down->more;
+ down->more = root;
+ root = down;
+ if (!root->less)
+ break;
+ }
+ more->less = root;
+ more = root;
+ root = root->less;
+ continue;
+ }
+ break;
+ }
+ if (0 < sign)
+ {
+ if ((down = root->more))
+ {
+ sign = __fat_compare_volume_name (name,down);
+ if (0 < sign)
+ {
+ root->more = down->less;
+ down->less = root;
+ root = down;
+ if (!root->more)
+ break;
+ }
+ less->more = root;
+ less = root;
+ root = root->more;
+ continue;
+ }
+ }
+ break;
+ }
+ less->more = root->less;
+ more->less = root->more;
+ root->less = ((struct fat_volume *)head)->more;
+ root->more = ((struct fat_volume *)head)->less;
+ return root;
+ }
+
+static inline struct fat_volume *__fat_insert_volume (struct fat_volume *root,struct fat_volume *node)
+ {
+ if (!root)
+ {
+ node->less =
+ node->more = 0;
+ }
+ else if (node < (root = __fat_splay_volume (root,node->name)))
+ {
+ node->less = root->less;
+ node->more = root;
+ root->less = 0;
+ }
+ else if
+ {
+ node->less = root;
+ node->more = root->more;
+ node->more = 0;
+ }
+ return node;
+ }
+
+#if 0
+static inline struct fat_volume *__fat_remove_volume (struct fat_volume *root,struct memory_free_page *node)
+ {
+ root = __fat_splay_volume (root,node->name);
+ if (root->less)
+ {
+ node = __fat_splay_volume (root->less,node->name);
+ node->more = root->more;
+ }
+ else
+ node = root->more;
+ return node;
+ }
+#endif
+
+static inline struct fat_volume *__fat_lookup_volume (struct fat_volume *root,char const *name)
+ {
+ return __fat_splay_volume (root,0);
+ }
+
+static struct fat_volume *__fat_first_volume (struct fat_volume *root)
+ {
+ struct fat_volume *down;
+ struct fat_volume *less;
+ struct fat_volume *more;
+ struct fat_volume *head[2];
+ ((struct fat_volume *)head)->less =
+ ((struct fat_volume *)head)->more = 0;
+ less =
+ more = &head;
+ if (root)
+ while (1)
+ {
+ if ((down = root->less))
+ {
+ root->less = down->more;
+ down->more = root;
+ root = down;
+ if (!root->less)
+ break;
+ more->less = root;
+ more = root;
+ root = root->less;
+ continue;
+ }
+ break;
+ }
+ less->more = root->less;
+ more->less = root->more;
+ root->less = ((struct fat_volume *)head)->more;
+ root->more = ((struct fat_volume *)head)->less;
+ return root;
+ }
+
+static inline struct fat_volume *__fat_scan_volume (struct fat_volume *root,int next)
+ {
+ return __fat_first_volume (next ? root->more : root,0);
+ }
+
+static int __fat_build_volume_tree (struct fat_volume *root)
+ {
+ struct fat_volume *volume;
+ int number = 4;
+ struct __fat_partition_info *partition_info;
+ struct __fat_mbr_sector mbr_sector;
+ struct __fat_bpb_sector bpb_sector;
+ struct __fat_fsi_sector fsi_sector;
+ if (__fat_get_mbr_sector (&mbr_sector) <= 0)
+ return 0;
+ partition_info = mbr_sector.partition_table;
+ for (;number-- > 0; ++partition_info)
+ {
+ switch (partition_info->filesystem_type)
+ {
+ case 0x05: // extended partition - handle it as well
+ {
+ if (!__fat_build_volume_list (list))
+ return 0;
+ break;
+ }
+ case 0x0B: // FAT32 partitions
+ case 0x0C:
+ {
+ if (!(volume = memory_allocate_page (0)))
+ return 0;
+ volume->next = 0;
+ volume->partition_start = partition_info->start;
+ volume->partition_sectors = partition_info->sectors;
+ if (__fat_check_bpb_sector (volume,&mbr_sector,&fsi_sector) > 0)
+ {
+ dump_volume (volume);
+ *root = volume;
+ list = &volume->next;
+ break;
+ }
+ else
+ memory_release_page (volume,0);
+ }
+ }
+ }
+ return 1;
+ }
+
+static struct fat_volume *__fat_volume_root;
+
+void fat_setup (void)
+ {
+ //build_volume_list (&root);
+ }
diff --git a/firmware/test/fat/inlines.h b/firmware/test/fat/inlines.h
index 02242bb4cb..eb776e9792 100644
--- a/firmware/test/fat/inlines.h
+++ b/firmware/test/fat/inlines.h
@@ -23,4 +23,5 @@
#define __LIBRARY_FAT_INLINES_H__
+
#endif \ No newline at end of file
diff --git a/firmware/test/fat/makefile b/firmware/test/fat/makefile
index 90a8964d40..1cd259b52f 100644
--- a/firmware/test/fat/makefile
+++ b/firmware/test/fat/makefile
@@ -1,20 +1,21 @@
-#############################################################################
+##############################################################################
## __________ __ ___.
## Open \______ \ ____ ____ | | _\_ |__ _______ ___
## Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
## Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
## Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
## \/ \/ \/ \/ \/
-## Copyright Alan Korr, 2002. All rights reserved.
+## $Id:
##
-## Permission to use, copy, modify, and distribute this software for any
-## purpose is hereby granted without fee, provided that this copyright and
-## permissions notice appear in all copies and derivatives, and that no
-## charge may be made for the software and its documentation except to cover
-## cost of distribution.
+## Copyright (C) 2002 by Alan Korr
##
-## This software is provided "as is" without express or implied warranty.
-#############################################################################
+## 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.
+##
+##############################################################################
ARCH = test
PACKAGE = fat
VERSION = 0.0.0
diff --git a/firmware/test/fat/return_values.h b/firmware/test/fat/return_values.h
index 114a0abb5f..67747ffc36 100644
--- a/firmware/test/fat/return_values.h
+++ b/firmware/test/fat/return_values.h
@@ -21,4 +21,11 @@
#endif
#ifndef __LIBRARY_FAT_RETURN_VALUES_H__
# define __LIBRARY_FAT_RETURN_VALUES_H__
+
+enum
+ {
+ FAT_RETURN_SUCCESS = 1,
+ FAT_RETURN_FAILURE = 0
+ };
+
#endif \ No newline at end of file
diff --git a/firmware/test/fat/types.h b/firmware/test/fat/types.h
index 3a84aa3e97..d83de9e2c1 100644
--- a/firmware/test/fat/types.h
+++ b/firmware/test/fat/types.h
@@ -21,4 +21,23 @@
#endif
#ifndef __LIBRARY_FAT_TYPES_H__
# define __LIBRARY_FAT_TYPES_H__
+
+// [Alan]:
+// I would like to draw your attention about the fact that SH1
+// cannot use misaligned address access so you must be very cautious
+// with structures stored in FAT32 partition because they come from
+// PC world where misaligned address accesses are usual and not
+// problematic. To avoid such a trouble, I decide to use special
+// structures where fields are moved in such a way they can be
+// accessed by SH1. It is possible thanks to the callback mechanism
+// I use for reading or writing from/to an ATA device in ata.h/c.
+// So don't be puzzled if those structures seem odd compared
+// with the usual ones from PC world. I use this mechanism for structures
+// 'partition_info', 'mbr_sector' and 'fsi_sector' for instance, but
+// not for structure 'bpb_sector' which is too much complex to handle
+// that way, I think.
+// By the way, SH1 is big endian, not little endian as PC is.
+
+
+
#endif \ No newline at end of file