mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-21 12:59:14 +12:00
104 lines
No EOL
3.7 KiB
C++
104 lines
No EOL
3.7 KiB
C++
#include "services/csnd.hpp"
|
|
|
|
#include "ipc.hpp"
|
|
#include "kernel.hpp"
|
|
#include "result/result.hpp"
|
|
|
|
namespace CSNDCommands {
|
|
enum : u32 {
|
|
Initialize = 0x00010140,
|
|
ExecuteCommands = 0x00030040,
|
|
AcquireSoundChannels = 0x00050000,
|
|
};
|
|
}
|
|
|
|
void CSNDService::reset() {
|
|
csndMutex = std::nullopt;
|
|
initialized = false;
|
|
sharedMemory = nullptr;
|
|
sharedMemSize = 0;
|
|
}
|
|
|
|
void CSNDService::handleSyncRequest(u32 messagePointer) {
|
|
const u32 command = mem.read32(messagePointer);
|
|
|
|
switch (command) {
|
|
case CSNDCommands::AcquireSoundChannels: acquireSoundChannels(messagePointer); break;
|
|
case CSNDCommands::ExecuteCommands: executeCommands(messagePointer); break;
|
|
case CSNDCommands::Initialize: initialize(messagePointer); break;
|
|
|
|
default:
|
|
Helpers::warn("Unimplemented CSND service requested. Command: %08X\n", command);
|
|
mem.write32(messagePointer + 4, Result::Success);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CSNDService::acquireSoundChannels(u32 messagePointer) {
|
|
log("CSND::AcquireSoundChannels\n");
|
|
// The CSND service talks to the DSP using the DSP FIFO to negotiate what CSND channels are allocated to the DSP, and this seems to be channels 0-7 (usually). The rest are dedicated to CSND services.
|
|
// https://www.3dbrew.org/wiki/CSND_Services
|
|
constexpr u32 csndChannelMask = 0xFFFFFF00;
|
|
|
|
mem.write32(messagePointer, IPC::responseHeader(0x5, 2, 0));
|
|
mem.write32(messagePointer + 4, Result::Success);
|
|
mem.write32(messagePointer + 8, csndChannelMask);
|
|
}
|
|
|
|
void CSNDService::initialize(u32 messagePointer) {
|
|
u32 blockSize = mem.read32(messagePointer + 4);
|
|
const u32 offset0 = mem.read32(messagePointer + 8);
|
|
const u32 offset1 = mem.read32(messagePointer + 12);
|
|
const u32 offset2 = mem.read32(messagePointer + 16);
|
|
const u32 offset3 = mem.read32(messagePointer + 20);
|
|
|
|
log("CSND::Initialize (Block size = %08X, offset0 = %X, offset1 = %X, offset2 = %X, offset3 = %X)\n", blockSize, offset0, offset1, offset2, offset3);
|
|
|
|
// Align block size to 4KB. CSND shared memory block is currently stubbed to be 0x3000 == 12KB, so panic if this is more than requested
|
|
blockSize = (blockSize + 0xFFF) & ~0xFFF;
|
|
if (blockSize != 12_KB) {
|
|
Helpers::panic("Unhandled size for CSND shared memory block");
|
|
}
|
|
|
|
if (initialized) {
|
|
printf("CSND initialized twice\n");
|
|
}
|
|
|
|
if (!csndMutex.has_value()) {
|
|
csndMutex = kernel.makeMutex(false);
|
|
}
|
|
|
|
initialized = true;
|
|
sharedMemSize = blockSize;
|
|
|
|
mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 3));
|
|
mem.write32(messagePointer + 4, Result::Success);
|
|
mem.write32(messagePointer + 8, 0x4000000);
|
|
mem.write32(messagePointer + 12, csndMutex.value());
|
|
mem.write32(messagePointer + 16, KernelHandles::CSNDSharedMemHandle);
|
|
}
|
|
|
|
void CSNDService::executeCommands(u32 messagePointer) {
|
|
const u32 offset = mem.read32(messagePointer + 4);
|
|
log("CSND::ExecuteCommands (command offset = %X)\n", offset);
|
|
|
|
mem.write32(messagePointer, IPC::responseHeader(0x5, 2, 0));
|
|
|
|
if (!sharedMemory) {
|
|
Helpers::warn("CSND::Execute commands without shared memory");
|
|
mem.write32(messagePointer + 4, Result::FailurePlaceholder);
|
|
return;
|
|
}
|
|
|
|
mem.write32(messagePointer + 4, Result::Success);
|
|
|
|
// This is initially zero when this command data is written by the user process, once the CSND module finishes processing the command this is set
|
|
// to 0x1. This flag is only set to value 1 for the first command(once processing for the entire command chain is finished) at the offset
|
|
// specified in the service command, not all type0 commands in the chain.
|
|
constexpr u32 commandListDoneOffset = 0x4;
|
|
|
|
// Make sure to not access OoB of the shared memory block when marking command list processing as finished
|
|
if (offset + commandListDoneOffset < sharedMemSize) {
|
|
sharedMemory[offset + commandListDoneOffset] = 1;
|
|
}
|
|
} |