Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

io_fcsr.c

/*
      io_fcsr.c based on

      compact_flash.c
      By chishm (Michael Chisholm)

      Hardware Routines for using a GBA Flash Cart and SRAM as a
      block device.

      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.

      The file system must be 512 byte aligned, in cart address space.
      SRAM is supported.
*/


#include "io_fcsr.h"

#ifdef SUPPORT_FCSR
#include <string.h>

//---------------------------------------------------------------
// 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

#ifdef NDS
 #define SRAM_START 0x0A000000
#else
 #define SRAM_START 0x0E000000
#endif

#define NO_SRAM 0xFFFFFFFF

#define FCSR 0x52534346
const char FCSR_LabelString[] = " Chishm FAT";

u8* FCSR_FileSysPointer = 0;
u8* FCSR_SramSectorPointer[4] = {0,0,0,0};
u32 FCSR_SramSectorStart[4] = {0,0,0,0};
u32 FCSR_SramSectorEnd[4] = {0,0,0,0};

/*-----------------------------------------------------------------
FCSR_IsInserted
Is a GBA Flash Cart with a valid file system inserted?
bool return OUT:  true if a GBA FC card is inserted
-----------------------------------------------------------------*/
bool FCSR_IsInserted (void)
{
      bool flagFoundFileSys = false;

      u32* fileSysPointer = (u32*)0x08000100;         // Start at beginning of cart address space, offset by expected location of string

      // Search for file system
      while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys)  // Only search while not at end of cart address space
      {
            while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
                  fileSysPointer += 0x40;
            if ((strncmp(FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
            {
                  flagFoundFileSys = true;
            } else {
                  fileSysPointer += 0x80;
            }
      }

      return flagFoundFileSys;
}


/*-----------------------------------------------------------------
FCSR_ClearStatus
Finish any pending operations
bool return OUT:  always true for GBA FC
-----------------------------------------------------------------*/
bool FCSR_ClearStatus (void)
{
      return true;
}


/*-----------------------------------------------------------------
FCSR_ReadSectors
Read 512 byte sector numbered "sector" into "buffer"
u32 sector IN: address of first 512 byte sector on Flash Cart to read
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 FCSR_ReadSectors (u32 sector, u8 numSecs, void* buffer)
{
      int i;
      bool flagSramSector = false;
      int numSectors = (numSecs > 0 ? numSecs : 256);
      int readLength = numSectors * BYTE_PER_READ;
      u8* src;
      u8* dst;

      // Find which region this read is in
      for (i = 0; (i < 4) && !flagSramSector; i++)
      {
            if ((sector >= FCSR_SramSectorStart[i]) && (sector < FCSR_SramSectorEnd[i]))
            {
                  flagSramSector = true;
                  break;
            }
      }

      // Make sure read will be completely in SRAM range if it is partially there
      if ( flagSramSector && ((sector + numSectors) > FCSR_SramSectorEnd[i]))
            return false;

      // Copy data to buffer
      if (flagSramSector)
      {
            src = FCSR_SramSectorPointer[i] + (sector - FCSR_SramSectorStart[i]) * BYTE_PER_READ;
      } else {
            src = FCSR_FileSysPointer + sector * BYTE_PER_READ;
      }
      dst = (u8*)buffer;

      if (flagSramSector)
      {
            while (readLength--)
            {
                  *dst++ = *src++;
            }
      } else {    // Reading from Cart ROM

#ifdef _CF_USE_DMA
 #ifdef NDS
  #ifdef ARM9
            DC_FlushRange( buffer, readLength);
  #endif    // ARM9
            DMA3_SRC = (u32)src;
            DMA3_DEST = (u32)buffer;
            DMA3_CR = (readLength >> 1) | DMA_COPY_HALFWORDS;
 #else      // ! NDS
            DMA3COPY ( src, buffer, (readLength >> 1) | DMA16 | DMA_ENABLE);
 #endif     // NDS
#else // !_CF_USE_DMA
            memcpy (buffer, src, readLength);
#endif      // _CF_USE_DMA

      }     // if (flagSramSector)

      return true;
}

/*-----------------------------------------------------------------
FCSR_WriteSectors
Write 512 byte sector numbered "sector" from "buffer"
u32 sector IN: address of 512 byte sector on Flash Cart to read
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 FCSR_WriteSectors (u32 sector, u8 numSecs, void* buffer)
{
      int i;
      bool flagSramSector = false;
      int writeLength = (numSecs > 0 ? numSecs : 256) * BYTE_PER_READ;
      u8* src = (u8*) buffer;
      u8* dst;

      // Find which region this sector belongs in
      for (i = 0; (i < 4) && !flagSramSector; i++)
      {
            if ((sector >= FCSR_SramSectorStart[i]) && (sector < FCSR_SramSectorEnd[i]))
            {
                  flagSramSector = true;
                  break;
            }
      }

      if (!flagSramSector)
            return false;

      // Entire write must be within an SRAM region
      if ((sector + (numSecs > 0 ? numSecs : 256)) > FCSR_SramSectorEnd[i])
            return false;

      // Copy data to SRAM
      dst = FCSR_SramSectorPointer[i] + (sector - FCSR_SramSectorStart[i]) * BYTE_PER_READ;
      while (writeLength--)
      {
            *dst++ = *src++;
      }

      return true;
}

/*-----------------------------------------------------------------
FCSR_Shutdown
unload the Flash Cart interface
-----------------------------------------------------------------*/
bool FCSR_Shutdown(void)
{
      int i;
      if (FCSR_ClearStatus() == false)
            return false;

      FCSR_FileSysPointer = 0;

      for (i=0; i < 4; i++)
      {
            FCSR_SramSectorPointer[i] = 0;
            FCSR_SramSectorStart[i] = 0;
            FCSR_SramSectorEnd[i] = 0;
      }
      return true;
}

/*-----------------------------------------------------------------
FCSR_StartUp
initializes the Flash Cart interface, returns true if successful,
otherwise returns false
-----------------------------------------------------------------*/
bool FCSR_StartUp(void)
{
      bool flagFoundFileSys = false;
      int i;
      int SramRegionSize[4];
      u8* srcByte;
      u8* destByte;

      u32* fileSysPointer = (u32*)0x08000100;         // Start at beginning of cart address space, offset by expected location of string

      // Search for file system
      while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys)  // Only search while not at end of cart address space
      {
            while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
                  fileSysPointer += 0x40;
            if ((strncmp(FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
            {
                  flagFoundFileSys = true;
            } else {
                  fileSysPointer += 0x80;
            }
      }

      if (!flagFoundFileSys)
            return false;

      // Flash cart file system pointer has been found
      FCSR_FileSysPointer = (u8*)(fileSysPointer - 0x40);

      // Get SRAM sector regions from header block
      for (i = 0; i < 4; i++)
      {
            FCSR_SramSectorStart[i] = fileSysPointer[i+4];
            SramRegionSize[i] = fileSysPointer[i+8];
            FCSR_SramSectorEnd[i] = FCSR_SramSectorStart[i] + SramRegionSize[i];
      }

      // Calculate SRAM region pointers
      FCSR_SramSectorPointer[0] = (u8*)(SRAM_START + 4);
      for (i = 1; i < 4; i++)
      {
            FCSR_SramSectorPointer[i] = FCSR_SramSectorPointer[i-1] + (SramRegionSize[i-1] * BYTE_PER_READ);
      }

      // Initialise SRAM with overlay if it hasn't been done so
      if ( (*((u8*)SRAM_START) != 'F')  || (*((u8*)(SRAM_START+1)) != 'C') || (*((u8*)(SRAM_START+2)) != 'S') || (*((u8*)(SRAM_START+3)) != 'R') )
      {
            *((u8*)SRAM_START) = 'F';
            *((u8*)(SRAM_START+1)) = 'C';
            *((u8*)(SRAM_START+2)) = 'S';
            *((u8*)(SRAM_START+3)) = 'R';

            for (i = 0; i < 4; i++)
            {
                  srcByte = FCSR_FileSysPointer + (FCSR_SramSectorStart[i] * BYTE_PER_READ);
                  destByte = FCSR_SramSectorPointer[i];
                  while (srcByte < FCSR_FileSysPointer + (FCSR_SramSectorEnd[i] * BYTE_PER_READ) )
                        *destByte++ = *srcByte++;
            }
      }

            // Get SRAM sector regions from header block
      for (i = 0; i < 4; i++)
      {
            if (SramRegionSize[i] == 0)
            {
                  FCSR_SramSectorStart[i] = NO_SRAM;
                  FCSR_SramSectorEnd[i] = NO_SRAM;
            }
      }

      return true;
}

/*-----------------------------------------------------------------
the actual interface structure
-----------------------------------------------------------------*/
IO_INTERFACE io_fcsr = {
      DEVICE_TYPE_FCSR, // 'FCSR'
      FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
      (FN_MEDIUM_STARTUP)&FCSR_StartUp,
      (FN_MEDIUM_ISINSERTED)&FCSR_IsInserted,
      (FN_MEDIUM_READSECTORS)&FCSR_ReadSectors,
      (FN_MEDIUM_WRITESECTORS)&FCSR_WriteSectors,
      (FN_MEDIUM_CLEARSTATUS)&FCSR_ClearStatus,
      (FN_MEDIUM_SHUTDOWN)&FCSR_Shutdown
} ;

/*-----------------------------------------------------------------
FCSR_GetInterface
returns the interface structure to host
-----------------------------------------------------------------*/
LPIO_INTERFACE FCSR_GetInterface(void) {
      return &io_fcsr ;
} ;

#endif // SUPPORT_FCSR

Generated by  Doxygen 1.6.0   Back to index