From 2ea28cb54d40f3117acb75ed23c77e69f75da698 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 24 Jul 2026 14:28:53 +0200 Subject: kapi: add driver stacking test --- kernel/kapi/devices/driver.tests.cpp | 230 +++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 kernel/kapi/devices/driver.tests.cpp (limited to 'kernel/kapi') 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 + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +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 = 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 override + { + auto const * ident = dev.as(); + auto const * claims = drv.as(); + 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(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 = 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(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()); + } + + [[nodiscard]] auto match(kapi::devices::device const & dev, kapi::devices::driver const & drv) const + -> kstd::result override + { + auto const * ident = dev.as(); + auto const * claims = drv.as(); + 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 override + { + auto self_as_bus = kstd::static_pointer_cast(dev.shared_from_this()); + auto leaf = kstd::make_shared("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 override + { + constexpr auto static names = std::array{"stacking_test_controller"}; + return names; + } + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override + { + if (interface == controller_driver_identification::id) + { + return static_cast(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 override + { + return kstd::success(); + } + + auto unbind(kapi::devices::device &) -> void override {} + + [[nodiscard]] auto supported_names() const -> std::span override + { + constexpr auto static names = std::array{"stacking_test_leaf"}; + return names; + } + + protected: + auto query_interface(kapi::devices::interface interface) -> void * override + { + if (interface == leaf_driver_identification::id) + { + return static_cast(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("stacking_test_controller_bus"); + + kapi::devices::driver_registry::get().add(kstd::make_shared()); + kapi::devices::driver_registry::get().add(kstd::make_shared()); + + WHEN("the controller device is attached to the controller bus") + { + outer_bus->add_child(kstd::make_shared()); + + 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); + } + } + } +} -- cgit v1.2.3