From 22fb4ff0956491139ec84cfc87602e9eaccdf39a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 26 Oct 2020 04:06:02 -0700 Subject: [PATCH] sdmmc: add DeviceDetector, gpio: implement client api --- .../libstratosphere/include/stratosphere.hpp | 1 + .../impl/ams_system_thread_definitions.hpp | 16 +- .../include/stratosphere/ddsf.hpp | 19 ++ .../include/stratosphere/ddsf/ddsf_types.hpp | 30 ++ .../include/stratosphere/gpio.hpp | 20 ++ .../include/stratosphere/gpio/gpio_api.hpp | 25 ++ .../stratosphere/gpio/gpio_pad_api.hpp | 58 ++++ .../gpio/gpio_pad_name.board.nintendo_nx.hpp | 55 ++++ .../gpio/gpio_select_pad_name.hpp | 24 ++ .../include/stratosphere/gpio/gpio_types.hpp | 44 +++ .../source/boot2/boot2_api.cpp | 15 +- .../source/gpio/gpio_client_api.cpp | 190 +++++++++++++ libraries/libvapours/include/vapours.hpp | 1 + .../include/vapours/device_code.hpp | 49 ++++ .../vapours/sdmmc/sdmmc_build_config.hpp | 3 + .../sdmmc/impl/sdmmc_device_detector.cpp | 262 ++++++++++++++++++ .../sdmmc/impl/sdmmc_device_detector.hpp | 99 +++++++ .../source/sdmmc/impl/sdmmc_port_sd_card0.cpp | 1 + .../source/sdmmc/impl/sdmmc_port_sd_card0.hpp | 2 + .../impl/sdmmc_sd_card_device_accessor.hpp | 25 ++ stratosphere/boot2/source/boot2_main.cpp | 4 +- stratosphere/fatal/source/fatal_main.cpp | 4 +- stratosphere/fatal/source/fatal_repair.cpp | 11 +- .../fatal/source/fatal_task_power.cpp | 22 +- .../fatal/source/fatal_task_sound.cpp | 12 +- 25 files changed, 950 insertions(+), 42 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/ddsf.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/ddsf/ddsf_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/gpio.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.board.nintendo_nx.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp create mode 100644 libraries/libstratosphere/source/gpio/gpio_client_api.cpp create mode 100644 libraries/libvapours/include/vapours/device_code.hpp create mode 100644 libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp create mode 100644 libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.hpp create mode 100644 libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.hpp diff --git a/libraries/libstratosphere/include/stratosphere.hpp b/libraries/libstratosphere/include/stratosphere.hpp index c46b4dd08..6096ca240 100644 --- a/libraries/libstratosphere/include/stratosphere.hpp +++ b/libraries/libstratosphere/include/stratosphere.hpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp b/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp index 7d60ab72d..837598518 100644 --- a/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp +++ b/libraries/libstratosphere/include/stratosphere/ams/impl/ams_system_thread_definitions.hpp @@ -39,19 +39,21 @@ namespace ams::impl { AMS_DEFINE_SYSTEM_THREAD(21, pm, Main); AMS_DEFINE_SYSTEM_THREAD(21, pm, ProcessTrack); + /* NCM. */ AMS_DEFINE_SYSTEM_THREAD(21, ncm, MainWaitThreads); AMS_DEFINE_SYSTEM_THREAD(21, ncm, ContentManagerServerIpcSession); AMS_DEFINE_SYSTEM_THREAD(21, ncm, LocationResolverServerIpcSession); /* FS. */ - AMS_DEFINE_SYSTEM_THREAD(16, fs, WorkerThreadPool); - AMS_DEFINE_SYSTEM_THREAD(17, fs, Main); - AMS_DEFINE_SYSTEM_THREAD(17, fs, WorkerRealTimeAccess); - AMS_DEFINE_SYSTEM_THREAD(18, fs, WorkerNormalPriorityAccess); - AMS_DEFINE_SYSTEM_THREAD(19, fs, WorkerLowPriorityAccess); - AMS_DEFINE_SYSTEM_THREAD(30, fs, WorkerBackgroundAccess); - AMS_DEFINE_SYSTEM_THREAD(30, fs, PatrolReader); + AMS_DEFINE_SYSTEM_THREAD(11, sdmmc, DeviceDetector); + AMS_DEFINE_SYSTEM_THREAD(16, fs, WorkerThreadPool); + AMS_DEFINE_SYSTEM_THREAD(17, fs, Main); + AMS_DEFINE_SYSTEM_THREAD(17, fs, WorkerRealTimeAccess); + AMS_DEFINE_SYSTEM_THREAD(18, fs, WorkerNormalPriorityAccess); + AMS_DEFINE_SYSTEM_THREAD(19, fs, WorkerLowPriorityAccess); + AMS_DEFINE_SYSTEM_THREAD(30, fs, WorkerBackgroundAccess); + AMS_DEFINE_SYSTEM_THREAD(30, fs, PatrolReader); /* Boot. */ AMS_DEFINE_SYSTEM_THREAD(-1, boot, Main); diff --git a/libraries/libstratosphere/include/stratosphere/ddsf.hpp b/libraries/libstratosphere/include/stratosphere/ddsf.hpp new file mode 100644 index 000000000..000a4aedd --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ddsf.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_types.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_types.hpp new file mode 100644 index 000000000..467c48dbe --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_types.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::ddsf { + + enum AccessMode { + AccessMode_None = (0u << 0), + AccessMode_Read = (1u << 0), + AccessMode_Write = (1u << 1), + + AccessMode_ReadWrite = AccessMode_Read | AccessMode_Write, + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio.hpp b/libraries/libstratosphere/include/stratosphere/gpio.hpp new file mode 100644 index 000000000..861f294b7 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp new file mode 100644 index 000000000..a58c8b21c --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::gpio { + + void Initialize(); + void Finalize(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_api.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_api.hpp new file mode 100644 index 000000000..a02d34884 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_api.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include +#include + +namespace ams::gpio { + + struct GpioPadSession { + void *_session; + os::SystemEventType *_event; + }; + + Result OpenSession(GpioPadSession *out_session, ams::DeviceCode device_code); + void CloseSession(GpioPadSession *session); + + Direction GetDirection(GpioPadSession *session); + void SetDirection(GpioPadSession *session, Direction direction); + + GpioValue GetValue(GpioPadSession *session); + void SetValue(GpioPadSession *session, GpioValue value); + + InterruptMode GetInterruptMode(GpioPadSession *session); + void SetInterruptMode(GpioPadSession *session, InterruptMode mode); + + bool GetInterruptEnable(GpioPadSession *session); + void SetInterruptEnable(GpioPadSession *session, bool en); + + InterruptStatus GetInterruptStatus(GpioPadSession *session); + void ClearInterruptStatus(GpioPadSession *session); + + int GetDebounceTime(GpioPadSession *session); + void SetDebounceTime(GpioPadSession *session, int ms); + + bool GetDebounceEnabled(GpioPadSession *session); + void SetDebounceEnabled(GpioPadSession *session, bool en); + + Result BindInterrupt(os::SystemEventType *event, GpioPadSession *session); + void UnbindInterrupt(GpioPadSession *session); + + Result IsWakeEventActive(bool *out_is_active, ams::DeviceCode device_code); + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.board.nintendo_nx.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.board.nintendo_nx.hpp new file mode 100644 index 000000000..8a201779e --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_pad_name.board.nintendo_nx.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::gpio { + + enum GpioPadName { + GpioPadName_CodecLdoEnTemp = 1, + GpioPadName_ButtonVolUp = 25, + GpioPadName_ButtonVolDn = 26, + GpioPadName_SdCd = 56, + }; + + /* TODO: Better place for this? */ + constexpr inline const DeviceCode DeviceCode_CodecLdoEnTemp = 0x33000002; + constexpr inline const DeviceCode DeviceCode_ButtonVolUp = 0x35000002; + constexpr inline const DeviceCode DeviceCode_ButtonVolDn = 0x35000003; + constexpr inline const DeviceCode DeviceCode_SdCd = 0x3C000002; + + constexpr inline GpioPadName ConvertToGpioPadName(DeviceCode dc) { + switch (dc.GetInternalValue()) { + case DeviceCode_CodecLdoEnTemp.GetInternalValue(): return GpioPadName_CodecLdoEnTemp; + case DeviceCode_ButtonVolUp .GetInternalValue(): return GpioPadName_ButtonVolUp; + case DeviceCode_ButtonVolDn .GetInternalValue(): return GpioPadName_ButtonVolDn; + case DeviceCode_SdCd .GetInternalValue(): return GpioPadName_SdCd; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + constexpr inline DeviceCode ConvertToDeviceCode(GpioPadName gpn) { + switch (gpn) { + case GpioPadName_CodecLdoEnTemp: return DeviceCode_CodecLdoEnTemp; + case GpioPadName_ButtonVolUp: return DeviceCode_ButtonVolUp; + case GpioPadName_ButtonVolDn: return DeviceCode_ButtonVolDn; + case GpioPadName_SdCd: return DeviceCode_SdCd; + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp new file mode 100644 index 000000000..25e665375 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_select_pad_name.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + #include +#else + /* Error? */ +#endif diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp new file mode 100644 index 000000000..b2b9331ac --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::gpio { + + enum InterruptMode { + InterruptMode_LowLevel = 0, + InterruptMode_HighLevel = 1, + InterruptMode_RisingEdge = 2, + InterruptMode_FallingEdge = 3, + InterruptMode_AnyEdge = 4, + }; + + enum Direction { + Direction_Input = 0, + Direction_Output = 1, + }; + + enum GpioValue { + GpioValue_Low = 0, + GpioValue_High = 1, + }; + + enum InterruptStatus { + InterruptStatus_Inactive = 0, + InterruptStatus_Active = 1, + }; + +} diff --git a/libraries/libstratosphere/source/boot2/boot2_api.cpp b/libraries/libstratosphere/source/boot2/boot2_api.cpp index c2c050f39..4f4cda01a 100644 --- a/libraries/libstratosphere/source/boot2/boot2_api.cpp +++ b/libraries/libstratosphere/source/boot2/boot2_api.cpp @@ -167,20 +167,19 @@ namespace ams::boot2 { } } - bool GetGpioPadLow(GpioPadName pad) { - GpioPadSession button; - if (R_FAILED(gpioOpenSession(&button, pad))) { + bool GetGpioPadLow(DeviceCode device_code) { + gpio::GpioPadSession button; + if (R_FAILED(gpio::OpenSession(std::addressof(button), device_code))) { return false; } /* Ensure we close even on early return. */ - ON_SCOPE_EXIT { gpioPadClose(&button); }; + ON_SCOPE_EXIT { gpio::CloseSession(std::addressof(button)); }; /* Set direction input. */ - gpioPadSetDirection(&button, GpioDirection_Input); + gpio::SetDirection(std::addressof(button), gpio::Direction_Input); - GpioValue val; - return R_SUCCEEDED(gpioPadGetValue(&button, &val)) && val == GpioValue_Low; + return gpio::GetValue(std::addressof(button)) == gpio::GpioValue_Low; } bool IsForceMaintenance() { @@ -197,7 +196,7 @@ namespace ams::boot2 { /* Contact GPIO, read plus/minus buttons. */ { - return GetGpioPadLow(GpioPadName_ButtonVolUp) && GetGpioPadLow(GpioPadName_ButtonVolDown); + return GetGpioPadLow(gpio::DeviceCode_ButtonVolUp) && GetGpioPadLow(gpio::DeviceCode_ButtonVolDn); } } diff --git a/libraries/libstratosphere/source/gpio/gpio_client_api.cpp b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp new file mode 100644 index 000000000..17e0e6f36 --- /dev/null +++ b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::gpio { + + /* TODO: This deserves proper new interface def support. */ + + namespace { + + /* TODO: Manager object. */ + constinit os::SdkMutex g_init_mutex; + constinit int g_initialize_count = 0; + + using InternalSession = ::GpioPadSession; + + InternalSession *GetInterface(GpioPadSession *session) { + AMS_ASSERT(session->_session != nullptr); + return static_cast<::GpioPadSession *>(session->_session); + } + + } + + void Initialize() { + std::scoped_lock lk(g_init_mutex); + + if ((g_initialize_count++) == 0) { + R_ABORT_UNLESS(::gpioInitialize()); + } + } + + void Finalize() { + std::scoped_lock lk(g_init_mutex); + + AMS_ASSERT(g_initialize_count > 0); + + if ((--g_initialize_count) == 0) { + ::gpioExit(); + } + } + + Result OpenSession(GpioPadSession *out_session, ams::DeviceCode device_code) { + /* Allocate the session. */ + InternalSession *internal_session = static_cast(std::malloc(sizeof(InternalSession))); + AMS_ABORT_UNLESS(internal_session != nullptr); + auto session_guard = SCOPE_GUARD { std::free(internal_session); }; + + /* Get the session. */ + if (hos::GetVersion() >= hos::Version_7_0_0) { + R_TRY(::gpioOpenSession2(internal_session, device_code.GetInternalValue(), ddsf::AccessMode_ReadWrite)); + } else { + R_ABORT_UNLESS(::gpioOpenSession(internal_session, static_cast<::GpioPadName>(static_cast(ConvertToGpioPadName(device_code))))); + } + + /* Set output. */ + out_session->_session = internal_session; + out_session->_event = nullptr; + + /* We succeeded. */ + session_guard.Cancel(); + return ResultSuccess(); + } + + void CloseSession(GpioPadSession *session) { + AMS_ASSERT(session != nullptr); + + /* Unbind the interrupt, if it's still bound. */ + if (session->_event != nullptr) { + gpio::UnbindInterrupt(session); + } + + /* Close the session. */ + ::gpioPadClose(GetInterface(session)); + std::free(session->_session); + session->_session = nullptr; + } + + Result IsWakeEventActive(bool *out_is_active, ams::DeviceCode device_code) { + if (hos::GetVersion() >= hos::Version_7_0_0) { + R_TRY(::gpioIsWakeEventActive2(out_is_active, device_code.GetInternalValue())); + } else { + R_ABORT_UNLESS(::gpioIsWakeEventActive(out_is_active, static_cast<::GpioPadName>(static_cast(ConvertToGpioPadName(device_code))))); + } + + return ResultSuccess(); + } + + Direction GetDirection(GpioPadSession *session) { + ::GpioDirection out; + R_ABORT_UNLESS(::gpioPadGetDirection(GetInterface(session), std::addressof(out))); + return static_cast(static_cast(out)); + } + + void SetDirection(GpioPadSession *session, Direction direction) { + R_ABORT_UNLESS(::gpioPadSetDirection(GetInterface(session), static_cast<::GpioDirection>(static_cast(direction)))); + } + + GpioValue GetValue(GpioPadSession *session) { + ::GpioValue out; + R_ABORT_UNLESS(::gpioPadGetValue(GetInterface(session), std::addressof(out))); + return static_cast(static_cast(out)); + } + + void SetValue(GpioPadSession *session, GpioValue value) { + R_ABORT_UNLESS(::gpioPadSetValue(GetInterface(session), static_cast<::GpioValue>(static_cast(value)))); + } + + InterruptMode GetInterruptMode(GpioPadSession *session) { + ::GpioInterruptMode out; + R_ABORT_UNLESS(::gpioPadGetInterruptMode(GetInterface(session), std::addressof(out))); + return static_cast(static_cast(out)); + } + + void SetInterruptMode(GpioPadSession *session, InterruptMode mode) { + R_ABORT_UNLESS(::gpioPadSetInterruptMode(GetInterface(session), static_cast<::GpioInterruptMode>(static_cast(mode)))); + } + + bool GetInterruptEnable(GpioPadSession *session) { + bool out; + R_ABORT_UNLESS(::gpioPadGetInterruptEnable(GetInterface(session), std::addressof(out))); + return out; + } + + void SetInterruptEnable(GpioPadSession *session, bool en) { + R_ABORT_UNLESS(::gpioPadSetInterruptEnable(GetInterface(session), en)); + } + + InterruptStatus GetInterruptStatus(GpioPadSession *session) { + ::GpioInterruptStatus out; + R_ABORT_UNLESS(::gpioPadGetInterruptStatus(GetInterface(session), std::addressof(out))); + return static_cast(static_cast(out)); + } + + void ClearInterruptStatus(GpioPadSession *session) { + R_ABORT_UNLESS(::gpioPadClearInterruptStatus(GetInterface(session))); + } + + int GetDebounceTime(GpioPadSession *session) { + int out; + R_ABORT_UNLESS(::gpioPadGetDebounceTime(GetInterface(session), std::addressof(out))); + return out; + } + + void SetDebounceTime(GpioPadSession *session, int ms) { + R_ABORT_UNLESS(::gpioPadSetDebounceTime(GetInterface(session), ms)); + } + + bool GetDebounceEnabled(GpioPadSession *session) { + bool out; + R_ABORT_UNLESS(::gpioPadGetDebounceEnabled(GetInterface(session), std::addressof(out))); + return out; + } + + void SetDebounceEnabled(GpioPadSession *session, bool en) { + R_ABORT_UNLESS(::gpioPadSetDebounceEnabled(GetInterface(session), en)); + } + + Result BindInterrupt(os::SystemEventType *event, GpioPadSession *session) { + ::Event ev; + R_TRY(::gpioPadBindInterrupt(GetInterface(session), std::addressof(ev))); + + os::AttachReadableHandleToSystemEvent(event, ev.revent, true, os::EventClearMode_ManualClear); + + session->_event = event; + return ResultSuccess(); + } + + void UnbindInterrupt(GpioPadSession *session) { + AMS_ASSERT(session->_event != nullptr); + + R_ABORT_UNLESS(::gpioPadUnbindInterrupt(GetInterface(session))); + + os::DestroySystemEvent(session->_event); + session->_event = nullptr; + } + +} diff --git a/libraries/libvapours/include/vapours.hpp b/libraries/libvapours/include/vapours.hpp index 0bd48b651..a47ec53bc 100644 --- a/libraries/libvapours/include/vapours.hpp +++ b/libraries/libvapours/include/vapours.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include diff --git a/libraries/libvapours/include/vapours/device_code.hpp b/libraries/libvapours/include/vapours/device_code.hpp new file mode 100644 index 000000000..c39abcaf2 --- /dev/null +++ b/libraries/libvapours/include/vapours/device_code.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +namespace ams { + + namespace impl { + + using DeviceCodeType = u32; + + } + + /* TODO: Better understand device code components. */ + class DeviceCode { + private: + impl::DeviceCodeType inner_value; + public: + constexpr DeviceCode(impl::DeviceCodeType v) : inner_value(v) { /* ... */ } + + constexpr impl::DeviceCodeType GetInternalValue() const { return this->inner_value; } + + constexpr bool operator==(const DeviceCode &rhs) const { + return this->GetInternalValue() == rhs.GetInternalValue(); + } + + constexpr bool operator!=(const DeviceCode &rhs) const { + return !(*this == rhs); + } + }; + + constexpr inline const DeviceCode InvalidDeviceCode(0); + +} diff --git a/libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp b/libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp index fd2bfb37c..b8ca6e2b1 100644 --- a/libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp +++ b/libraries/libvapours/include/vapours/sdmmc/sdmmc_build_config.hpp @@ -34,6 +34,7 @@ #define AMS_SDMMC_USE_UTIL_TIMER //#define AMS_SDMMC_ENABLE_MMC_HS400 //#define AMS_SDMMC_SET_PLLC4_BASE + //#define AMS_SDMMC_USE_SD_CARD_DETECTOR #elif defined(ATMOSPHERE_IS_MESOSPHERE) @@ -47,6 +48,7 @@ #define AMS_SDMMC_USE_UTIL_TIMER //#define AMS_SDMMC_ENABLE_MMC_HS400 //#define AMS_SDMMC_SET_PLLC4_BASE + //#define AMS_SDMMC_USE_SD_CARD_DETECTOR #elif defined(ATMOSPHERE_IS_STRATOSPHERE) @@ -60,6 +62,7 @@ //#define AMS_SDMMC_USE_UTIL_TIMER #define AMS_SDMMC_ENABLE_MMC_HS400 #define AMS_SDMMC_SET_PLLC4_BASE + #define AMS_SDMMC_USE_SD_CARD_DETECTOR #else #error "Unknown execution context for ams::sdmmc!" diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp new file mode 100644 index 000000000..39f3c233f --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#if defined(AMS_SDMMC_USE_SD_CARD_DETECTOR) +#include "sdmmc_device_detector.hpp" + +namespace ams::sdmmc::impl { + + bool DeviceDetector::IsCurrentInserted() { + return gpio::GetValue(std::addressof(this->gpio_pad_session)) == this->inserted_gpio_value; + } + + void DeviceDetector::HandleDeviceStatus(bool prev_inserted, bool cur_inserted) { + if (!prev_inserted && !cur_inserted) { + /* Not inserted -> Not inserted, nothing to do. */ + } else if (!prev_inserted && cur_inserted) { + /* Card was inserted. */ + if (this->callback_info.inserted_callback != nullptr) { + this->callback_info.inserted_callback(this->callback_info.inserted_callback_arg); + } + } else if (prev_inserted && !cur_inserted) { + /* Card was removed. */ + if (this->callback_info.removed_callback != nullptr) { + this->callback_info.removed_callback(this->callback_info.removed_callback_arg); + } + } else /* if (prev_inserted && cur_inserted) */ { + /* Card was removed, and then inserted. */ + if (this->callback_info.removed_callback != nullptr) { + this->callback_info.removed_callback(this->callback_info.removed_callback_arg); + } + + if (this->callback_info.inserted_callback != nullptr) { + this->callback_info.inserted_callback(this->callback_info.inserted_callback_arg); + } + } + } + + void DeviceDetector::DetectorThread() { + /* Initialize the gpio session. */ + sm::DoWithSession([] { gpio::Initialize(); }); + gpio::OpenSession(std::addressof(this->gpio_pad_session), this->gpio_device_code); + gpio::SetDirection(std::addressof(this->gpio_pad_session), gpio::Direction_Input); + gpio::SetDebounceTime(std::addressof(this->gpio_pad_session), this->gpio_debounce_ms); + gpio::SetDebounceEnabled(std::addressof(this->gpio_pad_session), true); + gpio::SetInterruptMode(std::addressof(this->gpio_pad_session), gpio::InterruptMode_AnyEdge); + + /* Get the gpio session's interrupt event. */ + os::SystemEventType gpio_event; + R_ABORT_UNLESS(gpio::BindInterrupt(std::addressof(gpio_event), std::addressof(this->gpio_pad_session))); + + /* Initialize and link waitable holders. */ + os::WaitableManagerType wait_manager; + os::WaitableHolderType detector_thread_end_holder; + os::WaitableHolderType request_sleep_wake_event_holder; + os::WaitableHolderType gpio_event_holder; + os::InitializeWaitableManager(std::addressof(wait_manager)); + os::InitializeWaitableHolder(std::addressof(detector_thread_end_holder), std::addressof(this->detector_thread_end_event)); + os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(detector_thread_end_holder)); + os::InitializeWaitableHolder(std::addressof(request_sleep_wake_event_holder), std::addressof(this->request_sleep_wake_event)); + os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(request_sleep_wake_event_holder)); + os::InitializeWaitableHolder(std::addressof(gpio_event_holder), std::addressof(gpio_event)); + os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(gpio_event_holder)); + + /* Wait before detecting the initial state of the card. */ + os::SleepThread(TimeSpan::FromMilliSeconds(this->gpio_debounce_ms)); + bool cur_inserted = this->IsCurrentInserted(); + this->is_prev_inserted = cur_inserted; + + /* Set state as awake. */ + this->state = State_Awake; + os::SignalEvent(std::addressof(this->ready_device_status_event)); + + /* Enable interrupts to be informed of device status. */ + gpio::SetInterruptEnable(std::addressof(this->gpio_pad_session), true); + + /* Wait, servicing our events. */ + while (true) { + /* Get the signaled holder. */ + os::WaitableHolderType *signaled_holder = os::WaitAny(std::addressof(wait_manager)); + + /* Process the holder. */ + bool insert_change = false; + if (signaled_holder == std::addressof(detector_thread_end_holder)) { + /* We should kill ourselves. */ + os::ClearEvent(std::addressof(this->detector_thread_end_event)); + this->state = State_Finalized; + break; + } else if (signaled_holder == std::addressof(request_sleep_wake_event_holder)) { + /* A request for us to sleep/wake has come in, so we'll acknowledge it. */ + os::ClearEvent(std::addressof(this->request_sleep_wake_event)); + this->state = State_Sleep; + os::SignalEvent(std::addressof(this->acknowledge_sleep_awake_event)); + + /* Temporarily unlink our interrupt event. */ + os::UnlinkWaitableHolder(std::addressof(gpio_event_holder)); + + /* Wait to be signaled. */ + signaled_holder = os::WaitAny(std::addressof(wait_manager)); + + /* Link our interrupt event back in. */ + os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(gpio_event_holder)); + + /* We're awake again. Either because we should exit, or because we were asked to wake up. */ + os::ClearEvent(std::addressof(this->request_sleep_wake_event)); + this->state = State_Awake; + os::SignalEvent(std::addressof(this->acknowledge_sleep_awake_event)); + + /* If we were asked to exit, do so. */ + if (signaled_holder == std::addressof(detector_thread_end_holder)) { + /* We should kill ourselves. */ + os::ClearEvent(std::addressof(this->detector_thread_end_event)); + this->state = State_Finalized; + break; + } else /* if (signaled_holder == std::addressof(request_sleep_wake_event_holder)) */ { + if ((this->force_detection) || + (({ bool active; R_SUCCEEDED(gpio::IsWakeEventActive(std::addressof(active), this->gpio_device_code)) && active; })) || + (os::TryWaitSystemEvent(std::addressof(gpio_event))) || + (this->is_prev_inserted != this->IsCurrentInserted())) + { + insert_change = true; + } + } + } else /* if (signaled_holder == std::addressof(gpio_event_holder)) */ { + /* An event was detected. */ + insert_change = true; + } + + /* Handle an insert change, if one occurred. */ + if (insert_change) { + /* Call the relevant callback, if we have one. */ + if (this->device_detection_event_callback != nullptr) { + this->device_detection_event_callback(this->device_detection_event_callback_arg); + } + + /* Clear the interrupt event. */ + os::ClearSystemEvent(std::addressof(gpio_event)); + gpio::ClearInterruptStatus(std::addressof(this->gpio_pad_session)); + gpio::SetInterruptEnable(std::addressof(this->gpio_pad_session), true); + + /* Update insertion status. */ + cur_inserted = this->IsCurrentInserted(); + this->HandleDeviceStatus(this->is_prev_inserted, cur_inserted); + this->is_prev_inserted = cur_inserted; + } + } + + /* Disable interrupts to our gpio event. */ + gpio::SetInterruptEnable(std::addressof(this->gpio_pad_session), false); + + /* Finalize and unlink waitable holders. */ + os::UnlinkWaitableHolder(std::addressof(gpio_event_holder)); + os::FinalizeWaitableHolder(std::addressof(gpio_event_holder)); + os::UnlinkWaitableHolder(std::addressof(request_sleep_wake_event_holder)); + os::FinalizeWaitableHolder(std::addressof(request_sleep_wake_event_holder)); + os::UnlinkWaitableHolder(std::addressof(detector_thread_end_holder)); + os::FinalizeWaitableHolder(std::addressof(detector_thread_end_holder)); + os::FinalizeWaitableManager(std::addressof(wait_manager)); + + /* Finalize the gpio session. */ + gpio::UnbindInterrupt(std::addressof(this->gpio_pad_session)); + gpio::CloseSession(std::addressof(this->gpio_pad_session)); + gpio::Finalize(); + } + + void DeviceDetector::Initialize(CallbackInfo *ci) { + /* Transition our state from finalized to initializing. */ + AMS_ABORT_UNLESS(this->state == State_Finalized); + this->state = State_Initializing; + + /* Set our callback infos. */ + this->callback_info = *ci; + + /* Initialize our events. */ + os::InitializeEvent(std::addressof(this->ready_device_status_event), false, os::EventClearMode_ManualClear); + os::InitializeEvent(std::addressof(this->request_sleep_wake_event), false, os::EventClearMode_ManualClear); + os::InitializeEvent(std::addressof(this->acknowledge_sleep_awake_event), false, os::EventClearMode_ManualClear); + os::InitializeEvent(std::addressof(this->detector_thread_end_event), false, os::EventClearMode_ManualClear); + + /* Create and start the detector thread. */ + os::CreateThread(std::addressof(this->detector_thread), DetectorThreadEntry, this, this->detector_thread_stack, sizeof(this->detector_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(sdmmc, DeviceDetector)); + os::SetThreadNamePointer(std::addressof(this->detector_thread), AMS_GET_SYSTEM_THREAD_NAME(sdmmc, DeviceDetector)); + os::StartThread(std::addressof(this->detector_thread)); + } + + void DeviceDetector::Finalize() { + /* Ensure we're not already finalized. */ + AMS_ABORT_UNLESS(this->state != State_Finalized); + + /* Signal event to end the detector thread. */ + os::SignalEvent(std::addressof(this->detector_thread_end_event)); + os::WaitThread(std::addressof(this->detector_thread)); + + /* Finalize thread and events. */ + os::DestroyThread(std::addressof(this->detector_thread)); + os::FinalizeEvent(std::addressof(this->ready_device_status_event)); + os::FinalizeEvent(std::addressof(this->request_sleep_wake_event)); + os::FinalizeEvent(std::addressof(this->acknowledge_sleep_awake_event)); + os::FinalizeEvent(std::addressof(this->detector_thread_end_event)); + } + + void DeviceDetector::PutToSleep() { + /* Signal request, wait for acknowledgement. */ + os::SignalEvent(std::addressof(this->request_sleep_wake_event)); + os::WaitEvent(std::addressof(this->acknowledge_sleep_awake_event)); + os::ClearEvent(std::addressof(this->acknowledge_sleep_awake_event)); + } + + void DeviceDetector::Awaken(bool force_det) { + /* Signal request, wait for acknowledgement. */ + this->force_detection = force_det; + os::SignalEvent(std::addressof(this->request_sleep_wake_event)); + os::WaitEvent(std::addressof(this->acknowledge_sleep_awake_event)); + os::ClearEvent(std::addressof(this->acknowledge_sleep_awake_event)); + } + + bool DeviceDetector::IsInserted() { + bool inserted = false; + + switch (this->state) { + case State_Initializing: + /* Wait for us to know whether the device is inserted. */ + os::WaitEvent(std::addressof(this->ready_device_status_event)); + [[fallthrough]]; + case State_Awake: + /* Get whether the device is currently inserted. */ + inserted = this->IsCurrentInserted(); + break; + case State_Sleep: + case State_Finalized: + /* Get whether the device was inserted when we last knew. */ + inserted = this->is_prev_inserted; + break; + } + + return inserted; + } + + void DeviceDetector::RegisterDetectionEventCallback(DeviceDetectionEventCallback cb, void *arg) { + this->device_detection_event_callback_arg = arg; + this->device_detection_event_callback = cb; + } + + void DeviceDetector::UnregisterDetectionEventCallback() { + this->device_detection_event_callback = nullptr; + } + +} + +#endif diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.hpp new file mode 100644 index 000000000..a61f05095 --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#if defined(AMS_SDMMC_USE_SD_CARD_DETECTOR) +#include + +namespace ams::sdmmc::impl { + + using InsertedCallback = void (*)(void *); + using RemovedCallback = void (*)(void *); + + struct CallbackInfo { + InsertedCallback inserted_callback; + void *inserted_callback_arg; + RemovedCallback removed_callback; + void *removed_callback_arg; + }; + + class DeviceDetector { + private: + enum State { + State_Initializing = 0, + State_Awake = 1, + State_Sleep = 2, + State_Finalized = 3, + }; + private: + alignas(os::ThreadStackAlignment) u8 detector_thread_stack[8_KB]; + State state; + bool is_prev_inserted; + bool force_detection; + os::ThreadType detector_thread; + os::EventType detector_thread_end_event; + os::EventType request_sleep_wake_event; + os::EventType acknowledge_sleep_awake_event; + os::EventType ready_device_status_event; + + DeviceCode gpio_device_code; + gpio::GpioValue inserted_gpio_value; + u32 gpio_debounce_ms; + gpio::GpioPadSession gpio_pad_session; + + CallbackInfo callback_info; + + DeviceDetectionEventCallback device_detection_event_callback; + void *device_detection_event_callback_arg; + private: + static void DetectorThreadEntry(void *arg) { + reinterpret_cast(arg)->DetectorThread(); + } + + void DetectorThread(); + bool IsCurrentInserted(); + void HandleDeviceStatus(bool prev_inserted, bool cur_inserted); + public: + explicit DeviceDetector(DeviceCode dc, gpio::GpioValue igv, u32 gd) + : gpio_device_code(dc), inserted_gpio_value(igv), gpio_debounce_ms(gd) + { + this->state = State_Finalized; + this->is_prev_inserted = false; + this->force_detection = false; + this->callback_info = {}; + this->device_detection_event_callback = nullptr; + this->device_detection_event_callback_arg = nullptr; + } + + void Initialize(CallbackInfo *ci); + void Finalize(); + + void PutToSleep(); + void Awaken(bool force_det); + + u32 GetDebounceMilliSeconds() const { + return this->gpio_debounce_ms; + } + + bool IsInserted(); + + void RegisterDetectionEventCallback(DeviceDetectionEventCallback cb, void *arg); + void UnregisterDetectionEventCallback(); + }; + +} + +#endif \ No newline at end of file diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.cpp index de45bb20c..9793878be 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.cpp @@ -24,6 +24,7 @@ namespace ams::sdmmc::impl { SdmmcControllerForPortSdCard0 g_sd_card0_host_controller; + } IHostController *GetHostControllerOfPortSdCard0() { diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.hpp index 72d4bb4b4..690dbb67c 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.hpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_port_sd_card0.hpp @@ -17,10 +17,12 @@ #include #include "sdmmc_i_host_controller.hpp" #include "sdmmc_i_device_accessor.hpp" +#include "sdmmc_sd_card_device_accessor.hpp" namespace ams::sdmmc::impl { IHostController *GetHostControllerOfPortSdCard0(); IDeviceAccessor *GetDeviceAccessorOfPortSdCard0(); + SdCardDeviceAccessor *GetSdCardDeviceAccessorOfPortSdCard0(); } diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.hpp new file mode 100644 index 000000000..f038a62d3 --- /dev/null +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_card_device_accessor.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "sdmmc_base_device_accessor.hpp" + +namespace ams::sdmmc::impl { + + /* TODO */ + struct SdCardDeviceAccessor; + +} diff --git a/stratosphere/boot2/source/boot2_main.cpp b/stratosphere/boot2/source/boot2_main.cpp index b7e7d4570..cd5e7effc 100644 --- a/stratosphere/boot2/source/boot2_main.cpp +++ b/stratosphere/boot2/source/boot2_main.cpp @@ -75,7 +75,7 @@ void __appInit(void) { R_ABORT_UNLESS(pminfoInitialize()); R_ABORT_UNLESS(pmshellInitialize()); R_ABORT_UNLESS(setsysInitialize()); - R_ABORT_UNLESS(gpioInitialize()); + R_ABORT_UNLESS(gpio::Initialize()); }); /* Mount the SD card. */ @@ -86,7 +86,7 @@ void __appInit(void) { void __appExit(void) { fs::Unmount("sdmc"); - gpioExit(); + gpio::Exit(); setsysExit(); pmshellExit(); pminfoExit(); diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 3b576347b..09e866241 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -92,7 +92,7 @@ void __appInit(void) { R_ABORT_UNLESS(psmInitialize()); R_ABORT_UNLESS(spsmInitialize()); R_ABORT_UNLESS(plInitialize(::PlServiceType_User)); - R_ABORT_UNLESS(gpioInitialize()); + gpio::Initialize(); R_ABORT_UNLESS(fsInitialize()); }); @@ -105,7 +105,7 @@ void __appExit(void) { /* Cleanup services. */ fsExit(); plExit(); - gpioExit(); + gpio::Finalize(); spsmExit(); psmExit(); lblExit(); diff --git a/stratosphere/fatal/source/fatal_repair.cpp b/stratosphere/fatal/source/fatal_repair.cpp index bc57fe698..77e3685d4 100644 --- a/stratosphere/fatal/source/fatal_repair.cpp +++ b/stratosphere/fatal/source/fatal_repair.cpp @@ -33,22 +33,21 @@ namespace ams::fatal::srv { bool IsInRepairWithoutVolHeld() { if (IsInRepair()) { - GpioPadSession vol_btn; - if (R_FAILED(gpioOpenSession(&vol_btn, GpioPadName_ButtonVolUp))) { + gpio::GpioPadSession vol_btn; + if (R_FAILED(gpio::OpenSession(std::addressof(vol_btn), gpio::DeviceCode_ButtonVolUp))) { return true; } /* Ensure we close even on early return. */ - ON_SCOPE_EXIT { gpioPadClose(&vol_btn); }; + ON_SCOPE_EXIT { gpio::CloseSession(std::addressof(vol_btn)); }; /* Set direction input. */ - gpioPadSetDirection(&vol_btn, GpioDirection_Input); + gpio::SetDirection(std::addressof(vol_btn), gpio::Direction_Input); /* Ensure that we're holding the volume button for a full second. */ auto start = os::GetSystemTick(); do { - GpioValue val; - if (R_FAILED(gpioPadGetValue(&vol_btn, &val)) || val != GpioValue_Low) { + if (gpio::GetValue(std::addressof(vol_btn)) != gpio::GpioValue_Low) { return true; } diff --git a/stratosphere/fatal/source/fatal_task_power.cpp b/stratosphere/fatal/source/fatal_task_power.cpp index 4d70a35d5..5f9acaefe 100644 --- a/stratosphere/fatal/source/fatal_task_power.cpp +++ b/stratosphere/fatal/source/fatal_task_power.cpp @@ -156,33 +156,33 @@ namespace ams::fatal::srv { RebootTimingObserver fatal_reboot_helper(config.IsFatalRebootEnabled(), config.GetFatalRebootTimeoutInterval()); bool check_vol_up = true, check_vol_down = true; - GpioPadSession vol_up_btn, vol_down_btn; - if (R_FAILED(gpioOpenSession(&vol_up_btn, GpioPadName_ButtonVolUp))) { + gpio::GpioPadSession vol_up_btn, vol_down_btn; + if (R_FAILED(gpio::OpenSession(std::addressof(vol_up_btn), gpio::DeviceCode_ButtonVolUp))) { check_vol_up = false; } - if (R_FAILED(gpioOpenSession(&vol_down_btn, GpioPadName_ButtonVolDown))) { + if (R_FAILED(gpio::OpenSession(std::addressof(vol_down_btn), gpio::DeviceCode_ButtonVolDn))) { check_vol_down = false; } /* Ensure we close on early return. */ - ON_SCOPE_EXIT { if (check_vol_up) { gpioPadClose(&vol_up_btn); } }; - ON_SCOPE_EXIT { if (check_vol_down) { gpioPadClose(&vol_down_btn); } }; + ON_SCOPE_EXIT { if (check_vol_up) { gpio::CloseSession(std::addressof(vol_up_btn)); } }; + ON_SCOPE_EXIT { if (check_vol_down) { gpio::CloseSession(std::addressof(vol_down_btn)); } }; /* Set direction input. */ if (check_vol_up) { - gpioPadSetDirection(&vol_up_btn, GpioDirection_Input); + gpio::SetDirection(std::addressof(vol_up_btn), gpio::Direction_Input); } if (check_vol_down) { - gpioPadSetDirection(&vol_down_btn, GpioDirection_Input); + gpio::SetDirection(std::addressof(vol_down_btn), gpio::Direction_Input); } BpcSleepButtonState state; - GpioValue val; while (true) { if (fatal_reboot_helper.IsRebootTiming() || (quest_reboot_helper.IsRebootTiming()) || - (check_vol_up && R_SUCCEEDED(gpioPadGetValue(&vol_up_btn, &val)) && val == GpioValue_Low) || - (check_vol_down && R_SUCCEEDED(gpioPadGetValue(&vol_down_btn, &val)) && val == GpioValue_Low) || - (R_SUCCEEDED(bpcGetSleepButtonState(&state)) && state == BpcSleepButtonState_Held)) { + (check_vol_up && gpio::GetValue(std::addressof(vol_up_btn)) == gpio::GpioValue_Low) || + (check_vol_down && gpio::GetValue(std::addressof(vol_down_btn)) == gpio::GpioValue_Low) || + (R_SUCCEEDED(bpcGetSleepButtonState(&state)) && state == BpcSleepButtonState_Held)) + { /* If any of the above conditions succeeded, we should reboot. */ bpcRebootSystem(); return; diff --git a/stratosphere/fatal/source/fatal_task_sound.cpp b/stratosphere/fatal/source/fatal_task_sound.cpp index cc235b7d5..ad5d6eb59 100644 --- a/stratosphere/fatal/source/fatal_task_sound.cpp +++ b/stratosphere/fatal/source/fatal_task_sound.cpp @@ -70,16 +70,16 @@ namespace ams::fatal::srv { /* Talk to the ALC5639 over GPIO, and disable audio output */ { - GpioPadSession audio; - if (R_SUCCEEDED(gpioOpenSession(&audio, GpioPadName_AudioCodec))) { - ON_SCOPE_EXIT { gpioPadClose(&audio); }; + gpio::GpioPadSession audio; + if (R_SUCCEEDED(gpio::OpenSession(std::addressof(audio), gpio::DeviceCode_CodecLdoEnTemp))) { + ON_SCOPE_EXIT { gpio::CloseSession(std::addressof(audio)); }; /* Set direction output, sleep 200 ms so it can take effect. */ - gpioPadSetDirection(&audio, GpioDirection_Output); - svcSleepThread(200000000UL); + gpio::SetDirection(std::addressof(audio), gpio::Direction_Output); + os::SleepThread(TimeSpan::FromMilliSeconds(200)); /* Pull audio codec low. */ - gpioPadSetValue(&audio, GpioValue_Low); + gpio::SetValue(std::addressof(audio), gpio::GpioValue_Low); } } }