diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp index f06dd552f..1dc09f300 100644 --- a/src/core/hle/service/ir/ir.cpp +++ b/src/core/hle/service/ir/ir.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "core/hle/service/ir/ir.h" #include "core/hle/service/ir/ir_rst.h" #include "core/hle/service/ir/ir_u.h" @@ -11,23 +12,27 @@ namespace Service { namespace IR { -void Init() { - AddService(new IR_RST_Interface); - AddService(new IR_U_Interface); - AddService(new IR_User_Interface); - - InitUser(); - InitRST(); -} - -void Shutdown() { - ShutdownUser(); - ShutdownRST(); -} +static std::weak_ptr current_ir_rst; +static std::weak_ptr current_ir_user; void ReloadInputDevices() { - ReloadInputDevicesUser(); - ReloadInputDevicesRST(); + if (auto ir_user = current_ir_user.lock()) + ir_user->ReloadInputDevices(); + + if (auto ir_rst = current_ir_rst.lock()) + ir_rst->ReloadInputDevices(); +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + std::make_shared()->InstallAsService(service_manager); + + auto ir_user = std::make_shared(); + ir_user->InstallAsService(service_manager); + current_ir_user = ir_user; + + auto ir_rst = std::make_shared(); + ir_rst->InstallAsService(service_manager); + current_ir_rst = ir_rst; } } // namespace IR diff --git a/src/core/hle/service/ir/ir.h b/src/core/hle/service/ir/ir.h index 6be3e950c..3b1a32eac 100644 --- a/src/core/hle/service/ir/ir.h +++ b/src/core/hle/service/ir/ir.h @@ -4,20 +4,17 @@ #pragma once +namespace SM { +class ServiceManager; +} + namespace Service { - -class Interface; - namespace IR { -/// Initialize IR service -void Init(); - -/// Shutdown IR service -void Shutdown(); - /// Reload input devices. Used when input configuration changed void ReloadInputDevices(); +void InstallInterfaces(SM::ServiceManager& service_manager); + } // namespace IR } // namespace Service diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 71da32f17..84690aecf 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -2,15 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include "common/bit_field.h" #include "core/core_timing.h" -#include "core/frontend/input.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" -#include "core/hle/service/ir/ir.h" #include "core/hle/service/ir/ir_rst.h" #include "core/settings.h" @@ -48,18 +45,7 @@ struct SharedMem { static_assert(sizeof(SharedMem) == 0x98, "SharedMem has wrong size!"); -static Kernel::SharedPtr update_event; -static Kernel::SharedPtr shared_memory; -static u32 next_pad_index; -static CoreTiming::EventType* update_callback_id; -static std::unique_ptr zl_button; -static std::unique_ptr zr_button; -static std::unique_ptr c_stick; -static std::atomic is_device_reload_pending; -static bool raw_c_stick; -static int update_period; - -static void LoadInputDevices() { +void IR_RST::LoadInputDevices() { zl_button = Input::CreateDevice( Settings::values.buttons[Settings::NativeButton::ZL]); zr_button = Input::CreateDevice( @@ -68,13 +54,13 @@ static void LoadInputDevices() { Settings::values.analogs[Settings::NativeAnalog::CStick]); } -static void UnloadInputDevices() { +void IR_RST::UnloadInputDevices() { zl_button = nullptr; zr_button = nullptr; c_stick = nullptr; } -static void UpdateCallback(u64 userdata, int cycles_late) { +void IR_RST::UpdateCallback(u64 userdata, int cycles_late) { SharedMem* mem = reinterpret_cast(shared_memory->GetPointer()); if (is_device_reload_pending.exchange(false)) @@ -133,30 +119,15 @@ static void UpdateCallback(u64 userdata, int cycles_late) { CoreTiming::ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id); } -/** - * IR::GetHandles service function - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Translate header, used by the ARM11-kernel - * 3 : Shared memory handle - * 4 : Event handle - */ -static void GetHandles(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 0, 0); +void IR_RST::GetHandles(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x01, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); rb.Push(RESULT_SUCCESS); - rb.PushMoveHandles(Kernel::g_handle_table.Create(Service::IR::shared_memory).Unwrap(), - Kernel::g_handle_table.Create(Service::IR::update_event).Unwrap()); + rb.PushMoveObjects(shared_memory, update_event); } -/** - * IR::Initialize service function - * Inputs: - * 1 : pad state update period in ms - * 2 : bool output raw c-stick data - */ -static void Initialize(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 0); +void IR_RST::Initialize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x02, 2, 0); update_period = static_cast(rp.Pop()); raw_c_stick = rp.Pop(); @@ -173,8 +144,8 @@ static void Initialize(Interface* self) { LOG_DEBUG(Service_IR, "called. update_period=%d, raw_c_stick=%d", update_period, raw_c_stick); } -static void Shutdown(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); +void IR_RST::Shutdown(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x03, 0, 0); CoreTiming::UnscheduleEvent(update_callback_id, 0); UnloadInputDevices(); @@ -184,18 +155,7 @@ static void Shutdown(Interface* self) { LOG_DEBUG(Service_IR, "called"); } -const Interface::FunctionInfo FunctionTable[] = { - {0x00010000, GetHandles, "GetHandles"}, - {0x00020080, Initialize, "Initialize"}, - {0x00030000, Shutdown, "Shutdown"}, - {0x00090000, nullptr, "WriteToTwoFields"}, -}; - -IR_RST_Interface::IR_RST_Interface() { - Register(FunctionTable); -} - -void InitRST() { +IR_RST::IR_RST() : ServiceFramework("ir:rst", 1) { using namespace Kernel; // Note: these two kernel objects are even available before Initialize service function is // called. @@ -204,16 +164,23 @@ void InitRST() { 0, MemoryRegion::BASE, "IRRST:SharedMemory"); update_event = Event::Create(ResetType::OneShot, "IRRST:UpdateEvent"); - update_callback_id = CoreTiming::RegisterEvent("IRRST:UpdateCallBack", UpdateCallback); + update_callback_id = + CoreTiming::RegisterEvent("IRRST:UpdateCallBack", [this](u64 userdata, int cycles_late) { + UpdateCallback(userdata, cycles_late); + }); + + static const FunctionInfo functions[] = { + {0x00010000, &IR_RST::GetHandles, "GetHandles"}, + {0x00020080, &IR_RST::Initialize, "Initialize"}, + {0x00030000, &IR_RST::Shutdown, "Shutdown"}, + {0x00090000, nullptr, "WriteToTwoFields"}, + }; + RegisterHandlers(functions); } -void ShutdownRST() { - shared_memory = nullptr; - update_event = nullptr; - UnloadInputDevices(); -} +IR_RST::~IR_RST() = default; -void ReloadInputDevicesRST() { +void IR_RST::ReloadInputDevices() { is_device_reload_pending.store(true); } diff --git a/src/core/hle/service/ir/ir_rst.h b/src/core/hle/service/ir/ir_rst.h index d932bb7e5..621c1b51c 100644 --- a/src/core/hle/service/ir/ir_rst.h +++ b/src/core/hle/service/ir/ir_rst.h @@ -4,25 +4,76 @@ #pragma once +#include +#include +#include "core/frontend/input.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/service/service.h" +namespace Kernel { +class Event; +class SharedMemory; +} + +namespace CoreTiming { +class EventType; +}; + namespace Service { namespace IR { -class IR_RST_Interface : public Service::Interface { +/// Interface to "ir:rst" service +class IR_RST final : public ServiceFramework { public: - IR_RST_Interface(); + IR_RST(); + ~IR_RST(); + void ReloadInputDevices(); - std::string GetPortName() const override { - return "ir:rst"; - } +private: + /** + * GetHandles service function + * No input + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Handle translation descriptor + * 3 : Shared memory handle + * 4 : Event handle + */ + void GetHandles(Kernel::HLERequestContext& ctx); + + /** + * Initialize service function + * Inputs: + * 1 : pad state update period in ms + * 2 : bool output raw c-stick data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void Initialize(Kernel::HLERequestContext& ctx); + + /** + * Shutdown service function + * No input + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void Shutdown(Kernel::HLERequestContext& ctx); + + void LoadInputDevices(); + void UnloadInputDevices(); + void UpdateCallback(u64 userdata, int cycles_late); + + Kernel::SharedPtr update_event; + Kernel::SharedPtr shared_memory; + u32 next_pad_index{0}; + CoreTiming::EventType* update_callback_id; + std::unique_ptr zl_button; + std::unique_ptr zr_button; + std::unique_ptr c_stick; + std::atomic is_device_reload_pending{false}; + bool raw_c_stick{false}; + int update_period{0}; }; -void InitRST(); -void ShutdownRST(); - -/// Reload input devices. Used when input configuration changed -void ReloadInputDevicesRST(); - } // namespace IR } // namespace Service diff --git a/src/core/hle/service/ir/ir_u.cpp b/src/core/hle/service/ir/ir_u.cpp index ce00d5732..23ccbf33f 100644 --- a/src/core/hle/service/ir/ir_u.cpp +++ b/src/core/hle/service/ir/ir_u.cpp @@ -7,31 +7,28 @@ namespace Service { namespace IR { -const Interface::FunctionInfo FunctionTable[] = { - // clang-format off - {0x00010000, nullptr, "Initialize"}, - {0x00020000, nullptr, "Shutdown"}, - {0x00030042, nullptr, "StartSendTransfer"}, - {0x00040000, nullptr, "WaitSendTransfer"}, - {0x000500C2, nullptr, "StartRecvTransfer"}, - {0x00060000, nullptr, "WaitRecvTransfer"}, - {0x00070080, nullptr, "GetRecvTransferCount"}, - {0x00080000, nullptr, "GetSendState"}, - {0x00090040, nullptr, "SetBitRate"}, - {0x000A0000, nullptr, "GetBitRate"}, - {0x000B0040, nullptr, "SetIRLEDState"}, - {0x000C0000, nullptr, "GetIRLEDRecvState"}, - {0x000D0000, nullptr, "GetSendFinishedEvent"}, - {0x000E0000, nullptr, "GetRecvFinishedEvent"}, - {0x000F0000, nullptr, "GetTransferState"}, - {0x00100000, nullptr, "GetErrorStatus"}, - {0x00110040, nullptr, "SetSleepModeActive"}, - {0x00120040, nullptr, "SetSleepModeState"}, - // clang-format on -}; - -IR_U_Interface::IR_U_Interface() { - Register(FunctionTable); +IR_U::IR_U() : ServiceFramework("ir:u", 1) { + static const FunctionInfo functions[] = { + {0x00010000, nullptr, "Initialize"}, + {0x00020000, nullptr, "Shutdown"}, + {0x00030042, nullptr, "StartSendTransfer"}, + {0x00040000, nullptr, "WaitSendTransfer"}, + {0x000500C2, nullptr, "StartRecvTransfer"}, + {0x00060000, nullptr, "WaitRecvTransfer"}, + {0x00070080, nullptr, "GetRecvTransferCount"}, + {0x00080000, nullptr, "GetSendState"}, + {0x00090040, nullptr, "SetBitRate"}, + {0x000A0000, nullptr, "GetBitRate"}, + {0x000B0040, nullptr, "SetIRLEDState"}, + {0x000C0000, nullptr, "GetIRLEDRecvState"}, + {0x000D0000, nullptr, "GetSendFinishedEvent"}, + {0x000E0000, nullptr, "GetRecvFinishedEvent"}, + {0x000F0000, nullptr, "GetTransferState"}, + {0x00100000, nullptr, "GetErrorStatus"}, + {0x00110040, nullptr, "SetSleepModeActive"}, + {0x00120040, nullptr, "SetSleepModeState"}, + }; + RegisterHandlers(functions); } } // namespace IR diff --git a/src/core/hle/service/ir/ir_u.h b/src/core/hle/service/ir/ir_u.h index 056d2ce1a..16c117fea 100644 --- a/src/core/hle/service/ir/ir_u.h +++ b/src/core/hle/service/ir/ir_u.h @@ -9,13 +9,10 @@ namespace Service { namespace IR { -class IR_U_Interface : public Service::Interface { +/// Interface to "ir:u" service +class IR_U final : public ServiceFramework { public: - IR_U_Interface(); - - std::string GetPortName() const override { - return "ir:u"; - } + IR_U(); }; } // namespace IR diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp index 1c0af1572..aee4b1305 100644 --- a/src/core/hle/service/ir/ir_user.cpp +++ b/src/core/hle/service/ir/ir_user.cpp @@ -4,14 +4,12 @@ #include #include -#include #include "common/string_util.h" #include "common/swap.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/service/ir/extra_hid.h" -#include "core/hle/service/ir/ir.h" #include "core/hle/service/ir/ir_user.h" namespace Service { @@ -183,14 +181,8 @@ private: u32 max_data_size; }; -static Kernel::SharedPtr conn_status_event, send_event, receive_event; -static Kernel::SharedPtr shared_memory; -static std::unique_ptr extra_hid; -static IRDevice* connected_device; -static boost::optional receive_buffer; - /// Wraps the payload into packet and puts it to the receive buffer -static void PutToReceive(const std::vector& payload) { +void IR_USER::PutToReceive(const std::vector& payload) { LOG_TRACE(Service_IR, "called, data=%s", Common::ArrayToString(payload.data(), payload.size()).c_str()); size_t size = payload.size(); @@ -237,44 +229,22 @@ static void PutToReceive(const std::vector& payload) { } } -/** - * IR::InitializeIrNopShared service function - * Initializes ir:USER service with a user provided shared memory. The shared memory is configured - * to shared mode (with SharedMemoryHeader at the beginning of the shared memory). - * Inputs: - * 1 : Size of shared memory - * 2 : Recv buffer size - * 3 : Recv buffer packet count - * 4 : Send buffer size - * 5 : Send buffer packet count - * 6 : BaudRate (u8) - * 7 : 0 (Handle descriptor) - * 8 : Handle of shared memory - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void InitializeIrNopShared(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x18, 6, 2); +void IR_USER::InitializeIrNopShared(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x18, 6, 2); const u32 shared_buff_size = rp.Pop(); const u32 recv_buff_size = rp.Pop(); const u32 recv_buff_packet_count = rp.Pop(); const u32 send_buff_size = rp.Pop(); const u32 send_buff_packet_count = rp.Pop(); const u8 baud_rate = rp.Pop(); - const Kernel::Handle handle = rp.PopHandle(); + shared_memory = rp.PopObject(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - shared_memory = Kernel::g_handle_table.Get(handle); - if (!shared_memory) { - LOG_CRITICAL(Service_IR, "invalid shared memory handle 0x%08X", handle); - rb.Push(IPC::ERR_INVALID_HANDLE); - return; - } shared_memory->name = "IR_USER: shared memory"; - receive_buffer = - BufferManager(shared_memory, 0x10, 0x20, recv_buff_packet_count, recv_buff_size); + receive_buffer = std::make_unique(shared_memory, 0x10, 0x20, + recv_buff_packet_count, recv_buff_size); SharedMemoryHeader shared_memory_init{}; shared_memory_init.initialized = 1; std::memcpy(shared_memory->GetPointer(), &shared_memory_init, sizeof(SharedMemoryHeader)); @@ -283,23 +253,13 @@ static void InitializeIrNopShared(Interface* self) { LOG_INFO(Service_IR, "called, shared_buff_size=%u, recv_buff_size=%u, " "recv_buff_packet_count=%u, send_buff_size=%u, " - "send_buff_packet_count=%u, baud_rate=%u, handle=0x%08X", + "send_buff_packet_count=%u, baud_rate=%u", shared_buff_size, recv_buff_size, recv_buff_packet_count, send_buff_size, - send_buff_packet_count, baud_rate, handle); + send_buff_packet_count, baud_rate); } -/** - * IR::RequireConnection service function - * Searches for an IR device and connects to it. After connecting to the device, applications can - * use SendIrNop function, ReceiveIrNop function (or read from the buffer directly) to communicate - * with the device. - * Inputs: - * 1 : device ID? always 1 for circle pad pro - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void RequireConnection(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0); +void IR_USER::RequireConnection(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x06, 1, 0); const u8 device_id = rp.Pop(); u8* shared_memory_ptr = shared_memory->GetPointer(); @@ -325,47 +285,25 @@ static void RequireConnection(Interface* self) { LOG_INFO(Service_IR, "called, device_id = %u", device_id); } -/** - * IR::GetReceiveEvent service function - * Gets an event that is signaled when a packet is received from the IR device. - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : 0 (Handle descriptor) - * 3 : Receive event handle - */ -void GetReceiveEvent(Interface* self) { - IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x0A, 1, 2); +void IR_USER::GetReceiveEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb(ctx, 0x0A, 1, 2); rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles(Kernel::g_handle_table.Create(Service::IR::receive_event).Unwrap()); + rb.PushCopyObjects(receive_event); LOG_INFO(Service_IR, "called"); } -/** - * IR::GetSendEvent service function - * Gets an event that is signaled when the sending of a packet is complete - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : 0 (Handle descriptor) - * 3 : Send event handle - */ -void GetSendEvent(Interface* self) { - IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x0B, 1, 2); +void IR_USER::GetSendEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb(ctx, 0x0B, 1, 2); rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles(Kernel::g_handle_table.Create(Service::IR::send_event).Unwrap()); + rb.PushCopyObjects(send_event); LOG_INFO(Service_IR, "called"); } -/** - * IR::Disconnect service function - * Disconnects from the current connected IR device. - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void Disconnect(Interface* self) { +void IR_USER::Disconnect(Kernel::HLERequestContext& ctx) { if (connected_device) { connected_device->OnDisconnect(); connected_device = nullptr; @@ -376,67 +314,41 @@ static void Disconnect(Interface* self) { shared_memory_ptr[offsetof(SharedMemoryHeader, connection_status)] = 0; shared_memory_ptr[offsetof(SharedMemoryHeader, connected)] = 0; - IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x09, 1, 0); + IPC::RequestBuilder rb(ctx, 0x09, 1, 0); rb.Push(RESULT_SUCCESS); LOG_INFO(Service_IR, "called"); } -/** - * IR::GetConnectionStatusEvent service function - * Gets an event that is signaled when the connection status is changed - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : 0 (Handle descriptor) - * 3 : Connection Status Event handle - */ -static void GetConnectionStatusEvent(Interface* self) { - IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x0C, 1, 2); +void IR_USER::GetConnectionStatusEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb(ctx, 0x0C, 1, 2); rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles(Kernel::g_handle_table.Create(Service::IR::conn_status_event).Unwrap()); + rb.PushCopyObjects(conn_status_event); LOG_INFO(Service_IR, "called"); } -/** - * IR::FinalizeIrNop service function - * Finalize ir:USER service. - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void FinalizeIrNop(Interface* self) { +void IR_USER::FinalizeIrNop(Kernel::HLERequestContext& ctx) { if (connected_device) { connected_device->OnDisconnect(); connected_device = nullptr; } shared_memory = nullptr; - receive_buffer = boost::none; + receive_buffer = nullptr; - IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x02, 1, 0); + IPC::RequestBuilder rb(ctx, 0x02, 1, 0); rb.Push(RESULT_SUCCESS); LOG_INFO(Service_IR, "called"); } -/** - * IR::SendIrNop service function - * Sends a packet to the connected IR device - * Inpus: - * 1 : Size of data to send - * 2 : 2 + (size << 14) (Static buffer descriptor) - * 3 : Data buffer address - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void SendIrNop(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 1, 2); +void IR_USER::SendIrNop(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0D, 1, 2); const u32 size = rp.Pop(); - const VAddr address = rp.PopStaticBuffer(nullptr); - - std::vector buffer(size); - Memory::ReadBlock(address, buffer.data(), size); + std::vector buffer = rp.PopStaticBuffer(); + ASSERT(size == buffer.size()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); if (connected_device) { @@ -452,18 +364,8 @@ static void SendIrNop(Interface* self) { LOG_TRACE(Service_IR, "called, data=%s", Common::ArrayToString(buffer.data(), size).c_str()); } -/** - * IR::ReleaseReceivedData function - * Release a specified amount of packet from the receive buffer. This is called after the - * application reads received packet from the buffer directly, to release the buffer space for - * future packets. - * Inpus: - * 1 : Number of packets to release - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void ReleaseReceivedData(Interface* self) { - IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x19, 1, 0); +void IR_USER::ReleaseReceivedData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x19, 1, 0); u32 count = rp.Pop(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); @@ -479,72 +381,55 @@ static void ReleaseReceivedData(Interface* self) { LOG_TRACE(Service_IR, "called, count=%u", count); } -const Interface::FunctionInfo FunctionTable[] = { - {0x00010182, nullptr, "InitializeIrNop"}, - {0x00020000, FinalizeIrNop, "FinalizeIrNop"}, - {0x00030000, nullptr, "ClearReceiveBuffer"}, - {0x00040000, nullptr, "ClearSendBuffer"}, - {0x000500C0, nullptr, "WaitConnection"}, - {0x00060040, RequireConnection, "RequireConnection"}, - {0x000702C0, nullptr, "AutoConnection"}, - {0x00080000, nullptr, "AnyConnection"}, - {0x00090000, Disconnect, "Disconnect"}, - {0x000A0000, GetReceiveEvent, "GetReceiveEvent"}, - {0x000B0000, GetSendEvent, "GetSendEvent"}, - {0x000C0000, GetConnectionStatusEvent, "GetConnectionStatusEvent"}, - {0x000D0042, SendIrNop, "SendIrNop"}, - {0x000E0042, nullptr, "SendIrNopLarge"}, - {0x000F0040, nullptr, "ReceiveIrnop"}, - {0x00100042, nullptr, "ReceiveIrnopLarge"}, - {0x00110040, nullptr, "GetLatestReceiveErrorResult"}, - {0x00120040, nullptr, "GetLatestSendErrorResult"}, - {0x00130000, nullptr, "GetConnectionStatus"}, - {0x00140000, nullptr, "GetTryingToConnectStatus"}, - {0x00150000, nullptr, "GetReceiveSizeFreeAndUsed"}, - {0x00160000, nullptr, "GetSendSizeFreeAndUsed"}, - {0x00170000, nullptr, "GetConnectionRole"}, - {0x00180182, InitializeIrNopShared, "InitializeIrNopShared"}, - {0x00190040, ReleaseReceivedData, "ReleaseReceivedData"}, - {0x001A0040, nullptr, "SetOwnMachineId"}, -}; +IR_USER::IR_USER() : ServiceFramework("ir:USER", 1) { + const FunctionInfo functions[] = { + {0x00010182, nullptr, "InitializeIrNop"}, + {0x00020000, &IR_USER::FinalizeIrNop, "FinalizeIrNop"}, + {0x00030000, nullptr, "ClearReceiveBuffer"}, + {0x00040000, nullptr, "ClearSendBuffer"}, + {0x000500C0, nullptr, "WaitConnection"}, + {0x00060040, &IR_USER::RequireConnection, "RequireConnection"}, + {0x000702C0, nullptr, "AutoConnection"}, + {0x00080000, nullptr, "AnyConnection"}, + {0x00090000, &IR_USER::Disconnect, "Disconnect"}, + {0x000A0000, &IR_USER::GetReceiveEvent, "GetReceiveEvent"}, + {0x000B0000, &IR_USER::GetSendEvent, "GetSendEvent"}, + {0x000C0000, &IR_USER::GetConnectionStatusEvent, "GetConnectionStatusEvent"}, + {0x000D0042, &IR_USER::SendIrNop, "SendIrNop"}, + {0x000E0042, nullptr, "SendIrNopLarge"}, + {0x000F0040, nullptr, "ReceiveIrnop"}, + {0x00100042, nullptr, "ReceiveIrnopLarge"}, + {0x00110040, nullptr, "GetLatestReceiveErrorResult"}, + {0x00120040, nullptr, "GetLatestSendErrorResult"}, + {0x00130000, nullptr, "GetConnectionStatus"}, + {0x00140000, nullptr, "GetTryingToConnectStatus"}, + {0x00150000, nullptr, "GetReceiveSizeFreeAndUsed"}, + {0x00160000, nullptr, "GetSendSizeFreeAndUsed"}, + {0x00170000, nullptr, "GetConnectionRole"}, + {0x00180182, &IR_USER::InitializeIrNopShared, "InitializeIrNopShared"}, + {0x00190040, &IR_USER::ReleaseReceivedData, "ReleaseReceivedData"}, + {0x001A0040, nullptr, "SetOwnMachineId"}, + }; + RegisterHandlers(functions); -IR_User_Interface::IR_User_Interface() { - Register(FunctionTable); -} - -void InitUser() { using namespace Kernel; - shared_memory = nullptr; - conn_status_event = Event::Create(ResetType::OneShot, "IR:ConnectionStatusEvent"); send_event = Event::Create(ResetType::OneShot, "IR:SendEvent"); receive_event = Event::Create(ResetType::OneShot, "IR:ReceiveEvent"); - receive_buffer = boost::none; - - extra_hid = std::make_unique(PutToReceive); - - connected_device = nullptr; + extra_hid = + std::make_unique([this](const std::vector& data) { PutToReceive(data); }); } -void ShutdownUser() { +IR_USER::~IR_USER() { if (connected_device) { connected_device->OnDisconnect(); - connected_device = nullptr; } - - extra_hid = nullptr; - receive_buffer = boost::none; - shared_memory = nullptr; - conn_status_event = nullptr; - send_event = nullptr; - receive_event = nullptr; } -void ReloadInputDevicesUser() { - if (extra_hid) - extra_hid->RequestInputDevicesReload(); +void IR_USER::ReloadInputDevices() { + extra_hid->RequestInputDevicesReload(); } IRDevice::IRDevice(SendFunc send_func_) : send_func(send_func_) {} diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h index 930650406..64673293f 100644 --- a/src/core/hle/service/ir/ir_user.h +++ b/src/core/hle/service/ir/ir_user.h @@ -5,11 +5,25 @@ #pragma once #include +#include +#include #include "core/hle/service/service.h" +namespace Kernel { +class Event; +class SharedMemory; +} + +namespace CoreTiming { +class EventType; +}; + namespace Service { namespace IR { +class BufferManager; +class ExtraHID; + /// An interface representing a device that can communicate with 3DS via ir:USER service class IRDevice { public: @@ -39,20 +53,126 @@ private: const SendFunc send_func; }; -class IR_User_Interface : public Service::Interface { +/// Interface to "ir:USER" service +class IR_USER final : public ServiceFramework { public: - IR_User_Interface(); + IR_USER(); + ~IR_USER(); - std::string GetPortName() const override { - return "ir:USER"; - } + void ReloadInputDevices(); + +private: + /** + * InitializeIrNopShared service function + * Initializes ir:USER service with a user provided shared memory. The shared memory is + * configured + * to shared mode (with SharedMemoryHeader at the beginning of the shared memory). + * Inputs: + * 1 : Size of shared memory + * 2 : Recv buffer size + * 3 : Recv buffer packet count + * 4 : Send buffer size + * 5 : Send buffer packet count + * 6 : BaudRate (u8) + * 7 : 0 (Handle descriptor) + * 8 : Handle of shared memory + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void InitializeIrNopShared(Kernel::HLERequestContext& ctx); + + /** + * RequireConnection service function + * Searches for an IR device and connects to it. After connecting to the device, applications + * can + * use SendIrNop function, ReceiveIrNop function (or read from the buffer directly) to + * communicate + * with the device. + * Inputs: + * 1 : device ID? always 1 for circle pad pro + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void RequireConnection(Kernel::HLERequestContext& ctx); + + /** + * GetReceiveEvent service function + * Gets an event that is signaled when a packet is received from the IR device. + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : 0 (Handle descriptor) + * 3 : Receive event handle + */ + void GetReceiveEvent(Kernel::HLERequestContext& ctx); + + /** + * GetSendEvent service function + * Gets an event that is signaled when the sending of a packet is complete + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : 0 (Handle descriptor) + * 3 : Send event handle + */ + void GetSendEvent(Kernel::HLERequestContext& ctx); + + /** + * Disconnect service function + * Disconnects from the current connected IR device. + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void Disconnect(Kernel::HLERequestContext& ctx); + + /** + * GetConnectionStatusEvent service function + * Gets an event that is signaled when the connection status is changed + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : 0 (Handle descriptor) + * 3 : Connection Status Event handle + */ + void GetConnectionStatusEvent(Kernel::HLERequestContext& ctx); + + /** + * FinalizeIrNop service function + * Finalize ir:USER service. + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void FinalizeIrNop(Kernel::HLERequestContext& ctx); + + /** + * SendIrNop service function + * Sends a packet to the connected IR device + * Inpus: + * 1 : Size of data to send + * 2 : 2 + (size << 14) (Static buffer descriptor) + * 3 : Data buffer address + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void SendIrNop(Kernel::HLERequestContext& ctx); + + /** + * ReleaseReceivedData function + * Release a specified amount of packet from the receive buffer. This is called after the + * application reads received packet from the buffer directly, to release the buffer space for + * future packets. + * Inpus: + * 1 : Number of packets to release + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void ReleaseReceivedData(Kernel::HLERequestContext& ctx); + + void PutToReceive(const std::vector& payload); + + Kernel::SharedPtr conn_status_event, send_event, receive_event; + Kernel::SharedPtr shared_memory; + IRDevice* connected_device{nullptr}; + std::unique_ptr receive_buffer; + std::unique_ptr extra_hid; }; -void InitUser(); -void ShutdownUser(); - -/// Reload input devices. Used when input configuration changed -void ReloadInputDevicesUser(); - } // namespace IR } // namespace Service diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5456890b2..d8925f773 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -275,7 +275,7 @@ void Init() { DLP::Init(); FRD::Init(); HID::Init(); - IR::Init(); + IR::InstallInterfaces(*SM::g_service_manager); MVD::Init(); NDM::Init(); NEWS::Init(); @@ -307,7 +307,6 @@ void Shutdown() { NIM::Shutdown(); NEWS::Shutdown(); NDM::Shutdown(); - IR::Shutdown(); HID::Shutdown(); FRD::Shutdown(); DLP::Shutdown();