aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/ds/arm9/source
diff options
context:
space:
mode:
authorNeil Millstone2006-11-03 23:16:29 +0000
committerNeil Millstone2006-11-03 23:16:29 +0000
commitea6663fdfa5f2b9d8351f9b06219d0dae1494a6c (patch)
tree76a1ca3e5f5672194133d3bdaabdb038275a0e57 /backends/platform/ds/arm9/source
parentd5608e82edb4a73f6ab30a8db9a79dc16ed2ed9f (diff)
downloadscummvm-rg350-ea6663fdfa5f2b9d8351f9b06219d0dae1494a6c.tar.gz
scummvm-rg350-ea6663fdfa5f2b9d8351f9b06219d0dae1494a6c.tar.bz2
scummvm-rg350-ea6663fdfa5f2b9d8351f9b06219d0dae1494a6c.zip
Merging in changes made in branch for 0.9.1 release into trunk
svn-id: r24596
Diffstat (limited to 'backends/platform/ds/arm9/source')
-rw-r--r--backends/platform/ds/arm9/source/cdaudio.cpp18
-rw-r--r--backends/platform/ds/arm9/source/dsmain.cpp360
-rw-r--r--backends/platform/ds/arm9/source/dsmain.h3
-rw-r--r--backends/platform/ds/arm9/source/dsoptions.cpp58
-rw-r--r--backends/platform/ds/arm9/source/dsoptions.h3
-rw-r--r--backends/platform/ds/arm9/source/fat/disc_io.c104
-rw-r--r--backends/platform/ds/arm9/source/fat/disc_io.h190
-rw-r--r--backends/platform/ds/arm9/source/fat/gba_nds_fat.c4
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3_common.c60
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3sd.c739
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3sd.h71
-rw-r--r--backends/platform/ds/arm9/source/fat/io_m3sd_asm.s1
-rw-r--r--backends/platform/ds/arm9/source/fat/io_mmcf.c363
-rw-r--r--backends/platform/ds/arm9/source/fat/io_mmcf.h25
-rw-r--r--backends/platform/ds/arm9/source/fat/io_mpcf.c3
-rw-r--r--backends/platform/ds/arm9/source/fat/io_njsd.c679
-rw-r--r--backends/platform/ds/arm9/source/fat/io_njsd.h50
-rw-r--r--backends/platform/ds/arm9/source/fat/io_scsd_asm.s521
-rw-r--r--backends/platform/ds/arm9/source/fat/io_sd_common.c203
-rw-r--r--backends/platform/ds/arm9/source/fat/io_sd_common.h114
-rw-r--r--backends/platform/ds/arm9/source/osystem_ds.cpp12
-rw-r--r--backends/platform/ds/arm9/source/osystem_ds.h27
-rw-r--r--backends/platform/ds/arm9/source/portdefs.h1
-rw-r--r--backends/platform/ds/arm9/source/ramsave.cpp51
-rw-r--r--backends/platform/ds/arm9/source/ramsave.h21
-rw-r--r--backends/platform/ds/arm9/source/scummhelp.cpp12
-rw-r--r--backends/platform/ds/arm9/source/zipreader.cpp13
27 files changed, 2520 insertions, 1186 deletions
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)&sector)+3);
-@ char2=(u8*)databuff;
-@ *char2++=coma+0x40;
-@ *char2++=*char1--;
-@ *char2++=*char1--;
-@ *char2++=*char1--;
-@ *char2++=*char1;
-@ *char2=sd_crc7_s((u32)databuff,5);
-@
-@ sd_com_write_s((u32)databuff,6);
-@
-@}
-SDCommand:
- stmfd r13!,{r14}
-
- sub r13,r13,#16
- add r0,r0,#0x40
- strb r0,[r13,#4]
-
- mov r1,r2,lsr #24
- strb r1,[r13,#5]
- mov r1,r2,lsr #16
- strb r1,[r13,#6]
- mov r1,r2,lsr #8
- strb r1,[r13,#7]
- strb r2,[r13,#8]
- add r0,r13,#4
- mov r1,#5
- bl sd_crc7_s
- strb r0,[r13,#9]
- add r0,r13,#4
- mov r1,#6
- bl sd_com_write_s
-
- add r13,r13,#16
- ldmfd r13!,{r15}
-@ bx r14
-@---------------------------end SDCommand--------------------
-
-@----------void ReadSector(u16 *buff,u32 sector,u8 readnum)-------------
- .ALIGN
- .GLOBAL ReadSector @ r0:Srcp r1:num ok
- .CODE 32
-
-@void ReadSector(u16 *buff,u32 sector,u8 readnum)
-@{
-@ register u16 i,j;
-@ i=readnum;
-@ sectno<<=9;
-@ SDCommand(18,0,sector);
-@ for (j=0;j<i ; j++)
-@ {
-@ sd_data_read_s((u32)buff+j*512);
-@ }
-@ SDCommand(12,0,0);
-@ get_resp();
-@ send_clk(0x10);
-@
-@}
-ReadSector:
- stmfd r13!,{r4-r6,r14}
-
- mov r4,r0
- mov r5,r2
-
- mov r2,r1,lsl #9
- mov r0,#18
- mov r1,#0
- bl SDCommand
- mov r6,#0
-beginforj_ReadSector:
- cmp r6,r5
- bge endforj_ReadSector
- mov r0,r4
- add r0,r0,r6,lsl #9
- bl sd_data_read_s
- add r6,r6,#1
- b beginforj_ReadSector
-endforj_ReadSector:
- mov r0,#12
- mov r1,#0
- mov r2,#0
- bl SDCommand
- bl get_resp
- mov r0,#0x10
- bl send_clk
- mov r0,#1
- ldmfd r13!,{r4-r6,r15}
-@ bx r14
-@----------end ReadSector------------
-
-@-----------void get_resp(void)-------------------
-
-
- .ALIGN
- .GLOBAL get_resp @ r0:Srcp r1:num ok
- .CODE 32
-get_resp:
-
- stmfd r13!,{r14}
- mov r1,#6
- bl sd_com_read_s
- ldmfd r13!,{r15}
-@-----------end get_resp-------------------
-
-
-@---------------void WriteSector(u16 *buff,u32 sector,u8 writenum)---------------------
- .ALIGN
- .GLOBAL WriteSector @ r0:Srcp r1:num ok
- .CODE 32
-
-@void WriteSector(u16 *buff,u32 sector,u8 writenum)
-@{
-@ register u16 i,j;
-@ u16 crc16[5];
-@ i=writenum;
-@
-@ sectno<<=9;
-@
-@ SDCommand(25,0,sector);
-@ get_resp();
-@ send_clk(0x10);
-@
-@ for (j=0;j<i ; j++)
-@ {
-@ sd_crc16_s((u32)(u32)buff+j*512,512,(u32)crc16);
-@ sd_data_write_s((u32)buff+j*512,(u32)crc16);
-@ send_clk(0x10);
-@ }
-@ SDCommand(12,0,0);
-@ get_resp();
-@ send_clk(0x10);
-@ while((*(u16*)sd_dataadd &0x0100)==0);
-@
-@}
-@
-WriteSector:
- stmfd r13!,{r4-r6,r14}
-
- sub r13,r13,#20
-
- mov r4,r0
- mov r5,r2
-
- mov r2,r1,lsl #9
- mov r0,#25
- mov r1,#0
- bl SDCommand
- bl get_resp
- mov r0,#0x10
- bl send_clk
- mov r6,#0
-
-beginforj_WriteSector:
- cmp r6,r5
- bge endforj_WriteSector
- mov r0,r4
- add r0,r0,r6,lsl #9
- mov r1,#512
- add r2,r13,#4
- bl sd_crc16_s
- mov r0,r4
- add r0,r0,r6,lsl #9
- add r1,r13,#4
- bl sd_data_write_s
- mov r0,#0x10
- bl send_clk
- add r6,r6,#1
- b beginforj_WriteSector
-endforj_WriteSector:
- mov r0,#12
- mov r1,#0
- mov r2,#0
- bl SDCommand
- bl get_resp
- mov r0,#0x10
- bl send_clk
- ldr r0,=sd_dataadd
-beginwhile_WriteSector:
- ldrh r1,[r0]
- tst r1,#0x0100
- beq beginwhile_WriteSector
- mov r0,#1
- add r13,r13,#20
- ldmfd r13!,{r4-r6,r15}
-@---------------end WriteSector--------------------
-
-@----------------void InitSCMode(void)---------------
- .ALIGN
- .GLOBAL InitSCMode
- .CODE 32
-InitSCMode:
- mvn r0,#0x0F6000000
- sub r0,r0,#0x01
- mov r1,#0x0A500
- add r1,r1,#0x5A
- strh r1,[r0]
- strh r1,[r0]
- mov r2,#3
- strh r2,[r0]
- strh r2,[r0]
- bx r14
-@----------------end InitSCMode ---------------
-
-@----------------bool MemoryCard_IsInserted(void)---------------
- .ALIGN
- .GLOBAL MemoryCard_IsInserted
- .CODE 32
-
-MemoryCard_IsInserted:
- ldr r0,=sd_comadd
- ldrh r1,[r0]
- tst r1,#0x300
- moveq r0,#1
- movne r0,#0
- bx r14
-@----------------end MemoryCard_IsInserted---------------
-
- .END
-
-
-
-
-
-
-
-
-
-
-
diff --git a/backends/platform/ds/arm9/source/fat/io_sd_common.c b/backends/platform/ds/arm9/source/fat/io_sd_common.c
new file mode 100644
index 0000000000..0a38e6277c
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_sd_common.c
@@ -0,0 +1,203 @@
+/*
+ io_sd_common.c
+
+ By chishm (Michael Chisholm)
+
+ Common SD card routines
+
+ SD routines partially based on sd.s by Romman
+
+ Copyright (c) 2006 Michael "Chishm" Chisholm
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ 2006-08-07 - Chishm
+ * Moved the SD initialization to a common function
+ * Increased timeouts for slower cards
+*/
+
+#include "io_sd_common.h"
+
+#define MAX_STARTUP_TRIES 1000 // Arbitrary value, check if the card is ready 20 times before giving up
+#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
+
+/*
+Improved CRC7 function provided by cory1492
+Calculates the CRC of an SD command, and includes the end bit in the byte
+*/
+u8 _SD_CRC7(u8* data, int cnt) {
+ int i, a;
+ u8 crc, temp;
+
+ crc = 0;
+ for (a = 0; a < cnt; a++)
+ {
+ temp = data[a];
+ for (i = 0; i < 8; i++)
+ {
+ crc <<= 1;
+ if ((temp & 0x80) ^ (crc & 0x80)) crc ^= 0x09;
+ temp <<= 1;
+ }
+ }
+ crc = (crc << 1) | 1;
+ return(crc);
+}
+
+/*
+Calculates the CRC16 for a sector of data. Calculates it
+as 4 separate lots, merged into one buffer. This is used
+for 4 SD data lines, not for 1 data line alone.
+*/
+void _SD_CRC16 (u8* buff, int buffLength, u8* crc16buff) {
+ u32 a, b, c, d;
+ int count;
+ u32 bitPattern = 0x80808080; // r7
+ u32 crcConst = 0x1021; // r8
+ u32 dataByte = 0; // r2
+
+ a = 0; // r3
+ b = 0; // r4
+ c = 0; // r5
+ d = 0; // r6
+
+ buffLength = buffLength * 8;
+
+
+ do {
+ if (bitPattern & 0x80) dataByte = *buff++;
+
+ a = a << 1;
+ if ( a & 0x10000) a ^= crcConst;
+ if (dataByte & (bitPattern >> 24)) a ^= crcConst;
+
+ b = b << 1;
+ if (b & 0x10000) b ^= crcConst;
+ if (dataByte & (bitPattern >> 25)) b ^= crcConst;
+
+ c = c << 1;
+ if (c & 0x10000) c ^= crcConst;
+ if (dataByte & (bitPattern >> 26)) c ^= crcConst;
+
+ d = d << 1;
+ if (d & 0x10000) d ^= crcConst;
+ if (dataByte & (bitPattern >> 27)) d ^= crcConst;
+
+ bitPattern = (bitPattern >> 4) | (bitPattern << 28);
+ } while (buffLength-=4);
+
+ count = 16; // r8
+
+ do {
+ bitPattern = bitPattern << 4;
+ if (a & 0x8000) bitPattern |= 8;
+ if (b & 0x8000) bitPattern |= 4;
+ if (c & 0x8000) bitPattern |= 2;
+ if (d & 0x8000) bitPattern |= 1;
+
+ a = a << 1;
+ b = b << 1;
+ c = c << 1;
+ d = d << 1;
+
+ count--;
+
+ if (!(count & 0x01)) {
+ *crc16buff++ = (u8)(bitPattern & 0xff);
+ }
+ } while (count != 0);
+
+ return;
+}
+
+/*
+Initialise the SD card, after it has been sent into an Idle state
+cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
+cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
+use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
+RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
+*/
+bool _SD_InitCard (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
+ _SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
+ bool use4bitBus,
+ u32 *RCA)
+{
+ u8 responseBuffer[17] = {0};
+ int i;
+
+ for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
+ cmd_6byte_response (responseBuffer, APP_CMD, 0);
+ if (
+ cmd_6byte_response (responseBuffer, SD_APP_OP_COND, SD_OCR_VALUE) &&
+ ((responseBuffer[1] & 0x80) != 0))
+ {
+ // Card is ready to receive commands now
+ break;
+ }
+ }
+ if (i >= MAX_STARTUP_TRIES) {
+ return false;
+ }
+
+ // The card's name, as assigned by the manufacturer
+ cmd_17byte_response (responseBuffer, ALL_SEND_CID, 0);
+
+ // Get a new address
+ for (i = 0; i < MAX_STARTUP_TRIES ; i++) {
+ cmd_6byte_response (responseBuffer, SEND_RELATIVE_ADDR, 0);
+ *RCA = (responseBuffer[1] << 24) | (responseBuffer[2] << 16);
+ if ((responseBuffer[3] & 0x1e) != (SD_STATE_STBY << 1)) {
+ break;
+ }
+ }
+ if (i >= MAX_STARTUP_TRIES) {
+ return false;
+ }
+
+ // Some cards won't go to higher speeds unless they think you checked their capabilities
+ cmd_17byte_response (responseBuffer, SEND_CSD, *RCA);
+
+ // Only this card should respond to all future commands
+ cmd_6byte_response (responseBuffer, SELECT_CARD, *RCA);
+
+ if (use4bitBus) {
+ // Set a 4 bit data bus
+ cmd_6byte_response (responseBuffer, APP_CMD, *RCA);
+ cmd_6byte_response (responseBuffer, SET_BUS_WIDTH, 2); // 4-bit mode.
+ }
+
+ // Use 512 byte blocks
+ cmd_6byte_response (responseBuffer, SET_BLOCKLEN, 512); // 512 byte blocks
+
+ // Wait until card is ready for data
+ i = 0;
+ do {
+ if (i >= RESPONSE_TIMEOUT) {
+ return false;
+ }
+ i++;
+ } while (!cmd_6byte_response (responseBuffer, SEND_STATUS, *RCA) && ((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
+
+ return true;
+}
+
+
diff --git a/backends/platform/ds/arm9/source/fat/io_sd_common.h b/backends/platform/ds/arm9/source/fat/io_sd_common.h
new file mode 100644
index 0000000000..09abffab39
--- /dev/null
+++ b/backends/platform/ds/arm9/source/fat/io_sd_common.h
@@ -0,0 +1,114 @@
+/*
+ io_sd_common.h
+
+ By chishm (Michael Chisholm)
+
+ Common SD card routines
+
+ SD routines partially based on sd.s by Romman
+
+ Copyright (c) 2006 Michael "Chishm" Chisholm
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ 2006-07-11 - Chishm
+ * Original release
+
+ 2006-07-28 - Chishm
+ * Changed voltage range that the SD card can use
+*/
+
+#ifndef IO_SD_COMMON_H
+#define IO_SD_COMMON_H
+
+#include "disc_io.h"
+
+/* SD commands */
+#define GO_IDLE_STATE 0
+#define ALL_SEND_CID 2
+#define SEND_RELATIVE_ADDR 3
+#define SELECT_CARD 7
+#define SEND_CSD 9
+#define STOP_TRANSMISSION 12
+#define SEND_STATUS 13
+#define GO_INACTIVE_STATE 15
+#define SET_BLOCKLEN 16
+#define READ_SINGLE_BLOCK 17
+#define READ_MULTIPLE_BLOCK 18
+#define WRITE_BLOCK 24
+#define WRITE_MULTIPLE_BLOCK 25
+#define APP_CMD 55
+
+/* SD App commands */
+#define SET_BUS_WIDTH 6
+#define SD_APP_OP_COND 41
+
+/* OCR (Operating Conditions Register) send value */
+//#define SD_OCR_VALUE 0x00030000 /* 2.8V to 3.0V */
+//#define SD_OCR_VALUE 0x003F8000 /* 2.7V to 3.4V */
+#define SD_OCR_VALUE 0x00FC0000
+
+/* SD Data repsonses */
+#define SD_CARD_BUSY 0xff
+
+/* SD states */
+#define SD_STATE_IDLE 0 // Idle state, after power on or GO_IDLE_STATE command
+#define SD_STATE_READY 1 // Ready state, after card replies non-busy to SD_APP_OP_COND
+#define SD_STATE_IDENT 2 // Identification state, after ALL_SEND_CID
+#define SD_STATE_STBY 3 // Standby state, when card is deselected
+#define SD_STATE_TRAN 4 // Transfer state, after card is selected and ready for data transfer
+#define SD_STATE_DATA 5 //
+#define SD_STATE_RCV 6 // Receive data state
+#define SD_STATE_PRG 7 // Programming state
+#define SD_STATE_DIS 8 // Disconnect state
+#define SD_STATE_INA 9 // Inactive state, after GO_INACTIVE_STATE
+
+#define READY_FOR_DATA 1 // bit 8 in card status
+
+/*
+Calculate the CRC7 of a command and return it preshifted with
+an end bit added
+*/
+extern u8 _SD_CRC7(u8* data, int size);
+
+/*
+Calculate the CRC16 of a block of data, ready for transmission on
+four data lines at once
+*/
+extern void _SD_CRC16 (u8* buff, int buffLength, u8* crc16buff);
+
+typedef bool (*_SD_FN_CMD_6BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
+typedef bool (*_SD_FN_CMD_17BYTE_RESPONSE) (u8* responseBuffer, u8 command, u32 data);
+
+/*
+Initialise the SD card, after it has been sent into an Idle state
+cmd_6byte_response: a pointer to a function that sends the SD card a command and gets a 6 byte response
+cmd_17byte_response: a pointer to a function that sends the SD card a command and gets a 17 byte response
+use4bitBus: initialise card to use a 4 bit data bus when communicating with the card
+RCA: a pointer to the location to store the card's Relative Card Address, preshifted up by 16 bits.
+*/
+extern bool _SD_InitCard (_SD_FN_CMD_6BYTE_RESPONSE cmd_6byte_response,
+ _SD_FN_CMD_17BYTE_RESPONSE cmd_17byte_response,
+ bool use4bitBus,
+ u32 *RCA);
+
+#endif // define IO_SD_COMMON_H
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() {