From 7d78433e6ea80b651f80201b6c5beef799887e7f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 23 Jul 2026 22:34:49 +0200 Subject: x86_64: port legacy PIT driver to new architecture --- arch/x86_64/arch/bus/isa.cpp | 29 +++++++++++ arch/x86_64/arch/bus/isa.hpp | 35 +++++++++++++- arch/x86_64/arch/devices/init.cpp | 10 ++-- arch/x86_64/arch/devices/legacy_pit.cpp | 85 ++++++++++++++++++++++++++++----- arch/x86_64/arch/devices/legacy_pit.hpp | 48 +++++++++++++++++-- 5 files changed, 184 insertions(+), 23 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/arch/bus/isa.cpp b/arch/x86_64/arch/bus/isa.cpp index dd248f76..573feb72 100644 --- a/arch/x86_64/arch/bus/isa.cpp +++ b/arch/x86_64/arch/bus/isa.cpp @@ -2,6 +2,11 @@ #include +#include + +#include +#include + namespace arch::bus { @@ -9,4 +14,28 @@ namespace arch::bus : kapi::devices::bus{"isa"} {} + auto isa::enumerate(kapi::devices::bus &) -> void + { + // NOTE: ISA does not support enumeration, but we need to fulfill the interface. + } + + auto isa::match(kapi::devices::device const & device, kapi::devices::driver const & driver) const + -> kstd::result + { + auto identification = device.as(); + auto claims = driver.as(); + + if (!identification || !claims || !std::ranges::contains(claims->supported_names(), identification->isa_name())) + { + return kstd::failure(kapi::devices::driver_match_errc::no_match); + } + + return 0u; + } + + auto isa::protocol() -> kapi::devices::bus_protocol * + { + return this; + } + } // namespace arch::bus \ No newline at end of file diff --git a/arch/x86_64/arch/bus/isa.hpp b/arch/x86_64/arch/bus/isa.hpp index 5741a640..a09127dd 100644 --- a/arch/x86_64/arch/bus/isa.hpp +++ b/arch/x86_64/arch/bus/isa.hpp @@ -1,14 +1,45 @@ #ifndef TEACHOS_X86_64_BUS_ISA_HPP #define TEACHOS_X86_64_BUS_ISA_HPP -#include +#include + +#include + +#include +#include +#include namespace arch::bus { - struct isa final : public kapi::devices::bus + struct isa_identification + { + constexpr auto static id = kapi::devices::interface{"isa_identification"}; + + virtual ~isa_identification() = default; + + [[nodiscard]] virtual auto isa_name() const -> std::string_view = 0; + }; + + struct isa_driver_identification + { + constexpr auto static id = kapi::devices::interface{"isa_driver_identification"}; + + virtual ~isa_driver_identification() = default; + + [[nodiscard]] virtual auto supported_names() const -> std::span = 0; + }; + + struct isa final : public kapi::devices::bus, kapi::devices::bus_protocol { isa(); + + auto enumerate(kapi::devices::bus & self) -> void override; + + [[nodiscard]] auto match(kapi::devices::device const & device, kapi::devices::driver const & driver) const + -> kstd::result override; + + [[nodiscard]] auto protocol() -> kapi::devices::bus_protocol * override; }; } // namespace arch::bus diff --git a/arch/x86_64/arch/devices/init.cpp b/arch/x86_64/arch/devices/init.cpp index 2c4fb3c3..f6adcbcf 100644 --- a/arch/x86_64/arch/devices/init.cpp +++ b/arch/x86_64/arch/devices/init.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -14,7 +15,6 @@ #include #include -#include namespace arch::devices { @@ -63,12 +63,12 @@ namespace arch::devices kstd::println("[x86_64:DEV] Initializing ISA bus..."); auto isa_bus = kstd::make_shared(); + auto root_bus = kapi::devices::get_root_bus(); - auto pit = kstd::make_shared(pit_frequency_in_hz); - isa_bus->add_child(std::move(pit)); + root_bus->add_child(isa_bus); - auto root_bus = kapi::devices::get_root_bus(); - root_bus->add_child(std::move(isa_bus)); + kapi::devices::driver_registry::get().add(kstd::make_shared(pit_frequency_in_hz)); + isa_bus->add_child(kstd::make_shared()); } } // namespace arch::devices diff --git a/arch/x86_64/arch/devices/legacy_pit.cpp b/arch/x86_64/arch/devices/legacy_pit.cpp index d93b38fd..5e968a6b 100644 --- a/arch/x86_64/arch/devices/legacy_pit.cpp +++ b/arch/x86_64/arch/devices/legacy_pit.cpp @@ -1,16 +1,25 @@ #include +#include #include #include #include #include +#include +#include + +#include #include +#include +#include namespace arch::devices { + using namespace std::string_view_literals; + namespace { using command_port = io::port<0x43, std::uint8_t, io::port_write>; @@ -20,19 +29,46 @@ namespace arch::devices constexpr auto base_frequency = 1'193'182u; constexpr auto square_wave_mode = 0x36; + + constexpr auto pit_names = std::array{"pit"sv}; } // namespace - legacy_pit::legacy_pit(std::uint32_t frequency_in_hz) - : kapi::devices::device{"legacy_pit"} - , m_irq_number{0} - , m_frequency_in_hz{frequency_in_hz} + pit_device::pit_device() + : device{"legacy_pit"} + {} + + auto pit_device::isa_name() const -> std::string_view + { + return "pit"; + } + + auto pit_device::init() -> bool + { + return true; + } + + auto pit_device::query_interface(kapi::devices::interface interface) -> void * + { + if (interface == arch::bus::isa_identification::id) + { + return static_cast(this); + } + + return kapi::devices::device::query_interface(interface); + } + + pit_driver::pit_driver(std::uint32_t frequency_in_hz) + : m_frequency_in_hz{frequency_in_hz} {} - auto legacy_pit::init() -> bool + auto pit_driver::probe(kapi::devices::device & device) -> kstd::result { - auto divisor = static_cast(base_frequency / m_frequency_in_hz); + auto data = kstd::make_shared(0, m_frequency_in_hz, 0); + device.set_driver_data(data); - kapi::interrupts::register_handler(m_irq_number, *this); + auto divisor = static_cast(base_frequency / data->frequency_in_hz); + + kapi::interrupts::register_handler(data->irq_number, *this); command_port::write(square_wave_mode); io::wait(); @@ -41,19 +77,46 @@ namespace arch::devices channel_0_port::write(divisor >> 8 & 0xff); io::wait(); - return true; + return kstd::success(); } - auto legacy_pit::handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status + auto pit_driver::unbind(kapi::devices::device & device) -> void { - if (irq_number != m_irq_number) + auto data = static_pointer_cast(device.driver_data()); + + kapi::interrupts::unregister_handler(data->irq_number, *this); + + device.set_driver_data(nullptr); + } + + auto pit_driver::supported_names() const -> std::span + { + return pit_names; + } + + auto pit_driver::handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status + { + // auto data = static_pointer_cast(device.driver_data()); + + if (irq_number != 0) { return kapi::interrupts::status::unhandled; } - ++m_ticks; + // TODO: upgrade kapi interrupts to gain access to the device. + // ++m_ticks; return kapi::interrupts::status::handled; } + auto pit_driver::query_interface(kapi::devices::interface interface) -> void * + { + if (interface == arch::bus::isa_driver_identification::id) + { + return static_cast(this); + } + + return kapi::devices::driver::query_interface(interface); + } + } // namespace arch::devices \ No newline at end of file diff --git a/arch/x86_64/arch/devices/legacy_pit.hpp b/arch/x86_64/arch/devices/legacy_pit.hpp index 7a74144e..1bb41e2b 100644 --- a/arch/x86_64/arch/devices/legacy_pit.hpp +++ b/arch/x86_64/arch/devices/legacy_pit.hpp @@ -1,26 +1,64 @@ #ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP #define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP -#include +#include + +#include #include +#include + #include +#include +#include namespace arch::devices { - struct legacy_pit : kapi::devices::device, kapi::interrupts::handler + //! The ISA device for the legacy Programmable Interrupt Timer. + //! + //! This type identifies the PIT device node to the driver, so the driver can be matched successfully. + struct pit_device final : kapi::devices::device, arch::bus::isa_identification { - explicit legacy_pit(std::uint32_t frequency_in_hz); + pit_device(); + // TODO: remove auto init() -> bool override; + //! Get the synthetic ISA identifier for this device. + //! + //! @return the string "pit" + [[nodiscard]] auto isa_name() const -> std::string_view override; + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override; + }; + + //! The driver for the legacy, ISA-connected Programmable Interrupt Timer. + struct pit_driver final : kapi::devices::driver, arch::bus::isa_driver_identification, kapi::interrupts::handler + { + explicit pit_driver(std::uint32_t frequency_in_hz); + + [[nodiscard]] auto probe(kapi::devices::device & device) -> kstd::result override; + + auto unbind(kapi::devices::device & device) -> void override; + + [[nodiscard]] auto supported_names() const -> std::span override; + auto handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status override; + protected: + auto query_interface(kapi::devices::interface interface) -> void * override; + private: - std::uint32_t m_irq_number{}; + struct driver_data + { + std::uint32_t irq_number{}; + std::uint32_t frequency_in_hz{}; + std::uint64_t ticks{}; + }; + std::uint32_t m_frequency_in_hz{}; - std::uint64_t m_ticks{}; }; } // namespace arch::devices -- cgit v1.2.3