diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index ffe4fb1c19..4cf3f0344c 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -47,6 +47,7 @@ set(KERNEL_SOURCES Devices/Audio/IntelHDA/Codec.cpp Devices/Audio/IntelHDA/Controller.cpp Devices/Audio/IntelHDA/Format.cpp + Devices/Audio/IntelHDA/InterruptHandler.cpp Devices/Audio/IntelHDA/Stream.cpp Devices/Audio/Management.cpp Devices/BlockDevice.cpp diff --git a/Kernel/Devices/Audio/IntelHDA/Controller.cpp b/Kernel/Devices/Audio/IntelHDA/Controller.cpp index 817146cb8f..2c82f20a95 100644 --- a/Kernel/Devices/Audio/IntelHDA/Controller.cpp +++ b/Kernel/Devices/Audio/IntelHDA/Controller.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,6 @@ UNMAP_AFTER_INIT ErrorOr> Controller::create(PCI: UNMAP_AFTER_INIT Controller::Controller(PCI::DeviceIdentifier const& pci_device_identifier, NonnullOwnPtr controller_io_window) : PCI::Device(const_cast(pci_device_identifier)) - , PCIIRQHandler(*this, device_identifier().interrupt_line().value()) , m_controller_io_window(move(controller_io_window)) { } @@ -39,7 +39,7 @@ UNMAP_AFTER_INIT ErrorOr Controller::initialize(Badge) { // Enable DMA and interrupts PCI::enable_bus_mastering(device_identifier()); - enable_irq(); + m_interrupt_handler = TRY(InterruptHandler::create(*this)); // 3.3.3, 3.3.4: Controller version auto version_minor = m_controller_io_window->read8(ControllerRegister::VersionMinor); @@ -299,7 +299,7 @@ ErrorOr Controller::reset() return {}; } -bool Controller::handle_irq(Kernel::RegisterState const&) +ErrorOr Controller::handle_interrupt(Badge) { // Check if any interrupt status bit is set auto interrupt_status = m_controller_io_window->read32(ControllerRegister::InterruptStatus); @@ -308,11 +308,8 @@ bool Controller::handle_irq(Kernel::RegisterState const&) // FIXME: Actually look at interrupt_status and iterate over streams as soon as // we support multiple streams. - if (m_output_path) { - auto maybe_error = m_output_path->output_stream().handle_interrupt({}); - if (maybe_error.is_error()) - dbgln("IntelHDA: Error during interrupt handling: {}", maybe_error.error()); - } + if (m_output_path) + TRY(m_output_path->output_stream().handle_interrupt({})); return true; } diff --git a/Kernel/Devices/Audio/IntelHDA/Controller.h b/Kernel/Devices/Audio/IntelHDA/Controller.h index e3967c4f73..0cefa8b22b 100644 --- a/Kernel/Devices/Audio/IntelHDA/Controller.h +++ b/Kernel/Devices/Audio/IntelHDA/Controller.h @@ -14,9 +14,9 @@ #include #include #include +#include #include #include -#include #include namespace Kernel::Audio::IntelHDA { @@ -27,8 +27,7 @@ class Codec; class Controller final : public AudioController - , public PCI::Device - , public PCIIRQHandler { + , public PCI::Device { public: static ErrorOr probe(PCI::DeviceIdentifier const&); static ErrorOr> create(PCI::DeviceIdentifier const&); @@ -37,9 +36,7 @@ public: // ^PCI::Device virtual StringView device_name() const override { return "IntelHDA"sv; } - // ^PCIIRQHandler - virtual StringView purpose() const override { return "IntelHDA IRQ Handler"sv; } - + ErrorOr handle_interrupt(Badge); ErrorOr send_command(u8 codec_address, u8 node_id, CodecControlVerb verb, u16 payload); private: @@ -81,9 +78,6 @@ private: ErrorOr configure_output_route(); ErrorOr reset(); - // ^PCIIRQHandler - virtual bool handle_irq(RegisterState const&) override; - // ^AudioController virtual RefPtr audio_channel(u32 index) const override; virtual ErrorOr write(size_t channel_index, UserOrKernelBuffer const& data, size_t length) override; @@ -97,6 +91,7 @@ private: u8 m_number_of_bidirectional_streams; OwnPtr m_command_buffer; OwnPtr m_response_buffer; + RefPtr m_interrupt_handler; Vector> m_codecs {}; OwnPtr m_output_path; RefPtr m_audio_channel; diff --git a/Kernel/Devices/Audio/IntelHDA/InterruptHandler.cpp b/Kernel/Devices/Audio/IntelHDA/InterruptHandler.cpp new file mode 100644 index 0000000000..62777bcf28 --- /dev/null +++ b/Kernel/Devices/Audio/IntelHDA/InterruptHandler.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023, Jelle Raaijmakers + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Kernel::Audio::IntelHDA { + +InterruptHandler::InterruptHandler(Controller& controller) + : PCIIRQHandler(controller, controller.device_identifier().interrupt_line().value()) + , m_controller(controller) +{ + enable_irq(); +} + +bool InterruptHandler::handle_irq(RegisterState const&) +{ + auto result_or_error = m_controller.handle_interrupt({}); + if (result_or_error.is_error()) { + dmesgln("IntelHDA: Error during interrupt handling: {}", result_or_error.release_error()); + return false; + } + return result_or_error.release_value(); +} + +} diff --git a/Kernel/Devices/Audio/IntelHDA/InterruptHandler.h b/Kernel/Devices/Audio/IntelHDA/InterruptHandler.h new file mode 100644 index 0000000000..84d961c75d --- /dev/null +++ b/Kernel/Devices/Audio/IntelHDA/InterruptHandler.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, Jelle Raaijmakers + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Kernel::Audio::IntelHDA { + +class Controller; + +class InterruptHandler + : public PCIIRQHandler + , public RefCounted { +public: + static ErrorOr> create(Controller& controller) + { + return adopt_nonnull_ref_or_enomem(new (nothrow) InterruptHandler(controller)); + } + + // ^PCIIRQHandler + virtual StringView purpose() const override { return "IntelHDA IRQ Handler"sv; } + +private: + InterruptHandler(Controller& controller); + + // ^PCIIRQHandler + virtual bool handle_irq(RegisterState const&) override; + + Controller& m_controller; +}; + +}