mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-06 14:15:41 +12:00
Properly implement camera ports, add more cam commands
This commit is contained in:
parent
f78acb8049
commit
84b8bc8c48
2 changed files with 153 additions and 16 deletions
|
@ -12,14 +12,25 @@
|
|||
class Kernel;
|
||||
|
||||
class CAMService {
|
||||
using Event = std::optional<Handle>;
|
||||
|
||||
struct Port {
|
||||
Event bufferErrorInterruptevent = std::nullopt;
|
||||
u16 transferBytes;
|
||||
|
||||
void reset() {
|
||||
bufferErrorInterruptevent = std::nullopt;
|
||||
transferBytes = 256;
|
||||
}
|
||||
};
|
||||
|
||||
Handle handle = KernelHandles::CAM;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, camLogger)
|
||||
|
||||
using Event = std::optional<Handle>;
|
||||
static constexpr size_t portCount = 4; // PORT_NONE, PORT_CAM1, PORT_CAM2, PORT_BOTH
|
||||
std::array<Event, portCount> bufferErrorInterruptEvents;
|
||||
static constexpr size_t portCount = 2;
|
||||
std::array<Port, portCount> ports;
|
||||
|
||||
// Service commands
|
||||
void driverInitialize(u32 messagePointer);
|
||||
|
@ -33,7 +44,7 @@ class CAMService {
|
|||
void setSize(u32 messagePointer);
|
||||
void setTransferLines(u32 messagePointer);
|
||||
void setTrimming(u32 messagePointer);
|
||||
void setTrimminsParamsCenter(u32 messagePointer);
|
||||
void setTrimmingParamsCenter(u32 messagePointer);
|
||||
|
||||
public:
|
||||
CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
|
|
|
@ -19,17 +19,65 @@ namespace CAMCommands {
|
|||
};
|
||||
}
|
||||
|
||||
void CAMService::reset() { bufferErrorInterruptEvents.fill(std::nullopt); }
|
||||
// Helper struct for working with camera ports
|
||||
class PortSelect {
|
||||
u32 value;
|
||||
|
||||
public:
|
||||
PortSelect(u32 val) : value(val) {}
|
||||
bool isValid() const { return value < 4; }
|
||||
|
||||
bool isSinglePort() const {
|
||||
// 1 corresponds to the first camera port and 2 corresponds to the second port
|
||||
return value == 1 || value == 2;
|
||||
}
|
||||
|
||||
bool isBothPorts() const {
|
||||
// 3 corresponds to both ports
|
||||
return value == 3;
|
||||
}
|
||||
|
||||
// Returns the index of the camera port, assuming that it's only a single port
|
||||
int getSingleIndex() const {
|
||||
if (!isSinglePort()) [[unlikely]] {
|
||||
Helpers::panic("Camera: getSingleIndex called for port with invalid value");
|
||||
}
|
||||
|
||||
return value - 1;
|
||||
}
|
||||
|
||||
std::vector<int> getPortIndices() const {
|
||||
switch (value) {
|
||||
case 1: return {0}; // Only port 1
|
||||
case 2: return {1}; // Only port 2
|
||||
case 3: return {0, 1}; // Both port 1 and port 2
|
||||
default: return {}; // No ports or invalid ports
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void CAMService::reset() {
|
||||
for (auto& port : ports) {
|
||||
port.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CAMService::handleSyncRequest(u32 messagePointer) {
|
||||
const u32 command = mem.read32(messagePointer);
|
||||
switch (command) {
|
||||
case CAMCommands::DriverInitialize: driverInitialize(messagePointer); break;
|
||||
case CAMCommands::DriverFinalize: driverFinalize(messagePointer); break;
|
||||
case CAMCommands::GetBufferErrorInterruptEvent: getBufferErrorInterruptEvent(messagePointer); break;
|
||||
case CAMCommands::GetMaxLines: getMaxLines(messagePointer); break;
|
||||
case CAMCommands::GetSuitableY2rStandardCoefficient: getSuitableY2RCoefficients(messagePointer); break;
|
||||
case CAMCommands::GetTransferBytes: getTransferBytes(messagePointer); break;
|
||||
case CAMCommands::SetContrast: setContrast(messagePointer); break;
|
||||
case CAMCommands::SetFrameRate: setFrameRate(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;
|
||||
|
@ -42,6 +90,12 @@ void CAMService::driverInitialize(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void CAMService::driverFinalize(u32 messagePointer) {
|
||||
log("CAM::DriverFinalize\n");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x3A, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void CAMService::setContrast(u32 messagePointer) {
|
||||
const u32 cameraSelect = mem.read32(messagePointer + 4);
|
||||
const u32 contrast = mem.read32(messagePointer + 8);
|
||||
|
@ -53,12 +107,23 @@ void CAMService::setContrast(u32 messagePointer) {
|
|||
}
|
||||
|
||||
void CAMService::setTransferLines(u32 messagePointer) {
|
||||
const u32 port = mem.read32(messagePointer + 4);
|
||||
const s16 lines = mem.read16(messagePointer + 8);
|
||||
const s16 width = mem.read16(messagePointer + 12);
|
||||
const s16 height = mem.read16(messagePointer + 16);
|
||||
const u32 portIndex = mem.read32(messagePointer + 4);
|
||||
const u16 lines = mem.read16(messagePointer + 8);
|
||||
const u16 width = mem.read16(messagePointer + 12);
|
||||
const u16 height = mem.read16(messagePointer + 16);
|
||||
const PortSelect port(portIndex);
|
||||
|
||||
log("CAM::SetTransferLines (port = %d, lines = %d, width = %d, height = %d)\n", port, lines, width, height);
|
||||
if (port.isValid()) {
|
||||
const u32 transferBytes = lines * width * 2;
|
||||
|
||||
for (int i : port.getPortIndices()) {
|
||||
ports[i].transferBytes = transferBytes;
|
||||
}
|
||||
} else {
|
||||
Helpers::warn("CAM::SetTransferLines: Invalid port\n");
|
||||
}
|
||||
|
||||
log("CAM::SetTransferLines (port = %d, lines = %d, width = %d, height = %d)\n", portIndex, lines, width, height);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
|
@ -74,6 +139,41 @@ void CAMService::setFrameRate(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void CAMService::setSize(u32 messagePointer) {
|
||||
const u32 cameraSelect = mem.read32(messagePointer + 4);
|
||||
const u32 size = mem.read32(messagePointer + 8);
|
||||
const u32 context = mem.read32(messagePointer + 12);
|
||||
|
||||
log("CAM::SetSize (camera select = %d, size = %d, context = %d)\n", cameraSelect, size, context);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x1F, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void CAMService::setTrimming(u32 messagePointer) {
|
||||
const u32 port = mem.read32(messagePointer + 4);
|
||||
const bool trim = mem.read8(messagePointer + 8) != 0;
|
||||
|
||||
log("CAM::SetTrimming (port = %d, trimming = %s)\n", port, trim ? "enabled" : "disabled");
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0E, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void CAMService::setTrimmingParamsCenter(u32 messagePointer) {
|
||||
const u32 port = mem.read32(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));
|
||||
const s16 cameraHeight = s16(mem.read16(messagePointer + 20));
|
||||
|
||||
log("CAM::SetTrimmingParamsCenter (port = %d), trim size = (%d, %d), camera size = (%d, %d)\n", port, trimWidth, trimHeight, cameraWidth,
|
||||
cameraHeight);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x12, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
// Algorithm taken from Citra
|
||||
// https://github.com/citra-emu/citra/blob/master/src/core/hle/service/cam/cam.cpp#L465
|
||||
void CAMService::getMaxLines(u32 messagePointer) {
|
||||
|
@ -106,16 +206,40 @@ void CAMService::getMaxLines(u32 messagePointer) {
|
|||
}
|
||||
}
|
||||
|
||||
void CAMService::getSuitableY2RCoefficients(u32 messagePointer) {
|
||||
log("CAM::GetSuitableY2RCoefficients\n");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x36, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
// Y2R standard coefficient value
|
||||
mem.write32(messagePointer + 8, 0);
|
||||
}
|
||||
|
||||
void CAMService::getTransferBytes(u32 messagePointer) {
|
||||
const u32 portIndex = mem.read32(messagePointer + 4);
|
||||
const PortSelect port(portIndex);
|
||||
log("CAM::GetTransferBytes (port = %d)\n", portIndex);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0C, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
|
||||
if (port.isSinglePort()) {
|
||||
mem.write32(messagePointer + 8, ports[port.getSingleIndex()].transferBytes);
|
||||
} else {
|
||||
// TODO: This should return the proper error code
|
||||
Helpers::warn("CAM::GetTransferBytes: Invalid port index");
|
||||
mem.write32(messagePointer + 8, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CAMService::getBufferErrorInterruptEvent(u32 messagePointer) {
|
||||
const u32 port = mem.read32(messagePointer + 4);
|
||||
log("CAM::GetBufferErrorInterruptEvent (port = %d)\n", port);
|
||||
const u32 portIndex = mem.read32(messagePointer + 4);
|
||||
const PortSelect port(portIndex);
|
||||
log("CAM::GetBufferErrorInterruptEvent (port = %d)\n", portIndex);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 2));
|
||||
|
||||
if (port >= portCount) {
|
||||
Helpers::panic("CAM::GetBufferErrorInterruptEvent: Invalid port");
|
||||
} else {
|
||||
auto& event = bufferErrorInterruptEvents[port];
|
||||
if (port.isSinglePort()) {
|
||||
auto& event = ports[port.getSingleIndex()].bufferErrorInterruptevent;
|
||||
if (!event.has_value()) {
|
||||
event = kernel.makeEvent(ResetType::OneShot);
|
||||
}
|
||||
|
@ -123,5 +247,7 @@ void CAMService::getBufferErrorInterruptEvent(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, 0);
|
||||
mem.write32(messagePointer + 12, event.value());
|
||||
} else {
|
||||
Helpers::panic("CAM::GetBufferErrorInterruptEvent: Invalid port");
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue