From 442ae3a210a06fa19c6c1673682b174e025546a1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:10:18 +0200 Subject: [PATCH 1/4] Add CAM::SetReceiving, fix ports --- include/services/cam.hpp | 7 ++++-- src/core/services/cam.cpp | 47 ++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/include/services/cam.hpp b/include/services/cam.hpp index 57cb7e13..eec70208 100644 --- a/include/services/cam.hpp +++ b/include/services/cam.hpp @@ -15,11 +15,13 @@ class CAMService { using Event = std::optional; struct Port { - Event bufferErrorInterruptevent = std::nullopt; + Event bufferErrorInterruptEvent = std::nullopt; + Event receiveEvent = std::nullopt; u16 transferBytes; void reset() { - bufferErrorInterruptevent = std::nullopt; + bufferErrorInterruptEvent = std::nullopt; + receiveEvent = std::nullopt; transferBytes = 256; } }; @@ -41,6 +43,7 @@ class CAMService { void getTransferBytes(u32 messagePointer); void setContrast(u32 messagePointer); void setFrameRate(u32 messagePointer); + void setReceiving(u32 messagePointer); void setSize(u32 messagePointer); void setTransferLines(u32 messagePointer); void setTrimming(u32 messagePointer); diff --git a/src/core/services/cam.cpp b/src/core/services/cam.cpp index 8c59321d..c0335dcb 100644 --- a/src/core/services/cam.cpp +++ b/src/core/services/cam.cpp @@ -8,6 +8,7 @@ namespace CAMCommands { enum : u32 { GetBufferErrorInterruptEvent = 0x00060040, + SetReceiving = 0x00070102, DriverInitialize = 0x00390000, DriverFinalize = 0x003A0000, SetTransferLines = 0x00090100, @@ -76,12 +77,16 @@ void CAMService::handleSyncRequest(u32 messagePointer) { case CAMCommands::GetTransferBytes: getTransferBytes(messagePointer); break; case CAMCommands::SetContrast: setContrast(messagePointer); break; case CAMCommands::SetFrameRate: setFrameRate(messagePointer); break; + case CAMCommands::SetReceiving: setReceiving(messagePointer); break; + case CAMCommands::SetSize: setSize(messagePointer); break; case CAMCommands::SetTransferLines: setTransferLines(messagePointer); break; case CAMCommands::SetTrimming: setTrimming(messagePointer); break; case CAMCommands::SetTrimmingParamsCenter: setTrimmingParamsCenter(messagePointer); break; - case CAMCommands::SetSize: setSize(messagePointer); break; - default: Helpers::panic("Unimplemented CAM service requested. Command: %08X\n", command); break; + default: + Helpers::warn("Unimplemented CAM service requested. Command: %08X\n", command); + mem.write32(messagePointer + 4, 0); + break; } } @@ -108,7 +113,7 @@ void CAMService::setContrast(u32 messagePointer) { } void CAMService::setTransferLines(u32 messagePointer) { - const u32 portIndex = mem.read32(messagePointer + 4); + const u32 portIndex = mem.read8(messagePointer + 4); const u16 lines = mem.read16(messagePointer + 8); const u16 width = mem.read16(messagePointer + 12); const u16 height = mem.read16(messagePointer + 16); @@ -152,7 +157,7 @@ void CAMService::setSize(u32 messagePointer) { } void CAMService::setTrimming(u32 messagePointer) { - const u32 port = mem.read32(messagePointer + 4); + const u32 port = mem.read8(messagePointer + 4); const bool trim = mem.read8(messagePointer + 8) != 0; log("CAM::SetTrimming (port = %d, trimming = %s)\n", port, trim ? "enabled" : "disabled"); @@ -162,7 +167,7 @@ void CAMService::setTrimming(u32 messagePointer) { } void CAMService::setTrimmingParamsCenter(u32 messagePointer) { - const u32 port = mem.read32(messagePointer + 4); + const u32 port = mem.read8(messagePointer + 4); const s16 trimWidth = s16(mem.read16(messagePointer + 8)); const s16 trimHeight = s16(mem.read16(messagePointer + 12)); const s16 cameraWidth = s16(mem.read16(messagePointer + 16)); @@ -216,7 +221,7 @@ void CAMService::getSuitableY2RCoefficients(u32 messagePointer) { } void CAMService::getTransferBytes(u32 messagePointer) { - const u32 portIndex = mem.read32(messagePointer + 4); + const u32 portIndex = mem.read8(messagePointer + 4); const PortSelect port(portIndex); log("CAM::GetTransferBytes (port = %d)\n", portIndex); @@ -233,14 +238,14 @@ void CAMService::getTransferBytes(u32 messagePointer) { } void CAMService::getBufferErrorInterruptEvent(u32 messagePointer) { - const u32 portIndex = mem.read32(messagePointer + 4); + const u32 portIndex = mem.read8(messagePointer + 4); const PortSelect port(portIndex); log("CAM::GetBufferErrorInterruptEvent (port = %d)\n", portIndex); mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 2)); if (port.isSinglePort()) { - auto& event = ports[port.getSingleIndex()].bufferErrorInterruptevent; + auto& event = ports[port.getSingleIndex()].bufferErrorInterruptEvent; if (!event.has_value()) { event = kernel.makeEvent(ResetType::OneShot); } @@ -251,4 +256,30 @@ void CAMService::getBufferErrorInterruptEvent(u32 messagePointer) { } else { Helpers::panic("CAM::GetBufferErrorInterruptEvent: Invalid port"); } +} + +void CAMService::setReceiving(u32 messagePointer) { + const u32 destination = mem.read32(messagePointer + 4); + const u32 portIndex = mem.read8(messagePointer + 8); + const u32 size = mem.read32(messagePointer + 12); + const u16 transferUnit = mem.read16(messagePointer + 16); + const Handle process = mem.read32(messagePointer + 24); + + const PortSelect port(portIndex); + log("CAM::SetReceiving (port = %d)\n", portIndex); + + mem.write32(messagePointer, IPC::responseHeader(0x7, 1, 2)); + + if (port.isSinglePort()) { + auto& event = ports[port.getSingleIndex()].receiveEvent; + 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()); + } else { + Helpers::panic("CAM::SetReceiving: Invalid port"); + } } \ No newline at end of file From 707b11ccd84df170f9e57e9d5caaa7148cead27f Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:23:16 +0200 Subject: [PATCH 2/4] Add CAM::StartCapture --- include/services/cam.hpp | 1 + src/core/services/cam.cpp | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/services/cam.hpp b/include/services/cam.hpp index eec70208..5ef3edba 100644 --- a/include/services/cam.hpp +++ b/include/services/cam.hpp @@ -48,6 +48,7 @@ class CAMService { void setTransferLines(u32 messagePointer); void setTrimming(u32 messagePointer); void setTrimmingParamsCenter(u32 messagePointer); + void startCapture(u32 messagePointer); public: CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} diff --git a/src/core/services/cam.cpp b/src/core/services/cam.cpp index c0335dcb..e617ef2f 100644 --- a/src/core/services/cam.cpp +++ b/src/core/services/cam.cpp @@ -7,6 +7,7 @@ namespace CAMCommands { enum : u32 { + StartCapture = 0x00010040, GetBufferErrorInterruptEvent = 0x00060040, SetReceiving = 0x00070102, DriverInitialize = 0x00390000, @@ -82,6 +83,7 @@ void CAMService::handleSyncRequest(u32 messagePointer) { case CAMCommands::SetTransferLines: setTransferLines(messagePointer); break; case CAMCommands::SetTrimming: setTrimming(messagePointer); break; case CAMCommands::SetTrimmingParamsCenter: setTrimmingParamsCenter(messagePointer); break; + case CAMCommands::StartCapture: startCapture(messagePointer); break; default: Helpers::warn("Unimplemented CAM service requested. Command: %08X\n", command); @@ -282,4 +284,26 @@ void CAMService::setReceiving(u32 messagePointer) { } else { Helpers::panic("CAM::SetReceiving: Invalid port"); } -} \ No newline at end of file +} + +void CAMService::startCapture(u32 messagePointer) { + const u32 portIndex = mem.read8(messagePointer + 4); + const PortSelect port(portIndex); + log("CAM::StartCapture (port = %d)\n", portIndex); + + mem.write32(messagePointer, IPC::responseHeader(0x01, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); + + if (port.isValid()) { + for (int i : port.getPortIndices()) { + auto& event = ports[port.getSingleIndex()].receiveEvent; + + // Until we properly implement cameras, immediately signal the receive event + if (event.has_value()) { + kernel.signalEvent(event.value()); + } + } + } else { + Helpers::warn("CAM::StartCapture: Invalid port index"); + } +} From 194f29206b9dd759701a83b3c8cb6fcb340924e2 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:31:26 +0200 Subject: [PATCH 3/4] Stub Y2R::SetSendingYUV --- include/services/y2r.hpp | 1 + src/core/services/y2r.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/include/services/y2r.hpp b/include/services/y2r.hpp index 0a1cae2f..a08c41a2 100644 --- a/include/services/y2r.hpp +++ b/include/services/y2r.hpp @@ -98,6 +98,7 @@ class Y2RService { void setSendingY(u32 messagePointer); void setSendingU(u32 messagePointer); void setSendingV(u32 messagePointer); + void setSendingYUV(u32 messagePointer); void setSpacialDithering(u32 messagePointer); void setStandardCoeff(u32 messagePointer); void setTemporalDithering(u32 messagePointer); diff --git a/src/core/services/y2r.cpp b/src/core/services/y2r.cpp index b5daf6bb..99b18418 100644 --- a/src/core/services/y2r.cpp +++ b/src/core/services/y2r.cpp @@ -18,6 +18,7 @@ namespace Y2RCommands { SetSendingY = 0x00100102, SetSendingU = 0x00110102, SetSendingV = 0x00120102, + SetSendingYUV = 0x00130102, SetReceiving = 0x00180102, SetInputLineWidth = 0x001A0040, GetInputLineWidth = 0x001B0000, @@ -82,6 +83,7 @@ void Y2RService::handleSyncRequest(u32 messagePointer) { case Y2RCommands::SetSendingY: setSendingY(messagePointer); break; case Y2RCommands::SetSendingU: setSendingU(messagePointer); break; case Y2RCommands::SetSendingV: setSendingV(messagePointer); break; + case Y2RCommands::SetSendingYUV: setSendingYUV(messagePointer); break; case Y2RCommands::SetSpacialDithering: setSpacialDithering(messagePointer); break; case Y2RCommands::SetStandardCoeff: setStandardCoeff(messagePointer); break; case Y2RCommands::SetTemporalDithering: setTemporalDithering(messagePointer); break; @@ -399,6 +401,14 @@ void Y2RService::setSendingV(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void Y2RService::setSendingYUV(u32 messagePointer) { + log("Y2R::SetSendingYUV\n"); + Helpers::warn("Unimplemented Y2R::SetSendingYUV"); + + mem.write32(messagePointer, IPC::responseHeader(0x13, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void Y2RService::setReceiving(u32 messagePointer) { log("Y2R::SetReceiving\n"); Helpers::warn("Unimplemented Y2R::setReceiving"); From 76a14b3bae409c268e76daf721962136b690aa7e Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:20:56 +0200 Subject: [PATCH 4/4] Implement CAM::GetMaxBytes/SetTransferBytes --- include/services/cam.hpp | 2 ++ src/core/services/cam.cpp | 49 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/services/cam.hpp b/include/services/cam.hpp index 5ef3edba..60ede3b9 100644 --- a/include/services/cam.hpp +++ b/include/services/cam.hpp @@ -37,6 +37,7 @@ class CAMService { // Service commands void driverInitialize(u32 messagePointer); void driverFinalize(u32 messagePointer); + void getMaxBytes(u32 messagePointer); void getMaxLines(u32 messagePointer); void getBufferErrorInterruptEvent(u32 messagePointer); void getSuitableY2RCoefficients(u32 messagePointer); @@ -45,6 +46,7 @@ class CAMService { void setFrameRate(u32 messagePointer); void setReceiving(u32 messagePointer); void setSize(u32 messagePointer); + void setTransferBytes(u32 messagePointer); void setTransferLines(u32 messagePointer); void setTrimming(u32 messagePointer); void setTrimmingParamsCenter(u32 messagePointer); diff --git a/src/core/services/cam.cpp b/src/core/services/cam.cpp index e617ef2f..b3dfd1dc 100644 --- a/src/core/services/cam.cpp +++ b/src/core/services/cam.cpp @@ -14,7 +14,9 @@ namespace CAMCommands { DriverFinalize = 0x003A0000, SetTransferLines = 0x00090100, GetMaxLines = 0x000A0080, + SetTransferBytes = 0x000B0100, GetTransferBytes = 0x000C0040, + GetMaxBytes = 0x000D0080, SetTrimming = 0x000E0080, SetTrimmingParamsCenter = 0x00120140, SetSize = 0x001F00C0, // Set size has different headers between cam:u and New3DS QTM module @@ -73,6 +75,7 @@ void CAMService::handleSyncRequest(u32 messagePointer) { case CAMCommands::DriverInitialize: driverInitialize(messagePointer); break; case CAMCommands::DriverFinalize: driverFinalize(messagePointer); break; case CAMCommands::GetBufferErrorInterruptEvent: getBufferErrorInterruptEvent(messagePointer); break; + case CAMCommands::GetMaxBytes: getMaxBytes(messagePointer); break; case CAMCommands::GetMaxLines: getMaxLines(messagePointer); break; case CAMCommands::GetSuitableY2rStandardCoefficient: getSuitableY2RCoefficients(messagePointer); break; case CAMCommands::GetTransferBytes: getTransferBytes(messagePointer); break; @@ -87,7 +90,7 @@ void CAMService::handleSyncRequest(u32 messagePointer) { default: Helpers::warn("Unimplemented CAM service requested. Command: %08X\n", command); - mem.write32(messagePointer + 4, 0); + mem.write32(messagePointer + 4, Result::Success); break; } } @@ -114,6 +117,28 @@ void CAMService::setContrast(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void CAMService::setTransferBytes(u32 messagePointer) { + const u32 portIndex = mem.read8(messagePointer + 4); + const u32 bytes = mem.read16(messagePointer + 8); + // ...why do these parameters even exist? + const u16 width = mem.read16(messagePointer + 12); + const u16 height = mem.read16(messagePointer + 16); + const PortSelect port(portIndex); + + if (port.isValid()) { + for (int i : port.getPortIndices()) { + ports[i].transferBytes = bytes; + } + } else { + Helpers::warn("CAM::SetTransferBytes: Invalid port\n"); + } + + log("CAM::SetTransferBytes (port = %d, bytes = %d, width = %d, height = %d)\n", portIndex, bytes, width, height); + + mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void CAMService::setTransferLines(u32 messagePointer) { const u32 portIndex = mem.read8(messagePointer + 4); const u16 lines = mem.read16(messagePointer + 8); @@ -214,6 +239,28 @@ void CAMService::getMaxLines(u32 messagePointer) { } } +void CAMService::getMaxBytes(u32 messagePointer) { + const u16 width = mem.read16(messagePointer + 4); + const u16 height = mem.read16(messagePointer + 8); + log("CAM::GetMaxBytes (width = %d, height = %d)\n", width, height); + + constexpr u32 MIN_TRANSFER_UNIT = 256; + constexpr u32 MAX_BUFFER_SIZE = 2560; + if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { + Helpers::panic("CAM::GetMaxLines out of range"); + } else { + u32 bytes = MAX_BUFFER_SIZE; + + while (width * height * 2 % bytes != 0) { + bytes -= MIN_TRANSFER_UNIT; + } + + mem.write32(messagePointer, IPC::responseHeader(0xA, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, bytes); + } +} + void CAMService::getSuitableY2RCoefficients(u32 messagePointer) { log("CAM::GetSuitableY2RCoefficients\n"); mem.write32(messagePointer, IPC::responseHeader(0x36, 2, 0));