Moved disc interfaces to appropriate libraries (DLDI to libnds, SD/USB to libogc).

Changed read/write functions to use size_t and seek function to use off_t -- will help on 64 bit platforms.
Partitions no longer specified by fat1:/, fat2:/, etc.
Use "nice" device names. On GBA/NDS the default partition is still fat:/; however on Wii and GC sd:/, usb:/, etc. are used instead.
Added fsync and ftruncate functions.
Mount and unmount no longer startup/shutdown the device, this is the job of the host app.
Mount now accepts a partition start parameter.
Used standard types, eg uint32_t instead of u32.
Archive bit is set when closing/synchronizing a modified file.
Various minor bug fixes.
This commit is contained in:
Michael Chisholm 2008-11-20 05:22:28 +00:00
parent 841c1a692c
commit 2cc2cc2e39
62 changed files with 908 additions and 6057 deletions

View File

@ -17,7 +17,7 @@ include $(DEVKITARM)/gba_rules
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD ?= release
SOURCES := ../source ../source/disc_io
SOURCES := ../source
INCLUDES := ../include
DATA :=
LIB := $(TOPDIR)/gba/lib

View File

@ -24,7 +24,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@ -35,11 +34,8 @@
extern "C" {
#endif
#include "gba_types.h"
typedef enum {PI_CART_SLOT} PARTITION_INTERFACE;
struct IO_INTERFACE_STRUCT ;
#include <stdint.h>
#include "disc_io.h"
/*
Initialise any inserted block-devices.
@ -47,45 +43,36 @@ Add the fat device driver to the devoptab, making it available for standard file
cacheSize: The number of pages to allocate for each inserted block-device
setAsDefaultDevice: if true, make this the default device driver for file operations
*/
bool fatInit (u32 cacheSize, bool setAsDefaultDevice);
extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
/*
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
*/
bool fatInitDefault (void);
extern bool fatInitDefault (void);
/*
Mount the device specified by partitionNumber
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
This will mount the active partition or the first valid partition on the disc,
and will use a cache size optimized for the host system.
*/
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface);
/*
Mount a partition on a custom device
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
If startSector = 0, it will mount the active partition of the first valid partition on
the disc. Otherwise it will try to mount the partition starting at startSector.
cacheSize specifies the number of pages to allocate for the cache.
This will not startup the disc, so you need to call interface->startup(); first.
*/
bool fatMountCustomInterface (struct IO_INTERFACE_STRUCT* device, u32 cacheSize);
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
Unmount the partition specified by name.
If there are open files, it will attempt to synchronise them to disc.
*/
bool fatUnmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:
PD_DEFAULT is unallowed.
Doesn't do anything useful on GBA, since there is only one device
*/
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber);
extern void fatUnmount (const char* name);
#ifdef __cplusplus
}

View File

@ -24,15 +24,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-14
* fatInitialise renamed to fatInit
2006-07-16 - Chishm
* Added fatInitDefault
*/
@ -50,73 +41,54 @@ extern "C" {
#endif
#endif
#include <stdint.h>
#if defined(__gamecube__) || defined (__wii__)
# include <gctypes.h>
# include <ogc/disc_io.h>
#else
# ifdef NDS
# include <nds/ndstypes.h>
# include "nds/disc_io.h"
# else
# include "gba_types.h"
# include "disc_io.h"
# endif
#endif
#if defined( __wii__ )
typedef enum {PI_DEFAULT, PI_SDGECKO_A, PI_SDGECKO_B, PI_INTERNAL_SD, PI_CUSTOM, PI_MAX_PARTITIONS } PARTITION_INTERFACE;
#elif defined(__gamecube__)
typedef enum {PI_DEFAULT, PI_SDGECKO_A, PI_SDGECKO_B, PI_CUSTOM, PI_MAX_PARTITIONS } PARTITION_INTERFACE;
#elif defined(NDS)
typedef enum {PI_DEFAULT, PI_SLOT_1, PI_SLOT_2, PI_CUSTOM, PI_MAX_PARTITIONS} PARTITION_INTERFACE;
#elif defined(GBA)
typedef enum {PI_CART_SLOT, PI_MAX_PARTITIONS} PARTITION_INTERFACE;
#endif
struct IO_INTERFACE_STRUCT ;
/*
Initialise any inserted block-devices.
Add the fat device driver to the devoptab, making it available for standard file functions.
cacheSize: The number of pages to allocate for each inserted block-device
setAsDefaultDevice: if true, make this the default device driver for file operations
*/
bool fatInit (u32 cacheSize, bool setAsDefaultDevice);
extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
/*
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
*/
bool fatInitDefault (void);
extern bool fatInitDefault (void);
/*
Mount the device specified by partitionNumber
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
This will mount the active partition or the first valid partition on the disc,
and will use a cache size optimized for the host system.
*/
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface);
/*
Mount a partition on a custom device
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
If startSector = 0, it will mount the active partition of the first valid partition on
the disc. Otherwise it will try to mount the partition starting at startSector.
cacheSize specifies the number of pages to allocate for the cache.
This will not startup the disc, so you need to call interface->startup(); first.
*/
bool fatMountCustomInterface (const struct IO_INTERFACE_STRUCT* device, u32 cacheSize);
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
Unmount the partition specified by name.
If there are open files, it will attempt to synchronise them to disc.
*/
bool fatUnmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:
PD_DEFAULT is unallowed.
Doesn't do anything useful on GBA, since there is only one device
*/
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber);
extern void fatUnmount (const char* name);
#ifdef __cplusplus
}

View File

@ -22,7 +22,7 @@ endif
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD ?= wii_release
SOURCES := ../source ../source/ogc_io
SOURCES := ../source
INCLUDES := ../include
DATA :=
LIBDIR := $(TOPDIR)/libogc/lib

View File

@ -24,7 +24,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@ -35,15 +34,8 @@
extern "C" {
#endif
#include <gctypes.h>
#if defined(__wii__)
typedef enum {PI_DEFAULT, PI_SDGECKO_A, PI_SDGECKO_B, PI_INTERNAL_SD, PI_CUSTOM } PARTITION_INTERFACE;
#else
typedef enum {PI_DEFAULT, PI_SDGECKO_A, PI_SDGECKO_B, PI_CUSTOM } PARTITION_INTERFACE;
#endif
struct IO_INTERFACE_STRUCT ;
#include <stdint.h>
#include <ogc/disc_io.h>
/*
Initialise any inserted block-devices.
@ -51,45 +43,36 @@ Add the fat device driver to the devoptab, making it available for standard file
cacheSize: The number of pages to allocate for each inserted block-device
setAsDefaultDevice: if true, make this the default device driver for file operations
*/
bool fatInit (u32 cacheSize, bool setAsDefaultDevice);
extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
/*
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
*/
bool fatInitDefault (void);
extern bool fatInitDefault (void);
/*
Mount the device specified by partitionNumber
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
This will mount the active partition or the first valid partition on the disc,
and will use a cache size optimized for the host system.
*/
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface);
/*
Mount a partition on a custom device
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
If startSector = 0, it will mount the active partition of the first valid partition on
the disc. Otherwise it will try to mount the partition starting at startSector.
cacheSize specifies the number of pages to allocate for the cache.
This will not startup the disc, so you need to call interface->startup(); first.
*/
bool fatMountCustomInterface (struct IO_INTERFACE_STRUCT* device, u32 cacheSize);
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
Unmount the partition specified by name.
If there are open files, it will attempt to synchronise them to disc.
*/
bool fatUnmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:
PD_DEFAULT is unallowed.
Doesn't do anything useful on GBA, since there is only one device
*/
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber);
extern void fatUnmount (const char* name);
#ifdef __cplusplus
}

View File

@ -16,7 +16,7 @@ include $(DEVKITARM)/ds_rules
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD ?= release
SOURCES := ../source ../source/disc_io source
SOURCES := ../source source
INCLUDES := ../include
DATA :=
LIB := $(TOPDIR)/nds/lib

View File

@ -24,7 +24,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@ -37,14 +36,11 @@ extern "C" {
// When compiling for NDS, make sure NDS is defined
#ifndef NDS
#define NDS
#define NDS
#endif
#include <nds/ndstypes.h>
typedef enum {PI_DEFAULT, PI_SLOT_1, PI_SLOT_2, PI_CUSTOM} PARTITION_INTERFACE;
struct IO_INTERFACE_STRUCT ;
#include <stdint.h>
#include "nds/disc_io.h"
/*
Initialise any inserted block-devices.
@ -52,45 +48,36 @@ Add the fat device driver to the devoptab, making it available for standard file
cacheSize: The number of pages to allocate for each inserted block-device
setAsDefaultDevice: if true, make this the default device driver for file operations
*/
bool fatInit (u32 cacheSize, bool setAsDefaultDevice);
extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
/*
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
*/
bool fatInitDefault (void);
extern bool fatInitDefault (void);
/*
Mount the device specified by partitionNumber
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
This will mount the active partition or the first valid partition on the disc,
and will use a cache size optimized for the host system.
*/
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface);
/*
Mount a partition on a custom device
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
You can then access the filesystem using "name:/".
If startSector = 0, it will mount the active partition of the first valid partition on
the disc. Otherwise it will try to mount the partition starting at startSector.
cacheSize specifies the number of pages to allocate for the cache.
This will not startup the disc, so you need to call interface->startup(); first.
*/
bool fatMountCustomInterface (struct IO_INTERFACE_STRUCT* device, u32 cacheSize);
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
Unmount the partition specified by name.
If there are open files, it will attempt to synchronise them to disc.
*/
bool fatUnmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:
PD_DEFAULT is unallowed.
Doesn't do anything useful on GBA, since there is only one device
*/
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber);
extern void fatUnmount (const char* name);
#ifdef __cplusplus
}

View File

