summaryrefslogtreecommitdiff
path: root/Kernel/Devices
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Devices')
-rw-r--r--Kernel/Devices/Audio/AC97.cpp71
-rw-r--r--Kernel/Devices/Audio/AC97.h31
-rw-r--r--Kernel/Devices/Audio/Channel.cpp73
-rw-r--r--Kernel/Devices/Audio/Channel.h43
-rw-r--r--Kernel/Devices/Audio/Controller.h45
-rw-r--r--Kernel/Devices/Audio/Management.cpp82
-rw-r--r--Kernel/Devices/Audio/Management.h38
-rw-r--r--Kernel/Devices/Audio/SB16.cpp79
-rw-r--r--Kernel/Devices/Audio/SB16.h30
-rw-r--r--Kernel/Devices/DeviceManagement.cpp5
-rw-r--r--Kernel/Devices/DeviceManagement.h4
11 files changed, 378 insertions, 123 deletions
diff --git a/Kernel/Devices/Audio/AC97.cpp b/Kernel/Devices/Audio/AC97.cpp
index b19ab3b00b..d603313f9b 100644
--- a/Kernel/Devices/Audio/AC97.cpp
+++ b/Kernel/Devices/Audio/AC97.cpp
@@ -7,7 +7,6 @@
#include <Kernel/Devices/Audio/AC97.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Memory/AnonymousVMObject.h>
-#include <LibC/sys/ioctl_numbers.h>
namespace Kernel {
@@ -20,28 +19,14 @@ static constexpr u16 pcm_fixed_sample_rate = 48000;
static constexpr u16 pcm_sample_rate_minimum = 8000;
static constexpr u16 pcm_sample_rate_maximum = 48000;
-UNMAP_AFTER_INIT void AC97::detect()
+UNMAP_AFTER_INIT ErrorOr<NonnullRefPtr<AC97>> AC97::try_create(PCI::DeviceIdentifier const& pci_device_identifier)
{
- PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) {
- // Only consider PCI audio controllers
- if (device_identifier.class_code().value() != to_underlying(PCI::ClassID::Multimedia)
- || device_identifier.subclass_code().value() != to_underlying(PCI::Multimedia::SubclassID::AudioController))
- return;
-
- dbgln("AC97: found audio controller at {}", device_identifier.address());
- auto device_or_error = DeviceManagement::try_create_device<AC97>(device_identifier);
- if (device_or_error.is_error()) {
- dbgln("AC97: failed to initialize device {}", device_identifier.address());
- return;
- }
- DeviceManagement::the().attach_audio_device(device_or_error.release_value());
- });
+ return adopt_nonnull_ref_or_enomem(new (nothrow) AC97(pci_device_identifier));
}
UNMAP_AFTER_INIT AC97::AC97(PCI::DeviceIdentifier const& pci_device_identifier)
: PCI::Device(pci_device_identifier.address())
, IRQHandler(pci_device_identifier.interrupt_line().value())
- , CharacterDevice(42, 42)
, m_io_mixer_base(PCI::get_BAR0(pci_address()) & ~1)
, m_io_bus_base(PCI::get_BAR1(pci_address()) & ~1)
, m_pcm_out_channel(channel("PCMOut"sv, NativeAudioBusChannel::PCMOutChannel))
@@ -129,28 +114,6 @@ UNMAP_AFTER_INIT void AC97::initialize()
enable_irq();
}
-ErrorOr<void> AC97::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
-{
- switch (request) {
- case SOUNDCARD_IOCTL_GET_SAMPLE_RATE: {
- auto output = static_ptr_cast<u32*>(arg);
- return copy_to_user(output, &m_sample_rate);
- }
- case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
- auto sample_rate = static_cast<u32>(arg.ptr());
- TRY(set_pcm_output_sample_rate(sample_rate));
- return {};
- }
- default:
- return EINVAL;
- }
-}
-
-ErrorOr<size_t> AC97::read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t)
-{
- return 0;
-}
-
void AC97::reset_pcm_out()
{
m_pcm_out_channel.reset();
@@ -194,8 +157,36 @@ void AC97::set_pcm_output_volume(u8 left_channel, u8 right_channel, Muted mute)
m_io_mixer_base.offset(NativeAudioMixerRegister::SetPCMOutputVolume).out(volume_value);
}
-ErrorOr<size_t> AC97::write(OpenFileDescription&, u64, UserOrKernelBuffer const& data, size_t length)
+RefPtr<AudioChannel> AC97::audio_channel(u32 index) const
{
+ if (index == 0)
+ return m_audio_channel;
+ return {};
+}
+void AC97::detect_hardware_audio_channels(Badge<AudioManagement>)
+{
+ m_audio_channel = AudioChannel::must_create(*this, 0);
+}
+
+ErrorOr<void> AC97::set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate)
+{
+ if (channel_index != 0)
+ return Error::from_errno(ENODEV);
+ TRY(set_pcm_output_sample_rate(samples_per_second_rate));
+ return {};
+}
+ErrorOr<u32> AC97::get_pcm_output_sample_rate(size_t channel_index)
+{
+ if (channel_index != 0)
+ return Error::from_errno(ENODEV);
+ return m_sample_rate;
+}
+
+ErrorOr<size_t> AC97::write(size_t channel_index, UserOrKernelBuffer const& data, size_t length)
+{
+ if (channel_index != 0)
+ return Error::from_errno(ENODEV);
+
if (!m_output_buffer) {
m_output_buffer = TRY(MM.allocate_dma_buffer_pages(m_output_buffer_page_count * PAGE_SIZE, "AC97 Output buffer"sv, Memory::Region::Access::Write));
}
diff --git a/Kernel/Devices/Audio/AC97.h b/Kernel/Devices/Audio/AC97.h
index 56c31acd9e..a20fb9d2ec 100644
--- a/Kernel/Devices/Audio/AC97.h
+++ b/Kernel/Devices/Audio/AC97.h
@@ -9,6 +9,7 @@
#include <Kernel/Arch/x86/IO.h>
#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Bus/PCI/Device.h>
+#include <Kernel/Devices/Audio/Controller.h>
#include <Kernel/Devices/CharacterDevice.h>
#include <Kernel/Interrupts/IRQHandler.h>
@@ -17,25 +18,18 @@ namespace Kernel {
// See: https://www-inst.eecs.berkeley.edu/~cs150/Documents/ac97_r23.pdf
// And: https://www.intel.com/content/dam/doc/manual/io-controller-hub-7-hd-audio-ac97-manual.pdf
-class AC97 final : public PCI::Device
- , public IRQHandler
- , public CharacterDevice {
- friend class DeviceManagement;
+class AC97 final
+ : public AudioController
+ , public PCI::Device
+ , public IRQHandler {
public:
- static void detect();
+ static ErrorOr<NonnullRefPtr<AC97>> try_create(PCI::DeviceIdentifier const&);
virtual ~AC97() override;
// ^IRQHandler
- virtual StringView purpose() const override { return class_name(); }
-
- // ^CharacterDevice
- virtual bool can_read(const OpenFileDescription&, u64) const override { return false; }
- virtual bool can_write(const OpenFileDescription&, u64) const override { return true; }
- virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned, Userspace<void*>) override;
- virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override;
- virtual ErrorOr<size_t> write(OpenFileDescription&, u64, const UserOrKernelBuffer&, size_t) override;
+ virtual StringView purpose() const override { return "AC97"sv; }
private:
enum NativeAudioMixerRegister : u8 {
@@ -150,9 +144,6 @@ private:
// ^IRQHandler
virtual bool handle_irq(const RegisterState&) override;
- // ^CharacterDevice
- virtual StringView class_name() const override { return "AC97"sv; }
-
AC97Channel channel(StringView name, NativeAudioBusChannel channel) { return AC97Channel(*this, name, m_io_bus_base.offset(channel)); }
void initialize();
void reset_pcm_out();
@@ -161,6 +152,13 @@ private:
void set_pcm_output_volume(u8, u8, Muted);
ErrorOr<void> write_single_buffer(UserOrKernelBuffer const&, size_t, size_t);
+ // ^AudioController
+ virtual RefPtr<AudioChannel> audio_channel(u32 index) const override;
+ virtual ErrorOr<size_t> write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) override;
+ virtual void detect_hardware_audio_channels(Badge<AudioManagement>) override;
+ virtual ErrorOr<void> set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate) override;
+ virtual ErrorOr<u32> get_pcm_output_sample_rate(size_t channel_index) override;
+
OwnPtr<Memory::Region> m_buffer_descriptor_list;
u8 m_buffer_descriptor_list_index = 0;
bool m_double_rate_pcm_enabled = false;
@@ -173,6 +171,7 @@ private:
AC97Channel m_pcm_out_channel;
u32 m_sample_rate = 0;
bool m_variable_rate_pcm_supported = false;
+ RefPtr<AudioChannel> m_audio_channel;
};
}
diff --git a/Kernel/Devices/Audio/Channel.cpp b/Kernel/Devices/Audio/Channel.cpp
new file mode 100644
index 0000000000..ac390d7aed
--- /dev/null
+++ b/Kernel/Devices/Audio/Channel.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <Kernel/Devices/Audio/Management.h>
+#include <Kernel/Devices/DeviceManagement.h>
+#include <Kernel/Devices/RandomDevice.h>
+#include <Kernel/Random.h>
+#include <Kernel/Sections.h>
+#include <LibC/sys/ioctl_numbers.h>
+
+namespace Kernel {
+
+UNMAP_AFTER_INIT NonnullRefPtr<AudioChannel> AudioChannel::must_create(AudioController const& controller, size_t channel_index)
+{
+ auto audio_device_or_error = DeviceManagement::try_create_device<AudioChannel>(controller, channel_index);
+ // FIXME: Find a way to propagate errors
+ VERIFY(!audio_device_or_error.is_error());
+ return audio_device_or_error.release_value();
+}
+
+AudioChannel::AudioChannel(AudioController const& controller, size_t channel_index)
+ : CharacterDevice(AudioManagement::the().audio_type_major_number(), AudioManagement::the().generate_storage_minor_number())
+ , m_controller(controller)
+ , m_channel_index(channel_index)
+{
+}
+
+ErrorOr<void> AudioChannel::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
+{
+ auto controller = m_controller.strong_ref();
+ if (!controller)
+ return Error::from_errno(EIO);
+ switch (request) {
+ case SOUNDCARD_IOCTL_GET_SAMPLE_RATE: {
+ auto output = static_ptr_cast<u32*>(arg);
+ u32 sample_rate = 0;
+ sample_rate = TRY(controller->get_pcm_output_sample_rate(m_channel_index));
+ return copy_to_user(output, &sample_rate);
+ }
+ case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
+ auto sample_rate = static_cast<u32>(arg.ptr());
+ TRY(controller->set_pcm_output_sample_rate(m_channel_index, sample_rate));
+ return {};
+ }
+ default:
+ return EINVAL;
+ }
+}
+
+bool AudioChannel::can_read(const OpenFileDescription&, u64) const
+{
+ // FIXME: Implement input from device
+ return false;
+}
+
+ErrorOr<size_t> AudioChannel::read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t)
+{
+ // FIXME: Implement input from device
+ return Error::from_errno(ENOTIMPL);
+}
+
+ErrorOr<size_t> AudioChannel::write(OpenFileDescription&, u64, UserOrKernelBuffer const& buffer, size_t size)
+{
+ auto controller = m_controller.strong_ref();
+ if (!controller)
+ return Error::from_errno(EIO);
+ return controller->write(m_channel_index, buffer, size);
+}
+
+}
diff --git a/Kernel/Devices/Audio/Channel.h b/Kernel/Devices/Audio/Channel.h
new file mode 100644
index 0000000000..08da059352
--- /dev/null
+++ b/Kernel/Devices/Audio/Channel.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <Kernel/Devices/CharacterDevice.h>
+#include <Kernel/Interrupts/IRQHandler.h>
+#include <Kernel/Memory/PhysicalPage.h>
+#include <Kernel/PhysicalAddress.h>
+#include <Kernel/WaitQueue.h>
+
+namespace Kernel {
+
+class AudioController;
+class AudioChannel final
+ : public CharacterDevice {
+ friend class DeviceManagement;
+
+public:
+ static NonnullRefPtr<AudioChannel> must_create(AudioController const&, size_t channel_index);
+ virtual ~AudioChannel() override { }
+
+ // ^CharacterDevice
+ virtual bool can_read(const OpenFileDescription&, u64) const override;
+ virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override;
+ virtual ErrorOr<size_t> write(OpenFileDescription&, u64, const UserOrKernelBuffer&, size_t) override;
+ virtual bool can_write(const OpenFileDescription&, u64) const override { return true; }
+
+ virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned, Userspace<void*>) override;
+
+private:
+ AudioChannel(AudioController const&, size_t channel_index);
+
+ // ^CharacterDevice
+ virtual StringView class_name() const override { return "AudioChannel"sv; }
+
+ WeakPtr<AudioController> m_controller;
+ const size_t m_channel_index;
+};
+}
diff --git a/Kernel/Devices/Audio/Controller.h b/Kernel/Devices/Audio/Controller.h
new file mode 100644
index 0000000000..0b63c50eb6
--- /dev/null
+++ b/Kernel/Devices/Audio/Controller.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/IntrusiveList.h>
+#include <AK/OwnPtr.h>
+#include <AK/RefPtr.h>
+#include <AK/Weakable.h>
+#include <Kernel/Bus/PCI/Access.h>
+#include <Kernel/Bus/PCI/Device.h>
+#include <Kernel/Devices/Audio/Channel.h>
+#include <Kernel/Devices/Device.h>
+#include <Kernel/Locking/Mutex.h>
+#include <Kernel/Memory/PhysicalPage.h>
+#include <Kernel/PhysicalAddress.h>
+#include <Kernel/Random.h>
+
+namespace Kernel {
+
+class AudioManagement;
+class AudioController
+ : public RefCounted<AudioController>
+ , public Weakable<AudioController> {
+ friend class AudioManagement;
+
+public:
+ virtual ~AudioController() = default;
+
+ virtual RefPtr<AudioChannel> audio_channel(u32 index) const = 0;
+ virtual ErrorOr<size_t> write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) = 0;
+
+ virtual void detect_hardware_audio_channels(Badge<AudioManagement>) = 0;
+
+ virtual ErrorOr<void> set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate) = 0;
+ // Note: The return value is rate of samples per second
+ virtual ErrorOr<u32> get_pcm_output_sample_rate(size_t channel_index) = 0;
+
+private:
+ IntrusiveListNode<AudioController, RefPtr<AudioController>> m_node;
+};
+}
diff --git a/Kernel/Devices/Audio/Management.cpp b/Kernel/Devices/Audio/Management.cpp
new file mode 100644
index 0000000000..095b3c796b
--- /dev/null
+++ b/Kernel/Devices/Audio/Management.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Singleton.h>
+#include <Kernel/Bus/PCI/API.h>
+#include <Kernel/Bus/PCI/IDs.h>
+#include <Kernel/Devices/Audio/AC97.h>
+#include <Kernel/Devices/Audio/Management.h>
+#include <Kernel/Devices/Audio/SB16.h>
+#include <Kernel/Sections.h>
+
+namespace Kernel {
+
+static Singleton<AudioManagement> s_the;
+static Atomic<u32> s_device_minor_number;
+
+MajorNumber AudioManagement::audio_type_major_number()
+{
+ return 116;
+}
+MinorNumber AudioManagement::generate_storage_minor_number()
+{
+ auto minor_number = s_device_minor_number.load();
+ s_device_minor_number++;
+ return minor_number;
+}
+
+AudioManagement& AudioManagement::the()
+{
+ return *s_the;
+}
+
+UNMAP_AFTER_INIT AudioManagement::AudioManagement()
+{
+}
+
+UNMAP_AFTER_INIT void AudioManagement::enumerate_hardware_controllers()
+{
+ if (auto controller = SB16::try_detect_and_create(); !controller.is_error())
+ m_controllers_list.append(controller.release_value());
+
+ PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) {
+ // Note: Only consider PCI audio controllers
+ if (device_identifier.class_code().value() != to_underlying(PCI::ClassID::Multimedia)
+ || device_identifier.subclass_code().value() != to_underlying(PCI::Multimedia::SubclassID::AudioController))
+ return;
+
+ dbgln("AC97: found audio controller at {}", device_identifier.address());
+ // FIXME: Propagate errors properly
+ m_controllers_list.append(AC97::try_create(device_identifier).release_value());
+ });
+}
+
+UNMAP_AFTER_INIT void AudioManagement::enumerate_hardware_audio_channels()
+{
+ for (auto& controller : m_controllers_list)
+ controller.detect_hardware_audio_channels({});
+}
+
+UNMAP_AFTER_INIT bool AudioManagement::initialize()
+{
+
+ /* Explanation on the flow:
+ * 1. Enumerate all audio controllers connected to the system:
+ * a. Try to find the SB16 ISA-based controller.
+ * b. Enumerate the PCI bus and try to find audio controllers there too
+ * 2. Ask each controller to detect the audio channels and instantiate AudioChannel objects.
+ */
+ enumerate_hardware_controllers();
+ enumerate_hardware_audio_channels();
+
+ if (m_controllers_list.is_empty()) {
+ dbgln("No audio controller was initialized.");
+ return false;
+ }
+ return true;
+}
+
+}
diff --git a/Kernel/Devices/Audio/Management.h b/Kernel/Devices/Audio/Management.h
new file mode 100644
index 0000000000..9294fa881c
--- /dev/null
+++ b/Kernel/Devices/Audio/Management.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Badge.h>
+#include <AK/Error.h>
+#include <AK/IntrusiveList.h>
+#include <AK/OwnPtr.h>
+#include <AK/RefPtr.h>
+#include <AK/Time.h>
+#include <AK/Types.h>
+#include <Kernel/Devices/Audio/Controller.h>
+
+namespace Kernel {
+
+class AudioManagement {
+
+public:
+ AudioManagement();
+ static AudioManagement& the();
+
+ static MajorNumber audio_type_major_number();
+ static MinorNumber generate_storage_minor_number();
+
+ bool initialize();
+
+private:
+ void enumerate_hardware_controllers();
+ void enumerate_hardware_audio_channels();
+
+ IntrusiveList<&AudioController::m_node> m_controllers_list;
+};
+
+}
diff --git a/Kernel/Devices/Audio/SB16.cpp b/Kernel/Devices/Audio/SB16.cpp
index b654060ba1..2d23118538 100644
--- a/Kernel/Devices/Audio/SB16.cpp
+++ b/Kernel/Devices/Audio/SB16.cpp
@@ -62,8 +62,6 @@ void SB16::set_sample_rate(uint16_t hz)
UNMAP_AFTER_INIT SB16::SB16()
: IRQHandler(SB16_DEFAULT_IRQ)
- // FIXME: We can't change version numbers later, i.e. after the sound card is initialized.
- , CharacterDevice(42, 42)
{
initialize();
}
@@ -72,7 +70,7 @@ UNMAP_AFTER_INIT SB16::~SB16()
{
}
-UNMAP_AFTER_INIT RefPtr<SB16> SB16::try_detect_and_create()
+UNMAP_AFTER_INIT ErrorOr<NonnullRefPtr<SB16>> SB16::try_detect_and_create()
{
IO::out8(0x226, 1);
IO::delay(32);
@@ -80,13 +78,8 @@ UNMAP_AFTER_INIT RefPtr<SB16> SB16::try_detect_and_create()
auto data = dsp_read();
if (data != 0xaa)
- return {};
- auto device_or_error = DeviceManagement::try_create_device<SB16>();
- if (device_or_error.is_error())
- return {};
- auto device = device_or_error.release_value();
- DeviceManagement::the().attach_audio_device(device);
- return device;
+ return Error::from_errno(ENODEV);
+ return adopt_nonnull_ref_or_enomem(new (nothrow) SB16());
}
UNMAP_AFTER_INIT void SB16::initialize()
@@ -115,27 +108,6 @@ UNMAP_AFTER_INIT void SB16::initialize()
set_sample_rate(m_sample_rate);
}
-ErrorOr<void> SB16::ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg)
-{
- switch (request) {
- case SOUNDCARD_IOCTL_GET_SAMPLE_RATE: {
- auto output = static_ptr_cast<u16*>(arg);
- return copy_to_user(output, &m_sample_rate);
- }
- case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: {
- auto sample_rate_input = static_cast<u32>(arg.ptr());
- if (sample_rate_input == 0 || sample_rate_input > 44100)
- return ENOTSUP;
- auto sample_rate_value = static_cast<u16>(sample_rate_input);
- if (m_sample_rate != sample_rate_value)
- set_sample_rate(sample_rate_value);
- return {};
- }
- default:
- return EINVAL;
- }
-}
-
void SB16::set_irq_register(u8 irq_number)
{
u8 bitmask;
@@ -184,16 +156,6 @@ void SB16::set_irq_line(u8 irq_number)
change_irq_number(irq_number);
}
-bool SB16::can_read(OpenFileDescription const&, u64) const
-{
- return false;
-}
-
-ErrorOr<size_t> SB16::read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t)
-{
- return 0;
-}
-
void SB16::dma_start(uint32_t length)
{
auto const addr = m_dma_region->physical_page(0)->paddr().get();
@@ -249,8 +211,41 @@ void SB16::wait_for_irq()
disable_irq();
}
-ErrorOr<size_t> SB16::write(OpenFileDescription&, u64, UserOrKernelBuffer const& data, size_t length)
+RefPtr<AudioChannel> SB16::audio_channel(u32 index) const
{
+ if (index == 0)
+ return m_audio_channel;
+ return {};
+}
+void SB16::detect_hardware_audio_channels(Badge<AudioManagement>)
+{
+ m_audio_channel = AudioChannel::must_create(*this, 0);
+}
+
+ErrorOr<void> SB16::set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate)
+{
+ if (channel_index != 0)
+ return Error::from_errno(ENODEV);
+ if (samples_per_second_rate == 0 || samples_per_second_rate > 44100)
+ return Error::from_errno(ENOTSUP);
+ auto sample_rate_value = static_cast<u16>(samples_per_second_rate);
+ if (m_sample_rate != sample_rate_value)
+ set_sample_rate(sample_rate_value);
+ return {};
+}
+
+ErrorOr<u32> SB16::get_pcm_output_sample_rate(size_t channel_index)
+{
+ if (channel_index != 0)
+ return Error::from_errno(ENODEV);
+ return m_sample_rate;
+}
+
+ErrorOr<size_t> SB16::write(size_t channel_index, UserOrKernelBuffer const& data, size_t length)
+{
+ if (channel_index != 0)
+ return Error::from_errno(ENODEV);
+
if (!m_dma_region) {
m_dma_region = TRY(MM.allocate_dma_buffer_page("SB16 DMA buffer", Memory::Region::Access::Write));
}
diff --git a/Kernel/Devices/Audio/SB16.h b/Kernel/Devices/Audio/SB16.h
index a5b77dc76b..8d6e85d467 100644
--- a/Kernel/Devices/Audio/SB16.h
+++ b/Kernel/Devices/Audio/SB16.h
@@ -6,6 +6,7 @@
#pragma once
+#include <Kernel/Devices/Audio/Controller.h>
#include <Kernel/Devices/CharacterDevice.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Memory/PhysicalPage.h>
@@ -16,34 +17,30 @@ namespace Kernel {
class SB16;
-class SB16 final : public IRQHandler
- , public CharacterDevice {
- friend class DeviceManagement;
+class SB16 final
+ : public AudioController
+ , public IRQHandler {
public:
virtual ~SB16() override;
- static RefPtr<SB16> try_detect_and_create();
+ static ErrorOr<NonnullRefPtr<SB16>> try_detect_and_create();
- // ^CharacterDevice
- virtual bool can_read(const OpenFileDescription&, u64) const override;
- virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override;
- virtual ErrorOr<size_t> write(OpenFileDescription&, u64, const UserOrKernelBuffer&, size_t) override;
- virtual bool can_write(const OpenFileDescription&, u64) const override { return true; }
-
- virtual StringView purpose() const override { return class_name(); }
-
- virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned, Userspace<void*>) override;
+ virtual StringView purpose() const override { return "SB16"sv; }
private:
+ // ^AudioController
+ virtual RefPtr<AudioChannel> audio_channel(u32 index) const override;
+ virtual ErrorOr<size_t> write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) override;
+ virtual void detect_hardware_audio_channels(Badge<AudioManagement>) override;
+ virtual ErrorOr<void> set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate) override;
+ virtual ErrorOr<u32> get_pcm_output_sample_rate(size_t channel_index) override;
+
SB16();
// ^IRQHandler
virtual bool handle_irq(const RegisterState&) override;
- // ^CharacterDevice
- virtual StringView class_name() const override { return "SB16"sv; }
-
void initialize();
void wait_for_irq();
void dma_start(uint32_t length);
@@ -59,5 +56,6 @@ private:
u16 m_sample_rate { 44100 };
WaitQueue m_irq_queue;
+ RefPtr<AudioChannel> m_audio_channel;
};
}
diff --git a/Kernel/Devices/DeviceManagement.cpp b/Kernel/Devices/DeviceManagement.cpp
index cf107a0f68..af82467454 100644
--- a/Kernel/Devices/DeviceManagement.cpp
+++ b/Kernel/Devices/DeviceManagement.cpp
@@ -22,11 +22,6 @@ UNMAP_AFTER_INIT void DeviceManagement::initialize()
s_the.ensure_instance();
}
-UNMAP_AFTER_INIT void DeviceManagement::attach_audio_device(CharacterDevice const& device)
-{
- m_audio_devices.append(device);
-}
-
UNMAP_AFTER_INIT void DeviceManagement::attach_console_device(ConsoleDevice const& device)
{
m_console_device = device;
diff --git a/Kernel/Devices/DeviceManagement.h b/Kernel/Devices/DeviceManagement.h
index 0e849d72bd..e23f86ce92 100644
--- a/Kernel/Devices/DeviceManagement.h
+++ b/Kernel/Devices/DeviceManagement.h
@@ -38,9 +38,6 @@ public:
bool is_console_device_attached() const { return !m_console_device.is_null(); }
void attach_console_device(ConsoleDevice const&);
- // FIXME: Once we have a singleton for managing many sound cards, remove this from here
- void attach_audio_device(CharacterDevice const&);
-
Optional<DeviceEvent> dequeue_top_device_event(Badge<DeviceControlDevice>);
void after_inserting_device(Badge<Device>, Device&);
@@ -76,7 +73,6 @@ private:
RefPtr<ConsoleDevice> m_console_device;
RefPtr<DeviceControlDevice> m_device_control_device;
// FIXME: Once we have a singleton for managing many sound cards, remove this from here
- NonnullRefPtrVector<CharacterDevice, 1> m_audio_devices;
SpinlockProtected<HashMap<u64, Device*>> m_devices;
mutable Spinlock m_event_queue_lock;