Kernel: Implement basic AC97 driver
This commit is contained in:
parent
674e194a91
commit
8a663cb94f
|
@ -6,6 +6,8 @@ set(KERNEL_SOURCES
|
||||||
kernel/ACPI/AML/OpRegion.cpp
|
kernel/ACPI/AML/OpRegion.cpp
|
||||||
kernel/ACPI/BatterySystem.cpp
|
kernel/ACPI/BatterySystem.cpp
|
||||||
kernel/APIC.cpp
|
kernel/APIC.cpp
|
||||||
|
kernel/Audio/AC97/Controller.cpp
|
||||||
|
kernel/Audio/Controller.cpp
|
||||||
kernel/BootInfo.cpp
|
kernel/BootInfo.cpp
|
||||||
kernel/CPUID.cpp
|
kernel/CPUID.cpp
|
||||||
kernel/Credentials.cpp
|
kernel/Credentials.cpp
|
||||||
|
|
|
@ -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 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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] {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ namespace Kernel
|
||||||
Ethernet,
|
Ethernet,
|
||||||
Loopback,
|
Loopback,
|
||||||
TmpFS,
|
TmpFS,
|
||||||
|
AudioController,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
#include <kernel/Audio/AC97/Controller.h>
|
||||||
|
#include <kernel/Audio/AC97/Definitions.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
enum AudioMixerRegister : uint8_t
|
||||||
|
{
|
||||||
|
Reset = 0x00,
|
||||||
|
MasterVolume = 0x02,
|
||||||
|
AuxOutVolume = 0x04,
|
||||||
|
MonoVolume = 0x06,
|
||||||
|
MasterToneRL = 0x08,
|
||||||
|
PC_BEEPVolume = 0x0A,
|
||||||
|
PhoneVolume = 0x0C,
|
||||||
|
MicVolume = 0x0E,
|
||||||
|
LineInVolume = 0x10,
|
||||||
|
CDVolume = 0x12,
|
||||||
|
VideoVolume = 0x14,
|
||||||
|
AuxInVolume = 0x16,
|
||||||
|
PCMOutVolume = 0x18,
|
||||||
|
RecordSelect = 0x1A,
|
||||||
|
RecordGain = 0x1C,
|
||||||
|
RecordGainMic = 0x1E,
|
||||||
|
GeneralPurpose = 0x20,
|
||||||
|
_3DControl = 0x22,
|
||||||
|
PowerdownCtrlStat = 0x26,
|
||||||
|
ExtendedAudio = 0x28,
|
||||||
|
ExtendedAudioCtrlStat = 0x2A,
|
||||||
|
PCMFrontDACRate = 0x2C,
|
||||||
|
PCMSurroundDACRate = 0x2E,
|
||||||
|
PCMLFEDACRate = 0x30,
|
||||||
|
PCMLRADCRate = 0x32,
|
||||||
|
MICADCRate = 0x34,
|
||||||
|
_6ChVolC_LFE = 0x36,
|
||||||
|
_6ChVolL_R_Surround = 0x38,
|
||||||
|
S_PDIFControl = 0x3A
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BusMasterRegister : uint8_t
|
||||||
|
{
|
||||||
|
PI_BDBAR = 0x00,
|
||||||
|
PI_CIV = 0x04,
|
||||||
|
PI_LVI = 0x05,
|
||||||
|
PI_SR = 0x06,
|
||||||
|
PI_PICB = 0x08,
|
||||||
|
PI_PIV = 0x0A,
|
||||||
|
PI_CR = 0x0B,
|
||||||
|
PO_BDBAR = 0x10,
|
||||||
|
PO_CIV = 0x14,
|
||||||
|
PO_LVI = 0x15,
|
||||||
|
PO_SR = 0x16,
|
||||||
|
PO_PICB = 0x18,
|
||||||
|
PO_PIV = 0x1A,
|
||||||
|
PO_CR = 0x1B,
|
||||||
|
MC_BDBAR = 0x20,
|
||||||
|
MC_CIV = 0x24,
|
||||||
|
MC_LVI = 0x25,
|
||||||
|
MC_SR = 0x26,
|
||||||
|
MC_PICB = 0x28,
|
||||||
|
MC_PIV = 0x2A,
|
||||||
|
MC_CR = 0x2B,
|
||||||
|
GLOB_CNT = 0x2C,
|
||||||
|
GLOB_STA = 0x30,
|
||||||
|
CAS = 0x34,
|
||||||
|
MC2_BDBAR = 0x40,
|
||||||
|
MC2_CIV = 0x44,
|
||||||
|
MC2_LVI = 0x45,
|
||||||
|
MC2_SR = 0x46,
|
||||||
|
MC2_PICB = 0x48,
|
||||||
|
MC2_PIV = 0x4A,
|
||||||
|
MC2_CR = 0x4B,
|
||||||
|
PI2_BDBAR = 0x50,
|
||||||
|
PI2_CIV = 0x54,
|
||||||
|
PI2_LVI = 0x55,
|
||||||
|
PI2_SR = 0x56,
|
||||||
|
PI2_PICB = 0x58,
|
||||||
|
PI2_PIV = 0x5A,
|
||||||
|
PI2_CR = 0x5B,
|
||||||
|
SPBAR = 0x60,
|
||||||
|
SPCIV = 0x64,
|
||||||
|
SPLVI = 0x65,
|
||||||
|
SPSR = 0x66,
|
||||||
|
SPPICB = 0x68,
|
||||||
|
SPPIV = 0x6A,
|
||||||
|
SPCR = 0x6B,
|
||||||
|
SDM = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BusMasterStatus : uint16_t
|
||||||
|
{
|
||||||
|
DMAHalted = 1 << 0,
|
||||||
|
CELV = 1 << 1,
|
||||||
|
LVBCI = 1 << 2,
|
||||||
|
BCIS = 1 << 3,
|
||||||
|
FIFOE = 1 << 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BusMasterControl : uint8_t
|
||||||
|
{
|
||||||
|
RDBM = 1 << 0,
|
||||||
|
RR = 1 << 1,
|
||||||
|
LVBIE = 1 << 2,
|
||||||
|
FEIE = 1 << 3,
|
||||||
|
IOCE = 1 << 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<AC97AudioController>> AC97AudioController::create(PCI::Device& pci_device)
|
||||||
|
{
|
||||||
|
auto* ac97_ptr = new AC97AudioController(pci_device);
|
||||||
|
if (ac97_ptr == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
auto ac97 = BAN::RefPtr<AC97AudioController>::adopt(ac97_ptr);
|
||||||
|
TRY(ac97->initialize());
|
||||||
|
return ac97;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> AC97AudioController::initialize()
|
||||||
|
{
|
||||||
|
m_pci_device.enable_bus_mastering();
|
||||||
|
|
||||||
|
m_mixer = TRY(m_pci_device.allocate_bar_region(0));
|
||||||
|
m_bus_master = TRY(m_pci_device.allocate_bar_region(1));
|
||||||
|
|
||||||
|
if (m_mixer->size() < 0x34 || m_bus_master->size() < 0x34)
|
||||||
|
return BAN::Error::from_errno(ENODEV);
|
||||||
|
|
||||||
|
// Reset bus master
|
||||||
|
m_bus_master->write32(BusMasterRegister::GLOB_CNT, 0x00);
|
||||||
|
|
||||||
|
// no interrupts, 2 channels, 16 bit samples
|
||||||
|
m_bus_master->write32(BusMasterRegister::GLOB_CNT, 0x02);
|
||||||
|
|
||||||
|
// Reset mixer to default values
|
||||||
|
m_mixer->write16(AudioMixerRegister::Reset, 0);
|
||||||
|
|
||||||
|
// Master volume 100%, no mute
|
||||||
|
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x0000);
|
||||||
|
|
||||||
|
// PCM output volume left/right +0 db, no mute
|
||||||
|
m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808);
|
||||||
|
|
||||||
|
TRY(initialize_bld());
|
||||||
|
|
||||||
|
TRY(initialize_interrupts());
|
||||||
|
|
||||||
|
// disable transfer, enable all interrupts
|
||||||
|
m_bus_master->write8(BusMasterRegister::PO_CR, IOCE | FEIE | LVBIE);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> AC97AudioController::initialize_bld()
|
||||||
|
{
|
||||||
|
const size_t bdl_size = sizeof(AC97::BufferDescriptorListEntry) * m_bdl_entries;
|
||||||
|
const size_t buffer_size = m_samples_per_entry * sizeof(int16_t);
|
||||||
|
|
||||||
|
m_bdl_region = TRY(DMARegion::create(bdl_size + buffer_size * m_used_bdl_entries));
|
||||||
|
memset(reinterpret_cast<void*>(m_bdl_region->vaddr()), 0x00, m_bdl_region->size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_bdl_entries; i++)
|
||||||
|
{
|
||||||
|
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[i];
|
||||||
|
entry.address = m_bdl_region->paddr() + bdl_size + (i % m_used_bdl_entries) * buffer_size;
|
||||||
|
entry.samples = 0;
|
||||||
|
entry.flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bus_master->write32(BusMasterRegister::PO_BDBAR, m_bdl_region->paddr());
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> AC97AudioController::initialize_interrupts()
|
||||||
|
{
|
||||||
|
TRY(m_pci_device.reserve_interrupts(1));
|
||||||
|
m_pci_device.enable_interrupt(0, *this);
|
||||||
|
|
||||||
|
// enable interrupts
|
||||||
|
m_bus_master->write32(BusMasterRegister::GLOB_CNT, m_bus_master->read32(BusMasterRegister::GLOB_CNT) | 0x01);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void AC97AudioController::handle_new_data()
|
||||||
|
{
|
||||||
|
ASSERT(m_spinlock.current_processor_has_lock());
|
||||||
|
|
||||||
|
if (m_bdl_head != m_bdl_tail)
|
||||||
|
return;
|
||||||
|
|
||||||
|
queue_samples_to_bld();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AC97AudioController::queue_samples_to_bld()
|
||||||
|
{
|
||||||
|
ASSERT(m_spinlock.current_processor_has_lock());
|
||||||
|
|
||||||
|
uint32_t lvi = m_bdl_head;
|
||||||
|
|
||||||
|
while (m_bdl_head != (m_bdl_tail + m_used_bdl_entries) % m_bdl_entries)
|
||||||
|
{
|
||||||
|
const uint32_t next_bld_head = (m_bdl_head + 1) % m_bdl_entries;
|
||||||
|
if (next_bld_head == m_bdl_tail)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const size_t sample_data_tail = (m_sample_data_head + m_sample_data_capacity - m_sample_data_size) % m_sample_data_capacity;
|
||||||
|
|
||||||
|
const size_t max_memcpy = BAN::Math::min(m_sample_data_size, m_sample_data_capacity - sample_data_tail);
|
||||||
|
const size_t samples = BAN::Math::min(max_memcpy / 2, m_samples_per_entry);
|
||||||
|
if (samples == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
auto& entry = reinterpret_cast<AC97::BufferDescriptorListEntry*>(m_bdl_region->vaddr())[m_bdl_head];
|
||||||
|
entry.samples = samples;
|
||||||
|
entry.flags = (1 << 15);
|
||||||
|
memcpy(
|
||||||
|
reinterpret_cast<void*>(m_bdl_region->paddr_to_vaddr(entry.address)),
|
||||||
|
&m_sample_data[sample_data_tail],
|
||||||
|
samples * 2
|
||||||
|
);
|
||||||
|
|
||||||
|
m_sample_data_size -= samples * 2;
|
||||||
|
|
||||||
|
lvi = m_bdl_head;
|
||||||
|
m_bdl_head = next_bld_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if head was not updated, no data was queued
|
||||||
|
if (lvi == m_bdl_head)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_sample_data_blocker.unblock();
|
||||||
|
|
||||||
|
m_bus_master->write8(BusMasterRegister::PO_LVI, lvi);
|
||||||
|
|
||||||
|
// start playing if we are not already
|
||||||
|
const uint8_t control = m_bus_master->read8(BusMasterRegister::PO_CR);
|
||||||
|
if (!(control & RDBM))
|
||||||
|
m_bus_master->write8(BusMasterRegister::PO_CR, control | RDBM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AC97AudioController::handle_irq()
|
||||||
|
{
|
||||||
|
const uint16_t status = m_bus_master->read16(BusMasterRegister::PO_SR);
|
||||||
|
if (!(status & (LVBCI | BCIS | FIFOE)))
|
||||||
|
return;
|
||||||
|
m_bus_master->write16(BusMasterRegister::PO_SR, LVBCI | BCIS | FIFOE);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_spinlock);
|
||||||
|
|
||||||
|
if (status & LVBCI)
|
||||||
|
{
|
||||||
|
const uint8_t control = m_bus_master->read8(BusMasterRegister::PO_CR);
|
||||||
|
m_bus_master->write8(BusMasterRegister::PO_CR, control & ~RDBM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & BCIS)
|
||||||
|
{
|
||||||
|
m_bdl_tail = (m_bdl_tail + 1) % m_bdl_entries;
|
||||||
|
queue_samples_to_bld();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
#include <kernel/Audio/AC97/Controller.h>
|
||||||
|
#include <kernel/Audio/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<BAN::RefPtr<AudioController>> 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())
|
||||||
|
{
|
||||||
|
DevFileSystem::get().add_device(ret.value());
|
||||||
|
return BAN::RefPtr<AudioController>(ret.release_value());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwarnln("Failed to initialize AC97: {}", ret.error());
|
||||||
|
return ret.release_error();
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
#include <BAN/ScopeGuard.h>
|
#include <BAN/ScopeGuard.h>
|
||||||
|
|
||||||
#include <kernel/APIC.h>
|
|
||||||
#include <kernel/ACPI/ACPI.h>
|
#include <kernel/ACPI/ACPI.h>
|
||||||
|
#include <kernel/APIC.h>
|
||||||
|
#include <kernel/Audio/Controller.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
@ -228,6 +229,18 @@ namespace Kernel::PCI
|
||||||
dprintln("{}", res.error());
|
dprintln("{}", res.error());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 0x04:
|
||||||
|
{
|
||||||
|
switch (pci_device.subclass())
|
||||||
|
{
|
||||||
|
case 0x01:
|
||||||
|
case 0x03:
|
||||||
|
if (auto res = AudioController::create(pci_device); res.is_error())
|
||||||
|
dprintln("Sound Card: {}", res.error());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 0x0C:
|
case 0x0C:
|
||||||
{
|
{
|
||||||
switch (pci_device.subclass())
|
switch (pci_device.subclass())
|
||||||
|
|
|
@ -47,6 +47,11 @@ struct winsize
|
||||||
#define TIOCGWINSZ 50
|
#define TIOCGWINSZ 50
|
||||||
#define TIOCSWINSZ 51
|
#define TIOCSWINSZ 51
|
||||||
|
|
||||||
|
#define SND_GET_CHANNELS 60 /* stores number of channels to uint32_t argument */
|
||||||
|
#define SND_GET_SAMPLE_RATE 61 /* stores sample rate to uint32_t argument */
|
||||||
|
#define SND_RESET_BUFFER 62 /* stores the size of internal buffer to uint32_t argument and clears the buffer */
|
||||||
|
#define SND_GET_BUFFERSZ 63 /* stores the size of internal buffer to uint32_t argument */
|
||||||
|
|
||||||
int ioctl(int, int, ...);
|
int ioctl(int, int, ...);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
Loading…
Reference in New Issue