Kernel: Implement basic AC97 driver

This commit is contained in:
2025-07-10 17:29:11 +03:00
parent 674e194a91
commit 8a663cb94f
9 changed files with 506 additions and 1 deletions

View File

@@ -0,0 +1,51 @@
#pragma once
#include <kernel/Audio/Controller.h>
#include <kernel/Memory/DMARegion.h>
namespace Kernel
{
class AC97AudioController : public AudioController, public Interruptable
{
public:
static BAN::ErrorOr<BAN::RefPtr<AC97AudioController>> create(PCI::Device& pci_device);
void handle_irq() override;
protected:
void handle_new_data() override;
uint32_t get_channels() const override { return 2; }
uint32_t get_sample_rate() const override { return 48000; }
private:
AC97AudioController(PCI::Device& pci_device)
: m_pci_device(pci_device)
{ }
BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize_bld();
BAN::ErrorOr<void> initialize_interrupts();
void queue_samples_to_bld();
private:
static constexpr size_t m_bdl_entries = 32;
static constexpr size_t m_samples_per_entry = 0x1000;
// We only store samples in 2 BDL entries at a time to reduce the amount of samples queued.
// This is to reduce latency as you cannot remove data already passed to the BDLs
static constexpr size_t m_used_bdl_entries = 2;
PCI::Device& m_pci_device;
BAN::UniqPtr<PCI::BarRegion> m_mixer;
BAN::UniqPtr<PCI::BarRegion> m_bus_master;
BAN::UniqPtr<DMARegion> m_bdl_region;
uint32_t m_bdl_tail { 0 };
uint32_t m_bdl_head { 0 };
};
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
namespace Kernel::AC97
{
struct BufferDescriptorListEntry
{
uint32_t address;
uint16_t samples;
uint16_t flags; // bit 14: last entry, bit 15: IOC
};
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include <kernel/Device/Device.h>
#include <kernel/PCI.h>
namespace Kernel
{
class AudioController : public CharacterDevice
{
public:
static BAN::ErrorOr<BAN::RefPtr<AudioController>> create(PCI::Device& pci_device);
dev_t rdev() const override { return m_rdev; }
BAN::StringView name() const override { return m_name; }
protected:
AudioController();
virtual void handle_new_data() = 0;
virtual uint32_t get_channels() const = 0;
virtual uint32_t get_sample_rate() const = 0;
bool can_read_impl() const override { return false; }
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return m_sample_data_size < m_sample_data_capacity; }
bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; }
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
BAN::ErrorOr<long> ioctl_impl(int cmd, void* arg) override;
protected:
ThreadBlocker m_sample_data_blocker;
mutable SpinLock m_spinlock;
static constexpr size_t m_sample_data_capacity = 1 << 20;
uint8_t m_sample_data[m_sample_data_capacity];
size_t m_sample_data_head { 0 };
size_t m_sample_data_size { 0 };
private:
const dev_t m_rdev;
char m_name[10] {};
};
}

View File

@@ -22,6 +22,7 @@ namespace Kernel
Ethernet,
Loopback,
TmpFS,
AudioController,
};
}