diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp index 4428ac11c..3b81c8af3 100644 --- a/libraries/libstratosphere/include/stratosphere/fs.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_i_event_notifier.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_i_event_notifier.hpp new file mode 100644 index 000000000..375ed1afd --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_i_event_notifier.hpp @@ -0,0 +1,33 @@ +/* + * 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 "fs_common.hpp" + +namespace ams::fs { + + class IEventNotifier { + public: + virtual ~IEventNotifier() { /* ... */ } + + Result BindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) { + AMS_ASSERT(out != nullptr); + return this->DoBindEvent(out, clear_mode); + } + private: + virtual Result DoBindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) = 0; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp index e27c12195..183f7bea5 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_sd_card.hpp @@ -18,8 +18,14 @@ namespace ams::fs { + class IEventNotifier; + Result MountSdCard(const char *name); Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name); + Result OpenSdCardDetectionEventNotifier(std::unique_ptr *out); + + bool IsSdCardInserted(); + } diff --git a/libraries/libstratosphere/include/stratosphere/fssrv.hpp b/libraries/libstratosphere/include/stratosphere/fssrv.hpp index a2fb95b3d..70fa77bba 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv.hpp @@ -17,6 +17,7 @@ #pragma once #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_event_notifier.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_event_notifier.hpp new file mode 100644 index 000000000..090369985 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fssrv/sf/fssrv_sf_i_event_notifier.hpp @@ -0,0 +1,23 @@ +/* + * 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 + +#define AMS_FSSRV_I_EVENT_NOTIFIER_INTERFACE_INFO(C, H) \ + AMS_SF_METHOD_INFO(C, H, 0, Result, GetEventHandle, (ams::sf::OutCopyHandle out), (out)) + +AMS_SF_DEFINE_INTERFACE(ams::fssrv::sf, IEventNotifier, AMS_FSSRV_I_EVENT_NOTIFIER_INTERFACE_INFO) diff --git a/libraries/libstratosphere/source/fs/fs_sd_card.cpp b/libraries/libstratosphere/source/fs/fs_sd_card.cpp index d001cef8c..b11982b11 100644 --- a/libraries/libstratosphere/source/fs/fs_sd_card.cpp +++ b/libraries/libstratosphere/source/fs/fs_sd_card.cpp @@ -15,6 +15,7 @@ */ #include #include "fsa/fs_mount_utils.hpp" +#include "impl/fs_event_notifier_object_adapter.hpp" namespace ams::fs { @@ -87,4 +88,30 @@ namespace ams::fs { return fsa::Register(name, std::move(subdir_fs)); } + Result OpenSdCardDetectionEventNotifier(std::unique_ptr *out) { + /* Try to open an event notifier. */ + FsEventNotifier notifier; + AMS_FS_R_TRY(fsOpenSdCardDetectionEventNotifier(std::addressof(notifier))); + + /* Create an event notifier adapter. */ + auto adapter = std::make_unique(notifier); + R_UNLESS(adapter != nullptr, fs::ResultAllocationFailureInSdCardB()); + + *out = std::move(adapter); + return ResultSuccess(); + } + + bool IsSdCardInserted() { + /* Open device operator. */ + FsDeviceOperator device_operator; + AMS_FS_R_ABORT_UNLESS(::fsOpenDeviceOperator(std::addressof(device_operator))); + ON_SCOPE_EXIT { ::fsDeviceOperatorClose(std::addressof(device_operator)); }; + + /* Get SD card inserted. */ + bool inserted; + AMS_FS_R_ABORT_UNLESS(::fsDeviceOperatorIsSdCardInserted(std::addressof(device_operator), std::addressof(inserted))); + + return inserted; + } + } diff --git a/libraries/libstratosphere/source/fs/impl/fs_event_notifier_object_adapter.hpp b/libraries/libstratosphere/source/fs/impl/fs_event_notifier_object_adapter.hpp new file mode 100644 index 000000000..ea0cc64f0 --- /dev/null +++ b/libraries/libstratosphere/source/fs/impl/fs_event_notifier_object_adapter.hpp @@ -0,0 +1,59 @@ +/* + * 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::fs::impl { + + class EventNotifierObjectAdapter final : public ::ams::fs::IEventNotifier, public ::ams::fs::impl::Newable { + private: + sf::SharedPointer m_object; + public: + EventNotifierObjectAdapter(sf::SharedPointer &&obj) : m_object(obj) { /* ... */ } + virtual ~EventNotifierObjectAdapter() { /* ... */ } + private: + virtual Result DoBindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) override { + /* Get the handle. */ + sf::CopyHandle handle; + AMS_FS_R_TRY(m_object->GetEventHandle(std::addressof(handle))); + + /* Create the system event. */ + os::AttachReadableHandleToSystemEvent(out, handle, true, clear_mode); + + return ResultSuccess(); + } + }; + + class RemoteEventNotifierObjectAdapter final : public ::ams::fs::IEventNotifier, public ::ams::fs::impl::Newable { + private: + ::FsEventNotifier m_notifier; + public: + RemoteEventNotifierObjectAdapter(::FsEventNotifier &n) : m_notifier(n) { /* ... */ } + virtual ~RemoteEventNotifierObjectAdapter() { fsEventNotifierClose(std::addressof(m_notifier)); } + private: + virtual Result DoBindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) override { + /* Get the handle. */ + ::Event e; + R_TRY(fsEventNotifierGetEventHandle(std::addressof(m_notifier), std::addressof(e), false)); + + /* Create the system event. */ + os::AttachReadableHandleToSystemEvent(out, e.revent, true, clear_mode); + + return ResultSuccess(); + } + }; + +} diff --git a/stratosphere/TioServer/source/tio_file_server.cpp b/stratosphere/TioServer/source/tio_file_server.cpp index 8c02dcfab..2b5309c8a 100644 --- a/stratosphere/TioServer/source/tio_file_server.cpp +++ b/stratosphere/TioServer/source/tio_file_server.cpp @@ -18,6 +18,7 @@ #include "tio_file_server_packet.hpp" #include "tio_file_server_htcs_server.hpp" #include "tio_file_server_processor.hpp" +#include "tio_sd_card_observer.hpp" namespace ams::tio { @@ -36,10 +37,12 @@ namespace ams::tio { constexpr const char HtcsPortName[] = "iywys@$TioServer_FileServer"; alignas(os::ThreadStackAlignment) u8 g_server_stack[os::MemoryPageSize]; + alignas(os::ThreadStackAlignment) u8 g_observer_stack[os::MemoryPageSize]; alignas(os::ThreadStackAlignment) u8 g_dispatch_stacks[NumDispatchThreads][os::MemoryPageSize]; constinit FileServerHtcsServer g_file_server_htcs_server; constinit FileServerProcessor g_file_server_processor(g_file_server_htcs_server); + constinit SdCardObserver g_sd_card_observer; constinit os::ThreadType g_file_server_dispatch_threads[NumDispatchThreads]; @@ -51,6 +54,10 @@ namespace ams::tio { constinit uintptr_t g_free_mq_storage[NumDispatchThreads]; constinit uintptr_t g_dispatch_mq_storage[NumDispatchThreads]; + void OnSdCardInsertionChanged(bool inserted) { + g_file_server_processor.SetInserted(inserted); + } + void OnFileServerHtcsSocketAccepted(int fd) { /* Service requests, while we can. */ while (true) { @@ -110,10 +117,12 @@ namespace ams::tio { /* Initialize the htcs server. */ g_file_server_htcs_server.Initialize(HtcsPortName, g_server_stack, sizeof(g_server_stack), OnFileServerHtcsSocketAccepted); - /* TODO: Initialize SD card observer. */ + /* Initialize SD card observer. */ + g_sd_card_observer.Initialize(g_observer_stack, sizeof(g_observer_stack)); + g_sd_card_observer.SetCallback(OnSdCardInsertionChanged); /* Initialize the command processor. */ - g_file_server_processor.SetInserted(false); + g_file_server_processor.SetInserted(g_sd_card_observer.IsSdCardInserted()); g_file_server_processor.SetRequestBufferSize(RequestBufferSize); /* Initialize the dispatch message queues. */ diff --git a/stratosphere/TioServer/source/tio_sd_card_observer.cpp b/stratosphere/TioServer/source/tio_sd_card_observer.cpp new file mode 100644 index 000000000..981b7aecf --- /dev/null +++ b/stratosphere/TioServer/source/tio_sd_card_observer.cpp @@ -0,0 +1,64 @@ +/* + * 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 "tio_sd_card_observer.hpp" + +namespace ams::tio { + + void SdCardObserver::Initialize(void *thread_stack, size_t thread_stack_size) { + /* Setup our thread. */ + R_ABORT_UNLESS(os::CreateThread(std::addressof(m_thread), ThreadEntry, this, thread_stack, thread_stack_size, AMS_GET_SYSTEM_THREAD_PRIORITY(TioServer, SdCardObserver))); + + /* Set our thread name pointer. */ + os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(TioServer, SdCardObserver)); + + /* Set our initial insertion state. */ + m_inserted = fs::IsSdCardInserted(); + } + + void SdCardObserver::SetCallback(SdCardInsertionCallback callback) { + /* Check that we don't already have a callback. */ + AMS_ABORT_UNLESS(m_callback == nullptr); + + /* Set our callback. */ + m_callback = callback; + } + + void SdCardObserver::ThreadFunc() { + /* Open detection event notifier. */ + std::unique_ptr notifier; + R_ABORT_UNLESS(fs::OpenSdCardDetectionEventNotifier(std::addressof(notifier))); + + /* Bind the detection event. */ + os::SystemEventType event; + R_ABORT_UNLESS(notifier->BindEvent(std::addressof(event), os::EventClearMode_AutoClear)); + + /* Loop, waiting for insertion events. */ + while (true) { + /* Wait for an event. */ + os::WaitSystemEvent(std::addressof(event)); + + /* Update our insertion state. */ + m_inserted = fs::IsSdCardInserted(); + + /* Invoke our callback. */ + if (m_callback) { + m_callback(m_inserted); + } + } + } + +} diff --git a/stratosphere/TioServer/source/tio_sd_card_observer.hpp b/stratosphere/TioServer/source/tio_sd_card_observer.hpp new file mode 100644 index 000000000..4347d9846 --- /dev/null +++ b/stratosphere/TioServer/source/tio_sd_card_observer.hpp @@ -0,0 +1,43 @@ +/* + * 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::tio { + + using SdCardInsertionCallback = void(*)(bool inserted); + + class SdCardObserver { + private: + bool m_inserted; + SdCardInsertionCallback m_callback; + os::ThreadType m_thread; + public: + constexpr SdCardObserver() : m_inserted(false), m_callback(nullptr), m_thread{} { /* ... */ } + + bool IsSdCardInserted() const { return m_inserted; } + private: + static void ThreadEntry(void *arg) { + static_cast(arg)->ThreadFunc(); + } + + void ThreadFunc(); + public: + void Initialize(void *thread_stack, size_t thread_stack_size); + void SetCallback(SdCardInsertionCallback callback); + }; + +} \ No newline at end of file