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 f08fa246f..1c3bca1a3 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 @@ -140,6 +140,7 @@ namespace ams::impl { AMS_DEFINE_SYSTEM_THREAD(10, htc, Htcmisc); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcmiscReceive); AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcmiscSend); + AMS_DEFINE_SYSTEM_THREAD(10, htc, HtcObserver); AMS_DEFINE_SYSTEM_THREAD(10, tma, BridgePcieDriver); diff --git a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp new file mode 100644 index 000000000..4fc86daf9 --- /dev/null +++ b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp @@ -0,0 +1,87 @@ +/* + * 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 "htc_htcmisc_impl.hpp" + +namespace ams::htc::server { + + namespace { + + alignas(os::ThreadStackAlignment) u8 g_client_thread_stack[os::MemoryPageSize]; + alignas(os::ThreadStackAlignment) u8 g_server_thread_stack[os::MemoryPageSize]; + + } + + HtcmiscImpl::HtcmiscImpl(htclow::HtclowManager *htclow_manager) + : m_htclow_driver(htclow_manager, htclow::ModuleId::Htcmisc), + m_driver_manager(std::addressof(m_htclow_driver)), + m_rpc_client(std::addressof(m_htclow_driver), HtcmiscClientChannelId), + m_rpc_server(std::addressof(m_htclow_driver), HtcmiscServerChannelId), + m_cancel_event(os::EventClearMode_ManualClear), + m_cancelled(false), + m_connection_event(os::EventClearMode_ManualClear), + m_client_connected(false), + m_server_connected(false), + m_connected(false), + m_connection_mutex() + { + /* Create the client thread. */ + R_ABORT_UNLESS(os::CreateThread(std::addressof(m_client_thread), ClientThreadEntry, this, g_client_thread_stack, sizeof(g_client_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, Htcmisc))); + + /* Set the client thread name. */ + os::SetThreadNamePointer(std::addressof(m_client_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, Htcmisc)); + + /* Start the client thread. */ + os::StartThread(std::addressof(m_client_thread)); + + /* Create the server thread. */ + R_ABORT_UNLESS(os::CreateThread(std::addressof(m_server_thread), ServerThreadEntry, this, g_server_thread_stack, sizeof(g_server_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, Htcmisc))); + + /* Set the server thread name. */ + os::SetThreadNamePointer(std::addressof(m_server_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, Htcmisc)); + + /* Start the server thread. */ + os::StartThread(std::addressof(m_server_thread)); + } + + HtcmiscImpl::~HtcmiscImpl() { + /* Cancel ourselves. */ + this->Cancel(); + + /* Wait for our threads to be done, and destroy them. */ + os::WaitThread(std::addressof(m_client_thread)); + os::DestroyThread(std::addressof(m_client_thread)); + os::WaitThread(std::addressof(m_server_thread)); + os::DestroyThread(std::addressof(m_server_thread)); + } + + void HtcmiscImpl::Cancel() { + /* Set ourselves as cancelled. */ + m_cancelled = true; + + /* Signal our cancel event. */ + m_cancel_event.Signal(); + } + + void HtcmiscImpl::ClientThread() { + AMS_ABORT("HtcmiscImpl::ClientThread"); + } + + void HtcmiscImpl::ServerThread() { + AMS_ABORT("HtcmiscImpl::ServerThread"); + } + +} diff --git a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.hpp b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.hpp index d2cd85c1e..7cd407f1f 100644 --- a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.hpp +++ b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.hpp @@ -31,16 +31,24 @@ namespace ams::htc::server { rpc::HtcmiscRpcServer m_rpc_server; os::ThreadType m_client_thread; os::ThreadType m_server_thread; - os::Event m_event_61200; - u8 m_61228; - os::Event m_event_61230; + os::Event m_cancel_event; + bool m_cancelled; + os::Event m_connection_event; bool m_client_connected; bool m_server_connected; - u8 m_6125A; + bool m_connected; os::SdkMutex m_connection_mutex; + private: + static void ClientThreadEntry(void *arg) { static_cast(arg)->ClientThread(); } + static void ServerThreadEntry(void *arg) { static_cast(arg)->ServerThread(); } + + void ClientThread(); + void ServerThread(); public: HtcmiscImpl(htclow::HtclowManager *htclow_manager); + ~HtcmiscImpl(); public: + void Cancel(); /* TODO */ }; diff --git a/libraries/libstratosphere/source/htc/server/htc_observer.cpp b/libraries/libstratosphere/source/htc/server/htc_observer.cpp new file mode 100644 index 000000000..4e1c6622b --- /dev/null +++ b/libraries/libstratosphere/source/htc/server/htc_observer.cpp @@ -0,0 +1,75 @@ +/* + * 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 "htc_observer.hpp" + +namespace ams::htc::server { + + Observer::Observer(const HtcmiscImpl &misc_impl) + : m_connect_event(os::EventClearMode_ManualClear, true), + m_disconnect_event(os::EventClearMode_ManualClear, true), + m_stop_event(os::EventClearMode_ManualClear), + m_misc_impl(misc_impl), + m_thread_running(false), + m_stopped(false), + m_connected(false), + m_is_service_available(false) + { + /* Initialize htcs library. */ + AMS_ABORT("htcs::impl::HtcsManagerHolder::AddReference();"); + + /* Update our event state. */ + this->UpdateEvent(); + + /* Start. */ + R_ABORT_UNLESS(this->Start()); + } + + Result Observer::Start() { + /* Check that we're not already running. */ + AMS_ASSERT(!m_thread_running); + + /* Create the thread. */ + R_TRY(os::CreateThread(std::addressof(m_observer_thread), ObserverThreadEntry, this, m_observer_thread_stack, sizeof(m_observer_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcObserver))); + + /* Set the thread name pointer. */ + os::SetThreadNamePointer(std::addressof(m_observer_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcObserver)); + + /* Mark our thread as running. */ + m_thread_running = true; + m_stopped = false; + + /* Start our thread. */ + os::StartThread(std::addressof(m_observer_thread)); + + return ResultSuccess(); + } + + void Observer::UpdateEvent() { + if (m_connected && m_is_service_available) { + m_disconnect_event.Clear(); + m_connect_event.Signal(); + } else { + m_connect_event.Clear(); + m_disconnect_event.Signal(); + } + } + + void Observer::ObserverThreadBody() { + AMS_ABORT("Observer::ObserverThreadBody"); + } + +} diff --git a/libraries/libstratosphere/source/htc/server/htc_observer.hpp b/libraries/libstratosphere/source/htc/server/htc_observer.hpp index bde6d56cf..ea9bf2d2d 100644 --- a/libraries/libstratosphere/source/htc/server/htc_observer.hpp +++ b/libraries/libstratosphere/source/htc/server/htc_observer.hpp @@ -23,15 +23,24 @@ namespace ams::htc::server { private: os::SystemEvent m_connect_event; os::SystemEvent m_disconnect_event; - os::Event m_event_60; + os::Event m_stop_event; os::ThreadType m_observer_thread; const HtcmiscImpl &m_misc_impl; bool m_thread_running; bool m_stopped; bool m_connected; bool m_is_service_available; + alignas(os::ThreadStackAlignment) u8 m_observer_thread_stack[os::MemoryPageSize]; public: Observer(const HtcmiscImpl &misc_impl); + private: + static void ObserverThreadEntry(void *arg) { static_cast(arg)->ObserverThreadBody(); } + + void ObserverThreadBody(); + private: + Result Start(); + + void UpdateEvent(); }; } diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_server.cpp b/libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_server.cpp new file mode 100644 index 000000000..438df31e2 --- /dev/null +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_htcmisc_rpc_server.cpp @@ -0,0 +1,40 @@ +/* + * 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 "htc_htcmisc_rpc_server.hpp" + +namespace ams::htc::server::rpc { + + namespace { + + constexpr inline size_t ReceiveThreadStackSize = os::MemoryPageSize; + + alignas(os::ThreadStackAlignment) constinit u8 g_receive_thread_stack[ReceiveThreadStackSize]; + + } + + HtcmiscRpcServer::HtcmiscRpcServer(driver::IDriver *driver, htclow::ChannelId channel) + : m_00(0), + m_driver(driver), + m_channel_id(channel), + m_receive_thread_stack(g_receive_thread_stack), + m_cancelled(false), + m_thread_running(false) + { + /* ... */ + } + +} diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp new file mode 100644 index 000000000..394252c8e --- /dev/null +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.cpp @@ -0,0 +1,52 @@ +/* + * 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 "htc_rpc_client.hpp" + +namespace ams::htc::server::rpc { + + namespace { + + constexpr inline size_t ThreadStackSize = os::MemoryPageSize; + + alignas(os::ThreadStackAlignment) constinit u8 g_receive_thread_stack[ThreadStackSize]; + alignas(os::ThreadStackAlignment) constinit u8 g_send_thread_stack[ThreadStackSize]; + + constinit os::SdkMutex g_rpc_mutex; + + } + + RpcClient::RpcClient(driver::IDriver *driver, htclow::ChannelId channel) + : m_00(0), + m_driver(driver), + m_channel_id(channel), + m_receive_thread_stack(g_receive_thread_stack), + m_send_thread_stack(g_send_thread_stack), + m_mutex(g_rpc_mutex), + m_cancelled(false), + m_thread_running(false) + { + /* Initialize all events. */ + /* TODO: MaxTaskCount? */ + for (size_t i = 0; i < util::size(m_5F8_events); ++i) { + os::InitializeEvent(std::addressof(m_5F8_events[i]), false, os::EventClearMode_AutoClear); + os::InitializeEvent(std::addressof(m_1138_events[i]), false, os::EventClearMode_AutoClear); + } + + /* TODO: Clear all of m_3C0 array to zero. */ + } + +} diff --git a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp index 4ca916797..52811489f 100644 --- a/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp +++ b/libraries/libstratosphere/source/htc/server/rpc/htc_rpc_client.hpp @@ -28,7 +28,7 @@ namespace ams::htc::server::rpc { void *m_send_thread_stack; os::ThreadType m_receive_thread; os::ThreadType m_send_thread; - os::SdkMutex *m_p_mutex; + os::SdkMutex &m_mutex; /* TODO: m_task_id_free_list */ /* TODO: m_task_table */ /* TODO: m_3C0[0x48] */ diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp index c8fc4722c..ca1615a5f 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_service.cpp @@ -351,6 +351,22 @@ namespace ams::htclow::ctrl { this->DisconnectInternal(); } + void HtcctrlService::DisconnectInternal() { + /* Disconnect, if we need to. */ + if (m_state_machine->IsDisconnectionNeeded()) { + /* Send a disconnect packet. */ + m_send_buffer.AddPacket(m_packet_factory->MakeDisconnectPacket()); + + /* Signal our event. */ + m_event.Signal(); + + /* Wait for us to be disconnected. */ + while (!m_state_machine->IsDisconnected()) { + m_condvar.Wait(m_mutex); + } + } + } + void HtcctrlService::Resume() { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp index e9acb3fd2..c1271c769 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.cpp @@ -64,6 +64,13 @@ namespace ams::htclow::ctrl { return !ctrl::IsDisconnected(m_state) && m_state != HtcctrlState_DriverConnected; } + bool HtcctrlStateMachine::IsDisconnectionNeeded() { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + return !ctrl::IsDisconnected(m_state) && m_state != HtcctrlState_Sleep && m_state != HtcctrlState_DriverConnected; + } + bool HtcctrlStateMachine::IsConnected() { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp index 1e9fd254f..4881d6f46 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_ctrl_state_machine.hpp @@ -59,6 +59,7 @@ namespace ams::htclow::ctrl { bool IsSleepingStatusChanged(); bool IsInformationNeeded(); + bool IsDisconnectionNeeded(); bool IsConnected(); bool IsReadied(); diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp index c41a900e9..3250bbbbb 100644 --- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp +++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp @@ -16,9 +16,17 @@ #include #include "htclow_mux_channel_impl.hpp" #include "../htclow_packet_factory.hpp" +#include "../htclow_default_channel_config.hpp" namespace ams::htclow::mux { + SendBuffer::SendBuffer(impl::ChannelInternalType channel, PacketFactory *pf) + : m_channel(channel), m_packet_factory(pf), m_ring_buffer(), m_packet_list(), + m_version(ProtocolVersion), m_flow_control_enabled(true), m_max_packet_size(DefaultChannelConfig.max_packet_size) + { + /* ... */ + } + SendBuffer::~SendBuffer() { m_ring_buffer.Clear(); this->Clear();