@ -17,8 +17,8 @@ int nitroFSDirNext(struct _reent *r, DIR_ITER *dirState, char *filename, struct
int nitroFSDirClose(struct _reent *r, DIR_ITER *dirState);
int nitroFSOpen(struct _reent *r, void *fileStruct, const char *path,int flags,int mode);
int nitroFSClose(struct _reent *r,int fd);
int nitroFSRead(struct _reent *r,int fd,char *ptr,int len);
int nitroFSSeek(struct _reent *r,int fd,int pos,int dir);
ssize_t nitroFSRead(struct _reent *r,int fd,char *ptr,size_t len);
off_t nitroFSSeek(struct _reent *r,int fd,off_t pos,int dir);
int nitroFSFstat(struct _reent *r,int fd,struct stat *st);
#define LOADERSTR "PASS" //look for this
@ -81,9 +81,9 @@ devoptab_t nitroFSdevoptab={
sizeof(struct nitroFSStruct), // int structSize;
&nitroFSOpen, // int (*open_r)(struct _reent *r, void *fileStruct, const char *path,int flags,int mode);
&nitroFSClose, // int (*close_r)(struct _reent *r,int fd);
NULL, // int (*write_r)(struct _reent *r,int fd,const char *ptr,int len);
&nitroFSRead, // int (*read_r)(struct _reent *r,int fd,char *ptr,int len);
&nitroFSSeek, // int (*seek_r)(struct _reent *r,int fd,int pos,int dir);
NULL, // ssize_t (*write_r)(struct _reent *r,int fd,const char *ptr,size_t len);
&nitroFSRead, // ssize_t (*read_r)(struct _reent *r,int fd,char *ptr,size_t len);
&nitroFSSeek, // off_t (*seek_r)(struct _reent *r,int fd,off_t pos,int dir);
&nitroFSFstat, // int (*fstat_r)(struct _reent *r,int fd,struct stat *st);
NULL, // int (*stat_r)(struct _reent *r,const char *file,struct stat *st);
NULL, // int (*link_r)(struct _reent *r,const char *existing, const char *newLink);
@ -97,8 +97,11 @@ devoptab_t nitroFSdevoptab={
&nitroFSDirOpen, // DIR_ITER* (*diropen_r)(struct _reent *r, DIR_ITER *dirState, const char *path);
&nitroDirReset, // int (*dirreset_r)(struct _reent *r, DIR_ITER *dirState);
&nitroFSDirNext, // int (*dirnext_r)(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
&nitroFSDirClose // int (*dirclose_r)(struct _reent *r, DIR_ITER *dirState);
&nitroFSDirClose, // int (*dirclose_r)(struct _reent *r, DIR_ITER *dirState);
NULL, // int (*statvfs_r)(struct _reent *r, const char *path, struct statvfs *buf);
NULL, // int (*ftruncate_r)(struct _reent *r, int fd, off_t len);
NULL, // int (*fsync_r)(struct _reent *r, int fd);
NULL, // void *deviceData;
};
//inline these mebbe? these 4 'sub' functions deal with actually reading from either gba rom or .nds file :)
@ -340,7 +343,7 @@ int nitroFSClose(struct _reent *r,int fd) {
return(nitroSubClose(&((struct nitroFSStruct *)fd)->nrs));
}
int nitroFSRead(struct _reent *r,int fd,char *ptr,int len) {
ssize_t nitroFSRead(struct _reent *r,int fd,char *ptr,size_t len) {
struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd;
struct nitroRawStruct *nrs=&((struct nitroFSStruct *)fd)->nrs;
if(nrs->pos+len > fatStruct->end)
@ -350,7 +353,7 @@ int nitroFSRead(struct _reent *r,int fd,char *ptr,int len) {
return(nitroSubRead(nrs,ptr,len));
}
int nitroFSSeek(struct _reent *r,int fd,int pos,int dir) {
off_t nitroFSSeek(struct _reent *r,int fd ,off_t pos,int dir) {
//need check for eof here...
struct nitroFSStruct *fatStruct=(struct nitroFSStruct *)fd;
struct nitroRawStruct *nrs=&((struct nitroFSStruct *)fd)->nrs;

View File

@ -24,35 +24,34 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _BIT_OPS_H
#define _BIT_OPS_H
#include <stdint.h>
/*-----------------------------------------------------------------
Functions to deal with little endian values stored in u8 arrays
Functions to deal with little endian values stored in uint8_t arrays
-----------------------------------------------------------------*/
static inline u16 u8array_to_u16 (const u8* item, int offset) {
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset) {
return ( item[offset] | (item[offset + 1] << 8));
}
static inline u32 u8array_to_u32 (const u8* item, int offset) {
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset) {
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
}
static inline void u16_to_u8array (u8* item, int offset, u16 value) {
item[offset] = (u8)value;
item[offset + 1] = (u8)(value >> 8);
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value) {
item[offset] = (uint8_t) value;
item[offset + 1] = (uint8_t)(value >> 8);
}
static inline void u32_to_u8array (u8* item, int offset, u32 value) {
item[offset] = (u8)value;
item[offset + 1] = (u8)(value >> 8);
item[offset + 2] = (u8)(value >> 16);
item[offset + 3] = (u8)(value >> 24);
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value) {
item[offset] = (uint8_t) value;
item[offset + 1] = (uint8_t)(value >> 8);
item[offset + 2] = (uint8_t)(value >> 16);
item[offset + 3] = (uint8_t)(value >> 24);
}
#endif // _BIT_OPS_H

View File

@ -31,13 +31,10 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2007-11-14 - Chishm
* Fixed _FAT_cache_constructor to return NULL on error, not false
* Fixed _FAT_cache_flush to return false on error. With thanks to xorloser
*/
#include <string.h>
#include <limits.h>
#include "common.h"
#include "cache.h"
@ -46,11 +43,11 @@
#include "mem_allocate.h"
#include "bit_ops.h"
#define CACHE_FREE 0xFFFFFFFF
#define CACHE_FREE UINT_MAX
CACHE* _FAT_cache_constructor (u32 numberOfPages, const IO_INTERFACE* discInterface) {
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE* discInterface) {
CACHE* cache;
u32 i;
unsigned int i;
CACHE_ENTRY* cacheEntries;
if (numberOfPages < 2) {
@ -80,7 +77,7 @@ CACHE* _FAT_cache_constructor (u32 numberOfPages, const IO_INTERFACE* discInterf
cache->cacheEntries = cacheEntries;
cache->pages = (u8*) _FAT_mem_allocate ( CACHE_PAGE_SIZE * numberOfPages);
cache->pages = (uint8_t*) _FAT_mem_allocate ( CACHE_PAGE_SIZE * numberOfPages);
if (cache->pages == NULL) {
_FAT_mem_free (cache->cacheEntries);
_FAT_mem_free (cache);
@ -107,13 +104,13 @@ Retrieve a sector's page from the cache. If it is not found in the cache,
load it into the cache and return the page it was loaded to.
Return CACHE_FREE on error.
*/
static u32 _FAT_cache_getSector (CACHE* cache, u32 sector) {
u32 i;
static unsigned int _FAT_cache_getSector (CACHE* cache, sec_t sector) {
unsigned int i;
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
u32 numberOfPages = cache->numberOfPages;
unsigned int numberOfPages = cache->numberOfPages;
u32 leastUsed = 0;
u32 lowestCount = 0xFFFFFFFF;
unsigned int leastUsed = 0;
unsigned int lowestCount = UINT_MAX;
for (i = 0; (i < numberOfPages) && (cacheEntries[i].sector != sector); i++) {
// While searching for the desired sector, also search for the leased used page
@ -153,8 +150,8 @@ static u32 _FAT_cache_getSector (CACHE* cache, u32 sector) {
/*
Reads some data from a cache page, determined by the sector number
*/
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, u32 sector, u32 offset, u32 size) {
u32 page;
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size) {
unsigned int page;
if (offset + size > BYTES_PER_READ) {
return false;
@ -168,8 +165,8 @@ bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, u32 sector, u32 o
return true;
}
bool _FAT_cache_readLittleEndianValue (CACHE* cache, u32 *value, u32 sector, u32 offset, u32 num_bytes) {
u8 buf[4];
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
uint8_t buf[4];
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
switch(num_bytes) {
@ -184,8 +181,8 @@ bool _FAT_cache_readLittleEndianValue (CACHE* cache, u32 *value, u32 sector, u32
/*
Writes some data to a cache page, making sure it is loaded into memory first.
*/
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size) {
u32 page;
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) {
unsigned int page;
if (offset + size > BYTES_PER_READ) {
return false;
@ -202,8 +199,8 @@ bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, u32 sector
return true;
}
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const u32 value, u32 sector, u32 offset, u32 size) {
u8 buf[4] = {0, 0, 0, 0};
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
uint8_t buf[4] = {0, 0, 0, 0};
switch(size) {
case 1: buf[0] = value; break;
@ -218,8 +215,8 @@ bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const u32 value, u32 secto
/*
Writes some data to a cache page, zeroing out the page first
*/
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size) {
u32 page;
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) {
unsigned int page;
if (offset + size > BYTES_PER_READ) {
return false;
@ -243,7 +240,7 @@ Flushes all dirty pages to disc, clearing the dirty flag.
Also resets all pages' page count to 0.
*/
bool _FAT_cache_flush (CACHE* cache) {
u32 i;
unsigned int i;
for (i = 0; i < cache->numberOfPages; i++) {
if (cache->cacheEntries[i].dirty) {
@ -259,7 +256,7 @@ bool _FAT_cache_flush (CACHE* cache) {
}
void _FAT_cache_invalidate (CACHE* cache) {
int i;
unsigned int i;
for (i = 0; i < cache->numberOfPages; i++) {
cache->cacheEntries[i].sector = CACHE_FREE;
cache->cacheEntries[i].count = 0;

View File

@ -31,9 +31,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _CACHE_H
@ -45,16 +42,16 @@
#define CACHE_PAGE_SIZE BYTES_PER_READ
typedef struct {
u32 sector;
u32 count;
sec_t sector;
unsigned int count;
bool dirty;
} CACHE_ENTRY;
typedef struct {
const IO_INTERFACE* disc;
u32 numberOfPages;
const DISC_INTERFACE* disc;
unsigned int numberOfPages;
CACHE_ENTRY* cacheEntries;
u8* pages;
uint8_t* pages;
} CACHE;
@ -65,43 +62,43 @@ offset is the position to start reading from
size is the amount of data to read
Precondition: offset + size <= BYTES_PER_READ
*/
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, u32 sector, u32 offset, u32 size);
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size);
bool _FAT_cache_readLittleEndianValue (CACHE* cache, u32 *value, u32 sector, u32 offset, u32 num_bytes);
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes);
/*
Write data to a sector in the cache
If the sector is not in the cache, it will be swapped in.
When the sector is swapped out, the data will be written to the disc
offset is the position to start reading from
size is the amount of data to read
offset is the position to start writing to
size is the amount of data to write
Precondition: offset + size <= BYTES_PER_READ
*/
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size);
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const u32 value, u32 sector, u32 offset, u32 num_bytes);
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes);
/*
Write data to a sector in the cache, zeroing the sector first
If the sector is not in the cache, it will be swapped in.
When the sector is swapped out, the data will be written to the disc
offset is the position to start reading from
size is the amount of data to read
offset is the position to start writing to
size is the amount of data to write
Precondition: offset + size <= BYTES_PER_READ
*/
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size);
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
/*
Read a full sector from the cache
*/
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, u32 sector) {
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) {
return _FAT_cache_readPartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
}
/*
Write a full sector to the cache
*/
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, u32 sector) {
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) {
return _FAT_cache_writePartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
}
@ -115,7 +112,7 @@ Clear out the contents of the cache without writing any dirty sectors first
*/
void _FAT_cache_invalidate (CACHE* cache);
CACHE* _FAT_cache_constructor (u32 numberOfPages, const IO_INTERFACE* discInterface);
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE* discInterface);
void _FAT_cache_destructor (CACHE* cache);

View File

@ -24,14 +24,16 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _COMMON_H
#define _COMMON_H
#define BYTES_PER_READ 512
#include <fat.h>
#include <stddef.h>
#include <stdint.h>
// When compiling for NDS, make sure NDS is defined
#ifndef NDS
#if defined ARM9 || defined ARM7
@ -39,24 +41,34 @@
#endif
#endif
// Platform specific includes
#if defined(__gamecube__) || defined (__wii__)
#include <gctypes.h>
#else
# ifdef NDS
#include <ogc/disc_io.h>
#include <gccore.h>
#elif defined(NDS)
#include <nds/ndstypes.h>
#include <nds/system.h>
# else
#include "gba_types.h"
# endif
#include <nds/disc_io.h>
#elif defined(GBA)
#include <gba_types.h>
#include <disc_io.h>
#endif
#define BYTES_PER_READ 512
#ifndef NULL
#define NULL 0
// Platform specific options
#if defined (__wii__)
#define DEFAULT_CACHE_PAGES 8
#define USE_LWP_LOCK
#define USE_RTC_TIME
#elif defined (__gamecube__)
#define DEFAULT_CACHE_PAGES 8
#define USE_LWP_LOCK
#define USE_RTC_TIME
#elif defined (NDS)
#define DEFAULT_CACHE_PAGES 8
#define USE_RTC_TIME
#elif defined (GBA)
#define DEFAULT_CACHE_PAGES 2
#endif
#include <fat.h>
#endif // _COMMON_H

View File

@ -25,47 +25,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-14 - Chishm
* entryFromPath correctly finds "" and "." now
2006-08-17 - Chishm
* entryFromPath doesn't look for "" anymore - use "." to refer to the current directory
2006-08-19 - Chishm
* Fixed entryFromPath bug when looking for "." in root directory
2006-10-01 - Chishm
* Now clears the whole new cluster when linking in more clusters for a directory
2006-10-28 - Chishm
* stat returns the hostType for the st_dev value
2007-03-14 - Chishm
* Check long file names for buffer overflow
2007-04-22 - Chishm
* Added space to list of illegal alias characters - fixes filename creation bug when filename contained a space
2007-09-01 - Chishm
* Use CLUSTER_ERROR when an error occurs with the FAT, not CLUSTER_FREE
2007-11-01 - Chishm
* Added unicode support
2007-11-04 - Chishm
* Fixed alias creation bugs
2007-11-16 - Chishm
* Fixed LFN creation with character codes > 0x7F
2008-08-02 - Chishm
* Correct cluster given on FAT32 when .. entry is included in path to subdirectory
* Fixed creation of long filename entry for all-caps filenames longer than 8 characters
2008-09-07 - Chishm
* Don't read high 16 bits of start cluster from a directory entry on non-FAT32 partititions, in case it contains non-zero data
* Thanks to Chris Liu
*/
#include <string.h>
@ -73,6 +32,7 @@
#include <wchar.h>
#include <wctype.h>
#include <stdlib.h>
#include <stdio.h>
#include "directory.h"
#include "common.h"
@ -125,8 +85,8 @@ Returns -1 if it is an invalid LFN
*/
#define ABOVE_UCS_RANGE 0xF0
static int _FAT_directory_lfnLength (const char* name) {
u32 i;
u32 nameLength;
unsigned int i;
size_t nameLength;
int ucsLength;
const char* tempName = name;
@ -185,7 +145,7 @@ static size_t _FAT_directory_mbstoucs2 (ucs2_t* dst, const char* src, size_t len
/*
Convert a UCS-2 string into a NUL-terminated multibyte string, storing at most len chars
return number of chars stored
return number of chars stored, or (size_t)-1 on error
*/
static size_t _FAT_directory_ucs2tombs (char* dst, const ucs2_t* src, size_t len) {
mbstate_t ps = {0};
@ -194,7 +154,7 @@ static size_t _FAT_directory_ucs2tombs (char* dst, const ucs2_t* src, size_t len
char buff[MB_CUR_MAX];
int i;
while (count < len - 1 && src != '\0') {
while (count < len - 1 && *src != '\0') {
bytes = wcrtomb (buff, *src, &ps);
if (bytes < 0) {
return -1;
@ -233,7 +193,7 @@ static int _FAT_directory_mbsncasecmp (const char* s1, const char* s2, size_t le
s2 += b2;
b1 = mbrtowc(&wc1, s1, MB_CUR_MAX, &ps1);
b2 = mbrtowc(&wc2, s2, MB_CUR_MAX, &ps2);
if (b1 < 0 || b2 < 0) {
if ((int)b1 < 0 || (int)b2 < 0) {
break;
}
len1 -= b1;
@ -276,7 +236,7 @@ static bool _FAT_directory_entryGetAlias (const u8* entryData, char* destName) {
return (destName[0] != '\0');
}
u32 _FAT_directory_entryGetCluster (PARTITION* partition, const u8* entryData) {
uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData) {
if (partition->filesysType == FS_FAT32) {
// Only use high 16 bits of start cluster when we are certain they are correctly defined
return u8array_to_u16(entryData,DIR_ENTRY_cluster) | (u8array_to_u16(entryData, DIR_ENTRY_clusterHigh) << 16);
@ -286,9 +246,8 @@ u32 _FAT_directory_entryGetCluster (PARTITION* partition, const u8* entryData) {
}
static bool _FAT_directory_incrementDirEntryPosition (PARTITION* partition, DIR_ENTRY_POSITION* entryPosition, bool extendDirectory) {
DIR_ENTRY_POSITION position;
position = *entryPosition;
u32 tempCluster;
DIR_ENTRY_POSITION position = *entryPosition;
uint32_t tempCluster;
// Increment offset, wrapping at the end of a sector
++ position.offset;
@ -323,17 +282,12 @@ static bool _FAT_directory_incrementDirEntryPosition (PARTITION* partition, DIR_
bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry) {
DIR_ENTRY_POSITION entryStart;
DIR_ENTRY_POSITION entryEnd;
u8 entryData[0x20];
uint8_t entryData[0x20];
ucs2_t lfn[MAX_LFN_LENGTH];
bool notFound, found;
u32 maxSectors;
int lfnPos;
u8 lfnChkSum, chkSum;
uint8_t lfnChkSum, chkSum;
bool lfnExists;
int i;
lfnChkSum = 0;
@ -347,13 +301,6 @@ bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry) {
entryEnd = entryStart;
// Can only be FAT16_ROOT_DIR_CLUSTER if it is the root directory on a FAT12 or FAT16 partition
if (entryStart.cluster == FAT16_ROOT_DIR_CLUSTER) {
maxSectors = partition->dataStart - partition->rootDirStart;
} else {
maxSectors = partition->sectorsPerCluster;
}
lfnExists = false;
found = false;
@ -364,7 +311,9 @@ bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry) {
notFound = true;
}
_FAT_cache_readPartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, entryEnd.cluster) + entryEnd.sector, entryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
_FAT_cache_readPartialSector (partition->cache, entryData,
_FAT_fat_clusterToSector(partition, entryEnd.cluster) + entryEnd.sector,
entryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
if (entryData[DIR_ENTRY_attributes] == ATTRIB_LFN) {
// It's an LFN
@ -412,7 +361,7 @@ bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry) {
}
if (lfnExists) {
if (_FAT_directory_ucs2tombs (entry->filename, lfn, MAX_FILENAME_LENGTH) < 0) {
if (_FAT_directory_ucs2tombs (entry->filename, lfn, MAX_FILENAME_LENGTH) == (size_t)-1) {
// Failed to convert the file name to UTF-8. Maybe the wrong locale is set?
return false;
}
@ -436,7 +385,7 @@ bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry) {
}
}
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster) {
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster) {
entry->dataStart.cluster = dirCluster;
entry->dataStart.sector = 0;
entry->dataStart.offset = -1; // Start before the beginning of the directory
@ -469,19 +418,14 @@ bool _FAT_directory_getRootEntry (PARTITION* partition, DIR_ENTRY* entry) {
}
bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry) {
DIR_ENTRY_POSITION entryStart;
DIR_ENTRY_POSITION entryEnd;
entryStart = entry->dataStart;
entryEnd = entry->dataEnd;
DIR_ENTRY_POSITION entryStart = entry->dataStart;
DIR_ENTRY_POSITION entryEnd = entry->dataEnd;
bool entryStillValid;
bool finished;
ucs2_t lfn[MAX_LFN_LENGTH];
int i;
int lfnPos;
u8 entryData[DIR_ENTRY_DATA_SIZE];
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
memset (entry->filename, '\0', MAX_FILENAME_LENGTH);
@ -525,7 +469,7 @@ bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry) {
}
} else {
// Encode the long file name into a multibyte string
if (_FAT_directory_ucs2tombs (entry->filename, lfn, MAX_FILENAME_LENGTH) < 0) {
if (_FAT_directory_ucs2tombs (entry->filename, lfn, MAX_FILENAME_LENGTH) == (size_t)-1) {
return false;
}
}
@ -539,11 +483,9 @@ bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const
size_t dirnameLength;
const char* pathPosition;
const char* nextPathPosition;
u32 dirCluster;
uint32_t dirCluster;
bool foundFile;
char alias[MAX_ALIAS_LENGTH];
bool found, notFound;
pathPosition = path;
@ -659,14 +601,11 @@ bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const
}
bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry) {
DIR_ENTRY_POSITION entryStart;
DIR_ENTRY_POSITION entryEnd;
entryStart = entry->dataStart;
entryEnd = entry->dataEnd;
DIR_ENTRY_POSITION entryStart = entry->dataStart;
DIR_ENTRY_POSITION entryEnd = entry->dataEnd;
bool entryStillValid;
bool finished;
u8 entryData[DIR_ENTRY_DATA_SIZE];
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
// Create an empty directory entry to overwrite the old ones with
for ( entryStillValid = true, finished = false;
@ -688,14 +627,11 @@ bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry) {
return true;
}
static bool _FAT_directory_findEntryGap (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster, u32 size) {
static bool _FAT_directory_findEntryGap (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster, size_t size) {
DIR_ENTRY_POSITION gapStart;
DIR_ENTRY_POSITION gapEnd;
u8 entryData[DIR_ENTRY_DATA_SIZE];
u32 dirEntryRemain;
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
size_t dirEntryRemain;
bool endOfDirectory, entryStillValid;
// Scan Dir for free entry
@ -763,11 +699,11 @@ static bool _FAT_directory_findEntryGap (PARTITION* partition, DIR_ENTRY* entry,
return true;
}
static bool _FAT_directory_entryExists (PARTITION* partition, const char* name, u32 dirCluster) {
static bool _FAT_directory_entryExists (PARTITION* partition, const char* name, uint32_t dirCluster) {
DIR_ENTRY tempEntry;
bool foundFile;
char alias[MAX_ALIAS_LENGTH];
u32 dirnameLength;
size_t dirnameLength;
dirnameLength = strnlen(name, MAX_FILENAME_LENGTH);
@ -835,7 +771,7 @@ static int _FAT_directory_createAlias (char* alias, const char* lfn) {
lfnPos += bytesUsed;
continue;
}
if (oemChar == WEOF) {
if (oemChar == EOF) {
oemChar = '_'; // Replace unconvertable characters with underscores
lossyConversion = true;
}
@ -882,7 +818,7 @@ static int _FAT_directory_createAlias (char* alias, const char* lfn) {
lfnExt += bytesUsed;
continue;
}
if (oemChar == WEOF) {
if (oemChar == EOF) {
oemChar = '_'; // Replace unconvertable characters with underscores
lossyConversion = true;
}
@ -910,14 +846,14 @@ static int _FAT_directory_createAlias (char* alias, const char* lfn) {
}
}
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster) {
u32 entrySize;
u8 lfnEntry[DIR_ENTRY_DATA_SIZE];
s32 i,j; // Must be signed for use when decrementing in for loop
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster) {
size_t entrySize;
uint8_t lfnEntry[DIR_ENTRY_DATA_SIZE];
int i,j; // Must be signed for use when decrementing in for loop
char *tmpCharPtr;
DIR_ENTRY_POSITION curEntryPos;
bool entryStillValid;
u8 aliasCheckSum = 0;
uint8_t aliasCheckSum = 0;
char alias [MAX_ALIAS_LENGTH];
int aliasLen;
int lfnLen;
@ -938,7 +874,7 @@ bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirClu
entry->filename[i] = '\0';
}
// Remove leading spaces
for (i = 0; (i < strlen (entry->filename)) && (entry->filename[i] == ' '); ++i) ;
for (i = 0; (i < (int)strlen (entry->filename)) && (entry->filename[i] == ' '); ++i) ;
if (i > 0) {
memmove (entry->filename, entry->filename + i, strlen (entry->filename + i));
}
@ -1060,7 +996,7 @@ bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirClu
{
if (i > 1) {
// Long filename entry
lfnEntry[LFN_offset_ordinal] = (i - 1) | (i == entrySize ? LFN_END : 0);
lfnEntry[LFN_offset_ordinal] = (i - 1) | ((size_t)i == entrySize ? LFN_END : 0);
for (j = 0; j < 13; j++) {
if (lfn [(i - 2) * 13 + j] == '\0') {
if ((j > 1) && (lfn [(i - 2) * 13 + (j-1)] == '\0')) {

View File

@ -25,16 +25,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2007-11-01 - Chishm
* Added unicode support
2008-09-07 - Chishm
* Don't read high 16 bits of start cluster from a directory entry on non-FAT32 partititions, in case it contains non-zero data
* Thanks to Chris Liu
*/
#ifndef _DIRECTORY_H
@ -70,13 +60,13 @@
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
typedef struct {
u32 cluster;
u32 sector;
s32 offset;
uint32_t cluster;
sec_t sector;
int32_t offset;
} DIR_ENTRY_POSITION;
typedef struct {
u8 entryData[DIR_ENTRY_DATA_SIZE];
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
char filename[MAX_FILENAME_LENGTH];
@ -121,7 +111,7 @@ Places result in entry
entry will be destroyed even if no directory entry is found
Returns true on success, false on failure
*/
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster);
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
/*
Reads the next directory entry after the one already pointed to by entry
@ -161,12 +151,12 @@ The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are
updated with the new directory entry position and alias.
Returns true on success, false on failure
*/
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster);
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
/*
Get the start cluster of a file from it's entry data
*/
u32 _FAT_directory_entryGetCluster (PARTITION* partition, const u8* entryData);
uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData);
/*
Fill in the file name and entry data of DIR_ENTRY* entry.

View File

@ -25,81 +25,28 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _DISC_H
#define _DISC_H
#include "common.h"
//----------------------------------------------------------------------
// Customisable features
// Use DMA to read the card, remove this line to use normal reads/writes
// #define _IO_USE_DMA
// Allow buffers not alligned to 16 bits when reading files.
// Note that this will slow down access speed, so only use if you have to.
// It is also incompatible with DMA
#define _IO_ALLOW_UNALIGNED
#if defined _IO_USE_DMA && defined _IO_ALLOW_UNALIGNED
#error "You can't use both DMA and unaligned memory"
#endif
#define DEVICE_TYPE_WII 0
#define DEVICE_TYPE_GC 1
#define FEATURE_MEDIUM_CANREAD 0x00000001
#define FEATURE_MEDIUM_CANWRITE 0x00000002
#define FEATURE_SLOT_GBA 0x00000010
#define FEATURE_SLOT_NDS 0x00000020
#define FEATURE_GAMECUBE_SLOTA 0x00000010
#define FEATURE_GAMECUBE_SLOTB 0x00000020
typedef bool (* FN_MEDIUM_STARTUP)(void) ;
typedef bool (* FN_MEDIUM_ISINSERTED)(void) ;
typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u32 numSectors, void* buffer) ;
typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u32 numSectors, const void* buffer) ;
typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ;
typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ;
struct IO_INTERFACE_STRUCT {
unsigned long ioType ;
unsigned long features ;
FN_MEDIUM_STARTUP fn_startup ;
FN_MEDIUM_ISINSERTED fn_isInserted ;
FN_MEDIUM_READSECTORS fn_readSectors ;
FN_MEDIUM_WRITESECTORS fn_writeSectors ;
FN_MEDIUM_CLEARSTATUS fn_clearStatus ;
FN_MEDIUM_SHUTDOWN fn_shutdown ;
} ;
typedef struct IO_INTERFACE_STRUCT IO_INTERFACE ;
/*
Search for a block based device in all available slots.
Return a pointer to a usable interface if one is found,
NULL if not.
A list of all default devices to try at startup,
terminated by a {NULL,NULL} entry.
*/
extern const IO_INTERFACE* _FAT_disc_findInterface (void);
/*
Search for a block based device in a specific slot.
Return a pointer to a usable interface if one is found,
NULL if not.
*/
extern const IO_INTERFACE* _FAT_disc_findInterfaceSlot (PARTITION_INTERFACE partitionNumber);
typedef struct {
const char* name;
const DISC_INTERFACE* (*getInterface)(void);
} INTERFACE_ID;
extern const INTERFACE_ID _FAT_disc_interfaces[];
/*
Check if a disc is inserted
Return true if a disc is inserted and ready, false otherwise
*/
static inline bool _FAT_disc_isInserted (const IO_INTERFACE* disc) {
return disc->fn_isInserted();
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc) {
return disc->isInserted();
}
/*
@ -108,8 +55,8 @@ numSectors is between 1 and 256
sector is from 0 to 2^28
buffer is a pointer to the memory to fill
*/
static inline bool _FAT_disc_readSectors (const IO_INTERFACE* disc, u32 sector, u32 numSectors, void* buffer) {
return disc->fn_readSectors (sector, numSectors, buffer);
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer) {
return disc->readSectors (sector, numSectors, buffer);
}
/*
@ -118,43 +65,43 @@ numSectors is between 1 and 256
sector is from 0 to 2^28
buffer is a pointer to the memory to read from
*/
static inline bool _FAT_disc_writeSectors (const IO_INTERFACE* disc, u32 sector, u32 numSectors, const void* buffer) {
return disc->fn_writeSectors (sector, numSectors, buffer);
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer) {
return disc->writeSectors (sector, numSectors, buffer);
}
/*
Reset the card back to a ready state
*/
static inline bool _FAT_disc_clearStatus (const IO_INTERFACE* disc) {
return disc->fn_clearStatus();
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc) {
return disc->clearStatus();
}
/*
Initialise the disc to a state ready for data reading or writing
*/
static inline bool _FAT_disc_startup (const IO_INTERFACE* disc) {
return disc->fn_startup();
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc) {
return disc->startup();
}
/*
Put the disc in a state ready for power down.
Complete any pending writes and disable the disc if necessary
*/
static inline bool _FAT_disc_shutdown (const IO_INTERFACE* disc) {
return disc->fn_shutdown();
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc) {
return disc->shutdown();
}
/*
Return a 32 bit value unique to each type of interface
*/
static inline u32 _FAT_disc_hostType (const IO_INTERFACE* disc) {
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc) {
return disc->ioType;
}
/*
Return a 32 bit value that specifies the capabilities of the disc
*/
static inline u32 _FAT_disc_features (const IO_INTERFACE* disc) {
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc) {
return disc->features;
}

View File

@ -1,210 +0,0 @@
/*
disc.c
uniformed io-interface to work with Chishm's FAT library
Written by MightyMax
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2005-11-06 - Chishm
* Added WAIT_CR modifications for NDS
2006-02-03 www.neoflash.com
* Added SUPPORT_* defines, comment out any of the SUPPORT_* defines in disc_io.h to remove support
for the given interface and stop code being linked to the binary
* Added support for MK2 MMC interface
* Added disc_Cache* functions
2006-02-05 - Chishm
* Added Supercard SD support
2006-02-26 - Cytex
* Added EFA2 support
2006-05-18 - Chishm
* Rewritten for FATlib disc.c
2006-06-19 - Chishm
* Changed read and write interface to accept a u32 instead of a u8 for the number of sectors
2006-07-11 - Chishm
* Removed disc_Cache* functions, since there is now a proper unified cache
* Removed SUPPORT_* defines
* Rewrote device detection functions
* First libfat release
2006-07-25 - Chishm
* Changed IO_INTERFACEs to const
2006-08-02 - Chishm
* Added NinjaDS
2006-12-25 - Chishm
* Added DLDI
* Removed experimental interfaces
2007-05-01 - Chishm
* Removed FCSR
*/
#include "../disc.h"
#ifdef NDS
#include <nds.h>
#endif
#include <fat.h>
// Include known io-interfaces:
#include "io_dldi.h"
#include "io_njsd.h"
#include "io_nmmc.h"
#include "io_mpcf.h"
#include "io_m3cf.h"
#include "io_sccf.h"
#include "io_scsd.h"
#include "io_m3sd.h"
const IO_INTERFACE* ioInterfaces[] = {
&_io_dldi, // Reserved for new interfaces
#ifdef NDS
// Place Slot 1 (DS Card) interfaces here
&_io_njsd, &_io_nmmc,
#endif
// Place Slot 2 (GBA Cart) interfaces here
&_io_mpcf, &_io_m3cf, &_io_sccf, &_io_scsd, &_io_m3sd
};
/*
Hardware level disc funtions
*/
const IO_INTERFACE* _FAT_disc_gbaSlotFindInterface (void)
{
// If running on an NDS, make sure the correct CPU can access
// the GBA cart. First implemented by SaTa.
#ifdef NDS
#ifdef ARM9
sysSetCartOwner(BUS_OWNER_ARM9);
#endif
#endif
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if ((ioInterfaces[i]->features & FEATURE_SLOT_GBA) && (ioInterfaces[i]->fn_startup())) {
return ioInterfaces[i];
}
}
return NULL;
}
#ifdef NDS
/*
* Check the DS card slot for a valid memory card interface
* If an interface is found, it is set as the default interace
* and it returns true. Otherwise the default interface is left
* untouched and it returns false.
*/
const IO_INTERFACE* _FAT_disc_dsSlotFindInterface (void)
{
#ifdef ARM9
sysSetCardOwner(BUS_OWNER_ARM9);
#endif
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if ((ioInterfaces[i]->features & FEATURE_SLOT_NDS) && (ioInterfaces[i]->fn_startup())) {
return ioInterfaces[i];
}
}
return NULL;
}
#endif
/*
* When running on an NDS, check the either slot for a valid memory
* card interface.
* When running on a GBA, call _FAT_disc_gbaSlotFindInterface
* If an interface is found, it is set as the default interace
* and it returns true. Otherwise the default interface is left
* untouched and it returns false.
*/
#ifdef NDS
const IO_INTERFACE* _FAT_disc_findInterface (void)
{
#ifdef ARM9
sysSetBusOwners(BUS_OWNER_ARM9, BUS_OWNER_ARM9);
#endif
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if (ioInterfaces[i]->fn_startup()) {
return ioInterfaces[i];
}
}
return NULL;
}
#else
const IO_INTERFACE* _FAT_disc_findInterface (void)
{
return _FAT_disc_gbaSlotFindInterface();
}
#endif
const IO_INTERFACE* _FAT_disc_findInterfaceSlot (PARTITION_INTERFACE partitionNumber)
{
#ifdef NDS
switch (partitionNumber) {
case PI_SLOT_1:
// Mount the disc in slot 1
return _FAT_disc_dsSlotFindInterface ();
break;
case PI_SLOT_2:
// Mount the disc in slot 2
return _FAT_disc_gbaSlotFindInterface ();
break;
case PI_DEFAULT:
case PI_CUSTOM:
default:
// Anything else has to be handled specially
return NULL;
break;
}
#else
return _FAT_disc_gbaSlotFindInterface ();
#endif
}

View File

@ -1,322 +0,0 @@
/*
io_cf_common.c based on
compact_flash.c
By chishm (Michael Chisholm)
Common hardware routines for using a compact flash card. This is not reentrant
and does not do range checking on the supplied addresses. This is designed to
be as fast as possible.
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_cf_common.h"
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
//---------------------------------------------------------------
// CF Addresses & Commands
CF_REGISTERS cfRegisters = {0};
/*-----------------------------------------------------------------
_CF_isInserted
Is a compact flash card inserted?
bool return OUT: true if a CF card is inserted
-----------------------------------------------------------------*/
bool _CF_isInserted (void) {
// Change register, then check if value did change
*(cfRegisters.status) = CF_STS_INSERTED;
return ((*(cfRegisters.status) & 0xff) == CF_STS_INSERTED);
}
/*-----------------------------------------------------------------
_CF_clearStatus
Tries to make the CF card go back to idle mode
bool return OUT: true if a CF card is idle
-----------------------------------------------------------------*/
bool _CF_clearStatus (void) {
int i;
// Wait until CF card is finished previous commands
i=0;
while ((*(cfRegisters.command) & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT)) {
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*(cfRegisters.status) & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT)) {
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
return true;
}
/*-----------------------------------------------------------------
_CF_readSectors
Read 512 byte sector numbered "sector" into "buffer"
u32 sector IN: address of first 512 byte sector on CF card to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer OUT: pointer to 512 byte buffer to store data in
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _CF_readSectors (u32 sector, u32 numSectors, void* buffer) {
int i;
u16 *buff = (u16*)buffer;
#ifdef _IO_ALLOW_UNALIGNED
u8 *buff_u8 = (u8*)buffer;
int temp;
#endif
#if (defined _IO_USE_DMA) && (defined NDS) && (defined ARM9)
DC_FlushRange( buffer, j * BYTES_PER_READ);
#endif
// Wait until CF card is finished previous commands
i=0;
while ((*(cfRegisters.command) & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT)) {
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*(cfRegisters.status) & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT)) {
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Set number of sectors to read
*(cfRegisters.sectorCount) = (numSectors < 256 ? numSectors : 0); // Read a maximum of 256 sectors, 0 means 256
// Set read sector
*(cfRegisters.lba1) = sector & 0xFF; // 1st byte of sector number
*(cfRegisters.lba2) = (sector >> 8) & 0xFF; // 2nd byte of sector number
*(cfRegisters.lba3) = (sector >> 16) & 0xFF; // 3rd byte of sector number
*(cfRegisters.lba4) = ((sector >> 24) & 0x0F )| CF_CMD_LBA; // last nibble of sector number
// Set command to read
*(cfRegisters.command) = CF_CMD_READ;
while (numSectors--)
{
// Wait until card is ready for reading
i = 0;
while (((*(cfRegisters.status) & 0xff)!= CF_STS_READY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Read data
#ifdef _IO_USE_DMA
#ifdef NDS
DMA3_SRC = (u32)(cfRegisters.data);
DMA3_DEST = (u32)buff;
DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_SRC_FIX;
#else
DMA3COPY ( (cfRegisters.data), buff, 256 | DMA16 | DMA_ENABLE | DMA_SRC_FIXED);
#endif
buff += BYTES_PER_READ / 2;
#elif defined _IO_ALLOW_UNALIGNED
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--)
{
temp = *(cfRegisters.data);
*buff_u8++ = temp & 0xFF;
*buff_u8++ = temp >> 8;
}
} else {
while(i--)
*buff++ = *(cfRegisters.data);
}
#else
i=256;
while(i--)
*buff++ = *(cfRegisters.data);
#endif
}
#if (defined _IO_USE_DMA) && (defined NDS)
// Wait for end of transfer before returning
while(DMA3_CR & DMA_BUSY);
#endif
return true;
}
/*-----------------------------------------------------------------
_CF_writeSectors
Write 512 byte sector numbered "sector" from "buffer"
u32 sector IN: address of 512 byte sector on CF card to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer IN: pointer to 512 byte buffer to read data from
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _CF_writeSectors (u32 sector, u32 numSectors, void* buffer) {
int i;
u16 *buff = (u16*)buffer;
#ifdef _IO_ALLOW_UNALIGNED
u8 *buff_u8 = (u8*)buffer;
int temp;
#endif
#if defined _IO_USE_DMA && defined NDS && defined ARM9
DC_FlushRange( buffer, j * BYTES_PER_READ);
#endif
// Wait until CF card is finished previous commands
i=0;
while ((*(cfRegisters.command) & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*(cfRegisters.status) & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Set number of sectors to write
*(cfRegisters.sectorCount) = (numSectors < 256 ? numSectors : 0); // Write a maximum of 256 sectors, 0 means 256
// Set write sector
*(cfRegisters.lba1) = sector & 0xFF; // 1st byte of sector number
*(cfRegisters.lba2) = (sector >> 8) & 0xFF; // 2nd byte of sector number
*(cfRegisters.lba3) = (sector >> 16) & 0xFF; // 3rd byte of sector number
*(cfRegisters.lba4) = ((sector >> 24) & 0x0F )| CF_CMD_LBA; // last nibble of sector number
// Set command to write
*(cfRegisters.command) = CF_CMD_WRITE;
while (numSectors--)
{
// Wait until card is ready for writing
i = 0;
while (((*(cfRegisters.status) & 0xff) != CF_STS_READY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Write data
#ifdef _IO_USE_DMA
#ifdef NDS
DMA3_SRC = (u32)buff;
DMA3_DEST = (u32)(cfRegisters.data);
DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_DST_FIX;
#else
DMA3COPY( buff, (cfRegisters.data), 256 | DMA16 | DMA_ENABLE | DMA_DST_FIXED);
#endif
buff += BYTES_PER_READ / 2;
#elif defined _IO_ALLOW_UNALIGNED
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--)
{
temp = *buff_u8++;
temp |= *buff_u8++ << 8;
*(cfRegisters.data) = temp;
}
} else {
while(i--)
*(cfRegisters.data) = *buff++;
}
#else
i=256;
while(i--)
*(cfRegisters.data) = *buff++;
#endif
}
#if defined _IO_USE_DMA && defined NDS
// Wait for end of transfer before returning
while(DMA3_CR & DMA_BUSY);
#endif
return true;
}
/*-----------------------------------------------------------------
_CF_shutdown
shutdown the CF interface
-----------------------------------------------------------------*/
bool _CF_shutdown(void) {
return _CF_clearStatus() ;
}
/*-----------------------------------------------------------------
_CF_startUp
Initializes the CF interface using the supplied registers
returns true if successful, otherwise returns false
-----------------------------------------------------------------*/
bool _CF_startup(const CF_REGISTERS *usableCfRegs) {
cfRegisters = *usableCfRegs;
// See if there is a read/write register
u16 temp = *(cfRegisters.lba1);
*(cfRegisters.lba1) = (~temp & 0xFF);
temp = (~temp & 0xFF);
if (!(*(cfRegisters.lba1) == temp)) {
return false;
}
// Make sure it is 8 bit
*(cfRegisters.lba1) = 0xAA55;
if (*(cfRegisters.lba1) == 0xAA55) {
return false;
}
return true;
}

View File

@ -1,78 +0,0 @@
/*
io_cf_common.h
By chishm (Michael Chisholm)
Common Compact Flash card values
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-16 - Chishm
* Combined all CF interfaces into one common set of routines
*/
#ifndef IO_CF_COMMON_H
#define IO_CF_COMMON_H
#include "../disc.h"
typedef struct {
vu16* data;
vu16* status;
vu16* command;
vu16* error;
vu16* sectorCount;
vu16* lba1;
vu16* lba2;
vu16* lba3;
vu16* lba4;
} CF_REGISTERS;
// CF Card status
#define CF_STS_INSERTED 0x50
#define CF_STS_REMOVED 0x00
#define CF_STS_READY 0x58
#define CF_STS_DRQ 0x08
#define CF_STS_BUSY 0x80
// CF Card commands
#define CF_CMD_LBA 0xE0
#define CF_CMD_READ 0x20
#define CF_CMD_WRITE 0x30
#define CF_CARD_TIMEOUT 10000000
bool _CF_isInserted (void);
bool _CF_clearStatus (void);
bool _CF_readSectors (u32 sector, u32 numSectors, void* buffer);
bool _CF_writeSectors (u32 sector, u32 numSectors, void* buffer);
bool _CF_shutdown(void);
bool _CF_startup(const CF_REGISTERS *usableCfRegs);
#endif // define IO_CF_COMMON_H

View File

@ -1,44 +0,0 @@
/*
io_dldi.h
Reserved space for post-compilation adding of an extra driver
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-12-22 - Chishm
* Original release
*/
#ifndef IO_DLDI_H
#define IO_DLDI_H
// 'DLDI'
#define DEVICE_TYPE_DLDI 0x49444C44
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_dldi ;
#endif // define IO_DLDI_H

View File

@ -1,73 +0,0 @@
@---------------------------------------------------------------------------------
.align 4
.arm
.global _io_dldi
@---------------------------------------------------------------------------------
.equ FEATURE_MEDIUM_CANREAD, 0x00000001
.equ FEATURE_MEDIUM_CANWRITE, 0x00000002
.equ FEATURE_SLOT_GBA, 0x00000010
.equ FEATURE_SLOT_NDS, 0x00000020
_dldi_start:
@---------------------------------------------------------------------------------
@ Driver patch file standard header -- 16 bytes
.word 0xBF8DA5ED @ Magic number to identify this region
.asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator)
.byte 0x01 @ Version number
.byte 0x0F @32KiB @ Log [base-2] of the size of this driver in bytes.
.byte 0x00 @ Sections to fix
.byte 0x0F @32KiB @ Log [base-2] of the allocated space in bytes.
@---------------------------------------------------------------------------------
@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes
.align 4
.asciz "Default (No interface)"
@---------------------------------------------------------------------------------
@ Offsets to important sections within the data -- 32 bytes
.align 6
.word _dldi_start @ data start
.word _dldi_end @ data end
.word 0x00000000 @ Interworking glue start -- Needs address fixing
.word 0x00000000 @ Interworking glue end
.word 0x00000000 @ GOT start -- Needs address fixing
.word 0x00000000 @ GOT end
.word 0x00000000 @ bss start -- Needs setting to zero
.word 0x00000000 @ bss end
@---------------------------------------------------------------------------------
@ IO_INTERFACE data -- 32 bytes
_io_dldi:
.ascii "DLDI" @ ioType
.word 0x00000000 @ Features
.word _DLDI_startup @
.word _DLDI_isInserted @
.word _DLDI_readSectors @ Function pointers to standard device driver functions
.word _DLDI_writeSectors @
.word _DLDI_clearStatus @
.word _DLDI_shutdown @
@---------------------------------------------------------------------------------
_DLDI_startup:
_DLDI_isInserted:
_DLDI_readSectors:
_DLDI_writeSectors:
_DLDI_clearStatus:
_DLDI_shutdown:
mov r0, #0x00 @ Return false for every function
bx lr
@---------------------------------------------------------------------------------
.align
.pool
.space (_dldi_start + 32768) - . @ Fill to 32KiB
_dldi_end:
.end
@---------------------------------------------------------------------------------

View File

@ -1,307 +0,0 @@
/*
io_efa2.c by CyteX
Based on io_mpfc.c by chishm (Michael Chisholm)
Hardware Routines for reading the NAND flash located on
EFA2 flash carts
This software is completely free. No warranty is provided.
If you use it, please give me credit and email me about your
project at cytex <at> gmx <dot> de and do not forget to also
drop chishm <at> hotmail <dot> com a line
Use with permission by Michael "Chishm" Chisholm
*/
#include "io_efa2.h"
//
// EFA2 register addresses
//
// RTC registers
#define REG_RTC_CLK (*(vu16*)0x080000c4)
#define REG_RTC_EN (*(vu16*)0x080000c8)
// "Magic" registers used for unlock/lock sequences
#define REG_EFA2_MAGIC_A (*(vu16*)0x09fe0000)
#define REG_EFA2_MAGIC_B (*(vu16*)0x08000000)
#define REG_EFA2_MAGIC_C (*(vu16*)0x08020000)
#define REG_EFA2_MAGIC_D (*(vu16*)0x08040000)
#define REG_EFA2_MAGIC_E (*(vu16*)0x09fc0000)
// NAND flash lock/unlock register
#define REG_EFA2_NAND_LOCK (*(vu16*)0x09c40000)
// NAND flash enable register
#define REG_EFA2_NAND_EN (*(vu16*)0x09400000)
// NAND flash command write register
#define REG_EFA2_NAND_CMD (*(vu8*)0x09ffffe2)
// NAND flash address/data write register
#define REG_EFA2_NAND_WR (*(vu8*)0x09ffffe0)
// NAND flash data read register
#define REG_EFA2_NAND_RD (*(vu8*)0x09ffc000)
// ID of Samsung K9K1G NAND flash chip
#define EFA2_NAND_ID 0xEC79A5C0
// first sector of udisk
#define EFA2_UDSK_START 0x40
//
// EFA2 access functions
//
// deactivate RTC ports
static inline void _EFA2_rtc_deactivate(void) {
REG_RTC_EN = 0;
}
// unlock register access
static void _EFA2_reg_unlock(void) {
REG_EFA2_MAGIC_A = 0x0d200;
REG_EFA2_MAGIC_B = 0x01500;
REG_EFA2_MAGIC_C = 0x0d200;
REG_EFA2_MAGIC_D = 0x01500;
}
// finish/lock register access
static inline void _EFA2_reg_lock(void) {
REG_EFA2_MAGIC_E = 0x1500;
}
// global reset/init/enable/unlock ?
static void _EFA2_global_unlock(void) {
_EFA2_reg_unlock();
*(vu16*)0x09880000 = 0x08000;
_EFA2_reg_lock();
}
// global lock, stealth mode
/*static void _EFA2_global_lock(void) {
// quite sure there is such a sequence, but haven't had
// a look for it upto now
}*/
// unlock NAND Flash
static void _EFA2_nand_unlock(void) {
_EFA2_reg_unlock();
REG_EFA2_NAND_LOCK = 0x01500;
_EFA2_reg_lock();
}
// lock NAND Flash
static void _EFA2_nand_lock(void) {
_EFA2_reg_unlock();
REG_EFA2_NAND_LOCK = 0x0d200;
_EFA2_reg_lock();
}
//
// Set NAND Flash chip enable and write protection bits ?
//
// val | ~CE | ~WP |
// -----+-----+-----+
// 0 | 0 | 0 |
// 1 | 1 | 0 |
// 3 | 1 | 1 |
// -----+-----+-----+
//
static void _EFA2_nand_enable(u16 val) {
_EFA2_reg_unlock();
REG_EFA2_NAND_EN = val;
_EFA2_reg_lock();
}
//
// Perform NAND reset
// NAND has to be unlocked and enabled when called
//
static inline void _EFA2_nand_reset(void) {
REG_EFA2_NAND_CMD = 0xff; // write reset command
}
//
// Read out NAND ID information, could be used for card detection
//
// | EFA2 1GBit |
// ------------------+------------+
// maker code | 0xEC |
// device code | 0x79 |
// don't care | 0xA5 |
// multi plane code | 0xC0 |
// ------------------+------------+
//
static u32 _EFA2_nand_id(void) {
u8 byte;
u32 id;
_EFA2_nand_unlock();
_EFA2_nand_enable(1);
REG_EFA2_NAND_CMD = 0x90; // write id command
REG_EFA2_NAND_WR = 0x00; // (dummy) address cycle
byte = REG_EFA2_NAND_RD; // read maker code
id = byte;
byte = REG_EFA2_NAND_RD; // read device code
id = (id << 8) | byte;
byte = REG_EFA2_NAND_RD; // read don't care
id = (id << 8) | byte;
byte = REG_EFA2_NAND_RD; // read multi plane code
id = (id << 8) | byte;
_EFA2_nand_enable(0);
_EFA2_nand_lock();
return (id);
}
//
// Start of gba_nds_fat block device description
//
/*-----------------------------------------------------------------
EFA2_clearStatus
Reads and checks NAND status information
bool return OUT: true if NAND is idle
-----------------------------------------------------------------*/
bool _EFA2_clearStatus (void)
{
// tbd: currently there is no write support, so always return
// true, there is no possibility for pending operations
return true;
}
/*-----------------------------------------------------------------
EFA2_isInserted
Checks to see if the NAND chip used by the EFA2 is present
bool return OUT: true if the correct NAND chip is found
-----------------------------------------------------------------*/
bool _EFA2_isInserted (void)
{
_EFA2_clearStatus();
return (_EFA2_nand_id() == EFA2_NAND_ID);
}
/*-----------------------------------------------------------------
EFA2_readSectors
Read "numSecs" 512 byte sectors starting from "sector" into "buffer"
No error correction, no use of spare cells, no use of R/~B signal
u32 sector IN: number of first 512 byte sector to be read
u32 numSecs IN: number of 512 byte sectors to read,
void* buffer OUT: pointer to 512 byte buffer to store data in
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _EFA2_readSectors (u32 sector, u32 numSecs, void* buffer)
{
int i;
#ifndef _IO_ALLOW_UNALIGNED
u8 byte;
u16 word;
#endif
// NAND page 0x40 (EFA2_UDSK_START) contains the MBR of the
// udisk and thus is sector 0. The original EFA2 firmware
// does never look at this, it only watches page 0x60, which
// contains the boot block of the FAT16 partition. That is
// fixed, so the EFA2 udisk must not be reformated, else
// the ARK Octopus and also the original Firmware won't be
// able to access the udisk anymore and I have to write a
// recovery tool.
u32 page = EFA2_UDSK_START + sector;
// future enhancement: wait for possible write operations to
// be finisched
if (!_EFA2_clearStatus()) return false;
_EFA2_nand_unlock();
_EFA2_nand_enable(1);
_EFA2_nand_reset();
// set NAND to READ1 operation mode and transfer page address
REG_EFA2_NAND_CMD = 0x00; // write READ1 command
REG_EFA2_NAND_WR = 0x00; // write address [7:0]
REG_EFA2_NAND_WR = (page ) & 0xff; // write address [15:8]
REG_EFA2_NAND_WR = (page >> 8 ) & 0xff; // write address[23:16]
REG_EFA2_NAND_WR = (page >> 16) & 0xff; // write address[26:24]
// Due to a bug in EFA2 design there is need to waste some cycles
// "by hand" instead the possibility to check the R/~B port of
// the NAND flash via a register. The RTC deactivation is only
// there to make sure the loop won't be optimized by the compiler
for (i=0 ; i < 3 ; i++) _EFA2_rtc_deactivate();
while (numSecs--)
{
// read page data
#ifdef _IO_ALLOW_UNALIGNED
// slow byte access to RAM, but works in principle
for (i=0 ; i < 512 ; i++)
((u8*)buffer)[i] = REG_EFA2_NAND_RD;
#else
// a bit faster, but DMA is not possible
for (i=0 ; i < 256 ; i++) {
byte = REG_EFA2_NAND_RD; // read lo-byte
word = byte;
byte = REG_EFA2_NAND_RD; // read hi-byte
word = word | (byte << 8);
((u16*)buffer)[i] = word;
}
#endif
}
_EFA2_nand_enable(0);
_EFA2_nand_lock();
return true;
}
/*-----------------------------------------------------------------
EFA2_writeSectors
Write "numSecs" 512 byte sectors starting at "sector" from "buffer"
u32 sector IN: address of 512 byte sector on card to write
u32 numSecs IN: number of 512 byte sectors to write
1 to 256 sectors can be written, 0 = 256
void* buffer IN: pointer to 512 byte buffer to read data from
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _EFA2_writeSectors (u32 sector, u8 numSecs, void* buffer)
{
// Upto now I focused on reading NAND, write operations
// will follow
return false;
}
/*-----------------------------------------------------------------
EFA2_shutdown
unload the EFA2 interface
-----------------------------------------------------------------*/
bool _EFA2_shutdown(void)
{
return _EFA2_clearStatus();
}
/*-----------------------------------------------------------------
EFA2_startUp
initializes the EFA2 card, returns true if successful,
otherwise returns false
-----------------------------------------------------------------*/
bool _EFA2_startUp(void)
{
_EFA2_global_unlock();
return (_EFA2_nand_id() == EFA2_NAND_ID);
}
/*-----------------------------------------------------------------
the actual interface structure
-----------------------------------------------------------------*/
const IO_INTERFACE _io_efa2 = {
DEVICE_TYPE_EFA2,
FEATURE_MEDIUM_CANREAD | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_EFA2_startUp,
(FN_MEDIUM_ISINSERTED)&_EFA2_isInserted,
(FN_MEDIUM_READSECTORS)&_EFA2_readSectors,
(FN_MEDIUM_WRITESECTORS)&_EFA2_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_EFA2_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_EFA2_shutdown
};

View File

@ -1,23 +0,0 @@
/*
io_efa2.h by CyteX
Based on io_mpfc.h by chishm (Michael Chisholm)
Hardware Routines for reading the NAND flash located on
EFA2 flash carts
Used with permission from Cytex.
*/
#ifndef IO_EFA2_H
#define IO_EFA2_H
// 'EFA2'
#define DEVICE_TYPE_EFA2 0x32414645
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_efa2;
#endif // define IO_EFA2_H

View File

@ -1,334 +0,0 @@
/*
io_fcsr.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for using a GBA Flash Cart and SRAM as a
block device.
The file system must be 512 byte aligned, in cart address space.
SRAM is supported.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_fcsr.h"
#include <string.h>
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
#ifdef NDS
#define SRAM_START 0x0A000000
#else
#define SRAM_START 0x0E000000
#endif
#define NO_SRAM 0xFFFFFFFF
#define FCSR 0x52534346
const char _FCSR_LabelString[] = " Chishm FAT";
u8* _FCSR_FileSysPointer = 0;
u8* _FCSR_SramSectorPointer[4] = {0,0,0,0};
u32 _FCSR_SramSectorStart[4] = {0,0,0,0};
u32 _FCSR_SramSectorEnd[4] = {0,0,0,0};
/*-----------------------------------------------------------------
_FCSR_isInserted
Is a GBA Flash Cart with a valid file system inserted?
bool return OUT: true if a GBA FC card is inserted
-----------------------------------------------------------------*/
bool _FCSR_isInserted (void)
{
bool flagFoundFileSys = false;
u32* fileSysPointer = (u32*)0x08000100; // Start at beginning of cart address space, offset by expected location of string
// Search for file system
while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys) // Only search while not at end of cart address space
{
while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
fileSysPointer += 0x40;
if ((strncmp(_FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
{
flagFoundFileSys = true;
} else {
fileSysPointer += 0x80;
}
}
return flagFoundFileSys;
}
/*-----------------------------------------------------------------
_FCSR_clearStatus
Finish any pending operations
bool return OUT: always true for GBA FC
-----------------------------------------------------------------*/
bool _FCSR_clearStatus (void)
{
return true;
}
/*-----------------------------------------------------------------
_FCSR_readSectors
Read 512 byte sector numbered "sector" into "buffer"
u32 sector IN: address of first 512 byte sector on Flash Cart to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer OUT: pointer to 512 byte buffer to store data in
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _FCSR_readSectors (u32 sector, u32 numSectors, void* buffer)
{
int i;
bool flagSramSector = false;
int readLength = numSectors * BYTES_PER_READ;
u8* src;;
u8* dst;
// Find which region this read is in
for (i = 0; (i < 4) && !flagSramSector; i++)
{
if ((sector >= _FCSR_SramSectorStart[i]) && (sector < _FCSR_SramSectorEnd[i]))
{
flagSramSector = true;
break;
}
}
// Make sure read will be completely in SRAM range if it is partially there
if ( flagSramSector && ((sector + numSectors) > _FCSR_SramSectorEnd[i]))
return false;
// Copy data to buffer
if (flagSramSector)
{
src = _FCSR_SramSectorPointer[i] + (sector - _FCSR_SramSectorStart[i]) * BYTES_PER_READ;
} else {
src = _FCSR_FileSysPointer + sector * BYTES_PER_READ;
}
dst = (u8*)buffer;
if (flagSramSector)
{
while (readLength--)
{
*dst++ = *src++;
}
} else { // Reading from Cart ROM
#ifdef _IO_USE_DMA
#ifdef NDS
#ifdef ARM9
DC_FlushRange( buffer, readLength);
#endif // ARM9
DMA3_SRC = (u32)src;
DMA3_DEST = (u32)buffer;
DMA3_CR = (readLength >> 1) | DMA_COPY_HALFWORDS;
#else // ! NDS
DMA3COPY ( src, buffer, (readLength >> 1) | DMA16 | DMA_ENABLE);
#endif // NDS
#else // !_IO_USE_DMA
memcpy (buffer, src, readLength);
#endif // _IO_USE_DMA
} // if (flagSramSector)
return true;
}
/*-----------------------------------------------------------------
_FCSR_writeSectors
Write 512 byte sector numbered "sector" from "buffer"
u32 sector IN: address of 512 byte sector on Flash Cart to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer IN: pointer to 512 byte buffer to read data from
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _FCSR_writeSectors (u32 sector, u8 numSectors, void* buffer)
{
int i;
bool flagSramSector = false;
u32 writeLength = numSectors * BYTES_PER_READ;
u8* src = (u8*) buffer;
u8* dst;
// Find which region this sector belongs in
for (i = 0; (i < 4) && !flagSramSector; i++)
{
if ((sector >= _FCSR_SramSectorStart[i]) && (sector < _FCSR_SramSectorEnd[i]))
{
flagSramSector = true;
break;
}
}
if (!flagSramSector)
return false;
// Entire write must be within an SRAM region
if ((sector + numSectors) > _FCSR_SramSectorEnd[i])
return false;
// Copy data to SRAM
dst = _FCSR_SramSectorPointer[i] + (sector - _FCSR_SramSectorStart[i]) * BYTES_PER_READ;
while (writeLength--)
{
*dst++ = *src++;
}
return true;
}
/*-----------------------------------------------------------------
_FCSR_shutdown
unload the Flash Cart interface
-----------------------------------------------------------------*/
bool _FCSR_shutdown(void)
{
int i;
if (_FCSR_clearStatus() == false)
return false;
_FCSR_FileSysPointer = 0;
for (i=0; i < 4; i++)
{
_FCSR_SramSectorPointer[i] = 0;
_FCSR_SramSectorStart[i] = 0;
_FCSR_SramSectorEnd[i] = 0;
}
return true;
}
/*-----------------------------------------------------------------
_FCSR_startUp
initializes the Flash Cart interface, returns true if successful,
otherwise returns false
-----------------------------------------------------------------*/
bool _FCSR_startUp(void)
{
bool flagFoundFileSys = false;
int i;
int SramRegionSize[4];
u8* srcByte;
u8* destByte;
u32* fileSysPointer = (u32*)0x08000100; // Start at beginning of cart address space, offset by expected location of string
// Search for file system
while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys) // Only search while not at end of cart address space
{
while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
fileSysPointer += 0x40;
if ((strncmp(_FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
{
flagFoundFileSys = true;
} else {
fileSysPointer += 0x80;
}
}
if (!flagFoundFileSys)
return false;
// Flash cart file system pointer has been found
_FCSR_FileSysPointer = (u8*)(fileSysPointer - 0x40);
// Get SRAM sector regions from header block
for (i = 0; i < 4; i++)
{
_FCSR_SramSectorStart[i] = fileSysPointer[i+4];
SramRegionSize[i] = fileSysPointer[i+8];
_FCSR_SramSectorEnd[i] = _FCSR_SramSectorStart[i] + SramRegionSize[i];
}
// Calculate SRAM region pointers
_FCSR_SramSectorPointer[0] = (u8*)(SRAM_START + 4);
for (i = 1; i < 4; i++)
{
_FCSR_SramSectorPointer[i] = _FCSR_SramSectorPointer[i-1] + (SramRegionSize[i-1] * BYTES_PER_READ);
}
// Initialise SRAM with overlay if it hasn't been done so
if ( (*((u8*)SRAM_START) != 'F') || (*((u8*)(SRAM_START+1)) != 'C') || (*((u8*)(SRAM_START+2)) != 'S') || (*((u8*)(SRAM_START+3)) != 'R') )
{
*((u8*)SRAM_START) = 'F';
*((u8*)(SRAM_START+1)) = 'C';
*((u8*)(SRAM_START+2)) = 'S';
*((u8*)(SRAM_START+3)) = 'R';
for (i = 0; i < 4; i++)
{
srcByte = _FCSR_FileSysPointer + (_FCSR_SramSectorStart[i] * BYTES_PER_READ);
destByte = _FCSR_SramSectorPointer[i];
while (srcByte < _FCSR_FileSysPointer + (_FCSR_SramSectorEnd[i] * BYTES_PER_READ) )
*destByte++ = *srcByte++;
}
}
// Get SRAM sector regions from header block
for (i = 0; i < 4; i++)
{
if (SramRegionSize[i] == 0)
{
_FCSR_SramSectorStart[i] = NO_SRAM;
_FCSR_SramSectorEnd[i] = NO_SRAM;
}
}
return true;
}
/*-----------------------------------------------------------------
the actual interface structure
-----------------------------------------------------------------*/
const IO_INTERFACE _io_fcsr = {
DEVICE_TYPE_FCSR, // 'FCSR'
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_FCSR_startUp,
(FN_MEDIUM_ISINSERTED)&_FCSR_isInserted,
(FN_MEDIUM_READSECTORS)&_FCSR_readSectors,
(FN_MEDIUM_WRITESECTORS)&_FCSR_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_FCSR_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_FCSR_shutdown
} ;

View File

@ -1,44 +0,0 @@
/*
io_fcsr.h
Hardware Routines for using a GBA Flash Cart with SRAM
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_FCSR_H
#define IO_FCSR_H
// 'FCSR'
#define DEVICE_TYPE_FCSR 0x52534346
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_fcsr ;
#endif // define IO_FCSR_H

View File

@ -1,60 +0,0 @@
/*
io_m3_common.c
Routines common to all version of the M3
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_m3_common.h"
static u16 _M3_readHalfword (u32 addr) {
return *((vu16*)addr);
}
void _M3_changeMode (u32 mode) {
_M3_readHalfword (0x08e00002);
_M3_readHalfword (0x0800000e);
_M3_readHalfword (0x08801ffc);
_M3_readHalfword (0x0800104a);
_M3_readHalfword (0x08800612);
_M3_readHalfword (0x08000000);
_M3_readHalfword (0x08801b66);
_M3_readHalfword (0x08000000 + (mode << 1));
_M3_readHalfword (0x0800080e);
_M3_readHalfword (0x08000000);
if ((mode & 0x0f) != 4) {
_M3_readHalfword (0x09000000);
} else {
_M3_readHalfword (0x080001e4);
_M3_readHalfword (0x080001e4);
_M3_readHalfword (0x08000188);
_M3_readHalfword (0x08000188);
}
}

View File

@ -1,48 +0,0 @@
/*
io_m3_common.h
Routines common to all version of the M3
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_M3_COMMON_H
#define IO_M3_COMMON_H
#include "../disc.h"
// Values for changing mode
#define M3_MODE_ROM 0x00400004
#define M3_MODE_MEDIA 0x00400003
extern void _M3_changeMode (u32 mode);
#endif // IO_M3_COMMON_H

View File

@ -1,96 +0,0 @@
/*
io_m3cf.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for reading a compact flash card
using the M3 Perfect CF Adapter
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_m3cf.h"
#include "io_m3_common.h"
#include "io_cf_common.h"
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
//---------------------------------------------------------------
// M3 CF Addresses
#define REG_M3CF_STS ((vu16*)0x080C0000) // Status of the CF Card / Device control
#define REG_M3CF_CMD ((vu16*)0x088E0000) // Commands sent to control chip and status return
#define REG_M3CF_ERR ((vu16*)0x08820000) // Errors / Features
#define REG_M3CF_SEC ((vu16*)0x08840000) // Number of sector to transfer
#define REG_M3CF_LBA1 ((vu16*)0x08860000) // 1st byte of sector address
#define REG_M3CF_LBA2 ((vu16*)0x08880000) // 2nd byte of sector address
#define REG_M3CF_LBA3 ((vu16*)0x088A0000) // 3rd byte of sector address
#define REG_M3CF_LBA4 ((vu16*)0x088C0000) // last nibble of sector address | 0xE0
#define REG_M3CF_DATA ((vu16*)0x08800000) // Pointer to buffer of CF data transered from card
static const CF_REGISTERS _M3CF_Registers = {
REG_M3CF_DATA,
REG_M3CF_STS,
REG_M3CF_CMD,
REG_M3CF_ERR,
REG_M3CF_SEC,
REG_M3CF_LBA1,
REG_M3CF_LBA2,
REG_M3CF_LBA3,
REG_M3CF_LBA4
};
bool _M3CF_startup(void) {
_M3_changeMode (M3_MODE_MEDIA);
return _CF_startup (&_M3CF_Registers);
}
const IO_INTERFACE _io_m3cf = {
DEVICE_TYPE_M3CF,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_M3CF_startup,
(FN_MEDIUM_ISINSERTED)&_CF_isInserted,
(FN_MEDIUM_READSECTORS)&_CF_readSectors,
(FN_MEDIUM_WRITESECTORS)&_CF_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_CF_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_CF_shutdown
} ;

View File

@ -1,45 +0,0 @@
/*
io_m3cf.h
Hardware Routines for reading a compact flash card
using the M3 CF
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_M3CF_H
#define IO_M3CF_H
// 'M3CF'
#define DEVICE_TYPE_M3CF 0x4643334D
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_m3cf ;
#endif // define IO_M3CF_H

View File

@ -1,518 +0,0 @@
/*
io_m3sd.c
Hardware Routines for reading a Secure Digital card
using the M3 SD
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-25 - Chishm
* Improved startup function that doesn't delay hundreds of seconds
before reporting no card inserted.
* Fixed writeData function to timeout on error
* writeSectors function now wait until the card is ready before continuing with a transfer
2006-08-05 - Chishm
* Tries multiple times to get a Relative Card Address at startup
2006-08-07 - Chishm
* Moved the SD initialization to a common function
*/
#include "io_m3sd.h"
#include "io_sd_common.h"
#include "io_m3_common.h"
//---------------------------------------------------------------
// M3SD register addresses
#define REG_M3SD_DIR (*(vu16*)0x08800000) // direction control register
#define REG_M3SD_DAT (*(vu16*)0x09000000) // SD data line, 8 bits at a time
#define REG_M3SD_CMD (*(vu16*)0x09200000) // SD command byte
#define REG_M3SD_ARGH (*(vu16*)0x09400000) // SD command argument, high halfword
#define REG_M3SD_ARGL (*(vu16*)0x09600000) // SD command argument, low halfword
#define REG_M3SD_STS (*(vu16*)0x09800000) // command and status register
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
#define TRANSMIT_TIMEOUT 20000 // Time to wait for the M3 to respond to transmit or receive requests
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
//---------------------------------------------------------------
// Variables required for tracking SD state
static u32 _M3SD_relativeCardAddress = 0; // Preshifted Relative Card Address
//---------------------------------------------------------------
// Internal M3 SD functions
static inline void _M3SD_unlock (void) {
_M3_changeMode (M3_MODE_MEDIA);
}
static inline bool _M3SD_waitOnBusy (void) {
int i = 0;
while ( (REG_M3SD_STS & 0x01) == 0x00) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
return false;
}
}
return true;
}
static inline bool _M3SD_waitForDataReady (void) {
int i = 0;
while ( (REG_M3SD_STS & 0x40) == 0x00) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
return false;
}
}
return true;
}
static bool _M3SD_sendCommand (u16 command, u32 argument) {
REG_M3SD_STS = 0x8;
REG_M3SD_CMD = 0x40 + command; // Include the start bit
REG_M3SD_ARGH = argument >> 16;
REG_M3SD_ARGL = argument;
// The CRC7 of the command is calculated by the M3
REG_M3SD_DIR=0x29;
if (!_M3SD_waitOnBusy()) {
REG_M3SD_DIR=0x09;
return false;
}
REG_M3SD_DIR=0x09;
return true;
}
static bool _M3SD_sendByte (u8 byte) {
int i = 0;
REG_M3SD_DAT = byte;
REG_M3SD_DIR = 0x03;
REG_M3SD_STS = 0x01;
while ((REG_M3SD_STS & 0x04) == 0) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
return false;
}
}
return true;
}
static u8 _M3SD_getByte (void) {
int i;
// Request 8 bits of data from the SD's CMD pin
REG_M3SD_DIR = 0x02;
REG_M3SD_STS = 0x02;
// Wait for the data to be ready
i = 0;
while ((REG_M3SD_STS & 0x08) == 0) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
// Return an empty byte if a timeout occurs
return 0xFF;
}
}
i = 0;
while ((REG_M3SD_STS & 0x08) != 0) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
// Return an empty byte if a timeout occurs
return 0xFF;
}
}
// Return the data
return (REG_M3SD_DAT & 0xff);
}
// Returns the response from the SD card to a previous command.
static bool _M3SD_getResponse (u8* dest, u32 length) {
u32 i;
u8 dataByte;
int shiftAmount;
// Wait for the card to be non-busy
for (i = 0; i < RESPONSE_TIMEOUT; i++) {
dataByte = _M3SD_getByte();
if (dataByte != SD_CARD_BUSY) {
break;
}
}
if (dest == NULL) {
return true;
}
// Still busy after the timeout has passed
if (dataByte == 0xff) {
return false;
}
// Read response into buffer
for ( i = 0; i < length; i++) {
dest[i] = dataByte;
dataByte = _M3SD_getByte();
}
// dataByte will contain the last piece of the response
// Send 16 more clocks, 8 more than the delay required between a response and the next command
i = _M3SD_getByte();
i = _M3SD_getByte();
// Shift response so that the bytes are correctly aligned
// The register may not contain properly aligned data
for (shiftAmount = 0; ((dest[0] << shiftAmount) & 0x80) != 0x00; shiftAmount++) {
if (shiftAmount >= 7) {
return false;
}
}
for (i = 0; i < length - 1; i++) {
dest[i] = (dest[i] << shiftAmount) | (dest[i+1] >> (8-shiftAmount));
}
// Get the last piece of the response from dataByte
dest[i] = (dest[i] << shiftAmount) | (dataByte >> (8-shiftAmount));
return true;
}
static inline bool _M3SD_getResponse_R1 (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static inline bool _M3SD_getResponse_R1b (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static inline bool _M3SD_getResponse_R2 (u8* dest) {
return _M3SD_getResponse (dest, 17);
}
static inline bool _M3SD_getResponse_R3 (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static inline bool _M3SD_getResponse_R6 (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static void _M3SD_sendClocks (u32 numClocks) {
while (numClocks--) {
_M3SD_sendByte(0xff);
}
}
static void _M3SD_getClocks (u32 numClocks) {
while (numClocks--) {
_M3SD_getByte();
}
}
bool _M3SD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
_M3SD_sendCommand (command, data);
return _M3SD_getResponse (responseBuffer, 6);
}
bool _M3SD_cmd_17byte_response (u8* responseBuffer, u8 command, u32 data) {
_M3SD_sendCommand (command, data);
return _M3SD_getResponse (responseBuffer, 17);
}
static bool _M3SD_initCard (void) {
// Give the card time to stabilise
_M3SD_sendClocks (NUM_STARTUP_CLOCKS);
// Reset the card
if (!_M3SD_sendCommand (GO_IDLE_STATE, 0)) {
return false;
}
_M3SD_getClocks (NUM_STARTUP_CLOCKS);
// Card is now reset, including it's address
_M3SD_relativeCardAddress = 0;
// Init the card
return _SD_InitCard (_M3SD_cmd_6byte_response,
_M3SD_cmd_17byte_response,
true,
&_M3SD_relativeCardAddress);
}
static bool _M3SD_readData (void* buffer) {
u32 i;
u8* buff_u8 = (u8*)buffer;
u16* buff = (u16*)buffer;
u16 temp;
REG_M3SD_DIR = 0x49;
if (!_M3SD_waitForDataReady()) {
REG_M3SD_DIR = 0x09;
return false;
}
REG_M3SD_DIR = 0x09;
REG_M3SD_DIR = 0x8;
REG_M3SD_STS = 0x4;
i = REG_M3SD_DIR;
// Read data
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--)
{
temp = REG_M3SD_DIR;
*buff_u8++ = temp & 0xFF;
*buff_u8++ = temp >> 8;
}
} else {
while(i--)
*buff++ = REG_M3SD_DIR;
}
// Read end checksum
i = REG_M3SD_DIR + REG_M3SD_DIR + REG_M3SD_DIR + REG_M3SD_DIR;
return true;
}
static void _M3SD_clkout (void) {
REG_M3SD_DIR = 0x4;
REG_M3SD_DIR = 0xc;
/* __asm volatile (
"ldr r1, =0x08800000 \n"
"mov r0, #0x04 \n"
"strh r0, [r1] \n"
"mov r0, r0 \n"
"mov r0, r0 \n"
"mov r0, #0x0c \n"
"strh r0, [r1] \n"
: // Outputs
: // Inputs
: "r0", "r1" // Clobber list
);*/
}
static void _M3SD_clkin (void) {
REG_M3SD_DIR = 0x0;
REG_M3SD_DIR = 0x8;
/* __asm volatile (
"ldr r1, =0x08800000 \n"
"mov r0, #0x00 \n"
"strh r0, [r1] \n"
"mov r0, r0 \n"
"mov r0, r0 \n"
"mov r0, #0x08 \n"
"strh r0, [r1] \n"
: // Outputs
: // Inputs
: "r0", "r1" // Clobber list
);*/
}
static bool _M3SD_writeData (u8* data, u8* crc) {
int i;
u8 temp;
do {
_M3SD_clkin();
} while ((REG_M3SD_DAT & 0x100) == 0);
REG_M3SD_DAT = 0; // Start bit
_M3SD_clkout();
for (i = 0; i < BYTES_PER_READ; i++) {
temp = (*data++);
REG_M3SD_DAT = temp >> 4;
_M3SD_clkout();
REG_M3SD_DAT = temp;
_M3SD_clkout();
}
if (crc != NULL) {
for (i = 0; i < 8; i++) {
temp = (*crc++);
REG_M3SD_DAT = temp >> 4;
_M3SD_clkout();
REG_M3SD_DAT = temp;
_M3SD_clkout();
}
}
i = 32;
while (i--) {
temp += 2; // a NOP to stop the compiler optimising out the loop
}
for (i = 0; i < 32; i++) {
REG_M3SD_DAT = 0xff;
_M3SD_clkout();
}
do {
_M3SD_clkin();
} while ((REG_M3SD_DAT & 0x100) == 0);
return true;
}
//---------------------------------------------------------------
// Functions needed for the external interface
bool _M3SD_startUp (void) {
_M3SD_unlock();
return _M3SD_initCard();
}
bool _M3SD_isInserted (void) {
u8 responseBuffer [6];
// Make sure the card receives the command
if (!_M3SD_sendCommand (SEND_STATUS, 0)) {
return false;
}
// Make sure the card responds
if (!_M3SD_getResponse_R1 (responseBuffer)) {
return false;
}
// Make sure the card responded correctly
if (responseBuffer[0] != SEND_STATUS) {
return false;
}
return true;
}
bool _M3SD_readSectors (u32 sector, u32 numSectors, void* buffer) {
u32 i;
u8* dest = (u8*) buffer;
u8 responseBuffer[6];
if (numSectors == 1) {
// If it's only reading one sector, use the (slightly faster) READ_SINGLE_BLOCK
if (!_M3SD_sendCommand (READ_SINGLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
if (!_M3SD_readData (buffer)) {
return false;
}
} else {
// Stream the required number of sectors from the card
if (!_M3SD_sendCommand (READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
for(i=0; i < numSectors; i++, dest+=BYTES_PER_READ) {
if (!_M3SD_readData(dest)) {
return false;
}
REG_M3SD_STS = 0x8;
}
// Stop the streaming
_M3SD_sendCommand (STOP_TRANSMISSION, 0);
_M3SD_getResponse_R1b (responseBuffer);
}
return true;
}
bool _M3SD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
u8 crc[8];
u8 responseBuffer[6];
u32 offset = sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
int i;
// Precalculate the data CRC
_SD_CRC16 ( data, BYTES_PER_READ, crc);
while (numSectors--) {
// Send a single sector write command
_M3SD_sendCommand (WRITE_BLOCK, offset);
if (!_M3SD_getResponse_R1 (responseBuffer)) {
return false;
}
REG_M3SD_DIR = 0x4;
REG_M3SD_STS = 0x0;
// Send the data
if (! _M3SD_writeData( data, crc)) {
return false;
}
if (numSectors > 0) {
offset += BYTES_PER_READ;
data += BYTES_PER_READ;
// Calculate the next CRC while waiting for the card to finish writing
_SD_CRC16 ( data, BYTES_PER_READ, crc);
}
// Wait for the card to be ready for the next transfer
i = WRITE_TIMEOUT;
responseBuffer[3] = 0;
do {
_M3SD_sendCommand (SEND_STATUS, _M3SD_relativeCardAddress);
_M3SD_getResponse_R1 (responseBuffer);
i--;
if (i <= 0) {
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
}
return true;
}
bool _M3SD_clearStatus (void) {
return _M3SD_initCard ();
}
bool _M3SD_shutdown (void) {
_M3_changeMode (M3_MODE_ROM);
return true;
}
const IO_INTERFACE _io_m3sd = {
DEVICE_TYPE_M3SD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_M3SD_startUp,
(FN_MEDIUM_ISINSERTED)&_M3SD_isInserted,
(FN_MEDIUM_READSECTORS)&_M3SD_readSectors,
(FN_MEDIUM_WRITESECTORS)&_M3SD_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_M3SD_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_M3SD_shutdown
} ;

View File

@ -1,48 +0,0 @@
/*
io_m3sd.h
Hardware Routines for reading a Secure Digital card
using the M3 SD
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_M3SD_H
#define IO_M3SD_H
// 'M3SD'
#define DEVICE_TYPE_M3SD 0x4453334D
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_m3sd ;
#endif // define IO_M3SD_H

View File

@ -1,100 +0,0 @@
/*
io_mpcf.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for reading a compact flash card
using the GBA Movie Player
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_mpcf.h"
#include "io_cf_common.h"
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
//---------------------------------------------------------------
// GBAMP CF Addresses
#define REG_MPCF_STS ((vu16*)0x098C0000) // Status of the CF Card / Device control
#define REG_MPCF_CMD ((vu16*)0x090E0000) // Commands sent to control chip and status return
#define REG_MPCF_ERR ((vu16*)0x09020000) // Errors / Features
#define REG_MPCF_SEC ((vu16*)0x09040000) // Number of sector to transfer
#define REG_MPCF_LBA1 ((vu16*)0x09060000) // 1st byte of sector address
#define REG_MPCF_LBA2 ((vu16*)0x09080000) // 2nd byte of sector address
#define REG_MPCF_LBA3 ((vu16*)0x090A0000) // 3rd byte of sector address
#define REG_MPCF_LBA4 ((vu16*)0x090C0000) // last nibble of sector address | 0xE0
#define REG_MPCF_DATA ((vu16*)0x09000000) // Pointer to buffer of CF data transered from card
static const CF_REGISTERS _MPCF_Registers = {
REG_MPCF_DATA,
REG_MPCF_STS,
REG_MPCF_CMD,
REG_MPCF_ERR,
REG_MPCF_SEC,
REG_MPCF_LBA1,
REG_MPCF_LBA2,
REG_MPCF_LBA3,
REG_MPCF_LBA4
};
/*-----------------------------------------------------------------
_MPCF_startup
initializes the CF interface, returns true if successful,
otherwise returns false
-----------------------------------------------------------------*/
bool _MPCF_startup(void) {
return _CF_startup(&_MPCF_Registers);
}
/*-----------------------------------------------------------------
the actual interface structure
-----------------------------------------------------------------*/
const IO_INTERFACE _io_mpcf = {
DEVICE_TYPE_MPCF,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_MPCF_startup,
(FN_MEDIUM_ISINSERTED)&_CF_isInserted,
(FN_MEDIUM_READSECTORS)&_CF_readSectors,
(FN_MEDIUM_WRITESECTORS)&_CF_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_CF_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_CF_shutdown
} ;

View File

@ -1,45 +0,0 @@
/*
io_mpcf.h
Hardware Routines for reading a compact flash card
using the GBA Movie Player
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_MPCF_H
#define IO_MPCF_H
// 'MPCF'
#define DEVICE_TYPE_MPCF 0x4643504D
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_mpcf ;
#endif // define IO_MPCF_H

View File

@ -1,595 +0,0 @@
/*
io_njsd.c
Hardware Routines for reading an SD card using
a NinjaDS SD adapter.
Original code supplied by NinjaMod
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-05 - Chishm
* First release
2006-08-06 - Chishm
* Removed unneeded _NJSD_writeRAM function
* Removed casts for calls to cardWriteCommand
2006-08-07 - Chishm
* Moved the SD initialization to a common function
*/
#include "io_njsd.h"
#ifdef NDS
#include <nds.h>
#include <string.h>
#include "io_sd_common.h"
#define _NJSD_SYNC
//---------------------------------------------------------------
// Card communication speeds
#define SD_CLK_167KHz 00
#define SD_CLK_250KHz 01
#define SD_CLK_5MHz 02
#define SD_CLK_25MHz 03
//---------------------------------------------------------------
// Response types
#define SD_RSP_48 0
#define SD_RSP_136 1
#define SD_RSP_DATA 2
#define SD_RSP_STREAM 3
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define IRQ_TIMEOUT 1000000
#define RESET_TIMEOUT 10000
#define COMMAND_TIMEOUT 100000
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
static const u8 _NJSD_read_cmd[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40};
static const u8 _NJSD_read_end_cmd[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x41};
static int _NJSD_speed = SD_CLK_5MHz; // Default speed;
static u32 _NJSD_cardFlags;
static u32 _NJSD_relativeCardAddress = 0;
static inline bool _NJSD_waitIRQ(void) {
int i = IRQ_TIMEOUT;
while (!(REG_IF & 0x100000) && --i);
REG_IF = 0x100000;
if (i <= 0) {
return false;
} else {
return true;
}
}
static inline void _NJSD_writeCardCommand
(u8 cmd0, u8 cmd1, u8 cmd2, u8 cmd3, u8 cmd4, u8 cmd5, u8 cmd6, u8 cmd7)
{
CARD_COMMAND[0] = cmd0;
CARD_COMMAND[1] = cmd1;
CARD_COMMAND[2] = cmd2;
CARD_COMMAND[3] = cmd3;
CARD_COMMAND[4] = cmd4;
CARD_COMMAND[5] = cmd5;
CARD_COMMAND[6] = cmd6;
CARD_COMMAND[7] = cmd7;
}
static bool _NJSD_reset (void) {
int i;
CARD_CR1H = CARD_CR1_ENABLE;
_NJSD_writeCardCommand (0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
CARD_CR2 = 0xA0406000;
i = RESET_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
return false;
}
return true;
}
static bool _NJSD_init (u32 flags) {
_NJSD_cardFlags = flags;
REG_IF = 0x100000; // Clear cart IRQ.
irqDisable (IRQ_CARD_LINE);
if (! _NJSD_reset() ) {
return false;
}
return true;
}
static bool _NJSD_sendCMDR (int speed, u8 *rsp_buf, int type, u8 cmd, u32 param) {
int i;
u32 data;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
REG_IF = 0x100000;
CARD_CR1H = CARD_CR1_ENABLE;
if ((type & 3) < 2) {
CARD_COMMAND[0] = 0xF0 | (speed << 2) | 1 | (type << 1);
} else if ((type & 3) == 2) {
CARD_COMMAND[0] = 0xE0 | (speed << 2) | 0 | (1 << 1);
} else {
CARD_COMMAND[0] = 0xF0 | (speed << 2) | 0 | (1 << 1);
}
CARD_COMMAND[1] = (type & 0x40) | ((( type >> 2) & 7) << 3);
CARD_COMMAND[2] = 0x40 | cmd;
CARD_COMMAND[3] = (param>>24) & 0xFF;
CARD_COMMAND[4] = (param>>16) & 0xFF;
CARD_COMMAND[5] = (param>>8) & 0xFF;
CARD_COMMAND[6] = (param>>0) & 0xFF;
CARD_COMMAND[7] = 0; // offset = 0
if ((type & 3) < 2) {
CARD_CR2 = _NJSD_cardFlags | 0x01000000;
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
i = 0;
do {
// Read data if available
if (CARD_CR2 & CARD_DATA_READY) {
data=CARD_DATA_RD;
if (rsp_buf != NULL) {
if (i == 4) {
rsp_buf[0] = (data>>0)&0xFF;
rsp_buf[1] = (data>>8)&0xFF;
rsp_buf[2] = (data>>16)&0xFF;
rsp_buf[3] = (data>>24)&0xFF;
} else if (i == 5) {
rsp_buf[4] = (data>>0)&0xFF;
rsp_buf[5] = (data>>8)&0xFF;
}
}
i++;
}
} while (CARD_CR2 & CARD_BUSY);
} else {
CARD_CR2 = _NJSD_cardFlags;
while (CARD_CR2 & CARD_BUSY);
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
static bool _NJSD_writeSector (u8 *buffer, u8 *crc_buf, u32 offset) {
int i;
u8 responseBuffer[6];
u32 data;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
CARD_CR1H = CARD_CR1_ENABLE;
_NJSD_writeCardCommand (0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
CARD_CR2 = 0xA0406000;
i = COMMAND_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
for (i = 0; i < 65; i++)
{
CARD_CR1H = CARD_CR1_ENABLE; // | CARD_CR1_IRQ;
if (i < 64)
{
_NJSD_writeCardCommand (buffer[i*8+0], buffer[i*8+1], buffer[i*8+2], buffer[i*8+3],
buffer[i*8+4], buffer[i*8+5], buffer[i*8+6], buffer[i*8+7]);
} else {
_NJSD_writeCardCommand (crc_buf[0], crc_buf[1], crc_buf[2], crc_buf[3],
crc_buf[4], crc_buf[5], crc_buf[6], crc_buf[7]);
}
CARD_CR2 = 0xA7406000;
do {
// Read data if available
if (CARD_CR2 & CARD_DATA_READY) {
data=CARD_DATA_RD;
}
} while (CARD_CR2 & CARD_BUSY);
}
CARD_CR1H = CARD_CR1_ENABLE;
_NJSD_writeCardCommand (0xF0 | (1 << 2) | 1, 0x80, 0x40 | WRITE_BLOCK, (u8)(offset>>24),
(u8)(offset>>16), (u8)(offset>>8), (u8)(offset>>0), 0x00);
CARD_CR2 = 0xA7406000;
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
i = 0;
do {
// Read data if available
if (CARD_CR2 & CARD_DATA_READY) {
data = CARD_DATA_RD;
if (i == 2) {
responseBuffer[0] = (u8)(data>>0);
responseBuffer[1] = (u8)(data>>8);
responseBuffer[2] = (u8)(data>>16);
responseBuffer[3] = (u8)(data>>24);
} else if (i == 3) {
responseBuffer[4] = (u8)(data>>0);
responseBuffer[5] = (u8)(data>>8);
}
i++;
}
} while (CARD_CR2 & CARD_BUSY);
i = WRITE_TIMEOUT;
responseBuffer[3] = 0;
do {
_NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_48, SEND_STATUS, _NJSD_relativeCardAddress);
i--;
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
static bool _NJSD_sendCLK (int speed, int count) {
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
REG_IF = 0x100000;
#endif
//CARD_CR1H = CARD_CR1_ENABLE; // | CARD_CR1_IRQ;
_NJSD_writeCardCommand (0xE0 | ((speed & 3) << 2), 0, (count - 1), 0, 0, 0, 0, 0);
CARD_CR2 = _NJSD_cardFlags;
i = COMMAND_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
static bool _NJSD_sendCMDN (int speed, u8 cmd, u32 param) {
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
REG_IF = 0x100000;
CARD_CR1H = CARD_CR1_ENABLE; // | CARD_CR1_IRQ;
_NJSD_writeCardCommand (0xF0 | ((speed & 3) << 2), 0x00, 0x40 | cmd, (param>>24) & 0xFF,
(param>>16) & 0xFF, (param>>8) & 0xFF, (param>>0) & 0xFF, 0x00);
CARD_CR2 = _NJSD_cardFlags;
i = COMMAND_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
bool _NJSD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
return _NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_48, command, data);
}
bool _NJSD_cmd_17byte_response (u8* responseBuffer, u8 command, u32 data) {
return _NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_136, command, data);
}
static bool _NJSD_cardInit (void) {
// If the commands succeed the first time, assume they'll always succeed
if (! _NJSD_sendCLK (SD_CLK_167KHz, 256) ) {
return false;
}
if (! _NJSD_sendCMDN (SD_CLK_167KHz, GO_IDLE_STATE, 0) ) {
return false;
}
_NJSD_sendCLK (SD_CLK_167KHz, 8);
_NJSD_sendCLK (SD_CLK_167KHz, 256);
_NJSD_sendCMDN (SD_CLK_167KHz, GO_IDLE_STATE, 0);
_NJSD_sendCLK (SD_CLK_167KHz, 8);
return _SD_InitCard (_NJSD_cmd_6byte_response,
_NJSD_cmd_17byte_response,
true,
&_NJSD_relativeCardAddress);
}
bool _NJSD_isInserted(void) {
u8 responseBuffer [8];
_NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_48, SEND_STATUS, 0);
// Make sure the card responded correctly
if (responseBuffer[0] != SEND_STATUS) {
return false;
}
return true;
}
bool _NJSD_clearStatus (void) {
return _NJSD_reset();
}
bool _NJSD_shutdown(void) {
return _NJSD_clearStatus();
}
bool _NJSD_startup(void) {
if (! _NJSD_init(0xA0406000) ) {
return false;
}
if (! _NJSD_cardInit() ) {
return false;
}
return true;
}
bool _NJSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
u8 crc[8];
u32 offset = sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
while (numSectors--) {
_SD_CRC16 ( data, BYTES_PER_READ, crc);
if (! _NJSD_writeSector (data, crc, offset)) {
return false;
}
offset += BYTES_PER_READ;
data += BYTES_PER_READ;
}
return true;
}
#ifdef _IO_ALLOW_UNALIGNED
bool _NJSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
u32 tmp[BYTES_PER_READ>>2];
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
#endif
u8* tbuf = (u8*)buffer;
if (numSectors == 0) {
return false;
}
#ifdef _NJSD_SYNC
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
if (numSectors > 1) {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_DATA, READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ);
for (i = 0; i < numSectors - 2; i++) {
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_cmd);
memcpy (tbuf + i * BYTES_PER_READ, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + i * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
}
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
}
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_end_cmd);
memcpy (tbuf + (numSectors - 2) * BYTES_PER_READ, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 2) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_end_cmd);
}
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_cmd);
memcpy (tbuf + (numSectors - 1) * BYTES_PER_READ, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 1) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
}
} else {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_STREAM, READ_SINGLE_BLOCK, sector * BYTES_PER_READ);
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_cmd);
memcpy (tbuf, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)tbuf, BYTES_PER_READ, _NJSD_read_cmd);
}
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
#else // not defined _IO_ALLOW_UNALIGNED
bool _NJSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
#endif
u8* tbuf = (u8*)buffer;
if (numSectors == 0) {
return false;
}
#ifdef _NJSD_SYNC
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
if (numSectors > 1) {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_DATA, READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ);
for (i = 0; i < numSectors - 2; i++) {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + i * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
}
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 2) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_end_cmd);
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 1) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
} else {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_STREAM, READ_SINGLE_BLOCK, sector * BYTES_PER_READ);
cardPolledTransfer (0xA1406000, (u32*)tbuf, BYTES_PER_READ, _NJSD_read_cmd);
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
#endif // _IO_ALLOW_UNALIGNED
const IO_INTERFACE _io_njsd = {
DEVICE_TYPE_NJSD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_NDS,
(FN_MEDIUM_STARTUP)&_NJSD_startup,
(FN_MEDIUM_ISINSERTED)&_NJSD_isInserted,
(FN_MEDIUM_READSECTORS)&_NJSD_readSectors,
(FN_MEDIUM_WRITESECTORS)&_NJSD_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_NJSD_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_NJSD_shutdown
} ;
#endif // defined NDS

View File

@ -1,50 +0,0 @@
/*
io_njsd.h
Hardware Routines for reading an SD card using
a NinjaDS SD adapter.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-02 - Chishm
* Original release
*/
#ifndef IO_NJSD_H
#define IO_NJSD_H
#include "../disc.h"
#ifdef NDS
// 'NJSD'
#define DEVICE_TYPE_NJSD 0x44534A4E
// export interface
extern const IO_INTERFACE _io_njsd;
#endif // defined NDS
#endif // define IO_NJSD_H

View File

@ -1,348 +0,0 @@
/*
io_nmmc.c
Hardware Routines for reading an SD or MMC card using
a Neoflash MK2 or MK3.
Written by www.neoflash.com
Submit bug reports for this device to the NeoFlash forums
See license.txt for license details.
2006-02-09 - www.neoflash.com:
* First stable release
2006-02-13 - Chishm
* Added ReadMK2Config function
* Added read config test to init function so no unnecessary card commands are sent
* Changed data read and write functions to use multiple block commands
*/
#include "io_nmmc.h"
#ifdef NDS
#include <nds/card.h>
int _NMMC_spi_freq = 3;
#define MK2_CONFIG_ZIP_RAM_CLOSE (1 << 5)
#define MK2_CONFIG_GAME_FLASH_CLOSE ((1 << 4) | (1 << 0))
//#define MK2_CONFIG_ZIP_RAM_CLOSE ((1 << 5) | (1 << 1))
//#define MK2_CONFIG_GAME_FLASH_CLOSE (1 << 4)
#define MMC_READ_MULTIPLE_BLOCK 18
#define MMC_READ_BLOCK 17
#define MMC_WRITE_MULTIPLE_BLOCK 25
#define MMC_WRITE_BLOCK 24
#define MMC_STOP_TRANSMISSION 12
#define MMC_SET_BLOCKLEN 16
#define MMC_SET_BLOCK_COUNT 23
#define MMC_SEND_CSD 9
// SPI functions
static inline void _Neo_OpenSPI( u8 frequency )
{
CARD_CR1 = 0x0000A040 | frequency;
}
static inline u8 _Neo_SPI( u8 dataByte )
{
CARD_EEPDATA = dataByte;
while (CARD_CR1 & 0x80); // card busy
return CARD_EEPDATA;
}
static inline void _Neo_CloseSPI ( void )
{
CARD_CR1 = 0;
}
static inline void _Neo_MK2GameMode() {
_Neo_OpenSPI(_NMMC_spi_freq); // Enable DS Card's SPI port
_Neo_SPI(0xF1); // Switch to game mode
_Neo_CloseSPI(); // Disable DS Card's SPI port
}
static inline void _Neo_EnableEEPROM( bool enable ) {
_Neo_OpenSPI(_NMMC_spi_freq);
if(enable) _Neo_SPI(0x06);
else _Neo_SPI(0x0E);
_Neo_CloseSPI();
}
static void _Neo_WriteMK2Config(u8 config) {
_Neo_EnableEEPROM(true);
_Neo_OpenSPI(_NMMC_spi_freq);
_Neo_SPI(0xFA); // Send mem conf write command
_Neo_SPI(0x01); // Send high byte (0x01)
_Neo_SPI(config); // Send low byte
_Neo_CloseSPI();
_Neo_EnableEEPROM(false);
}
static u8 _Neo_ReadMK2Config(void)
{
u8 config;
_Neo_EnableEEPROM(true);
_Neo_OpenSPI(_NMMC_spi_freq);
_Neo_SPI(0xf8); // Send mem conf read command
_Neo_SPI(0x01); // Send high byte
config = _Neo_SPI(0x00); // Get low byte
_Neo_CloseSPI();
_Neo_EnableEEPROM(false);
return config;
}
// Low level functions
u8 selectMMC_command [8] = {0xFF, 0x00, 0x6A, 0xDF, 0x37, 0x59, 0x33, 0xA3};
static void _Neo_SelectMMC (u8 dataByte)
{
selectMMC_command[1] = dataByte; // Set enable / disable byte
cardWriteCommand (selectMMC_command); // Send "5. Use the EEPROM CS to access the MK2 MMC/SD card"
CARD_CR2 = CARD_ACTIVATE | CARD_nRESET;
while (CARD_CR2 & CARD_BUSY);
return;
}
static void _Neo_EnableMMC( bool enable )
{
if ( enable == false) {
_Neo_CloseSPI ();
_Neo_SelectMMC (0);
_Neo_SelectMMC (0);
} else {
_Neo_SelectMMC (1);
_Neo_SelectMMC (1);
_Neo_OpenSPI (_NMMC_spi_freq);
}
return;
}
static void _Neo_SendMMCCommand( u8 command, u32 argument )
{
_Neo_SPI (0xFF);
_Neo_SPI (command | 0x40);
_Neo_SPI ((argument >> 24) & 0xff);
_Neo_SPI ((argument >> 16) & 0xff);
_Neo_SPI ((argument >> 8) & 0xff) ;
_Neo_SPI (argument & 0xff);
_Neo_SPI (0x95);
_Neo_SPI (0xFF);
return;
}
static bool _Neo_CheckMMCResponse( u8 response, u8 mask ) {
u32 i;
for(i=0;i<256;i++) {
if( ( _Neo_SPI( 0xFF ) & mask ) == response )
return true;
}
return false;
}
// Neo MMC functions
static bool _Neo_InitMMC() {
_Neo_MK2GameMode();
_Neo_WriteMK2Config( MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE);
// Make sure the configuration was accepted
if (_Neo_ReadMK2Config() != (MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE)) {
return false; // If not, then it wasn't initialised properly
}
return true;
}
// Neo MMC driver functions
bool _NMMC_isInserted(void) {
int i;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
_Neo_SendMMCCommand(MMC_SEND_CSD, 0);
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
if( _Neo_CheckMMCResponse( 0xFE, 0xFF ) == false ) { // Check for Start Block token
_Neo_EnableMMC( false );
return false;
}
// consume data from card, and send clocks.
for (i = 0; i < 28; i++) {
_Neo_SPI(0xff);
}
return true;
}
bool _NMMC_clearStatus (void) {
u32 i;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
for (i = 0; i < 10; i++) {
_Neo_SPI(0xFF); // Send 10 0xFF bytes to MMC card
}
_Neo_SendMMCCommand(0, 0); // Send GO_IDLE_STATE command
if( _Neo_CheckMMCResponse( 0x01, 0xFF ) == false ) { // Check that it replied with 0x01 (not idle, no other error)
_Neo_EnableMMC( false );
return false;
}
for(i=0;i<256;i++) {
_Neo_SendMMCCommand(1, 0); // Poll with SEND_OP_COND
if( _Neo_CheckMMCResponse( 0x00, 0x01 ) == true ) { // Check for idle state
_Neo_EnableMMC( false ); // Close SPI port to MMC card
return true; // Card is now idle
}
}
_Neo_EnableMMC( false );
return false;
}
bool _NMMC_shutdown(void) {
return _NMMC_clearStatus();
}
bool _NMMC_startUp(void) {
int i;
int transSpeed;
if (_Neo_InitMMC() == false) {
return false;
}
if (_NMMC_clearStatus() == false) {
return false;
}
_Neo_EnableMMC( true ); // Open SPI port to MMC card
// Set block length
_Neo_SendMMCCommand(MMC_SET_BLOCKLEN, BYTES_PER_READ );
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
// Check if we can use a higher SPI frequency
_Neo_SendMMCCommand(MMC_SEND_CSD, 0);
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
if( _Neo_CheckMMCResponse( 0xFE, 0xFF ) == false ) { // Check for Start Block token
_Neo_EnableMMC( false );
return false;
}
for (i = 0; i < 3; i++) {
_Neo_SPI(0xFF);
}
transSpeed = _Neo_SPI (0xFF);
for (i = 0; i < 24; i++) {
_Neo_SPI(0xFF);
}
if ((transSpeed & 0xf0) >= 0x30) {
_NMMC_spi_freq = 0;
}
_Neo_EnableMMC( false );
return true;
}
bool _NMMC_writeSectors (u32 sector, u32 totalSecs, const void* buffer)
{
u32 i;
u8 *p=(u8*)buffer;
sector *= BYTES_PER_READ;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
_Neo_SendMMCCommand( 25, sector );
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
while (totalSecs--) {
_Neo_SPI( 0xFC ); // Send Start Block token
for( i = 0; i < BYTES_PER_READ; i++ ) // Send a block of data
_Neo_SPI( *p++ );
_Neo_SPI( 0xFF ); // Send fake CRC16
_Neo_SPI( 0xFF ); // Send fake CRC16
if( ( _Neo_SPI( 0xFF ) & 0x0F ) != 0x05 ) { // Make sure the block was accepted
_Neo_EnableMMC( false );
return false;
}
while( _Neo_SPI( 0xFF ) == 0x00 ); // Wait for the block to be written
}
// Stop transmission block
_Neo_SPI( 0xFD ); // Send Stop Transmission Block token
for( i = 0; i < BYTES_PER_READ; i++ ) // Send a block of fake data
_Neo_SPI( 0xFF );
_Neo_SPI( 0xFF ); // Send fake CRC16
_Neo_SPI( 0xFF ); // Send fake CRC16
_Neo_SPI (0xFF); // Send 8 clocks
while( _Neo_SPI( 0xFF ) == 0x00 ); // Wait for the busy signal to clear
for ( i = 0; i < 0x10; i++) {
_Neo_SPI (0xFF); // Send clocks for the MMC card to finish what it's doing
}
_Neo_EnableMMC( false ); // Close SPI port to MMC card
return true;
}
bool _NMMC_readSectors (u32 sector, u32 totalSecs, void* buffer)
{
u32 i;
u8 *p=(u8*)buffer;
sector *= BYTES_PER_READ;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
while (totalSecs--) {
_Neo_SendMMCCommand(MMC_READ_BLOCK, sector );
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
if( _Neo_CheckMMCResponse( 0xFE, 0xFF ) == false ) { // Check for Start Block token
_Neo_EnableMMC( false );
return false;
}
for( i = 0; i < BYTES_PER_READ; i++ ) // Read in a block of data
*p++ = _Neo_SPI( 0xFF );
_Neo_SPI( 0xFF ); // Ignore CRC16
_Neo_SPI( 0xFF ); // Ignore CRC16
sector += BYTES_PER_READ;
}
_Neo_EnableMMC( false ); // Close SPI port to MMC card
return true;
}
const IO_INTERFACE _io_nmmc = {
DEVICE_TYPE_NMMC,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_NDS,
(FN_MEDIUM_STARTUP)&_NMMC_startUp,
(FN_MEDIUM_ISINSERTED)&_NMMC_isInserted,
(FN_MEDIUM_READSECTORS)&_NMMC_readSectors,
(FN_MEDIUM_WRITESECTORS)&_NMMC_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_NMMC_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_NMMC_shutdown
} ;
#endif // defined NDS

View File

@ -1,53 +0,0 @@
/*
io_nmmc.h
Hardware Routines for reading an SD or MMC card using
a Neoflash MK2 or MK3.
Original version written by www.neoflash.com,
moddified and used with permission of www.neoflash.com
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_NMMC_H
#define IO_NMMC_H
#include "../disc.h"
#ifdef NDS
// 'NMMC'
#define DEVICE_TYPE_NMMC 0x434D4D4E
// export interface
extern const IO_INTERFACE _io_nmmc;
#endif // defined NDS
#endif // define IO_NMMC_H

View File

@ -1,47 +0,0 @@
/*
io_m3_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_sc_common.h"
/*-----------------------------------------------------------------
_SC_changeMode (was SC_Unlock)
Added by MightyMax
Modified by Chishm
Modified again by loopy
1=ram(readonly), 5=ram, 3=SD interface?
-----------------------------------------------------------------*/
void _SC_changeMode(u8 mode) {
vu16 *unlockAddress = (vu16*)0x09FFFFFE;
*unlockAddress = 0xA55A ;
*unlockAddress = 0xA55A ;
*unlockAddress = mode ;
*unlockAddress = mode ;
}

View File

@ -1,49 +0,0 @@
/*
io_sc_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2007-01-29 - Chishm
* Added SC_MODE_FLASH
*/
#ifndef IO_SC_COMMON_H
#define IO_SC_COMMON_H
#include "../disc.h"
// Values for changing mode
#define SC_MODE_FLASH 0x1510
#define SC_MODE_RAM 0x5
#define SC_MODE_MEDIA 0x3
#define SC_MODE_RAM_RO 0x1
extern void _SC_changeMode (u8 mode);
#endif // IO_SC_COMMON_H

View File

@ -1,83 +0,0 @@
/*
io_sccf.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for reading a compact flash card
using the Super Card CF
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_sccf.h"
#include "io_sc_common.h"
#include "io_cf_common.h"
//---------------------------------------------------------------
// SC CF Addresses
#define REG_SCCF_STS ((vu16*)0x098C0000) // Status of the CF Card / Device control
#define REG_SCCF_CMD ((vu16*)0x090E0000) // Commands sent to control chip and status return
#define REG_SCCF_ERR ((vu16*)0x09020000) // Errors / Features
#define REG_SCCF_SEC ((vu16*)0x09040000) // Number of sector to transfer
#define REG_SCCF_LBA1 ((vu16*)0x09060000) // 1st byte of sector address
#define REG_SCCF_LBA2 ((vu16*)0x09080000) // 2nd byte of sector address
#define REG_SCCF_LBA3 ((vu16*)0x090A0000) // 3rd byte of sector address
#define REG_SCCF_LBA4 ((vu16*)0x090C0000) // last nibble of sector address | 0xE0
#define REG_SCCF_DATA ((vu16*)0x09000000) // Pointer to buffer of CF data transered from card
static const CF_REGISTERS _SCCF_Registers = {
REG_SCCF_DATA,
REG_SCCF_STS,
REG_SCCF_CMD,
REG_SCCF_ERR,
REG_SCCF_SEC,
REG_SCCF_LBA1,
REG_SCCF_LBA2,
REG_SCCF_LBA3,
REG_SCCF_LBA4
};
bool _SCCF_startup(void) {
_SC_changeMode (SC_MODE_MEDIA);
return _CF_startup(&_SCCF_Registers);
}
const IO_INTERFACE _io_sccf = {
DEVICE_TYPE_SCCF,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_SCCF_startup,
(FN_MEDIUM_ISINSERTED)&_CF_isInserted,
(FN_MEDIUM_READSECTORS)&_CF_readSectors,
(FN_MEDIUM_WRITESECTORS)&_CF_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_CF_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_CF_shutdown
} ;

View File

@ -1,45 +0,0 @@
/*
io_sccf.h
Hardware Routines for reading a compact flash card
using the Supercard CF
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_SCCF_H
#define IO_SCCF_H
// 'SCCF'
#define DEVICE_TYPE_SCCF 0x46434353
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_sccf;
#endif // define IO_SCCF_H

View File

@ -1,399 +0,0 @@
/*
io_scsd.c
Hardware Routines for reading a Secure Digital card
using the SC SD
Some code based on scsd_c.c, written by Amadeus
and Jean-Pierre Thomasset as part of DSLinux.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-22 - Chishm
* First release of stable code
2006-07-25 - Chishm
* Improved startup function that doesn't delay hundreds of seconds
before reporting no card inserted.
2006-08-05 - Chishm
* Tries multiple times to get a Relative Card Address at startup
2006-08-07 - Chishm
* Moved the SD initialization to a common function
2006-08-19 - Chishm
* Added SuperCard Lite support
*/
#include "io_scsd.h"
#include "io_sd_common.h"
#include "io_sc_common.h"
//---------------------------------------------------------------
// SCSD register addresses
#define REG_SCSD_CMD (*(vu16*)(0x09800000))
/* bit 0: command bit to read */
/* bit 7: command bit to write */
#define REG_SCSD_DATAWRITE (*(vu16*)(0x09000000))
#define REG_SCSD_DATAREAD (*(vu16*)(0x09100000))
#define REG_SCSD_DATAREAD_32 (*(vu32*)(0x09100000))
#define REG_SCSD_LITE_ENABLE (*(vu16*)(0x09440000))
#define REG_SCSD_LOCK (*(vu16*)(0x09FFFFFE))
/* bit 0: 1 */
/* bit 1: enable IO interface (SD,CF) */
/* bit 2: enable R/W SDRAM access */
//---------------------------------------------------------------
// Responses
#define SCSD_STS_BUSY 0x100
#define SCSD_STS_INSERTED 0x300
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
#define TRANSMIT_TIMEOUT 100000 // Time to wait for the SC to respond to transmit or receive requests
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define BUSY_WAIT_TIMEOUT 500000
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
//---------------------------------------------------------------
// Variables required for tracking SD state
static u32 _SCSD_relativeCardAddress = 0; // Preshifted Relative Card Address
//---------------------------------------------------------------
// Internal SC SD functions
extern bool _SCSD_writeData_s (u8 *data, u16* crc);
static inline void _SCSD_unlock (void) {
_SC_changeMode (SC_MODE_MEDIA);
}
static inline void _SCSD_enable_lite (void) {
REG_SCSD_LITE_ENABLE = 0;
}
static bool _SCSD_sendCommand (u8 command, u32 argument) {
u8 databuff[6];
u8 *tempDataPtr = databuff;
int length = 6;
u16 dataByte;
int curBit;
int i;
*tempDataPtr++ = command | 0x40;
*tempDataPtr++ = argument>>24;
*tempDataPtr++ = argument>>16;
*tempDataPtr++ = argument>>8;
*tempDataPtr++ = argument;
*tempDataPtr = _SD_CRC7 (databuff, 5);
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) == 0) && (--i));
if (i == 0) {
return false;
}
dataByte = REG_SCSD_CMD;
tempDataPtr = databuff;
while (length--) {
dataByte = *tempDataPtr++;
for (curBit = 7; curBit >=0; curBit--){
REG_SCSD_CMD = dataByte;
dataByte = dataByte << 1;
}
}
return true;
}
// Returns the response from the SD card to a previous command.
static bool _SCSD_getResponse (u8* dest, u32 length) {
u32 i;
int dataByte;
int numBits = length * 8;
// Wait for the card to be non-busy
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) != 0) && (--i));
if (dest == NULL) {
return true;
}
if (i == 0) {
// Still busy after the timeout has passed
return false;
}
// The first bit is always 0
dataByte = 0;
numBits--;
// Read the remaining bits in the response.
// It's always most significant bit first
while (numBits--) {
dataByte = (dataByte << 1) | (REG_SCSD_CMD & 0x01);
if ((numBits & 0x7) == 0) {
// It's read a whole byte, so store it
*dest++ = (u8)dataByte;
dataByte = 0;
}
}
// Send 16 more clocks, 8 more than the delay required between a response and the next command
for (i = 0; i < 16; i++) {
dataByte = REG_SCSD_CMD;
}
return true;
}
static inline bool _SCSD_getResponse_R1 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static inline bool _SCSD_getResponse_R1b (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static inline bool _SCSD_getResponse_R2 (u8* dest) {
return _SCSD_getResponse (dest, 17);
}
static inline bool _SCSD_getResponse_R3 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static inline bool _SCSD_getResponse_R6 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static void _SCSD_sendClocks (u32 numClocks) {
u16 temp;
do {
temp = REG_SCSD_CMD;
} while (numClocks--);
}
bool _SCSD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 6);
}
bool _SCSD_cmd_17byte_response (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 17);
}
static bool _SCSD_initCard (void) {
_SCSD_enable_lite();
// Give the card time to stabilise
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Reset the card
if (!_SCSD_sendCommand (GO_IDLE_STATE, 0)) {
return false;
}
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Card is now reset, including it's address
_SCSD_relativeCardAddress = 0;
// Init the card
return _SD_InitCard (_SCSD_cmd_6byte_response,
_SCSD_cmd_17byte_response,
true,
&_SCSD_relativeCardAddress);
}
static bool _SCSD_readData (void* buffer) {
u8* buff_u8 = (u8*)buffer;
u16* buff = (u16*)buffer;
volatile register u32 temp;
int i;
i = BUSY_WAIT_TIMEOUT;
while ((REG_SCSD_DATAREAD & SCSD_STS_BUSY) && (--i));
if (i == 0) {
return false;
}
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--) {
temp = REG_SCSD_DATAREAD_32;
temp = REG_SCSD_DATAREAD_32 >> 16;
*buff_u8++ = (u8)temp;
*buff_u8++ = (u8)(temp >> 8);
}
} else {
while(i--) {
temp = REG_SCSD_DATAREAD_32;
temp = REG_SCSD_DATAREAD_32 >> 16;
*buff++ = temp;
}
}
for (i = 0; i < 8; i++) {
temp = REG_SCSD_DATAREAD_32;
}
temp = REG_SCSD_DATAREAD;
return true;
}
//---------------------------------------------------------------
// Functions needed for the external interface
bool _SCSD_startUp (void) {
_SCSD_unlock();
return _SCSD_initCard();
}
bool _SCSD_isInserted (void) {
u8 responseBuffer [6];
// Make sure the card receives the command
if (!_SCSD_sendCommand (SEND_STATUS, 0)) {
return false;
}
// Make sure the card responds
if (!_SCSD_getResponse_R1 (responseBuffer)) {
return false;
}
// Make sure the card responded correctly
if (responseBuffer[0] != SEND_STATUS) {
return false;
}
return true;
}
bool _SCSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
u32 i;
u8* dest = (u8*) buffer;
u8 responseBuffer[6];
if (numSectors == 1) {
// If it's only reading one sector, use the (slightly faster) READ_SINGLE_BLOCK
if (!_SCSD_sendCommand (READ_SINGLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
if (!_SCSD_readData (buffer)) {
return false;
}
} else {
// Stream the required number of sectors from the card
if (!_SCSD_sendCommand (READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
for(i=0; i < numSectors; i++, dest+=BYTES_PER_READ) {
if (!_SCSD_readData(dest)) {
return false;
}
}
// Stop the streaming
_SCSD_sendCommand (STOP_TRANSMISSION, 0);
_SCSD_getResponse_R1b (responseBuffer);
}
_SCSD_sendClocks(0x10);
return true;
}
bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
u16 crc[4]; // One per data line
u8 responseBuffer[6];
u32 offset = sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
int i;
while (numSectors--) {
// Calculate the CRC16
_SD_CRC16 ( data, BYTES_PER_READ, (u8*)crc);
// Send write command and get a response
_SCSD_sendCommand (WRITE_BLOCK, offset);
if (!_SCSD_getResponse_R1 (responseBuffer)) {
return false;
}
// Send the data and CRC
if (! _SCSD_writeData_s (data, crc)) {
return false;
}
// Send a few clocks to the SD card
_SCSD_sendClocks(0x10);
offset += BYTES_PER_READ;
data += BYTES_PER_READ;
// Wait until card is finished programming
i = WRITE_TIMEOUT;
responseBuffer[3] = 0;
do {
_SCSD_sendCommand (SEND_STATUS, _SCSD_relativeCardAddress);
_SCSD_getResponse_R1 (responseBuffer);
i--;
if (i <= 0) {
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
}
return true;
}
bool _SCSD_clearStatus (void) {
return _SCSD_initCard ();
}
bool _SCSD_shutdown (void) {
_SC_changeMode (SC_MODE_RAM_RO);
return true;
}
const IO_INTERFACE _io_scsd = {
DEVICE_TYPE_SCSD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_SCSD_startUp,
(FN_MEDIUM_ISINSERTED)&_SCSD_isInserted,
(FN_MEDIUM_READSECTORS)&_SCSD_readSectors,
(FN_MEDIUM_WRITESECTORS)&_SCSD_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_SCSD_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_SCSD_shutdown
} ;

View File

@ -1,48 +0,0 @@
/*
io_scsd.h
Hardware Routines for reading a Secure Digital card
using the Supercard SD
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-22 - Chishm
* First release of stable code
*/
#ifndef IO_SCSD_H
#define IO_SCSD_H
// 'SCSD'
#define DEVICE_TYPE_SCSD 0x44534353
#include "../disc.h"
// export interface
extern const IO_INTERFACE _io_scsd ;
#endif // define IO_SCSD_H

View File

@ -1,139 +0,0 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ io_scsd_s.s
@
@ Hardware Routines for reading a Secure Digital card
@ using the SC SD
@
@ Based on code supplied by Romman
@
@ Copyright (c) 2006 Michael "Chishm" Chisholm
@
@ Redistribution and use in source and binary forms, with or without modification,
@ are permitted provided that the following conditions are met:
@
@ 1. Redistributions of source code must retain the above copyright notice,
@ this list of conditions and the following disclaimer.
@ 2. Redistributions in binary form must reproduce the above copyright notice,
@ this list of conditions and the following disclaimer in the documentation and/or
@ other materials provided with the distribution.
@ 3. The name of the author may not be used to endorse or promote products derived
@ from this software without specific prior written permission.
@
@ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
@ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
@ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
@ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@
@ 2006-07-22 - Chishm
@ * First release of stable code
@
@ 2006-08-19 - Chishm
@ * Added SuperCard Lite support
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.align 4
.arm
.equ REG_SCSD_DATAWRITE, 0x09000000
.equ BYTES_PER_READ, 0x200
.equ SCSD_STS_BUSY, 0x100
.equ BUSY_WAIT_TIMEOUT, 0x10000
.equ FALSE, 0
.equ TRUE, 1
@ bool _SCSD_writeData_s (u8 *data, u16* crc)
.global _SCSD_writeData_s
_SCSD_writeData_s:
stmfd r13!, {r4-r5}
mov r5, #BYTES_PER_READ
mov r2, #REG_SCSD_DATAWRITE
@ Wait for a free data buffer on the SD card
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_busy_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #SCSD_STS_BUSY
beq _SCSD_writeData_busy_wait
ldrh r3, [r2] @ extra clock
mov r3, #0 @ start bit
strh r3,[r2]
@ Check if the data buffer is aligned on a halfword boundary
tst r0, #1
beq _SCSD_writeData_data_loop
@ Used when the source data is unaligned
_SCSD_writeData_data_loop_unaligned:
ldrb r3, [r0], #1
ldrb r4, [r0], #1
orr r3, r3, r4, lsl #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop_unaligned
b _SCSD_writeData_crc
@ Write the data to the card
@ 4 halfwords are transmitted to the Supercard at once, for timing purposes
@ Only the first halfword needs to contain data for standard SuperCards
@ For the SuperCard Lite, the data is split into 4 nibbles, one per halfword
_SCSD_writeData_data_loop:
ldrh r3, [r0], #2
@ This bit added for SCLite. Notice that the shift is not the same as in
@ the original (buggy) code supplied by Romman
add r3, r3, r3, lsl #20
mov r4, r3, lsr #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop
@ Send the data CRC
_SCSD_writeData_crc:
cmp r1, #0
movne r0, r1
movne r1, #0
movne r5, #8
bne _SCSD_writeData_data_loop
mov r3, #0xff @ end bit
strh r3, [r2]
@ Wait for the SD card to signal that it is finished recieving
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_finished_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #0x100
bne _SCSD_writeData_finished_wait
@ Send 8 more clocks, as required by the SD card
ldmia r2, {r3-r4}
@ return true for success
mov r0, #TRUE
_SCSD_writeData_return:
ldmfd r13!,{r4-r5}
bx r14

View File

@ -1,210 +0,0 @@
/*
io_sd_common.c
By chishm (Michael Chisholm)
Common SD card routines
SD routines partially based on sd.s by Romman
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-07 - Chishm
* Moved the SD initialization to a common function
* Increased timeouts for slower cards
2006-08-08 - Chishm
* Init aborts when it doesn't get a valid response to APP_CMD - speeds up detection when no card is inserted
*/
#include "io_sd_common.h"
#define MAX_STARTUP_TRIES 1000 // Arbitrary value, check if the card is ready 20 times before giving up
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
/*
Improved CRC7 function provided by cory1492
Calculates the CRC of an SD command, and includes the end bit in the byte
*/
u8 _SD_CRC7(u8* data, int cnt) {
int i, a;
u8 crc, temp;
crc = 0;
for (a = 0; a < cnt; a++)
{
temp = data[a];
for (i = 0; i < 8; i++)
{
crc <<= 1;
if ((temp & 0x80) ^ (crc & 0x80)) crc ^= 0x09;
temp <<= 1;
}
}
crc = (crc << 1) | 1;
return(crc);
}
/*
Calculates the CRC16 for a sector of data. Calculates it
as 4 separate lots, merged into one buffer. This is used
for 4 SD data lines, not for 1 data line alone.
*/
void _SD_CRC16 (u8* buff, int buffLength, u8* crc16buff) {
u32 a, b, c, d;
int count;
u32 bitPattern = 0x80808080; // r7
u32 crcConst = 0x1021; // r8
u32 dataByte = 0; // r2
a = 0; // r3
b = 0; // r4
c = 0; // r5
d = 0; // r6
buffLength = buffLength * 8;
do {
if (bitPattern & 0x80) dataByte = *buff++;
a = a << 1;
if ( a & 0x10000) a ^= crcConst;
if (dataByte & (bitPattern >> 24)) a ^= crcConst;
b = b << 1;
if (b & 0x10000) b ^= crcConst;
if (dataByte & (bitPattern >> 25)) b ^= crcConst;
c = c << 1;
if (c & 0x10000) c ^= crcConst;
if (dataByte & (bitPattern >> 26)) c ^= crcConst;
d = d << 1;
if (d & 0x10000) d ^= crcConst;
if (dataByte & (bitPattern >> 27)) d ^= crcConst;
bitPattern = (bitPattern >> 4) | (bitPattern << 28);
} while (buffLength-=4);
count = 16; // r8
do {
bitPattern = bitPattern << 4;
if (a & 0x8000) bitPattern |= 8;
if (b & 0x8000) bitPattern |= 4;
if (c & 0x8000) bitPattern |= 2;
if (d & 0x8000) bitPattern |= 1;
a = a << 1;
b = b << 1;
c = c << 1;
d = d << 1;
count--;
if (!(count & 0x01)) {
*crc16buff++ = (u8)(bitPattern & 0xff);
}
} while (count != 0);
return;
}
/*
Initialise the SD card, after it has been sent into an Idle state
cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
*/
bool _SD_InitCard (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
_SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
bool use4bitBus,
u32 *RCA)
{
u8 responseBuffer[17] = {0};
int i;
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
cmd_6byte_response (responseBuffer, APP_CMD, 0);
// Check that the card gave the correct response
if (responseBuffer[0] != APP_CMD) {
return false;
}
if (
cmd_6byte_response (responseBuffer, SD_APP_OP_COND, SD_OCR_VALUE) &&
((responseBuffer[1] & 0x80) != 0))
{
// Card is ready to receive commands now
break;
}
}
if (i >= MAX_STARTUP_TRIES) {
return false;
}
// The card's name, as assigned by the manufacturer
cmd_17byte_response (responseBuffer, ALL_SEND_CID, 0);
// Get a new address
for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
cmd_6byte_response (responseBuffer, SEND_RELATIVE_ADDR, 0);
*RCA = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
if ((responseBuffer[3] & 0x1e) != (SD_STATE_STBY << 1)) {
break;
}
}
if (i >= MAX_STARTUP_TRIES) {
return false;
}
// Some cards won't go to higher speeds unless they think you checked their capabilities
cmd_17byte_response (responseBuffer, SEND_CSD, *RCA);
// Only this card should respond to all future commands
cmd_6byte_response (responseBuffer, SELECT_CARD, *RCA);
if (use4bitBus) {
// Set a 4 bit data bus
cmd_6byte_response (responseBuffer, APP_CMD, *RCA);
cmd_6byte_response (responseBuffer, SET_BUS_WIDTH, 2); // 4-bit mode.
}
// Use 512 byte blocks
cmd_6byte_response (responseBuffer, SET_BLOCKLEN, 512); // 512 byte blocks
// Wait until card is ready for data
i = 0;
do {
if (i >= RESPONSE_TIMEOUT) {
return false;
}
i++;
} while (!cmd_6byte_response (responseBuffer, SEND_STATUS, *RCA) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
return true;
}

View File

@ -1,117 +0,0 @@
/*
io_sd_common.h
By chishm (Michael Chisholm)
Common SD card routines
SD routines partially based on sd.s by Romman
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-28 - Chishm
* Changed voltage range that the SD card can use
2006-11-14 - Chishm
* Reduced voltage range again. Hopefully fixes MicroSD cards.
*/
#ifndef IO_SD_COMMON_H
#define IO_SD_COMMON_H
#include "../disc.h"
/* SD commands */
#define GO_IDLE_STATE 0
#define ALL_SEND_CID 2
#define SEND_RELATIVE_ADDR 3
#define SELECT_CARD 7
#define SEND_CSD 9
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define GO_INACTIVE_STATE 15
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCK 18
#define WRITE_BLOCK 24
#define WRITE_MULTIPLE_BLOCK 25
#define APP_CMD 55
/* SD App commands */
#define SET_BUS_WIDTH 6
#define SD_APP_OP_COND 41
/* OCR (Operating Conditions Register) send value */
#define SD_OCR_VALUE 0x00030000 /* 2.8V to 3.0V */
//#define SD_OCR_VALUE 0x003F8000 /* 2.7V to 3.4V */
//#define SD_OCR_VALUE 0x00FC0000
/* SD Data repsonses */
#define SD_CARD_BUSY 0xff
/* SD states */
#define SD_STATE_IDLE 0 // Idle state, after power on or GO_IDLE_STATE command
#define SD_STATE_READY 1 // Ready state, after card replies non-busy to SD_APP_OP_COND
#define SD_STATE_IDENT 2 // Identification state, after ALL_SEND_CID
#define SD_STATE_STBY 3 // Standby state, when card is deselected
#define SD_STATE_TRAN 4 // Transfer state, after card is selected and ready for data transfer
#define SD_STATE_DATA 5 //
#define SD_STATE_RCV 6 // Receive data state
#define SD_STATE_PRG 7 // Programming state
#define SD_STATE_DIS 8 // Disconnect state
#define SD_STATE_INA 9 // Inactive state, after GO_INACTIVE_STATE
#define READY_FOR_DATA 1 // bit 8 in card status
/*
Calculate the CRC7 of a command and return it preshifted with
an end bit added
*/
extern u8 _SD_CRC7(u8* data, int size);
/*
Calculate the CRC16 of a block of data, ready for transmission on
four data lines at once
*/
extern void _SD_CRC16 (u8* buff, int buffLength, u8* crc16buff);
typedef bool (*_SD_FN_CMD_6BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
typedef bool (*_SD_FN_CMD_17BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
/*
Initialise the SD card, after it has been sent into an Idle state
cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
*/
extern bool _SD_InitCard (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
_SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
bool use4bitBus,
u32 *RCA);
#endif // define IO_SD_COMMON_H

View File

@ -26,29 +26,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-13 - Chishm
* Moved all externally visible directory related functions to fatdir
* Added _FAT_mkdir_r
2006-08-14 - Chishm
* Added directory iterator functions
2006-08-19 - Chishm
* Updated dirnext return values to return correctly
2006-10-01 - Chishm
* Now clears the whole cluster when creating a new directory, bug found by Hermes
2007-01-10 - Chishm
* Updated directory iterator functions for DevkitPro r20
2007-10-25 - Chishm
* Use CLUSTER_ERROR when an error occurs with the FAT, not CLUSTER_FREE
* Added statvfs functionality
2008-09-11 - Chishm
* Fixed unlink not freeing cluster chains -- discovered by rodries
*/
#include <string.h>
@ -70,15 +47,11 @@
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
PARTITION* partition = NULL;
DIR_ENTRY dirEntry;
// Get the partition this file is on
_FAT_lock();
partition = _FAT_partition_getPartitionFromPath (path);
if (partition == NULL) {
_FAT_unlock();
r->_errno = ENODEV;
return -1;
}
@ -88,14 +61,15 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
path = strchr (path, ':') + 1;
}
if (strchr (path, ':') != NULL) {
_FAT_unlock();
r->_errno = EINVAL;
return -1;
}
_FAT_lock(&partition->lock);
// Search for the file on the disc
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOENT;
return -1;
}
@ -103,7 +77,7 @@ int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st) {
// Fill in the stat struct
_FAT_directory_entryStat (partition, &dirEntry, st);
_FAT_unlock();
_FAT_unlock(&partition->lock);
return 0;
}
@ -116,23 +90,19 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
PARTITION* partition = NULL;
DIR_ENTRY dirEntry;
DIR_ENTRY dirContents;
u32 cluster;
uint32_t cluster;
bool nextEntry;
bool errorOccured = false;
// Get the partition this directory is on
_FAT_lock();
partition = _FAT_partition_getPartitionFromPath (path);
if (partition == NULL) {
_FAT_unlock();
r->_errno = ENODEV;
return -1;
}
// Make sure we aren't trying to write to a read-only disc
if (partition->readOnly) {
_FAT_unlock();
r->_errno = EROFS;
return -1;
}
@ -142,14 +112,15 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
path = strchr (path, ':') + 1;
}
if (strchr (path, ':') != NULL) {
_FAT_unlock();
r->_errno = EINVAL;
return -1;
}
_FAT_lock(&partition->lock);
// Search for the file on the disc
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOENT;
return -1;
}
@ -164,7 +135,7 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
while (nextEntry) {
if (!_FAT_directory_isDot (&dirContents)) {
// The directory had something in it that isn't a reference to itself or it's parent
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EPERM;
return -1;
}
@ -192,7 +163,7 @@ int _FAT_unlink_r (struct _reent *r, const char *path) {
errorOccured = true;
}
_FAT_unlock();
_FAT_unlock(&partition->lock);
if (errorOccured) {
return -1;
} else {
@ -204,11 +175,8 @@ int _FAT_chdir_r (struct _reent *r, const char *path) {
PARTITION* partition = NULL;
// Get the partition this directory is on
_FAT_lock();
partition = _FAT_partition_getPartitionFromPath (path);
if (partition == NULL) {
_FAT_unlock();
r->_errno = ENODEV;
return -1;
}
@ -218,26 +186,20 @@ int _FAT_chdir_r (struct _reent *r, const char *path) {
path = strchr (path, ':') + 1;
}
if (strchr (path, ':') != NULL) {
_FAT_unlock();
r->_errno = EINVAL;
return -1;
}
// Set the default device to match this one
if (!_FAT_partition_setDefaultPartition (partition)) {
_FAT_unlock();
r->_errno = ENOENT;
return -1;
}
_FAT_lock(&partition->lock);
// Try changing directory
if (_FAT_directory_chdir (partition, path)) {
// Successful
_FAT_unlock();
_FAT_unlock(&partition->lock);
return 0;
} else {
// Failed
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOTDIR;
return -1;
}
@ -248,28 +210,27 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
DIR_ENTRY oldDirEntry;
DIR_ENTRY newDirEntry;
const char *pathEnd;
u32 dirCluster;
uint32_t dirCluster;
// Get the partition this directory is on
_FAT_lock();
partition = _FAT_partition_getPartitionFromPath (oldName);
if (partition == NULL) {
_FAT_unlock();
r->_errno = ENODEV;
return -1;
}
_FAT_lock(&partition->lock);
// Make sure the same partition is used for the old and new names
if (partition != _FAT_partition_getPartitionFromPath (newName)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EXDEV;
return -1;
}
// Make sure we aren't trying to write to a read-only disc
if (partition->readOnly) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EROFS;
return -1;
}
@ -279,7 +240,7 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
oldName = strchr (oldName, ':') + 1;
}
if (strchr (oldName, ':') != NULL) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EINVAL;
return -1;
}
@ -287,21 +248,21 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
newName = strchr (newName, ':') + 1;
}
if (strchr (newName, ':') != NULL) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EINVAL;
return -1;
}
// Search for the file on the disc
if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOENT;
return -1;
}
// Make sure there is no existing file / directory with the new name
if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EEXIST;
return -1;
}
@ -318,7 +279,7 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
// Recycling newDirEntry, since it needs to be recreated anyway
if (!_FAT_directory_entryFromPath (partition, &newDirEntry, newName, pathEnd) ||
!_FAT_directory_isDirectory(&newDirEntry)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOTDIR;
return -1;
}
@ -335,26 +296,26 @@ int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName) {
// Write the new entry
if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOSPC;
return -1;
}
// Remove the old entry
if (!_FAT_directory_removeEntry (partition, &oldDirEntry)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EIO;
return -1;
}
// Flush any sectors in the disc cache
if (!_FAT_cache_flush (partition->cache)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EIO;
return -1;
}
_FAT_unlock();
_FAT_unlock(&partition->lock);
return 0;
}
@ -363,14 +324,11 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
bool fileExists;
DIR_ENTRY dirEntry;
const char* pathEnd;
u32 parentCluster, dirCluster;
u8 newEntryData[DIR_ENTRY_DATA_SIZE];
uint32_t parentCluster, dirCluster;
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
_FAT_lock();
partition = _FAT_partition_getPartitionFromPath (path);
if (partition == NULL) {
_FAT_unlock();
r->_errno = ENODEV;
return -1;
}
@ -380,24 +338,25 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
path = strchr (path, ':') + 1;
}
if (strchr (path, ':') != NULL) {
_FAT_unlock();
r->_errno = EINVAL;
return -1;
}
_FAT_lock(&partition->lock);
// Search for the file/directory on the disc
fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL);
// Make sure it doesn't exist
if (fileExists) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EEXIST;
return -1;
}
if (partition->readOnly) {
// We can't write to a read-only partition
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EROFS;
return -1;
}
@ -413,7 +372,7 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
// Recycling dirEntry, since it needs to be recreated anyway
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) ||
!_FAT_directory_isDirectory(&dirEntry)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOTDIR;
return -1;
}
@ -437,7 +396,7 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
dirCluster = _FAT_fat_linkFreeClusterCleared (partition, CLUSTER_FREE);
if (!_FAT_fat_isValidCluster(partition, dirCluster)) {
// No space left on disc for the cluster
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOSPC;
return -1;
}
@ -446,7 +405,7 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
// Write the new directory's entry to it's parent
if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOSPC;
return -1;
}
@ -475,30 +434,29 @@ int _FAT_mkdir_r (struct _reent *r, const char *path, int mode) {
// Flush any sectors in the disc cache
if (!_FAT_cache_flush(partition->cache)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EIO;
return -1;
}
_FAT_unlock();
_FAT_unlock(&partition->lock);
return 0;
}
int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
{
PARTITION* partition = NULL;
u32 freeClusterCount;
unsigned int freeClusterCount;
// Get the partition of the requested path
_FAT_lock();
partition = _FAT_partition_getPartitionFromPath (path);
if (partition == NULL) {
_FAT_unlock();
r->_errno = ENODEV;
return -1;
}
_FAT_lock(&partition->lock);
freeClusterCount = _FAT_fat_freeClusterCount (partition);
// FAT clusters = POSIX blocks
@ -523,7 +481,7 @@ int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
// Maximum filename length.
buf->f_namemax = MAX_FILENAME_LENGTH;
_FAT_unlock();
_FAT_unlock(&partition->lock);
return 0;
}
@ -532,11 +490,8 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
bool fileExists;
_FAT_lock();
state->partition = _FAT_partition_getPartitionFromPath (path);
if (state->partition == NULL) {
_FAT_unlock();
r->_errno = ENODEV;
return NULL;
}
@ -546,22 +501,24 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
path = strchr (path, ':') + 1;
}
if (strchr (path, ':') != NULL) {
_FAT_unlock();
r->_errno = EINVAL;
return NULL;
}
_FAT_lock(&state->partition->lock);
// Get the start cluster of the directory
fileExists = _FAT_directory_entryFromPath (state->partition, &dirEntry, path, NULL);
if (!fileExists) {
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
r->_errno = ENOENT;
return NULL;
}
// Make sure it is a directory
if (! _FAT_directory_isDirectory (&dirEntry)) {
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
r->_errno = ENOTDIR;
return NULL;
}
@ -575,17 +532,18 @@ DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
// We are now using this entry
state->inUse = true;
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
return (DIR_ITER*) state;
}
int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) {
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
_FAT_lock(&state->partition->lock);
// Make sure we are still using this entry
_FAT_lock();
if (!state->inUse) {
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
r->_errno = EBADF;
return -1;
}
@ -594,24 +552,25 @@ int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState) {
state->validEntry =
_FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster);
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
return 0;
}
int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) {
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
_FAT_lock(&state->partition->lock);
// Make sure we are still using this entry
_FAT_lock();
if (!state->inUse) {
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
r->_errno = EBADF;
return -1;
}
// Make sure there is another file to report on
if (! state->validEntry) {
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
r->_errno = ENOENT;
return -1;
}
@ -627,7 +586,7 @@ int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct
state->validEntry =
_FAT_directory_getNextEntry (state->partition, &(state->currentEntry));
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
return 0;
}
@ -635,9 +594,9 @@ int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState) {
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
// We are no longer using this entry
_FAT_lock();
_FAT_lock(&state->partition->lock);
state->inUse = false;
_FAT_unlock();
_FAT_unlock(&state->partition->lock);
return 0;
}

