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] [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<Handle> connectionStatusEvent = std::nullopt; + std::optional<MemoryBlock> 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 <cstddef> + #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<MemoryBlock>(); + 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