- Removed virtual functions for all of the stat stuff. This did however introduce some issues, mainly with /proc becoming out of sync if you changed your ID. I propose we do the linux thing and just have a stat update function which is optional, but allows dynamic updates of stat fields for cases such as those in uid/gid in /proc. - Simplified the API, although still kind of annoying it is a bit simpler. - Moved some of the FS structure from having the FS inode inside the in memory inode to a Serialise <-> Deserialise model where Inodes are deserialised from disk into in memory ones and then back into on disk ones when it comes time for syncing. This makes it semantically better in my opinion, as it explicitly separates disk and non-disk functionality.
120 lines
3.2 KiB
C++
120 lines
3.2 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<void> AudioController::initialize()
|
|
{
|
|
m_sample_data = TRY(ByteRingBuffer::create(m_sample_data_capacity));
|
|
return {};
|
|
}
|
|
|
|
BAN::ErrorOr<size_t> AudioController::write_impl(off_t, BAN::ConstByteSpan buffer)
|
|
{
|
|
SpinLockGuard lock_guard(m_spinlock);
|
|
|
|
while (m_sample_data->full())
|
|
{
|
|
SpinLockGuardAsMutex smutex(lock_guard);
|
|
TRY(Thread::current().block_or_eintr_indefinite(m_sample_data_blocker, &smutex));
|
|
}
|
|
|
|
const size_t to_copy = BAN::Math::min(buffer.size(), m_sample_data->free());
|
|
m_sample_data->push(buffer.slice(0, to_copy));
|
|
|
|
handle_new_data();
|
|
|
|
return to_copy;
|
|
}
|
|
|
|
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->pop(m_sample_data->size());
|
|
return 0;
|
|
}
|
|
case SND_GET_TOTAL_PINS:
|
|
*static_cast<uint32_t*>(arg) = get_total_pins();
|
|
return 0;
|
|
case SND_GET_PIN:
|
|
*static_cast<uint32_t*>(arg) = get_current_pin();
|
|
return 0;
|
|
case SND_SET_PIN:
|
|
TRY(set_current_pin(*static_cast<uint32_t*>(arg)));
|
|
return 0;
|
|
case SND_GET_VOLUME_INFO:
|
|
*static_cast<snd_volume_info*>(arg) = m_volume_info;
|
|
return 0;
|
|
case SND_SET_VOLUME_MDB:
|
|
TRY(set_volume_mdB(*static_cast<int32_t*>(arg)));
|
|
return 0;
|
|
}
|
|
|
|
return CharacterDevice::ioctl_impl(cmd, arg);
|
|
}
|
|
|
|
}
|