diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index cdf1dca3254..d32357bd25d 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -46,6 +46,8 @@ set(KERNEL_SOURCES Coredump.cpp Devices/AsyncDeviceRequest.cpp Devices/Audio/AC97.cpp + Devices/Audio/Channel.cpp + Devices/Audio/Management.cpp Devices/Audio/SB16.cpp Devices/BlockDevice.cpp Devices/CharacterDevice.cpp diff --git a/Kernel/Devices/Audio/AC97.cpp b/Kernel/Devices/Audio/AC97.cpp index b19ab3b00bd..d603313f9b4 100644 --- a/Kernel/Devices/Audio/AC97.cpp +++ b/Kernel/Devices/Audio/AC97.cpp @@ -7,7 +7,6 @@ #include #include #include -#include 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> 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(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 AC97::ioctl(OpenFileDescription&, unsigned request, Userspace arg) -{ - switch (request) { - case SOUNDCARD_IOCTL_GET_SAMPLE_RATE: { - auto output = static_ptr_cast(arg); - return copy_to_user(output, &m_sample_rate); - } - case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: { - auto sample_rate = static_cast(arg.ptr()); - TRY(set_pcm_output_sample_rate(sample_rate)); - return {}; - } - default: - return EINVAL; - } -} - -ErrorOr 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 AC97::write(OpenFileDescription&, u64, UserOrKernelBuffer const& data, size_t length) +RefPtr AC97::audio_channel(u32 index) const { + if (index == 0) + return m_audio_channel; + return {}; +} +void AC97::detect_hardware_audio_channels(Badge) +{ + m_audio_channel = AudioChannel::must_create(*this, 0); +} + +ErrorOr 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 AC97::get_pcm_output_sample_rate(size_t channel_index) +{ + if (channel_index != 0) + return Error::from_errno(ENODEV); + return m_sample_rate; +} + +ErrorOr 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 56c31acd9e0..a20fb9d2ec4 100644 --- a/Kernel/Devices/Audio/AC97.h +++ b/Kernel/Devices/Audio/AC97.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -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> 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 ioctl(OpenFileDescription&, unsigned, Userspace) override; - virtual ErrorOr read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override; - virtual ErrorOr 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 write_single_buffer(UserOrKernelBuffer const&, size_t, size_t); + // ^AudioController + virtual RefPtr audio_channel(u32 index) const override; + virtual ErrorOr write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) override; + virtual void detect_hardware_audio_channels(Badge) override; + virtual ErrorOr set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate) override; + virtual ErrorOr get_pcm_output_sample_rate(size_t channel_index) override; + OwnPtr 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 m_audio_channel; }; } diff --git a/Kernel/Devices/Audio/Channel.cpp b/Kernel/Devices/Audio/Channel.cpp new file mode 100644 index 00000000000..ac390d7aed5 --- /dev/null +++ b/Kernel/Devices/Audio/Channel.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +UNMAP_AFTER_INIT NonnullRefPtr AudioChannel::must_create(AudioController const& controller, size_t channel_index) +{ + auto audio_device_or_error = DeviceManagement::try_create_device(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 AudioChannel::ioctl(OpenFileDescription&, unsigned request, Userspace 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(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(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 AudioChannel::read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) +{ + // FIXME: Implement input from device + return Error::from_errno(ENOTIMPL); +} + +ErrorOr 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 00000000000..08da0593527 --- /dev/null +++ b/Kernel/Devices/Audio/Channel.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Kernel { + +class AudioController; +class AudioChannel final + : public CharacterDevice { + friend class DeviceManagement; + +public: + static NonnullRefPtr must_create(AudioController const&, size_t channel_index); + virtual ~AudioChannel() override { } + + // ^CharacterDevice + virtual bool can_read(const OpenFileDescription&, u64) const override; + virtual ErrorOr read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override; + virtual ErrorOr write(OpenFileDescription&, u64, const UserOrKernelBuffer&, size_t) override; + virtual bool can_write(const OpenFileDescription&, u64) const override { return true; } + + virtual ErrorOr ioctl(OpenFileDescription&, unsigned, Userspace) override; + +private: + AudioChannel(AudioController const&, size_t channel_index); + + // ^CharacterDevice + virtual StringView class_name() const override { return "AudioChannel"sv; } + + WeakPtr 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 00000000000..0b63c50eb66 --- /dev/null +++ b/Kernel/Devices/Audio/Controller.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class AudioManagement; +class AudioController + : public RefCounted + , public Weakable { + friend class AudioManagement; + +public: + virtual ~AudioController() = default; + + virtual RefPtr audio_channel(u32 index) const = 0; + virtual ErrorOr write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) = 0; + + virtual void detect_hardware_audio_channels(Badge) = 0; + + virtual ErrorOr 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 get_pcm_output_sample_rate(size_t channel_index) = 0; + +private: + IntrusiveListNode> m_node; +}; +} diff --git a/Kernel/Devices/Audio/Management.cpp b/Kernel/Devices/Audio/Management.cpp new file mode 100644 index 00000000000..095b3c796bb --- /dev/null +++ b/Kernel/Devices/Audio/Management.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2021, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +static Singleton s_the; +static Atomic 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 00000000000..9294fa881c8 --- /dev/null +++ b/Kernel/Devices/Audio/Management.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +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 b654060ba16..2d231185387 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::try_detect_and_create() +UNMAP_AFTER_INIT ErrorOr> SB16::try_detect_and_create() { IO::out8(0x226, 1); IO::delay(32); @@ -80,13 +78,8 @@ UNMAP_AFTER_INIT RefPtr SB16::try_detect_and_create() auto data = dsp_read(); if (data != 0xaa) - return {}; - auto device_or_error = DeviceManagement::try_create_device(); - 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 SB16::ioctl(OpenFileDescription&, unsigned request, Userspace arg) -{ - switch (request) { - case SOUNDCARD_IOCTL_GET_SAMPLE_RATE: { - auto output = static_ptr_cast(arg); - return copy_to_user(output, &m_sample_rate); - } - case SOUNDCARD_IOCTL_SET_SAMPLE_RATE: { - auto sample_rate_input = static_cast(arg.ptr()); - if (sample_rate_input == 0 || sample_rate_input > 44100) - return ENOTSUP; - auto sample_rate_value = static_cast(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 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 SB16::write(OpenFileDescription&, u64, UserOrKernelBuffer const& data, size_t length) +RefPtr SB16::audio_channel(u32 index) const { + if (index == 0) + return m_audio_channel; + return {}; +} +void SB16::detect_hardware_audio_channels(Badge) +{ + m_audio_channel = AudioChannel::must_create(*this, 0); +} + +ErrorOr 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(samples_per_second_rate); + if (m_sample_rate != sample_rate_value) + set_sample_rate(sample_rate_value); + return {}; +} + +ErrorOr SB16::get_pcm_output_sample_rate(size_t channel_index) +{ + if (channel_index != 0) + return Error::from_errno(ENODEV); + return m_sample_rate; +} + +ErrorOr 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 a5b77dc76ba..8d6e85d467f 100644 --- a/Kernel/Devices/Audio/SB16.h +++ b/Kernel/Devices/Audio/SB16.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -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 try_detect_and_create(); + static ErrorOr> try_detect_and_create(); - // ^CharacterDevice - virtual bool can_read(const OpenFileDescription&, u64) const override; - virtual ErrorOr read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override; - virtual ErrorOr 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 ioctl(OpenFileDescription&, unsigned, Userspace) override; + virtual StringView purpose() const override { return "SB16"sv; } private: + // ^AudioController + virtual RefPtr audio_channel(u32 index) const override; + virtual ErrorOr write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) override; + virtual void detect_hardware_audio_channels(Badge) override; + virtual ErrorOr set_pcm_output_sample_rate(size_t channel_index, u32 samples_per_second_rate) override; + virtual ErrorOr 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 m_audio_channel; }; } diff --git a/Kernel/Devices/DeviceManagement.cpp b/Kernel/Devices/DeviceManagement.cpp index cf107a0f68d..af824674545 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 0e849d72bd1..e23f86ce923 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 dequeue_top_device_event(Badge); void after_inserting_device(Badge, Device&); @@ -76,7 +73,6 @@ private: RefPtr m_console_device; RefPtr m_device_control_device; // FIXME: Once we have a singleton for managing many sound cards, remove this from here - NonnullRefPtrVector m_audio_devices; SpinlockProtected> m_devices; mutable Spinlock m_event_queue_lock; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index bdac48bfd31..9a7da70dfa3 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -13,8 +13,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -339,8 +338,7 @@ void init_stage2(void*) (void)RandomDevice::must_create().leak_ref(); PTYMultiplexer::initialize(); - (void)SB16::try_detect_and_create(); - AC97::detect(); + AudioManagement::the().initialize(); StorageManagement::the().initialize(kernel_command_line().root_device(), kernel_command_line().is_force_pio(), kernel_command_line().is_nvme_polling_enabled()); if (VirtualFileSystem::the().mount_root(StorageManagement::the().root_filesystem()).is_error()) {