mirror of
https://github.com/dborth/fceugx.git
synced 2024-12-04 22:34:14 +01:00
import VFAT from Genplus for use with WiiSD
This commit is contained in:
parent
7df8e60875
commit
2feeacec70
@ -34,7 +34,7 @@ LANG := ENGLISH
|
||||
|
||||
#CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) -DFCEU_VERSION_NUMERIC=9812 -DNGC=1 -DZLIB -DBIG_ENDIAN -DHAVE_ASPRINTF=1 -DSTDC -D_SZ_ONE_DIRECTORY=1 -D_LZMA_IN_CB=1 -D_LZMA_OUT_READ
|
||||
CFLAGS = -g -Os -Wall $(MACHDEP) $(INCLUDE) -DFCEU_VERSION_NUMERIC=9812 -DNGC=1 \
|
||||
-DZLIB -DBIG_ENDIAN -DHAVE_ASPRINTF=1 -DSTDC \
|
||||
-DZLIB -DBIG_ENDIAN -DWORDS_BIGENDIAN -DHAVE_ASPRINTF=1 -DSTDC \
|
||||
-D_SZ_ONE_DIRECTORY=1 -D_LZMA_IN_CB=1 -D_LZMA_OUT_READ \
|
||||
-DINTL_$(LANG)
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
|
@ -17,12 +17,11 @@
|
||||
#include "gcdvd.h"
|
||||
|
||||
#ifdef HW_RVL
|
||||
#include "wiisd/sdio.h"
|
||||
#include "wiisd/tff.h"
|
||||
#include "wiisd/vfat.h"
|
||||
|
||||
/*Front SCARD*/
|
||||
FATFS frontfs;
|
||||
FILINFO finfo;
|
||||
VFATFS vfs;
|
||||
FSDIRENTRY vfsfile;
|
||||
#endif
|
||||
|
||||
/*** Simplified Directory Entry Record
|
||||
@ -37,7 +36,6 @@ FILINFO finfo;
|
||||
#define PAGESIZE 11
|
||||
|
||||
#define FCEUDIR "fceu"
|
||||
#define SAVEDIR "saves"
|
||||
#define ROMSDIR "roms"
|
||||
|
||||
FILEENTRIES filelist[MAXFILES];
|
||||
@ -561,51 +559,33 @@ int parseWiiSDdirectory() {
|
||||
int entries = 0;
|
||||
int nbfiles = 0;
|
||||
int numstored = 0;
|
||||
DIRECTORY sddir;
|
||||
s32 result;
|
||||
char msg[1024];
|
||||
|
||||
/* initialize selection */
|
||||
selection = offset = 0;
|
||||
|
||||
/* Get a list of files from the actual root directory */
|
||||
result = f_opendir(&sddir, rootWiiSDdir);
|
||||
if(result != FR_OK) {
|
||||
sprintf(msg, "f_opendir(%s) failed with %d.", rootWiiSDdir, result);
|
||||
FSDIRENTRY vfsdir;
|
||||
int result = VFAT_opendir(0, &vfsdir, rootWiiSDdir);
|
||||
if(result != FS_SUCCESS) {
|
||||
sprintf(msg, "Opendir(%s) failed with %d.", rootWiiSDdir, result);
|
||||
WaitPrompt(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&finfo, 0, sizeof(finfo));
|
||||
|
||||
// f_readdir doesn't seem to find ".." dir, manually add it.
|
||||
if (strlen(rootWiiSDdir) > 0) {
|
||||
strcpy(filelist[numstored].filename, "..");
|
||||
filelist[numstored].length = 0;
|
||||
filelist[numstored].flags = 1;
|
||||
while (VFAT_readdir(&vfsdir) == FS_SUCCESS) {
|
||||
sprintf(msg, "VFAT Adding %s", vfsdir.longname);
|
||||
ShowAction(msg);
|
||||
memset (&filelist[numstored], 0, sizeof (FILEENTRIES));
|
||||
strncpy(filelist[numstored].filename,(char *)(vfsdir.longname), MAX_LONG_NAME);
|
||||
filelist[numstored].filename[MAX_LONG_NAME-1] = 0;
|
||||
filelist[numstored].length = vfsdir.fsize;
|
||||
filelist[numstored].flags = (char)(vfsdir.dirent.attribute & ATTR_DIRECTORY);
|
||||
numstored++;
|
||||
nbfiles++;
|
||||
}
|
||||
f_readdir(&sddir, &finfo);
|
||||
finfo.fname[12] = 0;
|
||||
while(strlen(finfo.fname) != 0) {
|
||||
finfo.fname[12] = 0;
|
||||
//if(!(finfo.fattrib & AM_DIR))
|
||||
//{
|
||||
if (strcmp((const char*)finfo.fname, ".") != 0) { // Skip "." directory
|
||||
sprintf(msg, "Adding %s", finfo.fname);
|
||||
//ShowAction(msg);
|
||||
memset(&filelist[numstored], 0, sizeof (FILEENTRIES));
|
||||
strncpy(filelist[numstored].filename,(const char*)finfo.fname,MAXJOLIET);
|
||||
filelist[numstored].filename[MAXJOLIET-1] = 0;
|
||||
filelist[numstored].length = finfo.fsize;
|
||||
filelist[numstored].flags = (char)(finfo.fattrib & AM_DIR);
|
||||
numstored++;
|
||||
}
|
||||
nbfiles++;
|
||||
//}
|
||||
memset(&finfo, 0, sizeof(finfo));
|
||||
f_readdir(&sddir, &finfo);
|
||||
}
|
||||
VFAT_closedir(&vfsdir);
|
||||
|
||||
entries = nbfiles;
|
||||
if (entries < 0) entries = 0;
|
||||
if (entries > MAXFILES) entries = MAXFILES;
|
||||
@ -786,16 +766,6 @@ void FileSelector() {
|
||||
maxfiles = parsedir();
|
||||
}
|
||||
} else {
|
||||
#ifdef HW_RVL
|
||||
if (UseWiiSDCARD) {
|
||||
strncpy(finfo.fname, filelist[selection].filename, 12);
|
||||
int l = strlen(finfo.fname);
|
||||
if (l > 12) l = 12;
|
||||
finfo.fname[l] = 0;
|
||||
finfo.fsize = filelist[selection].length;
|
||||
finfo.fattrib = filelist[selection].flags ? AM_DIR : 0;
|
||||
}
|
||||
#endif
|
||||
rootdir = filelist[selection].offset;
|
||||
rootdirlength = filelist[selection].length;
|
||||
// Now load the DVD file to it's offset
|
||||
@ -817,62 +787,18 @@ int LoadDVDFile( unsigned char *buffer ) {
|
||||
u64 discoffset;
|
||||
|
||||
#ifdef HW_RVL
|
||||
FIL fp;
|
||||
u32 bytes_read = 0, bytes_read_total = 0;
|
||||
|
||||
if(UseWiiSDCARD) {
|
||||
ShowAction((char*)"Loading ... Wait");
|
||||
char filename[1024];
|
||||
sprintf(filename, "%s/%s", rootWiiSDdir, finfo.fname);
|
||||
sprintf(filename, "%s/%s", rootWiiSDdir, filelist[selection].filename);
|
||||
|
||||
/*if(f_mount(0, &frontfs) != FR_OK) {
|
||||
WaitPrompt("f_mount failed");
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
int res = f_stat(filename, &finfo);
|
||||
if(res != FR_OK) {
|
||||
int res = VFAT_fopen(0, &vfsfile, filename, FS_READ);
|
||||
if (res != FS_SUCCESS) {
|
||||
char msg[1024];
|
||||
sprintf(msg, "f_stat %s failed, error %d", filename, res);
|
||||
sprintf(msg, "Open %s failed, error %d", filename, res);
|
||||
WaitPrompt(msg);
|
||||
//f_mount(0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = f_open(&fp, filename, FA_READ);
|
||||
if (res != FR_OK) {
|
||||
char msg[1024];
|
||||
sprintf(msg, "f_open failed, error %d", res);
|
||||
WaitPrompt(msg);
|
||||
//f_mount(0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(bytes_read_total < finfo.fsize) {
|
||||
if(f_read(&fp, buffer + bytes_read_total, 0x200, &bytes_read) != FR_OK) {
|
||||
WaitPrompt((char*)"f_read failed");
|
||||
f_close(&fp);
|
||||
//f_mount(0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bytes_read == 0)
|
||||
break;
|
||||
bytes_read_total += bytes_read;
|
||||
}
|
||||
|
||||
if(bytes_read_total < finfo.fsize) {
|
||||
//printf("error: read %u of %u bytes.\n", bytes_read_total, (unsigned int)finfo.fsize);
|
||||
WaitPrompt((char*)"read failed : over read!");
|
||||
f_close(&fp);
|
||||
//f_mount(0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ShowAction((char*)"Loading Rom Succeeded");
|
||||
f_close(&fp);
|
||||
//f_mount(0, NULL);
|
||||
return bytes_read_total;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -887,12 +813,21 @@ int LoadDVDFile( unsigned char *buffer ) {
|
||||
|
||||
ShowAction("Loading ... Wait");
|
||||
if (UseSDCARD) SDCARD_ReadFile (filehandle, &readbuffer, 2048);
|
||||
#ifdef HW_RVL
|
||||
else if (UseWiiSDCARD) VFAT_fread(&vfsfile, &readbuffer, 2048);
|
||||
#endif
|
||||
else dvd_read(&readbuffer, 2048, discoffset);
|
||||
|
||||
if ( isZipFile() == false ) {
|
||||
if (UseSDCARD) SDCARD_SeekFile (filehandle, 0, SDCARD_SEEK_SET);
|
||||
#ifdef HW_RVL
|
||||
else if (UseWiiSDCARD) VFAT_fseek(&vfsfile, 0, SEEK_SET);
|
||||
#endif
|
||||
for ( i = 0; i < blocks; i++ ) {
|
||||
if (UseSDCARD) SDCARD_ReadFile (filehandle, &readbuffer, 2048);
|
||||
#ifdef HW_RVL
|
||||
else if (UseWiiSDCARD) VFAT_fread(&vfsfile, &readbuffer, 2048);
|
||||
#endif
|
||||
else dvd_read(&readbuffer, 2048, discoffset);
|
||||
memcpy(&buffer[offset], &readbuffer, 2048);
|
||||
offset += 2048;
|
||||
@ -903,6 +838,9 @@ int LoadDVDFile( unsigned char *buffer ) {
|
||||
if( rootdirlength % 2048 ) {
|
||||
i = rootdirlength % 2048;
|
||||
if (UseSDCARD) SDCARD_ReadFile (filehandle, &readbuffer, i);
|
||||
#ifdef HW_RVL
|
||||
else if (UseWiiSDCARD) VFAT_fread(&vfsfile, &readbuffer, i);
|
||||
#endif
|
||||
else dvd_read(&readbuffer, 2048, discoffset);
|
||||
memcpy(&buffer[offset], &readbuffer, i);
|
||||
}
|
||||
@ -910,6 +848,9 @@ int LoadDVDFile( unsigned char *buffer ) {
|
||||
return unzipDVDFile( buffer, (u32)discoffset, rootdirlength);
|
||||
}
|
||||
if (UseSDCARD) SDCARD_CloseFile (filehandle);
|
||||
#ifdef HW_RVL
|
||||
else if (UseWiiSDCARD) VFAT_fclose(&vfsfile);
|
||||
#endif
|
||||
|
||||
return rootdirlength;
|
||||
}
|
||||
@ -965,13 +906,17 @@ int OpenWiiSD () {
|
||||
haveSDdir = 0;
|
||||
char msg[128];
|
||||
|
||||
memset(&vfs, 0, sizeof(VFATFS));
|
||||
if (haveWiiSDdir == 0) {
|
||||
/* don't mess with DVD entries */
|
||||
havedir = 0;
|
||||
|
||||
/* Mount WiiSD */
|
||||
if(f_mount(0, &frontfs) != FR_OK) {
|
||||
WaitPrompt((char*)"f_mount failed");
|
||||
/* Mount WiiSD with VFAT */
|
||||
VFAT_unmount(0, &vfs);
|
||||
int res = VFAT_mount(FS_SLOTA, &vfs);
|
||||
if (res != FS_TYPE_FAT16) {
|
||||
sprintf(msg, "Error mounting WiiSD: %d", res);
|
||||
WaitPrompt(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -992,13 +937,11 @@ int OpenWiiSD () {
|
||||
/* no entries found */
|
||||
sprintf (msg, "Error reading %s", rootWiiSDdir);
|
||||
WaitPrompt (msg);
|
||||
//f_mount(0, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Retrieve previous entries list and made a new selection */
|
||||
else FileSelector ();
|
||||
//f_mount(0, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -52,9 +52,15 @@ extern int UseSDCARD;
|
||||
extern unsigned char DecodeJoy( unsigned short pp );
|
||||
extern unsigned char GetAnalog(int Joy);
|
||||
|
||||
#ifdef HW_RVL
|
||||
void (*PSOReload)() = (void(*)())0x90000020;
|
||||
#else
|
||||
void (*PSOReload)() = (void(*)())0x80001800;
|
||||
#endif
|
||||
|
||||
void Reboot() {
|
||||
#ifdef HW_RVL
|
||||
// Thanks to hell_hibou
|
||||
// Thanks to eke-eke
|
||||
SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0);
|
||||
#else
|
||||
#define SOFTRESET_ADR ((volatile u32*)0xCC003024)
|
||||
@ -1002,12 +1008,6 @@ int MainMenu() {
|
||||
short j;
|
||||
int redraw = 1;
|
||||
|
||||
#ifdef HW_RVL
|
||||
void (*PSOReload)() = (void(*)())0x90000020;
|
||||
#else
|
||||
void (*PSOReload)() = (void(*)())0x80001800;
|
||||
#endif
|
||||
|
||||
/*** Stop any running Audio ***/
|
||||
AUDIO_StopDMA();
|
||||
|
||||
|
@ -45,13 +45,8 @@ long long basetime;
|
||||
|
||||
void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count);
|
||||
|
||||
extern void *PSOReload();
|
||||
static void reset_cb() {
|
||||
#ifdef HW_RVL
|
||||
void (*PSOReload)() = (void(*)())0x90000020;
|
||||
#else
|
||||
void (*PSOReload)() = (void(*)())0x80001800;
|
||||
#endif
|
||||
|
||||
PSOReload();
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,8 @@ int mcversion = 0x981211;
|
||||
|
||||
static u8 SysArea[CARD_WORKAREA] ATTRIBUTE_ALIGN(32);
|
||||
#ifdef HW_RVL
|
||||
extern FILINFO finfo;
|
||||
FATFS frontfs;
|
||||
FILINFO finfo;
|
||||
#endif
|
||||
extern int ChosenSlot;
|
||||
extern int ChosenDevice;
|
||||
@ -545,6 +546,13 @@ void SD_Manage(int mode, int slot) {
|
||||
int res;
|
||||
u32 offset = 0;
|
||||
|
||||
/* Mount WiiSD with TinyFatFS*/
|
||||
if(f_mount(0, &frontfs) != FR_OK) {
|
||||
WaitPrompt((char*)"f_mount failed");
|
||||
return 0;
|
||||
}
|
||||
memset(&finfo, 0, sizeof(finfo));
|
||||
|
||||
if (mode == 0)
|
||||
res = f_open(&fp, path, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
else {
|
||||
|
@ -29,6 +29,8 @@ static s32 sd_fd = -1;
|
||||
|
||||
static u32 status __attribute__((aligned(32)));
|
||||
|
||||
s32 sd_deinit();
|
||||
|
||||
s32 sd_send_cmd(u32 cmd, u32 type, u32 resp, u32 arg, u32 blocks, u32 bsize, u32 addr)
|
||||
{
|
||||
static u32 request[9] __attribute__((aligned(32)));
|
||||
@ -45,12 +47,12 @@ s32 sd_send_cmd(u32 cmd, u32 type, u32 resp, u32 arg, u32 blocks, u32 bsize, u32
|
||||
request[4] = blocks;
|
||||
request[5] = bsize;
|
||||
request[6] = addr;
|
||||
request[7] = 0;
|
||||
request[8] = 0;
|
||||
//request[7] = 0;
|
||||
//request[8] = 0;
|
||||
|
||||
r = IOS_Ioctl(sd_fd, 7, (u8 *)request, 36, (u8 *)reply, 0x10);
|
||||
printf("sd_send_cmd(%x, %x, %x, %x, %x, %x, %x) = %d", cmd, type, resp, arg, blocks, bsize, addr, r);
|
||||
printf(" -> %x %x %x %x\n", reply[0], reply[1], reply[2], reply[3]); // TODO: add some argument for this reply
|
||||
//printf("sd_send_cmd(%x, %x, %x, %x, %x, %x, %x) = %d", cmd, type, resp, arg, blocks, bsize, addr, r);
|
||||
//printf(" -> %x %x %x %x\n", reply[0], reply[1], reply[2], reply[3]); // TODO: add some argument for this reply
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -60,7 +62,7 @@ s32 sd_reset()
|
||||
s32 r;
|
||||
|
||||
r = IOS_Ioctl(sd_fd, 4, 0, 0, (u8 *)&status, 4);
|
||||
printf("sd_reset(): r = %d; status = %d\n", r, status);
|
||||
//printf("sd_reset(): r = %d; status = %d\n", r, status);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -69,15 +71,7 @@ s32 sd_select()
|
||||
s32 r;
|
||||
|
||||
r = sd_send_cmd(7, 3, 2, status & 0xFFFF0000, 0, 0, 0);
|
||||
printf("sd_select(): r = %d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
s32 sd_deselect()
|
||||
{
|
||||
s32 r;
|
||||
r = sd_send_cmd(7, 3, 2, 0, 0, 0, 0);
|
||||
printf("sd_deselect(): r = %d\n", r);
|
||||
//printf("sd_select(): r = %d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -86,7 +80,7 @@ s32 sd_set_blocklen(u32 len)
|
||||
s32 r;
|
||||
|
||||
r = sd_send_cmd(0x10, 3, 1, len, 0, 0, 0);
|
||||
printf("sd_set_blocklen(%x) = %d\n", len, r);
|
||||
//printf("sd_set_blocklen(%x) = %d\n", len, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -101,10 +95,10 @@ u8 sd_get_hcreg()
|
||||
|
||||
query[0] = 0x28;
|
||||
query[3] = 1;
|
||||
query[4] = 0;
|
||||
//query[4] = 0;
|
||||
|
||||
r = IOS_Ioctl(sd_fd, 2, (u8 *)query, 0x18, (u8 *)&data, 4);
|
||||
printf("sd_get_hcreg() = %d; r = %d\n", data & 0xFF, r);
|
||||
//printf("sd_get_hcreg() = %d; r = %d\n", data & 0xFF, r);
|
||||
return data & 0xFF;
|
||||
}
|
||||
|
||||
@ -120,7 +114,7 @@ s32 sd_set_hcreg(u8 value)
|
||||
query[4] = value;
|
||||
|
||||
r = IOS_Ioctl(sd_fd, 1, (u8 *)query, 0x18, 0, 0);
|
||||
printf("sd_set_hcreg(%d) = %d\n", value, r);
|
||||
//printf("sd_set_hcreg(%d) = %d\n", value, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -151,7 +145,7 @@ s32 sd_clock()
|
||||
|
||||
c = 1;
|
||||
r = IOS_Ioctl(sd_fd, 6, &c, 4, 0, 0);
|
||||
printf("sd_clock() = %d\n", r);
|
||||
//printf("sd_clock() = %d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -195,8 +189,8 @@ s32 sd_read(u32 n, u8 *buf)
|
||||
|
||||
if(r != 0)
|
||||
{
|
||||
printf("sd_read() = %d\n", r);
|
||||
printf(" %x %x %x %x\n", res[0], res[1], res[2], res[3]);
|
||||
//printf("sd_read() = %d\n", r);
|
||||
//printf(" %x %x %x %x\n", res[0], res[1], res[2], res[3]);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -241,8 +235,8 @@ s32 sd_write(u32 n, const u8 *buf)
|
||||
|
||||
if(r != 0)
|
||||
{
|
||||
printf("sd_write() = %d\n", r);
|
||||
printf(" %x %x %x %x\n", res[0], res[1], res[2], res[3]);
|
||||
//printf("sd_write() = %d\n", r);
|
||||
//printf(" %x %x %x %x\n", res[0], res[1], res[2], res[3]);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -255,12 +249,13 @@ s32 sd_init()
|
||||
|
||||
if(sd_fd > 0)
|
||||
{
|
||||
printf("sd_init() called more than once. using old sd_fd: %d\n", sd_fd);
|
||||
return 0;
|
||||
//printf("sd_init() called more than once. using old sd_fd: %d\n", sd_fd);
|
||||
//return 0;
|
||||
sd_deinit();
|
||||
}
|
||||
|
||||
sd_fd = IOS_Open("/dev/sdio/slot0", 0);
|
||||
printf("sd_fd = %d\n", sd_fd);
|
||||
//printf("sd_fd = %d\n", sd_fd);
|
||||
if(sd_fd < 0)
|
||||
return sd_fd;
|
||||
|
||||
@ -287,7 +282,7 @@ s32 sd_init()
|
||||
|
||||
s32 sd_deinit()
|
||||
{
|
||||
sd_deselect();
|
||||
sd_reset();
|
||||
return IOS_Close(sd_fd);
|
||||
}
|
||||
|
||||
|
93
source/drivers/gamecube/wiisd/vdiskio.c
Normal file
93
source/drivers/gamecube/wiisd/vdiskio.c
Normal file
@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* Diskio Module
|
||||
* -------------
|
||||
*
|
||||
* This module is almost identical to the one found in ChaN's TinyFAT FS.
|
||||
* It's a logical abstration after all :)
|
||||
*
|
||||
* This covers stdio file on a SD image file
|
||||
*
|
||||
* 03/08: quickly modified by eke-eke to support Wii Front SD
|
||||
****************************************************************************/
|
||||
#include <gccore.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sdio.h"
|
||||
#include "vfat.h"
|
||||
|
||||
#define CARDIO_ERROR_READY 0
|
||||
|
||||
|
||||
/* End of not so public exports */
|
||||
|
||||
/****************************************************************************
|
||||
* DISKIO_Init
|
||||
*
|
||||
* Initialise communication with the disc
|
||||
****************************************************************************/
|
||||
int DISKIO_Init( int drive )
|
||||
{
|
||||
int res;
|
||||
|
||||
if ( drive < 0 || drive > 1 )
|
||||
return FS_ERR_PARAM;
|
||||
|
||||
res = sd_init();
|
||||
|
||||
if ( res == CARDIO_ERROR_READY )
|
||||
return FS_SUCCESS;
|
||||
|
||||
return FS_ERR_IO;
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DISKIO_ReadSectors
|
||||
*
|
||||
* Read sectors from the disc
|
||||
****************************************************************************/
|
||||
int DISKIO_ReadSectors( int drive, void *buffer, int sector, int count )
|
||||
{
|
||||
int res = -1;
|
||||
int i;
|
||||
int bytes = 0;
|
||||
|
||||
if ( drive != 0 && drive != 1 )
|
||||
return FS_ERR_PARAM; /* Must be 0 or 1 */
|
||||
|
||||
/* libOGC appears to only read in single sectors */
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
res = sd_read(sector + i, buffer + bytes);
|
||||
if ( res != CARDIO_ERROR_READY )
|
||||
return FS_ERR_IO;
|
||||
bytes += SECTOR_SIZE;
|
||||
}
|
||||
|
||||
if ( res == CARDIO_ERROR_READY )
|
||||
return FS_SUCCESS;
|
||||
|
||||
return FS_ERR_IO;
|
||||
|
||||
}
|
||||
|
36
source/drivers/gamecube/wiisd/vdiskio.h
Normal file
36
source/drivers/gamecube/wiisd/vdiskio.h
Normal file
@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* Diskio Module
|
||||
* -------------
|
||||
*
|
||||
* This module is almost identical to the one found in ChaN's TinyFAT FS.
|
||||
* It's a logical abstration after all :)
|
||||
*
|
||||
* This covers stdio file on a SD image file
|
||||
****************************************************************************/
|
||||
#ifndef __DISKIO__
|
||||
#define __DISKIO__
|
||||
|
||||
int DISKIO_Init( int drive );
|
||||
int DISKIO_ReadSectors( int drive, void *buffer, int sector, int count );
|
||||
|
||||
#endif
|
||||
|
924
source/drivers/gamecube/wiisd/vfat.c
Normal file
924
source/drivers/gamecube/wiisd/vfat.c
Normal file
@ -0,0 +1,924 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* $Date: 2007-08-05 14:27:48 +0100 (Sun, 05 Aug 2007) $
|
||||
* $Rev: 8 $
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "vfat.h"
|
||||
#include "vdiskio.h"
|
||||
|
||||
static BYTE sector[SECTOR_SIZE]; /**< Local sector buffer */
|
||||
static VFATFS *vfs[2]; /**< VFATFS Pointers for 2 drives */
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Z E R O S E C T O R / B I O S P A R A M E T E R B L O C K
|
||||
*
|
||||
* These functions take care of parsing the 0th sector/BPB
|
||||
* Supports SuperFloppy Format and standard partitioning.
|
||||
*
|
||||
*/
|
||||
|
||||
/**\defgroup INTERNALS VFATFS Private Functions
|
||||
* \brief These are internal helper functions and should
|
||||
* not be called by an application!\n
|
||||
* They are documented here for convenience only.
|
||||
*/
|
||||
|
||||
/**\ingroup INTERNALS
|
||||
* \brief Check for BIOS Parameter Block
|
||||
* \param sector 512 byte sector data
|
||||
* \return FS_TYPE_FAT16 on success
|
||||
*/
|
||||
static int BPBCheck( BYTE *sector )
|
||||
{
|
||||
BPB16 *bpb = (BPB16 *)sector;
|
||||
|
||||
/* Check signatures */
|
||||
if ( ( bpb->sigkey1 == 0x55 ) && ( bpb->sigkey2 == 0xAA ) )
|
||||
{
|
||||
/* Check for FAT16 signature */
|
||||
if ( memcmp(bpb->FilSysType, "FAT16", 5) == 0 )
|
||||
return FS_TYPE_FAT16;
|
||||
/* Non MS utilities simply put FAT */
|
||||
if ( memcmp(bpb->FilSysType, "FAT", 3) == 0 )
|
||||
return FS_TYPE_FAT16;
|
||||
}
|
||||
|
||||
return FS_TYPE_NONE;
|
||||
}
|
||||
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Partition Entry Check
|
||||
* \param sector 512 byte sector data
|
||||
* \return Partition Start LBA on success
|
||||
*/
|
||||
static unsigned int PECheck( BYTE *sector )
|
||||
{
|
||||
int i;
|
||||
PARTENTRY *pe;
|
||||
|
||||
if ( ( sector[SECTOR_SIZE-2] == 0x55 ) && ( sector[SECTOR_SIZE-1] == 0xAA ) )
|
||||
{
|
||||
/* Find a FAT16 partition entry */
|
||||
for( i = 0; i < 4; i++ )
|
||||
{
|
||||
pe = (PARTENTRY *)(sector + 446 + (i<<4));
|
||||
if ( pe->partitiontype == 0x06 )
|
||||
{
|
||||
return SWAP32(pe->partitionstart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FS_TYPE_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_Mount
|
||||
*
|
||||
* Function to mount a FAT16-VFAT volume
|
||||
***************************************************************************/
|
||||
int VFAT_mount( int driveid, VFATFS *v )
|
||||
{
|
||||
int ret;
|
||||
unsigned int bpbsector = 0;
|
||||
BPB16 *bpb = (BPB16 *)sector;
|
||||
BYTE media = 0;
|
||||
|
||||
if ( driveid < 0 || driveid > 1 )
|
||||
return FS_TYPE_NONE;
|
||||
|
||||
memset(v, 0, sizeof(VFATFS));
|
||||
|
||||
/* Copy pointer */
|
||||
vfs[driveid] = v;
|
||||
|
||||
if ( DISKIO_Init( driveid ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
if ( DISKIO_ReadSectors( driveid, sector, 0, 1 ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
/* Check for SuperFloppy Format */
|
||||
ret = BPBCheck( sector );
|
||||
|
||||
if ( ret == FS_TYPE_NONE )
|
||||
{
|
||||
/* Check for Partition Entry */
|
||||
bpbsector = PECheck(sector);
|
||||
if ( !bpbsector )
|
||||
return FS_TYPE_NONE;
|
||||
|
||||
if ( DISKIO_ReadSectors( driveid, sector, bpbsector, 1 ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
/* Check BPB */
|
||||
ret = BPBCheck( sector );
|
||||
}
|
||||
|
||||
if ( ret == FS_TYPE_FAT16 )
|
||||
{
|
||||
/* Capture defaults to machine native format */
|
||||
v->BaseOffset = bpbsector;
|
||||
v->BytesPerSector = SWAP16(bpb->bytesPerSec);
|
||||
v->SectorsPerFAT = SWAP16(bpb->FATsz16);
|
||||
v->ReservedSectors = SWAP16(bpb->reservedSec);
|
||||
v->NumberOfFATs = bpb->numFATs;
|
||||
v->SectorsPerCluster = bpb->secPerClust;
|
||||
v->RootDirEntries = SWAP16(bpb->rootEntCount);
|
||||
|
||||
/* Calculate number of root directory sectors */
|
||||
v->RootDirSectors = ( ( SWAP16(bpb->rootEntCount) << 5 ) + ( v->BytesPerSector - 1 ) ) / v->BytesPerSector;
|
||||
|
||||
/* First data sector */
|
||||
v->FirstDataSector = v->ReservedSectors + (v->NumberOfFATs * v->SectorsPerFAT) + v->RootDirSectors + v->BaseOffset;
|
||||
|
||||
/* Total sectors */
|
||||
if ( bpb->totSec16 == 0 )
|
||||
v->TotalSectors = SWAP32(bpb->totSec32);
|
||||
else
|
||||
v->TotalSectors = SWAP16(bpb->totSec16);
|
||||
|
||||
/* Data Sectors */
|
||||
v->DataSectors = v->TotalSectors - ( v->ReservedSectors + ( v->NumberOfFATs * v->SectorsPerFAT ) + v->RootDirSectors );
|
||||
|
||||
/* Count of clusters */
|
||||
v->CountOfClusters = v->DataSectors / bpb->secPerClust;
|
||||
|
||||
/* From v1.03 Document - Page 14 - FAT Type Determination */
|
||||
if ( v->CountOfClusters < 4085 )
|
||||
return FS_TYPE_NONE; /* FAT12 Volume */
|
||||
else
|
||||
{
|
||||
if ( v->CountOfClusters >= 65525 )
|
||||
return FS_TYPE_NONE; /* FAT32 Volume */
|
||||
}
|
||||
|
||||
/* Root Directory Offset */
|
||||
v->RootDirOffset = v->ReservedSectors + ( bpb->numFATs * v->SectorsPerFAT ) + v->BaseOffset;
|
||||
|
||||
/* First copy of FAT offset */
|
||||
v->FirstFATOffset = v->ReservedSectors + v->BaseOffset;
|
||||
|
||||
media = bpb->media;
|
||||
|
||||
/* Read first FAT */
|
||||
if ( DISKIO_ReadSectors( driveid, sector, v->FirstFATOffset, 1 ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
if ( sector[0] == media )
|
||||
{
|
||||
/* Allocate work spaces */
|
||||
v->FAT = (WORD *)malloc(v->SectorsPerFAT * SECTOR_SIZE);
|
||||
if ( v->FAT == NULL )
|
||||
return FS_ERR_NOMEM;
|
||||
|
||||
/* Save time running in and out - just load up the FAT table */
|
||||
if ( DISKIO_ReadSectors(driveid, v->FAT, v->FirstFATOffset, v->SectorsPerFAT) != FS_SUCCESS )
|
||||
{
|
||||
free(v->FAT);
|
||||
return FS_ERR_IO;
|
||||
}
|
||||
|
||||
/* Likewise, the same for the root directory */
|
||||
v->rootDir = (BYTE *)malloc(v->BytesPerSector * v->RootDirSectors);
|
||||
if ( v->rootDir == NULL )
|
||||
{
|
||||
free(v->FAT);
|
||||
return FS_ERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Read root directory */
|
||||
if ( DISKIO_ReadSectors(driveid, v->rootDir, v->RootDirOffset, v->RootDirSectors) != FS_SUCCESS )
|
||||
{
|
||||
free(v->FAT);
|
||||
free(v->rootDir);
|
||||
return FS_ERR_IO;
|
||||
}
|
||||
return FS_TYPE_FAT16;
|
||||
}
|
||||
}
|
||||
|
||||
return FS_TYPE_NONE;
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_unmount
|
||||
*
|
||||
* Release memory allocated by from a mounted VFATFS
|
||||
****************************************************************************/
|
||||
void VFAT_unmount( int driveid, VFATFS *v )
|
||||
{
|
||||
if ( v->FAT != NULL )
|
||||
free(v->FAT);
|
||||
|
||||
if ( v->rootDir != NULL )
|
||||
free(v->rootDir);
|
||||
|
||||
vfs[driveid] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* F I L E N A M I N G S U P P O R T
|
||||
*
|
||||
* Routines to en/decode long and short file names
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* CalcShortNameChecksum
|
||||
*
|
||||
* Calculate the checksum for a short filename
|
||||
* Filename should be in UPPER case, and padded with spaces to match
|
||||
* a standard directory entry
|
||||
****************************************************************************/
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Calculate the checksum of a short directory name
|
||||
* \param fname 11 character, space padded short directory name
|
||||
* \return checksum
|
||||
*/
|
||||
static unsigned char CalcShortNameCheckSum( BYTE *fname )
|
||||
{
|
||||
int i;
|
||||
unsigned char sum = 0;
|
||||
|
||||
for( i = 0; i < 11; i++ )
|
||||
sum = ( ( sum & 1 ) ? 0x80 : 0 ) + ( sum >> 1 ) + fname[i];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* BuildShortNameFromDirEntry
|
||||
*
|
||||
* User friendly shortname
|
||||
****************************************************************************/
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Convert a short directory entry to an application friendly name
|
||||
* \param sfn SFNDIRREC pointer
|
||||
* \param out Buffer to hold converted file name
|
||||
* \return None
|
||||
*/
|
||||
static void BuildShortNameFromDirEntry( SFNDIRREC *sfn, BYTE *out )
|
||||
{
|
||||
int i,j;
|
||||
|
||||
for(i = 0, j = 0; i < 11; i++ )
|
||||
{
|
||||
if ( sfn->dirname[i] != 32 )
|
||||
{
|
||||
out[j++] = sfn->dirname[i];
|
||||
}
|
||||
|
||||
if ( (i == 7) && ( sfn->dirname[8] != 32 ) )
|
||||
out[j++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* BuildLongNameFromDirEntry
|
||||
*
|
||||
* Build a long name from unicode to asciiz.
|
||||
* Each directory entry may contain up to 13 characters for sub entry.
|
||||
****************************************************************************/
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Build a long file name as ASCIIZ
|
||||
* \param lfn LFNDIRREC pointer
|
||||
* \param position LFN directory record number
|
||||
* \param out Output buffer
|
||||
* \return None.
|
||||
*/
|
||||
static void BuildLongNameFromDirEntry( LFNDIRREC *lfn, int position, BYTE *out )
|
||||
{
|
||||
int j = ( ( position - 1 ) * 13 );
|
||||
int i;
|
||||
|
||||
/* Part one */
|
||||
for( i = 0; i < 10; i += 2 )
|
||||
{
|
||||
if ( lfn->dirname1[i] == 0xFF )
|
||||
return;
|
||||
|
||||
out[j++] = lfn->dirname1[i];
|
||||
}
|
||||
|
||||
/* Part two */
|
||||
for( i = 0; i < 12; i += 2 )
|
||||
{
|
||||
if ( lfn->dirname2[i] == 0xFF )
|
||||
return;
|
||||
|
||||
out[j++] = lfn->dirname2[i];
|
||||
}
|
||||
|
||||
/* Part three */
|
||||
for( i = 0; i < 4; i += 2 )
|
||||
{
|
||||
if ( lfn->dirname3[i] == 0xFF )
|
||||
return;
|
||||
|
||||
out[j++] = lfn->dirname3[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* D I R E C T O R Y F U N C T I O N S
|
||||
*
|
||||
* These routines take care of all directory level parsing
|
||||
*/
|
||||
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Retrieve first sector number of a cluster
|
||||
* \param drive Device drive number
|
||||
* \param cluster Cluster number to determine first sector of
|
||||
* \return First sector of cluster
|
||||
*/
|
||||
static int SectorFromCluster( int drive, int cluster )
|
||||
{
|
||||
VFATFS *v = vfs[drive];
|
||||
return ( ( cluster - 2 ) * v->SectorsPerCluster ) + v->FirstDataSector;
|
||||
}
|
||||
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Read a complete cluster
|
||||
* \param d FSDIRENTRY pointer. CurrentCluster is used
|
||||
* \return FS_SUCCESS on success
|
||||
*/
|
||||
static int ReadCluster( FSDIRENTRY *d )
|
||||
{
|
||||
int sector;
|
||||
|
||||
sector = SectorFromCluster( d->driveid, d->CurrentCluster );
|
||||
if ( DISKIO_ReadSectors( d->driveid, d->clusterdata, sector, vfs[d->driveid]->SectorsPerCluster) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
d->CachedCluster = d->CurrentCluster;
|
||||
return FS_SUCCESS;
|
||||
}
|
||||
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Update entry with next cluster in chain
|
||||
* \param d FSDIRENTRY pointer. CurrentCluster is used
|
||||
* \return True on success
|
||||
*/
|
||||
static int NextCluster( FSDIRENTRY *d )
|
||||
{
|
||||
d->CurrentCluster = SWAP16(vfs[d->driveid]->FAT[d->CurrentCluster]);
|
||||
if ( d->CurrentCluster >= CLUSTER_END_CHAIN )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* FindEntry
|
||||
*
|
||||
* Look through a directory tree looking for an active entry.
|
||||
* The current cluster should be available in d->clusterdata
|
||||
****************************************************************************/
|
||||
/** \ingroup INTERNALS
|
||||
* \param d FSDIRENTRY pointer
|
||||
* \param maxentries Maximum directory entries held in cluster
|
||||
* \return True if found, False if not found
|
||||
*/
|
||||
static int FindEntry( FSDIRENTRY *d, int maxentries )
|
||||
{
|
||||
int found = 0;
|
||||
unsigned char *direntry;
|
||||
VFATFS *v = vfs[d->driveid];
|
||||
SFNDIRREC *sfn;
|
||||
LFNDIRREC *lfn;
|
||||
static BYTE checksum = 0;
|
||||
|
||||
if ( !d->crosscluster )
|
||||
{
|
||||
/* Clear names */
|
||||
memset(d->shortname, 0, 13);
|
||||
memset(d->longname, 0, MAX_LONG_NAME);
|
||||
}
|
||||
|
||||
while( d->CurrentDirEntry < maxentries && !found )
|
||||
{
|
||||
/* Pointer to this directory entry */
|
||||
if ( d->CurrentCluster == ROOTCLUSTER )
|
||||
direntry = (v->rootDir + ( d->CurrentDirEntry << 5 ) );
|
||||
else
|
||||
direntry = (d->clusterdata + ( d->CurrentDirEntry << 5 ) );
|
||||
|
||||
switch( direntry[0] )
|
||||
{
|
||||
case 0x00:
|
||||
case 0xE5:
|
||||
break; /* Inactive entries */
|
||||
|
||||
default:
|
||||
|
||||
sfn = (SFNDIRREC *)direntry;
|
||||
d->crosscluster = 1;
|
||||
|
||||
if ( ( sfn->attribute & ATTR_LONG_NAME_MASK ) == ATTR_LONG_NAME )
|
||||
{
|
||||
if ( direntry[0] & LFN_LAST_ENTRY )
|
||||
memset(&d->longname, 0, MAX_LONG_NAME);
|
||||
|
||||
lfn = (LFNDIRREC *)direntry;
|
||||
BuildLongNameFromDirEntry( lfn, direntry[0] & LFN_ENTRY_MASK, d->longname);
|
||||
checksum = lfn->checksum;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Short name entry */
|
||||
found = 1;
|
||||
memcpy(&d->dirent, direntry, 32);
|
||||
BuildShortNameFromDirEntry( sfn, d->shortname );
|
||||
d->fsize = SWAP32(sfn->filesize);
|
||||
d->crosscluster = 0;
|
||||
/* Ensure long name is populated with something */
|
||||
if ( strlen((char *)d->longname) == 0 )
|
||||
{
|
||||
strcpy((char *)d->longname, (char *)d->shortname);
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If checksums don't match - the FS is inconsistent
|
||||
To do no harm, skip this entry */
|
||||
if ( checksum == CalcShortNameCheckSum(sfn->dirname) )
|
||||
return found;
|
||||
else
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d->CurrentDirEntry++;
|
||||
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* FindInRootDirectory
|
||||
*
|
||||
* Root directory is somewhat special. It's a fixed length and has no entry
|
||||
* in the FAT as such.
|
||||
*
|
||||
* Logically, this should be the first 2 clusters, but the spec says it can
|
||||
* be set to any size by the format utility (Think NT! FAT64/128/256)
|
||||
*
|
||||
* For speed, as all searches begin here, the root directory is held in
|
||||
* memory throughout.
|
||||
*
|
||||
* FSDIRENTRY should only have the drive id set.
|
||||
****************************************************************************/
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Find an entry in the root directory
|
||||
* \param d FSDIRENTRY pointer
|
||||
* \param search Name to find
|
||||
* \return True if found, False if not
|
||||
*/
|
||||
static int FindInRootDirectory( FSDIRENTRY *d, char *search )
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
d->CurrentDirEntry++;
|
||||
|
||||
while( (FindEntry(d, vfs[d->driveid]->RootDirEntries)) && !found )
|
||||
{
|
||||
if ( strcasecmp(search, (char *) d->shortname) == 0 )
|
||||
{
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if ( strcasecmp(search, (char *) d->longname) == 0 )
|
||||
{
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
d->CurrentDirEntry++;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* FindInClusters
|
||||
*
|
||||
* Generic routine to find a given name in a chain of clusters.
|
||||
* Used for non-Root Directory searching
|
||||
****************************************************************************/
|
||||
/** \ingroup INTERNALS
|
||||
* \brief Find a directory record in a cluster chain
|
||||
* \param d FSDIRENTRY pointer
|
||||
* \param findme Name of directory record to find
|
||||
* \return True if found, False if not
|
||||
*/
|
||||
static int FindInClusters( FSDIRENTRY *d, char *findme )
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
if ( d->CurrentDirEntry == -1 )
|
||||
d->CurrentDirEntry = 0;
|
||||
|
||||
/* While not at end of chain */
|
||||
while( !found && ( d->CurrentCluster < CLUSTER_END_CHAIN ) )
|
||||
{
|
||||
/* Retrieve dir entries looking for match */
|
||||
while( !found && (FindEntry( d, ( vfs[d->driveid]->BytesPerSector * vfs[d->driveid]->SectorsPerCluster) >> 5 ) ) )
|
||||
{
|
||||
if ( strcasecmp((char *)d->shortname, findme) == 0 )
|
||||
found = 1;
|
||||
if ( strcasecmp((char *)d->longname, findme) == 0 )
|
||||
found = 1;
|
||||
|
||||
if (!found)
|
||||
d->CurrentDirEntry++;
|
||||
}
|
||||
|
||||
/* Read next cluster */
|
||||
if ( !found )
|
||||
{
|
||||
if ( NextCluster(d) )
|
||||
{
|
||||
d->CurrentDirEntry = 0;
|
||||
ReadCluster(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_opendir
|
||||
*
|
||||
* Find the requested directory.
|
||||
****************************************************************************/
|
||||
int VFAT_opendir( int drive, FSDIRENTRY *d, char *search )
|
||||
{
|
||||
char *p;
|
||||
char srchtmp[1024];
|
||||
int searchroot = 1;
|
||||
int found = 0;
|
||||
|
||||
/* Clear out FSDIRENTRY */
|
||||
memset(d, 0, sizeof(FSDIRENTRY));
|
||||
|
||||
/* Set drive and root */
|
||||
d->driveid = drive;
|
||||
d->CurrentCluster = ROOTCLUSTER;
|
||||
d->CurrentDirEntry = -1;
|
||||
|
||||
/* Is this a request for root ? */
|
||||
if ( ( strlen(search) == 0 ) || ( strcmp(search,PSEPS) == 0 ) || ( strcmp(search, DIR_ROOT) == 0 ) )
|
||||
{
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
|
||||
/* Searching for a sub-directory */
|
||||
if ( search[0] == PSEP )
|
||||
strcpy(srchtmp, &search[1]);
|
||||
else
|
||||
strcpy(srchtmp, search);
|
||||
|
||||
p = strtok(srchtmp, PSEPS);
|
||||
while ( p )
|
||||
{
|
||||
found = 0;
|
||||
if ( searchroot )
|
||||
{
|
||||
if ( !FindInRootDirectory(d, p) )
|
||||
return FS_NO_FILE;
|
||||
else
|
||||
{
|
||||
/* MUST be a directory */
|
||||
if ( d->dirent.attribute & ATTR_DIRECTORY )
|
||||
{
|
||||
d->CurrentCluster = d->FirstCluster = SWAP16(d->dirent.fstClustLow);
|
||||
d->CurrentDirEntry = -1;
|
||||
|
||||
/* Allocate the cluster for this data record */
|
||||
d->clusterdata = (BYTE *)malloc(vfs[d->driveid]->SectorsPerCluster * vfs[d->driveid]->BytesPerSector);
|
||||
ReadCluster(d);
|
||||
found = 1;
|
||||
searchroot = 0;
|
||||
}
|
||||
else
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( FindInClusters( d, p ) )
|
||||
{
|
||||
/* MUST be a directory */
|
||||
if ( !( d->dirent.attribute & ATTR_DIRECTORY ) )
|
||||
{
|
||||
free(d->clusterdata);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
/* Read up this cluster */
|
||||
d->CurrentCluster = d->FirstCluster = SWAP16(d->dirent.fstClustLow);
|
||||
d->CurrentDirEntry = 0;
|
||||
ReadCluster(d);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
p = strtok(NULL, PSEPS);
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
{
|
||||
if ( d->clusterdata != NULL )
|
||||
{
|
||||
free(d->clusterdata);
|
||||
d->clusterdata = NULL;
|
||||
}
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
return FS_FILE_OK;
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_readdir
|
||||
****************************************************************************/
|
||||
int VFAT_readdir( FSDIRENTRY *d )
|
||||
{
|
||||
int ret;
|
||||
|
||||
d->CurrentDirEntry++;
|
||||
/* Are we in root ? */
|
||||
if ( d->CurrentCluster == ROOTCLUSTER )
|
||||
{
|
||||
if( FindEntry( d, vfs[d->driveid]->RootDirEntries ) )
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
while( d->CurrentCluster < CLUSTER_END_CHAIN )
|
||||
{
|
||||
ret = FindEntry( d, ( vfs[d->driveid]->BytesPerSector * vfs[d->driveid]->SectorsPerCluster) >> 5 );
|
||||
|
||||
if ( ret )
|
||||
return FS_FILE_OK;
|
||||
|
||||
if ( NextCluster(d) )
|
||||
{
|
||||
d->CurrentDirEntry = 0;
|
||||
ReadCluster(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_closedir
|
||||
****************************************************************************/
|
||||
void VFAT_closedir( FSDIRENTRY *d )
|
||||
{
|
||||
if ( d->clusterdata != NULL )
|
||||
{
|
||||
free(d->clusterdata);
|
||||
d->clusterdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fopen
|
||||
*
|
||||
* v0.1 - VFAT_READ_ONLY Supported
|
||||
****************************************************************************/
|
||||
int VFAT_fopen( int drive, FSDIRENTRY *d, char *fname, int mode )
|
||||
{
|
||||
char filename[1024];
|
||||
char path[1024];
|
||||
char temp[1024];
|
||||
char *p;
|
||||
|
||||
if ( drive < 0 || drive > 1 )
|
||||
return FS_NO_FILE;
|
||||
|
||||
if ( mode != FS_READ )
|
||||
return FS_NO_FILE;
|
||||
|
||||
/* Clear */
|
||||
memset(d, 0, sizeof(FSDIRENTRY));
|
||||
d->driveid = drive;
|
||||
|
||||
path[0] = temp[0] = filename[0] = 0;
|
||||
|
||||
if ( fname[0] == PSEP )
|
||||
strcpy(temp, &fname[1]);
|
||||
else
|
||||
strcpy(temp, fname);
|
||||
|
||||
/* Split into filename and path */
|
||||
p = strrchr(temp, PSEP);
|
||||
if ( p )
|
||||
{
|
||||
/* Have path and filename */
|
||||
*p = 0;
|
||||
strcpy(path, temp);
|
||||
p++;
|
||||
strcpy(filename, p);
|
||||
}
|
||||
else
|
||||
strcpy(filename, temp);
|
||||
|
||||
/* Do search */
|
||||
if ( strlen(path) )
|
||||
{
|
||||
if ( VFAT_opendir(drive, d, path) != FS_FILE_OK )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
if ( !FindInClusters( d, filename ) )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Much simpler check on root directory */
|
||||
d->CurrentCluster = ROOTCLUSTER;
|
||||
d->CurrentDirEntry = -1;
|
||||
if ( !FindInRootDirectory( d, filename ) )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
d->clusterdata = (BYTE *)malloc(vfs[d->driveid]->SectorsPerCluster * vfs[d->driveid]->BytesPerSector);
|
||||
}
|
||||
|
||||
/* Must be a file only */
|
||||
if ( d->dirent.attribute & ( ATTR_DIRECTORY | ATTR_VOLUME_ID ) )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
d->FirstCluster = d->CurrentCluster = SWAP16(d->dirent.fstClustLow);
|
||||
d->CachedCluster = -1;
|
||||
|
||||
return FS_FILE_OK;
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fclose
|
||||
****************************************************************************/
|
||||
void VFAT_fclose( FSDIRENTRY *d )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fread
|
||||
****************************************************************************/
|
||||
int VFAT_fread( FSDIRENTRY *d, void *buffer, int length )
|
||||
{
|
||||
int cluster;
|
||||
int tbytes;
|
||||
int umask;
|
||||
int i;
|
||||
int bytesdone = 0;
|
||||
int reallength;
|
||||
BYTE *p = (BYTE *)buffer;
|
||||
|
||||
if ( length <= 0 )
|
||||
return 0;
|
||||
|
||||
/* Determine which cluster in the chain we are in */
|
||||
tbytes = ( vfs[d->driveid]->SectorsPerCluster * vfs[d->driveid]->BytesPerSector );
|
||||
umask = tbytes - 1;
|
||||
cluster = ( d->fpos / tbytes );
|
||||
|
||||
/* Rewind current cluster */
|
||||
d->CurrentCluster = d->FirstCluster;
|
||||
|
||||
/* Bring this cluster into view */
|
||||
for ( i = 0; i < cluster; i++ )
|
||||
d->CurrentCluster = SWAP16(vfs[d->driveid]->FAT[d->CurrentCluster]);
|
||||
|
||||
/* Read the cluster */
|
||||
if ( d->CachedCluster != d->CurrentCluster )
|
||||
ReadCluster(d);
|
||||
|
||||
/* Get real read length */
|
||||
reallength = ( d->fpos + length ) < d->fsize ? length : d->fsize - d->fpos;
|
||||
|
||||
if ( reallength <= 0 )
|
||||
return 0;
|
||||
|
||||
/* Move data */
|
||||
while( reallength )
|
||||
{
|
||||
if ( !(d->fpos & umask) && ( reallength >= tbytes ) )
|
||||
{
|
||||
/* Move a full cluster */
|
||||
memcpy(p + bytesdone, d->clusterdata, tbytes);
|
||||
reallength -= tbytes;
|
||||
bytesdone += tbytes;
|
||||
d->fpos += tbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
p[bytesdone++] = d->clusterdata[d->fpos & umask];
|
||||
d->fpos++;
|
||||
reallength--;
|
||||
}
|
||||
|
||||
if ( !( d->fpos & umask ) )
|
||||
{
|
||||
if ( NextCluster(d) )
|
||||
{
|
||||
ReadCluster(d);
|
||||
}
|
||||
else
|
||||
return bytesdone;
|
||||
}
|
||||
}
|
||||
|
||||
return bytesdone;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fseek
|
||||
****************************************************************************/
|
||||
int VFAT_fseek( FSDIRENTRY *d, int where, int whence )
|
||||
{
|
||||
switch( whence )
|
||||
{
|
||||
case SEEK_SET:
|
||||
if ( ( where >= 0 ) && ( where <= d->fsize ) )
|
||||
{
|
||||
d->fpos = where;
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
if ( ( ( d->fpos + where ) >= 0 ) && ( ( d->fpos + where ) <= d->fsize ) )
|
||||
{
|
||||
d->fpos += where;
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
if ( ( where <= 0 ) && ( abs(where) <= d->fsize ) )
|
||||
{
|
||||
d->fpos = d->fsize + where;
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_ftell
|
||||
*
|
||||
* Return the current position of a file
|
||||
****************************************************************************/
|
||||
int VFAT_ftell( FSDIRENTRY *d )
|
||||
{
|
||||
return d->fpos;
|
||||
}
|
||||
|
364
source/drivers/gamecube/wiisd/vfat.h
Normal file
364
source/drivers/gamecube/wiisd/vfat.h
Normal file
@ -0,0 +1,364 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* $Date: 2007-08-05 14:27:48 +0100 (Sun, 05 Aug 2007) $
|
||||
* $Rev: 8 $
|
||||
****************************************************************************/
|
||||
#ifndef __FATVFAT__
|
||||
#define __FATVFAT__
|
||||
|
||||
#include "integer.h"
|
||||
|
||||
/* x86 type definitions */
|
||||
/**\typedef VDWORD
|
||||
* Unsigned 32 bit integer
|
||||
*/
|
||||
typedef unsigned int VDWORD;
|
||||
/**\typedef WORD
|
||||
* Unsigned 16 bit short
|
||||
*/
|
||||
//typedef unsigned short WORD;
|
||||
/**\typedef BYTE
|
||||
* Unsigned 8 bit char
|
||||
*/
|
||||
//typedef unsigned char BYTE;
|
||||
|
||||
/* Big Endian Support */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define SWAP16(a) (((a&0xff)<<8) | ((a&0xff00)>>8))
|
||||
#define SWAP32(a) (((a&0xff000000)>>24) | ((a&0xff0000) >> 8) | ((a&0xff00)<<8) |((a&0xff)<<24))
|
||||
#else
|
||||
#define SWAP16(a) (a)
|
||||
#define SWAP32(a) (a)
|
||||
#endif
|
||||
|
||||
/* General */
|
||||
/**\def SECTOR_SIZE
|
||||
* Set to sector size of device\n
|
||||
* Default is 512, which is suitable for most SD cards\n
|
||||
* All sector sizes must be a power of 2
|
||||
*/
|
||||
#define SECTOR_SIZE 512 /* Default sector is 512 bytes */
|
||||
/**\def SECTOR_SHIFT_BITS
|
||||
* Number of shift bits for faster multiplication and division
|
||||
*/
|
||||
#define SECTOR_SHIFT_BITS 9 /* Sector shift bits */
|
||||
#define LFN_LAST_ENTRY 0x40 /* Long File Name last entry mask */
|
||||
#define LFN_ENTRY_MASK 0x3F /* Long File Name entry number mask */
|
||||
#define ROOTCLUSTER 0xdeadc0de /* Unique root directory cluster id */
|
||||
|
||||
/**\def PSEP
|
||||
* Path separator. Default unix style /
|
||||
*/
|
||||
#define PSEP '/' /* Path separator. Default unix / */
|
||||
/**\def PSEPS
|
||||
* Path separator string. Default unix style /
|
||||
*/
|
||||
#define PSEPS "/" /* Path separator string. Default unix / */
|
||||
|
||||
#define DIR_ROOT "." /* Root directory entry */
|
||||
#define DIR_PARENT ".." /* Parent directory entry */
|
||||
|
||||
/* FSTYPES */
|
||||
#define FS_TYPE_NONE 0
|
||||
#define FS_TYPE_FAT16 1
|
||||
|
||||
/* Errors */
|
||||
#define FS_FILE_OK 0
|
||||
#define FS_SUCCESS FS_FILE_OK
|
||||
#define FS_ERR_NOMEM -128
|
||||
#define FS_NO_FILE -64
|
||||
#define FS_ERR_IO -32
|
||||
#define FS_ERR_PARAM -16
|
||||
|
||||
/* File modes */
|
||||
#define FS_READ 1
|
||||
|
||||
/* Gamecube Specific */
|
||||
#define FS_SLOTA 0
|
||||
#define FS_SLOTB 1
|
||||
|
||||
/* FAT12/16 */
|
||||
typedef struct
|
||||
{
|
||||
BYTE jmpBoot[3]; /**< Always 0xEBxx90 or 0xE9xxxx */
|
||||
BYTE OEMName[8]; /**< OEM Name 'MSWIN4.1' or similar */
|
||||
WORD bytesPerSec; /**< Bytes per sector */
|
||||
BYTE secPerClust; /**< Sectors per cluster */
|
||||
WORD reservedSec; /**< Reserved Sector Count */
|
||||
BYTE numFATs; /**< Number of FAT copies */
|
||||
WORD rootEntCount; /**< FAT12/16 number of root entries. */
|
||||
WORD totSec16; /**< Sector count if < 0x10000 */
|
||||
BYTE media; /**< Media ID byte (HD == 0xF8) */
|
||||
WORD FATsz16; /**< Sectors occupied by one copy of FAT */
|
||||
WORD secPerTrack; /**< Sectors per track */
|
||||
WORD numHeads; /**< Number of heads */
|
||||
VDWORD hiddenSec; /**< Hidden sector count */
|
||||
VDWORD totSec32; /**< Total sectors when >= 0x10000 */
|
||||
BYTE drvNum; /**< BIOS Drive Number (0x80) */
|
||||
BYTE reserved1; /**< Unused - always zero */
|
||||
BYTE bootSig; /**< Boot signature */
|
||||
VDWORD volID; /**< Volume serial number */
|
||||
BYTE volName[11]; /**< Volume Name */
|
||||
BYTE FilSysType[8]; /**< File system type */
|
||||
BYTE filler[SECTOR_SIZE-64]; /**< Byte padding */
|
||||
BYTE sigkey1; /**< 0x55 */
|
||||
BYTE sigkey2; /**< 0xAA */
|
||||
}
|
||||
#ifndef DOXYGEN_FIX_ATTR
|
||||
__attribute__((__packed__))
|
||||
#endif
|
||||
BPB16;
|
||||
|
||||
/* Partition entry */
|
||||
typedef struct
|
||||
{
|
||||
BYTE bootindicator; /**< Boot indicator 00 == No 0x80 == Boot */
|
||||
BYTE startCHS[3]; /**< Start Cylinder / Head / Sector */
|
||||
BYTE partitiontype; /**< Partition Type. ID 06 FAT 16 */
|
||||
BYTE endCHS[3]; /**< End Cylinder / Head / Sector */
|
||||
VDWORD partitionstart; /**< LBA Start Sector */
|
||||
VDWORD partitionsize; /**< Partition size in sectors */
|
||||
}
|
||||
#ifndef DOXYGEN_FIX_ATTR
|
||||
__attribute__((__packed__))
|
||||
#endif
|
||||
PARTENTRY;
|
||||
|
||||
/* VFAT - Main structure */
|
||||
typedef struct
|
||||
{
|
||||
VDWORD BaseOffset; /**< Offset in sectors to BPB */
|
||||
VDWORD SectorsPerCluster; /**< Sectors per cluster (Native) */
|
||||
VDWORD BytesPerSector; /**< Bytes per sector (Native) */
|
||||
VDWORD ReservedSectors; /**< Reserved sectors (Native) */
|
||||
VDWORD RootDirSectors; /**< Root directory sectors (Native) */
|
||||
VDWORD SectorsPerFAT; /**< Sectors per FAT (Native) */
|
||||
VDWORD NumberOfFATs; /**< Number of FAT copies (Native) */
|
||||
VDWORD FirstDataSector; /**< First data sector offset (Native) */
|
||||
VDWORD TotalSectors; /**< Total sectors (Native) */
|
||||
VDWORD CountOfClusters; /**< Count of clusters (Native) */
|
||||
VDWORD DataSectors; /**< Number of Data sectors (Native) */
|
||||
VDWORD RootDirOffset; /**< Offset of root directory (Native) */
|
||||
VDWORD FirstFATOffset; /**< Offset to first copy of FAT (Native) */
|
||||
VDWORD RootDirEntries; /**< Number of root directory entries (Native) */
|
||||
WORD *FAT; /**< Holds first FAT copy */
|
||||
BYTE *rootDir; /**< Holds entire root directory */
|
||||
}
|
||||
#ifndef DOXYGEN_FIX_ATTR
|
||||
__attribute__((__packed__))
|
||||
#endif
|
||||
VFATFS;
|
||||
|
||||
/*
|
||||
* Directory Functions
|
||||
*/
|
||||
|
||||
#define MAX_LONG_NAME 256
|
||||
|
||||
/* Directory entry attributes */
|
||||
#define ATTR_READ_ONLY 0x01
|
||||
#define ATTR_HIDDEN 0x02
|
||||
#define ATTR_SYSTEM 0x04
|
||||
#define ATTR_VOLUME_ID 0x08
|
||||
#define ATTR_DIRECTORY 0x10
|
||||
#define ATTR_ARCHIVE 0x20
|
||||
#define ATTR_LONG_NAME (ATTR_READ_ONLY | \
|
||||
ATTR_HIDDEN | \
|
||||
ATTR_SYSTEM | \
|
||||
ATTR_VOLUME_ID )
|
||||
|
||||
#define ATTR_LONG_NAME_MASK ( ATTR_READ_ONLY | \
|
||||
ATTR_HIDDEN | \
|
||||
ATTR_SYSTEM | \
|
||||
ATTR_VOLUME_ID | \
|
||||
ATTR_DIRECTORY | \
|
||||
ATTR_ARCHIVE )
|
||||
|
||||
/**\def CLUSTER_END_CHAIN
|
||||
* Any value equal or greater than 0xFFF8 should be
|
||||
* considered an end of chain marker.
|
||||
*/
|
||||
#define CLUSTER_END_CHAIN 0xFFF8
|
||||
|
||||
/**\def CLUSTER_BAD
|
||||
* Documentation states that any BAD or unusable sector should be marked\n
|
||||
* as 0xFFF7.
|
||||
*/
|
||||
#define CLUSTER_BAD 0xFFF7
|
||||
|
||||
/* Short file name */
|
||||
typedef struct
|
||||
{
|
||||
BYTE dirname[11]; /**< Record name */
|
||||
BYTE attribute; /**< Attributes */
|
||||
BYTE NTReserved; /**< Reserved for Windows NT - set 0 */
|
||||
BYTE dirTenthSecs; /**< Tenth of a second, 0-199 */
|
||||
WORD dirCreateTime; /**< Time of creation */
|
||||
WORD dirCreateDate; /**< Date of creation */
|
||||
WORD dirLastAccDate;/**< Date of last access */
|
||||
WORD fstClustHigh; /**< High word of first cluster - ZERO on FAT16 (LE)*/
|
||||
WORD dirWriteTime; /**< Time of last write */
|
||||
WORD dirWriteDate; /**< Date of last write */
|
||||
WORD fstClustLow; /**< Low word of first cluster (LE)*/
|
||||
VDWORD filesize; /**< Filesize in bytes (LE)*/
|
||||
}
|
||||
#ifndef DOXYGEN_FIX_ATTR
|
||||
__attribute__((__packed__))
|
||||
#endif
|
||||
SFNDIRREC;
|
||||
|
||||
/* Long file name */
|
||||
typedef struct
|
||||
{
|
||||
BYTE ordinal; /**< Entry number (0x4x) == Last entry */
|
||||
BYTE dirname1[10]; /**< First part of filename in unicode */
|
||||
BYTE attribute; /**< Attributes - MUST be ATTR_LONG_NAME (0x0F) */
|
||||
BYTE type; /**< Reserved */
|
||||
BYTE checksum; /**< SFN Checksum */
|
||||
BYTE dirname2[12]; /**< Second part of filename in unicode */
|
||||
WORD fstClustLo; /**< MUST BE ZERO! */
|
||||
BYTE dirname3[4]; /**< Third part of filename in unicode */
|
||||
}
|
||||
#ifndef DOXYGEN_FIX_ATTR
|
||||
__attribute__((__packed__))
|
||||
#endif
|
||||
LFNDIRREC;
|
||||
|
||||
/* User dir entry */
|
||||
typedef struct
|
||||
{
|
||||
BYTE longname[MAX_LONG_NAME]; /**< Long file name, application friendly */
|
||||
BYTE shortname[13]; /**< Short file name, application friendly */
|
||||
VDWORD fpos; /**< Current file position */
|
||||
VDWORD fsize; /**< File size in bytes (Native) */
|
||||
VDWORD driveid; /**< Device number */
|
||||
VDWORD FirstCluster; /**< First cluster in chain (Native) */
|
||||
VDWORD CurrentCluster; /**< Current cluster in chain (Native) */
|
||||
VDWORD CachedCluster; /**< Cached cluster (Native) */
|
||||
VDWORD CurrentDirEntry; /**< Current directory entry in current cluster (Native) */
|
||||
VDWORD crosscluster; /**< Record crosses cluster boundary */
|
||||
BYTE *clusterdata; /**< Cluster data */
|
||||
/* Now a copy of the current directory entry */
|
||||
SFNDIRREC dirent; /**< Copy of physical SFNDIRREC */
|
||||
}
|
||||
#ifndef DOXYGEN_FIX_ATTR
|
||||
__attribute__((__packed__))
|
||||
#endif
|
||||
FSDIRENTRY;
|
||||
|
||||
/* VFAT API */
|
||||
/** \defgroup VFATDir VFATFS Directory Level Functions
|
||||
* \brief VFAT FS Directory Functions
|
||||
*/
|
||||
|
||||
/* Directory */
|
||||
|
||||
/** \ingroup VFATDir
|
||||
* \brief Open a directory
|
||||
* \param drive Device number to use
|
||||
* \param d Pointer to user provided FSDIRENTRY
|
||||
* \param search Path to open
|
||||
* \return FS_SUCCESS if succesful
|
||||
*/
|
||||
int VFAT_opendir( int drive, FSDIRENTRY *d, char *search );
|
||||
|
||||
/** \ingroup VFATDir
|
||||
* \brief Read directory entries
|
||||
* \param d Pointer to user provided FSDIRENTRY, previously populated from VFAT_opendir
|
||||
* \return FS_SUCCESS if successful
|
||||
*/
|
||||
int VFAT_readdir( FSDIRENTRY *d );
|
||||
|
||||
/** \ingroup VFATDir
|
||||
* \brief Close a previously opened directory
|
||||
* \param d Pointer to user provided FSDIRENTRY, previously populated from VFAT_opendir
|
||||
* \return None.
|
||||
*/
|
||||
void VFAT_closedir( FSDIRENTRY *d );
|
||||
|
||||
/** \defgroup VFATFile VFATFS File Level Functions
|
||||
* \brief VFAT FS File functions
|
||||
*/
|
||||
|
||||
/** \ingroup VFATFile
|
||||
* \brief Open a file
|
||||
* \param drive Device number to use
|
||||
* \param d Pointer to user provided FSDIRENTRY
|
||||
* \param fname Filename, including full path, to open
|
||||
* \param mode Currently only FS_READ is supported
|
||||
* \return FS_SUCCESS if successful.
|
||||
*/
|
||||
int VFAT_fopen( int drive, FSDIRENTRY *d, char *fname, int mode );
|
||||
|
||||
/** \ingroup VFATFile
|
||||
* \brief Close a previously opened file
|
||||
* \param d Pointer to user provided FSDIRENTRY, previously populated by VFAT_fopen
|
||||
* \return None.
|
||||
*/
|
||||
void VFAT_fclose( FSDIRENTRY *d );
|
||||
|
||||
/** \ingroup VFATFile
|
||||
* \brief Read from an open file
|
||||
* \param d Pointer to user provided FSDIRENTRY, populated by a successful call to VFAT_fopen
|
||||
* \param buffer Buffer to receive data
|
||||
* \param length Number of bytes to read to the buffer
|
||||
* \return Number of bytes read if positive. If <0 an error has occurred.
|
||||
*/
|
||||
int VFAT_fread( FSDIRENTRY *d, void *buffer, int length );
|
||||
|
||||
/** \ingroup VFATFile
|
||||
* \brief Return the current file position
|
||||
* \param d Pointer to user provided FSDIRENTRY
|
||||
* \return Current file position
|
||||
*/
|
||||
int VFAT_ftell( FSDIRENTRY *d );
|
||||
|
||||
/** \ingroup VFATFile
|
||||
* \brief Move current file pointer to the requested position
|
||||
* \param d Pointer to user provided FSDIRENTRY
|
||||
* \param where New byte position
|
||||
* \param whence Define movement type. SEEK_SET, SEEK_END and SEEK_CUR are supported
|
||||
* \return FS_SUCCESS if successful
|
||||
*/
|
||||
int VFAT_fseek( FSDIRENTRY *d, int where, int whence );
|
||||
|
||||
/** \defgroup VFATMount VFATFS Device Mount Functions
|
||||
* \brief Device mount / unmount functions
|
||||
*/
|
||||
|
||||
/** \ingroup VFATMount
|
||||
* \brief Mount a device
|
||||
* \param driveid Device number to mount
|
||||
* \param v Pointer to user provided VFATFS
|
||||
* \return FS_TYPE_FAT16 on success.
|
||||
*/
|
||||
int VFAT_mount( int driveid, VFATFS *v );
|
||||
|
||||
/** \ingroup VFATMount
|
||||
* \brief Unmount a device
|
||||
* \param driveid Device drive number
|
||||
* \param v Pointer to user provided VFATFS
|
||||
* \return None
|
||||
*/
|
||||
void VFAT_unmount( int driveid, VFATFS *v );
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user