diff options
author | Neil Millstone | 2006-11-03 23:16:29 +0000 |
---|---|---|
committer | Neil Millstone | 2006-11-03 23:16:29 +0000 |
commit | ea6663fdfa5f2b9d8351f9b06219d0dae1494a6c (patch) | |
tree | 76a1ca3e5f5672194133d3bdaabdb038275a0e57 | |
parent | d5608e82edb4a73f6ab30a8db9a79dc16ed2ed9f (diff) | |
download | scummvm-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
34 files changed, 2678 insertions, 1238 deletions
diff --git a/backends/platform/ds/arm7/Makefile b/backends/platform/ds/arm7/Makefile index d0498b069b..600842e812 100644 --- a/backends/platform/ds/arm7/Makefile +++ b/backends/platform/ds/arm7/Makefile @@ -12,6 +12,9 @@ TARGET := arm7 BUILD := build SOURCES := gfx source data INCLUDES := include build + +# Enable support for debugger (must be the same as in the arm9 makefile) +USE_DEBUGGER = 1 #--------------------------------------------------------------------------------- # options for code generation @@ -27,6 +30,11 @@ CFLAGS := -g -Wall -O2\ CFLAGS += $(INCLUDE) -DARM7 +ifdef USE_DEBUGGER + CFLAGS += -DUSE_DEBUGGER +endif + + CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti ASFLAGS := -g $(ARCH) LDFLAGS := -g $(ARCH) -mno-fpu @@ -49,6 +57,10 @@ PREFIX := arm-eabi- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- LIBS := -lnds7 + +ifdef USE_DEBUGGER + LIBS += -ldswifi7 +endif #--------------------------------------------------------------------------------- diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp index bdee17ddc9..cfa2d1fb2f 100644 --- a/backends/platform/ds/arm7/source/main.cpp +++ b/backends/platform/ds/arm7/source/main.cpp @@ -34,9 +34,11 @@ #include <stdlib.h> #include <string.h> #include <registers_alt.h> - #include <NDS/scummvm_ipc.h> ////////////////////////////////////////////////////////////////////// +#ifdef USE_DEBUGGER +#include <dswifi7.h> +#endif #define TOUCH_CAL_X1 (*(vs16*)0x027FFCD8) @@ -99,7 +101,7 @@ s8 getFreeSoundChannel() { } void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F, u8 pan=63, u8 format=0) { - REG_IME = IME_DISABLE; +// REG_IME = IME_DISABLE; channel = getFreeSoundChannel(); /* if (format == 2) { @@ -216,7 +218,7 @@ void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 // IPC->fillSoundSecondHalf = true; // soundFirstHalf = true; - REG_IME = IME_ENABLE; +// REG_IME = IME_ENABLE; } void stopSound(int chan) { @@ -310,9 +312,8 @@ void performSleep() { powerManagerWrite(0, 0x30, false); } -*/ - +*/ void performSleep() { powerManagerWrite(0, 0x30, true); @@ -345,11 +346,9 @@ void performSleep() { ////////////////////////////////////////////////////////////////////// - -void InterruptHandler(void) { - static int heartbeat = 0; - - if (REG_IF & IRQ_TIMER1) { + + +void InterruptTimer1() { IPC->fillNeeded[playingSection] = true; soundFilled[playingSection] = false; @@ -385,13 +384,9 @@ void InterruptHandler(void) { soundFilled[r] = true; //} }*/ - - - REG_IF = IRQ_TIMER1; - } +} - - if (REG_IF & IRQ_TIMER3) { +void InterruptTimer3() { while (IPC->adpcm.semaphore); // Wait for buffer to become free if needed IPC->adpcm.semaphore = true; // Lock the buffer structure to prevent clashing with the ARM7 @@ -403,11 +398,9 @@ void InterruptHandler(void) { IPC->streamPlayingSection++; } - REG_IF = IRQ_TIMER3; IPC->adpcm.semaphore = false; - } - +} // IPC->performArm9SleepMode = false; @@ -420,13 +413,12 @@ void InterruptHandler(void) { - - if (REG_IF & IRQ_VBLANK) { + void InterruptVBlank() { uint16 but=0, x=0, y=0, xpx=0, ypx=0, z1=0, z2=0, batt=0, aux=0; int t1=0, t2=0; uint32 temp=0; uint8 ct[sizeof(IPC->curtime)]; - + static int heartbeat = 0; // Update the heartbeat heartbeat++; @@ -472,6 +464,7 @@ void InterruptHandler(void) { // Read the temperature temp = touchReadTemperature(&t1, &t2); + // Update the IPC struct IPC->heartbeat = heartbeat; IPC->buttons = but; @@ -508,18 +501,69 @@ void InterruptHandler(void) { stopSound(-snd->data[i].rate); } } - } - - REG_IF = IRQ_VBLANK; - } - -} + } + + + #ifdef USE_DEBUGGER + Wifi_Update(); // update wireless in vblank + #endif + } ////////////////////////////////////////////////////////////////////// + + +#ifdef USE_DEBUGGER + +// callback to allow wifi library to notify arm9 +void arm7_synctoarm9() { // send fifo message + REG_IPC_FIFO_TX = 0x87654321; +} +// interrupt handler to allow incoming notifications from arm9 +void arm7_fifo() { // check incoming fifo messages + u32 msg = REG_IPC_FIFO_RX; + if(msg==0x87654321) Wifi_Sync(); +} + +void initDebugger() { + + // set up the wifi irq + irqSet(IRQ_WIFI, Wifi_Interrupt); // set up wifi interrupt + irqEnable(IRQ_WIFI); + + //get them talking together + + // sync with arm9 and init wifi + u32 fifo_temp; + + while(1) { // wait for magic number + while(REG_IPC_FIFO_CR&IPC_FIFO_RECV_EMPTY) swiWaitForVBlank(); + fifo_temp=REG_IPC_FIFO_RX; + if(fifo_temp==0x12345678) break; + } + + while(REG_IPC_FIFO_CR&IPC_FIFO_RECV_EMPTY) swiWaitForVBlank(); + fifo_temp=REG_IPC_FIFO_RX; // give next value to wifi_init + Wifi_Init(fifo_temp); + + irqSet(IRQ_FIFO_NOT_EMPTY,arm7_fifo); // set up fifo irq + irqEnable(IRQ_FIFO_NOT_EMPTY); + REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_RECV_IRQ; + + Wifi_SetSyncHandler(arm7_synctoarm9); // allow wifi lib to notify arm9 + // arm7 wifi init complete + +} +#endif + int main(int argc, char ** argv) { + +#ifdef USE_DEBUGGER + REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR; +#endif + // Reset the clock if needed rtcReset(); @@ -528,7 +572,9 @@ int main(int argc, char ** argv) { SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F); IPC->soundData = 0; IPC->reset = false; - + + + for (int r = 0; r < 8; r++) { IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512); @@ -540,14 +586,29 @@ int main(int argc, char ** argv) { // Set up the interrupt handler - REG_IME = 0; + + irqInit(); + + irqSet(IRQ_VBLANK, InterruptVBlank); + irqEnable(IRQ_VBLANK); + + irqSet(IRQ_TIMER1, InterruptTimer1); + irqEnable(IRQ_TIMER1); + + irqSet(IRQ_TIMER3, InterruptTimer3); + irqEnable(IRQ_TIMER3); + +/* REG_IME = 0; IRQ_HANDLER = &InterruptHandler; REG_IE = IRQ_VBLANK | IRQ_TIMER1 | IRQ_TIMER3; REG_IF = ~0; DISP_SR = DISP_VBLANK_IRQ; REG_IME = 1; - - + */ + +#ifdef USE_DEBUGGER + initDebugger(); +#endif // Keep the ARM7 out of main RAM while (1) { diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index 07ada936ed..c17693b148 100644 --- a/backends/platform/ds/arm9/makefile +++ b/backends/platform/ds/arm9/makefile @@ -1,14 +1,22 @@ #BUILD_PLUGINS = 1 libndsdir = $(DEVKITPRO)/libnds -#DS_BUILD_A = 1 +# Select the build you want by uncommenting one of the following lines: + +DS_BUILD_A = 1 #DS_BUILD_B = 1 -DS_BUILD_C = 1 +#DS_BUILD_C = 1 + -#DS_SCUMM_BUILD = 1 -#DS_NON_SCUMM_BUILD = 1 +# Uncomment the following line to build in support for MP3 audio +# using libmad: +USE_MAD = 1 -#USE_MAD = 1 +# Uncomment the following line to enable support for the +# ace DS Debugger (remembering to make the same change in the arm7 makefile): +#USE_DEBUGGER = 1 +# NOTE: The header and libs for the debugger is assumed to be in the libnds +# folder. VPATH = $(srcdir) @@ -17,7 +25,8 @@ VPATH = $(srcdir) ifdef DS_BUILD_A - DEFINES = -DDS_SCUMM_BUILD + DEFINES = -DDS_SCUMM_BUILD -DDS_BUILD_A + LOGO = logoa.bmp DISABLE_HE = 1 #DISABLE_SCUMM = 1 DISABLE_SCUMM_7_8 = 1 @@ -36,37 +45,39 @@ ifdef DS_BUILD_A endif ifdef DS_BUILD_B - DEFINES = -DDS_NON_SCUMM_BUILD + DEFINES = -DDS_NON_SCUMM_BUILD -DDS_BUILD_B + LOGO = logob.bmp DISABLE_HE = 1 DISABLE_SCUMM = 1 DISABLE_SCUMM_7_8 = 1 - #DISABLE_AGOS = 1 - DISABLE_SKY = 1 + DISABLE_AGOS = 1 + #DISABLE_SKY = 1 DISABLE_SWORD1 = 1 DISABLE_SWORD2 = 1 #DISABLE_QUEEN = 1 DISABLE_SAGA = 1 DISABLE_KYRA = 1 - #DISABLE_GOB = 1 + DISABLE_GOB = 1 DISABLE_LURE = 1 DISABLE_CINE = 1 DISABLE_AGI = 1 BUILD=scummvm-B endif -ifdef DS_BUILD_C - DEFINES = -DDS_NON_SCUMM_BUILD +ifdef DS_BUILD_C + DEFINES = -DDS_NON_SCUMM_BUILD -DDS_BUILD_C + LOGO = logoc.bmp DISABLE_HE = 1 DISABLE_SCUMM = 1 DISABLE_SCUMM_7_8 = 1 - DISABLE_AGOS = 1 + #DISABLE_AGOS = 1 DISABLE_SKY = 1 DISABLE_SWORD1 = 1 DISABLE_SWORD2 = 1 DISABLE_QUEEN = 1 - #DISABLE_SAGA = 1 - DISABLE_KYRA = 1 - DISABLE_GOB = 1 + DISABLE_SAGA = 1 + #DISABLE_KYRA = 1 + #DISABLE_GOB = 1 DISABLE_LURE = 1 DISABLE_CINE = 1 DISABLE_AGI = 1 @@ -84,6 +95,11 @@ CFLAGS = -Wno-multichar -Wall -Os\ -Wno-multichar -mcpu=arm9tdmi -mtune=arm9tdmi \ -mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\ -ffast-math -mthumb-interwork + +ifdef USE_DEBUGGER + DEFINES += -DUSE_DEBUGGER + CFLAGS += -g +endif CXXFLAGS= $(CFLAGS) -Wno-non-virtual-dtor -Wno-non-virtual-dtor \ -fno-exceptions -fno-rtti @@ -94,6 +110,7 @@ ifdef USE_MAD DEFINES += -DUSE_MAD endif + LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt INCLUDES= -I./ -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/common -I$(portdir)/source -I$(portdir)/source/compressor -I$(portdir)/source/fat \ @@ -105,6 +122,9 @@ LIBS = -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9 ifdef USE_MAD LIBS += -lmad endif +ifdef USE_DEBUGGER + LIBS += -ldsdebugger -ldswifi9 +endif #-Lscumm -lscumm -Lbase -lbase -Lcommon -lcommon -Lgraphics -lgraphics -Lgui -lgui -Lsound -lsound EXECUTABLE = scummvm.elf @@ -144,7 +164,18 @@ FAT_OBJS := $(portdir)/source/fat/disc_io.o $(portdir)/source/fat/gba_nds_fat.o $(portdir)/source/fat/io_mpcf.o $(portdir)/source/fat/io_sccf.o\ $(portdir)/source/fat/io_m3sd.o\ $(portdir)/source/fat/io_nmmc.o $(portdir)/source/fat/io_scsd.o \ - $(portdir)/source/fat/io_m3sd_asm.o $(portdir)/source/fat/io_scsd_asm.o + $(portdir)/source/fat/io_m3sd_asm.o $(portdir)/source/fat/io_scsd_asm.o \ + $(portdir)/source/fat/io_njsd.o \ + $(portdir)/source/fat/io_mmcf.o \ + $(portdir)/source/fat/io_sd_common.o \ + $(portdir)/source/fat/io_m3_common.o + + + +# $(portdir)/source/fat/io_cf_common.o $(portdir)/source/fat/io_m3_common.o\ +# $(portdir)/source/fat/io_sd_common.o $(portdir)/source/fat/io_scsd_s.o \ +# $(portdir)/source/fat/io_sc_common.o $(portdir)/source/fat/io_sd_common.o + @@ -230,6 +261,7 @@ else endif +#--------------------------------------------------------------------------------- #--------------------------------------------------------------------------------- %.o : %.pcx @@ -269,9 +301,10 @@ endif #--------------------------------------------------------------------------------- %.nds: %.bin - @echo ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../logo.bmp "$(shell basename $@);ScummVM 0.9.0;Port v0.6" - ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../logo.bmp "$(shell basename $@);ScummVM 0.9.0;Port v0.6" - dsbuild $@ + @echo ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../$(LOGO) "$(shell basename $@);ScummVM 0.9.0;DS Port" + ndstool -c $@ -9 scummvm.bin $(ARM7BIN) -b ../../$(LOGO) "$(shell basename $@);ScummVM 0.9.1;DS Port" + dsbuild $@ -l ../ndsloader.bin + padbin 16 $(basename $@).ds.gba #--------------------------------------------------------------------------------- diff --git a/backends/platform/ds/arm9/ndsloader.bin b/backends/platform/ds/arm9/ndsloader.bin Binary files differnew file mode 100644 index 0000000000..05abb01b2a --- /dev/null +++ b/backends/platform/ds/arm9/ndsloader.bin diff --git a/backends/platform/ds/arm9/source/cdaudio.cpp b/backends/platform/ds/arm9/source/cdaudio.cpp index 50f06055d1..5b354342c4 100644 --- a/backends/platform/ds/arm9/source/cdaudio.cpp +++ b/backends/platform/ds/arm9/source/cdaudio.cpp @@ -133,8 +133,14 @@ void playTrack(int track, int numLoops, int startFrame, int duration) { char str[100]; - sprintf(str, "/track%d.wav", track); - path = path + str; + + if (path[strlen(path.c_str()) - 1] == '/') { + sprintf(str, "track%d.wav", track); + path = path + str; + } else { + sprintf(str, "/track%d.wav", track); + path = path + str; + } //1820160 @@ -459,10 +465,14 @@ bool checkCD() { consolePrintf("Attempted to open cd drive\n"); Common::String path = ConfMan.get("path"); - path = path + "/track2.wav"; // 6577 153 154 + if (path[strlen(path.c_str()) - 1] == '/') { + path = path + "track2.wav"; + } else { + path = path + "/track2.wav"; + } consolePrintf("Looking for %s...", path.c_str()); - + FILE* file; if ((file = DS::std_fopen(path.c_str(), "r"))) { consolePrintf("Success!\n"); diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index dbdf4fd876..a833a76605 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -19,6 +19,21 @@ */ +// - Turn off when quit - Done +// - Simon and Kyrandia - Done +// - 200% scale option - Done +// - Change zoom range - Done +// - Speed increase! - Done +// - Fixed bugs in Sky - Done +// - Change name of ini file and intro screen for build c - Done +// - Check for existance of zip file in batch file - Done +// - Add new support - Done +// - Fix help screen + +// - Remove scummconsole.c +// - Delete files +// - Fatlib conversion + #include <nds.h> #include <ARM9/console.h> //basic print funcionality @@ -40,6 +55,9 @@ #include "registers_alt.h" //#include "compact_flash.h" #include "dsoptions.h" +#include "user_debugger.h" +#include "ramsave.h" +#include "disc_io.h" #include "blitters.h" namespace DS { @@ -58,7 +76,7 @@ enum MouseMode { // Defines #define FRAME_TIME 17 #define SCUMM_GAME_HEIGHT 142 -#define SCUMM_GAME_WIDTH 232 +#define SCUMM_GAME_WIDTH 227 int textureID; u16* texture; @@ -93,6 +111,7 @@ int bufferFrame; int bufferRate; int bufferSamples; bool soundHiPart; +int soundFrequency; // Events int lastEventFrame; @@ -116,11 +135,7 @@ u8 gameID; bool consoleEnable = true; bool gameScreenSwap = false; bool cpuScaler = false; -bool isCpuScalerEnabled() -{ - return cpuScaler; -} - +bool isCpuScalerEnabled(); MouseMode mouseMode; @@ -152,6 +167,9 @@ char gameName[32]; int gameWidth = 320; int gameHeight = 200; +// Scale +bool twoHundredPercentFixedScale = false; + enum controlType { CONT_SCUMM_ORIGINAL, CONT_SCUMM_SAMNMAX, @@ -216,6 +234,10 @@ void updateStatus(); TransferSound soundControl; +bool isCpuScalerEnabled() { + return cpuScaler; +} + //plays an 8 bit mono sample at 11025Hz void playSound(const void* data, u32 length, bool loop, bool adpcm, int rate) { @@ -313,11 +335,49 @@ void restoreGameBackBuffer() { } +void startSound(int freq, int buffer) { + bufferRate = freq * 2; + bufferFrame = 0; + bufferSamples = 4096; + + bufferFirstHalf = false; + bufferSecondHalf = true; + + int bytes = (2 * (bufferSamples)) + 100; + + soundBuffer = (s16 *) malloc(bytes * 2); + + + soundHiPart = true; + + for (int r = 0; r < bytes; r++) { + soundBuffer[r] = 0; + } + + soundFrequency = freq; + + + swiWaitForVBlank(); + swiWaitForVBlank(); + playSound(soundBuffer, (bufferSamples * 2), true, false, freq * 2); + swiWaitForVBlank(); + swiWaitForVBlank(); + swiWaitForVBlank(); +} + +int getSoundFrequency() { + return soundFrequency; +} + + void initGame() { // This is a good time to check for left handed mode since the mode change is done as the game starts. // There's probably a better way, but hey. // consolePrintf("initing game\n"); + static bool firstTime = true; + + setOptions(); //strcpy(gameName, ConfMan.getActiveDomain().c_str()); @@ -332,7 +392,17 @@ void initGame() { // consolePrintf("Game list num: %d\n", currentGame); } } - + + if (firstTime) { + firstTime = false; + + if (ConfMan.hasKey("22khzaudio", "ds") && ConfMan.getBool("22khzaudio", "ds")) { + startSound(22050, 8192); + } else { + startSound(11025, 4096); + } + + } } @@ -348,6 +418,10 @@ void setTouchYOffset(int y) { touchYOffset = y; } +void set200PercentFixedScale(bool on) { + twoHundredPercentFixedScale = on; +} + void setUnscaledMode(bool enable) { scaledMode = !enable; } @@ -991,7 +1065,7 @@ void addEventsToQueue() { // Extra controls for Benieth a Steel Sky if ((getKeysDown() & KEY_DOWN)) { penY = 0; - penX = 0; // Show inventory by moving mouse onto top line + penX = 160; // Show inventory by moving mouse onto top line } } @@ -1244,6 +1318,15 @@ void VBlankHandler(void) { // consolePri ntf("X:%d Y:%d\n", getPenX(), getPenY()); + static bool firstTime = true; + + // This is to ensure that the ARM7 vblank handler runs before this one. + // Fixes the problem with the MMD when the screens swap over on load. + if (firstTime) { + firstTime = false; + return; + } + IPC->tweak = tweak; soundUpdate(); @@ -1327,35 +1410,45 @@ void VBlankHandler(void) { SUB_BG3_XDY = 0; SUB_BG3_YDX = 0; SUB_BG3_YDY = (int) (subScreenHeight / 192.0f * 256);*/ + + static int ratio = ( 320 << 8) / SCUMM_GAME_WIDTH; if ((getKeysHeld() & KEY_L) || (getKeysHeld() & KEY_R)) { - if ((getKeysHeld() & KEY_A) && (subScreenScale < 256)) { - subScreenScale += 3; + if ((getKeysHeld() & KEY_A) && (subScreenScale < ratio)) { + subScreenScale += 2; } if ((getKeysHeld() & KEY_B) && (subScreenScale > 128)) { - subScreenScale -=3; + subScreenScale -=2; } - - int xCenter = subScTargetX + ((subScreenWidth >> 1) << 8); - int yCenter = subScTargetY + ((subScreenHeight >> 1) << 8); - - subScreenWidth = SCUMM_GAME_WIDTH * subScreenScale >> 8; - subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8; - - subScTargetX = xCenter - ((subScreenWidth >> 1) << 8); - subScTargetY = yCenter - ((subScreenHeight >> 1) << 8); - + } - - if (subScTargetX < 0) subScTargetX = 0; - if (subScTargetX > (gameWidth - subScreenWidth) << 8) subScTargetX = (gameWidth - subScreenWidth) << 8; + int xCenter = subScTargetX + ((subScreenWidth >> 1) << 8); + int yCenter = subScTargetY + ((subScreenHeight >> 1) << 8); - if (subScTargetY < 0) subScTargetY = 0; - if (subScTargetY > (gameHeight - subScreenHeight) << 8) subScTargetY = (gameHeight - subScreenHeight) << 8; + if (twoHundredPercentFixedScale) { + subScreenWidth = 256 >> 1; + subScreenHeight = 192 >> 1; + } else { + subScreenWidth = SCUMM_GAME_WIDTH * subScreenScale >> 8; + subScreenHeight = SCUMM_GAME_HEIGHT * subScreenScale >> 8; } + + subScTargetX = xCenter - ((subScreenWidth >> 1) << 8); + subScTargetY = yCenter - ((subScreenHeight >> 1) << 8); + + + + + if (subScTargetX < 0) subScTargetX = 0; + if (subScTargetX > (gameWidth - subScreenWidth) << 8) subScTargetX = (gameWidth - subScreenWidth) << 8; + + if (subScTargetY < 0) subScTargetY = 0; + if (subScTargetY > (gameHeight - subScreenHeight) << 8) subScTargetY = (gameHeight - subScreenHeight) << 8; + + subScX += (subScTargetX - subScX) >> 2; subScY += (subScTargetY - subScY) >> 2; @@ -1526,9 +1619,19 @@ void initHardware() { */ + for (int r = 0; r < 255; r++) { + PALETTE[r] = 0; + } PALETTE[255] = RGB15(0,31,0); + + for (int r = 0; r < 255; r++) { + PALETTE_SUB[r] = 0; + } + + PALETTE_SUB[255] = RGB15(0,31,0); + // Allocate save buffer for game screen // savedBuffer = new u8[320 * 200]; displayMode16Bit(); @@ -1797,9 +1900,11 @@ bool getIndyFightState() { bool GBAMPAvail = false; -void initGBAMP() { - FAT_InitFiles(); - if (disc_IsInserted()) { +void initGBAMP(int mode) { + if (FAT_InitFiles()) { + if (mode == 2) { + disc_IsInserted(); + } GBAMPAvail = true; consolePrintf("Found flash card reader!\n"); } else { @@ -1813,14 +1918,52 @@ bool isGBAMPAvailable() { } +#ifdef USE_DEBUGGER +void initDebugger() { + set_verbosity(VERBOSE_INFO | VERBOSE_ERROR); + wireless_init(0); + wireless_connect(); + + // This is where the address of the computer running the Java + // stub goes. + debugger_connect_tcp(192, 168, 0, 1); + debugger_init(); + + // Update function - should really call every frame + user_debugger_update(); +} + + +// Ensure the function is processed with C linkage +extern "C" void debug_print_stub(char* string); + +void debug_print_stub(char *string) { + consolePrintf(string); +} +#endif + +void powerOff() { + while (keysHeld() != 0) { // Wait for all keys to be released. + swiWaitForVBlank(); // Allow you to read error before the power + } // is turned off. + + for (int r = 0; r < 60; r++) { + swiWaitForVBlank(); + } + + if (ConfMan.hasKey("disablepoweroff", "ds") && ConfMan.getBool("disablepoweroff", "ds")) { + while (true); + } else { + IPC->reset = true; // Send message to ARM7 to turn power off + while (true); // Stop the program continuing beyond this point + } +} ///////////////// // Main ///////////////// - - int main(void) { soundCallback = NULL; @@ -1828,6 +1971,13 @@ int main(void) initHardware(); +#ifdef USE_DEBUGGER + swiWaitForVBlank(); + if (!(keysHeld() & KEY_Y)) { + initDebugger(); + } +#endif + // Let arm9 read cartridge *((u16 *) (0x04000204)) &= ~0x0080; @@ -1844,19 +1994,14 @@ int main(void) // playSound(twang, 11010, true); // 18640 // bufferSize = 10; - bufferRate = 22050; - bufferFrame = 0; -// bufferSamples = (bufferRate * bufferSize) / 60; - bufferSamples = 4096; - - bufferFirstHalf = false; - bufferSecondHalf = true; - - lastEventFrame = 0; - mouseMode = MOUSE_LEFT; + /*bufferRate = 44100; + bufferFrame = 0; + bufferSamples = 8192; + bufferFirstHalf = false; + bufferSecondHalf = true; int bytes = (2 * (bufferSamples)) + 100; @@ -1864,6 +2009,25 @@ int main(void) soundHiPart = true; + + for (int r = 0; r < bytes; r++) { + soundBuffer[r] = 0; + } + + + swiWaitForVBlank(); + swiWaitForVBlank(); + playSound(soundBuffer, (bufferSamples * 2), true); + swiWaitForVBlank(); + swiWaitForVBlank(); + swiWaitForVBlank(); +*/ + + + lastEventFrame = 0; + mouseMode = MOUSE_LEFT; + + /* TIMER1_CR = 0; TIMER1_DATA = TIMER_FREQ(bufferRate); @@ -1883,50 +2047,110 @@ int main(void) - consolePrintf("------------------------\n"); + consolePrintf("---------------------------\n"); consolePrintf("ScummVM DS\n"); consolePrintf("Ported by Neil Millstone\n"); -#ifdef DS_SCUMM_BUILD - consolePrintf("Version 0.61 build A\n"); -#else - consolePrintf("Version 0.61 build B\n"); + consolePrintf("Version 0.10.0SVN "); +#if defined(DS_BUILD_A) + consolePrintf("build A\n"); + consolePrintf("Supports: Lucasarts SCUMM\n"); + consolePrintf("---------------------------\n"); +#elif defined(DS_BUILD_B) + consolePrintf("build B\n"); + consolePrintf("Supports: BASS, QUEEN\n"); + consolePrintf("---------------------------\n"); +#elif defined(DS_BUILD_C) + consolePrintf("build C\n"); + consolePrintf("---------------------------\n"); + consolePrintf("Supports: SIMON, KYRA, GOB\n"); #endif - consolePrintf("------------------------\n"); consolePrintf("L/R + D-pad/pen: Scroll view\n"); consolePrintf("D-pad left: Left mouse button\n"); consolePrintf("D-pad right: Right mouse button\n"); consolePrintf("D-pad up: Hover mouse\n"); - consolePrintf("D-pad down: Skip dialog line\n"); consolePrintf("B button: Skip cutscenes\n"); consolePrintf("Select: DS Options menu\n"); consolePrintf("Start: Game menu\n"); consolePrintf("Y (in game): Toggle console\n"); consolePrintf("X: Toggle keyboard\n"); consolePrintf("A: Swap screens\n"); - consolePrintf("L + R on bootup: Clear SRAM\n\n"); - consolePrintf("For a complete poo list see the\n"); + consolePrintf("L+R (on start): Clear SRAM\n"); + +#if defined(DS_BUILD_A) + consolePrintf("For a complete key list see the\n"); consolePrintf("help screen.\n\n"); +#else + consolePrintf("\n"); +#endif + + // Do M3 detection selectioon + int extraData = DSSaveFileManager::getExtraData(); + bool present = DSSaveFileManager::isExtraDataPresent(); - for (int r = 0; r < bytes; r++) { - soundBuffer[r] = 0; + for (int r = 0; r < 30; r++) { + swiWaitForVBlank(); } - - swiWaitForVBlank(); - swiWaitForVBlank(); - playSound(soundBuffer, (bufferSamples * 2), true); - swiWaitForVBlank(); - swiWaitForVBlank(); - swiWaitForVBlank(); - + int mode = extraData & 0x03; + + if (mode == 0) { + if ((keysHeld() & KEY_L) && !(keysHeld() & KEY_R)) { + mode = 1; + } else if (!(keysHeld() & KEY_L) && (keysHeld() & KEY_R)) { + mode = 2; + } + } else { + if ((keysHeld() & KEY_L) && !(keysHeld() & KEY_R)) { + mode = 0; + } + } + if (mode == 0) { + consolePrintf("On startup hold L if you have\n"); + consolePrintf("an M3 SD or R for an SC SD\n"); + } else if (mode == 1) { + consolePrintf("Using M3 SD Mode.\n"); + consolePrintf("Hold L on startup to disable.\n"); + } else if (mode == 2) { + consolePrintf("Using SC SD Mode.\n"); + consolePrintf("Hold L on startup to disable.\n"); + } + + disc_setEnable(mode); + DSSaveFileManager::setExtraData(mode); + + +/* + if ((present) && (extraData & 0x00000001)) { + + if (keysHeld() & KEY_L) { + extraData &= ~0x00000001; + consolePrintf("M3 SD Detection: OFF\n"); + DSSaveFileManager::setExtraData(extraData); + } else { + consolePrintf("M3 SD Detection: ON\n"); + consolePrintf("Hold L on startup to disable.\n"); + } + + } else if (keysHeld() & KEY_L) { + consolePrintf("M3 SD Detection: ON\n"); + extraData |= 0x00000001; + DSSaveFileManager::setExtraData(extraData); + } else { + consolePrintf("M3 SD Detection: OFF\n"); + consolePrintf("Hold L on startup to enable.\n"); + } + + disc_setM3SDEnable(extraData & 0x00000001); +*/ // Create a file system node to force search for a zip file in GBA rom space + DSFileSystemNode* node = new DSFileSystemNode(); if (!node->getZip() || (!node->getZip()->isReady())) { // If not found, init CF/SD driver - initGBAMP(); + initGBAMP(mode); } delete node; @@ -1936,6 +2160,7 @@ int main(void) // OSystem_DS::instance(); + g_system = new OSystem_DS(); assert(g_system); @@ -1945,20 +2170,28 @@ int main(void) // printf("'%s'", Common::ConfigManager::kTransientDomain.c_str()); //printf("'%s'", Common::ConfigManager::kApplicationDomain.c_str()); - +#if defined(DS_BUILD_A) + char* argv[2] = {"/scummvmds", "--config=scummvm.ini"}; +#elif defined(DS_BUILD_B) char* argv[2] = {"/scummvmds", "--config=scummvmb.ini"}; +#elif defined(DS_BUILD_C) + char* argv[2] = {"/scummvmds", "--config=scummvmc.ini"}; +#endif + + #ifdef DS_NON_SCUMM_BUILD while (1) { scummvm_main(2, (char **) &argv); + powerOff(); } #else while (1) { scummvm_main(1, (char **) &argv); + powerOff(); } #endif - return 0; } @@ -1968,3 +2201,4 @@ int main(void) int main() { DS::main(); } + diff --git a/backends/platform/ds/arm9/source/dsmain.h b/backends/platform/ds/arm9/source/dsmain.h index 20d9adcd25..040e78663a 100644 --- a/backends/platform/ds/arm9/source/dsmain.h +++ b/backends/platform/ds/arm9/source/dsmain.h @@ -61,6 +61,7 @@ u16* get8BitBackBuffer(); void setTalkPos(int x, int y); void setTopScreenTarget(int x, int y); +void set200PercentFixedScale(bool on); // Timers void setTimerCallback(OSystem_DS::TimerProc proc, int interval); // Setup a callback function at a regular interval @@ -72,6 +73,7 @@ void setSoundProc(OSystem_DS::SoundProc proc, void* param); // Setup a callba void doSoundCallback(); // Call function if sound buffers need more data void playSound(const void* data, u32 length, bool loop, bool adpcm = false, int rate = 22050); // Start a sound void stopSound(int channel); +int getSoundFrequency(); // Event queue void addEventsToQueue(); @@ -108,7 +110,6 @@ void setIndyFightState(bool st); bool getIndyFightState(); bool isCpuScalerEnabled(); - // Display bool getIsDisplayMode8Bit(); void setGameSize(int width, int height); diff --git a/backends/platform/ds/arm9/source/dsoptions.cpp b/backends/platform/ds/arm9/source/dsoptions.cpp index 2fd4fb136f..90722507e2 100644 --- a/backends/platform/ds/arm9/source/dsoptions.cpp +++ b/backends/platform/ds/arm9/source/dsoptions.cpp @@ -36,8 +36,8 @@ namespace Scumm { namespace DS { -DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 20, 320 - 40, 200 - 40) { - addButton(this, 10, 140, "Close", GUI::kCloseCmd, 'C'); +DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 0, 320 - 40, 200 - 20) { + addButton(this, 10, 160, "Close", GUI::kCloseCmd, 'C'); #ifdef DS_SCUMM_BUILD if (!DS::isGBAMPAvailable()) { @@ -45,29 +45,32 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 20, 320 - 40, 200 - 40) { } #endif - new GUI::StaticTextWidget(this, 0, 10, 280, 20, "ScummVM DS Options", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(this, 80, 10, 130, 15, "ScummVM DS Options", GUI::kTextAlignCenter); - _leftHandedCheckbox = new GUI::CheckboxWidget(this, 20, 30, 280, 20, "Left handed mode", 0, 'L'); - _indyFightCheckbox = new GUI::CheckboxWidget(this, 20, 50, 280, 20, "Indy fighting controls", 0, 'I'); - _unscaledCheckbox = new GUI::CheckboxWidget(this, 20, 70, 280, 20, "Unscaled lower screen", 0, 'S'); + _leftHandedCheckbox = new GUI::CheckboxWidget(this, 20, 25, 200, 20, "Left handed mode", 0, 'L'); + _indyFightCheckbox = new GUI::CheckboxWidget(this, 20, 40, 200, 20, "Indy fighting controls", 0, 'I'); + _unscaledCheckbox = new GUI::CheckboxWidget(this, 20, 55, 200, 20, "Unscaled main screen", 0, 'S'); + _twoHundredPercentCheckbox = new GUI::CheckboxWidget(this, 20, 70, 230, 20, "Zoomed screen at fixed 200% zoom", 0, 'T'); + _highQualityAudioCheckbox = new GUI::CheckboxWidget(this, 20, 85, 250, 20, "High quality audio (slower) (reboot)", 0, 'T'); + _disablePowerOff = new GUI::CheckboxWidget(this, 20, 100, 250, 20, "Disable power off on quit", 0, 'T'); - new GUI::StaticTextWidget(this, 20, 90, 110, 20, "Touch X Offset", GUI::kTextAlignLeft); - _touchX = new GUI::SliderWidget(this, 130, 90, 130, 12, 1); + new GUI::StaticTextWidget(this, 20, 130, 110, 15, "Touch X Offset", GUI::kTextAlignLeft); + _touchX = new GUI::SliderWidget(this, 130, 130, 130, 12, 1); _touchX->setMinValue(-8); _touchX->setMaxValue(+8); _touchX->setValue(0); _touchX->setFlags(GUI::WIDGET_CLEARBG); - new GUI::StaticTextWidget(this, 20, 110, 110, 20, "Touch Y Offset", GUI::kTextAlignLeft); - _touchY = new GUI::SliderWidget(this, 130, 110, 130, 12, 2); + new GUI::StaticTextWidget(this, 20, 145, 110, 15, "Touch Y Offset", GUI::kTextAlignLeft); + _touchY = new GUI::SliderWidget(this, 130, 145, 130, 12, 2); _touchY->setMinValue(-8); _touchY->setMaxValue(+8); _touchY->setValue(0); _touchY->setFlags(GUI::WIDGET_CLEARBG); - new GUI::StaticTextWidget(this, 130 + 65 - 10, 130, 20, 20, "0", GUI::kTextAlignCenter); - new GUI::StaticTextWidget(this, 130 + 130 - 10, 130, 20, 20, "8", GUI::kTextAlignCenter); - new GUI::StaticTextWidget(this, 130 - 10, 130, 20, 20, "-8", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(this, 130 + 65 - 10, 160, 20, 15, "0", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(this, 130 + 130 - 10, 160, 20, 15, "8", GUI::kTextAlignCenter); + new GUI::StaticTextWidget(this, 130 - 10, 160, 20, 15, "-8", GUI::kTextAlignCenter); #ifdef DS_SCUMM_BUILD _delDialog = new Scumm::SaveLoadChooser("Delete game:", "Delete", false, Scumm::g_scumm); @@ -84,7 +87,25 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 20, 320 - 40, 200 - 40) { } else { _unscaledCheckbox->setState(false); } - + + if (ConfMan.hasKey("twohundredpercent", "ds")) { + _twoHundredPercentCheckbox->setState(ConfMan.getBool("twohundredpercent", "ds")); + } else { + _twoHundredPercentCheckbox->setState(false); + } + + if (ConfMan.hasKey("22khzaudio", "ds")) { + _highQualityAudioCheckbox->setState(ConfMan.getBool("22khzaudio", "ds")); + } else { + _highQualityAudioCheckbox->setState(false); + } + + if (ConfMan.hasKey("disablepoweroff", "ds")) { + _disablePowerOff->setState(ConfMan.getBool("disablepoweroff", "ds")); + } else { + _disablePowerOff->setState(false); + } + _indyFightCheckbox->setState(DS::getIndyFightState()); if (ConfMan.hasKey("xoffset", "ds")) { @@ -104,6 +125,9 @@ DSOptionsDialog::DSOptionsDialog() : GUI::Dialog(20, 20, 320 - 40, 200 - 40) { DSOptionsDialog::~DSOptionsDialog() { ConfMan.setBool("lefthanded", _leftHandedCheckbox->getState(), "ds"); ConfMan.setBool("unscaled", _unscaledCheckbox->getState(), "ds"); + ConfMan.setBool("twohundredpercent", _twoHundredPercentCheckbox->getState(), "ds"); + ConfMan.setBool("22khzaudio", _highQualityAudioCheckbox->getState(), "ds"); + ConfMan.setBool("disablepoweroff", _disablePowerOff->getState(), "ds"); ConfMan.setInt("xoffset", _touchX->getValue(), "ds"); ConfMan.setInt("yoffset", _touchY->getValue(), "ds"); DS::setOptions(); @@ -189,6 +213,12 @@ void setOptions() { DS::setUnscaledMode(false); } + if (ConfMan.hasKey("twohundredpercent", "ds")) { + DS::set200PercentFixedScale(ConfMan.getBool("twohundredpercent", "ds")); + } else { + DS::set200PercentFixedScale(false); + } + if (ConfMan.hasKey("xoffset", "ds")) { DS::setTouchXOffset(ConfMan.getInt("xoffset", "ds")); } else { diff --git a/backends/platform/ds/arm9/source/dsoptions.h b/backends/platform/ds/arm9/source/dsoptions.h index b7a6eefcce..3ab20666c6 100644 --- a/backends/platform/ds/arm9/source/dsoptions.h +++ b/backends/platform/ds/arm9/source/dsoptions.h @@ -47,7 +47,10 @@ protected: GUI::SliderWidget* _touchY; GUI::CheckboxWidget* _leftHandedCheckbox; GUI::CheckboxWidget* _unscaledCheckbox; + GUI::CheckboxWidget* _twoHundredPercentCheckbox; GUI::CheckboxWidget* _indyFightCheckbox; + GUI::CheckboxWidget* _highQualityAudioCheckbox; + GUI::CheckboxWidget* _disablePowerOff; #ifdef DS_SCUMM_BUILD Scumm::SaveLoadChooser* _delDialog; #endif 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:ƒRƒ}ƒ“ƒhƒ‚[ƒhH - SDIDA1=0x40+17; // ƒRƒ}ƒ“ƒh CMD17 - SDIDA2=(sectorn>>7);// ƒZƒNƒ^H 9ƒrƒbƒg=ƒAƒhƒŒƒXH ‚P‚Uƒrƒbƒg - SDIDA3=(sectorn<<9);// ƒZƒNƒ^L 7ƒrƒbƒg=ƒAƒhƒŒƒXL ‚P‚Uƒrƒbƒg - SDDIR=0x29; // ƒRƒ}ƒ“ƒh‘—MH - 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)§or)+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 diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp index e6b9aa70ee..247b4e73de 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.cpp +++ b/backends/platform/ds/arm9/source/osystem_ds.cpp @@ -49,9 +49,11 @@ OSystem_DS::OSystem_DS() } OSystem_DS::~OSystem_DS() { + delete _mixer; + delete _timer; } -static int timer_handler(int t) +int OSystem_DS::timerHandler(int t) { DSTimerManager *tm = (DSTimerManager *)g_system->getTimerManager(); tm->handler(); @@ -60,12 +62,12 @@ static int timer_handler(int t) void OSystem_DS::initBackend() { ConfMan.setInt("autosave_period", 0); - ConfMan.setBool("FM_low_quality", true); + ConfMan.setBool("FM_medium_quality", true); _mixer = new DSAudioMixer; _timer = new DSTimerManager; DS::setSoundProc(Audio::Mixer::mixCallback, _mixer); - DS::setTimerCallback(&timer_handler, 10); + DS::setTimerCallback(&OSystem_DS::timerHandler, 10); OSystem::initBackend(); } @@ -123,8 +125,8 @@ int16 OSystem_DS::getWidth() { void OSystem_DS::setPalette(const byte *colors, uint start, uint num) { // consolePrintf("Set palette %d, %d colours\n", start, num); +//return; if (!DS::getIsDisplayMode8Bit()) return; - for (unsigned int r = start; r < start + num; r++) { int red = *colors; int green = *(colors + 1); @@ -402,7 +404,7 @@ void OSystem_DS::clearSoundCallback() int OSystem_DS::getOutputSampleRate() const { - return 11025; + return DS::getSoundFrequency(); } bool OSystem_DS::openCD(int drive) diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h index e3de86fc9b..dfff30bf4a 100644 --- a/backends/platform/ds/arm9/source/osystem_ds.h +++ b/backends/platform/ds/arm9/source/osystem_ds.h @@ -29,12 +29,10 @@ #include "backends/timer/default/default-timer.h" #include "sound/mixer.h" -class DSAudioMixer : public Audio::Mixer -{ +class DSAudioMixer : public Audio::Mixer { }; -class DSTimerManager : public DefaultTimerManager -{ +class DSTimerManager : public DefaultTimerManager { }; @@ -49,13 +47,13 @@ public: DSSaveFileManager saveManager; GBAMPSaveFileManager mpSaveManager; - DSAudioMixer* _mixer; - DSTimerManager* _timer; - + DSAudioMixer* _mixer; + DSTimerManager* _timer; + static OSystem_DS* _instance; typedef void (*SoundProc)(void *param, byte *buf, int len); - typedef int (*TimerProc)(int interval); + typedef int (*TimerProc)(int interval); public: @@ -134,8 +132,9 @@ public: virtual void initBackend(); - virtual Audio::Mixer* getMixer() { return _mixer; } - virtual Common::TimerManager* getTimerManager() { return _timer; } + virtual Audio::Mixer* getMixer() { return _mixer; } + virtual Common::TimerManager* getTimerManager() { return _timer; } + static int timerHandler(int t); }; static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { @@ -144,16 +143,16 @@ static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { OverlayColor OSystem_DS::RGBToColor(uint8 r, uint8 g, uint8 b) { - return 0x8000 | (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 5); + return 0x8000 | (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10); //consolePrintf("rgbtocol\n"); - return 0; + //return 0; } void OSystem_DS::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) { r = (color & 0x001F) << 3; - g = (color & 0x03E0) >> 5 << 3; - b = (color & 0x7C00) >> 10 << 3; + g = ((color & 0x03E0) >> 5) << 3; + b = ((color & 0x7C00) >> 10) << 3; //consolePrintf("coltorgb\n"); } diff --git a/backends/platform/ds/arm9/source/portdefs.h b/backends/platform/ds/arm9/source/portdefs.h index 76247cb966..02d54d3850 100644 --- a/backends/platform/ds/arm9/source/portdefs.h +++ b/backends/platform/ds/arm9/source/portdefs.h @@ -33,6 +33,7 @@ typedef signed int s32; //#define double float +#define CT_NO_TRANSPARENCY #undef assert #define assert(expr) consolePrintf("Asserted!") diff --git a/backends/platform/ds/arm9/source/ramsave.cpp b/backends/platform/ds/arm9/source/ramsave.cpp index 3f2791839a..f1849a97a3 100644 --- a/backends/platform/ds/arm9/source/ramsave.cpp +++ b/backends/platform/ds/arm9/source/ramsave.cpp @@ -25,6 +25,7 @@ #include "compressor/lz.h" #define CART_RAM ((vu8 *) (0x0A000000)) +#define SRAM_SAVE_MAX (65533) DSSaveFile::DSSaveFile() { ptr = 0; @@ -82,8 +83,7 @@ bool DSSaveFile::loadFromSaveRAM(vu8* address) { for (int t = 0; t < (int) sizeof(newSave); t++) { ((char *) (&newSave))[t] = *(address + t); } - - + if (newSave.magic == 0xBEEFCAFE) { newSave.isValid = true; @@ -101,6 +101,7 @@ bool DSSaveFile::loadFromSaveRAM(vu8* address) { this->saveData = saveData; ownsData = true; ptr = 0; + return true; } @@ -314,7 +315,7 @@ void DSSaveFileManager::loadAllFromSRAM() { gbaSave[r].deleteFile(); } - sramBytesFree = 65533; + sramBytesFree = SRAM_SAVE_MAX; // Try to find saves in save RAM for (int r = 0; r < 8; r++) { @@ -327,7 +328,7 @@ void DSSaveFileManager::loadAllFromSRAM() { } void DSSaveFileManager::formatSram() { - for (int r = 0; r < 65533; r++) { + for (int r = 0; r < SRAM_SAVE_MAX; r++) { *(CART_RAM + r) = 0; } @@ -421,6 +422,7 @@ Common::SaveFile *DSSaveFileManager::makeSaveFile(const char *filename, bool sav void DSSaveFileManager::flushToSaveRAM() { int cartAddr = 1; int s; + int extraData = DSSaveFileManager::getExtraData(); *((u16 *) (0x4000204)) |= 0x3; @@ -434,13 +436,13 @@ void DSSaveFileManager::flushToSaveRAM() { } } - if (size <= 65533) { + if (size <= SRAM_SAVE_MAX) { - for (int r = 0; r < 65533; r++) { + for (int r = 0; r < SRAM_SAVE_MAX; r++) { *(CART_RAM + r) = 0; } - sramBytesFree = 65533; + sramBytesFree = SRAM_SAVE_MAX; for (int r = 0; (r < 8); r++) { if (gbaSave[r].isValid() && (!gbaSave[r].isTemp())) { @@ -459,5 +461,40 @@ void DSSaveFileManager::flushToSaveRAM() { loadAllFromSRAM(); } + + DSSaveFileManager::setExtraData(extraData); // consolePrintf("SRAM free: %d bytes\n", getBytesFree()); } + +void DSSaveFileManager::setExtraData(int data) { + // Offset of extra data is 31. This overlaps the padding and reserved bytes of the first save entry. + // which have not been used up until now. So it should be safe. + + vu8* sram = CART_RAM + 31; + + *(sram + 0) = 0xF0; // This is an identifier to check + *(sram + 1) = 0x0D; // that extra data is present. + + *(sram + 2) = (data & 0xFF000000) >> 24; // Now write the actual data + *(sram + 3) = (data & 0x00FF0000) >> 16; // taking care to use single + *(sram + 4) = (data & 0x0000FF00) >> 8; // byte writes (it's an 8-bit bus) + *(sram + 5) = (data & 0x000000FF); +} + +bool DSSaveFileManager::isExtraDataPresent() { + vu8* sram = CART_RAM + 31; + + // Check for the identifier + return ((*(sram + 0) == 0xF0) && (*(sram + 1) == 0x0D)); +} + +int DSSaveFileManager::getExtraData() { + vu8* sram = CART_RAM + 31; + + if (isExtraDataPresent()) { + int value = (*(sram + 2) << 24) | (*(sram + 3) << 16) | (*(sram + 4) << 8) | (*(sram + 5)); + return value; + } else { + return 0; + } +} diff --git a/backends/platform/ds/arm9/source/ramsave.h b/backends/platform/ds/arm9/source/ramsave.h index affef289b0..b8baa26b02 100644 --- a/backends/platform/ds/arm9/source/ramsave.h +++ b/backends/platform/ds/arm9/source/ramsave.h @@ -35,14 +35,14 @@ class DSSaveFile : public Common::SaveFile { bool saveCompressed; struct SCUMMSave { - u32 magic; - bool isValid; - bool pad; - char name[16]; - u32 size; - u32 compressedSize; - u16 pad2; - u32 reserved; + u32 magic; // 4 + bool isValid; // 5 + bool pad; // 6 + char name[16]; // 22 + u32 size; // 26 + u32 compressedSize; // 30 + u16 extraMagic; // 32 + u32 reserved; // 36 } __attribute__ ((packed)); SCUMMSave save; @@ -89,6 +89,7 @@ public: bool loadFromSaveRAM(vu8* address); int saveToSaveRAM(vu8* address); + void deleteFile(); @@ -134,6 +135,10 @@ public: void loadAllFromSRAM(); + static bool isExtraDataPresent(); + static int getExtraData(); + static void setExtraData(int data); + protected: Common::SaveFile *makeSaveFile(const char *filename, bool saveOrLoad); }; diff --git a/backends/platform/ds/arm9/source/scummhelp.cpp b/backends/platform/ds/arm9/source/scummhelp.cpp index d71f0807e7..62f0dad4fd 100644 --- a/backends/platform/ds/arm9/source/scummhelp.cpp +++ b/backends/platform/ds/arm9/source/scummhelp.cpp @@ -47,10 +47,8 @@ void updateStrings(byte gameId, byte version, Common::Platform platform, ADD_BIND("A", "Switch screens"); ADD_BIND("Y", "Show/hide debug console"); ADD_BIND("X", "Show/hide keyboard"); - ADD_BIND("L + Pad", "Scroll current touch screen view"); - ADD_BIND("L + Pen", "Scroll current touch screen view"); - ADD_BIND("L + B", "Zoom in"); - ADD_BIND("L + A", "Zoom out"); + ADD_BIND("L + Pad/Pen", "Scroll current touch screen view"); + ADD_BIND("L + B/A", "Zoom in/out"); break; } @@ -66,10 +64,8 @@ void updateStrings(byte gameId, byte version, Common::Platform platform, ADD_BIND("Pad Up", "Show/hide keyboard"); ADD_BIND("Pad Left", "Show/hide debug console"); ADD_BIND("Pad Right", "Swap screens"); - ADD_BIND("R + Pad", "Scroll current touch screen view"); - ADD_BIND("R + Pen", "Scroll current touch screen view"); - ADD_BIND("R + B", "Zoom in"); - ADD_BIND("R + A", "Zoom out"); + ADD_BIND("R + Pad/Pen", "Scroll current touch screen view"); + ADD_BIND("R+down/right", "Zoom in/out"); break; } diff --git a/backends/platform/ds/arm9/source/zipreader.cpp b/backends/platform/ds/arm9/source/zipreader.cpp index 92dd170c2a..8cb97b20cf 100644 --- a/backends/platform/ds/arm9/source/zipreader.cpp +++ b/backends/platform/ds/arm9/source/zipreader.cpp @@ -92,6 +92,8 @@ bool ZipFile::currentFileInFolder() { if (_allFilesVisible) return true; getFileName(name); + +// consolePrintf("N:'%s'D:'%s'\n", name, _directory); if (_directory[0] == 0) { // Root directory name[strlen(name) - 1] = 0; @@ -214,10 +216,15 @@ void ZipFile::changeToRoot() { void ZipFile::changeDirectory(char* dir) { // consolePrintf("Current dir now '%s'\n", dir); + strcpy(_directory, dir); - size_t l = strlen(_directory); - if (l && (_directory[l-1] == '/' )) - _directory[l-1] = '\0'; + for (int r = 0; r < (int) strlen(_directory); r++) { + if (_directory[r] == '/') _directory[r] = '\\'; + } + + if (_directory[strlen(_directory) - 1] == '\\') { + _directory[strlen(_directory) - 1] = '\0'; + } } ZipFile::~ZipFile() { diff --git a/backends/platform/ds/logoa.bmp b/backends/platform/ds/logoa.bmp Binary files differnew file mode 100644 index 0000000000..0e98305d28 --- /dev/null +++ b/backends/platform/ds/logoa.bmp diff --git a/backends/platform/ds/logob.bmp b/backends/platform/ds/logob.bmp Binary files differnew file mode 100644 index 0000000000..9c28f5f0a4 --- /dev/null +++ b/backends/platform/ds/logob.bmp diff --git a/backends/platform/ds/logoc.bmp b/backends/platform/ds/logoc.bmp Binary files differnew file mode 100644 index 0000000000..41ec429926 --- /dev/null +++ b/backends/platform/ds/logoc.bmp |