diff --git a/libraries/libstratosphere/source/htclow/htclow_channel.cpp b/libraries/libstratosphere/source/htclow/htclow_channel.cpp
new file mode 100644
index 000000000..830369e25
--- /dev/null
+++ b/libraries/libstratosphere/source/htclow/htclow_channel.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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 "htclow_channel.hpp"
+
+namespace ams::htclow {
+
+ Result Channel::Open(const Module *module, ChannelId id) {
+ /* Check we're not already initialized. */
+ AMS_ASSERT(!module->GetBase()->_is_initialized);
+
+ /* Set our channel type. */
+ m_channel = {
+ ._is_initialized = true,
+ ._module_id = module->GetBase()->_id,
+ ._channel_id = id,
+ };
+
+ /* Open the channel. */
+ return m_manager->Open(impl::ConvertChannelType(m_channel));
+ }
+
+ void Channel::Close() {
+ m_manager->Close(impl::ConvertChannelType(m_channel));
+ }
+
+ ChannelState Channel::GetChannelState() {
+ return m_manager->GetChannelState(impl::ConvertChannelType(m_channel));
+ }
+
+ os::EventType *Channel::GetChannelStateEvent() {
+ return m_manager->GetChannelStateEvent(impl::ConvertChannelType(m_channel));
+ }
+
+ Result Channel::Connect() {
+ const auto channel = impl::ConvertChannelType(m_channel);
+
+ /* Begin the flush. */
+ u32 task_id;
+ R_TRY(m_manager->ConnectBegin(std::addressof(task_id), channel));
+
+ /* Wait for the task to finish. */
+ this->WaitEvent(m_manager->GetTaskEvent(task_id), false);
+
+ /* End the flush. */
+ return m_manager->ConnectEnd(channel, task_id);
+ }
+
+ Result Channel::Flush() {
+ /* Begin the flush. */
+ u32 task_id;
+ R_TRY(m_manager->FlushBegin(std::addressof(task_id), impl::ConvertChannelType(m_channel)));
+
+ /* Wait for the task to finish. */
+ this->WaitEvent(m_manager->GetTaskEvent(task_id), true);
+
+ /* End the flush. */
+ return m_manager->FlushEnd(task_id);
+ }
+
+ void Channel::Shutdown() {
+ m_manager->Shutdown(impl::ConvertChannelType(m_channel));
+ }
+
+ Result Channel::Receive(s64 *out, void *dst, s64 size, ReceiveOption option) {
+ /* Check pre-conditions. */
+ AMS_ABORT_UNLESS(util::IsIntValueRepresentable(size));
+
+ /* Determine the minimum allowable receive size. */
+ s64 min_size;
+ switch (option) {
+ case htclow::ReceiveOption_NonBlocking: min_size = 0; break;
+ case htclow::ReceiveOption_ReceiveAnyData: min_size = 1; break;
+ case htclow::ReceiveOption_ReceiveAllData: min_size = size; break;
+ AMS_UNREACHABLE_DEFAULT_CASE();
+ }
+
+ /* Repeatedly receive. */
+ s64 received = 0;
+ do {
+ s64 cur_received;
+ const Result result = this->ReceiveInternal(std::addressof(cur_received), static_cast(dst) + received, size - received, option);
+
+ if (R_FAILED(result)) {
+ if (htclow::ResultChannelReceiveBufferEmpty::Includes(result)) {
+ R_UNLESS(option != htclow::ReceiveOption_NonBlocking, htclow::ResultNonBlockingReceiveFailed());
+ }
+ if (htclow::ResultChannelNotExist::Includes(result)) {
+ *out = received;
+ }
+ return result;
+ }
+
+ received += static_cast(cur_received);
+ } while (received < min_size);
+
+ /* Set output size. */
+ AMS_ASSERT(received <= size);
+ *out = received;
+
+ return ResultSuccess();
+ }
+
+ Result Channel::Send(s64 *out, const void *src, s64 size, ReceiveOption option) {
+ /* Check pre-conditions. */
+ AMS_ASSERT(util::IsIntValueRepresentable(size));
+
+ /* Convert channel. */
+ const auto channel = impl::ConvertChannelType(m_channel);
+
+ /* Loop sending. */
+ s64 total_sent;
+ size_t cur_sent;
+ for (total_sent = 0; total_sent < size; total_sent += cur_sent) {
+ AMS_ASSERT(util::IsIntValueRepresentable(size - total_sent));
+
+ /* Begin the send. */
+ u32 task_id;
+ const auto begin_result = m_manager->SendBegin(std::addressof(task_id), std::addressof(cur_sent), static_cast(src) + total_sent, size - total_sent, channel);
+ if (R_FAILED(begin_result)) {
+ if (total_sent != 0) {
+ break;
+ } else {
+ return begin_result;
+ }
+ }
+
+ /* Wait for the task to finish. */
+ this->WaitEvent(m_manager->GetTaskEvent(task_id), true);
+
+ /* Finish the send. */
+ R_ABORT_UNLESS(m_manager->SendEnd(task_id));
+ }
+
+ /* Set output size. */
+ AMS_ASSERT(total_sent <= size);
+ *out = total_sent;
+
+ return ResultSuccess();
+ }
+
+ void Channel::SetConfig(const ChannelConfig &config) {
+ m_manager->SetConfig(impl::ConvertChannelType(m_channel), config);
+ }
+
+ void Channel::SetReceiveBuffer(void *buf, size_t size) {
+ m_manager->SetReceiveBuffer(impl::ConvertChannelType(m_channel), buf, size);
+ }
+
+ void Channel::SetSendBuffer(void *buf, size_t size) {
+ m_manager->SetSendBuffer(impl::ConvertChannelType(m_channel), buf, size);
+ }
+
+ void Channel::SetSendBufferWithData(const void *buf, size_t size) {
+ m_manager->SetSendBufferWithData(impl::ConvertChannelType(m_channel), buf, size);
+ }
+
+ Result Channel::WaitReceive(s64 size) {
+ /* Check pre-conditions. */
+ AMS_ASSERT(util::IsIntValueRepresentable(size));
+
+ return this->WaitReceiveInternal(size, nullptr);
+ }
+
+ Result Channel::WaitReceive(s64 size, os::EventType *event) {
+ /* Check pre-conditions. */
+ AMS_ASSERT(util::IsIntValueRepresentable(size));
+ AMS_ASSERT(event != nullptr);
+
+ return this->WaitReceiveInternal(size, event);
+ }
+
+ void Channel::WaitEvent(os::EventType *event, bool) {
+ return os::WaitEvent(event);
+ }
+
+ Result Channel::ReceiveInternal(s64 *out, void *dst, s64 size, ReceiveOption option) {
+ const auto channel = impl::ConvertChannelType(m_channel);
+ const bool blocking = option != ReceiveOption_NonBlocking;
+
+ /* Begin the receive. */
+ u32 task_id;
+ R_TRY(m_manager->ReceiveBegin(std::addressof(task_id), channel, blocking ? 1 : 0));
+
+ /* Wait for the task to finish. */
+ this->WaitEvent(m_manager->GetTaskEvent(task_id), false);
+
+ /* Receive the data. */
+ size_t received;
+ AMS_ASSERT(util::IsIntValueRepresentable(size));
+ R_TRY(m_manager->ReceiveEnd(std::addressof(received), dst, static_cast(size), channel, task_id));
+
+ /* Set the output size. */
+ AMS_ASSERT(util::IsIntValueRepresentable(received));
+ *out = static_cast(received);
+
+ return ResultSuccess();
+ }
+
+ Result Channel::WaitReceiveInternal(s64 size, os::EventType *event) {
+ const auto channel = impl::ConvertChannelType(m_channel);
+
+ /* Begin the wait. */
+ u32 task_id;
+ R_TRY(m_manager->WaitReceiveBegin(std::addressof(task_id), channel, size));
+
+
+ /* Perform the wait. */
+ if (event != nullptr) {
+ if (os::WaitAny(event, m_manager->GetTaskEvent(task_id)) == 0) {
+ m_manager->WaitReceiveEnd(task_id);
+ return htclow::ResultChannelWaitCancelled();
+ }
+ } else {
+ this->WaitEvent(m_manager->GetTaskEvent(task_id), false);
+ }
+
+ /* End the wait. */
+ return m_manager->WaitReceiveEnd(task_id);
+ }
+
+}
diff --git a/libraries/libstratosphere/source/htclow/htclow_channel.hpp b/libraries/libstratosphere/source/htclow/htclow_channel.hpp
new file mode 100644
index 000000000..2d99cc7c4
--- /dev/null
+++ b/libraries/libstratosphere/source/htclow/htclow_channel.hpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "htclow_manager.hpp"
+
+namespace ams::htclow {
+
+ class Channel final {
+ private:
+ HtclowManager *m_manager;
+ ChannelType m_channel;
+ public:
+ constexpr Channel(HtclowManager *manager) : m_manager(manager), m_channel() { /* ... */ }
+ constexpr ~Channel() { m_channel = {}; }
+
+ ChannelType *GetBase() { return std::addressof(m_channel); }
+ public:
+ Result Open(const Module *module, ChannelId id);
+ void Close();
+
+ ChannelState GetChannelState();
+ os::EventType *GetChannelStateEvent();
+
+ Result Connect();
+ Result Flush();
+ void Shutdown();
+
+ Result Receive(s64 *out, void *dst, s64 size, ReceiveOption option);
+ Result Send(s64 *out, const void *src, s64 size, ReceiveOption option);
+
+ void SetConfig(const ChannelConfig &config);
+ void SetReceiveBuffer(void *buf, size_t size);
+ void SetSendBuffer(void *buf, size_t size);
+ void SetSendBufferWithData(const void *buf, size_t size);
+
+ Result WaitReceive(s64 size);
+ Result WaitReceive(s64 size, os::EventType *event);
+ private:
+ void WaitEvent(os::EventType *event, bool);
+ Result ReceiveInternal(s64 *out, void *dst, s64 size, ReceiveOption option);
+ Result WaitReceiveInternal(s64 size, os::EventType *event);
+ };
+
+}
diff --git a/libraries/libstratosphere/source/htclow/htclow_manager.cpp b/libraries/libstratosphere/source/htclow/htclow_manager.cpp
index 398de260a..66990a084 100644
--- a/libraries/libstratosphere/source/htclow/htclow_manager.cpp
+++ b/libraries/libstratosphere/source/htclow/htclow_manager.cpp
@@ -96,8 +96,8 @@ namespace ams::htclow {
return m_impl->NotifyAwake();
}
- Result HtclowManager::ReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, bool blocking) {
- return m_impl->ReceiveBegin(out_task_id, channel, blocking);
+ Result HtclowManager::ReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size) {
+ return m_impl->ReceiveBegin(out_task_id, channel, size);
}
Result HtclowManager::ReceiveEnd(size_t *out, void *dst, size_t dst_size, impl::ChannelInternalType channel, u32 task_id) {
@@ -112,6 +112,14 @@ namespace ams::htclow {
return m_impl->SendEnd(task_id);
}
+ Result HtclowManager::WaitReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size) {
+ return m_impl->WaitReceiveBegin(out_task_id, channel, size);
+ }
+
+ Result HtclowManager::WaitReceiveEnd(u32 task_id) {
+ return m_impl->WaitReceiveEnd(task_id);
+ }
+
void HtclowManager::SetConfig(impl::ChannelInternalType channel, const ChannelConfig &config) {
return m_impl->SetConfig(channel, config);
}
diff --git a/libraries/libstratosphere/source/htclow/htclow_manager.hpp b/libraries/libstratosphere/source/htclow/htclow_manager.hpp
index 1842d2e5c..d01cc891a 100644
--- a/libraries/libstratosphere/source/htclow/htclow_manager.hpp
+++ b/libraries/libstratosphere/source/htclow/htclow_manager.hpp
@@ -56,12 +56,15 @@ namespace ams::htclow {
void NotifyAsleep();
void NotifyAwake();
- Result ReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, bool blocking);
+ Result ReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size);
Result ReceiveEnd(size_t *out, void *dst, size_t dst_size, impl::ChannelInternalType channel, u32 task_id);
Result SendBegin(u32 *out_task_id, size_t *out, const void *src, size_t src_size, impl::ChannelInternalType channel);
Result SendEnd(u32 task_id);
+ Result WaitReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size);
+ Result WaitReceiveEnd(u32 task_id);
+
void SetConfig(impl::ChannelInternalType channel, const ChannelConfig &config);
void SetDebugDriver(driver::IDriver *driver);
diff --git a/libraries/libstratosphere/source/htclow/htclow_manager_impl.cpp b/libraries/libstratosphere/source/htclow/htclow_manager_impl.cpp
index 7e9c61b7e..d4f6d2e8a 100644
--- a/libraries/libstratosphere/source/htclow/htclow_manager_impl.cpp
+++ b/libraries/libstratosphere/source/htclow/htclow_manager_impl.cpp
@@ -173,8 +173,16 @@ namespace ams::htclow {
return m_mux.SendEnd(task_id);
}
+ Result HtclowManagerImpl::WaitReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size) {
+ return m_mux.WaitReceiveBegin(out_task_id, channel, size);
+ }
+
+ Result HtclowManagerImpl::WaitReceiveEnd(u32 task_id) {
+ return m_mux.WaitReceiveEnd(task_id);
+ }
+
void HtclowManagerImpl::SetConfig(impl::ChannelInternalType channel, const ChannelConfig &config) {
- AMS_ABORT("HtclowManagerImpl::SetConfig");
+ return m_mux.SetConfig(channel, config);
}
void HtclowManagerImpl::SetDebugDriver(driver::IDriver *driver) {
diff --git a/libraries/libstratosphere/source/htclow/htclow_manager_impl.hpp b/libraries/libstratosphere/source/htclow/htclow_manager_impl.hpp
index 6839eab98..ce7eb0aea 100644
--- a/libraries/libstratosphere/source/htclow/htclow_manager_impl.hpp
+++ b/libraries/libstratosphere/source/htclow/htclow_manager_impl.hpp
@@ -74,6 +74,9 @@ namespace ams::htclow {
Result SendBegin(u32 *out_task_id, size_t *out, const void *src, size_t src_size, impl::ChannelInternalType channel);
Result SendEnd(u32 task_id);
+ Result WaitReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size);
+ Result WaitReceiveEnd(u32 task_id);
+
void SetConfig(impl::ChannelInternalType channel, const ChannelConfig &config);
void SetDebugDriver(driver::IDriver *driver);
diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux.cpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux.cpp
index 3bb6b9d19..220d28c62 100644
--- a/libraries/libstratosphere/source/htclow/mux/htclow_mux.cpp
+++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux.cpp
@@ -211,6 +211,9 @@ namespace ams::htclow::mux {
}
Result Mux::ConnectEnd(impl::ChannelInternalType channel, u32 task_id) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
/* Get the trigger for the task. */
const auto trigger = m_task_manager.GetTrigger(task_id);
@@ -255,6 +258,9 @@ namespace ams::htclow::mux {
}
Result Mux::FlushEnd(u32 task_id) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
/* Get the trigger for the task. */
const auto trigger = m_task_manager.GetTrigger(task_id);
@@ -287,6 +293,9 @@ namespace ams::htclow::mux {
}
Result Mux::ReceiveEnd(size_t *out, void *dst, size_t dst_size, impl::ChannelInternalType channel, u32 task_id) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
/* Free the task. */
m_task_manager.FreeTask(task_id);
@@ -317,6 +326,9 @@ namespace ams::htclow::mux {
}
Result Mux::SendEnd(u32 task_id) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
/* Get the trigger for the task. */
const auto trigger = m_task_manager.GetTrigger(task_id);
@@ -329,6 +341,38 @@ namespace ams::htclow::mux {
return ResultSuccess();
}
+ Result Mux::WaitReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size) {
+ return this->ReceiveBegin(out_task_id, channel, size);
+ }
+
+ Result Mux::WaitReceiveEnd(u32 task_id) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
+ /* Get the trigger for the task. */
+ const auto trigger = m_task_manager.GetTrigger(task_id);
+
+ /* Free the task. */
+ m_task_manager.FreeTask(task_id);
+
+ /* Check that we didn't hit a disconnect. */
+ R_UNLESS(trigger != EventTrigger_Disconnect, htclow::ResultInvalidChannelStateDisconnected());
+
+ return ResultSuccess();
+ }
+
+ void Mux::SetConfig(impl::ChannelInternalType channel, const ChannelConfig &config) {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
+ /* Find the channel. */
+ auto it = m_channel_impl_map.GetMap().find(channel);
+ AMS_ABORT_UNLESS(it != m_channel_impl_map.GetMap().end());
+
+ /* Perform the connection. */
+ return m_channel_impl_map[it->second].SetConfig(config);
+ }
+
void Mux::SetSendBuffer(impl::ChannelInternalType channel, void *buf, size_t buf_size, size_t max_packet_size) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux.hpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux.hpp
index 071efbe17..c3686223d 100644
--- a/libraries/libstratosphere/source/htclow/mux/htclow_mux.hpp
+++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux.hpp
@@ -74,6 +74,11 @@ namespace ams::htclow::mux {
Result SendBegin(u32 *out_task_id, size_t *out, const void *src, size_t src_size, impl::ChannelInternalType channel);
Result SendEnd(u32 task_id);
+ Result WaitReceiveBegin(u32 *out_task_id, impl::ChannelInternalType channel, size_t size);
+ Result WaitReceiveEnd(u32 task_id);
+
+ void SetConfig(impl::ChannelInternalType channel, const ChannelConfig &config);
+
void SetSendBuffer(impl::ChannelInternalType channel, void *buf, size_t buf_size, size_t max_packet_size);
void SetReceiveBuffer(impl::ChannelInternalType channel, void *buf, size_t buf_size);
void SetSendBufferWithData(impl::ChannelInternalType channel, const void *buf, size_t buf_size, size_t max_packet_size);
diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp
index 4b8aa3a9a..b465eeadf 100644
--- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp
+++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.cpp
@@ -425,6 +425,17 @@ namespace ams::htclow::mux {
return ResultSuccess();
}
+ void ChannelImpl::SetConfig(const ChannelConfig &config) {
+ /* Check our state. */
+ R_ABORT_UNLESS(this->CheckState({ChannelState_Unconnectable, ChannelState_Connectable}));
+
+ /* Set our config. */
+ m_config = config;
+
+ /* Set flow control for our send buffer. */
+ m_send_buffer.SetFlowControlEnabled(m_config.flow_control_enabled);
+ }
+
void ChannelImpl::SetSendBuffer(void *buf, size_t buf_size, size_t max_packet_size) {
/* Set buffer. */
m_send_buffer.SetBuffer(buf, buf_size);
diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.hpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.hpp
index c476aab77..5849b88a5 100644
--- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.hpp
+++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_channel_impl.hpp
@@ -80,6 +80,8 @@ namespace ams::htclow::mux {
Result DoShutdown();
+ void SetConfig(const ChannelConfig &config);
+
void SetSendBuffer(void *buf, size_t buf_size, size_t max_packet_size);
void SetReceiveBuffer(void *buf, size_t buf_size);
void SetSendBufferWithData(const void *buf, size_t buf_size, size_t max_packet_size);
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 3250bbbbb..214bc3032 100644
--- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp
+++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.cpp
@@ -41,6 +41,11 @@ namespace ams::htclow::mux {
m_version = version;
}
+ void SendBuffer::SetFlowControlEnabled(bool en) {
+ /* Set flow control enabled. */
+ m_flow_control_enabled = en;
+ }
+
void SendBuffer::MakeDataPacketHeader(PacketHeader *header, int body_size, s16 version, u64 share, u32 offset) const {
/* Set all packet fields. */
header->signature = HtcGen2Signature;
diff --git a/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.hpp b/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.hpp
index 665443459..373cece1b 100644
--- a/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.hpp
+++ b/libraries/libstratosphere/source/htclow/mux/htclow_mux_send_buffer.hpp
@@ -48,6 +48,7 @@ namespace ams::htclow::mux {
~SendBuffer();
void SetVersion(s16 version);
+ void SetFlowControlEnabled(bool en);
bool QueryNextPacket(PacketHeader *header, PacketBody *body, int *out_body_size, u64 max_data, u64 total_send_size, bool has_share, u64 share);
diff --git a/libraries/libvapours/include/vapours/results/htclow_results.hpp b/libraries/libvapours/include/vapours/results/htclow_results.hpp
index 16e65a413..eb90e2b90 100644
--- a/libraries/libvapours/include/vapours/results/htclow_results.hpp
+++ b/libraries/libvapours/include/vapours/results/htclow_results.hpp
@@ -23,6 +23,7 @@ namespace ams::htclow {
R_DEFINE_ERROR_RESULT(ConnectionFailure, 1);
R_DEFINE_ERROR_RESULT(UnknownDriverType, 3);
R_DEFINE_ERROR_RESULT(NonBlockingReceiveFailed, 5);
+ R_DEFINE_ERROR_RESULT(ChannelWaitCancelled, 8);
R_DEFINE_ERROR_RESULT(ChannelAlreadyExist, 9);
R_DEFINE_ERROR_RESULT(ChannelNotExist, 10);