diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 62324f6f1..130255c1b 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -27,6 +27,7 @@ #include "fatal_private.hpp" #include "fatal_user.hpp" #include "fatal_config.hpp" +#include "fatal_repair.hpp" extern "C" { extern u32 __start__; @@ -135,12 +136,13 @@ int main(int argc, char **argv) /* TODO: Load shared font. */ - /* TODO: Check whether we should throw fatal due to repair process... */ + /* Check whether we should throw fatal due to repair process. */ + CheckRepairStatus(); /* TODO: What's a good timeout value to use here? */ auto server_manager = new WaitableManager(1); - /* TODO: Create services. */ + /* Create services. */ server_manager->AddWaitable(new ServiceServer("fatal:p", 4)); server_manager->AddWaitable(new ServiceServer("fatal:u", 4)); server_manager->AddWaitable(GetFatalSettingsEvent()); diff --git a/stratosphere/fatal/source/fatal_repair.cpp b/stratosphere/fatal/source/fatal_repair.cpp index b9fdefef8..d4ff000f2 100644 --- a/stratosphere/fatal/source/fatal_repair.cpp +++ b/stratosphere/fatal/source/fatal_repair.cpp @@ -15,10 +15,70 @@ */ #include +#include #include "fatal_types.hpp" #include "fatal_repair.hpp" #include "fatal_throw.hpp" -void CheckRepairStatus() { - /* TODO */ +static bool InRepairWithoutVolHeld() { + if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) { + return false; + } + + bool in_repair; + if (R_FAILED(setsysGetFlag(SetSysFlag_InRepairProcessEnable, &in_repair)) || !in_repair) { + return false; + } + + { + GpioPadSession vol_btn; + if (R_SUCCEEDED(gpioOpenSession(&vol_btn, GpioPadName_ButtonVolUp))) { + /* Ensure we close even on early return. */ + ON_SCOPE_EXIT { gpioPadClose(&vol_btn); }; + + /* Set direction input. */ + gpioPadSetDirection(&vol_btn, GpioDirection_Input); + + /* Ensure that we're holding the volume button for a full second. */ + TimeoutHelper timeout_helper(1000000000UL); + while (!timeout_helper.TimedOut()) { + GpioValue val; + if (R_FAILED(gpioPadGetValue(&vol_btn, &val)) || val != GpioValue_Low) { + return true; + } + + /* Sleep for 100 ms. */ + svcSleepThread(100000000UL); + } + } + } + + return false; +} + +static bool InRepairWithoutTimeReviserCartridge() { + if (GetRuntimeFirmwareVersion() < FirmwareVersion_500) { + return false; + } + + bool requires_time_reviser; + if (R_FAILED(setsysGetFlag(SetSysFlag_RequiresRunRepairTimeReviser, &requires_time_reviser)) || !requires_time_reviser) { + return false; + } + + /* TODO: if (!IsGamecardInserted()) { return true; } */ + + /* TODO: return GetGameCardAttribute(GetGameCardHandle()) & GameCardAttribute_Repair == GameCardAttribute_Repair; */ + + return false; +} + +void CheckRepairStatus() { + if (InRepairWithoutVolHeld()) { + ThrowFatalForSelf(FatalResult_InRepairWithoutVolHeld); + } + + if (InRepairWithoutTimeReviserCartridge()) { + ThrowFatalForSelf(FatalResult_InRepairWithoutTimeReviserCartridge); + } }