#include "audio/AudioDevice.hpp" #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" #include "orbis/thread/Process.hpp" #include "orbis/thread/ProcessOps.hpp" #include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/Rc.hpp" #include // #include #define SNDCTL_DSP_RESET 0x20005000 #define SNDCTL_DSP_SETFRAGMENT 0xc004500a #define SNDCTL_DSP_SETFMT 0xc0045005 #define SNDCTL_DSP_SPEED 0xc0045002 #define SNDCTL_DSP_CHANNELS 0xc0045006 #define ORBIS_AUDIO_UPDATE_TICK_PARAMS 0xc004505c #define SNDCTL_DSP_SYNCGROUP 0xc048501c #define ORBIS_AUDIO_CONFIG_SPDIF 0xc0085063 #define SNDCTL_DSP_GETBLKSIZE 0x40045004 #define SOUND_PCM_READ_BITS 0x40045005 #define SNDCTL_DSP_GETOSPACE 0x4010500c #define SNDCTL_DSP_SYNCSTART 0x8004501d #define ORBIS_AUDIO_IOCTL_SETCONTROL 0x80085062 struct AoutFile : orbis::File {}; struct AoutDevice : public IoDevice { std::int8_t id; orbis::Ref audioDevice; AoutDevice(std::int8_t id, AudioDevice *audioDevice) : id(id), audioDevice(audioDevice) {} orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override; }; static orbis::ErrorCode aout_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { auto device = static_cast(file->device.get()); switch (request) { case SNDCTL_DSP_RESET: { ORBIS_LOG_TODO("SNDCTL_DSP_RESET"); if (auto audioDevice = device->audioDevice) { audioDevice->reset(); } return {}; } case SNDCTL_DSP_SETFRAGMENT: { struct Args { orbis::uint32_t fragment; }; auto args = reinterpret_cast(argp); ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFRAGMENT", args->fragment & 0xF, (args->fragment >> 16) & 0xF); if (auto audioDevice = device->audioDevice) { audioDevice->setSampleSize(1 << (args->fragment & 0xF), (args->fragment >> 16) & 0xF); } return {}; } case SNDCTL_DSP_SETFMT: { struct Args { orbis::uint32_t fmt; }; auto args = reinterpret_cast(argp); ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFMT", args->fmt); if (auto audioDevice = device->audioDevice) { audioDevice->setFormat(static_cast(args->fmt)); } return {}; } case SNDCTL_DSP_SPEED: { struct Args { orbis::uint32_t speed; }; auto args = reinterpret_cast(argp); if (auto audioDevice = device->audioDevice) { audioDevice->setFrequency(args->speed); } return {}; } case SNDCTL_DSP_CHANNELS: { struct Args { orbis::uint32_t channels; }; auto args = reinterpret_cast(argp); if (auto audioDevice = device->audioDevice) { audioDevice->setChannels(args->channels); } return {}; } case ORBIS_AUDIO_UPDATE_TICK_PARAMS: { struct Args { orbis::uint32_t tick; }; auto args = reinterpret_cast(argp); ORBIS_LOG_NOTICE("ORBIS_AUDIO_UPDATE_TICK_PARAMS", args->tick); return {}; } case SNDCTL_DSP_SYNCGROUP: { ORBIS_LOG_NOTICE("SNDCTL_DSP_SYNCGROUP"); return {}; } case ORBIS_AUDIO_CONFIG_SPDIF: { struct Args { orbis::uint64_t unk0; }; auto args = reinterpret_cast(argp); args->unk0 = 0x100000000; // Disable SPDIF output return {}; } case SNDCTL_DSP_GETBLKSIZE: { struct Args { orbis::uint32_t blksize; }; auto args = reinterpret_cast(argp); ORBIS_LOG_NOTICE("SNDCTL_DSP_GETBLKSIZE", args->blksize); return {}; } case SOUND_PCM_READ_BITS: { struct Args { orbis::uint32_t bits; }; auto args = reinterpret_cast(argp); ORBIS_LOG_NOTICE("SOUND_PCM_READ_BITS", args->bits); return {}; } case SNDCTL_DSP_GETOSPACE: { if (auto audioDevice = device->audioDevice) { auto info = audioDevice->getOSpace(); ORBIS_RET_ON_ERROR(orbis::uwrite(orbis::ptr(argp), info)); ORBIS_LOG_WARNING("SNDCTL_DSP_GETOSPACE", info.fragments, info.fragsize, info.fragstotal, info.bytes); } return {}; } case SNDCTL_DSP_SYNCSTART: { ORBIS_LOG_NOTICE("SNDCTL_DSP_SYNCSTART"); if (auto audioDevice = device->audioDevice) { audioDevice->start(); } return {}; } case ORBIS_AUDIO_IOCTL_SETCONTROL: { struct Args { orbis::uint64_t unk0; }; auto args = reinterpret_cast(argp); ORBIS_LOG_NOTICE("ORBIS_AUDIO_IOCTL_SETCONTROL", args->unk0); return {}; } default: ORBIS_LOG_FATAL("Unhandled aout ioctl", request); thread->where(); break; } return {}; } static orbis::ErrorCode aout_write(orbis::File *file, orbis::Uio *uio, orbis::Thread *thread) { auto device = static_cast(file->device.get()); if (auto audioDevice = device->audioDevice) { for (auto vec : std::span(uio->iov, uio->iovcnt)) { audioDevice->write(vec.base, vec.len); // rx::hexdump({(std::byte*)vec.base, vec.len}); uio->offset += vec.len; } } return {}; } static const orbis::FileOps fileOps = { .ioctl = aout_ioctl, .write = aout_write, }; orbis::ErrorCode AoutDevice::open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) { ORBIS_LOG_FATAL("aout device open", path, flags, mode); auto newFile = orbis::knew(); newFile->ops = &fileOps; newFile->device = this; thread->where(); *file = newFile; return {}; } IoDevice *createAoutCharacterDevice(std::int8_t id, AudioDevice *device) { return orbis::knew(id, device); }