From e3900de6c0c16967bf3251d096e2e42d00e0c848 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 27 Oct 2020 15:35:38 -0700 Subject: [PATCH] gpio: modernize client api instead of doing it the lazy way --- .../include/stratosphere/gpio.hpp | 2 + .../gpio/gpio_pad_name.board.nintendo_nx.hpp | 2 +- .../include/stratosphere/gpio/gpio_types.hpp | 10 +- .../gpio/sf/gpio_sf_i_manager.hpp | 41 +++++++ .../gpio/sf/gpio_sf_i_pad_session.hpp | 45 +++++++ .../source/gpio/gpio_client_api.cpp | 89 +++++++------- .../source/gpio/gpio_remote_manager_impl.hpp | 91 ++++++++++++++ .../gpio/gpio_remote_pad_session_impl.hpp | 113 ++++++++++++++++++ 8 files changed, 347 insertions(+), 46 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_manager.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp create mode 100644 libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp create mode 100644 libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp diff --git a/libraries/libstratosphere/include/stratosphere/gpio.hpp b/libraries/libstratosphere/include/stratosphere/gpio.hpp index 861f294b7..02175345f 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio.hpp @@ -16,5 +16,7 @@ #pragma once #include +#include +#include #include #include 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 index 8a201779e..c1c816c95 100644 --- 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 @@ -19,7 +19,7 @@ namespace ams::gpio { - enum GpioPadName { + enum GpioPadName : u32 { GpioPadName_CodecLdoEnTemp = 1, GpioPadName_ButtonVolUp = 25, GpioPadName_ButtonVolDn = 26, diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp index b2b9331ac..8d456c547 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_types.hpp @@ -18,7 +18,7 @@ namespace ams::gpio { - enum InterruptMode { + enum InterruptMode : u32 { InterruptMode_LowLevel = 0, InterruptMode_HighLevel = 1, InterruptMode_RisingEdge = 2, @@ -26,19 +26,21 @@ namespace ams::gpio { InterruptMode_AnyEdge = 4, }; - enum Direction { + enum Direction : u32 { Direction_Input = 0, Direction_Output = 1, }; - enum GpioValue { + enum GpioValue : u32 { GpioValue_Low = 0, GpioValue_High = 1, }; - enum InterruptStatus { + enum InterruptStatus : u32 { InterruptStatus_Inactive = 0, InterruptStatus_Active = 1, }; + using WakeBitFlag = util::BitFlagSet<128>; + } diff --git a/libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_manager.hpp b/libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_manager.hpp new file mode 100644 index 000000000..e54dc7b1b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_manager.hpp @@ -0,0 +1,41 @@ +/* + * 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 +#include + +namespace ams::gpio::sf { + + #define AMS_GPIO_I_MANAGER_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, OpenSessionForDev, (ams::sf::Out> out, s32 pad_descriptor) ) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, OpenSession, (ams::sf::Out> out, gpio::GpioPadName pad_name) ) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, OpenSessionForTest, (ams::sf::Out> out, gpio::GpioPadName pad_name) ) \ + AMS_SF_METHOD_INFO(C, H, 3, Result, IsWakeEventActive, (ams::sf::Out out, gpio::GpioPadName pad_name), hos::Version_Min, hos::Version_6_2_0) \ + AMS_SF_METHOD_INFO(C, H, 4, Result, GetWakeEventActiveFlagSet, (ams::sf::Out out), hos::Version_Min, hos::Version_6_2_0) \ + AMS_SF_METHOD_INFO(C, H, 5, Result, SetWakeEventActiveFlagSetForDebug, (gpio::GpioPadName pad_name, bool is_enabled), hos::Version_Min, hos::Version_6_2_0) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, SetWakePinDebugMode, (s32 mode) ) \ + AMS_SF_METHOD_INFO(C, H, 7, Result, OpenSession2, (ams::sf::Out> out, DeviceCode device_code, ddsf::AccessMode access_mode), hos::Version_5_0_0 ) \ + AMS_SF_METHOD_INFO(C, H, 8, Result, IsWakeEventActive2, (ams::sf::Out out, DeviceCode device_code), hos::Version_5_0_0 ) \ + AMS_SF_METHOD_INFO(C, H, 9, Result, SetWakeEventActiveFlagSetForDebug2, (DeviceCode device_code, bool is_enabled), hos::Version_5_0_0 ) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, SetRetryValues, (u32 arg0, u32 arg1), hos::Version_6_0_0 ) + + AMS_SF_DEFINE_INTERFACE(IManager, AMS_GPIO_I_MANAGER_INTERFACE_INFO) + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp b/libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp new file mode 100644 index 000000000..ec4791b1b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/sf/gpio_sf_i_pad_session.hpp @@ -0,0 +1,45 @@ +/* + * 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::sf { + + #define AMS_GPIO_I_PAD_SESSION_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, SetDirection, (gpio::Direction direction) ) \ + AMS_SF_METHOD_INFO(C, H, 1, Result, GetDirection, (ams::sf::Out out) ) \ + AMS_SF_METHOD_INFO(C, H, 2, Result, SetInterruptMode, (gpio::InterruptMode mode) ) \ + AMS_SF_METHOD_INFO(C, H, 3, Result, GetInterruptMode, (ams::sf::Out out) ) \ + AMS_SF_METHOD_INFO(C, H, 4, Result, SetInterruptEnable, (bool enable) ) \ + AMS_SF_METHOD_INFO(C, H, 5, Result, GetInterruptEnable, (ams::sf::Out out) ) \ + AMS_SF_METHOD_INFO(C, H, 6, Result, GetInterruptStatus, (ams::sf::Out out) ) \ + AMS_SF_METHOD_INFO(C, H, 7, Result, ClearInterruptStatus, () ) \ + AMS_SF_METHOD_INFO(C, H, 8, Result, SetValue, (gpio::GpioValue value) ) \ + AMS_SF_METHOD_INFO(C, H, 9, Result, GetValue, (ams::sf::Out out) ) \ + AMS_SF_METHOD_INFO(C, H, 10, Result, BindInterrupt, (ams::sf::OutCopyHandle out) ) \ + AMS_SF_METHOD_INFO(C, H, 11, Result, UnbindInterrupt, () ) \ + AMS_SF_METHOD_INFO(C, H, 12, Result, SetDebounceEnabled, (bool enable) ) \ + AMS_SF_METHOD_INFO(C, H, 13, Result, GetDebounceEnabled, (ams::sf::Out out) ) \ + AMS_SF_METHOD_INFO(C, H, 14, Result, SetDebounceTime, (s32 ms) ) \ + AMS_SF_METHOD_INFO(C, H, 15, Result, GetDebounceTime, (ams::sf::Out out) ) \ + AMS_SF_METHOD_INFO(C, H, 16, Result, SetValueForSleepState, (gpio::GpioValue value), hos::Version_4_0_0) \ + AMS_SF_METHOD_INFO(C, H, 16, Result, GetValueForSleepState, (ams::sf::Out out), hos::Version_6_0_0) + + AMS_SF_DEFINE_INTERFACE(IPadSession, AMS_GPIO_I_PAD_SESSION_INTERFACE_INFO) + +} diff --git a/libraries/libstratosphere/source/gpio/gpio_client_api.cpp b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp index 17e0e6f36..c5d88023b 100644 --- a/libraries/libstratosphere/source/gpio/gpio_client_api.cpp +++ b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp @@ -14,22 +14,22 @@ * along with this program. If not, see . */ #include +#include "gpio_remote_manager_impl.hpp" 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; + std::shared_ptr g_manager; - using InternalSession = ::GpioPadSession; + using InternalSession = std::shared_ptr; - InternalSession *GetInterface(GpioPadSession *session) { + InternalSession &GetInterface(GpioPadSession *session) { AMS_ASSERT(session->_session != nullptr); - return static_cast<::GpioPadSession *>(session->_session); + return *static_cast(session->_session); } } @@ -39,6 +39,7 @@ namespace ams::gpio { if ((g_initialize_count++) == 0) { R_ABORT_UNLESS(::gpioInitialize()); + g_manager = ams::sf::MakeShared(); } } @@ -48,21 +49,26 @@ namespace ams::gpio { AMS_ASSERT(g_initialize_count > 0); if ((--g_initialize_count) == 0) { + g_manager.reset(); ::gpioExit(); } } Result OpenSession(GpioPadSession *out_session, ams::DeviceCode device_code) { /* Allocate the session. */ - InternalSession *internal_session = static_cast(std::malloc(sizeof(InternalSession))); + InternalSession *internal_session = new (std::nothrow) InternalSession; AMS_ABORT_UNLESS(internal_session != nullptr); - auto session_guard = SCOPE_GUARD { std::free(internal_session); }; + auto session_guard = SCOPE_GUARD { delete 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))))); + { + ams::sf::cmif::ServiceObjectHolder object_holder; + if (hos::GetVersion() >= hos::Version_7_0_0) { + R_TRY(g_manager->OpenSession2(std::addressof(object_holder), device_code, ddsf::AccessMode_ReadWrite)); + } else { + R_TRY(g_manager->OpenSession(std::addressof(object_holder), ConvertToGpioPadName(device_code))); + } + *internal_session = object_holder.GetServiceObject(); } /* Set output. */ @@ -83,96 +89,97 @@ namespace ams::gpio { } /* Close the session. */ - ::gpioPadClose(GetInterface(session)); - std::free(session->_session); + delete std::addressof(GetInterface(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())); + R_TRY(g_manager->IsWakeEventActive2(out_is_active, device_code)); } else { - R_ABORT_UNLESS(::gpioIsWakeEventActive(out_is_active, static_cast<::GpioPadName>(static_cast(ConvertToGpioPadName(device_code))))); + R_TRY(g_manager->IsWakeEventActive(out_is_active, 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)); + Direction out; + R_ABORT_UNLESS(GetInterface(session)->GetDirection(std::addressof(out))); + return out; } void SetDirection(GpioPadSession *session, Direction direction) { - R_ABORT_UNLESS(::gpioPadSetDirection(GetInterface(session), static_cast<::GpioDirection>(static_cast(direction)))); + R_ABORT_UNLESS(GetInterface(session)->SetDirection(direction)); } GpioValue GetValue(GpioPadSession *session) { - ::GpioValue out; - R_ABORT_UNLESS(::gpioPadGetValue(GetInterface(session), std::addressof(out))); - return static_cast(static_cast(out)); + GpioValue out; + R_ABORT_UNLESS(GetInterface(session)->GetValue(std::addressof(out))); + return out; } void SetValue(GpioPadSession *session, GpioValue value) { - R_ABORT_UNLESS(::gpioPadSetValue(GetInterface(session), static_cast<::GpioValue>(static_cast(value)))); + R_ABORT_UNLESS(GetInterface(session)->SetValue(value)); } InterruptMode GetInterruptMode(GpioPadSession *session) { - ::GpioInterruptMode out; - R_ABORT_UNLESS(::gpioPadGetInterruptMode(GetInterface(session), std::addressof(out))); - return static_cast(static_cast(out)); + InterruptMode out; + R_ABORT_UNLESS(GetInterface(session)->GetInterruptMode(std::addressof(out))); + return out; } void SetInterruptMode(GpioPadSession *session, InterruptMode mode) { - R_ABORT_UNLESS(::gpioPadSetInterruptMode(GetInterface(session), static_cast<::GpioInterruptMode>(static_cast(mode)))); + R_ABORT_UNLESS(GetInterface(session)->SetInterruptMode(mode)); } bool GetInterruptEnable(GpioPadSession *session) { bool out; - R_ABORT_UNLESS(::gpioPadGetInterruptEnable(GetInterface(session), std::addressof(out))); + R_ABORT_UNLESS(GetInterface(session)->GetInterruptEnable(std::addressof(out))); return out; } void SetInterruptEnable(GpioPadSession *session, bool en) { - R_ABORT_UNLESS(::gpioPadSetInterruptEnable(GetInterface(session), en)); + R_ABORT_UNLESS(GetInterface(session)->SetInterruptEnable(en)); } InterruptStatus GetInterruptStatus(GpioPadSession *session) { - ::GpioInterruptStatus out; - R_ABORT_UNLESS(::gpioPadGetInterruptStatus(GetInterface(session), std::addressof(out))); - return static_cast(static_cast(out)); + InterruptStatus out; + R_ABORT_UNLESS(GetInterface(session)->GetInterruptStatus(std::addressof(out))); + return out; } void ClearInterruptStatus(GpioPadSession *session) { - R_ABORT_UNLESS(::gpioPadClearInterruptStatus(GetInterface(session))); + R_ABORT_UNLESS(GetInterface(session)->ClearInterruptStatus()); } int GetDebounceTime(GpioPadSession *session) { int out; - R_ABORT_UNLESS(::gpioPadGetDebounceTime(GetInterface(session), std::addressof(out))); + R_ABORT_UNLESS(GetInterface(session)->GetDebounceTime(std::addressof(out))); return out; } void SetDebounceTime(GpioPadSession *session, int ms) { - R_ABORT_UNLESS(::gpioPadSetDebounceTime(GetInterface(session), ms)); + R_ABORT_UNLESS(GetInterface(session)->SetDebounceTime(ms)); } bool GetDebounceEnabled(GpioPadSession *session) { bool out; - R_ABORT_UNLESS(::gpioPadGetDebounceEnabled(GetInterface(session), std::addressof(out))); + R_ABORT_UNLESS(GetInterface(session)->GetDebounceEnabled(std::addressof(out))); return out; } void SetDebounceEnabled(GpioPadSession *session, bool en) { - R_ABORT_UNLESS(::gpioPadSetDebounceEnabled(GetInterface(session), en)); + R_ABORT_UNLESS(GetInterface(session)->SetDebounceEnabled(en)); } Result BindInterrupt(os::SystemEventType *event, GpioPadSession *session) { - ::Event ev; - R_TRY(::gpioPadBindInterrupt(GetInterface(session), std::addressof(ev))); + AMS_ASSERT(session->_event == nullptr); - os::AttachReadableHandleToSystemEvent(event, ev.revent, true, os::EventClearMode_ManualClear); + ams::sf::CopyHandle handle; + R_TRY(GetInterface(session)->BindInterrupt(std::addressof(handle))); + + os::AttachReadableHandleToSystemEvent(event, handle.GetValue(), true, os::EventClearMode_ManualClear); session->_event = event; return ResultSuccess(); @@ -181,7 +188,7 @@ namespace ams::gpio { void UnbindInterrupt(GpioPadSession *session) { AMS_ASSERT(session->_event != nullptr); - R_ABORT_UNLESS(::gpioPadUnbindInterrupt(GetInterface(session))); + R_ABORT_UNLESS(GetInterface(session)->UnbindInterrupt()); os::DestroySystemEvent(session->_event); session->_event = nullptr; diff --git a/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp b/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp new file mode 100644 index 000000000..bb439b79f --- /dev/null +++ b/libraries/libstratosphere/source/gpio/gpio_remote_manager_impl.hpp @@ -0,0 +1,91 @@ +/* + * 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 "gpio_remote_pad_session_impl.hpp" + +namespace ams::gpio { + + class RemoteManagerImpl { + public: + RemoteManagerImpl() { /* ... */ } + + ~RemoteManagerImpl() { /* ... */ } + public: + /* Actual commands. */ + Result OpenSessionForDev(ams::sf::Out> out, s32 pad_descriptor) { + /* TODO: libnx bindings */ + AMS_ABORT(); + } + + Result OpenSession(ams::sf::Out> out, gpio::GpioPadName pad_name) { + ::GpioPadSession p; + R_TRY(::gpioOpenSession(std::addressof(p), static_cast<::GpioPadName>(static_cast(pad_name)))); + + out.SetValue(ams::sf::MakeShared(p)); + return ResultSuccess(); + } + + Result OpenSessionForTest(ams::sf::Out> out, gpio::GpioPadName pad_name) { + /* TODO: libnx bindings */ + AMS_ABORT(); + } + + Result IsWakeEventActive(ams::sf::Out out, gpio::GpioPadName pad_name) { + return ::gpioIsWakeEventActive2(out.GetPointer(), static_cast<::GpioPadName>(static_cast(pad_name))); + } + + Result GetWakeEventActiveFlagSet(ams::sf::Out out) { + /* TODO: libnx bindings */ + AMS_ABORT(); + } + + Result SetWakeEventActiveFlagSetForDebug(gpio::GpioPadName pad_name, bool is_enabled) { + /* TODO: libnx bindings */ + AMS_ABORT(); + } + + Result SetWakePinDebugMode(s32 mode) { + /* TODO: libnx bindings */ + AMS_ABORT(); + } + + Result OpenSession2(ams::sf::Out> out, DeviceCode device_code, ddsf::AccessMode access_mode) { + ::GpioPadSession p; + R_TRY(::gpioOpenSession2(std::addressof(p), device_code.GetInternalValue(), access_mode)); + + out.SetValue(ams::sf::MakeShared(p)); + return ResultSuccess(); + } + + Result IsWakeEventActive2(ams::sf::Out out, DeviceCode device_code) { + return ::gpioIsWakeEventActive2(out.GetPointer(), device_code.GetInternalValue()); + } + + Result SetWakeEventActiveFlagSetForDebug2(DeviceCode device_code, bool is_enabled) { + /* TODO: libnx bindings */ + AMS_ABORT(); + } + + Result SetRetryValues(u32 arg0, u32 arg1) { + /* TODO: libnx bindings */ + AMS_ABORT(); + } + + }; + static_assert(gpio::sf::IsIManager); + +} diff --git a/libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp b/libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp new file mode 100644 index 000000000..297132f08 --- /dev/null +++ b/libraries/libstratosphere/source/gpio/gpio_remote_pad_session_impl.hpp @@ -0,0 +1,113 @@ +/* + * 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 { + + class RemotePadSessionImpl { + private: + ::GpioPadSession srv; + public: + RemotePadSessionImpl(::GpioPadSession &p) : srv(p) { /* ... */ } + + ~RemotePadSessionImpl() { ::gpioPadClose(std::addressof(this->srv)); } + public: + /* Actual commands. */ + Result SetDirection(gpio::Direction direction) { + return ::gpioPadSetDirection(std::addressof(this->srv), static_cast<::GpioDirection>(static_cast(direction))); + } + + Result GetDirection(ams::sf::Out out) { + static_assert(sizeof(gpio::Direction) == sizeof(::GpioDirection)); + return ::gpioPadGetDirection(std::addressof(this->srv), reinterpret_cast<::GpioDirection *>(out.GetPointer())); + } + + Result SetInterruptMode(gpio::InterruptMode mode) { + return ::gpioPadSetInterruptMode(std::addressof(this->srv), static_cast<::GpioInterruptMode>(static_cast(mode))); + } + + Result GetInterruptMode(ams::sf::Out out) { + static_assert(sizeof(gpio::InterruptMode) == sizeof(::GpioInterruptMode)); + return ::gpioPadGetInterruptMode(std::addressof(this->srv), reinterpret_cast<::GpioInterruptMode *>(out.GetPointer())); + } + + Result SetInterruptEnable(bool enable) { + return ::gpioPadSetInterruptEnable(std::addressof(this->srv), enable); + } + + Result GetInterruptEnable(ams::sf::Out out) { + return ::gpioPadGetInterruptEnable(std::addressof(this->srv), out.GetPointer()); + } + + Result GetInterruptStatus(ams::sf::Out out) { + static_assert(sizeof(gpio::InterruptStatus) == sizeof(::GpioInterruptStatus)); + return ::gpioPadGetInterruptStatus(std::addressof(this->srv), reinterpret_cast<::GpioInterruptStatus *>(out.GetPointer())); + } + + Result ClearInterruptStatus() { + return ::gpioPadClearInterruptStatus(std::addressof(this->srv)); + } + + Result SetValue(gpio::GpioValue value) { + return ::gpioPadSetValue(std::addressof(this->srv), static_cast<::GpioValue>(static_cast(value))); + } + + Result GetValue(ams::sf::Out out) { + static_assert(sizeof(gpio::GpioValue) == sizeof(::GpioValue)); + return ::gpioPadGetValue(std::addressof(this->srv), reinterpret_cast<::GpioValue *>(out.GetPointer())); + } + + Result BindInterrupt(ams::sf::OutCopyHandle out) { + ::Event ev; + R_TRY(::gpioPadBindInterrupt(std::addressof(this->srv), std::addressof(ev))); + out.SetValue(ev.revent); + return ResultSuccess(); + } + + Result UnbindInterrupt() { + return ::gpioPadUnbindInterrupt(std::addressof(this->srv)); + } + + Result SetDebounceEnabled(bool enable) { + return ::gpioPadSetDebounceEnabled(std::addressof(this->srv), enable); + } + + Result GetDebounceEnabled(ams::sf::Out out) { + return ::gpioPadGetDebounceEnabled(std::addressof(this->srv), out.GetPointer()); + } + + Result SetDebounceTime(s32 ms) { + return ::gpioPadSetDebounceTime(std::addressof(this->srv), ms); + } + + Result GetDebounceTime(ams::sf::Out out) { + return ::gpioPadGetDebounceTime(std::addressof(this->srv), out.GetPointer()); + } + + Result SetValueForSleepState(gpio::GpioValue value) { + /* TODO: libnx bindings. */ + AMS_ABORT(); + } + + Result GetValueForSleepState(ams::sf::Out out) { + /* TODO: libnx bindings. */ + AMS_ABORT(); + } + }; + static_assert(gpio::sf::IsIPadSession); + +}