diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp index adec2cc5e..16f467e55 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_castable.hpp @@ -59,7 +59,7 @@ namespace ams::ddsf { template constexpr const T &SafeCastTo() const { this->AssertCastableTo(); - return static_cast(*this); + return static_cast(*this); } template @@ -71,7 +71,7 @@ namespace ams::ddsf { template constexpr const T *SafeCastToPointer() const { this->AssertCastableTo(); - return static_cast(this); + return static_cast(this); } #if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING) diff --git a/libraries/libstratosphere/include/stratosphere/gpio.hpp b/libraries/libstratosphere/include/stratosphere/gpio.hpp index e82c2336c..c5562ee42 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio.hpp @@ -21,3 +21,6 @@ #include #include #include +#include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad.hpp b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad.hpp index b724ec039..42258a2f1 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad.hpp @@ -23,7 +23,7 @@ namespace ams::gpio::driver { class Pad : public ::ams::ddsf::IDevice { NON_COPYABLE(Pad); NON_MOVEABLE(Pad); - AMS_DDSF_CASTABLE_TRAITS(ams::gpio::Pad, ::ams::ddsf::IDevice); + AMS_DDSF_CASTABLE_TRAITS(ams::gpio::driver::Pad, ::ams::ddsf::IDevice); private: int pad_number; bool is_interrupt_enabled; diff --git a/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad_accessor.hpp b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad_accessor.hpp new file mode 100644 index 000000000..5b84a26a7 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/driver/gpio_pad_accessor.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::driver { + + namespace impl { + + constexpr inline size_t GpioPadSessionSize = 0x60; + constexpr inline size_t GpioPadSessionAlign = 8; + struct alignas(GpioPadSessionAlign) GpioPadSessionImplPadded; + + } + + struct GpioPadSession { + util::TypedStorage _impl; + }; + + Result OpenSession(GpioPadSession *out, DeviceCode device_code); + void CloseSession(GpioPadSession *session); + + Result SetDirection(GpioPadSession *session, gpio::Direction direction); + Result GetDirection(gpio::Direction *out, GpioPadSession *session); + + Result SetValue(GpioPadSession *session, gpio::GpioValue value); + Result GetValue(gpio::GpioValue *out, GpioPadSession *session); + + /* TODO */ + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_event_holder.hpp b/libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_event_holder.hpp new file mode 100644 index 000000000..6284bdca0 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_event_holder.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::gpio::driver::impl { + + class EventHolder { + NON_COPYABLE(EventHolder); + NON_MOVEABLE(EventHolder); + private: + os::SystemEventType *event; + public: + constexpr EventHolder() : event(nullptr) { /* ... */ } + + void AttachEvent(os::SystemEventType *event) { + this->event = event; + } + + os::SystemEventType *DetachEvent() { + auto ev = this->event; + this->event = nullptr; + return ev; + } + + os::SystemEventType *GetSystemEvent() { + return this->event; + } + + bool IsBound() const { + return this->event != nullptr; + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_pad_session_impl.hpp b/libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_pad_session_impl.hpp new file mode 100644 index 000000000..6f37c8213 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/driver/impl/gpio_pad_session_impl.hpp @@ -0,0 +1,90 @@ +/* + * 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::driver { + + class Pad; + +} + +namespace ams::gpio::driver::impl { + + class PadSessionImpl : public ::ams::ddsf::ISession { + NON_COPYABLE(PadSessionImpl); + NON_MOVEABLE(PadSessionImpl); + AMS_DDSF_CASTABLE_TRAITS(ams::gpio::driver::impl::PadSessionImpl, ::ams::ddsf::ISession); + private: + EventHolder event_holder; + private: + Result UpdateDriverInterruptEnabled(); + public: + PadSessionImpl() : event_holder() { /* ... */ } + + ~PadSessionImpl() { + this->Close(); + } + + bool IsInterruptBound() const { + return this->event_holder.IsBound(); + } + + Result Open(Pad *pad, ddsf::AccessMode access_mode); + void Close(); + + Result BindInterrupt(os::SystemEventType *event); + void UnbindInterrupt(); + + Result GetInterruptEnabled(bool *out) const; + Result SetInterruptEnabled(bool en); + void SignalInterruptBoundEvent(); + }; + static_assert( sizeof(PadSessionImpl) <= GpioPadSessionSize); + static_assert(alignof(PadSessionImpl) <= GpioPadSessionAlign); + + struct alignas(GpioPadSessionAlign) GpioPadSessionImplPadded { + PadSessionImpl _impl; + u8 _padding[GpioPadSessionSize - sizeof(PadSessionImpl)]; + }; + static_assert( sizeof(GpioPadSessionImplPadded) == GpioPadSessionSize); + static_assert(alignof(GpioPadSessionImplPadded) == GpioPadSessionAlign); + + ALWAYS_INLINE PadSessionImpl &GetPadSessionImpl(GpioPadSession &session) { + return GetReference(session._impl)._impl; + } + + ALWAYS_INLINE const PadSessionImpl &GetPadSessionImpl(const GpioPadSession &session) { + return GetReference(session._impl)._impl; + } + + ALWAYS_INLINE PadSessionImpl &GetOpenPadSessionImpl(GpioPadSession &session) { + auto &ref = GetReference(session._impl)._impl; + AMS_ASSERT(ref.IsOpen()); + return ref; + } + + ALWAYS_INLINE const PadSessionImpl &GetOpenPadSessionImpl(const GpioPadSession &session) { + const auto &ref = GetReference(session._impl)._impl; + AMS_ASSERT(ref.IsOpen()); + return ref; + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp b/libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp index a58c8b21c..a88cd2edf 100644 --- a/libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/gpio/gpio_api.hpp @@ -16,10 +16,13 @@ #pragma once #include #include +#include namespace ams::gpio { void Initialize(); void Finalize(); + void InitializeWith(std::shared_ptr &&sp); + } diff --git a/libraries/libstratosphere/include/stratosphere/gpio/server/gpio_server_api.hpp b/libraries/libstratosphere/include/stratosphere/gpio/server/gpio_server_api.hpp new file mode 100644 index 000000000..07f20c6c0 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/server/gpio_server_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 +#include + +namespace ams::gpio::server { + + std::shared_ptr GetServiceObject(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/gpio/server/gpio_server_manager_impl.hpp b/libraries/libstratosphere/include/stratosphere/gpio/server/gpio_server_manager_impl.hpp new file mode 100644 index 000000000..54a3cc273 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/gpio/server/gpio_server_manager_impl.hpp @@ -0,0 +1,96 @@ +/* + * 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::server { + + class ManagerImpl { + private: + ams::sf::ExpHeapMemoryResource pad_session_memory_resource; + typename ams::sf::ServiceObjectAllocator + public: + ManagerImpl(); + + ~ManagerImpl(); + 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/include/stratosphere/sf/sf_lmem_utility.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_lmem_utility.hpp index cb06140a6..31688555a 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_lmem_utility.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_lmem_utility.hpp @@ -24,7 +24,13 @@ namespace ams::sf { private: lmem::HeapHandle handle; public: - explicit ExpHeapMemoryResource(lmem::HeapHandle h) : handle(h) { /* ... */ } + constexpr ExpHeapMemoryResource() : handle() { /* ... */ } + constexpr explicit ExpHeapMemoryResource(lmem::HeapHandle h) : handle(h) { /* ... */ } + + void Attach(lmem::HeapHandle h) { + AMS_ABORT_UNLESS(this->handle == lmem::HeapHandle()); + this->handle = h; + } lmem::HeapHandle GetHandle() const { return this->handle; } private: @@ -45,7 +51,13 @@ namespace ams::sf { private: lmem::HeapHandle handle; public: - explicit UnitHeapMemoryResource(lmem::HeapHandle h) : handle(h) { /* ... */ } + constexpr UnitHeapMemoryResource() : handle() { /* ... */ } + constexpr explicit UnitHeapMemoryResource(lmem::HeapHandle h) : handle(h) { /* ... */ } + + void Attach(lmem::HeapHandle h) { + AMS_ABORT_UNLESS(this->handle == lmem::HeapHandle()); + this->handle = h; + } lmem::HeapHandle GetHandle() const { return this->handle; } private: diff --git a/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp b/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp index bee400c81..4a587066b 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/sf_service_object.hpp @@ -62,6 +62,40 @@ namespace ams::sf { return std::make_shared>(std::make_shared(std::forward(args)...)); } + template + class ServiceObjectAllocator { + public: + using value_type = typename Interface::ImplHolder; + private: + MemoryResource * const memory_resource; + public: + constexpr ServiceObjectAllocator(MemoryResource *mr) : memory_resource(mr) { /* ... */ } + + value_type *allocate(size_t n) const { + void *mem = this->memory_resource->Allocate(n * sizeof(value_type), alignof(value_type)); + AMS_ABORT_UNLESS(mem != nullptr); + return mem; + } + + void deallocate(void *p, size_t n) const { + this->memory_resource->Deallocate(p, n * sizeof(value_type), alignof(value_type)); + } + + inline bool operator==(const ServiceObjectAllocator &rhs) const { + return this->memory_resource->is_equal(*rhs->memory_resource); + } + + inline bool operator!=(const ServiceObjectAllocator &rhs) const { + return !(*this == rhs); + } + }; + + template + requires std::constructible_from + constexpr ALWAYS_INLINE std::shared_ptr> AllocateShared(const Allocator &allocator, Arguments &&... args) { + return std::allocate_shared>(allocator, std::forward(args)...); + } + template constexpr ALWAYS_INLINE std::shared_ptr> GetSharedPointerTo(Impl *impl) { return std::make_shared>(impl); @@ -72,4 +106,4 @@ namespace ams::sf { return GetSharedPointerTo(std::addressof(impl)); } -} \ No newline at end of file +} diff --git a/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.cpp b/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.cpp index bd9150d49..aa152fb7b 100644 --- a/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.cpp +++ b/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.cpp @@ -19,6 +19,71 @@ namespace ams::gpio::driver::board::nintendo_nx::impl { + void InterruptEventHandler::Initialize(DriverImpl *drv, os::InterruptName intr, int ctlr) { + /* Set fields. */ + this->driver = drv; + this->interrupt_name = intr; + this->controller_number = ctlr; + + /* Initialize interrupt event. */ + os::InitializeInterruptEvent(std::addressof(this->interrupt_event), intr, os::EventClearMode_ManualClear); + + /* Initialize base. */ + IEventHandler::Initialize(std::addressof(this->interrupt_event)); + } + + void InterruptEventHandler::HandleEvent() { + /* Lock the driver's interrupt mutex. */ + std::scoped_lock lk(this->driver->interrupt_control_mutex); + + /* Check each pad. */ + bool found = false; + for (auto it = this->driver->interrupt_pad_list.begin(); !found && it != this->driver->interrupt_pad_list.end(); ++it) { + found = this->CheckAndHandleInterrupt(*it); + } + + /* If we didn't find a pad, clear the interrupt event. */ + if (!found) { + os::ClearInterruptEvent(std::addressof(this->interrupt_event)); + } + } + + bool InterruptEventHandler::CheckAndHandleInterrupt(TegraPad &pad) { + /* Get the pad's number. */ + const InternalGpioPadNumber pad_number = static_cast(pad.GetPadNumber()); + + /* Check if the pad matches our controller number. */ + if (this->controller_number != ConvertInternalGpioPadNumberToController(pad_number)) { + return false; + } + + /* Get the addresses of INT_STA, INT_ENB. */ + const uintptr_t sta_address = GetGpioRegisterAddress(this->driver->gpio_virtual_address, GpioRegisterType_GPIO_INT_STA, pad_number); + const uintptr_t enb_address = GetGpioRegisterAddress(this->driver->gpio_virtual_address, GpioRegisterType_GPIO_INT_STA, pad_number); + const uintptr_t pad_index = ConvertInternalGpioPadNumberToBitIndex(pad_number); + + /* Check if both STA and ENB are set. */ + if (reg::Read(sta_address, 1u << pad_index) == 0 || reg::Read(enb_address, 1u << pad_index) == 0) { + return false; + } + + /* The pad is signaled. First, clear the enb bit. */ + SetMaskedBit(enb_address, pad_index, 0); + reg::Read(enb_address); + + /* Disable the interrupt on the pad. */ + pad.SetInterruptEnabled(false); + this->driver->RemoveInterruptPad(std::addressof(pad)); + + /* Clear the interrupt event. */ + os::ClearInterruptEvent(std::addressof(this->interrupt_event)); + + /* Signal the pad's bound event. */ + pad.SignalInterruptBoundEvent(); + + return true; + } + DriverImpl::DriverImpl(dd::PhysicalAddress reg_paddr, size_t size) : gpio_physical_address(reg_paddr), gpio_virtual_address(), suspend_handler(this), interrupt_pad_list(), interrupt_control_mutex() { /* Get the corresponding virtual address for our physical address. */ this->gpio_virtual_address = dd::QueryIoMapping(reg_paddr, size); diff --git a/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.hpp b/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.hpp index cd1add92f..b78f341da 100644 --- a/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.hpp +++ b/libraries/libstratosphere/source/gpio/driver/board/nintendo_nx/impl/gpio_driver_impl.hpp @@ -29,13 +29,13 @@ namespace ams::gpio::driver::board::nintendo_nx::impl { DriverImpl *driver; os::InterruptName interrupt_name; os::InterruptEventType interrupt_event; - int port_number; + int controller_number; private: - void CheckAndHandleInterrupt(TegraPad *pad); + bool CheckAndHandleInterrupt(TegraPad &pad); public: - InterruptEventHandler() : IEventHandler(), driver(nullptr), interrupt_name(), interrupt_event(), port_number() { /* ... */ } + InterruptEventHandler() : IEventHandler(), driver(nullptr), interrupt_name(), interrupt_event(), controller_number() { /* ... */ } - void Initialize(DriverImpl *driver, os::InterruptName intr, int port); + void Initialize(DriverImpl *drv, os::InterruptName intr, int ctlr); virtual void HandleEvent() override; }; @@ -44,11 +44,12 @@ namespace ams::gpio::driver::board::nintendo_nx::impl { NON_COPYABLE(DriverImpl); NON_MOVEABLE(DriverImpl); AMS_DDSF_CASTABLE_TRAITS(ams::gpio::driver::board::nintendo_nx::impl::DriverImpl, ::ams::gpio::driver::IGpioDriver); + friend class InterruptEventHandler; private: dd::PhysicalAddress gpio_physical_address; uintptr_t gpio_virtual_address; SuspendHandler suspend_handler; - TegraPad::List interrupt_pad_list; + TegraPad::InterruptList interrupt_pad_list; mutable os::SdkMutex interrupt_control_mutex; public: DriverImpl(dd::PhysicalAddress reg_paddr, size_t size); @@ -96,6 +97,33 @@ namespace ams::gpio::driver::board::nintendo_nx::impl { virtual Result SuspendLow() override; virtual Result Resume() override; virtual Result ResumeLow() override; + private: + static constexpr ALWAYS_INLINE TegraPad &GetTegraPad(Pad *pad) { + AMS_ASSERT(pad != nullptr); + return static_cast(*pad); + } + + static ALWAYS_INLINE const PadInfo &GetInfo(Pad *pad) { + return GetTegraPad(pad).GetInfo(); + } + + static ALWAYS_INLINE PadStatus &GetStatus(Pad *pad) { + return GetTegraPad(pad).GetStatus(); + } + + void AddInterruptPad(TegraPad *pad) { + AMS_ASSERT(pad != nullptr); + if (!pad->IsLinkedToInterruptBoundPadList()) { + this->interrupt_pad_list.push_back(*pad); + } + } + + void RemoveInterruptPad(TegraPad *pad) { + AMS_ASSERT(pad != nullptr); + if (pad->IsLinkedToInterruptBoundPadList()) { + this->interrupt_pad_list.erase(this->interrupt_pad_list.iterator_to(*pad)); + } + } }; } diff --git a/libraries/libstratosphere/source/gpio/driver/gpio_pad.cpp b/libraries/libstratosphere/source/gpio/driver/gpio_pad.cpp new file mode 100644 index 000000000..3899e01e9 --- /dev/null +++ b/libraries/libstratosphere/source/gpio/driver/gpio_pad.cpp @@ -0,0 +1,48 @@ +/* + * 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 + +#include "impl/gpio_driver_core.hpp" + +namespace ams::gpio::driver { + + bool Pad::IsAnySessionBoundToInterrupt() const { + /* Check to see if any session has an interrupt bound. */ + bool bound = false; + this->ForEachSession([&](const ddsf::ISession &session) -> bool { + const auto &impl = session.SafeCastTo(); + if (impl.IsInterruptBound()) { + bound = true; + return false; + } + return true; + }); + + return bound; + } + + void Pad::SignalInterruptBoundEvent() { + /* Signal relevant sessions. */ + this->ForEachSession([&](ddsf::ISession &session) -> bool { + auto &impl = session.SafeCastTo(); + if (impl.IsInterruptBound()) { + impl.SignalInterruptBoundEvent(); + } + return true; + }); + } + +} diff --git a/libraries/libstratosphere/source/gpio/driver/impl/gpio_pad_session_impl.cpp b/libraries/libstratosphere/source/gpio/driver/impl/gpio_pad_session_impl.cpp new file mode 100644 index 000000000..9e8f7c805 --- /dev/null +++ b/libraries/libstratosphere/source/gpio/driver/impl/gpio_pad_session_impl.cpp @@ -0,0 +1,150 @@ +/* + * 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::driver::impl { + + Result PadSessionImpl::Open(Pad *pad, ddsf::AccessMode access_mode) { + /* Check if the pad has any open sessions. */ + const bool first_session = !pad->HasAnyOpenSession(); + + /* Open the session. */ + R_TRY(ddsf::OpenSession(pad, this, access_mode)); + auto pad_guard = SCOPE_GUARD { ddsf::CloseSession(this); }; + + /* If we're the first, we want to initialize the pad. */ + if (first_session) { + R_TRY(pad->GetDriver().SafeCastTo().InitializePad(pad)); + } + + /* We opened successfully. */ + pad_guard.Cancel(); + return ResultSuccess(); + } + + void PadSessionImpl::Close() { + /* If the session isn't open, nothing to do. */ + if (!this->IsOpen()) { + return; + } + + /* Unbind the interrupt, if it's bound. */ + if (this->IsInterruptBound()) { + this->UnbindInterrupt(); + } + + /* Get the pad we're a session for. */ + auto &pad = this->GetDevice().SafeCastTo(); + + /* Close the session. */ + ddsf::CloseSession(this); + + /* If we were the last session on the pad, finalize the pad. */ + if (!pad.HasAnyOpenSession()) { + pad.GetDriver().SafeCastTo().FinalizePad(std::addressof(pad)); + } + } + + Result PadSessionImpl::BindInterrupt(os::SystemEventType *event) { + /* Acquire exclusive access to the relevant interrupt control mutex. */ + auto &pad = this->GetDevice().SafeCastTo(); + auto &mutex = pad.GetDriver().SafeCastTo().GetInterruptControlMutex(pad); + std::scoped_lock lk(mutex); + + /* Check that we're not already bound. */ + R_UNLESS(!this->IsInterruptBound(), gpio::ResultAlreadyBound()); + R_UNLESS(!this->GetDevice().SafeCastTo().IsAnySessionBoundToInterrupt(), gpio::ResultAlreadyBound()); + + /* Create the system event. */ + R_TRY(os::CreateSystemEvent(event, os::EventClearMode_ManualClear, true)); + auto ev_guard = SCOPE_GUARD { os::DestroySystemEvent(event); }; + + /* Attach the event to our holder. */ + this->event_holder.AttachEvent(event); + auto hl_guard = SCOPE_GUARD { this->event_holder.DetachEvent(); }; + + /* Update interrupt needed. */ + R_TRY(this->UpdateDriverInterruptEnabled()); + + /* We succeeded. */ + hl_guard.Cancel(); + ev_guard.Cancel(); + return ResultSuccess(); + } + + void PadSessionImpl::UnbindInterrupt() { + /* Acquire exclusive access to the relevant interrupt control mutex. */ + auto &pad = this->GetDevice().SafeCastTo(); + auto &mutex = pad.GetDriver().SafeCastTo().GetInterruptControlMutex(pad); + std::scoped_lock lk(mutex); + + /* If we're not bound, nothing to do. */ + if (!this->IsInterruptBound()) { + return; + } + + /* Detach and destroy the event */ + os::DestroySystemEvent(this->event_holder.DetachEvent()); + + /* Update interrupt needed. */ + R_ABORT_UNLESS(this->UpdateDriverInterruptEnabled()); + } + + Result PadSessionImpl::UpdateDriverInterruptEnabled() { + /* Check we have exclusive access to the relevant interrupt control mutex. */ + auto &pad = this->GetDevice().SafeCastTo(); + auto &driver = pad.GetDriver().SafeCastTo(); + AMS_ASSERT(driver.GetInterruptControlMutex(pad).IsLockedByCurrentThread()); + + /* Set interrupt enabled. */ + return driver.SetInterruptEnabled(std::addressof(pad), pad.IsInterruptRequiredForDriver()); + } + + Result PadSessionImpl::GetInterruptEnabled(bool *out) const { + *out = this->GetDevice().SafeCastTo().IsInterruptEnabled(); + return ResultSuccess(); + } + + Result PadSessionImpl::SetInterruptEnabled(bool en) { + /* Acquire exclusive access to the relevant interrupt control mutex. */ + auto &pad = this->GetDevice().SafeCastTo(); + auto &mutex = pad.GetDriver().SafeCastTo().GetInterruptControlMutex(pad); + std::scoped_lock lk(mutex); + + /* Set the interrupt enable. */ + const bool prev = pad.IsInterruptEnabled(); + pad.SetInterruptEnabled(en); + auto pad_guard = SCOPE_GUARD { pad.SetInterruptEnabled(prev); }; + + /* Update interrupt needed. */ + R_TRY(this->UpdateDriverInterruptEnabled()); + + pad_guard.Cancel(); + return ResultSuccess(); + } + + void PadSessionImpl::SignalInterruptBoundEvent() { + /* Check we have exclusive access to the relevant interrupt control mutex. */ + auto &pad = this->GetDevice().SafeCastTo(); + auto &driver = pad.GetDriver().SafeCastTo(); + AMS_ASSERT(driver.GetInterruptControlMutex(pad).IsLockedByCurrentThread()); + + if (auto *event = this->event_holder.GetSystemEvent(); event != nullptr) { + os::SignalSystemEvent(event); + } + } + +} diff --git a/libraries/libstratosphere/source/gpio/gpio_client_api.cpp b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp index c5d88023b..646d6e646 100644 --- a/libraries/libstratosphere/source/gpio/gpio_client_api.cpp +++ b/libraries/libstratosphere/source/gpio/gpio_client_api.cpp @@ -23,6 +23,7 @@ namespace ams::gpio { /* TODO: Manager object. */ constinit os::SdkMutex g_init_mutex; constinit int g_initialize_count = 0; + constinit bool g_remote = false; std::shared_ptr g_manager; using InternalSession = std::shared_ptr; @@ -40,9 +41,19 @@ namespace ams::gpio { if ((g_initialize_count++) == 0) { R_ABORT_UNLESS(::gpioInitialize()); g_manager = ams::sf::MakeShared(); + g_remote = true; } } + void InitializeWith(std::shared_ptr &&sp) { + std::scoped_lock lk(g_init_mutex); + + AMS_ABORT_UNLESS(g_initialize_count == 0); + + g_manager = std::move(sp); + g_initialize_count = 1; + } + void Finalize() { std::scoped_lock lk(g_init_mutex); @@ -50,7 +61,9 @@ namespace ams::gpio { if ((--g_initialize_count) == 0) { g_manager.reset(); - ::gpioExit(); + if (g_remote) { + ::gpioExit(); + } } } diff --git a/libraries/libstratosphere/source/gpio/server/gpio_server_api.cpp b/libraries/libstratosphere/source/gpio/server/gpio_server_api.cpp new file mode 100644 index 000000000..a6310b376 --- /dev/null +++ b/libraries/libstratosphere/source/gpio/server/gpio_server_api.cpp @@ -0,0 +1,36 @@ +/* + * 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 +#include "gpio_server_manager_impl.hpp" + +namespace ams::gpio::server { + + namespace { + + ManagerImpl g_manager_impl; + + std::shared_ptr GetManagerServiceObject() { + static std::shared_ptr s_sp = ams::sf::GetSharedPointerTo(g_manager_impl); + return s_sp; + } + + } + + std::shared_ptr GetServiceObject() { + return GetManagerServiceObject(); + } + +} diff --git a/libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.cpp b/libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.cpp new file mode 100644 index 000000000..4a7554ae6 --- /dev/null +++ b/libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.cpp @@ -0,0 +1,86 @@ +/* + * 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 +#include "gpio_server_manager_impl.hpp" + +namespace ams::gpio::server { + + ManagerImpl::ManagerImpl() : pad_session_memory_resource(), pad_allocator(std::addressof(pad_session_memory_resource)) { + this->heap_handle = lmem::CreateExpHeap(this->heap_buffer, sizeof(this->heap_buffer), lmem::CreateOption_None); + this->pad_session_memory_resource.Attach(this->heap_handle); + } + + ManagerImpl::~ManagerImpl() { + lmem::DestroyExpHeap(this->heap_handle); + } + + Result ManagerImpl::OpenSessionForDev(ams::sf::Out> out, s32 pad_descriptor) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::OpenSession(ams::sf::Out> out, gpio::GpioPadName pad_name) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::OpenSessionForTest(ams::sf::Out> out, gpio::GpioPadName pad_name) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::IsWakeEventActive(ams::sf::Out out, gpio::GpioPadName pad_name) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::GetWakeEventActiveFlagSet(ams::sf::Out out) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::SetWakeEventActiveFlagSetForDebug(gpio::GpioPadName pad_name, bool is_enabled) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::SetWakePinDebugMode(s32 mode) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::OpenSession2(ams::sf::Out> out, DeviceCode device_code, ddsf::AccessMode access_mode) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::IsWakeEventActive2(ams::sf::Out out, DeviceCode device_code) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::SetWakeEventActiveFlagSetForDebug2(DeviceCode device_code, bool is_enabled) { + /* TODO */ + AMS_ABORT(); + } + + Result ManagerImpl::SetRetryValues(u32 arg0, u32 arg1) { + /* TODO */ + AMS_ABORT(); + } + + +} diff --git a/libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.hpp b/libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.hpp new file mode 100644 index 000000000..18863acfc --- /dev/null +++ b/libraries/libstratosphere/source/gpio/server/gpio_server_manager_impl.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 "gpio_server_pad_session_impl.hpp" + +namespace ams::gpio::server { + + class ManagerImpl { + private: + lmem::HeapHandle heap_handle; + ams::sf::ExpHeapMemoryResource pad_session_memory_resource; + typename ams::sf::ServiceObjectAllocator pad_allocator; + u8 heap_buffer[12_KB]; + public: + ManagerImpl(); + + ~ManagerImpl(); + public: + /* Actual commands. */ + Result OpenSessionForDev(ams::sf::Out> out, s32 pad_descriptor); + Result OpenSession(ams::sf::Out> out, gpio::GpioPadName pad_name); + Result OpenSessionForTest(ams::sf::Out> out, gpio::GpioPadName pad_name); + Result IsWakeEventActive(ams::sf::Out out, gpio::GpioPadName pad_name); + Result GetWakeEventActiveFlagSet(ams::sf::Out out); + Result SetWakeEventActiveFlagSetForDebug(gpio::GpioPadName pad_name, bool is_enabled); + Result SetWakePinDebugMode(s32 mode); + Result OpenSession2(ams::sf::Out> out, DeviceCode device_code, ddsf::AccessMode access_mode); + Result IsWakeEventActive2(ams::sf::Out out, DeviceCode device_code); + Result SetWakeEventActiveFlagSetForDebug2(DeviceCode device_code, bool is_enabled); + Result SetRetryValues(u32 arg0, u32 arg1); + + }; + static_assert(gpio::sf::IsIManager); + +} diff --git a/libraries/libstratosphere/source/gpio/server/gpio_server_pad_session_impl.hpp b/libraries/libstratosphere/source/gpio/server/gpio_server_pad_session_impl.hpp new file mode 100644 index 000000000..299a10962 --- /dev/null +++ b/libraries/libstratosphere/source/gpio/server/gpio_server_pad_session_impl.hpp @@ -0,0 +1,207 @@ +/* + * 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::server { + + class ManagerImpl; + + class PadSessionImpl { + private: + ManagerImpl *parent; /* NOTE: this is an sf::SharedPointer<> in Nintendo's code. */ + gpio::driver::GpioPadSession internal_pad_session; + bool has_session; + os::SystemEvent system_event; + public: + explicit PadSessionImpl(ManagerImpl *p) : parent(p), has_session(false) { /* ... */ } + + ~PadSessionImpl() { + if (this->has_session) { + gpio::driver::CloseSession(std::addressof(this->internal_pad_session)); + } + } + + Result OpenSession(DeviceCode device_code) { + AMS_ABORT_UNLESS(!this->has_session); + + R_TRY(gpio::driver::OpenSession(std::addressof(this->internal_pad_session), device_code)); + this->has_session = true; + return ResultSuccess(); + } + public: + /* Actual commands. */ + Result SetDirection(gpio::Direction direction) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* Validate the direction. */ + R_UNLESS((direction == Direction_Input || direction == Direction_Output), gpio::ResultInvalidArgument()); + + /* Invoke the driver library. */ + R_TRY(gpio::driver::SetDirection(std::addressof(this->internal_pad_session), direction)); + + return ResultSuccess(); + } + + Result GetDirection(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* Invoke the driver library. */ + R_TRY(gpio::driver::GetDirection(out.GetPointer(), std::addressof(this->internal_pad_session))); + + return ResultSuccess(); + } + + Result SetInterruptMode(gpio::InterruptMode mode) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result GetInterruptMode(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result SetInterruptEnable(bool enable) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result GetInterruptEnable(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result GetInterruptStatus(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result ClearInterruptStatus() { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result SetValue(gpio::GpioValue value) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* Validate the value. */ + R_UNLESS((value == GpioValue_Low || value == GpioValue_High), gpio::ResultInvalidArgument()); + + /* Invoke the driver library. */ + R_TRY(gpio::driver::SetValue(std::addressof(this->internal_pad_session), value)); + + return ResultSuccess(); + } + + Result GetValue(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* Invoke the driver library. */ + R_TRY(gpio::driver::GetValue(out.GetPointer(), std::addressof(this->internal_pad_session))); + + return ResultSuccess(); + } + + Result BindInterrupt(ams::sf::OutCopyHandle out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result UnbindInterrupt() { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result SetDebounceEnabled(bool enable) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result GetDebounceEnabled(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result SetDebounceTime(s32 ms) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result GetDebounceTime(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result SetValueForSleepState(gpio::GpioValue value) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + + Result GetValueForSleepState(ams::sf::Out out) { + /* Validate our state. */ + AMS_ASSERT(this->has_session); + + /* TODO */ + AMS_ABORT(); + } + }; + static_assert(gpio::sf::IsIPadSession); + +} diff --git a/libraries/libstratosphere/source/os/os_interrupt_event.cpp b/libraries/libstratosphere/source/os/os_interrupt_event.cpp index e2bd5811f..54de8d18b 100644 --- a/libraries/libstratosphere/source/os/os_interrupt_event.cpp +++ b/libraries/libstratosphere/source/os/os_interrupt_event.cpp @@ -15,6 +15,7 @@ */ #include #include "impl/os_interrupt_event_impl.hpp" +#include "impl/os_waitable_holder_impl.hpp" #include "impl/os_waitable_object_list.hpp" namespace ams::os { @@ -61,4 +62,12 @@ namespace ams::os { return GetReference(event->impl).Clear(); } + void InitializeWaitableHolder(WaitableHolderType *waitable_holder, InterruptEventType *event) { + AMS_ASSERT(event->state == InterruptEventType::State_Initialized); + + new (GetPointer(waitable_holder->impl_storage)) impl::WaitableHolderOfInterruptEvent(event); + + waitable_holder->user_data = 0; + } + } diff --git a/libraries/libvapours/include/vapours/results.hpp b/libraries/libvapours/include/vapours/results.hpp index e225f4db5..95eb6442a 100644 --- a/libraries/libvapours/include/vapours/results.hpp +++ b/libraries/libvapours/include/vapours/results.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libvapours/include/vapours/results/gpio_results.hpp b/libraries/libvapours/include/vapours/results/gpio_results.hpp new file mode 100644 index 000000000..4f4cc6a5f --- /dev/null +++ b/libraries/libvapours/include/vapours/results/gpio_results.hpp @@ -0,0 +1,29 @@ +/* + * 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 { + + R_DEFINE_NAMESPACE_RESULT_MODULE(102); + + R_DEFINE_ERROR_RESULT(AlreadyBound, 1); + R_DEFINE_ERROR_RESULT(AlreadyOpen, 2); + R_DEFINE_ERROR_RESULT(DeviceNotFound, 3); + R_DEFINE_ERROR_RESULT(InvalidArgument, 4); + +} diff --git a/stratosphere/boot/source/boot_driver_management.cpp b/stratosphere/boot/source/boot_driver_management.cpp new file mode 100644 index 000000000..8a31a2720 --- /dev/null +++ b/stratosphere/boot/source/boot_driver_management.cpp @@ -0,0 +1,32 @@ +/* + * 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 +#include "boot_driver_management.hpp" + +namespace ams::boot { + + void InitializeGpioDriverLibrary() { + /* Initialize the gpio client library with the server manager object. */ + gpio::InitializeWith(gpio::server::GetServiceObject()); + + /* Initialize the board driver without enabling interrupt handlers. */ + gpio::driver::board::Initialize(false); + + /* Initialize the driver library. */ + gpio::driver::Initialize(); + } + +} diff --git a/stratosphere/boot/source/boot_driver_management.hpp b/stratosphere/boot/source/boot_driver_management.hpp new file mode 100644 index 000000000..4eeb2887e --- /dev/null +++ b/stratosphere/boot/source/boot_driver_management.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 + +namespace ams::boot { + + void InitializeGpioDriverLibrary(); + + +} + diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 0aeb3937d..49d4917bc 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -19,6 +19,7 @@ #include "boot_check_battery.hpp" #include "boot_check_clock.hpp" #include "boot_clock_initial_configuration.hpp" +#include "boot_driver_management.hpp" #include "boot_fan_enable.hpp" #include "boot_repair_boot_images.hpp" #include "boot_splash_screen.hpp" @@ -71,13 +72,13 @@ using namespace ams; namespace { - u8 g_exp_heap_memory[20_KB]; - u8 g_unit_heap_memory[5_KB]; - lmem::HeapHandle g_exp_heap_handle; - lmem::HeapHandle g_unit_heap_handle; + constinit u8 g_exp_heap_memory[20_KB]; + constinit u8 g_unit_heap_memory[5_KB]; + constinit lmem::HeapHandle g_exp_heap_handle; + constinit lmem::HeapHandle g_unit_heap_handle; - std::optional g_exp_heap_memory_resource; - std::optional g_unit_heap_memory_resource; + constinit sf::ExpHeapMemoryResource g_exp_heap_memory_resource; + constinit sf::UnitHeapMemoryResource g_unit_heap_memory_resource; void *Allocate(size_t size) { void *mem = lmem::AllocateFromExpHeap(g_exp_heap_handle, size); @@ -94,13 +95,13 @@ namespace { g_exp_heap_handle = lmem::CreateExpHeap(g_exp_heap_memory, sizeof(g_exp_heap_memory), lmem::CreateOption_ThreadSafe); g_unit_heap_handle = lmem::CreateUnitHeap(g_unit_heap_memory, sizeof(g_unit_heap_memory), sizeof(ddsf::DeviceCodeEntryHolder), lmem::CreateOption_ThreadSafe); - /* Create the memory resources. */ - g_exp_heap_memory_resource.emplace(g_exp_heap_handle); - g_unit_heap_memory_resource.emplace(g_unit_heap_handle); + /* Attach the memory resources. */ + g_exp_heap_memory_resource.Attach(g_exp_heap_handle); + g_unit_heap_memory_resource.Attach(g_unit_heap_handle); /* Register with ddsf. */ - ddsf::SetMemoryResource(std::addressof(*g_exp_heap_memory_resource)); - ddsf::SetDeviceCodeEntryHolderMemoryResource(std::addressof(*g_unit_heap_memory_resource)); + ddsf::SetMemoryResource(std::addressof(g_exp_heap_memory_resource)); + ddsf::SetDeviceCodeEntryHolderMemoryResource(std::addressof(g_unit_heap_memory_resource)); } } @@ -184,9 +185,12 @@ int main(int argc, char **argv) /* Change voltage from 3.3v to 1.8v for select devices. */ boot::ChangeGpioVoltageTo1_8v(); - /* Setup GPIO. */ + /* Setup gpio. */ gpio::driver::SetInitialGpioConfig(); + /* Initialize the gpio server library. */ + boot::InitializeGpioDriverLibrary(); + /* Check USB PLL/UTMIP clock. */ boot::CheckClock();