View File

@ -26,19 +26,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-13 - Chishm
* Moved all externally visible directory related functions to fatdir
* Added _FAT_mkdir_r
2006-08-14 - Chishm
* Added directory iterator functions
2007-01-10 - Chishm
* Updated directory iterator functions for DevkitPro r20
2007-10-25 - Chishm
* Added statvfs functionality
*/
@ -55,7 +42,7 @@
typedef struct {
PARTITION* partition;
DIR_ENTRY currentEntry;
u32 startCluster;
uint32_t startCluster;
bool inUse;
bool validEntry;
} DIR_STATE_STRUCT;

View File

@ -26,42 +26,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-17 - Chishm
* Made all path inputs const char*
* Added _FAT_rename_r
2006-08-02 - Chishm
* Fixed _FAT_seek_r
2006-08-13 - Chishm
* Moved all externally visible directory related functions to fatdir
2007-02-11 - Chishm
* Propagate disc errors up to the user app
2007-02-25 - Chishm
* Fixed seek to the end of a file bug
2007-04-12 - Chishm
* Fixed seek to end of file when reading
2007-11-04 - Chishm
* file_extend_r renamed to _FAT_file_extend_r
* A cluster is only allocated for a file when data is written, instead of when the file is opened
2008-05-12 - Chishm
* Modified WinterMute's seek then write fix for elegance
* Removed resetPosition
2008-05-12 - WinterMute
* Modified Chishm's elegant fix to reset the read/write positions
2008-11-12 - Chishm
* Only set append position when file is opened for append, as suggested by rodries. Improves open speed for large files.
*/
@ -84,7 +48,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
bool fileExists;
DIR_ENTRY dirEntry;
const char* pathEnd;
u32 dirCluster;
uint32_t dirCluster;
FILE_STRUCT* file = (FILE_STRUCT*) fileStruct;
partition = _FAT_partition_getPartitionFromPath (path);
@ -130,19 +94,19 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
}
// Search for the file on the disc
_FAT_lock();
_FAT_lock(&partition->lock);
fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL);
// The file shouldn't exist if we are trying to create it
if ((flags & O_CREAT) && (flags & O_EXCL) && fileExists) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EEXIST;
return -1;
}
// It should not be a directory if we're openning a file,
if (fileExists && _FAT_directory_isDirectory(&dirEntry)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EISDIR;
return -1;
}
@ -152,7 +116,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
if (flags & O_CREAT) {
if (partition->readOnly) {
// We can't write to a read-only partition
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EROFS;
return -1;
}
@ -168,7 +132,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Recycling dirEntry, since it needs to be recreated anyway
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) ||
!_FAT_directory_isDirectory(&dirEntry)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOTDIR;
return -1;
}
@ -186,13 +150,13 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC());
if (!_FAT_directory_addEntry (partition, &dirEntry, dirCluster)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOSPC;
return -1;
}
} else {
// file doesn't exist, and we aren't creating it
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOENT;
return -1;
}
@ -210,7 +174,7 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
// Make sure we aren't trying to write to a read-only file
if (file->write && !_FAT_directory_isWritable(&dirEntry)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EROFS;
return -1;
}
@ -257,25 +221,39 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
file->appendPosition = file->rwPosition;
}
file->modified = false;
file->inUse = true;
// Insert this file into the double-linked list of open files
partition->openFileCount += 1;
_FAT_unlock();
if (partition->firstOpenFile) {
file->nextOpenFile = partition->firstOpenFile;
partition->firstOpenFile->prevOpenFile = file;
} else {
file->nextOpenFile = NULL;
}
file->prevOpenFile = NULL;
partition->firstOpenFile = file;
_FAT_unlock(&partition->lock);
return (int) file;
}
int _FAT_close_r (struct _reent *r, int fd) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
u8 dirEntryData[DIR_ENTRY_DATA_SIZE];
/*
Synchronizes the file data to disc.
Does no locking of its own -- lock the partition before calling.
Returns 0 on success, an error code on failure.
*/
int _FAT_syncToDisc (FILE_STRUCT* file) {
uint8_t dirEntryData[DIR_ENTRY_DATA_SIZE];
_FAT_lock();
if (!file->inUse) {
_FAT_unlock();
r->_errno = EBADF;
return -1;
if (!file || !file->inUse) {
return EBADF;
}
if (file->write) {
if (file->write && file->modified) {
// Load the old entry
_FAT_cache_readPartialSector (file->partition->cache, dirEntryData,
_FAT_fat_clusterToSector(file->partition, file->dirEntryEnd.cluster) + file->dirEntryEnd.sector,
@ -296,6 +274,9 @@ int _FAT_close_r (struct _reent *r, int fd) {
// Access date
u16_to_u8array (dirEntryData, DIR_ENTRY_aDate, _FAT_filetime_getDateFromRTC());
// Set archive attribute
dirEntryData[DIR_ENTRY_attributes] |= ATTRIB_ARCH;
// Write the new entry
_FAT_cache_writePartialSector (file->partition->cache, dirEntryData,
_FAT_fat_clusterToSector(file->partition, file->dirEntryEnd.cluster) + file->dirEntryEnd.sector,
@ -303,47 +284,73 @@ int _FAT_close_r (struct _reent *r, int fd) {
// Flush any sectors in the disc cache
if (!_FAT_cache_flush(file->partition->cache)) {
_FAT_unlock();
r->_errno = EIO;
return -1;
return EIO;
}
}
}
file->inUse = false;
file->partition->openFileCount -= 1;
_FAT_unlock();
file->modified = false;
return 0;
}
int _FAT_read_r (struct _reent *r, int fd, char *ptr, int len) {
int _FAT_close_r (struct _reent *r, int fd) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
int ret = 0;
PARTITION* partition;
CACHE* cache;
FILE_POSITION position;
u32 tempNextCluster;
int tempVar;
u32 remain;
bool flagNoError = true;
// Make sure we can actually read from the file
_FAT_lock();
if ((file == NULL) || !file->inUse || !file->read) {
_FAT_unlock();
if (!file->inUse) {
r->_errno = EBADF;
return -1;
}
_FAT_lock(&file->partition->lock);
ret = _FAT_syncToDisc (file);
if (ret != 0) {
r->_errno = ret;
ret = -1;
}
file->inUse = false;
// Remove this file from the double-linked list of open files
file->partition->openFileCount -= 1;
if (file->nextOpenFile) {
file->nextOpenFile->prevOpenFile = file->prevOpenFile;
}
if (file->prevOpenFile) {
file->prevOpenFile->nextOpenFile = file->nextOpenFile;
} else {
file->partition->firstOpenFile = file->nextOpenFile;
}
_FAT_unlock(&file->partition->lock);
return ret;
}
ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
PARTITION* partition;
CACHE* cache;
FILE_POSITION position;
uint32_t tempNextCluster;
unsigned int tempVar;
size_t remain;
bool flagNoError = true;
// Make sure we can actually read from the file
if ((file == NULL) || !file->inUse || !file->read) {
r->_errno = EBADF;
return -1;
}
partition = file->partition;
_FAT_lock(&partition->lock);
// Don't try to read if the read pointer is past the end of file
if (file->currentPosition >= file->filesize || file->startCluster == CLUSTER_FREE) {
r->_errno = EOVERFLOW;
_FAT_unlock();
return 0;
}
@ -355,15 +362,11 @@ int _FAT_read_r (struct _reent *r, int fd, char *ptr, int len) {
// Short circuit cases where len is 0 (or less)
if (len <= 0) {
_FAT_unlock();
return 0;
}
remain = len;
position = file->rwPosition;
partition = file->partition;
cache = file->partition->cache;
// Align to sector
@ -480,7 +483,7 @@ int _FAT_read_r (struct _reent *r, int fd, char *ptr, int len) {
file->rwPosition = position;
file->currentPosition += len;
_FAT_unlock();
_FAT_unlock(&partition->lock);
return len;
}
@ -490,14 +493,10 @@ Extend a file so that the size is the same as the rwPosition
static bool _FAT_file_extend_r (struct _reent *r, FILE_STRUCT* file) {
PARTITION* partition = file->partition;
CACHE* cache = file->partition->cache;
FILE_POSITION position;
u32 remain;
u8 zeroBuffer [BYTES_PER_READ] = {0};
u32 tempNextCluster;
uint8_t zeroBuffer [BYTES_PER_READ] = {0};
uint32_t remain;
uint32_t tempNextCluster;
position.byte = file->filesize % BYTES_PER_READ;
position.sector = (file->filesize % partition->bytesPerCluster) / BYTES_PER_READ;
@ -507,20 +506,20 @@ static bool _FAT_file_extend_r (struct _reent *r, FILE_STRUCT* file) {
remain = file->currentPosition - file->filesize;
if ((remain > 0) && (file->filesize > 0) && (position.sector == 0)) {
if ((remain > 0) && (file->filesize > 0) && (position.sector == 0) && (position.byte == 0)) {
// Get a new cluster on the edge of a cluster boundary
tempNextCluster = _FAT_fat_linkFreeCluster(partition, position.cluster);
if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) {
// Couldn't get a cluster, so abort
r->_errno = ENOSPC;
return false;
} else {
position.cluster = tempNextCluster;
}
position.cluster = tempNextCluster;
position.sector = 0;
}
// Only need to clear to the end of the sector
if (remain + position.byte < BYTES_PER_READ) {
// Only need to clear to the end of the sector
_FAT_cache_writePartialSector (cache, zeroBuffer,
_FAT_fat_clusterToSector (partition, position.cluster) + position.sector, position.byte, remain);
position.byte += remain;
@ -543,9 +542,8 @@ static bool _FAT_file_extend_r (struct _reent *r, FILE_STRUCT* file) {
// Couldn't get a cluster, so abort
r->_errno = ENOSPC;
return false;
} else {
position.cluster = tempNextCluster;
}
position.cluster = tempNextCluster;
}
_FAT_disc_writeSectors (partition->disc,
@ -566,9 +564,8 @@ static bool _FAT_file_extend_r (struct _reent *r, FILE_STRUCT* file) {
// Couldn't get a cluster, so abort
r->_errno = ENOSPC;
return false;
} else {
position.cluster = tempNextCluster;
}
position.cluster = tempNextCluster;
}
if (remain > 0) {
@ -584,46 +581,45 @@ static bool _FAT_file_extend_r (struct _reent *r, FILE_STRUCT* file) {
}
int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) {
ssize_t _FAT_write_r (struct _reent *r, int fd, const char *ptr, size_t len) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
PARTITION* partition;
CACHE* cache;
FILE_POSITION position;
u32 tempNextCluster;
int tempVar;
u32 remain;
uint32_t tempNextCluster;
unsigned int tempVar;
size_t remain;
bool flagNoError = true;
bool flagAppending = false;
// Make sure we can actually write to the file
_FAT_lock();
if ((file == NULL) || !file->inUse || !file->write) {
_FAT_unlock();
r->_errno = EBADF;
return -1;
}
// Short circuit cases where len is 0 (or less)
if (len <= 0) {
_FAT_unlock();
return 0;
}
partition = file->partition;
cache = file->partition->cache;
_FAT_lock(&partition->lock);
// Only write up to the maximum file size, taking into account wrap-around of ints
if (remain + file->filesize > FILE_MAX_SIZE || len + file->filesize < file->filesize) {
len = FILE_MAX_SIZE - file->filesize;
}
remain = len;
// Short circuit cases where len is 0 (or less)
if (len <= 0) {
_FAT_unlock(&partition->lock);
return 0;
}
// Get a new cluster for the start of the file if required
if (file->startCluster == CLUSTER_FREE) {
tempNextCluster = _FAT_fat_linkFreeCluster (partition, CLUSTER_FREE);
if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) {
// Couldn't get a cluster, so abort immediately
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = ENOSPC;
return -1;
}
@ -646,7 +642,7 @@ int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) {
// If the write pointer is past the end of the file, extend the file to that size
if (file->currentPosition > file->filesize) {
if (!_FAT_file_extend_r (r, file)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
return -1;
}
}
@ -796,10 +792,11 @@ int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) {
}
// Amount read is the originally requested amount minus stuff remaining
// Amount written is the originally requested amount minus stuff remaining
len = len - remain;
// Update file information
file->modified = true;
if (file->append) {
// Appending doesn't affect the read pointer
file->appendPosition = position;
@ -813,59 +810,61 @@ int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len) {
}
}
_FAT_unlock();
_FAT_unlock(&partition->lock);
return len;
}
int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) {
off_t _FAT_seek_r (struct _reent *r, int fd, off_t pos, int dir) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
PARTITION* partition;
u32 cluster, nextCluster;
uint32_t cluster, nextCluster;
int clusCount;
int position;
off_t newPosition;
uint32_t position;
_FAT_lock();
if ((file == NULL) || (file->inUse == false)) {
// invalid file
_FAT_unlock();
r->_errno = EBADF;
return -1;
}
partition = file->partition;
_FAT_lock(&partition->lock);
switch (dir) {
case SEEK_SET:
position = pos;
newPosition = pos;
break;
case SEEK_CUR:
position = file->currentPosition + pos;
newPosition = (off_t)file->currentPosition + pos;
break;
case SEEK_END:
position = file->filesize + pos;
newPosition = (off_t)file->filesize + pos;
break;
default:
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EINVAL;
return -1;
}
if ((pos > 0) && (position < 0)) {
if ((pos > 0) && (newPosition < 0)) {
_FAT_unlock(&partition->lock);
r->_errno = EOVERFLOW;
_FAT_unlock();
return -1;
}
if (position < 0) {
_FAT_unlock();
// newPosition can only be larger than the FILE_MAX_SIZE on platforms where
// off_t is larger than 32 bits.
if (newPosition < 0 || ((sizeof(newPosition) > 4) && newPosition > (off_t)FILE_MAX_SIZE)) {
_FAT_unlock(&partition->lock);
r->_errno = EINVAL;
return -1;
}
position = (uint32_t)newPosition;
// Only change the read/write position if it is within the bounds of the current filesize,
// or at the very edge of the file
if (position <= file->filesize && file->startCluster != CLUSTER_FREE) {
@ -897,7 +896,7 @@ int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) {
file->rwPosition.sector = partition->sectorsPerCluster;
file->rwPosition.byte = 0;
} else {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EINVAL;
return -1;
}
@ -909,7 +908,7 @@ int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) {
// Save position
file->currentPosition = position;
_FAT_unlock();
_FAT_unlock(&partition->lock);
return position;
}
@ -917,27 +916,24 @@ int _FAT_seek_r (struct _reent *r, int fd, int pos, int dir) {
int _FAT_fstat_r (struct _reent *r, int fd, struct stat *st) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
PARTITION* partition;
DIR_ENTRY fileEntry;
_FAT_lock();
if ((file == NULL) || (file->inUse == false)) {
// invalid file
_FAT_unlock();
r->_errno = EBADF;
return -1;
}
partition = file->partition;
_FAT_lock(&partition->lock);
// Get the file's entry data
fileEntry.dataStart = file->dirEntryStart;
fileEntry.dataEnd = file->dirEntryEnd;
if (!_FAT_directory_entryFromPosition (partition, &fileEntry)) {
_FAT_unlock();
_FAT_unlock(&partition->lock);
r->_errno = EIO;
return -1;
}
@ -949,7 +945,142 @@ int _FAT_fstat_r (struct _reent *r, int fd, struct stat *st) {
st->st_ino = (ino_t)(file->startCluster); // The file serial number is the start cluster
st->st_size = file->filesize; // File size
_FAT_unlock();
_FAT_unlock(&partition->lock);
return 0;
}
int _FAT_ftruncate_r (struct _reent *r, int fd, off_t len) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
PARTITION* partition;
int ret=0;
uint32_t newSize = (uint32_t)len;
if (len < 0) {
// Trying to truncate to a negative size
r->_errno = EINVAL;
return -1;
}
if ((sizeof(len) > 4) && len > (off_t)FILE_MAX_SIZE) {
// Trying to extend the file beyond what FAT supports
r->_errno = EFBIG;
return -1;
}
if (!file || !file->inUse) {
// invalid file
r->_errno = EBADF;
return -1;
}
if (!file->write) {
// Read-only file
r->_errno = EINVAL;
return -1;
}
partition = file->partition;
_FAT_lock(&partition->lock);
if (newSize > file->filesize) {
// Expanding the file
FILE_POSITION savedPosition;
uint32_t savedOffset;
// Get a new cluster for the start of the file if required
if (file->startCluster == CLUSTER_FREE) {
uint32_t tempNextCluster = _FAT_fat_linkFreeCluster (partition, CLUSTER_FREE);
if (!_FAT_fat_isValidCluster(partition, tempNextCluster)) {
// Couldn't get a cluster, so abort immediately
_FAT_unlock(&partition->lock);
r->_errno = ENOSPC;
return -1;
}
file->startCluster = tempNextCluster;
file->rwPosition.cluster = file->startCluster;
file->rwPosition.sector = 0;
file->rwPosition.byte = 0;
}
// Save the read/write pointer
savedPosition = file->rwPosition;
savedOffset = file->currentPosition;
// Set the position to the new size
file->currentPosition = newSize;
// Extend the file to the new position
if (!_FAT_file_extend_r (r, file)) {
ret = -1;
}
// Set the append position to the new rwPointer
if (file->append) {
file->appendPosition = file->rwPosition;
}
// Restore the old rwPointer;
file->rwPosition = savedPosition;
file->currentPosition = savedOffset;
} else if (newSize < file->filesize){
// Shrinking the file
if (len == 0) {
// Cutting the file down to nothing, clear all clusters used
_FAT_fat_clearLinks (partition, file->startCluster);
file->startCluster = CLUSTER_FREE;
file->appendPosition.cluster = CLUSTER_FREE;
file->appendPosition.sector = 0;
file->appendPosition.byte = 0;
} else {
// Trimming the file down to the required size
unsigned int chainLength;
uint32_t lastCluster;
// Drop the unneeded end of the cluster chain.
// If the end falls on a cluster boundary, drop that cluster too,
// then set a flag to allocate a cluster as needed
chainLength = ((newSize-1) / partition->bytesPerCluster) + 1;
lastCluster = _FAT_fat_trimChain (partition, file->startCluster, chainLength);
if (file->append) {
file->appendPosition.byte = newSize % BYTES_PER_READ;
// Does the end of the file fall on the edge of a cluster?
if (newSize % partition->bytesPerCluster == 0) {
// Set a flag to allocate a new cluster
file->appendPosition.sector = partition->sectorsPerCluster;
} else {
file->appendPosition.sector = (newSize % partition->bytesPerCluster) / BYTES_PER_READ;
}
file->appendPosition.cluster = lastCluster;
}
}
} else {
// Truncating to same length, so don't do anything
}
file->filesize = newSize;
file->modified = true;
_FAT_unlock(&partition->lock);
return ret;
}
int _FAT_fsync_r (struct _reent *r, int fd) {
FILE_STRUCT* file = (FILE_STRUCT*) fd;
int ret = 0;
if (!file->inUse) {
r->_errno = EBADF;
return -1;
}
_FAT_lock(&file->partition->lock);
ret = _FAT_syncToDisc (file);
if (ret != 0) {
r->_errno = ret;
ret = -1;
}
_FAT_unlock(&file->partition->lock);
return ret;
}

View File

@ -26,19 +26,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-17 - Chishm
* Made all path inputs const char*
* Added _FAT_rename_r
2006-07-24 - Chishm
* Removed padding workaround from FILE_STRUCT
2006-08-13 - Chishm
* Moved all externally visible directory related functions to fatdir
*/
@ -52,36 +39,45 @@
#include "partition.h"
#include "directory.h"
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) // 4GiB - 1B
typedef struct {
u32 cluster;
u32 sector;
sec_t sector;
s32 byte;
} FILE_POSITION;
typedef struct {
u32 filesize;
u32 startCluster;
u32 currentPosition;
struct _FILE_STRUCT;
struct _FILE_STRUCT {
uint32_t filesize;
uint32_t startCluster;
uint32_t currentPosition;
FILE_POSITION rwPosition;
FILE_POSITION appendPosition;
bool read;
bool write;
bool append;
bool inUse;
PARTITION* partition;
bool modified;
DIR_ENTRY_POSITION dirEntryStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
DIR_ENTRY_POSITION dirEntryEnd; // Always points to the file's alias entry
} FILE_STRUCT;
PARTITION* partition;
struct _FILE_STRUCT* prevOpenFile; // The previous entry in a double-linked list of open files
struct _FILE_STRUCT* nextOpenFile; // The next entry in a double-linked list of open files
};
typedef struct _FILE_STRUCT FILE_STRUCT;
extern int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
extern int _FAT_close_r (struct _reent *r, int fd);
extern int _FAT_write_r (struct _reent *r,int fd, const char *ptr, int len);
extern ssize_t _FAT_write_r (struct _reent *r,int fd, const char *ptr, size_t len);
extern int _FAT_read_r (struct _reent *r, int fd, char *ptr, int len);
extern ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len);
extern int _FAT_seek_r (struct _reent *r, int fd,int pos, int dir);
extern off_t _FAT_seek_r (struct _reent *r, int fd, off_t pos, int dir);
extern int _FAT_fstat_r (struct _reent *r, int fd, struct stat *st);
@ -95,4 +91,15 @@ extern int _FAT_chdir_r (struct _reent *r, const char *name);
extern int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName);
extern int _FAT_ftruncate_r (struct _reent *r, int fd, off_t len);
extern int _FAT_fsync_r (struct _reent *r, int fd);
/*
Synchronizes the file data to disc.
Does no locking of its own -- lock the partition before calling.
Returns 0 on success, an error code on failure.
*/
extern int _FAT_syncToDisc (FILE_STRUCT* file);
#endif // _FATFILE_H

View File

@ -25,21 +25,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-11 - Chishm
* Made several fixes related to free clusters, thanks to Loopy
2006-10-01 - Chishm
* Added _FAT_fat_linkFreeClusterCleared to clear a cluster when it is allocated
2007-10-25 - Chishm
* Use CLUSTER_ERROR when an error occurs with the FAT, not CLUSTER_FREE
2007-11-04 - Chishm
* _FAT_fat_nextCluster returns CLUSTER_FREE when input cluster is CLUSTER_FREE
*/
@ -50,10 +35,10 @@
/*
Gets the cluster linked from input cluster
*/
u32 _FAT_fat_nextCluster(PARTITION* partition, u32 cluster)
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
{
u32 nextCluster = CLUSTER_FREE;
u32 sector;
uint32_t nextCluster = CLUSTER_FREE;
sec_t sector;
int offset;
if (cluster == CLUSTER_FREE) {
@ -67,6 +52,8 @@ u32 _FAT_fat_nextCluster(PARTITION* partition, u32 cluster)
break;
case FS_FAT12:
{
u32 nextCluster_h;
sector = partition->fat.fatStart + (((cluster * 3) / 2) / BYTES_PER_READ);
offset = ((cluster * 3) / 2) % BYTES_PER_READ;
@ -79,7 +66,7 @@ u32 _FAT_fat_nextCluster(PARTITION* partition, u32 cluster)
offset = 0;
sector++;
}
u32 nextCluster_h = 0;
nextCluster_h = 0;
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster_h, sector, offset, sizeof(u8));
nextCluster |= (nextCluster_h << 8);
@ -96,15 +83,14 @@ u32 _FAT_fat_nextCluster(PARTITION* partition, u32 cluster)
}
break;
}
case FS_FAT16:
sector = partition->fat.fatStart + ((cluster << 1) / BYTES_PER_READ);
offset = (cluster % (BYTES_PER_READ >> 1)) << 1;
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u16));
if (nextCluster >= 0xFFF7)
{
if (nextCluster >= 0xFFF7) {
nextCluster = CLUSTER_EOF;
}
break;
@ -115,8 +101,7 @@ u32 _FAT_fat_nextCluster(PARTITION* partition, u32 cluster)
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u32));
if (nextCluster >= 0x0FFFFFF7)
{
if (nextCluster >= 0x0FFFFFF7) {
nextCluster = CLUSTER_EOF;
}
break;
@ -133,10 +118,10 @@ u32 _FAT_fat_nextCluster(PARTITION* partition, u32 cluster)
writes value into the correct offset within a partition's FAT, based
on the cluster number.
*/
static bool _FAT_fat_writeFatEntry (PARTITION* partition, u32 cluster, u32 value) {
u32 sector;
static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value) {
sec_t sector;
int offset;
u32 oldValue;
uint32_t oldValue;
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
{
@ -218,10 +203,10 @@ to end of file, links the input cluster to it then returns the
cluster number
If an error occurs, return CLUSTER_ERROR
-----------------------------------------------------------------*/
u32 _FAT_fat_linkFreeCluster(PARTITION* partition, u32 cluster) {
u32 firstFree;
u32 curLink;
u32 lastCluster;
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster) {
uint32_t firstFree;
uint32_t curLink;
uint32_t lastCluster;
bool loopedAroundFAT = false;
lastCluster = partition->fat.lastCluster;
@ -278,10 +263,10 @@ to end of file, links the input cluster to it, clears the new
cluster to 0 valued bytes, then returns the cluster number
If an error occurs, return CLUSTER_ERROR
-----------------------------------------------------------------*/
u32 _FAT_fat_linkFreeClusterCleared (PARTITION* partition, u32 cluster) {
u32 newCluster;
int i;
u8 emptySector[BYTES_PER_READ];
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster) {
uint32_t newCluster;
uint32_t i;
uint8_t emptySector[BYTES_PER_READ];
// Link the cluster
newCluster = _FAT_fat_linkFreeCluster(partition, cluster);
@ -306,8 +291,8 @@ u32 _FAT_fat_linkFreeClusterCleared (PARTITION* partition, u32 cluster) {
_FAT_fat_clearLinks
frees any cluster used by a file
-----------------------------------------------------------------*/
bool _FAT_fat_clearLinks (PARTITION* partition, u32 cluster) {
u32 nextCluster;
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster) {
uint32_t nextCluster;
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
return false;
@ -331,11 +316,48 @@ bool _FAT_fat_clearLinks (PARTITION* partition, u32 cluster) {
return true;
}
/*-----------------------------------------------------------------
_FAT_fat_trimChain
Drop all clusters past the chainLength.
If chainLength is 0, all clusters are dropped.
If chainLength is 1, the first cluster is kept and the rest are
dropped, and so on.
Return the last cluster left in the chain.
-----------------------------------------------------------------*/
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength) {
uint32_t nextCluster;
if (chainLength == 0) {
// Drop the entire chain
_FAT_fat_clearLinks (partition, startCluster);
return CLUSTER_FREE;
} else {
// Find the last cluster in the chain, and the one after it
chainLength--;
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) {
chainLength--;
startCluster = nextCluster;
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
}
// Drop all clusters after the last in the chain
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF) {
_FAT_fat_clearLinks (partition, nextCluster);
}
// Mark the last cluster in the chain as the end of the file
_FAT_fat_writeFatEntry (partition, startCluster, CLUSTER_EOF);
return startCluster;
}
}
/*-----------------------------------------------------------------
_FAT_fat_lastCluster
Trace the cluster links until the last one is found
-----------------------------------------------------------------*/
u32 _FAT_fat_lastCluster (PARTITION* partition, u32 cluster) {
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster) {
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF)) {
cluster = _FAT_fat_nextCluster(partition, cluster);
}
@ -346,9 +368,9 @@ u32 _FAT_fat_lastCluster (PARTITION* partition, u32 cluster) {
_FAT_fat_freeClusterCount
Return the number of free clusters available
-----------------------------------------------------------------*/
u32 _FAT_fat_freeClusterCount (PARTITION* partition) {
u32 count = 0;
u32 curCluster;
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition) {
unsigned int count = 0;
uint32_t curCluster;
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++) {
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE) {

View File

@ -25,18 +25,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-10-01 - Chishm
* Added _FAT_fat_linkFreeClusterCleared to clear a cluster when it is allocated
2007-10-25 - Chishm
* Use CLUSTER_ERROR when an error occurs with the FAT, not CLUSTER_FREE
2008-08-17 - Chishm
* Added CLUSTER_ROOT definition
*/
#ifndef _FAT_H
@ -56,22 +44,26 @@
#define CLUSTERS_PER_FAT16 65525
u32 _FAT_fat_nextCluster(PARTITION* partition, u32 cluster);
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster);
u32 _FAT_fat_linkFreeCluster(PARTITION* partition, u32 cluster);
u32 _FAT_fat_linkFreeClusterCleared (PARTITION* partition, u32 cluster);
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster);
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster);
bool _FAT_fat_clearLinks (PARTITION* partition, u32 cluster);
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster);
u32 _FAT_fat_lastCluster (PARTITION* partition, u32 cluster);
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength);
u32 _FAT_fat_freeClusterCount (PARTITION* partition);
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster);
static inline u32 _FAT_fat_clusterToSector (PARTITION* partition, u32 cluster) {
return (cluster >= CLUSTER_FIRST) ? ((cluster - CLUSTER_FIRST) * partition->sectorsPerCluster) + partition->dataStart : partition->rootDirStart;
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition);
static inline sec_t _FAT_fat_clusterToSector (PARTITION* partition, uint32_t cluster) {
return (cluster >= CLUSTER_FIRST) ?
((cluster - CLUSTER_FIRST) * (sec_t)partition->sectorsPerCluster) + partition->dataStart :
partition->rootDirStart;
}
static inline bool _FAT_fat_isValidCluster (PARTITION* partition, u32 cluster) {
static inline bool _FAT_fat_isValidCluster (PARTITION* partition, uint32_t cluster) {
return (cluster >= CLUSTER_FIRST) && (cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */);
}

View File

@ -24,27 +24,12 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-09-30 - Chishm
* Validity checks performed on the time supplied by the IPC
* Cleaned up magic numbers
2006-10-01 - Chishm
* Fixed incorrect use of bitwise-or instead of logical-or
2007-10-30 - Chishm
* Uses standard POSIX time functions
2007-11-04 - Chishm
* Fix off-by-one error for months value
*/
#include <time.h>
#include "filetime.h"
#include "common.h"
#define MAX_HOUR 23
#define MAX_MINUTE 59
@ -55,8 +40,8 @@
#define MAX_DAY 31
#define MIN_DAY 1
u16 _FAT_filetime_getTimeFromRTC (void) {
#ifndef GBA
uint16_t _FAT_filetime_getTimeFromRTC (void) {
#ifdef USE_RTC_TIME
struct tm timeParts;
time_t epochTime;
@ -82,8 +67,8 @@ u16 _FAT_filetime_getTimeFromRTC (void) {
}
u16 _FAT_filetime_getDateFromRTC (void) {
#ifndef GBA
uint16_t _FAT_filetime_getDateFromRTC (void) {
#ifdef USE_RTC_TIME
struct tm timeParts;
time_t epochTime;
@ -105,7 +90,7 @@ u16 _FAT_filetime_getDateFromRTC (void) {
#endif
}
time_t _FAT_filetime_to_time_t (u16 t, u16 d) {
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d) {
struct tm timeParts;
timeParts.tm_hour = t >> 11;

View File

@ -24,12 +24,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2007-10-30 - Chishm
* Uses standard POSIX time functions
*/
#ifndef _FILETIME_H
@ -38,10 +32,10 @@
#include "common.h"
#include <sys/types.h>
u16 _FAT_filetime_getTimeFromRTC (void);
u16 _FAT_filetime_getDateFromRTC (void);
uint16_t _FAT_filetime_getTimeFromRTC (void);
uint16_t _FAT_filetime_getDateFromRTC (void);
time_t _FAT_filetime_to_time_t (u16 t, u16 d);
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d);
#endif // _FILETIME_H

View File

@ -24,24 +24,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-08-13 - Chishm
* Moved all externally visible directory related functions to fatdir
2006-08-14 - Chishm
* Added extended devoptab_t functions
2007-01-10 - Chishm
* fatInit now sets the correct path when setAsDefaultDevice
2007-01-11 - Chishm
* Added missing #include <unistd.h>
2007-10-25 - Chishm
* Added statvfs functionality
*/
#include <sys/iosupport.h>
@ -53,14 +35,10 @@
#include "fatfile.h"
#include "fatdir.h"
#include "lock.h"
#include "mem_allocate.h"
#include "disc.h"
#ifdef GBA
#define DEFAULT_CACHE_PAGES 2
#else
#define DEFAULT_CACHE_PAGES 8
#endif
const devoptab_t dotab_fat = {
static const devoptab_t dotab_fat = {
"fat",
sizeof (FILE_STRUCT),
_FAT_open_r,
@ -80,44 +58,111 @@ const devoptab_t dotab_fat = {
_FAT_dirreset_r,
_FAT_dirnext_r,
_FAT_dirclose_r,
_FAT_statvfs_r
_FAT_statvfs_r,
_FAT_ftruncate_r,
_FAT_fsync_r,
NULL /* Device data */
};
bool fatInit (u32 cacheSize, bool setAsDefaultDevice) {
int i;
bool device = false, setDefault = false;
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize) {
PARTITION* partition;
devoptab_t* devops;
char* nameCopy;
if ( PI_MAX_PARTITIONS == 1 ) {
if ( _FAT_partition_mount ( 0 , cacheSize) ) {
_FAT_partition_setDefaultInterface (0);
} else {
devops = _FAT_mem_allocate (sizeof(devoptab_t) + strlen(name) + 1);
if (!devops) {
return false;
}
// Use the space allocated at the end of the devoptab struct for storing the name
nameCopy = (char*)(devops+1);
// Initialize the file system
partition = _FAT_partition_constructor (interface, cacheSize, startSector);
if (!partition) {
_FAT_mem_free (devops);
return false;
}
} else {
// Add an entry for this device to the devoptab table
memcpy (devops, &dotab_fat, sizeof(dotab_fat));
strcpy (nameCopy, name);
devops->name = nameCopy;
devops->deviceData = partition;
for ( i = 1; i < PI_MAX_PARTITIONS; i++ ) {
device = _FAT_partition_mount ( i , cacheSize);
if ( device && !setDefault ) {
_FAT_partition_setDefaultInterface (i);
setDefault = true;
}
}
if ( !setDefault ) return false;
AddDevice (devops);
return true;
}
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) {
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES);
}
void fatUnmount (const char* name) {
devoptab_t *devops;
PARTITION* partition;
devops = (devoptab_t*)GetDeviceOpTab (name);
if (!devops) {
return;
}
AddDevice (&dotab_fat);
// Perform a quick check to make sure we're dealing with a libfat controlled device
if (devops->open_r != dotab_fat.open_r) {
return;
}
if (!RemoveDevice (name)) {
return;
}
partition = (PARTITION*)devops->deviceData;
_FAT_partition_destructor (partition);
_FAT_mem_free (devops);
}
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
int i;
int defaultDevice = -1;
const DISC_INTERFACE *disc;
for (i = 0;
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
i++)
{
disc = _FAT_disc_interfaces[i].getInterface();
if (disc->startup() && fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize)) {
// The first device to successfully mount is set as the default
if (defaultDevice < 0) {
defaultDevice = i;
}
}
}
if (defaultDevice < 0) {
// None of our devices mounted
return false;
}
if (setAsDefaultDevice) {
char filePath[MAXPATHLEN * 2] = "fat:/";
#ifndef GBA
char filePath[MAXPATHLEN * 2];
strcpy (filePath, _FAT_disc_interfaces[defaultDevice].name);
strcat (filePath, ":/");
#ifdef ARGV_MAGIC
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 ) {
if ( !strncasecmp( __system_argv->argv[0], "fat", 3)) {
// Check the app's path against each of our mounted devices, to see
// if we can support it. If so, change to that path.
for (i = 0;
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
i++)
{
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
strlen(_FAT_disc_interfaces[i].name)))
{
char *lastSlash;
strcpy(filePath, __system_argv->argv[0]);
char *lastSlash = strrchr( filePath, '/' );
lastSlash = strrchr( filePath, '/' );
if ( NULL != lastSlash) {
if ( *(lastSlash - 1) == ':') lastSlash++;
@ -125,12 +170,11 @@ bool fatInit (u32 cacheSize, bool setAsDefaultDevice) {
}
}
}
}
#endif
chdir (filePath);
}
_FAT_lock_init();
return true;
}
@ -138,23 +182,4 @@ bool fatInitDefault (void) {
return fatInit (DEFAULT_CACHE_PAGES, true);
}
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize) {
return _FAT_partition_mount (partitionNumber, cacheSize);
}
bool fatMountCustomInterface (const IO_INTERFACE* device, u32 cacheSize) {
return _FAT_partition_mountCustomInterface (device, cacheSize);
}
bool fatUnmount (PARTITION_INTERFACE partitionNumber) {
return _FAT_partition_unmount (partitionNumber);
}
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber) {
return _FAT_partition_unsafeUnmount (partitionNumber);
}
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber) {
return _FAT_partition_setDefaultInterface (partitionNumber);
}

View File

@ -1,35 +0,0 @@
/*
lock.h
Copyright (c) 2008 Sven Peter <svpe@gmx.net>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "lock.h"
#if defined(__wii__) || defined(__gamecube__)
mutex_t _FAT_mutex;
#endif /* __wii__ || __gamecube__ */

View File

@ -31,55 +31,56 @@
#include "common.h"
#if defined(__wii__) || defined(__gamecube__)
#ifdef USE_LWP_LOCK
#include <gccore.h>
extern mutex_t _FAT_mutex;
static inline void _FAT_lock_init()
static inline void _FAT_lock_init(mutex_t *mutex)
{
LWP_MutexInit(&_FAT_mutex, false);
LWP_MutexInit(mutex, false);
}
static inline void _FAT_lock_deinit()
static inline void _FAT_lock_deinit(mutex_t *mutex)
{
LWP_MutexDestroy(_FAT_mutex);
LWP_MutexDestroy(*mutex);
}
static inline void _FAT_lock()
static inline void _FAT_lock(mutex_t *mutex)
{
LWP_MutexLock(_FAT_mutex);
LWP_MutexLock(*mutex);
}
static inline void _FAT_unlock()
static inline void _FAT_unlock(mutex_t *mutex)
{
LWP_MutexUnlock(_FAT_mutex);
LWP_MutexUnlock(*mutex);
}
#else
static inline void _FAT_lock_init()
// We still need a blank lock type
#ifndef mutex_t
typedef int mutex_t;
#endif
static inline void _FAT_lock_init(mutex_t *mutex)
{
return;
}
static inline void _FAT_lock_deinit()
static inline void _FAT_lock_deinit(mutex_t *mutex)
{
return;
}
static inline void _FAT_lock()
static inline void _FAT_lock(mutex_t *mutex)
{
return;
}
static inline void _FAT_unlock()
static inline void _FAT_unlock(mutex_t *mutex)
{
return;
}
#endif /* __wii__ || __gamecube__ */
#endif // USE_LWP_LOCK
#endif // _CACHE_H

View File

@ -26,9 +26,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _MEM_ALLOCATE_H
@ -41,7 +38,7 @@ static inline void* _FAT_mem_allocate (size_t size) {
}
static inline void _FAT_mem_free (void* mem) {
return free (mem);
free (mem);
}
#endif // _MEM_ALLOCATE_H

View File

@ -1,169 +0,0 @@
/*
disc.c
uniformed io-interface to work with Chishm's FAT library
Written by MightyMax
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2005-11-06 - Chishm
* Added WAIT_CR modifications for NDS
2006-02-03 www.neoflash.com
* Added SUPPORT_* defines, comment out any of the SUPPORT_* defines in disc_io.h to remove support
for the given interface and stop code being linked to the binary
* Added support for MK2 MMC interface
* Added disc_Cache* functions
2006-02-05 - Chishm
* Added Supercard SD support
2006-02-26 - Cytex
* Added EFA2 support
2006-05-18 - Chishm
* Rewritten for FATlib disc.c
2006-06-19 - Chishm
* Changed read and write interface to accept a u32 instead of a u8 for the number of sectors
2006-07-11 - Chishm
* Removed disc_Cache* functions, since there is now a proper unified cache
* Removed SUPPORT_* defines
* Rewrote device detection functions
* First libfat release
2006-07-25 - Chishm
* Changed IO_INTERFACEs to const
2006-08-02 - Chishm
* Added NinjaDS
2006-12-25 - Chishm
* Added DLDI
* Removed experimental interfaces
2007-05-01 - Chishm
* Removed FCSR
*/
#include "../disc.h"
#include "wiisd.h"
#include "gcsd.h"
const IO_INTERFACE* ioInterfaces[] = {
#ifdef __gamecube__
&__io_gcsda,
&__io_gcsdb,
#endif
#ifdef __wii__
&__io_wiisd
#endif
};
#ifdef __wii__
const IO_INTERFACE* _FAT_disc_wiiFindInterface(void)
{
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if ((ioInterfaces[i]->ioType == DEVICE_TYPE_WII) && (ioInterfaces[i]->fn_startup())) {
return ioInterfaces[i];
}
}
return NULL;
}
#endif
const IO_INTERFACE* _FAT_disc_gcFindInterface(void)
{
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if ((ioInterfaces[i]->ioType == DEVICE_TYPE_GC) && (ioInterfaces[i]->fn_startup())) {
return ioInterfaces[i];
}
}
return NULL;
}
const IO_INTERFACE* _FAT_disc_gcFindInterfaceSlot(int slot)
{
int i;
int mask;
if(slot == 0)
mask = FEATURE_GAMECUBE_SLOTA;
else if(slot == 1)
mask = FEATURE_GAMECUBE_SLOTB;
else
return NULL;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if ((ioInterfaces[i]->ioType == DEVICE_TYPE_GC) && (ioInterfaces[i]->features & mask) && (ioInterfaces[i]->fn_startup())) {
return ioInterfaces[i];
}
}
return NULL;
}
const IO_INTERFACE* _FAT_disc_findInterface(void)
{
#ifdef __wii__
return _FAT_disc_wiiFindInterface();
#else
return _FAT_disc_gcFindInterface();
#endif
}
const IO_INTERFACE* _FAT_disc_findInterfaceSlot (PARTITION_INTERFACE partitionNumber)
{
switch(partitionNumber)
{
#ifdef __gamecube__
case PI_SDGECKO_A:
return _FAT_disc_gcFindInterfaceSlot(0);
break;
case PI_SDGECKO_B:
return _FAT_disc_gcFindInterfaceSlot(1);
break;
#endif
#ifdef __wii__
case PI_INTERNAL_SD:
return _FAT_disc_wiiFindInterface();
break;
#endif
default:
return NULL;
break;
}
}

