📄 fat.c
字号:
/*
gba_nds_fat.c
By chishm (Michael Chisholm)
Routines for reading a compact flash card
using the GBA Movie Player or M3.
Some FAT routines are based on those in fat.c, which
is part of avrlib by Pascal Stang.
This software is completely free. No warranty is provided.
If you use it, please give me credit and email me about your
project at chishm@hotmail.com
See gba_nds_fat.txt for help and license details.
*/
//---------------------------------------------------------------
// Includes
#include "fat.h"
#include <string.h>
#include "..\main\sys.h"
#include "..\hardware\hardware.h"
//----------------------------------------------------------------
// Data types
#ifndef NULL
#define NULL 0
#endif
//----------------------------------------------------------------
// NDS memory access control register
#ifdef NDS
#ifndef WAIT_CR
#define WAIT_CR (*(vunsigned short*)0x04000204)
#endif
#endif
//---------------------------------------------------------------
// Appropriate placement of CF functions and data
#ifdef NDS
#define _VARS_IN_RAM
#else
#define _VARS_IN_RAM __attribute__ ((section (".sbss")))
#endif
//-----------------------------------------------------------------
// FAT constants
#define CLUSTER_EOF_16 0xFFFF
#define CLUSTER_EOF 0x0FFFFFFF
#define CLUSTER_FREE 0x0000
#define CLUSTER_FIRST 0x0002
#define FILE_LAST 0x00
#define FILE_FREE 0xE5
#define FAT16_ROOT_DIR_CLUSTER 0x00
//-----------------------------------------------------------------
// long file name constants
#define LFN_END 0x40
#define LFN_DEL 0x80
//-----------------------------------------------------------------
// Data Structures
// Take care of packing for GCC - it doesn't obey pragma pack()
// properly for ARM targets.
#define BYTE_PER_READ 512
int usbhost_read(unsigned long rblk,unsigned long rcnt,void* rbuffer);
int usbhost_write(unsigned long rblk,unsigned long rcnt,void* rbuffer);
#define disc_ReadSectors(sector, numSecs, buffer) usbhost_read(sector,numSecs,buffer)
#define disc_WriteSectors(sector,numSecs, buffer) usbhost_write(sector,numSecs,buffer)
#define disc_ReadSector(sector,buffer) usbhost_read(sector,1,buffer)
#define disc_WriteSector(sector,buffer) usbhost_write(sector,1,buffer)
#define disc_Init() 1
#define disc_CacheFlush()
#define disc_ClearStatus()
#define disc_IsInserted() 1
// Boot Sector - must be packed
__packed typedef struct
{
unsigned char jmpBoot[3];
unsigned char OEMName[8];
// BIOS Parameter Block
unsigned short bytesPerSector;
unsigned char sectorsPerCluster;
unsigned short reservedSectors;
unsigned char numFATs;
unsigned short rootEntries;
unsigned short numSectorsSmall;
unsigned char mediaDesc;
unsigned short sectorsPerFAT;
unsigned short sectorsPerTrk;
unsigned short numHeads;
unsigned int numHiddenSectors;
unsigned int numSectors;
__packed union // Different types of extended BIOS Parameter Block for FAT16 and FAT32
{
__packed struct
{
// Ext BIOS Parameter Block for FAT16
unsigned char driveNumber;
unsigned char reserved1;
unsigned char extBootSig;
unsigned int volumeID;
unsigned char volumeLabel[11];
unsigned char fileSysType[8];
// Bootcode
unsigned char bootCode[448];
} fat16;
__packed struct
{
// FAT32 extended block
unsigned int sectorsPerFAT32;
unsigned short extFlags;
unsigned short fsVer;
unsigned int rootClus;
unsigned short fsInfo;
unsigned short bkBootSec;
unsigned char reserved[12];
// Ext BIOS Parameter Block for FAT16
unsigned char driveNumber;
unsigned char reserved1;
unsigned char extBootSig;
unsigned int volumeID;
unsigned char volumeLabel[11];
unsigned char fileSysType[8];
// Bootcode
unsigned char bootCode[420];
} fat32;
} extBlock;
unsigned short bootSig;
} BOOT_SEC;
// Directory entry - must be packed
__packed typedef struct
{
unsigned char name[8];
unsigned char ext[3];
unsigned char attrib;
unsigned char reserved;
unsigned char cTime_ms;
unsigned short cTime;
unsigned short cDate;
unsigned short aDate;
unsigned short startClusterHigh;
unsigned short mTime;
unsigned short mDate;
unsigned short startCluster;
unsigned int fileSize;
} DIR_ENT;
// Long file name directory entry - must be packed
__packed typedef struct
{
unsigned char ordinal; // Position within LFN
unsigned short char0;
unsigned short char1;
unsigned short char2;
unsigned short char3;
unsigned short char4;
unsigned char flag; // Should be equal to ATTRIB_LFN
unsigned char reserved1; // Always 0x00
unsigned char checkSum; // Checksum of short file name (alias)
unsigned short char5;
unsigned short char6;
unsigned short char7;
unsigned short char8;
unsigned short char9;
unsigned short char10;
unsigned short reserved2; // Always 0x0000
unsigned short char11;
unsigned short char12;
} DIR_ENT_LFN;
static const char lfn_offset_table[13]={0x01,0x03,0x05,0x07,0x09,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E};
//-----------------------------------------------------------------
// Global Variables
// _VARS_IN_RAM variables are stored in the largest section of WRAM
// available: IWRAM on NDS ARM7, EWRAM on NDS ARM9 and GBA
// Files
static _VARS_IN_RAM FAT_FILE openFiles[MAX_FILES_OPEN];
// Long File names
static _VARS_IN_RAM char lfnName[MAX_FILENAME_LENGTH];
static char lfnExists;
// Locations on card
static int filesysRootDir;
static int filesysRootDirClus;
static int filesysFAT;
static int filesysSecPerFAT;
static int filesysNumSec;
static int filesysData;
static int filesysBytePerSec;
static int filesysSecPerClus;
static int filesysBytePerClus;
static FS_TYPE filesysType = FS_UNKNOWN;
static unsigned int filesysTotalSize;
// Info about FAT
static unsigned int fatLastCluster;
static unsigned int fatFirstFree;
// fatBuffer used to reduce wear on the CF card from multiple writes
_VARS_IN_RAM char fatBuffer[BYTE_PER_READ];
static unsigned int fatBufferCurSector;
// Current working directory
static unsigned int curWorkDirCluster;
// Position of the directory entry last retreived with FAT_GetDirEntry
static unsigned int wrkDirCluster;
static int wrkDirSector;
static int wrkDirOffset;
// Global sector buffer to save on stack space
static _VARS_IN_RAM unsigned char globalBuffer[BYTE_PER_READ];
//-----------------------------------------------------------------
// 本文件的函数表
char ucase (char character);
unsigned short getRTCtoFileTime (void);
unsigned short getRTCtoFileDate (void);
char FAT_AddDirEntry (const char* path, DIR_ENT newDirEntry);
char FAT_ClearLinks (unsigned int cluster);
DIR_ENT FAT_DirEntFromPath (const char* path);
unsigned int FAT_FirstFreeCluster(void);
DIR_ENT FAT_GetDirEntry ( unsigned int dirCluster, int entry, int origin);
unsigned int FAT_LinkFreeCluster(unsigned int cluster);
unsigned int FAT_NextCluster(unsigned int cluster);
char FAT_WriteFatEntry (unsigned int cluster, unsigned int value);
char FAT_GetFilename (DIR_ENT dirEntry, char* alias);
char FAT_InitFiles (void);
char FAT_FreeFiles (void);
int FAT_remove (const char* path);
char FAT_chdir (const char* path);
FILE_TYPE FAT_FindFirstFile (char* filename);
FILE_TYPE FAT_FindNextFile (char* filename);
FILE_TYPE FAT_FileExists (const char* filename);
char FAT_GetAlias (char* alias);
char FAT_GetLongFilename (char* filename);
unsigned int FAT_GetFileSize (void);
unsigned int FAT_GetFileCluster (void);
FAT_FILE* FAT_fopen(const char* path, const char* mode);
char FAT_fclose (FAT_FILE* file);
char FAT_feof(FAT_FILE* file);
int FAT_fseek(FAT_FILE* file, int offset, int origin);
int FAT_ftell (FAT_FILE* file);
unsigned int FAT_fread (void* buffer, unsigned int size, unsigned int count, FAT_FILE* file);
unsigned int FAT_fwrite (const void* buffer, unsigned int size, unsigned int count, FAT_FILE* file);
char FAT_fgetc (FAT_FILE* file);
char FAT_fputc (char c, FAT_FILE* file);
/*-----------------------------------------------------------------
ucase
Returns the uppercase version of the given char
char IN: a character
char return OUT: uppercase version of character
-----------------------------------------------------------------*/
char ucase (char character)
{
if((character > 0x60) && (character < 0x7B))
{ character = character - 0x20; }
return (character);
}
/*-----------------------------------------------------------------
getRTCtoFileTime and getRTCtoFileDate
Returns the time / date in Dir Entry styled format
unsigned short return OUT: time / date in Dir Entry styled format
-----------------------------------------------------------------*/
unsigned short getRTCtoFileTime (void)
{
return (
( ( (ctime.hour > 11 ? ctime.hour - 40 : ctime.hour) & 0x1F) << 11) |
( (ctime.min & 0x3F) << 5) |
( (ctime.sec >> 1) & 0x1F) );
}
unsigned short getRTCtoFileDate (void)
{
return (
( ((ctime.year + 20) & 0x7F) <<9) |
( (ctime.month & 0xF) << 5) |
(ctime.day & 0x1F) );
}
/*-----------------------------------------------------------------
Disc level FAT routines
-----------------------------------------------------------------*/
#define FAT_ClustToSect(m) \
(((m-2) * filesysSecPerClus) + filesysData)
/*-----------------------------------------------------------------
FAT_NextCluster
Internal function - gets the cluster linked from input cluster
-----------------------------------------------------------------*/
unsigned int FAT_NextCluster(unsigned int cluster)
{
unsigned int nextCluster = CLUSTER_FREE;
unsigned int sector;
int offset;
switch (filesysType)
{
case FS_UNKNOWN:
nextCluster = CLUSTER_FREE;
break;
case FS_FAT12:
sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ);
offset = ((cluster * 3) / 2) % BYTE_PER_READ;
// If FAT buffer contains wrong sector
if (sector != fatBufferCurSector)
{
// Load correct sector to buffer
fatBufferCurSector = sector;
disc_ReadSector(fatBufferCurSector, fatBuffer);
}
nextCluster = ((unsigned char*)fatBuffer)[offset];
offset++;
if (offset >= BYTE_PER_READ) {
offset = 0;
fatBufferCurSector++;
disc_ReadSector(fatBufferCurSector, fatBuffer);
}
nextCluster |= (((unsigned char*)fatBuffer)[offset]) << 8;
if (cluster & 0x01) {
nextCluster = nextCluster >> 4;
} else {
nextCluster &= 0x0FFF;
}
if (nextCluster >= 0x0FF7)
{
nextCluster = CLUSTER_EOF;
}
break;
case FS_FAT16:
sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ);
offset = cluster % (BYTE_PER_READ >> 1);
// If FAT buffer contains wrong sector
if (sector != fatBufferCurSector)
{
// Load correct sector to buffer
fatBufferCurSector = sector;
disc_ReadSector(fatBufferCurSector, fatBuffer);
}
// read the nextCluster value
nextCluster = ((unsigned short*)fatBuffer)[offset];
if (nextCluster >= 0xFFF7)
{
nextCluster = CLUSTER_EOF;
}
break;
case FS_FAT32:
sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ);
offset = cluster % (BYTE_PER_READ >> 2);
// If FAT buffer contains wrong sector
if (sector != fatBufferCurSector)
{
// Load correct sector to buffer
fatBufferCurSector = sector;
disc_ReadSector(fatBufferCurSector, fatBuffer);
}
// read the nextCluster value
nextCluster = (((unsigned int*)fatBuffer)[offset]) & 0x0FFFFFFF;
if (nextCluster >= 0x0FFFFFF7)
{
nextCluster = CLUSTER_EOF;
}
break;
default:
nextCluster = CLUSTER_FREE;
break;
}
return nextCluster;
}
#ifdef CAN_WRITE_TO_DISC
/*-----------------------------------------------------------------
FAT_WriteFatEntry
Internal function - writes FAT information about a cluster
-----------------------------------------------------------------*/
char FAT_WriteFatEntry (unsigned int cluster, unsigned int value)
{
unsigned int sector;
int offset;
if ((cluster < 0x0002) || (cluster > fatLastCluster))
{
return false;
}
switch (filesysType)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -