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();