diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-07-24 14:28:53 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-07-24 14:28:53 +0200 |
| commit | 2ea28cb54d40f3117acb75ed23c77e69f75da698 (patch) | |
| tree | 82e4c37170676d6bc58791c7ebbb2cf79e6f3d65 /kernel | |
| parent | ee0d1a8f0c98b2b61bc4078c523ef23542bb4b83 (diff) | |
| download | kernel-2ea28cb54d40f3117acb75ed23c77e69f75da698.tar.xz kernel-2ea28cb54d40f3117acb75ed23c77e69f75da698.zip | |
kapi: add driver stacking test
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kapi/devices/driver.tests.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/kernel/kapi/devices/driver.tests.cpp b/kernel/kapi/devices/driver.tests.cpp new file mode 100644 index 00000000..abce92d2 --- /dev/null +++ b/kernel/kapi/devices/driver.tests.cpp @@ -0,0 +1,230 @@ +#include <kapi/devices.hpp> + +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/string.hpp> + +#include <catch2/catch_test_macros.hpp> + +#include <algorithm> +#include <array> +#include <cstdint> +#include <span> +#include <string_view> + +namespace +{ + struct controller_identification + { + constexpr auto static id = kapi::devices::interface{"stacking_test_controller_identification"}; + virtual ~controller_identification() = default; + [[nodiscard]] virtual auto controller_name() const -> std::string_view = 0; + }; + + struct controller_driver_identification + { + constexpr auto static id = kapi::devices::interface{"stacking_test_controller_driver_identification"}; + virtual ~controller_driver_identification() = default; + [[nodiscard]] virtual auto supported_names() const -> std::span<std::string_view const> = 0; + }; + + struct controller_bus final : kapi::devices::bus, kapi::devices::bus_protocol + { + using kapi::devices::bus::bus; + + auto enumerate(kapi::devices::bus &) -> void override {} + + [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const + -> kstd::result<std::uint32_t> override + { + auto const * ident = dev.as<controller_identification>(); + auto const * claims = drv.as<controller_driver_identification>(); + if (!ident || !claims || !std::ranges::contains(claims->supported_names(), ident->controller_name())) + { + return kstd::failure(kapi::devices::driver_match_errc::no_match); + } + return 0u; + } + + [[nodiscard]] auto protocol() -> kapi::devices::bus_protocol * override + { + return this; + } + }; + + struct controller_device final : kapi::devices::bus, controller_identification + { + controller_device() + : kapi::devices::bus{"stacking_test_controller"} + {} + + [[nodiscard]] auto controller_name() const -> std::string_view override + { + return "stacking_test_controller"; + } + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override + { + if (interface == controller_identification::id) + { + return static_cast<controller_identification *>(this); + } + return kapi::devices::bus::query_interface(interface); + } + }; + + struct leaf_identification + { + constexpr kapi::devices::interface static id{"stacking_test_leaf_identification"}; + virtual ~leaf_identification() = default; + [[nodiscard]] virtual auto leaf_name() const -> std::string_view = 0; + }; + + struct leaf_driver_identification + { + constexpr kapi::devices::interface static id{"stacking_test_leaf_driver_identification"}; + virtual ~leaf_driver_identification() = default; + [[nodiscard]] virtual auto supported_names() const -> std::span<std::string_view const> = 0; + }; + + struct leaf_device final : kapi::devices::device, leaf_identification + { + leaf_device() + : kapi::devices::device{"stacking_test_leaf"} + {} + + [[nodiscard]] auto leaf_name() const -> std::string_view override + { + return "stacking_test_leaf"; + } + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override + { + if (interface == leaf_identification::id) + { + return static_cast<leaf_identification *>(this); + } + return kapi::devices::device::query_interface(interface); + } + }; + + struct leaf_bus final : kapi::devices::bus, kapi::devices::bus_protocol + { + using kapi::devices::bus::bus; + + auto enumerate(kapi::devices::bus & self) -> void override + { + self.add_child(kstd::make_shared<leaf_device>()); + } + + [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const + -> kstd::result<std::uint32_t> override + { + auto const * ident = dev.as<leaf_identification>(); + auto const * claims = drv.as<leaf_driver_identification>(); + if (!ident || !claims || !std::ranges::contains(claims->supported_names(), ident->leaf_name())) + { + return kstd::failure(kapi::devices::driver_match_errc::no_match); + } + return 0u; + } + + [[nodiscard]] auto protocol() -> kapi::devices::bus_protocol * override + { + return this; + } + }; + + struct controller_driver final : kapi::devices::driver, controller_driver_identification + { + [[nodiscard]] auto probe(kapi::devices::device & dev) -> kstd::result<void> override + { + auto self_as_bus = kstd::static_pointer_cast<kapi::devices::bus>(dev.shared_from_this()); + auto leaf = kstd::make_shared<leaf_bus>("stacking_test_leaf_bus"); + self_as_bus->add_child(leaf); + leaf->enumerate(*leaf); + + return kstd::success(); + } + + auto unbind(kapi::devices::device &) -> void override {} + + [[nodiscard]] auto supported_names() const -> std::span<std::string_view const> override + { + constexpr auto static names = std::array<std::string_view, 1>{"stacking_test_controller"}; + return names; + } + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override + { + if (interface == controller_driver_identification::id) + { + return static_cast<controller_driver_identification *>(this); + } + + return kapi::devices::driver::query_interface(interface); + } + }; + + struct leaf_driver final : kapi::devices::driver, leaf_driver_identification + { + [[nodiscard]] auto probe(kapi::devices::device &) -> kstd::result<void> override + { + return kstd::success(); + } + + auto unbind(kapi::devices::device &) -> void override {} + + [[nodiscard]] auto supported_names() const -> std::span<std::string_view const> override + { + constexpr auto static names = std::array<std::string_view, 1>{"stacking_test_leaf"}; + return names; + } + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override + { + if (interface == leaf_driver_identification::id) + { + return static_cast<leaf_driver_identification *>(this); + } + + return kapi::devices::driver::query_interface(interface); + } + }; +} // namespace + +SCENARIO("a bound controller driver can attach a further, independently-typed bus protocol of its own", + "[devices][driver][stacking]") +{ + GIVEN("a controller bus, a controller driver, and a leaf driver, none aware of each other's identification scheme") + { + auto outer_bus = kstd::make_shared<controller_bus>("stacking_test_controller_bus"); + + kapi::devices::driver_registry::get().add(kstd::make_shared<controller_driver>()); + kapi::devices::driver_registry::get().add(kstd::make_shared<leaf_driver>()); + + WHEN("the controller device is attached to the controller bus") + { + outer_bus->add_child(kstd::make_shared<controller_device>()); + + THEN("the controller device bound the controller driver") + { + auto controller = kapi::devices::find_device("stacking_test_controller"); + REQUIRE(controller != nullptr); + REQUIRE(controller->state() == kapi::devices::state::bound); + } + + THEN("the leaf device the controller driver attached is reachable and bound to the leaf driver") + { + auto leaf = kapi::devices::find_device("stacking_test_leaf"); + REQUIRE(leaf != nullptr); + REQUIRE(leaf->state() == kapi::devices::state::bound); + REQUIRE(leaf->bound_driver() != nullptr); + } + } + } +} |
