#include #include #include #include #include #include #include #include #include #include namespace { struct controller_identification { constexpr auto static id = kapi::capabilities::facet_id{"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::capabilities::facet_id{"stacking_test_controller_driver_identification"}; virtual ~controller_driver_identification() = default; [[nodiscard]] virtual auto supported_names() const -> std::span = 0; }; struct controller_protocol : kapi::devices::bus_protocol { 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.facet(); auto const * claims = drv.facet(); if (!ident || !claims || !std::ranges::contains(claims->supported_names(), ident->controller_name())) { return kstd::failure(kapi::devices::driver_match_errc::no_match); } return 0u; } } constinit controller_protocol_instance{}; struct controller_bus final : kapi::devices::bus { using kapi::devices::bus::bus; [[nodiscard]] auto query_facet(kapi::capabilities::facet_id facet) -> void * override { if (facet == kapi::devices::bus_protocol::id) { return static_cast(&controller_protocol_instance); } return kapi::devices::bus::query_facet(facet); } }; 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_facet(kapi::capabilities::facet_id facet) -> void * override { if (facet == controller_identification::id) { return static_cast(this); } return kapi::devices::bus::query_facet(facet); } }; struct leaf_identification { constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_leaf_identification"}; virtual ~leaf_identification() = default; [[nodiscard]] virtual auto leaf_name() const -> std::string_view = 0; }; struct leaf_driver_identification { constexpr auto static id = kapi::capabilities::facet_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_facet(kapi::capabilities::facet_id facet) -> void * override { if (facet == leaf_identification::id) { return static_cast(this); } return kapi::devices::device::query_facet(facet); } }; struct leaf_protocol final : kapi::devices::bus_protocol { constexpr auto static id = kapi::capabilities::facet_id{"stacking_test_leaf_protocol"}; 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.facet(); auto const * claims = drv.facet(); if (!ident || !claims || !std::ranges::contains(claims->supported_names(), ident->leaf_name())) { return kstd::failure(kapi::devices::driver_match_errc::no_match); } return 0u; } } constinit leaf_protocol_instance{}; struct leaf_bus final : kapi::devices::bus { using kapi::devices::bus::bus; [[nodiscard]] auto query_facet(kapi::capabilities::facet_id id) -> void * override { if (id == kapi::devices::bus_protocol::id) { return static_cast(&leaf_protocol_instance); } return kapi::devices::bus::query_facet(id); } }; 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->facet()->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; } [[nodiscard]] auto name() const noexcept -> std::string_view override { return "Generic BHT Test Controller"; } protected: auto query_facet(kapi::capabilities::facet_id facet) -> void * override { if (facet == controller_driver_identification::id) { return static_cast(this); } return kapi::devices::driver::query_facet(facet); } }; 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; } [[nodiscard]] auto name() const noexcept -> std::string_view override { return "Generic BHT Leaf Device"; } protected: auto query_facet(kapi::capabilities::facet_id facet) -> void * override { if (facet == leaf_driver_identification::id) { return static_cast(this); } return kapi::devices::driver::query_facet(facet); } }; } // 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::device_registry::get().find("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::device_registry::get().find("stacking_test_leaf"); REQUIRE(leaf != nullptr); REQUIRE(leaf->state() == kapi::devices::state::bound); REQUIRE(leaf->bound_driver() != nullptr); } } } }