diff options
Diffstat (limited to 'backends/platform/ds/arm9/source/fat/io_mmcf.c')
-rw-r--r-- | backends/platform/ds/arm9/source/fat/io_mmcf.c | 363 |
1 files changed, 363 insertions, 0 deletions
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 |