diff --git a/include/services/cam.hpp b/include/services/cam.hpp index 3ff80a327..977292099 100644 --- a/include/services/cam.hpp +++ b/include/services/cam.hpp @@ -1,21 +1,33 @@ #pragma once +#include +#include + #include "helpers.hpp" #include "kernel_types.hpp" #include "logger.hpp" #include "memory.hpp" #include "result/result.hpp" +// Yay, circular dependencies! +class Kernel; + class CAMService { Handle handle = KernelHandles::CAM; Memory& mem; + Kernel& kernel; MAKE_LOG_FUNCTION(log, camLogger) + using Event = std::optional; + static constexpr size_t portCount = 4; // PORT_NONE, PORT_CAM1, PORT_CAM2, PORT_BOTH + std::array bufferErrorInterruptEvents; + // Service commands void driverInitialize(u32 messagePointer); void getMaxLines(u32 messagePointer); + void getBufferErrorInterruptEvent(u32 messagePointer); -public: - CAMService(Memory& mem) : mem(mem) {} + public: + CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} void reset(); void handleSyncRequest(u32 messagePointer); }; \ No newline at end of file diff --git a/src/core/services/cam.cpp b/src/core/services/cam.cpp index ea21cf9dd..e0acab37e 100644 --- a/src/core/services/cam.cpp +++ b/src/core/services/cam.cpp @@ -1,19 +1,22 @@ #include "services/cam.hpp" #include "ipc.hpp" +#include "kernel.hpp" namespace CAMCommands { enum : u32 { + GetBufferErrorInterruptEvent = 0x00060040, DriverInitialize = 0x00390000, - GetMaxLines = 0x000A0080 + GetMaxLines = 0x000A0080, }; } -void CAMService::reset() {} +void CAMService::reset() { bufferErrorInterruptEvents.fill(std::nullopt); } void CAMService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { case CAMCommands::DriverInitialize: driverInitialize(messagePointer); break; + case CAMCommands::GetBufferErrorInterruptEvent: getBufferErrorInterruptEvent(messagePointer); break; case CAMCommands::GetMaxLines: getMaxLines(messagePointer); break; default: Helpers::panic("CAM service requested. Command: %08X\n", command); } @@ -55,4 +58,24 @@ void CAMService::getMaxLines(u32 messagePointer) { mem.write32(messagePointer + 4, result); mem.write16(messagePointer + 8, lines); } +} + +void CAMService::getBufferErrorInterruptEvent(u32 messagePointer) { + const u32 port = mem.read32(messagePointer + 4); + log("CAM::GetBufferErrorInterruptEvent (port = %d)\n", port); + + mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 2)); + + if (port >= portCount) { + Helpers::panic("CAM::GetBufferErrorInterruptEvent: Invalid port"); + } else { + auto& event = bufferErrorInterruptEvents[port]; + if (!event.has_value()) { + event = kernel.makeEvent(ResetType::OneShot); + } + + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 0); + mem.write32(messagePointer + 12, event.value()); + } } \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index ea2c031f5..02f9d5691 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -6,7 +6,7 @@ #include "kernel.hpp" ServiceManager::ServiceManager(std::span regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) - : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem), cecd(mem, kernel), cfg(mem), + : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem, kernel), cecd(mem, kernel), cfg(mem), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), http(mem), ir_user(mem, kernel), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem), mic(mem), nfc(mem, kernel), nim(mem), ndm(mem), ptm(mem), soc(mem), ssl(mem), y2r(mem, kernel) {}