From d2b01b4aa5573df71fdb6e5f27d5a21d430f9e16 Mon Sep 17 00:00:00 2001 From: Asaduji <39374509+Asaduji@users.noreply.github.com> Date: Sun, 29 Mar 2026 17:49:58 +0200 Subject: [PATCH 1/2] Detect flashcart if fat can be mounted --- arm9/source/fsmngr.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arm9/source/fsmngr.cpp b/arm9/source/fsmngr.cpp index c6160b6a..711c8d4a 100644 --- a/arm9/source/fsmngr.cpp +++ b/arm9/source/fsmngr.cpp @@ -20,9 +20,11 @@ void cFSManager::init(int argc, char* argv[]) { } // Mount devices - if (isFlashcart()) { - fatMountSimple("fat", dldiGetInternal()); + // If we can mount fat, we're on a flashcart + if (fatMountSimple("fat", dldiGetInternal())) { chdir("fat:/"); + + _isFlashcart = true; _fsRoot = "fat:"; } From 25840e15e3094e7c9a2f8d17baf8152e734316af Mon Sep 17 00:00:00 2001 From: Asaduji <39374509+Asaduji@users.noreply.github.com> Date: Sun, 29 Mar 2026 19:02:14 +0200 Subject: [PATCH 2/2] Add 3DS detection, fixes nds-bootstrap on 3DS --- arm7/source/main.cpp | 17 +++ arm7/source/my_i2c.c | 133 ++++++++++++++++++ arm7/source/my_i2c.h | 19 +++ arm9/source/launcher/NdsBootstrapLauncher.cpp | 16 +++ arm9/source/launcher/NdsBootstrapLauncher.h | 1 + share/fifotool.h | 1 + 6 files changed, 187 insertions(+) create mode 100644 arm7/source/my_i2c.c create mode 100644 arm7/source/my_i2c.h diff --git a/arm7/source/main.cpp b/arm7/source/main.cpp index 6237e5db..ce924a3d 100644 --- a/arm7/source/main.cpp +++ b/arm7/source/main.cpp @@ -11,6 +11,7 @@ #include "../../share/fifotool.h" #include "../../share/memtool.h" #include "picoLoader7.h" +#include "my_i2c.h" #ifdef __cplusplus extern "C" { @@ -121,6 +122,20 @@ static u8 checkSD(void) { return status & (1u << 5); } +static u8 check3DS(void) { + if (!isDSiMode()) { + return 0; + } + + u8 byteBak = my_i2cReadRegister(0x4A, 0x71); + my_i2cWriteRegister(0x4A, 0x71, 0xD2); + u8 byteNew = my_i2cReadRegister(0x4A, 0x71); + u8 is3DS = (byteNew != 0xD2) ? 1 : 0; + my_i2cWriteRegister(0x4A, 0x71, byteBak); + + return is3DS; +} + static void menuValue32Handler(u32 value, void* data) { switch (value) { case MENU_MSG_GBA: { @@ -167,6 +182,8 @@ static void menuValue32Handler(u32 value, void* data) { case MENU_MSG_IS_SD_INSERTED: fifoSendValue32(FIFO_USER_01, checkSD()); break; + case MENU_MSG_IS_3DS: + fifoSendValue32(FIFO_USER_01, check3DS()); default: break; } diff --git a/arm7/source/my_i2c.c b/arm7/source/my_i2c.c new file mode 100644 index 00000000..9a802f32 --- /dev/null +++ b/arm7/source/my_i2c.c @@ -0,0 +1,133 @@ +/*--------------------------------------------------------------------------------- + + I2C control for the ARM7 + + Copyright (C) 2011 + Dave Murphy (WinterMute) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source + distribution. + +---------------------------------------------------------------------------------*/ + +#include +#include +#include "my_i2c.h" + +static u32 i2cCurrentDelay = 0; + +//--------------------------------------------------------------------------------- +void my_i2cDelay() { +//--------------------------------------------------------------------------------- + i2cWaitBusy(); + swiDelay(i2cCurrentDelay); +} + +//--------------------------------------------------------------------------------- +void my_i2cStop(u8 arg0) { +//--------------------------------------------------------------------------------- + if (i2cCurrentDelay) { + REG_I2CCNT = (arg0 << 5) | 0xC0; + my_i2cDelay(); + REG_I2CCNT = 0xC5; + } else REG_I2CCNT = (arg0 << 5) | 0xC1; +} + + +//--------------------------------------------------------------------------------- +u8 my_i2cGetResult() { +//--------------------------------------------------------------------------------- + i2cWaitBusy(); + return (REG_I2CCNT >> 4) & 0x01; +} + +//--------------------------------------------------------------------------------- +u8 my_i2cGetData() { +//--------------------------------------------------------------------------------- + i2cWaitBusy(); + return REG_I2CDATA; +} + +//--------------------------------------------------------------------------------- +void my_i2cSetDelay(u8 device) { +//--------------------------------------------------------------------------------- + if (device == I2C_PM ) { + i2cCurrentDelay = 0x180; + } else { + i2cCurrentDelay = 0; + } +} + +//--------------------------------------------------------------------------------- +u8 my_i2cSelectDevice(u8 device) { +//--------------------------------------------------------------------------------- + i2cWaitBusy(); + REG_I2CDATA = device; + REG_I2CCNT = 0xC2; + return my_i2cGetResult(); +} + +//--------------------------------------------------------------------------------- +u8 my_i2cSelectRegister(u8 reg) { +//--------------------------------------------------------------------------------- + my_i2cDelay(); + REG_I2CDATA = reg; + REG_I2CCNT = 0xC0; + return my_i2cGetResult(); +} + +//--------------------------------------------------------------------------------- +u8 my_i2cWriteRegister(u8 device, u8 reg, u8 data) { +//--------------------------------------------------------------------------------- + my_i2cSetDelay(device); + int i; + + for (i = 0; i < 8; i++) { + if ((my_i2cSelectDevice(device) != 0) && (my_i2cSelectRegister(reg) != 0)) { + my_i2cDelay(); + REG_I2CDATA = data; + my_i2cStop(0); + if (my_i2cGetResult() != 0) return 1; + } + REG_I2CCNT = 0xC5; + } + + return 0; +} + +//--------------------------------------------------------------------------------- +u8 my_i2cReadRegister(u8 device, u8 reg) { +//--------------------------------------------------------------------------------- + my_i2cSetDelay(device); + int i; + + for (i = 0; i < 8; i++) { + + if ((my_i2cSelectDevice(device) != 0) && (my_i2cSelectRegister(reg) != 0)) { + my_i2cDelay(); + if (my_i2cSelectDevice(device | 1)) { + my_i2cDelay(); + my_i2cStop(1); + return my_i2cGetData(); + } + } + + REG_I2CCNT = 0xC5; + } + + return 0xff; +} \ No newline at end of file diff --git a/arm7/source/my_i2c.h b/arm7/source/my_i2c.h new file mode 100644 index 00000000..43f50e46 --- /dev/null +++ b/arm7/source/my_i2c.h @@ -0,0 +1,19 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void my_i2cDelay(); +void my_i2cStop(u8 arg0); +u8 my_i2cGetResult(); +u8 my_i2cGetData(); +void my_i2cSetDelay(u8 device); +u8 my_i2cSelectDevice(u8 device); +u8 my_i2cSelectRegister(u8 reg); +u8 my_i2cWriteRegister(u8 device, u8 reg, u8 data); +u8 my_i2cReadRegister(u8 device, u8 reg); +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/arm9/source/launcher/NdsBootstrapLauncher.cpp b/arm9/source/launcher/NdsBootstrapLauncher.cpp index 304a67d3..32b1374b 100644 --- a/arm9/source/launcher/NdsBootstrapLauncher.cpp +++ b/arm9/source/launcher/NdsBootstrapLauncher.cpp @@ -121,6 +121,8 @@ bool NdsBootstrapLauncher::prepareIni(bool hb) { ini.SetString("NDS-BOOTSTRAP", "QUIT_PATH", fsManager().resolveSystemPath("/_nds/akmenunext/launcher.nds")); + ini.SetString("NDS-BOOTSTRAP", "CONSOLE_MODEL", is3DS() ? "2" : "0"); + std::string custIniPath = fsManager().resolveSystemPath("/_nds/akmenunext/ndsbs.ini"); if(access(custIniPath.c_str(), F_OK) != 0){ @@ -230,6 +232,20 @@ bool NdsBootstrapLauncher::prepareIni(bool hb) { return true; } +bool NdsBootstrapLauncher::is3DS(void) { + if (!isDSiMode()) { + return false; + } + + fifoSendValue32(FIFO_USER_01, MENU_MSG_IS_3DS); + + fifoWaitValue32(FIFO_USER_01); + + int result = fifoGetValue32(FIFO_USER_01); + + return result != 0; +} + bool launchHbStrap(std::string romPath){ progressWnd().setPercent(100); std::string ndsHbBootstrapPath = fsManager().resolveSystemPath("/_nds/nds-bootstrap-hb-release.nds"); diff --git a/arm9/source/launcher/NdsBootstrapLauncher.h b/arm9/source/launcher/NdsBootstrapLauncher.h index 48bcb6e2..fef2fbc8 100644 --- a/arm9/source/launcher/NdsBootstrapLauncher.h +++ b/arm9/source/launcher/NdsBootstrapLauncher.h @@ -19,6 +19,7 @@ class NdsBootstrapLauncher : public ILauncher { private: bool prepareCheats(void); bool prepareIni(bool hb); + bool is3DS(void); bool hotkeyCheck; std::string mRomPath; std::string mSavePath; diff --git a/share/fifotool.h b/share/fifotool.h index 36f991cf..ff7a034d 100644 --- a/share/fifotool.h +++ b/share/fifotool.h @@ -21,3 +21,4 @@ #define MENU_MSG_ARM7_REBOOT_TT 13 #define MENU_MSG_ARM7_REBOOT_PICOLOADER 14 #define MENU_MSG_IS_SD_INSERTED 15 +#define MENU_MSG_IS_3DS 16 \ No newline at end of file