aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/ds/arm9/source/fat
diff options
context:
space:
mode:
authorNeil Millstone2006-11-03 23:16:29 +0000
committerNeil Millstone2006-11-03 23:16:29 +0000
commitea6663fdfa5f2b9d8351f9b06219d0dae1494a6c (patch)
tree76a1ca3e5f5672194133d3bdaabdb038275a0e57 /backends/platform/ds/arm9/source/fat
parentd5608e82edb4a73f6ab30a8db9a79dc16ed2ed9f (diff)
downloadscummvm-rg350-ea6663fdfa5f2b9d8351f9b06219d0dae1494a6c.tar.gz
scummvm-rg350-ea6663fdfa5f2b9d8351f9b06219d0dae1494a6c.tar.bz2
scummvm-rg350-ea6663fdfa5f2b9d8351f9b06219d0dae1494a6c.zip
Merging in changes made in branch for 0.9.1 release into trunk
svn-id: r24596
Diffstat (limited to 'backends/platform/ds/arm9/source/fat')
-rw-r--r--backends/platform/ds/arm9/source/fat/disc_io.c104
-rw-r--r--backends/platform/ds/arm9/source/fat/disc_io.h190
-rw-r--r--backends/platform/ds/arm9/source/fat/gba_nds_fat.c4
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3_common.c60
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3sd.c739
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3sd.h71
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3sd_asm.s1
-rw-r--r--backends/platform/ds/arm9/source/fat/io_mmcf.c363
-rw-r--r--backends/platform/ds/arm9/source/fat/io_mmcf.h25
-rw-r--r--backends/platform/ds/arm9/source/fat/io_mpcf.c3
-rw-r--r--backends/platform/ds/arm9/source/fat/io_njsd.c679
-rw-r--r--backends/platform/ds/arm9/source/fat/io_njsd.h50
-rw-r--r--backends/platform/ds/arm9/source/fat/io_scsd_asm.s521
-rw-r--r--backends/platform/ds/arm9/source/fat/io_sd_common.c203
-rw-r--r--backends/platform/ds/arm9/source/fat/io_sd_common.h114
15 files changed, 2068 insertions, 1059 deletions
diff --git a/backends/platform/ds/arm9/source/fat/disc_io.c b/backends/platform/ds/arm9/source/fat/disc_io.c
index a977dc9023..69befa09b7 100644
--- a/backends/platform/ds/arm9/source/fat/disc_io.c
+++ b/backends/platform/ds/arm9/source/fat/disc_io.c
@@ -29,6 +29,7 @@
*/
#include "disc_io.h"
+#include "scummconsole.h"
#ifdef NDS
#include <nds.h>
@@ -68,6 +69,14 @@
#include "io_efa2.h"
#endif
+#ifdef SUPPORT_NJSD
+ #include "io_njsd.h"
+#endif
+
+#ifdef SUPPORT_MMCF
+ #include "io_mmcf.h"
+#endif
+
// Keep a pointer to the active interface
LPIO_INTERFACE active_interface = 0;
@@ -79,6 +88,7 @@ LPIO_INTERFACE active_interface = 0;
Added by www.neoflash.com
*/
+int discDetect = 0;
#ifdef DISC_CACHE
@@ -122,16 +132,16 @@ static u32 disc_CacheFindFree(void) {
i = j;
}
}
-
+ /*
if( cache[ i ].sector != CACHE_FREE && cache[i].dirty != 0 ) {
active_interface->fn_WriteSectors( cache[ i ].sector, 1, &cacheBuffer[ i * 512 ] );
- /* todo: handle write error here */
+ /* todo: handle write error here
cache[ i ].sector = CACHE_FREE;
cache[ i ].dirty = 0;
cache[ i ].count = 0;
- }
+ }*/
return i;
}
@@ -210,6 +220,10 @@ bool disc_CacheWriteSector( void *buffer, u32 sector ) {
*/
+void disc_setEnable(int disc) {
+ discDetect = disc;
+}
+
bool disc_setGbaSlotInterface (void)
{
// If running on an NDS, make sure the correct CPU can access
@@ -223,26 +237,45 @@ bool disc_setGbaSlotInterface (void)
#endif
#endif
-#ifdef SUPPORT_M3CF
- // check if we have a M3 perfect CF plugged in
- active_interface = M3CF_GetInterface() ;
+
+#ifdef SUPPORT_M3SD
+ if (discDetect == 1) {
+ // check if we have a M3 perfect SD plugged in
+ active_interface = M3SD_GetInterface() ;
+ if (active_interface->fn_StartUp())
+ {
+ // set M3 SD as default IO
+ return true ;
+ } ;
+ }
+#endif
+
+
+
+
+#ifdef SUPPORT_MMCF
+ // check if we have a GBA Flash Cart plugged in
+ active_interface = MMCF_GetInterface() ;
if (active_interface->fn_StartUp())
{
- // set M3 CF as default IO
+ // set MMCF as default IO
return true ;
} ;
#endif
-#ifdef SUPPORT_M3SD
- // check if we have a M3 perfect SD plugged in
- active_interface = M3SD_GetInterface() ;
+
+
+#ifdef SUPPORT_M3CF
+ // check if we have a M3 perfect CF plugged in
+ active_interface = M3CF_GetInterface() ;
if (active_interface->fn_StartUp())
{
- // set M3 SD as default IO
+ // set M3 CF as default IO
return true ;
} ;
#endif
+
#ifdef SUPPORT_MPCF
// check if we have a GBA Movie Player plugged in
active_interface = MPCF_GetInterface() ;
@@ -253,6 +286,7 @@ bool disc_setGbaSlotInterface (void)
} ;
#endif
+
#ifdef SUPPORT_SCCF
// check if we have a SuperCard CF plugged in
active_interface = SCCF_GetInterface() ;
@@ -263,15 +297,6 @@ bool disc_setGbaSlotInterface (void)
} ;
#endif
-#ifdef SUPPORT_SCSD
- // check if we have a SuperCard SD plugged in
- active_interface = SCSD_GetInterface() ;
- if (active_interface->fn_StartUp())
- {
- // set SC SD as default IO
- return true ;
- } ;
-#endif
#ifdef SUPPORT_EFA2
@@ -283,6 +308,7 @@ bool disc_setGbaSlotInterface (void)
} ;
#endif
+
#ifdef SUPPORT_FCSR
// check if we have a GBA Flash Cart plugged in
active_interface = FCSR_GetInterface() ;
@@ -293,6 +319,9 @@ bool disc_setGbaSlotInterface (void)
} ;
#endif
+
+
+
return false;
}
@@ -310,6 +339,29 @@ bool disc_setDsSlotInterface (void)
WAIT_CR |= (1<<11);
#endif
+#ifdef SUPPORT_SCSD
+ // check if we have a SuperCard SD plugged in
+ if (discDetect == 2) {
+ active_interface = SCSD_GetInterface() ;
+ consolePrintf("SCSD!");
+ if (active_interface->fn_StartUp())
+ {
+ // set SC SD as default IO
+ return true ;
+ } ;
+ }
+#endif
+
+#ifdef SUPPORT_NJSD
+ // check if we have a GBA Flash Cart plugged in
+ active_interface = NJSD_GetInterface() ;
+ if (active_interface->fn_StartUp())
+ {
+ // set NJSD as default IO
+ return true ;
+ } ;
+#endif
+
#ifdef SUPPORT_NMMC
// check if we have a Neoflash MK2 / MK3 plugged in
active_interface = NMMC_GetInterface() ;
@@ -320,6 +372,9 @@ bool disc_setDsSlotInterface (void)
} ;
#endif
+
+
+
return false;
}
#endif
@@ -378,7 +433,7 @@ bool disc_ReadSectors(u32 sector, u8 numSecs, void* buffer)
bool disc_WriteSectors(u32 sector, u8 numSecs, void* buffer)
{
-#ifdef DISC_CACHE
+/*#ifdef DISC_CACHE
u8 *p=(u8*)buffer;
u32 i;
u32 inumSecs=numSecs;
@@ -389,10 +444,13 @@ bool disc_WriteSectors(u32 sector, u8 numSecs, void* buffer)
return false;
}
return true;
-#else
+#else*/
+#ifdef DISC_CACHE
+ disc_CacheInit();
+#endif
if (active_interface) return active_interface->fn_WriteSectors(sector,numSecs,buffer) ;
return false ;
-#endif
+//#endif
}
bool disc_ClearStatus(void)
diff --git a/backends/platform/ds/arm9/source/fat/disc_io.h b/backends/platform/ds/arm9/source/fat/disc_io.h
index f647f9ac02..e904071c37 100644
--- a/backends/platform/ds/arm9/source/fat/disc_io.h
+++ b/backends/platform/ds/arm9/source/fat/disc_io.h
@@ -10,7 +10,8 @@
// Allow buffers not aligned 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 _CF_ALLOW_UNALIGNED
+#define _CF_ALLOW_UNALIGNED
+#define _IO_ALLOW_UNALIGNED
// Device support options, added by www.neoflash.com
@@ -22,13 +23,15 @@
#define SUPPORT_SCSD // comment out this line to remove Supercard SD support
//#define SUPPORT_EFA2 // comment out this line to remove EFA2 linker support
#define SUPPORT_FCSR // comment out this line to remove GBA Flash Cart support
+#define SUPPORT_NJSD
+#define SUPPORT_MMCF
// Disk caching options, added by www.neoflash.com
// Each additional sector cache uses 512 bytes of memory
// Disk caching is disabled on GBA to conserve memory
#define DISC_CACHE // uncomment this line to enable disc caching
-#define DISC_CACHE_COUNT 16 // maximum number of sectors to cache (512 bytes per sector)
+#define DISC_CACHE_COUNT 32 // maximum number of sectors to cache (512 bytes per sector)
//#define DISK_CACHE_DMA // use DMA for cache copies. If this is enabled, the data buffers must be word aligned
@@ -83,188 +86,8 @@ bool return OUT: true if a disc is inserted
-----------------------------------------------------------------*/
extern bool disc_IsInserted(void) ;
-/*-----------------------------------------------------------------
-disc_ReadSectors
-Read 512 byte sector numbered "sector" into "buffer"
-u32 sector IN: address of first 512 byte sector on disc to read
-u8 numSecs IN: number of 512 byte sectors to read,
- 1 to 256 sectors can be read, 0 = 256
-void* buffer OUT: pointer to 512 byte buffer to store data in
-bool return OUT: true if successful
------------------------------------------------------------------*/
-extern bool disc_ReadSectors(u32 sector, u8 numSecs, void* buffer) ;
-#define disc_ReadSector(sector,buffer) disc_ReadSectors(sector,1,buffer)
-
-/*-----------------------------------------------------------------
-disc_WriteSectors
-Write 512 byte sector numbered "sector" from "buffer"
-u32 sector IN: address of 512 byte sector on disc to write
-u8 numSecs IN: number of 512 byte sectors to write ,
- 1 to 256 sectors can be read, 0 = 256
-void* buffer IN: pointer to 512 byte buffer to read data from
-bool return OUT: true if successful
------------------------------------------------------------------*/
-extern bool disc_WriteSectors(u32 sector, u8 numSecs, void* buffer) ;
-#define disc_WriteSector(sector,buffer) disc_WriteSectors(sector,1,buffer)
-
-/*-----------------------------------------------------------------
-disc_ClearStatus
-Tries to make the disc go back to idle mode
-bool return OUT: true if the disc is idle
------------------------------------------------------------------*/
-extern bool disc_ClearStatus(void) ;
-
-/*-----------------------------------------------------------------
-disc_Shutdown
-unload the disc interface
-bool return OUT: true if successful
------------------------------------------------------------------*/
-extern bool disc_Shutdown(void) ;
-
-/*-----------------------------------------------------------------
-disc_HostType
-Returns a unique u32 number identifying the host type
-u32 return OUT: 0 if no host initialised, else the identifier of
- the host
------------------------------------------------------------------*/
-extern u32 disc_HostType(void);
-
-/*-----------------------------------------------------------------
-disc_CacheFlush
-Flushes any cache writes to disc
-bool return OUT: true if successful, false if an error occurs
-Added by www.neoflash.com
------------------------------------------------------------------*/
-#ifdef DISC_CACHE
-extern bool disc_CacheFlush(void);
-#else
-static inline bool disc_CacheFlush(void)
-{
- return true;
-}
-#endif // DISC_CACHE
-
-
-/*
-
- Interface for IO libs
-
-*/
-
-#define FEATURE_MEDIUM_CANREAD 0x00000001
-#define FEATURE_MEDIUM_CANWRITE 0x00000002
-#define FEATURE_SLOT_GBA 0x00000010
-#define FEATURE_SLOT_NDS 0x00000020
-
-typedef bool (* FN_MEDIUM_STARTUP)(void) ;
-typedef bool (* FN_MEDIUM_ISINSERTED)(void) ;
-typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u8 numSecs, void* buffer) ;
-typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u8 numSecs, void* buffer) ;
-typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ;
-typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ;
-
-
-typedef struct {
- unsigned long ul_ioType ;
- unsigned long ul_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 ;
-} IO_INTERFACE, *LPIO_INTERFACE ;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // define DISC_IO_H
-#ifndef DISC_IO_H
-#define DISC_IO_H
-
-//----------------------------------------------------------------------
-// Customisable features
-
-// Use DMA to read the card, remove this line to use normal reads/writes
-// #define _CF_USE_DMA
-
-// Allow buffers not aligned 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 _CF_ALLOW_UNALIGNED
-
-// Device support options, added by www.neoflash.com
-
-#define SUPPORT_NMMC // comment out this line to remove Neoflash MK2 MMC Card support
-#define SUPPORT_MPCF // comment out this line to remove GBA Movie Player support
-#define SUPPORT_M3CF // comment out this line to remove M3 Perfect CF support
-#define SUPPORT_M3SD // comment out this line to remove M3 Perfect SD support
-#define SUPPORT_SCCF // comment out this line to remove Supercard CF support
-#define SUPPORT_SCSD // comment out this line to remove Supercard SD support
-//#define SUPPORT_EFA2 // comment out this line to remove EFA2 linker support
-#define SUPPORT_FCSR // comment out this line to remove GBA Flash Cart support
-
-// Disk caching options, added by www.neoflash.com
-// Each additional sector cache uses 512 bytes of memory
-// Disk caching is disabled on GBA to conserve memory
-
-#define DISC_CACHE // uncomment this line to enable disc caching
-#define DISC_CACHE_COUNT 16 // maximum number of sectors to cache (512 bytes per sector)
-//#define DISK_CACHE_DMA // use DMA for cache copies. If this is enabled, the data buffers must be word aligned
-
-
-//----------------------------------------------------------------------
-
-#if defined _CF_USE_DMA && defined _CF_ALLOW_UNALIGNED
- #error You can't use both DMA and unaligned memory
-#endif
-
-// When compiling for NDS, make sure NDS is defined
-#ifndef NDS
- #if defined ARM9 || defined ARM7
- #define NDS
- #endif
-#endif
-
-#ifdef NDS
- #include <nds/jtypes.h>
-#else
- #include "gba_types.h"
-#endif
-
-// Disable NDS specific hardware and features if running on a GBA
-#ifndef NDS
- #undef SUPPORT_NMMC
- #undef DISC_CACHE
-#endif
-
-/*
-
- Interface for host program
-
-*/
-
-#define BYTE_PER_READ 512
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*-----------------------------------------------------------------
-disc_Init
-Detects the inserted hardware and initialises it if necessary
-bool return OUT: true if a suitable device was found
------------------------------------------------------------------*/
-extern bool disc_Init(void) ;
-
-/*-----------------------------------------------------------------
-disc_IsInserted
-Is a usable disc inserted?
-bool return OUT: true if a disc is inserted
------------------------------------------------------------------*/
-extern bool disc_IsInserted(void) ;
+extern void disc_setEnable(int en);
/*-----------------------------------------------------------------
disc_ReadSectors
Read 512 byte sector numbered "sector" into "buffer"
@@ -362,3 +185,4 @@ typedef struct {
#endif
#endif // define DISC_IO_H
+
diff --git a/backends/platform/ds/arm9/source/fat/gba_nds_fat.c b/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
index 46aff1ced9..5a44e2dbd9 100644
--- a/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
+++ b/backends/platform/ds/arm9/source/fat/gba_nds_fat.c
@@ -818,17 +818,19 @@ bool FAT_InitFiles (void)
{
return (false);
}
-
// Read first sector of CF card
if ( !disc_ReadSector(0, globalBuffer)) {
return false;
}
+
// Make sure it is a valid MBR or boot sector
if ( (globalBuffer[0x1FE] != 0x55) || (globalBuffer[0x1FF] != 0xAA)) {
return false;
}
+
+
// Check if there is a FAT string, which indicates this is a boot sector
if ((globalBuffer[0x36] == 'F') && (globalBuffer[0x37] == 'A') && (globalBuffer[0x38] == 'T'))
{
diff --git a/backends/platform/ds/arm9/source/fat/io_m3_common.c b/backends/platform/ds/arm9/source/fat/io_m3_common.c
new file mode 100644
index 0000000000..ab2c143327
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_m3_common.c
@@ -0,0 +1,60 @@
+/*
+ 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);
+ }
+}
+
diff --git a/backends/platform/ds/arm9/source/fat/io_m3sd.c b/backends/platform/ds/arm9/source/fat/io_m3sd.c
index 823f94a280..26f249279a 100644
--- a/backends/platform/ds/arm9/source/fat/io_m3sd.c
+++ b/backends/platform/ds/arm9/source/fat/io_m3sd.c
@@ -1,375 +1,526 @@
/*
- io_m3sd.c based on io_m3cf.c by SaTa.
+ io_m3sd.c
- 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
-
- This software is completely free. No warranty is provided.
- If you use it, please give me credit and email me about your
- project at chishm@hotmail.com
-
- See gba_nds_fat.txt for help and license details.
+ 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"
+//#include "common.h"
+#include "disc_io.h"
+#include <stdio.h>
+
+#define BYTES_PER_READ 512
+
+//---------------------------------------------------------------
+// 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);
+}
-#ifdef SUPPORT_M3SD
-
-//SD dir control bit cmddir=bit0 clken=bit1
-//output
-#define SDDIR (*(volatile u16*)0x8800000)
-
-//SD send get control bit send=bit0 get=bit1
-//output
-#define SDCON (*(volatile u16*)0x9800000)
-
-//SD output data obyte[7:0]=AD[7:0]
-//output
-#define SDODA (*(volatile u16*)0x9000000)
-
-//SD input data AD[7:0]=ibyte[7:0]
-//input
-#define SDIDA (*(volatile u16*)0x9000000)
-
-//readsector data1
-#define SDIDA1 (*(volatile u16*)0x9200000)
+static inline bool _M3SD_waitOnBusy (void) {
+ int i = 0;
+ while ( (REG_M3SD_STS & 0x01) == 0x00) {
+ i++;
+ if (i >= TRANSMIT_TIMEOUT) {
+ return false;
+ }
+ }
+ return true;
+}
-//readsector data2
-#define SDIDA2 (*(volatile u16*)0x9400000)
+static inline bool _M3SD_waitForDataReady (void) {
+ int i = 0;
+ while ( (REG_M3SD_STS & 0x40) == 0x00) {
+ i++;
+ if (i >= TRANSMIT_TIMEOUT) {
+ return false;
+ }
+ }
+ return true;
+}
-//readsector data3
-#define SDIDA3 (*(volatile u16*)0x9600000)
-//SD stutas cmdneg=bit0 cmdpos=bit1 issend=bit2 isget=bit3
-//input
-#define SDSTA (*(volatile u16*)0x9800000)
+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;
+}
-//#define CARD_TIMEOUT 10000000 // Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
-#define CARD_TIMEOUT (500*100) // M3SD timeout nomal:500
+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;
+}
-//======================================================
-bool M3SD_read1sector(u32 sectorn,u32 TAddr)
-{
- u32 i;
- int w;
-
- SDCON=0x8; // bit3:コマンドモード?
- SDIDA1=0x40+17; // コマンド CMD17
- SDIDA2=(sectorn>>7);// セクタH 9ビット=アドレスH 16ビット
- SDIDA3=(sectorn<<9);// セクタL 7ビット=アドレスL 16ビット
- SDDIR=0x29; // コマンド送信?
- i=0;
-
- while ( ((SDSTA&0x01) != 0x01)&&(i < CARD_TIMEOUT) )
- {
+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;
+ }
}
- SDDIR=0x09;
- i=0;
- SDDIR=0x49;
- while ( ((SDSTA&0x40) != 0x40)&&(i < CARD_TIMEOUT) )
- {
+ i = 0;
+ while ((REG_M3SD_STS & 0x08) != 0) {
i++;
+ if (i >= TRANSMIT_TIMEOUT) {
+ // Return an empty byte if a timeout occurs
+ return 0xFF;
+ }
}
- SDDIR=0x09;
-
- SDDIR=0x8;//cmd input clken=0 datadir input clock=0
- SDCON=0x4;//send=0 get=0 en25=1 cmd1=0
-
- w = SDDIR;
- for(w=0;w<0x100;w++)
- {
- u16 d16;
- u8 *d8=(u8 *)&d16;
-// *(u16*)(TAddr+w*2) = SDDIR; // 16bit
- d16 = SDDIR; // 16bit
- *(u8 *)(TAddr+w*2) =d8[0];
- *(u8 *)(TAddr+w*2+1) =d8[1];
-
+ // 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;
+ }
}
- w = SDDIR;
- w = SDDIR;
- if (i >= CARD_TIMEOUT)
+ if (dest == NULL) {
+ return true;
+ }
+
+ // Still busy after the timeout has passed
+ if (dataByte == 0xff) {
return false;
-
- return true;
+ }
-}
-//==================================================
-
+ // 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));
-//======================================================
-void SD_crc16(u16* buff,u16 num,u16* crc16buff);
-void SD_data_write(u16 *buff,u16* crc16buff);
+ return true;
+}
-u16 Hal4ATA_StatusByte;
-void Hal4ATA_GetStatus(void)
-{
- Hal4ATA_StatusByte = SDSTA;
+static inline bool _M3SD_getResponse_R1 (u8* dest) {
+ return _M3SD_getResponse (dest, 6);
}
-bool Hal4ATA_WaitOnBusy(void)
-{
- Hal4ATA_GetStatus();
- while ( (Hal4ATA_StatusByte & 0x01) != 0x1)
- {
- Hal4ATA_GetStatus();
- }
- return TRUE;
+static inline bool _M3SD_getResponse_R1b (u8* dest) {
+ return _M3SD_getResponse (dest, 6);
}
-bool Hal4ATA_WaitOnBusyNDrdy(void)
-{
- Hal4ATA_GetStatus();
- while ( (Hal4ATA_StatusByte&0x40) !=0x40)
- {
- Hal4ATA_GetStatus();
- }
- return TRUE;
+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);
+}
-void SendCommand(u16 command, u32 sectorn)
-{
- SDCON=0x8;
- SDIDA1=0x40+command;
- SDIDA2=(sectorn>>7);
- SDIDA3=(sectorn<<9);
+static inline bool _M3SD_getResponse_R6 (u8* dest) {
+ return _M3SD_getResponse (dest, 6);
+}
- SDDIR=0x29;
- Hal4ATA_WaitOnBusy();
- SDDIR=0x09;
+static void _M3SD_sendClocks (u32 numClocks) {
+ while (numClocks--) {
+ _M3SD_sendByte(0xff);
+ }
}
+static void _M3SD_getClocks (u32 numClocks) {
+ while (numClocks--) {
+ _M3SD_getByte();
+ }
+}
-#define DMA3SAD *(u32*)0x040000D4
-#define DMA3DAD *(u32*)0x040000D8
-#define DMA3CNT *(u32*)0x040000DC
+bool _M3SD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
+ _M3SD_sendCommand (command, data);
+ return _M3SD_getResponse (responseBuffer, 6);
+}
-void DMA3(u32 src, u32 dst, u32 cnt)
-{
- DMA3SAD=src;
- DMA3DAD=dst;
- DMA3CNT=cnt;
+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);
-void PassRespond(u32 num)
-{
- u32 i,dmanum;
+ // Card is now reset, including it's address
+ _M3SD_relativeCardAddress = 0;
- dmanum=(64+(num<<3))>>2;
- SDDIR=0x8;
- SDCON=0x4;
- DMA3(0x8800000,(u32)&i,0x80400000+dmanum);
+ // Init the card
+ return _SD_InitCard (_M3SD_cmd_6byte_response,
+ _M3SD_cmd_17byte_response,
+ true,
+ &_M3SD_relativeCardAddress);
}
-//bool M3SD_write1sector(u32 sectorn,u16 * p)
-bool M3SD_write1sector(u32 sectorn,u32 p)
-{
- u16 crc[4];
-
- SendCommand(24,sectorn);
- PassRespond(6);
-
- SDDIR=0x4;
- SDCON=0x0;
+static bool _M3SD_readData (void* buffer) {
+ u32 i;
+ u8* buff_u8 = (u8*)buffer;
+ u16* buff = (u16*)buffer;
+ u16 temp;
- SD_crc16((u16 *)p,512,crc);
- SD_data_write((u16 *)p,crc);
+ 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;
-}
-//==================================================
-
-
-// GBAMP CF Addresses
-
-#define M3_REG_STS *(vu16*)(0x09800000) // Status of the CF Card / Device control
+}
-#define M3_DATA (vu16*)(0x08800000) // Pointer to buffer of CF data transered from card
+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
+ );*/
+}
-// CF Card status
-#define CF_STS_INSERTED1 0x20
-#define CF_STS_INSERTED2 0x30
+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
+ );*/
+}
-/*-----------------------------------------------------------------
-M3SD_IsInserted
-Is a compact flash card inserted?
-bool return OUT: true if a CF card is inserted
------------------------------------------------------------------*/
-bool M3SD_IsInserted (void)
-{
+static bool _M3SD_writeData (u8* data, u8* crc) {
int i;
- u16 sta;
- // Change register, then check if value did change
- M3_REG_STS = CF_STS_INSERTED1;
-
- for(i=0;i<CARD_TIMEOUT;i++)
- {
- sta=M3_REG_STS;
- if((sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2))
- {
- return true;
- //break;
+ 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();
}
}
- return false;
-// return ( (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2) );
-// return true;
+ 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
-/*-----------------------------------------------------------------
-M3SD_ClearStatus
-Tries to make the CF card go back to idle mode
-bool return OUT: true if a CF card is idle
------------------------------------------------------------------*/
-bool M3SD_ClearStatus (void)
-{
-
-// int i=SDDIR;
- int i;
- u16 sta;
+bool _M3SD_startUp (void) {
+ _M3SD_unlock();
+ return _M3SD_initCard();
+}
- i = 0;
- M3_REG_STS = CF_STS_INSERTED1;
- while (i < CARD_TIMEOUT)
- {
- sta=M3_REG_STS;
- if( (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2) )break;
- i++;
+bool _M3SD_isInserted (void) {
+ u8 responseBuffer [6];
+ // Make sure the card receives the command
+ if (!_M3SD_sendCommand (SEND_STATUS, 0)) {
+ return false;
}
- if (i >= CARD_TIMEOUT)
+ // 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;
+ }
-/*-----------------------------------------------------------------
-M3SD_ReadSectors
-Read 512 byte sector numbered "sector" into "buffer"
-u32 sector IN: address of first 512 byte sector on CF card to read
-u8 numSecs IN: number of 512 byte sectors to read,
- 1 to 256 sectors can be read, 0 = 256
-void* buffer OUT: pointer to 512 byte buffer to store data in
-bool return OUT: true if successful
------------------------------------------------------------------*/
-bool M3SD_ReadSectors (u32 sector, u8 numSecs, void* buffer)
-{
-
+ if (!_M3SD_readData (buffer)) {
+ return false;
+ }
- //void M3SD_read1sector(u32 sectorn,u32 TAddr)
- bool r=true;
- int i;
- for(i=0;i<numSecs;i++)
- {
- if(M3SD_read1sector(i + sector , 512*i + (u32) buffer )==false)
- {
- r=false;
- break;
+ } 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 r;
+ return true;
}
-
-
-/*-----------------------------------------------------------------
-M3SD_WriteSectors
-Write 512 byte sector numbered "sector" from "buffer"
-u32 sector IN: address of 512 byte sector on CF card to read
-u8 numSecs IN: number of 512 byte sectors to read,
- 1 to 256 sectors can be read, 0 = 256
-void* buffer IN: pointer to 512 byte buffer to read data from
-bool return OUT: true if successful
------------------------------------------------------------------*/
-bool M3SD_WriteSectors (u32 sector, u8 numSecs, void* buffer)
-{
-
- bool r=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;
- for(i=0;i<numSecs;i++)
- {
- if(M3SD_write1sector(i + sector , 512*i + (u32) buffer )==false)
- {
- r=false;
- break;
+ // 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 r;
-
-// return false;
-
+
+ return true;
}
-
-/*-----------------------------------------------------------------
-M3_Unlock
-Returns true if M3 was unlocked, false if failed
-Added by MightyMax
------------------------------------------------------------------*/
-bool M3SD_Unlock(void)
-{
-
- // run unlock sequence
- volatile unsigned short tmp ;
- tmp = *(volatile unsigned short *)0x08000000 ;
- tmp = *(volatile unsigned short *)0x08E00002 ;
- tmp = *(volatile unsigned short *)0x0800000E ;
- tmp = *(volatile unsigned short *)0x08801FFC ;
- tmp = *(volatile unsigned short *)0x0800104A ;
- tmp = *(volatile unsigned short *)0x08800612 ;
- tmp = *(volatile unsigned short *)0x08000000 ;
- tmp = *(volatile unsigned short *)0x08801B66 ;
- tmp = *(volatile unsigned short *)0x08800006 ;
- tmp = *(volatile unsigned short *)0x08000000 ;
- // test that we have register access
- vu16 sta;
- sta=M3_REG_STS;
- sta=M3_REG_STS;
- if( (sta == CF_STS_INSERTED1)||(sta == CF_STS_INSERTED2) )return true;
-
- return false;
+bool _M3SD_clearStatus (void) {
+ return _M3SD_initCard ();
}
-bool M3SD_Shutdown(void) {
- return M3SD_ClearStatus() ;
-} ;
-
-bool M3SD_StartUp(void) {
- return M3SD_Unlock() ;
-} ;
-
+bool _M3SD_shutdown (void) {
+ _M3_changeMode (M3_MODE_ROM);
+ return true;
+}
-IO_INTERFACE io_m3sd = {
+IO_INTERFACE _io_m3sd = {
DEVICE_TYPE_M3SD,
- FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE,
- (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
+ 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
} ;
-
LPIO_INTERFACE M3SD_GetInterface(void) {
- return &io_m3sd ;
+ return &_io_m3sd ;
} ;
-#endif // SUPPORT_M3CF
diff --git a/backends/platform/ds/arm9/source/fat/io_m3sd.h b/backends/platform/ds/arm9/source/fat/io_m3sd.h
index bd6b2644cc..34d8cdbdeb 100644
--- a/backends/platform/ds/arm9/source/fat/io_m3sd.h
+++ b/backends/platform/ds/arm9/source/fat/io_m3sd.h
@@ -1,39 +1,37 @@
/*
- io_m3sd.h by SaTa.
-
- Hardware Routines for reading an SD card
- using the M3 SD
-
- This software is completely free. No warranty is provided.
- If you use it, please give me credit and email me about your
- project at chishm@hotmail.com
-
- See gba_nds_fat.txt for help and license details.
-*/
-
-#ifndef IO_M3SD_H
-#define IO_M3SD_H
-
-// 'M3SD'
-#define DEVICE_TYPE_M3SD 0x4453334D
-
-#include "disc_io.h"
-
-// export interface
-extern LPIO_INTERFACE M3SD_GetInterface(void) ;
-
-#endif // define IO_M3SD_H
-/*
- io_m3sd.h by SaTa.
-
- Hardware Routines for reading an SD card
- using the M3 SD
-
- This software is completely free. No warranty is provided.
- If you use it, please give me credit and email me about your
- project at chishm@hotmail.com
-
- See gba_nds_fat.txt for help and license details.
+ 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
@@ -45,6 +43,7 @@ extern LPIO_INTERFACE M3SD_GetInterface(void) ;
#include "disc_io.h"
// export interface
-extern LPIO_INTERFACE M3SD_GetInterface(void) ;
+//extern const IO_INTERFACE _io_m3sd ;
+LPIO_INTERFACE M3SD_GetInterface(void);
#endif // define IO_M3SD_H
diff --git a/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s b/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s
index 66d41173ff..ffaa971aca 100644
--- a/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s
+++ b/backends/platform/ds/arm9/source/fat/io_m3sd_asm.s
@@ -193,3 +193,4 @@ sd_data_write_busy2:
ldmfd r13!,{r4-r5,r15}
@-----------------end-------------------
+
diff --git a/backends/platform/ds/arm9/source/fat/io_mmcf.c b/backends/platform/ds/arm9/source/fat/io_mmcf.c
new file mode 100644
index 0000000000..3034afe311
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_mmcf.c
@@ -0,0 +1,363 @@
+/*
+ io_mmcf.c based on
+
+ 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
+
+ This software is completely free. No warranty is provided.
+ If you use it, please give me credit and email me about your
+ project at chishm@hotmail.com
+
+ See gba_nds_fat.txt for help and license details.
+*/
+
+
+#include "io_mmcf.h"
+
+#ifdef SUPPORT_MMCF
+
+//---------------------------------------------------------------
+// DMA
+#ifdef _CF_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
+
+#define CF_RD_DATA (*(volatile u16*)(0x08000000 + 0x00000))
+#define CF_RD_ERROR (*(volatile u16*)(0x08000000 + 0x20000))
+#define CF_RD_SECTOR_COUNT (*(volatile u16*)(0x08000000 + 0x40000))
+#define CF_RD_SECTOR_NO (*(volatile u16*)(0x08000000 + 0x60000))
+#define CF_RD_CYLINDER_LOW (*(volatile u16*)(0x08000000 + 0x80000))
+#define CF_RD_CYLINDER_HIGH (*(volatile u16*)(0x08000000 + 0xA0000))
+#define CF_RD_SEL_HEAD (*(volatile u16*)(0x08000000 + 0xC0000))
+#define CF_RD_STATUS (*(volatile u16*)(0x08000000 + 0xE0000))
+
+#define CF_WR_DATA (*(volatile u16*)(0x08000000 + 0x00000))
+#define CF_WR_FEATURES (*(volatile u16*)(0x08000000 + 0x20000))
+#define CF_WR_SECTOR_COUNT (*(volatile u16*)(0x08000000 + 0x40000))
+#define CF_WR_SECTOR_NO (*(volatile u16*)(0x08000000 + 0x60000))
+#define CF_WR_CYLINDER_LOW (*(volatile u16*)(0x08000000 + 0x80000))
+#define CF_WR_CYLINDER_HIGH (*(volatile u16*)(0x08000000 + 0xA0000))
+#define CF_WR_SEL_HEAD (*(volatile u16*)(0x08000000 + 0xC0000))
+#define CF_WR_COMMAND (*(volatile u16*)(0x08000000 + 0xE0000))
+
+
+#define GAME_PAK 0x08000000 // Game pack start address
+#define MP_DATA (vu16*)(GAME_PAK + 0x01000000) // Pointer to buffer of CF data transered from card
+#define MP_REG_LBA1 *(vu16*)(GAME_PAK + 0x01060000) // 1st byte of sector address
+#define CARD_TIMEOUT 10000000 // Updated due to suggestion from SaTa, otherwise card will timeout sometimes on a write
+
+
+static bool cf_block_ready(void)
+{
+ int i;
+
+ i = 0;
+
+ /*
+ do
+ {
+ while (!(CF_RD_STATUS & 0x40));
+ } while (CF_RD_STATUS & 0x80);
+ */
+
+ do
+ {
+ i++;
+ while ( (!(CF_RD_STATUS & 0x40)) && (i < CARD_TIMEOUT) ) i++;
+ } while ( (CF_RD_STATUS & 0x80) && (i < CARD_TIMEOUT) );
+
+ if (i >= CARD_TIMEOUT) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool cf_set_features(u32 feature)
+{
+ if ( !cf_block_ready() ) return false;
+
+ CF_WR_FEATURES = feature;
+ CF_WR_SECTOR_COUNT = 0x00; // config???
+ CF_WR_SEL_HEAD = 0x00;
+ CF_WR_COMMAND = 0xEF;
+
+ return true;
+}
+
+
+
+/*-----------------------------------------------------------------
+MMCF_IsInserted
+Is a compact flash card inserted?
+bool return OUT: true if a CF card is inserted
+-----------------------------------------------------------------*/
+bool MMCF_IsInserted (void)
+{
+ if ( !cf_set_features(0xAA) ) return false;
+
+ return true;
+}
+
+
+/*-----------------------------------------------------------------
+MMCF_ClearStatus
+Tries to make the CF card go back to idle mode
+bool return OUT: true if a CF card is idle
+-----------------------------------------------------------------*/
+bool MMCF_ClearStatus (void)
+{
+ return true;
+}
+
+
+/*-----------------------------------------------------------------
+MMCF_ReadSectors
+Read 512 byte sector numbered "sector" into "buffer"
+u32 sector IN: address of first 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer OUT: pointer to 512 byte buffer to store data in
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool MMCF_ReadSectors (u32 sector, u8 numSecs, void* buffer)
+{
+ int i;
+ int j = (numSecs > 0 ? numSecs : 256);
+ u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+ u8 *buff_u8 = (u8*)buffer;
+ int temp;
+#endif
+
+#if (defined _CF_USE_DMA) && (defined NDS) && (defined ARM9)
+ DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+ if ( !cf_block_ready() ) return false;
+
+ CF_WR_SECTOR_COUNT = numSecs;
+ CF_WR_SECTOR_NO = sector;
+ CF_WR_CYLINDER_LOW = sector >> 8;
+ CF_WR_CYLINDER_HIGH = sector >> 16;
+ CF_WR_SEL_HEAD = ((sector >> 24) & 0x0F) | 0xE0;
+ CF_WR_COMMAND = 0x20; // read sectors
+
+ while (j--)
+ {
+ if ( !cf_block_ready() ) return false;
+
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+ DMA3_SRC = (u32)MP_DATA;
+ DMA3_DEST = (u32)buff;
+ DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_SRC_FIX;
+ #else
+ DMA3COPY ( MP_DATA, buff, 256 | DMA16 | DMA_ENABLE | DMA_SRC_FIXED);
+ #endif
+ buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+ i=256;
+ if ((u32)buff_u8 & 0x01) {
+ while(i--)
+ {
+ temp = *MP_DATA;
+ *buff_u8++ = temp & 0xFF;
+ *buff_u8++ = temp >> 8;
+ }
+ } else {
+ while(i--)
+ *buff++ = *MP_DATA;
+ }
+#else
+ i=256;
+ while(i--)
+ *buff++ = *MP_DATA;
+#endif
+ }
+
+#if (defined _CF_USE_DMA) && (defined NDS)
+ // Wait for end of transfer before returning
+ while(DMA3_CR & DMA_BUSY);
+#endif
+
+ return true;
+}
+
+
+
+/*-----------------------------------------------------------------
+MMCF_WriteSectors
+Write 512 byte sector numbered "sector" from "buffer"
+u32 sector IN: address of 512 byte sector on CF card to read
+u8 numSecs IN: number of 512 byte sectors to read,
+ 1 to 256 sectors can be read, 0 = 256
+void* buffer IN: pointer to 512 byte buffer to read data from
+bool return OUT: true if successful
+-----------------------------------------------------------------*/
+bool MMCF_WriteSectors (u32 sector, u8 numSecs, void* buffer)
+{
+ int i;
+ int j = (numSecs > 0 ? numSecs : 256);
+ u16 *buff = (u16*)buffer;
+#ifdef _CF_ALLOW_UNALIGNED
+ u8 *buff_u8 = (u8*)buffer;
+ int temp;
+#endif
+
+#if defined _CF_USE_DMA && defined NDS && defined ARM9
+ DC_FlushRange( buffer, j * BYTE_PER_READ);
+#endif
+
+ if (numSecs > 1)
+ {
+ int r = 0;
+
+ for (r = 0; r < numSecs; r++)
+ {
+ MMCF_WriteSectors(sector + r, 1, ((unsigned char *) (buffer)) + 512);
+ }
+ }
+
+ if ( !cf_block_ready() ) return false;
+
+ CF_WR_SECTOR_COUNT = numSecs;
+ CF_WR_SECTOR_NO = sector;
+ CF_WR_CYLINDER_LOW = sector >> 8;
+ CF_WR_CYLINDER_HIGH = sector >> 16;
+ CF_WR_SEL_HEAD = ((sector >> 24) & 0x0F) | 0xE0;
+ CF_WR_COMMAND = 0x30; // write sectors
+
+ while (j--)
+ {
+ if ( !cf_block_ready() ) return false;
+
+#ifdef _CF_USE_DMA
+ #ifdef NDS
+ DMA3_SRC = (u32)buff;
+ DMA3_DEST = (u32)MP_DATA;
+ DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_DST_FIX;
+ #else
+ DMA3COPY( buff, MP_DATA, 256 | DMA16 | DMA_ENABLE | DMA_DST_FIXED);
+ #endif
+ buff += BYTE_PER_READ / 2;
+#elif defined _CF_ALLOW_UNALIGNED
+ i=256;
+ if ((u32)buff_u8 & 0x01) {
+ while(i--)
+ {
+ temp = *buff_u8++;
+ temp |= *buff_u8++ << 8;
+ *MP_DATA = temp;
+ }
+ } else {
+ while(i--)
+ *MP_DATA = *buff++;
+ }
+#else
+ i=256;
+ while(i--)
+ *MP_DATA = *buff++;
+#endif
+
+ }
+
+#if defined _CF_USE_DMA && defined NDS
+ // Wait for end of transfer before returning
+ while(DMA3_CR & DMA_BUSY);
+#endif
+
+//#define _CF_VERIFY
+
+#ifdef _CF_VERIFY
+ char* tmp = malloc(512);
+ int r;
+
+ for (r = 0; r < numSecs; r++)
+ {
+ MMCF_ReadSectors(sector + r, 1, tmp);
+ while (memcmp(temp, ((unsigned char *) (buffer)) + 512 * r, 512) != 0)
+ {
+ consolePrintf("Rewriting sector %d\n", r);
+ MMCF_WriteSectors(sector + r, 1, ((unsigned char *) (buffer)) + 512 * r);
+ MMCF_ReadSectors(sector + r, 1, tmp);
+ }
+ }
+
+ free(temp);
+#endif
+
+ return true;
+}
+
+/*-----------------------------------------------------------------
+MMCF_Shutdown
+unload the GBAMP CF interface
+-----------------------------------------------------------------*/
+bool MMCF_Shutdown(void)
+{
+ return MMCF_ClearStatus() ;
+}
+
+/*-----------------------------------------------------------------
+MMCF_StartUp
+initializes the CF interface, returns true if successful,
+otherwise returns false
+-----------------------------------------------------------------*/
+bool MMCF_StartUp(void)
+{
+ /*
+ u8 temp = MP_REG_LBA1;
+ MP_REG_LBA1 = (~temp & 0xFF);
+ temp = (~temp & 0xFF);
+ return (MP_REG_LBA1 == temp);
+ */
+ if ( (CF_RD_STATUS != 0x0050) || ( *((u8 *) (0x080000B2)) == 0x96) )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/*-----------------------------------------------------------------
+the actual interface structure
+-----------------------------------------------------------------*/
+IO_INTERFACE io_mmcf = {
+ DEVICE_TYPE_MMCF,
+ FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
+ (FN_MEDIUM_STARTUP)&MMCF_StartUp,
+ (FN_MEDIUM_ISINSERTED)&MMCF_IsInserted,
+ (FN_MEDIUM_READSECTORS)&MMCF_ReadSectors,
+ (FN_MEDIUM_WRITESECTORS)&MMCF_WriteSectors,
+ (FN_MEDIUM_CLEARSTATUS)&MMCF_ClearStatus,
+ (FN_MEDIUM_SHUTDOWN)&MMCF_Shutdown
+} ;
+
+/*-----------------------------------------------------------------
+MPCF_GetInterface
+returns the interface structure to host
+-----------------------------------------------------------------*/
+LPIO_INTERFACE MMCF_GetInterface(void) {
+ return &io_mmcf ;
+} ;
+
+#endif // SUPPORT_MMCF
diff --git a/backends/platform/ds/arm9/source/fat/io_mmcf.h b/backends/platform/ds/arm9/source/fat/io_mmcf.h
new file mode 100644
index 0000000000..baa43ac59f
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_mmcf.h
@@ -0,0 +1,25 @@
+/*
+ io_mmcf.h
+
+ Hardware Routines for reading a compact flash card
+ using the GBA Movie Player
+
+ This software is completely free. No warranty is provided.
+ If you use it, please give me credit and email me about your
+ project at chishm@hotmail.com
+
+ See gba_nds_fat.txt for help and license details.
+*/
+
+#ifndef IO_MMCF_H
+#define IO_MMCF_H
+
+// 'MMCF'
+#define DEVICE_TYPE_MMCF 0x4646504D
+
+#include "disc_io.h"
+
+// export interface
+extern LPIO_INTERFACE MMCF_GetInterface(void) ;
+
+#endif // define IO_MMCF_H
diff --git a/backends/platform/ds/arm9/source/fat/io_mpcf.c b/backends/platform/ds/arm9/source/fat/io_mpcf.c
index 1d41ad30a0..a12b6e8e1e 100644
--- a/backends/platform/ds/arm9/source/fat/io_mpcf.c
+++ b/backends/platform/ds/arm9/source/fat/io_mpcf.c
@@ -329,7 +329,8 @@ bool MPCF_StartUp(void)
u8 temp = MP_REG_LBA1;
MP_REG_LBA1 = (~temp & 0xFF);
temp = (~temp & 0xFF);
- return (MP_REG_LBA1 == temp) ;
+ // NDM: Added GBA ROM header check so that this doesn't detect a Max Media Dock!
+ return (MP_REG_LBA1 == temp) && ( *((u8 *) (0x080000B2)) == 0x96);
}
/*-----------------------------------------------------------------
diff --git a/backends/platform/ds/arm9/source/fat/io_njsd.c b/backends/platform/ds/arm9/source/fat/io_njsd.c
new file mode 100644
index 0000000000..8c06b468c7
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_njsd.c
@@ -0,0 +1,679 @@
+/*
+ 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
+*/
+
+#include "io_njsd.h"
+
+#ifdef NDS
+
+#include <nds.h>
+#include <string.h>
+#include "io_sd_common.h"
+
+#define BYTES_PER_READ 512
+//#define _NJSD_SYNC
+// #define _NJSD_DEBUG
+
+//---------------------------------------------------------------
+// Card communication speeds
+#define SD_CLK_200KHz 00
+#define SD_CLK_5MHz 01
+#define SD_CLK_8MHz 02
+#define SD_CLK_12MHz 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 1000
+#define COMMAND_TIMEOUT 10000
+#define MAX_STARTUP_TRIES 2000 // Arbitrary value, check if the card is ready 20 times before giving up
+#define WRITE_TIMEOUT 300 // 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_8MHz; // Default speed;
+
+static u32 _NJSD_cardFlags;
+
+static u32 _NJSD_relativeCardAddress = 0;
+
+#define _NJSD_irqFlag (*(volatile unsigned long*)(0x027FFEB0))
+
+
+static inline bool _NJSD_waitIRQ(void) {
+/*#ifdef _NJSD_SYNC
+ int i = IRQ_TIMEOUT;
+ while (!(REG_IF & 0x100000) && --i);
+ REG_IF = 0x100000;
+ if (i <= 0) {
+ return false;
+ } else {
+ return true;
+ }
+#else*/
+ int i = IRQ_TIMEOUT;
+ //if (!(REG_IME & 1))
+ //{
+ // irq's disabled...
+ while (!(REG_IF & 0x100000) && (!(_NJSD_irqFlag)) && --i);
+ _NJSD_irqFlag = 0;
+ REG_IF = 0x100000;
+ if (i <= 0) {
+ return false;
+ } else {
+ return true;
+ }
+ //} else {
+ // irq's enabled
+ // while (!(_NJSD_irqFlag) && --i);
+ // _NJSD_irqFlag = 0;
+ // REG_IF = 0x100000;
+ // if (i <= 0) {
+ // return false;
+ // } else {
+ // return true;
+ // }
+ //}
+//#endif
+}
+
+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 void _NJSD_irqHandler (void) {
+ _NJSD_irqFlag = 1;
+}
+
+static bool _NJSD_init (u32 flags) {
+ _NJSD_cardFlags = flags;
+
+ REG_IF = 0x100000; // Clear cart IRQ.
+
+ _NJSD_irqFlag = 0;
+#ifdef _NJSD_SYNC
+ irqDisable (IRQ_CARD_LINE);
+#else
+ irqSet(IRQ_CARD_LINE, _NJSD_irqHandler);
+ irqEnable (IRQ_CARD_LINE);
+#endif
+
+ 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_IE &= ~0x100000;
+ 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);
+
+#ifdef _NJSD_DEBUG
+ iprintf ("r: ");
+ for (i = 0; i < 6; i++)
+ iprintf ("%02X ", rsp_buf[i]);
+ iprintf ("\n");
+#endif
+ } 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);
+ }
+
+
+ REG_IE &= ~0x100000;
+ REG_IF = 0x100000;
+
+ 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_200KHz, 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;
+
+#endif
+ REG_IE &= ~0x100000;
+ REG_IF = 0x100000;
+
+ //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_IE &= ~0x100000;
+ 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;
+}
+
+static bool _NJSD_cardInit (void) {
+ u8 responseBuffer[17];
+ int i;
+
+ // If the commands succeed the first time, assume they'll always succeed
+ if (! _NJSD_sendCLK (SD_CLK_200KHz, 256) ) return false;
+ if (! _NJSD_sendCMDN (SD_CLK_200KHz, GO_IDLE_STATE, 0) ) return false;
+ _NJSD_sendCLK (SD_CLK_200KHz, 8);
+
+ _NJSD_sendCLK (SD_CLK_200KHz, 256);
+ _NJSD_sendCMDN (SD_CLK_200KHz, GO_IDLE_STATE, 0);
+ _NJSD_sendCLK (SD_CLK_200KHz, 8);
+
+ for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_48, APP_CMD, 0);
+ if (
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_48, 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
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_136, ALL_SEND_CID, 0);
+
+ // Get a new address
+ for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_48, SEND_RELATIVE_ADDR, 0);
+ _NJSD_relativeCardAddress = (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
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_136, SEND_CSD, _NJSD_relativeCardAddress);
+
+ // Only this card should respond to all future commands
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_48, SELECT_CARD, _NJSD_relativeCardAddress);
+
+ // Set a 4 bit data bus
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_48, APP_CMD, _NJSD_relativeCardAddress);
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_48, SET_BUS_WIDTH, 2); // 4-bit mode.
+
+ // Use 512 byte blocks
+ _NJSD_sendCMDR (SD_CLK_200KHz, responseBuffer, SD_RSP_48, SET_BLOCKLEN, 512); // 512 byte blocks
+
+ return true;
+}
+
+
+bool _NJSD_isInserted(void) {
+ u8 responseBuffer [8];
+ _NJSD_sendCMDR (SD_CLK_200KHz, 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, (u8*)_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, (u8*)_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, (u8*)_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, (u8*)_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, (u8*)_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, (u8*)_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, (u8*)_NJSD_read_cmd);
+ memcpy (tbuf, tmp, BYTES_PER_READ);
+ } else {
+ cardPolledTransfer (0xA1406000, (u32*)tbuf, BYTES_PER_READ, (u8*)_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, (u8*)_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, (u8*)_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, (u8*)_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, (u8*)_NJSD_read_cmd);
+ }
+
+#ifdef _NJSD_SYNC
+ REG_IME = old_REG_IME;
+#endif
+ return true;
+}
+#endif // _IO_ALLOW_UNALIGNED
+
+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
+} ;
+
+LPIO_INTERFACE NJSD_GetInterface(void) {
+ return &io_njsd ;
+} ;
+
+#endif // defined NDS
diff --git a/backends/platform/ds/arm9/source/fat/io_njsd.h b/backends/platform/ds/arm9/source/fat/io_njsd.h
new file mode 100644
index 0000000000..a297cda112
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_njsd.h
@@ -0,0 +1,50 @@
+/*
+ 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_io.h"
+
+#ifdef NDS
+
+// 'NJSD'
+#define DEVICE_TYPE_NJSD 0x44534A4E
+
+
+// export interface
+extern LPIO_INTERFACE NJSD_GetInterface(void) ;
+
+#endif // defined NDS
+
+#endif // define IO_NJSD_H
diff --git a/backends/platform/ds/arm9/source/fat/io_scsd_asm.s b/backends/platform/ds/arm9/source/fat/io_scsd_asm.s
index f138c07205..498cbb96c2 100644
--- a/backends/platform/ds/arm9/source/fat/io_scsd_asm.s
+++ b/backends/platform/ds/arm9/source/fat/io_scsd_asm.s
@@ -519,524 +519,3 @@ MemoryCard_IsInserted:
- .TEXT
-@--------------------------------sd data--------------------------------
-.equ sd_comadd,0x9800000
-.equ sd_dataadd,0x9000000
-.equ sd_dataradd,0x9100000
-@-----------------viod sd_data_write_s(u16 *buff,u16* crc16buff)-------------------
- .ALIGN
- .GLOBAL sd_data_write_s
- .CODE 32
-sd_data_write_s:
- stmfd r13!,{r4-r5}
- mov r5,#512
- mov r2,#sd_dataadd
-sd_data_write_busy:
- ldrh r3,[r2]
- tst r3,#0x100
- beq sd_data_write_busy
-
- ldrh r3,[r2]
-
- mov r3,#0 @star bit
- strh r3,[r2]
-sd_data_write_loop:
- ldrh r3,[r0],#2
- add r3,r3,r3,lsl #20
- mov r4,r3,lsl #8
- stmia r2,{r3-r4}
-
- subs r5, r5, #2
- bne sd_data_write_loop
-
- cmp r1,#0
- movne r0,r1
- movne r1,#0
- movne r5,#8
- bne sd_data_write_loop
-
- mov r3,#0xff @end bit
- strh r3,[r2]
-sd_data_write_loop2:
- ldrh r3,[r2]
- tst r3,#0x100
- bne sd_data_write_loop2
-
- ldmia r2,{r3-r4}
-
- ldmfd r13!,{r4-r5}
- bx r14
-@-----------------end sd_data_write_s-------------------
-
-@----------void sd_data_read_s(u16 *buff)-------------
- .ALIGN
- .GLOBAL sd_data_read_s
- .CODE 32
-sd_data_read_s:
- stmfd r13!,{r4}
- mov r1,#sd_dataradd
-sd_data_read_loop1:
- ldrh r3,[r1] @star bit
- tst r3,#0x100
- bne sd_data_read_loop1
- mov r2,#512
-sd_data_read_loop:
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- ldmia r1,{r3-r4}
- mov r3,r4,lsr #16
- strh r3 ,[r0],#2
-
- subs r2, r2, #16
- bne sd_data_read_loop
-
- ldmia r1,{r3-r4} @crc 16
- ldmia r1,{r3-r4}
- ldmia r1,{r3-r4}
- ldmia r1,{r3-r4}
- ldrh r3,[r1] @end bit
- ldmfd r13!,{r4}
- bx r14
-@----------end sd_data_read_s-------------
-
-@------void sd_com_crc16_s(u16* buff,u16 num,u16* crc16buff)
- .ALIGN
- .GLOBAL sd_crc16_s
- .CODE 32
-sd_crc16_s:
- stmfd r13!,{r4-r9}
- mov r9,r2
-
- mov r3,#0
- mov r4,#0
- mov r5,#0
- mov r6,#0
-
- ldr r7,=0x80808080
- ldr r8,=0x1021
- mov r1,r1,lsl #3
-sd_crc16_loop:
-
- tst r7,#0x80
- ldrneb r2,[r0],#1
-
- mov r3,r3,lsl #1
- tst r3,#0x10000
- eorne r3,r3,r8
- tst r2,r7,lsr #24
- eorne r3,r3,r8
-
- mov r4,r4,lsl #1
- tst r4,#0x10000
- eorne r4,r4,r8
- tst r2,r7,lsr #25
- eorne r4,r4,r8
-
- mov r5,r5,lsl #1
- tst r5,#0x10000
- eorne r5,r5,r8
- tst r2,r7,lsr #26
- eorne r5,r5,r8
-
- mov r6,r6,lsl #1
- tst r6,#0x10000
- eorne r6,r6,r8
- tst r2,r7,lsr #27
- eorne r6,r6,r8
-
- mov r7,r7,ror #4
- subs r1,r1,#4
- bne sd_crc16_loop
-
- mov r2,r9
- mov r8,#16
-sd_crc16_write_data:
- mov r7,r7,lsl #4
- tst r3,#0x8000
- orrne r7,r7,#8
- tst r4,#0x8000
- orrne r7,r7,#4
- tst r5,#0x8000
- orrne r7,r7,#2
- tst r6,#0x8000
- orrne r7,r7,#1
-
- mov r3,r3,lsl #1
- mov r4,r4,lsl #1
- mov r5,r5,lsl #1
- mov r6,r6,lsl #1
-
- sub r8,r8,#1
- tst r8,#1
- streqb r7,[r2],#1
- cmp r8,#0
- bne sd_crc16_write_data
-
- ldmfd r13!,{r4-r9}
- bx r14
-@------end sd_com_crc16_s-----------------------------------
-
-@--------------u8 sd_crc7_s(u16* buff,u16 num)----------------------------
- .ALIGN
- .GLOBAL sd_crc7_s
- .CODE 32
-sd_crc7_s:
- stmfd r13!,{r4}
-
- mov r3,#0
- ldr r4,=0x80808080
- mov r1,r1,lsl #3 @ *8
-sd_crc7_loop:
- tst r4,#0x80
- ldrneb r2,[r0],#1
-
- mov r3,r3,lsl #1
-
- tst r3,#0x80
- eorne r3,r3,#0x9
-
- tst r2,r4,lsr #24
- eorne r3,r3,#0x9
-
- mov r4,r4,ror #1
- subs r1,r1,#1
- bne sd_crc7_loop
-
- mov r3,r3,lsl #1
- add r0,r3,#1
- ldmfd r13!,{r4}
- bx r14
-@--------------end sd_crc7_s----------------------------
-
-@--------------sd_com_read_s(u16* buff,u32 num)------------------
- .ALIGN
- .GLOBAL sd_com_read_s
- .CODE 32
-
-sd_com_read_s:
- stmfd r13!,{r4-r6}
- mov r2,#sd_comadd
-sd_com_read_loop1:
- ldrh r3,[r2] @star bit
- tst r3,#1
- bne sd_com_read_loop1
-
-sd_com_read_loop:
- ldmia r2,{r3-r6}
- subs r1, r1, #1
- bne sd_com_read_loop
- ldmfd r13!,{r4-r6}
- bx r14
-@--------------end sd_com_read_s------------------
-
-@-------------------void sd_com_write_s(u16* buff,u32 num)-----------------
-
- .ALIGN
- .GLOBAL sd_com_write_s
- .CODE 32
-sd_com_write_s:
- stmfd r13!,{r4-r6}
-
- mov r2,#sd_comadd
-sd_com_write_busy:
- ldrh r3,[r2]
- tst r3,#0x1
- beq sd_com_write_busy
-
- ldrh r3,[r2]
-
-sd_com_write_loop:
- ldrb r3,[r0],#1
- add r3,r3,r3,lsl #17
- mov r4,r3,lsl #2
- mov r5,r4,lsl #2
- mov r6,r5,lsl #2
- stmia r2,{r3-r6}
- subs r1, r1, #1
- bne sd_com_write_loop
- ldmfd r13!,{r4-r6}
-
- bx r14
-@-------------------end sd_com_write_s-----------------
-
-@-----------------void send_clk(u32 num)---------
- .ALIGN
- .GLOBAL send_clk
- .CODE 32
-
-send_clk:
- mov r1,#sd_comadd
-send_clk_loop1:
- ldrh r3,[r1]
- subs r0,r0,#1
- bne send_clk_loop1
- bx r14
-@-----------------end send_clk---------
-
-@---------------------------void SDCommand(u8 command,u8 num,u32 sector)--------------------
- .ALIGN
- .GLOBAL SDCommand
- .CODE 32
-@void SDCommand(u8 command,u8 num,u32 sector )
-@{
-@ u8 databuff[6];
-@ register u8 *char1;
-@ register u8 *char2;
-@
-@ char1=(u8*)(((u32)&sector)+3);
-@ char2=(u8*)databuff;
-@ *char2++=coma+0x40;
-@ *char2++=*char1--;
-@ *char2++=*char1--;
-@ *char2++=*char1--;
-@ *char2++=*char1;
-@ *char2=sd_crc7_s((u32)databuff,5);
-@
-@ sd_com_write_s((u32)databuff,6);
-@
-@}
-SDCommand:
- stmfd r13!,{r14}
-
- sub r13,r13,#16
- add r0,r0,#0x40
- strb r0,[r13,#4]
-
- mov r1,r2,lsr #24
- strb r1,[r13,#5]
- mov r1,r2,lsr #16
- strb r1,[r13,#6]
- mov r1,r2,lsr #8
- strb r1,[r13,#7]
- strb r2,[r13,#8]
- add r0,r13,#4
- mov r1,#5
- bl sd_crc7_s
- strb r0,[r13,#9]
- add r0,r13,#4
- mov r1,#6
- bl sd_com_write_s
-
- add r13,r13,#16
- ldmfd r13!,{r15}
-@ bx r14
-@---------------------------end SDCommand--------------------
-
-@----------void ReadSector(u16 *buff,u32 sector,u8 readnum)-------------
- .ALIGN
- .GLOBAL ReadSector @ r0:Srcp r1:num ok
- .CODE 32
-
-@void ReadSector(u16 *buff,u32 sector,u8 readnum)
-@{
-@ register u16 i,j;
-@ i=readnum;
-@ sectno<<=9;
-@ SDCommand(18,0,sector);
-@ for (j=0;j<i ; j++)
-@ {
-@ sd_data_read_s((u32)buff+j*512);
-@ }
-@ SDCommand(12,0,0);
-@ get_resp();
-@ send_clk(0x10);
-@
-@}
-ReadSector:
- stmfd r13!,{r4-r6,r14}
-
- mov r4,r0
- mov r5,r2
-
- mov r2,r1,lsl #9
- mov r0,#18
- mov r1,#0
- bl SDCommand
- mov r6,#0
-beginforj_ReadSector:
- cmp r6,r5
- bge endforj_ReadSector
- mov r0,r4
- add r0,r0,r6,lsl #9
- bl sd_data_read_s
- add r6,r6,#1
- b beginforj_ReadSector
-endforj_ReadSector:
- mov r0,#12
- mov r1,#0
- mov r2,#0
- bl SDCommand
- bl get_resp
- mov r0,#0x10
- bl send_clk
- mov r0,#1
- ldmfd r13!,{r4-r6,r15}
-@ bx r14
-@----------end ReadSector------------
-
-@-----------void get_resp(void)-------------------
-
-
- .ALIGN
- .GLOBAL get_resp @ r0:Srcp r1:num ok
- .CODE 32
-get_resp:
-
- stmfd r13!,{r14}
- mov r1,#6
- bl sd_com_read_s
- ldmfd r13!,{r15}
-@-----------end get_resp-------------------
-
-
-@---------------void WriteSector(u16 *buff,u32 sector,u8 writenum)---------------------
- .ALIGN
- .GLOBAL WriteSector @ r0:Srcp r1:num ok
- .CODE 32
-
-@void WriteSector(u16 *buff,u32 sector,u8 writenum)
-@{
-@ register u16 i,j;
-@ u16 crc16[5];
-@ i=writenum;
-@
-@ sectno<<=9;
-@
-@ SDCommand(25,0,sector);
-@ get_resp();
-@ send_clk(0x10);
-@
-@ for (j=0;j<i ; j++)
-@ {
-@ sd_crc16_s((u32)(u32)buff+j*512,512,(u32)crc16);
-@ sd_data_write_s((u32)buff+j*512,(u32)crc16);
-@ send_clk(0x10);
-@ }
-@ SDCommand(12,0,0);
-@ get_resp();
-@ send_clk(0x10);
-@ while((*(u16*)sd_dataadd &0x0100)==0);
-@
-@}
-@
-WriteSector:
- stmfd r13!,{r4-r6,r14}
-
- sub r13,r13,#20
-
- mov r4,r0
- mov r5,r2
-
- mov r2,r1,lsl #9
- mov r0,#25
- mov r1,#0
- bl SDCommand
- bl get_resp
- mov r0,#0x10
- bl send_clk
- mov r6,#0
-
-beginforj_WriteSector:
- cmp r6,r5
- bge endforj_WriteSector
- mov r0,r4
- add r0,r0,r6,lsl #9
- mov r1,#512
- add r2,r13,#4
- bl sd_crc16_s
- mov r0,r4
- add r0,r0,r6,lsl #9
- add r1,r13,#4
- bl sd_data_write_s
- mov r0,#0x10
- bl send_clk
- add r6,r6,#1
- b beginforj_WriteSector
-endforj_WriteSector:
- mov r0,#12
- mov r1,#0
- mov r2,#0
- bl SDCommand
- bl get_resp
- mov r0,#0x10
- bl send_clk
- ldr r0,=sd_dataadd
-beginwhile_WriteSector:
- ldrh r1,[r0]
- tst r1,#0x0100
- beq beginwhile_WriteSector
- mov r0,#1
- add r13,r13,#20
- ldmfd r13!,{r4-r6,r15}
-@---------------end WriteSector--------------------
-
-@----------------void InitSCMode(void)---------------
- .ALIGN
- .GLOBAL InitSCMode
- .CODE 32
-InitSCMode:
- mvn r0,#0x0F6000000
- sub r0,r0,#0x01
- mov r1,#0x0A500
- add r1,r1,#0x5A
- strh r1,[r0]
- strh r1,[r0]
- mov r2,#3
- strh r2,[r0]
- strh r2,[r0]
- bx r14
-@----------------end InitSCMode ---------------
-
-@----------------bool MemoryCard_IsInserted(void)---------------
- .ALIGN
- .GLOBAL MemoryCard_IsInserted
- .CODE 32
-
-MemoryCard_IsInserted:
- ldr r0,=sd_comadd
- ldrh r1,[r0]
- tst r1,#0x300
- moveq r0,#1
- movne r0,#0
- bx r14
-@----------------end MemoryCard_IsInserted---------------
-
- .END
-
-
-
-
-
-
-
-
-
-
-
diff --git a/backends/platform/ds/arm9/source/fat/io_sd_common.c b/backends/platform/ds/arm9/source/fat/io_sd_common.c
new file mode 100644
index 0000000000..0a38e6277c
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_sd_common.c
@@ -0,0 +1,203 @@
+/*
+ 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
+*/
+
+#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);
+ 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;
+}
+
+
diff --git a/backends/platform/ds/arm9/source/fat/io_sd_common.h b/backends/platform/ds/arm9/source/fat/io_sd_common.h
new file mode 100644
index 0000000000..09abffab39
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_sd_common.h
@@ -0,0 +1,114 @@
+/*
+ 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
+*/
+
+#ifndef IO_SD_COMMON_H
+#define IO_SD_COMMON_H
+
+#include "disc_io.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