Files
serenity/Kernel/Devices/Audio/Management.cpp
Liav A. 16244c490a Kernel: Allocate all device major numbers within one known header file
We used to allocate major numbers quite randomly, with no common place
to look them up if needed.
This commit is changing that by placing all major number allocations
under a new C++ namespace, in the API/MajorNumberAllocation.h file.

We also add the foundations of what is needed before we can publish this
information (allocated numbers for block and char devices) to userspace.
2024-07-06 21:42:32 +02:00

94 lines
3.1 KiB
C++

/*
* 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/Access.h>
#include <Kernel/Devices/Audio/AC97/AC97.h>
#include <Kernel/Devices/Audio/IntelHDA/Controller.h>
#include <Kernel/Devices/Audio/Management.h>
namespace Kernel {
static Singleton<AudioManagement> s_the;
static Atomic<u32> s_device_minor_number;
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()
{
}
struct PCIAudioDriverInitializer {
ErrorOr<bool> (*probe)(PCI::DeviceIdentifier const&) = nullptr;
ErrorOr<NonnullRefPtr<AudioController>> (*create)(PCI::DeviceIdentifier const&) = nullptr;
};
static constexpr PCIAudioDriverInitializer s_initializers[] = {
{ AC97::probe, AC97::create },
{ Audio::IntelHDA::Controller::probe, Audio::IntelHDA::Controller::create },
};
UNMAP_AFTER_INIT ErrorOr<NonnullRefPtr<AudioController>> AudioManagement::determine_audio_device(PCI::DeviceIdentifier const& device_identifier) const
{
for (auto& initializer : s_initializers) {
auto initializer_probe_found_driver_match_or_error = initializer.probe(device_identifier);
if (initializer_probe_found_driver_match_or_error.is_error()) {
dmesgln("AudioManagement: Failed to probe device {}, due to {}", device_identifier.address(), initializer_probe_found_driver_match_or_error.error());
continue;
}
auto initializer_probe_found_driver_match = initializer_probe_found_driver_match_or_error.release_value();
if (initializer_probe_found_driver_match) {
auto device = TRY(initializer.create(device_identifier));
TRY(device->initialize({}));
return device;
}
}
dmesgln("AudioManagement: Failed to initialize device {}, unsupported audio device", device_identifier.address());
return Error::from_errno(ENODEV);
}
UNMAP_AFTER_INIT void AudioManagement::enumerate_hardware_controllers()
{
if (PCI::Access::is_disabled())
return;
MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) {
// Only consider PCI multimedia devices
if (device_identifier.class_code() != PCI::ClassID::Multimedia)
return;
auto result = determine_audio_device(device_identifier);
if (result.is_error()) {
dmesgln("Failed to initialize audio device ({} {}): {}", device_identifier.address(), device_identifier.hardware_id(), result.error());
return;
}
m_controllers_list.with([&](auto& list) { list.append(result.release_value()); });
}));
}
UNMAP_AFTER_INIT bool AudioManagement::initialize()
{
enumerate_hardware_controllers();
auto list_empty = m_controllers_list.with([&](auto& list) -> bool {
return list.is_empty();
});
if (list_empty)
dbgln("AudioManagement: no audio controller was initialized.");
return !list_empty;
}
}