forked from Bananymous/banan-os
111 lines
3.0 KiB
C++
111 lines
3.0 KiB
C++
#include <kernel/Audio/AC97/Controller.h>
|
|
#include <kernel/Audio/Controller.h>
|
|
#include <kernel/Audio/HDAudio/Controller.h>
|
|
#include <kernel/Device/DeviceNumbers.h>
|
|
#include <kernel/FS/DevFS/FileSystem.h>
|
|
#include <kernel/Lock/SpinLockAsMutex.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/sysmacros.h>
|
|
|
|
namespace Kernel
|
|
{
|
|
|
|
static BAN::Atomic<dev_t> s_next_audio_minor = 0;
|
|
|
|
AudioController::AudioController()
|
|
: CharacterDevice(0644, 0, 0)
|
|
, m_rdev(makedev(DeviceNumber::AudioController, s_next_audio_minor++))
|
|
{
|
|
char* ptr = m_name;
|
|
BAN::Formatter::print([&ptr](char c) { *ptr++ = c; }, "audio{}", minor(m_rdev));
|
|
}
|
|
|
|
BAN::ErrorOr<void> AudioController::create(PCI::Device& pci_device)
|
|
{
|
|
switch (pci_device.subclass())
|
|
{
|
|
case 0x01:
|
|
// We should confirm that the card is actually AC97 but I'm trusting osdev wiki on this one
|
|
// > you can probably expect that every sound card with subclass 0x01 is sound card compatibile with AC97
|
|
if (auto ret = AC97AudioController::create(pci_device); ret.is_error())
|
|
{
|
|
dwarnln("Failed to initialize AC97: {}", ret.error());
|
|
return ret.release_error();
|
|
}
|
|
break;
|
|
case 0x03:
|
|
if (auto ret = HDAudioController::create(pci_device); ret.is_error())
|
|
{
|
|
dwarnln("Failed to initialize Intel HDA: {}", ret.error());
|
|
return ret.release_error();
|
|
}
|
|
break;
|
|
default:
|
|
dprintln("Unsupported Sound card (PCI {2H}:{2H}:{2H})",
|
|
pci_device.class_code(),
|
|
pci_device.subclass(),
|
|
pci_device.prog_if()
|
|
);
|
|
return BAN::Error::from_errno(ENOTSUP);
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
BAN::ErrorOr<size_t> AudioController::write_impl(off_t, BAN::ConstByteSpan buffer)
|
|
{
|
|
SpinLockGuard lock_guard(m_spinlock);
|
|
|
|
while (m_sample_data_size >= m_sample_data_capacity)
|
|
{
|
|
SpinLockGuardAsMutex smutex(lock_guard);
|
|
TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex));
|
|
}
|
|
|
|
size_t nwritten = 0;
|
|
while (nwritten < buffer.size())
|
|
{
|
|
if (m_sample_data_size >= m_sample_data_capacity)
|
|
break;
|
|
|
|
const size_t max_memcpy = BAN::Math::min(m_sample_data_capacity - m_sample_data_size, m_sample_data_capacity - m_sample_data_head);
|
|
const size_t to_copy = BAN::Math::min(buffer.size() - nwritten, max_memcpy);
|
|
memcpy(m_sample_data + m_sample_data_head, buffer.data() + nwritten, to_copy);
|
|
|
|
nwritten += to_copy;
|
|
m_sample_data_head = (m_sample_data_head + to_copy) % m_sample_data_capacity;
|
|
m_sample_data_size += to_copy;
|
|
}
|
|
|
|
handle_new_data();
|
|
|
|
return nwritten;
|
|
}
|
|
|
|
BAN::ErrorOr<long> AudioController::ioctl_impl(int cmd, void* arg)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case SND_GET_CHANNELS:
|
|
*static_cast<uint32_t*>(arg) = get_channels();
|
|
return 0;
|
|
case SND_GET_SAMPLE_RATE:
|
|
*static_cast<uint32_t*>(arg) = get_sample_rate();
|
|
return 0;
|
|
case SND_RESET_BUFFER:
|
|
case SND_GET_BUFFERSZ:
|
|
{
|
|
SpinLockGuard _(m_spinlock);
|
|
*static_cast<uint32_t*>(arg) = m_sample_data_size;
|
|
if (cmd == SND_RESET_BUFFER)
|
|
m_sample_data_size = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return CharacterDevice::ioctl_impl(cmd, arg);
|
|
}
|
|
|
|
}
|