View File

@ -1,43 +0,0 @@
/*
gcsd.h
Hardware routines for reading and writing to SD geckos connected
to the memory card ports.
These functions are just wrappers around libsdcard's functions.
Copyright (c) 2008 Sven "svpe" Peter <svpe@gmx.net>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GCSD_H__
#define __GCSD_H__
#include <gccore.h>
#include "../disc.h"
extern const IO_INTERFACE __io_gcsda;
extern const IO_INTERFACE __io_gcsdb;
#endif

View File

@ -1,41 +0,0 @@
/*
wiisd.c
Hardware routines for reading and writing to the Wii's internal
SD slot.
Copyright (c) 2008 Sven "svpe" Peter <svpe@gmx.net>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __WIISD_H__
#define __WIISD_H__
#include <gccore.h>
#include "../disc.h"
extern const IO_INTERFACE __io_wiisd;
#endif

View File

@ -25,15 +25,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-08-10 - Chishm
* Fixed problem when openning files starting with "fat"
2006-10-28 - Chishm
* _partitions changed to _FAT_partitions to maintain the same style of naming as the functions
*/
@ -41,11 +32,12 @@
#include "bit_ops.h"
#include "file_allocation_table.h"
#include "directory.h"
#include "mem_allocate.h"
#include "fatfile.h"
#include <string.h>
#include <ctype.h>
#include "mem_allocate.h"
#include <sys/iosupport.h>
/*
This device name, as known by devkitPro toolchains
@ -102,25 +94,13 @@ enum BPB {
BPB_bootSig_AA = 0x1FF
};
#if defined(__wii__)
#define MAXIMUM_PARTITIONS 5
#elif defined(__gamecube__)
#define MAXIMUM_PARTITIONS 4
#elif defined(NDS)
#define MAXIMUM_PARTITIONS 4
#else // not defined NDS
#define MAXIMUM_PARTITIONS 1
#endif // defined NDS
PARTITION* _FAT_partitions[MAXIMUM_PARTITIONS] = {NULL};
// Use a single static buffer for the partitions
static const char FAT_SIG[3] = {'F', 'A', 'T'};
static PARTITION* _FAT_partition_constructor ( const IO_INTERFACE* disc, u32 cacheSize) {
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, sec_t startSector) {
PARTITION* partition;
int i;
u32 bootSector;
u8 sectorBuffer[BYTES_PER_READ] = {0};
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
// Read first sector of disc
if ( !_FAT_disc_readSectors (disc, 0, 1, sectorBuffer)) {
@ -132,12 +112,14 @@ static PARTITION* _FAT_partition_constructor ( const IO_INTERFACE* disc, u32 cac
return NULL;
}
if (startSector != 0) {
// We're told where to start the partition, so just accept it
} else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
// Check if there is a FAT string, which indicates this is a boot sector
if ((sectorBuffer[0x36] == 'F') && (sectorBuffer[0x37] == 'A') && (sectorBuffer[0x38] == 'T')) {
bootSector = 0;
} else if ((sectorBuffer[0x52] == 'F') && (sectorBuffer[0x53] == 'A') && (sectorBuffer[0x54] == 'T')) {
startSector = 0;
} else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG))) {
// Check for FAT32
bootSector = 0;
startSector = 0;
} else {
// This is an MBR
// Find first valid partition from MBR
@ -151,14 +133,21 @@ static PARTITION* _FAT_partition_constructor ( const IO_INTERFACE* disc, u32 cac
// Go to first valid partition
if ( i != 0x1FE) {
// Make sure it found a partition
bootSector = u8array_to_u32(sectorBuffer, 0x8 + i);
startSector = u8array_to_u32(sectorBuffer, 0x8 + i);
} else {
bootSector = 0; // No partition found, assume this is a MBR free disk
startSector = 0; // No partition found, assume this is a MBR free disk
}
}
// Now verify that this is indeed a FAT partition
if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) &&
memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
{
return NULL;
}
// Read in boot sector
if ( !_FAT_disc_readSectors (disc, bootSector, 1, sectorBuffer)) {
if ( !_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer)) {
return NULL;
}
@ -167,6 +156,9 @@ static PARTITION* _FAT_partition_constructor ( const IO_INTERFACE* disc, u32 cac
return NULL;
}
// Init the partition lock
_FAT_lock_init(&partition->lock);
// Set partition's disc interface
partition->disc = disc;
@ -184,15 +176,16 @@ static PARTITION* _FAT_partition_constructor ( const IO_INTERFACE* disc, u32 cac
partition->bytesPerSector = BYTES_PER_READ; // Sector size is redefined to be 512 bytes
partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster] * u8array_to_u16(sectorBuffer, BPB_bytesPerSector) / BYTES_PER_READ;
partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster;
partition->fat.fatStart = bootSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors);
partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors);
partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat);
partition->dataStart = partition->rootDirStart + (( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector);
partition->dataStart = partition->rootDirStart +
(( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector);
partition->totalSize = (partition->numberOfSectors - partition->dataStart) * partition->bytesPerSector;
partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector;
// Store info about FAT
partition->fat.lastCluster = (partition->numberOfSectors - partition->dataStart) / partition->sectorsPerCluster;
partition->fat.lastCluster = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster;
partition->fat.firstFree = CLUSTER_FIRST;
if (partition->fat.lastCluster < CLUSTERS_PER_FAT12) {
@ -230,195 +223,38 @@ static PARTITION* _FAT_partition_constructor ( const IO_INTERFACE* disc, u32 cac
return partition;
}
static void _FAT_partition_destructor (PARTITION* partition) {
void _FAT_partition_destructor (PARTITION* partition) {
FILE_STRUCT* nextFile;
_FAT_lock(&partition->lock);
// Synchronize open files
nextFile = partition->firstOpenFile;
while (nextFile) {
_FAT_syncToDisc (nextFile);
nextFile = nextFile->nextOpenFile;
}
// Free memory used by the cache, writing it to disc at the same time
_FAT_cache_destructor (partition->cache);
_FAT_disc_shutdown (partition->disc);
// Unlock the partition and destroy the lock
_FAT_unlock(&partition->lock);
_FAT_lock_deinit(&partition->lock);
// Free memory used by the partition
_FAT_mem_free (partition);
}
bool _FAT_partition_mount (PARTITION_INTERFACE partitionNumber, u32 cacheSize) {
int i;
const IO_INTERFACE* disc = NULL;
if (_FAT_partitions[partitionNumber] != NULL) {
return false;
}
disc = _FAT_disc_findInterfaceSlot (partitionNumber);
if (disc == NULL) {
return false;
}
// See if that disc is already in use, if so, then just copy the partition pointer
for (i = 0; i < MAXIMUM_PARTITIONS; i++) {
if ((_FAT_partitions[i] != NULL) && (_FAT_partitions[i]->disc == disc)) {
_FAT_partitions[partitionNumber] = _FAT_partitions[i];
return true;
}
}
_FAT_partitions[partitionNumber] = _FAT_partition_constructor (disc, cacheSize);
if (_FAT_partitions[partitionNumber] == NULL) {
return false;
}
return true;
}
bool _FAT_partition_mountCustomInterface (const IO_INTERFACE* device, u32 cacheSize) {
#ifdef GBA
if (_FAT_partitions[0] != NULL) return false;
if (device == NULL) return false;
// Only ever one partition on GBA
_FAT_partitions[0] = _FAT_partition_constructor (device, cacheSize);
#else
int i;
if (_FAT_partitions[PI_CUSTOM] != NULL) return false;
if (device == NULL) return false;
// See if that disc is already in use, if so, then just copy the partition pointer
for (i = 0; i < MAXIMUM_PARTITIONS; i++) {
if ((_FAT_partitions[i] != NULL) && (_FAT_partitions[i]->disc == device)) {
_FAT_partitions[PI_CUSTOM] = _FAT_partitions[i];
return true;
}
}
_FAT_partitions[PI_CUSTOM] = _FAT_partition_constructor (device, cacheSize);
if (_FAT_partitions[PI_CUSTOM] == NULL) {
return false;
}
#endif
return true;
}
bool _FAT_partition_setDefaultInterface (PARTITION_INTERFACE partitionNumber) {
#ifndef GBA // Can only set the default partition when there is more than 1, so doesn't apply to GBA
if ((partitionNumber < 1) || (partitionNumber >= MAXIMUM_PARTITIONS)) {
return false;
}
if (_FAT_partitions[partitionNumber] == NULL) {
return false;
}
_FAT_partitions[PI_DEFAULT] = _FAT_partitions[partitionNumber];
#endif
return true;
}
bool _FAT_partition_setDefaultPartition (PARTITION* partition) {
#ifndef GBA // Can only set the default partition when there is more than 1, so doesn't apply to GBA
int i;
if (partition == NULL) {
return false;
}
// Ensure that this device is already in the list
for (i = 1; i < MAXIMUM_PARTITIONS; i++) {
if (_FAT_partitions[i] == partition) {
break;
}
}
// It wasn't in the list, so fail
if (i == MAXIMUM_PARTITIONS) {
return false;
}
// Change the default partition / device to this one
_FAT_partitions[PI_DEFAULT] = partition;
#endif
return true;
}
bool _FAT_partition_unmount (PARTITION_INTERFACE partitionNumber) {
int i;
PARTITION* partition = _FAT_partitions[partitionNumber];
if (partition == NULL) {
return false;
}
if (partition->openFileCount > 0) {
// There are still open files that need closing
return false;
}
// Remove all references to this partition
for (i = 0; i < MAXIMUM_PARTITIONS; i++) {
if (_FAT_partitions[i] == partition) {
_FAT_partitions[i] = NULL;
}
}
_FAT_partition_destructor (partition);
return true;
}
bool _FAT_partition_unsafeUnmount (PARTITION_INTERFACE partitionNumber) {
int i;
PARTITION* partition = _FAT_partitions[partitionNumber];
if (partition == NULL) {
return false;
}
// Remove all references to this partition
for (i = 0; i < MAXIMUM_PARTITIONS; i++) {
if (_FAT_partitions[i] == partition) {
_FAT_partitions[i] = NULL;
}
}
_FAT_cache_invalidate (partition->cache);
_FAT_partition_destructor (partition);
return true;
}
PARTITION* _FAT_partition_getPartitionFromPath (const char* path) {
const devoptab_t *devops;
#ifdef GBA
return _FAT_partitions[0];
#else
int namelen;
int partitionNumber;
devops = GetDeviceOpTab (path);
// Device name extraction code taken from DevKitPro
namelen = strlen(DEVICE_NAME);
if (strchr (path, ':') == NULL) {
// No device specified
partitionNumber = PI_DEFAULT;
} else if( strncmp(DEVICE_NAME, path, namelen) == 0 ) {
if ( path[namelen] == ':' ) {
// Only the device name is specified
partitionNumber = PI_DEFAULT;
} else if (isdigit(path[namelen]) && path[namelen+1] ==':' ) {
// Device name and number specified
partitionNumber = path[namelen] - '0';
} else {
// Incorrect device name
return NULL;
}
} else {
// Incorrect device name
if (!devops) {
return NULL;
}
if ((partitionNumber < 0) || (partitionNumber >= MAXIMUM_PARTITIONS)) {
return NULL;
}
return _FAT_partitions[partitionNumber];
#endif
return (PARTITION*)devops->deviceData;
}

View File

@ -25,9 +25,6 @@
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _PARTITION_H
@ -35,6 +32,7 @@
#include "common.h"
#include "cache.h"
#include "lock.h"
// Device name
extern const char* DEVICE_NAME;
@ -42,75 +40,48 @@ extern const char* DEVICE_NAME;
// Filesystem type
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
typedef struct {
u32 fatStart;
u32 sectorsPerFat;
u32 lastCluster;
u32 firstFree;
sec_t fatStart;
uint32_t sectorsPerFat;
uint32_t lastCluster;
uint32_t firstFree;
} FAT;
typedef struct {
const IO_INTERFACE* disc;
const DISC_INTERFACE* disc;
CACHE* cache;
// Info about the partition
bool readOnly; // If this is set, then do not try writing to the disc
FS_TYPE filesysType;
u32 totalSize;
u32 rootDirStart;
u32 rootDirCluster;
u32 numberOfSectors;
u32 dataStart;
u32 bytesPerSector;
u32 sectorsPerCluster;
u32 bytesPerCluster;
uint64_t totalSize;
sec_t rootDirStart;
uint32_t rootDirCluster;
uint32_t numberOfSectors;
sec_t dataStart;
uint32_t bytesPerSector;
uint32_t sectorsPerCluster;
uint32_t bytesPerCluster;
FAT fat;
// Values that may change after construction
u32 cwdCluster; // Current working directory cluser
u32 openFileCount;
uint32_t cwdCluster; // Current working directory cluster
int openFileCount;
struct _FILE_STRUCT* firstOpenFile; // The start of a linked list of files
mutex_t lock; // A lock for partition operations
} PARTITION;
/*
Mount the device specified by partitionDevice
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
Mount the supplied device and return a pointer to the struct necessary to use it
*/
bool _FAT_partition_mount (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, sec_t startSector);
/*
Mount a partition on a custom device
Dismount the device and free all structures used.
Will also attempt to synchronise all open files to disc.
*/
bool _FAT_partition_mountCustomInterface (const IO_INTERFACE* device, u32 cacheSize);
void _FAT_partition_destructor (PARTITION* partition);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
*/
bool _FAT_partition_unmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool _FAT_partition_unsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:,
based on the device number
*/
bool _FAT_partition_setDefaultInterface (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:,
based on the partition pointer
*/
bool _FAT_partition_setDefaultPartition (PARTITION* partition);
/*
Return the partition specified in a path
For instance, "fat0:", "fat:", "/" and "fat:/" will all
return the default partition
Return the partition specified in a path, as taken from the devoptab.
*/
PARTITION* _FAT_partition_getPartitionFromPath (const char* path);