Kernel: Implement HD audio driver
This is very basic and does not support a lot of stuff (like changing the output pin :D)
This commit is contained in:
@@ -9,7 +9,7 @@ namespace Kernel
|
||||
class AC97AudioController : public AudioController, public Interruptable
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<AC97AudioController>> create(PCI::Device& pci_device);
|
||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||
|
||||
void handle_irq() override;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Kernel
|
||||
class AudioController : public CharacterDevice
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<AudioController>> create(PCI::Device& pci_device);
|
||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||
|
||||
dev_t rdev() const override { return m_rdev; }
|
||||
BAN::StringView name() const override { return m_name; }
|
||||
|
||||
74
kernel/include/kernel/Audio/HDAudio/AudioFunctionGroup.h
Normal file
74
kernel/include/kernel/Audio/HDAudio/AudioFunctionGroup.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Audio/Controller.h>
|
||||
#include <kernel/Audio/HDAudio/Controller.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class HDAudioController;
|
||||
|
||||
class HDAudioFunctionGroup : public AudioController
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
|
||||
|
||||
void on_stream_interrupt(uint8_t stream_index);
|
||||
|
||||
protected:
|
||||
// FIXME: allow setting these :D
|
||||
uint32_t get_channels() const override { return 2; }
|
||||
uint32_t get_sample_rate() const override { return 48000; }
|
||||
|
||||
void handle_new_data() override;
|
||||
|
||||
private:
|
||||
HDAudioFunctionGroup(BAN::RefPtr<HDAudioController> controller, uint8_t cid, HDAudio::AFGNode&& afg_node)
|
||||
: m_controller(controller)
|
||||
, m_afg_node(BAN::move(afg_node))
|
||||
, m_cid(cid)
|
||||
{ }
|
||||
~HDAudioFunctionGroup();
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
BAN::ErrorOr<void> initialize_stream();
|
||||
BAN::ErrorOr<void> initialize_output();
|
||||
BAN::ErrorOr<void> enable_output_path(uint8_t index);
|
||||
|
||||
void reset_stream();
|
||||
|
||||
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
|
||||
|
||||
uint16_t get_format_data() const;
|
||||
uint16_t get_volume_data() const;
|
||||
|
||||
size_t bdl_offset() const;
|
||||
|
||||
void queue_bdl_data();
|
||||
|
||||
private:
|
||||
static constexpr size_t m_max_path_length = 16;
|
||||
|
||||
// use 6 512 sample BDL entries
|
||||
// each entry is ~10.7 ms at 48 kHz
|
||||
// -> total buffered audio is 64 ms
|
||||
static constexpr size_t m_bdl_entry_sample_frames = 512;
|
||||
static constexpr size_t m_bdl_entry_count = 6;
|
||||
|
||||
BAN::RefPtr<HDAudioController> m_controller;
|
||||
const HDAudio::AFGNode m_afg_node;
|
||||
const uint8_t m_cid;
|
||||
|
||||
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
|
||||
size_t m_output_path_index { SIZE_MAX };
|
||||
|
||||
uint8_t m_stream_id { 0xFF };
|
||||
uint8_t m_stream_index { 0xFF };
|
||||
BAN::UniqPtr<DMARegion> m_bdl_region;
|
||||
|
||||
size_t m_bdl_head { 0 };
|
||||
size_t m_bdl_tail { 0 };
|
||||
bool m_stream_running { false };
|
||||
};
|
||||
|
||||
}
|
||||
77
kernel/include/kernel/Audio/HDAudio/Controller.h
Normal file
77
kernel/include/kernel/Audio/HDAudio/Controller.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <kernel/Audio/Controller.h>
|
||||
#include <kernel/Audio/HDAudio/Definitions.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class HDAudioController : public Interruptable, public BAN::RefCounted<HDAudioController>
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||
|
||||
BAN::ErrorOr<uint32_t> send_command(HDAudio::CORBEntry);
|
||||
|
||||
uint8_t get_stream_index(HDAudio::StreamType type, uint8_t index) const;
|
||||
|
||||
BAN::ErrorOr<uint8_t> allocate_stream_id();
|
||||
void deallocate_stream_id(uint8_t id);
|
||||
|
||||
BAN::ErrorOr<uint8_t> allocate_stream(HDAudio::StreamType type, void* afg);
|
||||
void deallocate_stream(uint8_t index);
|
||||
|
||||
PCI::BarRegion& bar0() { return *m_bar0; }
|
||||
|
||||
bool is_64bit() const { return m_is64bit; }
|
||||
|
||||
void handle_irq() override;
|
||||
|
||||
private:
|
||||
HDAudioController(PCI::Device& pci_device)
|
||||
: m_pci_device(pci_device)
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
BAN::ErrorOr<void> initialize_ring_buffers();
|
||||
|
||||
BAN::ErrorOr<void> reset_controller();
|
||||
|
||||
BAN::ErrorOr<HDAudio::Codec> initialize_codec(uint8_t codec);
|
||||
BAN::ErrorOr<HDAudio::AFGNode> initialize_node(uint8_t codec, uint8_t node);
|
||||
BAN::ErrorOr<HDAudio::AFGWidget> initialize_widget(uint8_t codec, uint8_t node);
|
||||
|
||||
private:
|
||||
struct RingBuffer
|
||||
{
|
||||
vaddr_t vaddr;
|
||||
uint32_t index;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
private:
|
||||
PCI::Device& m_pci_device;
|
||||
BAN::UniqPtr<PCI::BarRegion> m_bar0;
|
||||
bool m_is64bit { false };
|
||||
|
||||
bool m_use_immediate_command { false };
|
||||
|
||||
uint8_t m_output_streams { 0 };
|
||||
uint8_t m_input_streams { 0 };
|
||||
uint8_t m_bidir_streams { 0 };
|
||||
void* m_allocated_streams[30] {};
|
||||
|
||||
// NOTE: stream ids are from 1 to 15
|
||||
uint16_t m_allocated_stream_ids { 0 };
|
||||
|
||||
Mutex m_command_mutex;
|
||||
SpinLock m_rb_lock;
|
||||
ThreadBlocker m_rb_blocker;
|
||||
|
||||
RingBuffer m_corb;
|
||||
RingBuffer m_rirb;
|
||||
BAN::UniqPtr<DMARegion> m_ring_buffer_region;
|
||||
};
|
||||
|
||||
}
|
||||
78
kernel/include/kernel/Audio/HDAudio/Definitions.h
Normal file
78
kernel/include/kernel/Audio/HDAudio/Definitions.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace Kernel::HDAudio
|
||||
{
|
||||
|
||||
struct CORBEntry
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
uint32_t data : 8;
|
||||
uint32_t command : 12;
|
||||
uint32_t node_index : 8;
|
||||
uint32_t codec_address : 4;
|
||||
};
|
||||
uint32_t raw;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(CORBEntry) == sizeof(uint32_t));
|
||||
|
||||
struct BDLEntry
|
||||
{
|
||||
paddr_t address;
|
||||
uint32_t length;
|
||||
uint32_t ioc;
|
||||
};
|
||||
static_assert(sizeof(BDLEntry) == 16);
|
||||
|
||||
struct AFGWidget
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
OutputConverter,
|
||||
InputConverter,
|
||||
Mixer,
|
||||
Selector,
|
||||
PinComplex,
|
||||
Power,
|
||||
VolumeKnob,
|
||||
BeepGenerator,
|
||||
};
|
||||
|
||||
Type type;
|
||||
uint8_t id;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool input;
|
||||
bool output;
|
||||
} pin_complex;
|
||||
};
|
||||
|
||||
BAN::Vector<uint16_t> connections;
|
||||
};
|
||||
|
||||
struct AFGNode
|
||||
{
|
||||
uint8_t id;
|
||||
BAN::Vector<AFGWidget> widgets;
|
||||
};
|
||||
|
||||
struct Codec
|
||||
{
|
||||
uint8_t id;
|
||||
BAN::Vector<AFGNode> nodes;
|
||||
};
|
||||
|
||||
enum class StreamType
|
||||
{
|
||||
Input,
|
||||
Output,
|
||||
Bidirectional,
|
||||
};
|
||||
|
||||
}
|
||||
49
kernel/include/kernel/Audio/HDAudio/Registers.h
Normal file
49
kernel/include/kernel/Audio/HDAudio/Registers.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel::HDAudio
|
||||
{
|
||||
|
||||
enum Regs : uint8_t
|
||||
{
|
||||
GCAP = 0x00,
|
||||
VMIN = 0x02,
|
||||
VMAJ = 0x03,
|
||||
GCTL = 0x08,
|
||||
|
||||
INTCTL = 0x20,
|
||||
INTSTS = 0x24,
|
||||
|
||||
CORBLBASE = 0x40,
|
||||
CORBUBASE = 0x44,
|
||||
CORBWP = 0x48,
|
||||
CORBRP = 0x4A,
|
||||
CORBCTL = 0x4C,
|
||||
CORBSTS = 0x4D,
|
||||
CORBSIZE = 0x4E,
|
||||
|
||||
RIRBLBASE = 0x50,
|
||||
RIRBUBASE = 0x54,
|
||||
RIRBWP = 0x58,
|
||||
RINTCNT = 0x5A,
|
||||
RIRBCTL = 0x5C,
|
||||
RIRBSTS = 0x5D,
|
||||
RIRBSIZE = 0x5E,
|
||||
|
||||
ICOI = 0x60,
|
||||
ICII = 0x64,
|
||||
ICIS = 0x68,
|
||||
|
||||
SDCTL = 0x00,
|
||||
SDSTS = 0x03,
|
||||
SDLPIB = 0x04,
|
||||
SDCBL = 0x08,
|
||||
SDLVI = 0x0C,
|
||||
SDFIFOD = 0x10,
|
||||
SDFMT = 0x12,
|
||||
SDBDPL = 0x18,
|
||||
SDBDPU = 0x1C,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -70,6 +70,8 @@
|
||||
#define DEBUG_USB_MOUSE 0
|
||||
#define DEBUG_USB_MASS_STORAGE 0
|
||||
|
||||
#define DEBUG_HDAUDIO 0
|
||||
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user