From 03ae0d02d8e547f7716b54171067d3fe83746eeb Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:24:37 +0300 Subject: [PATCH 1/5] [IR] Implement shmem header --- include/services/ir_user.hpp | 19 +++++++++++++ src/core/services/ir_user.cpp | 53 ++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/services/ir_user.hpp b/include/services/ir_user.hpp index 2c7b1559..213147c9 100644 --- a/include/services/ir_user.hpp +++ b/include/services/ir_user.hpp @@ -24,6 +24,25 @@ class IRUserService { void requireConnection(u32 messagePointer); std::optional connectionStatusEvent = std::nullopt; + std::optional sharedMemory = std::nullopt; + bool connectedDevice = false; + + // Header of the IR shared memory containing various bits of info + // https://www.3dbrew.org/wiki/IRUSER_Shared_Memory + struct SharedMemoryStatus { + u32 latestReceiveError; + u32 latestSharedError; + + u8 connectionStatus; + u8 connectionAttemptStatus; + u8 connectionRole; + u8 machineID; + u8 isConnected; + u8 networkID; + u8 isInitialized; // https://github.com/citra-emu/citra/blob/c10ffda91feb3476a861c47fb38641c1007b9d33/src/core/hle/service/ir/ir_user.cpp#L41 + u8 unk1; + }; + static_assert(sizeof(SharedMemoryStatus) == 16); public: IRUserService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp index a4c98a82..f80a8ac9 100644 --- a/src/core/services/ir_user.cpp +++ b/src/core/services/ir_user.cpp @@ -1,5 +1,7 @@ #include "services/ir_user.hpp" +#include + #include "ipc.hpp" #include "kernel.hpp" @@ -13,7 +15,11 @@ namespace IRUserCommands { }; } -void IRUserService::reset() { connectionStatusEvent = std::nullopt; } +void IRUserService::reset() { + connectionStatusEvent = std::nullopt; + sharedMemory = std::nullopt; + connectedDevice = false; +} void IRUserService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); @@ -40,6 +46,14 @@ void IRUserService::initializeIrnopShared(u32 messagePointer) { log("IR:USER: InitializeIrnopShared (shared mem size = %08X, sharedMemHandle = %X) (stubbed)\n", sharedMemSize, sharedMemHandle); Helpers::warn("Game is initializing IR:USER. If it explodes, this is probably why"); + KernelObject* object = kernel.getObject(sharedMemHandle, KernelObjectType::MemoryBlock); + if (object == nullptr) { + Helpers::panic("IR::InitializeIrnopShared: Shared memory object does not exist"); + } + + MemoryBlock* memoryBlock = object->getData(); + sharedMemory = *memoryBlock; + mem.write32(messagePointer, IPC::responseHeader(0x18, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -47,6 +61,13 @@ void IRUserService::initializeIrnopShared(u32 messagePointer) { void IRUserService::finalizeIrnop(u32 messagePointer) { log("IR:USER: FinalizeIrnop\n"); + if (connectedDevice) { + connectedDevice = false; + // This should also disconnect CirclePad Pro? + } + + sharedMemory = std::nullopt; + // This should disconnect any connected device de-initialize the shared memory mem.write32(messagePointer, IPC::responseHeader(0x2, 1, 0)); mem.write32(messagePointer + 4, Result::Success); @@ -69,12 +90,42 @@ void IRUserService::requireConnection(u32 messagePointer) { const u8 deviceID = mem.read8(messagePointer + 4); log("IR:USER: RequireConnection (device: %d)\n", deviceID); + // Reference: https://github.com/citra-emu/citra/blob/c10ffda91feb3476a861c47fb38641c1007b9d33/src/core/hle/service/ir/ir_user.cpp#L306 + if (sharedMemory.has_value()) { + u32 sharedMemAddress = sharedMemory.value().addr; + + // What even is this device meant to be. + if (deviceID == 1) { + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionStatus), 2); + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionRole), 2); + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, isConnected), 1); + + connectedDevice = true; + if (connectionStatusEvent.has_value()) { + kernel.signalEvent(connectionStatusEvent.value()); + } + } else { + log("IR:USER: Unknown device %d\n", deviceID); + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionStatus), 1); + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionAttemptStatus), 2); + } + } + mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } void IRUserService::disconnect(u32 messagePointer) { log("IR:USER: Disconnect\n"); + + // If there's a connected device, disconnect it and trigger the status event + if (connectedDevice) { + connectedDevice = false; + if (connectionStatusEvent.has_value()) { + kernel.signalEvent(connectionStatusEvent.value()); + } + } + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file From af8661a249333b04a8b48ce252c81cfe9e4b2712 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:46:43 +0300 Subject: [PATCH 2/5] [IR] Fix disconnect --- src/core/services/ir_user.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp index f80a8ac9..a0fbbda5 100644 --- a/src/core/services/ir_user.cpp +++ b/src/core/services/ir_user.cpp @@ -118,6 +118,13 @@ void IRUserService::requireConnection(u32 messagePointer) { void IRUserService::disconnect(u32 messagePointer) { log("IR:USER: Disconnect\n"); + if (sharedMemory.has_value()) { + u32 sharedMemAddress = sharedMemory.value().addr; + + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionStatus), 0); + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, isConnected), 0); + } + // If there's a connected device, disconnect it and trigger the status event if (connectedDevice) { connectedDevice = false; From 58db16540b28a4331e2dc17bdf3cec9b6dbb0cbe Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:52:04 +0300 Subject: [PATCH 3/5] [IR] Fix initialized byte --- src/core/services/ir_user.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp index a0fbbda5..04cc40b0 100644 --- a/src/core/services/ir_user.cpp +++ b/src/core/services/ir_user.cpp @@ -54,6 +54,9 @@ void IRUserService::initializeIrnopShared(u32 messagePointer) { MemoryBlock* memoryBlock = object->getData(); sharedMemory = *memoryBlock; + // Set the initialized byte in shared mem to 1 + mem.write8(memoryBlock->addr + offsetof(SharedMemoryStatus, isInitialized), 1); + mem.write32(messagePointer, IPC::responseHeader(0x18, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } From cfcf757e70442491854792486bbfd4f6e3b84ac1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 13 Jul 2023 16:31:19 +0300 Subject: [PATCH 4/5] [IR] More bonk --- src/core/services/ir_user.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp index 04cc40b0..0d6286ae 100644 --- a/src/core/services/ir_user.cpp +++ b/src/core/services/ir_user.cpp @@ -56,6 +56,8 @@ void IRUserService::initializeIrnopShared(u32 messagePointer) { // Set the initialized byte in shared mem to 1 mem.write8(memoryBlock->addr + offsetof(SharedMemoryStatus, isInitialized), 1); + mem.write64(memoryBlock->addr + 0x10, 0); // Initialize the receive buffer info to all 0s + mem.write64(memoryBlock->addr + 0x18, 0); mem.write32(messagePointer, IPC::responseHeader(0x18, 1, 0)); mem.write32(messagePointer + 4, Result::Success); @@ -97,7 +99,7 @@ void IRUserService::requireConnection(u32 messagePointer) { if (sharedMemory.has_value()) { u32 sharedMemAddress = sharedMemory.value().addr; - // What even is this device meant to be. + // Seems to be the CirclePad Pro ID if (deviceID == 1) { mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionStatus), 2); mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionRole), 2); From 3ad0fc6a564cda013f7da08f6860d380b36fbb67 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 13 Jul 2023 20:28:32 +0300 Subject: [PATCH 5/5] IR please stop --- include/services/ir_user.hpp | 12 +++++++++++- src/core/services/ir_user.cpp | 31 ++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/include/services/ir_user.hpp b/include/services/ir_user.hpp index 213147c9..186d9717 100644 --- a/include/services/ir_user.hpp +++ b/include/services/ir_user.hpp @@ -11,6 +11,10 @@ class Kernel; class IRUserService { + enum class DeviceID : u8 { + CirclePadPro = 1, + }; + Handle handle = KernelHandles::IR_USER; Memory& mem; Kernel& kernel; @@ -20,10 +24,16 @@ class IRUserService { void disconnect(u32 messagePointer); void finalizeIrnop(u32 messagePointer); void getConnectionStatusEvent(u32 messagePointer); + void getReceiveEvent(u32 messagePointer); void initializeIrnopShared(u32 messagePointer); void requireConnection(u32 messagePointer); + void sendIrnop(u32 messagePointer); + + using IREvent = std::optional; + + IREvent connectionStatusEvent = std::nullopt; + IREvent receiveEvent = std::nullopt; - std::optional connectionStatusEvent = std::nullopt; std::optional sharedMemory = std::nullopt; bool connectedDevice = false; diff --git a/src/core/services/ir_user.cpp b/src/core/services/ir_user.cpp index 0d6286ae..47a2299a 100644 --- a/src/core/services/ir_user.cpp +++ b/src/core/services/ir_user.cpp @@ -10,13 +10,16 @@ namespace IRUserCommands { FinalizeIrnop = 0x00020000, RequireConnection = 0x00060040, Disconnect = 0x00090000, + GetReceiveEvent = 0x000A0000, GetConnectionStatusEvent = 0x000C0000, + SendIrnop = 0x000D0042, InitializeIrnopShared = 0x00180182 }; } void IRUserService::reset() { connectionStatusEvent = std::nullopt; + receiveEvent = std::nullopt; sharedMemory = std::nullopt; connectedDevice = false; } @@ -26,9 +29,11 @@ void IRUserService::handleSyncRequest(u32 messagePointer) { switch (command) { case IRUserCommands::Disconnect: disconnect(messagePointer); break; case IRUserCommands::FinalizeIrnop: finalizeIrnop(messagePointer); break; + case IRUserCommands::GetReceiveEvent: getReceiveEvent(messagePointer); break; case IRUserCommands::GetConnectionStatusEvent: getConnectionStatusEvent(messagePointer); break; case IRUserCommands::InitializeIrnopShared: initializeIrnopShared(messagePointer); break; case IRUserCommands::RequireConnection: requireConnection(messagePointer); break; + case IRUserCommands::SendIrnop: sendIrnop(messagePointer); break; default: Helpers::panic("ir:USER service requested. Command: %08X\n", command); } } @@ -84,6 +89,7 @@ void IRUserService::getConnectionStatusEvent(u32 messagePointer) { if (!connectionStatusEvent.has_value()) { connectionStatusEvent = kernel.makeEvent(ResetType::OneShot); } + //kernel.signalEvent(connectionStatusEvent.value()); // ?????????????? mem.write32(messagePointer, IPC::responseHeader(0xC, 1, 2)); mem.write32(messagePointer + 4, Result::Success); @@ -91,6 +97,20 @@ void IRUserService::getConnectionStatusEvent(u32 messagePointer) { mem.write32(messagePointer + 12, connectionStatusEvent.value()); } +void IRUserService::getReceiveEvent(u32 messagePointer) { + log("IR:USER: GetReceiveEvent\n"); + + if (!receiveEvent.has_value()) { + receiveEvent = kernel.makeEvent(ResetType::OneShot); + } + + mem.write32(messagePointer, IPC::responseHeader(0xA, 1, 2)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0x40000000); + // TOOD: Descriptor here + mem.write32(messagePointer + 12, receiveEvent.value()); +} + void IRUserService::requireConnection(u32 messagePointer) { const u8 deviceID = mem.read8(messagePointer + 4); log("IR:USER: RequireConnection (device: %d)\n", deviceID); @@ -99,9 +119,8 @@ void IRUserService::requireConnection(u32 messagePointer) { if (sharedMemory.has_value()) { u32 sharedMemAddress = sharedMemory.value().addr; - // Seems to be the CirclePad Pro ID - if (deviceID == 1) { - mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionStatus), 2); + if (deviceID == u8(DeviceID::CirclePadPro)) { + mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionStatus), 2); // Citra uses 2 here but only 1 works?? mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, connectionRole), 2); mem.write8(sharedMemAddress + offsetof(SharedMemoryStatus, isConnected), 1); @@ -120,6 +139,12 @@ void IRUserService::requireConnection(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void IRUserService::sendIrnop(u32 messagePointer) { + Helpers::panic("IR:USER: SendIrnop\n"); + + mem.write32(messagePointer + 4, Result::Success); +} + void IRUserService::disconnect(u32 messagePointer) { log("IR:USER: Disconnect\n");