aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kapi/kapi/devices.hpp40
-rw-r--r--kapi/kapi/devices/device.hpp23
-rw-r--r--kapi/kapi/devices/interface.hpp31
-rw-r--r--kapi/kapi/devices/interface_registry.hpp150
-rw-r--r--kapi/kapi/test_support/devices.hpp10
-rw-r--r--kernel/CMakeLists.txt1
-rw-r--r--kernel/kapi/devices.cpp21
-rw-r--r--kernel/kapi/devices/device.cpp6
-rw-r--r--kernel/kapi/devices/interface_registry.cpp108
-rw-r--r--kernel/kapi/devices/interface_registry.tests.cpp199
-rw-r--r--kernel/kernel/devices/storage/ram_disk/device.cpp1
-rw-r--r--kernel/kernel/test_support/state_reset_listener.cpp5
12 files changed, 586 insertions, 9 deletions
diff --git a/kapi/kapi/devices.hpp b/kapi/kapi/devices.hpp
index b597aa8c..64820f7c 100644
--- a/kapi/kapi/devices.hpp
+++ b/kapi/kapi/devices.hpp
@@ -1,10 +1,18 @@
#ifndef TEACHOS_KAPI_DEVICES_HPP
#define TEACHOS_KAPI_DEVICES_HPP
-#include <kapi/devices/bus.hpp> // IWYU pragma: export
-#include <kapi/devices/cpu.hpp> // IWYU pragma: export
-#include <kapi/devices/device.hpp> // IWYU pragma: export
-#include <kapi/devices/manager.hpp> // IWYU pragma: export
+#include <kapi/devices/bus.hpp> // IWYU pragma: export
+#include <kapi/devices/cpu.hpp> // IWYU pragma: export
+#include <kapi/devices/device.hpp> // IWYU pragma: export
+#include <kapi/devices/interface.hpp> // IWYU pragma: export
+#include <kapi/devices/interface_registry.hpp> // IWYU pragma: export
+#include <kapi/devices/manager.hpp> // IWYU pragma: export
+
+#include <kstd/memory.hpp>
+#include <kstd/result.hpp>
+#include <kstd/string.hpp>
+
+#include <utility>
namespace kapi::devices
{
@@ -22,6 +30,30 @@ namespace kapi::devices
//! @return a reference to the root bus.
auto get_root_bus() -> bus &;
+ //! Publish the fact that a given device implements a given interface.
+ //!
+ //! @tparam Interface The interface type implemented by the given device.
+ //! @param device The device to publish the interface for.
+ //! @param name A stable name for the device.
+ template<typename Interface>
+ auto publish_interface(kstd::shared_ptr<device> device, kstd::string name) -> kstd::result<void>
+ {
+ return interface_registry::get().publish<Interface>(device, std::move(name));
+ }
+
+ //! Publish the fact that a given device implements a given interface.
+ //!
+ //! @tparam Interface The interface type implemented by the given device.
+ //! @param device The device to publish the interface for.
+ //! @param name A stable name for the device.
+ //! @param implementation The implementation of the interface for the device.
+ template<typename Interface>
+ auto publish_interface(kstd::shared_ptr<device> device, kstd::string name, Interface * implementation)
+ -> kstd::result<void>
+ {
+ return interface_registry::get().publish(device, std::move(name), implementation);
+ }
+
//! @}
//! @addtogroup kapi-devices-platform-defined
diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp
index 104d7b8e..e99dd5f8 100644
--- a/kapi/kapi/devices/device.hpp
+++ b/kapi/kapi/devices/device.hpp
@@ -3,6 +3,8 @@
// IWYU pragma: private, include <kapi/devices.hpp>
+#include <kapi/devices/interface.hpp>
+
#include <kstd/memory.hpp>
#include <kstd/string.hpp>
@@ -38,6 +40,24 @@ namespace kapi::devices
*/
virtual auto init() -> bool = 0;
+ template<typename InterfaceType>
+ [[nodiscard]] constexpr auto as() -> InterfaceType *
+ {
+ return static_cast<InterfaceType *>(query_interface(InterfaceType::id));
+ }
+
+ template<typename InterfaceType>
+ [[nodiscard]] constexpr auto as() const noexcept -> InterfaceType const *
+ {
+ return static_cast<InterfaceType const *>(const_cast<device *>(this)->query_interface(InterfaceType::id));
+ }
+
+ template<typename InterfaceType>
+ [[nodiscard]] constexpr auto is_a() const noexcept -> bool
+ {
+ return const_cast<device *>(this)->query_interface(InterfaceType::id) != nullptr;
+ }
+
/**
* @brief Returns the major number of the device.
* @return Device major number.
@@ -62,6 +82,9 @@ namespace kapi::devices
*/
[[nodiscard]] virtual auto is_block_device() const -> bool;
+ protected:
+ auto virtual query_interface(interface interface) -> void *;
+
private:
friend struct bus;
diff --git a/kapi/kapi/devices/interface.hpp b/kapi/kapi/devices/interface.hpp
new file mode 100644
index 00000000..f5198691
--- /dev/null
+++ b/kapi/kapi/devices/interface.hpp
@@ -0,0 +1,31 @@
+#ifndef TEACHOS_KAPI_DEVICES_INTERFACE_HPP
+#define TEACHOS_KAPI_DEVICES_INTERFACE_HPP
+
+// IWYU pragma: private, include <kapi/devices.hpp>
+
+#include <string_view>
+
+namespace kapi::devices
+{
+
+ //! A tag to mark that a given devices provides a specific device capability interface.
+ struct interface
+ {
+ //! Construct a new interface with a given name.
+ constexpr explicit interface(std::string_view name)
+ : m_name{name}
+ {}
+
+ //! Get the name of this interface.
+ [[nodiscard]] constexpr auto name() const noexcept -> std::string_view const &;
+
+ //! Check if this interface is equal to another one.
+ constexpr auto operator==(interface const &) const noexcept -> bool = default;
+
+ private:
+ std::string_view m_name;
+ };
+
+} // namespace kapi::devices
+
+#endif
diff --git a/kapi/kapi/devices/interface_registry.hpp b/kapi/kapi/devices/interface_registry.hpp
new file mode 100644
index 00000000..9fad91e6
--- /dev/null
+++ b/kapi/kapi/devices/interface_registry.hpp
@@ -0,0 +1,150 @@
+#ifndef TEACHOS_KAPI_DEVICES_INTERFACE_REGISTRY_HPP
+#define TEACHOS_KAPI_DEVICES_INTERFACE_REGISTRY_HPP
+
+// IWYU pragma: private, include <kapi/devices.hpp>
+
+#include <kapi/devices/device.hpp>
+#include <kapi/devices/interface.hpp>
+
+#include <kstd/memory.hpp>
+#include <kstd/result.hpp>
+#include <kstd/string.hpp>
+#include <kstd/system_error.hpp>
+#include <kstd/vector.hpp>
+
+#include <string_view>
+#include <utility>
+
+namespace kapi::devices
+{
+
+ struct interface_registry
+ {
+ struct entry
+ {
+ constexpr entry(kstd::shared_ptr<struct device> device, kstd::string name, interface interface,
+ void * implementation)
+ : m_device{device}
+ , m_name{name}
+ , m_interface{interface}
+ , m_implementation{implementation}
+ {}
+
+ [[nodiscard]] constexpr auto device() const noexcept -> kstd::weak_ptr<device>
+ {
+ return m_device;
+ }
+
+ [[nodiscard]] constexpr auto name() const noexcept -> kstd::string const &
+ {
+ return m_name;
+ }
+
+ [[nodiscard]] constexpr auto interface() const noexcept -> interface
+ {
+ return m_interface;
+ }
+
+ [[nodiscard]] constexpr auto implementation() const noexcept -> void *
+ {
+ return m_implementation;
+ }
+
+ template<typename Interface>
+ [[nodiscard]] constexpr auto as() noexcept -> Interface *
+ {
+ return static_cast<Interface *>(m_implementation);
+ }
+
+ template<typename Interface>
+ [[nodiscard]] constexpr auto as() const noexcept -> Interface const *
+ {
+ return static_cast<Interface const *>(m_implementation);
+ }
+
+ private:
+ kstd::weak_ptr<struct device> m_device;
+ kstd::string m_name;
+ struct interface m_interface;
+ void * m_implementation;
+ };
+
+ interface_registry() = default;
+
+ auto static init() -> void;
+
+ auto static get() -> interface_registry &;
+
+ //! Publish the fact that a given device implements a given interface.
+ //!
+ //! @tparam Interface The interface type implemented by the given device.
+ //! @param device The device to publish the interface for.
+ //! @param name A stable name for the device.
+ template<typename Interface>
+ auto publish(kstd::shared_ptr<device> device, kstd::string name) -> kstd::result<void>
+ {
+ if (!device)
+ {
+ return kstd::failure(make_error_code(kstd::errc::invalid_argument));
+ }
+
+ return do_publish(device, std::move(name), Interface::id, device->as<Interface>());
+ }
+
+ //! Publish the fact that a given device implements a given interface.
+ //!
+ //! @tparam Interface The interface type implemented by the given device.
+ //! @param device The device to publish the interface for.
+ //! @param name A stable name for the device.
+ //! @param implementation The implementation of the interface for the device.
+ template<typename Interface>
+ auto publish(kstd::shared_ptr<device> device, kstd::string name, Interface * implementation) -> kstd::result<void>
+ {
+ return do_publish(device, std::move(name), Interface::id, implementation);
+ }
+
+ //! Withdraw a previously published inteface for a given device.
+ //!
+ //! @param device The device to withdraw the interface for.
+ //! @param interface The interface to withdraw for the given device.
+ auto unpublish(device const & device, interface interface) -> void;
+
+ //! Get all devices implementing a given interface.
+ //!
+ //! @param interface The interface for which to get the implementing devices.
+ [[nodiscard]] auto all(interface interface) const -> kstd::vector<entry>;
+
+ //! Find an entry for a given interface on a device with the given name.
+ //!
+ //! @param interface The interface to look for.
+ //! @param name The stable name of the device to look for.
+ //! @return An entry representing the published interface if it exists, an error otherwise.
+ [[nodiscard]] auto find(interface interface, std::string_view name) const -> kstd::result<entry>;
+
+ //! Find an entry for a given interface on a device with the given name.
+ //!
+ //! @tparam Interface The interface type to look for.
+ //! @param name The stable name of the device to look for.
+ //! @return An entry representing the published interface if it exists, an error otherwise.
+ template<typename Interface>
+ [[nodiscard]] auto find(std::string_view name) const -> kstd::result<entry>
+ {
+ return find(Interface::id, name);
+ }
+
+ private:
+ //! Publish the fact that a given device implements a given interface.
+ //!
+ //! @param device The device to publish the interface for.
+ //! @param name A stable name for the device.
+ //! @param interface The capability interface to be published for the device.
+ //! @param implementation The implementation of the interface for the device.
+ auto do_publish(kstd::shared_ptr<device> device, kstd::string name, interface interface, void * implementation)
+ -> kstd::result<void>;
+
+ kstd::vector<entry> m_entries;
+ };
+
+} // namespace kapi::devices
+
+#endif
diff --git a/kapi/kapi/test_support/devices.hpp b/kapi/kapi/test_support/devices.hpp
new file mode 100644
index 00000000..ab0911fc
--- /dev/null
+++ b/kapi/kapi/test_support/devices.hpp
@@ -0,0 +1,10 @@
+#ifndef KAPI_TEST_SUPPORT_DEVICES_HPP
+#define KAPI_TEST_SUPPORT_DEVICES_HPP
+
+namespace kapi::test_support::devices
+{
+ auto deinit() -> void;
+ auto deinit_interface_registry() -> void;
+} // namespace kapi::test_support::devices
+
+#endif
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
index 34d71de1..a73418f0 100644
--- a/kernel/CMakeLists.txt
+++ b/kernel/CMakeLists.txt
@@ -15,6 +15,7 @@ target_sources("kernel_lib" PRIVATE
"kapi/devices/bus.cpp"
"kapi/devices/cpu.cpp"
"kapi/devices/device.cpp"
+ "kapi/devices/interface_registry.cpp"
"kapi/filesystem.cpp"
"kapi/interrupts.cpp"
"kapi/memory.cpp"
diff --git a/kernel/kapi/devices.cpp b/kernel/kapi/devices.cpp
index de4bf9e5..ef72c667 100644
--- a/kernel/kapi/devices.cpp
+++ b/kernel/kapi/devices.cpp
@@ -3,6 +3,7 @@
#include <kernel/devices/root_bus.hpp>
#include <kapi/system.hpp>
+#include <kapi/test_support/devices.hpp>
#include <kstd/flat_map.hpp>
#include <kstd/memory.hpp>
@@ -25,12 +26,13 @@ namespace kapi::devices
auto init() -> void
{
- auto static is_initialized = std::atomic_flag{};
- if (is_initialized.test_and_set())
+ if (root_bus.has_value())
{
- return;
+ kapi::system::panic("[OS:DEV] The device subsystem has already been initialized");
}
+ interface_registry::init();
+
auto & bus = root_bus.emplace();
register_device(bus);
bus.init();
@@ -83,4 +85,15 @@ namespace kapi::devices
return nullptr;
}
-} // namespace kapi::devices \ No newline at end of file
+} // namespace kapi::devices
+
+namespace kapi::test_support::devices
+{
+ auto deinit() -> void
+ {
+ deinit_interface_registry();
+
+ kapi::devices::root_bus.reset();
+ kapi::devices::next_major_number = 1;
+ }
+} // namespace kapi::test_support::devices \ No newline at end of file
diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp
index 5dc59a27..d8cae29c 100644
--- a/kernel/kapi/devices/device.cpp
+++ b/kernel/kapi/devices/device.cpp
@@ -1,5 +1,6 @@
#include <kapi/devices/device.hpp>
+#include <kapi/devices.hpp>
#include <kapi/devices/bus.hpp>
#include <kstd/memory.hpp>
@@ -40,4 +41,9 @@ namespace kapi::devices
m_parent = parent;
}
+ auto device::query_interface(interface) -> void *
+ {
+ return nullptr;
+ }
+
} // namespace kapi::devices \ No newline at end of file
diff --git a/kernel/kapi/devices/interface_registry.cpp b/kernel/kapi/devices/interface_registry.cpp
new file mode 100644
index 00000000..8882e8db
--- /dev/null
+++ b/kernel/kapi/devices/interface_registry.cpp
@@ -0,0 +1,108 @@
+#include <kapi/devices/interface_registry.hpp>
+
+#include <kapi/devices.hpp>
+#include <kapi/system.hpp>
+#include <kapi/test_support/devices.hpp>
+
+#include <kstd/memory.hpp>
+#include <kstd/result.hpp>
+#include <kstd/string.hpp>
+#include <kstd/system_error.hpp>
+#include <kstd/vector.hpp>
+
+#include <algorithm>
+#include <optional>
+#include <string_view>
+#include <utility>
+
+namespace kapi::devices
+{
+
+ namespace
+ {
+ constinit auto static registry = std::optional<interface_registry>{};
+ }
+
+ auto interface_registry::init() -> void
+ {
+ if (registry.has_value())
+ {
+ system::panic("[kernel] Device interface registry has already been initialized.");
+ }
+
+ registry.emplace();
+ }
+
+ auto interface_registry::get() -> interface_registry &
+ {
+ if (!registry)
+ {
+ system::panic("[kernel] Device interface registry has not been initialized.");
+ }
+
+ return *registry;
+ }
+
+ auto interface_registry::do_publish(kstd::shared_ptr<device> device, kstd::string name, interface interface,
+ void * implementation) -> kstd::result<void>
+ {
+ erase_if(m_entries, [interface](auto e) { return e.interface() == interface && e.device().expired(); });
+
+ if (!device || !implementation || name.empty())
+ {
+ return kstd::failure(make_error_code(kstd::errc::invalid_argument));
+ }
+
+ auto published = std::ranges::any_of(m_entries, [&](auto const & entry) {
+ return entry.interface() == interface && entry.device().lock().get() == device.get();
+ });
+
+ if (published)
+ {
+ return kstd::failure(make_error_code(kstd::errc::file_exists));
+ }
+
+ m_entries.emplace_back(device, std::move(name), interface, implementation);
+
+ return kstd::success();
+ }
+
+ auto interface_registry::unpublish(device const & device, interface interface) -> void
+ {
+ erase_if(m_entries, [&](auto e) {
+ auto locked_device = e.device().lock();
+ return e.interface() == interface && locked_device && locked_device.get() == &device;
+ });
+ }
+
+ auto interface_registry::all(interface interface) const -> kstd::vector<entry>
+ {
+ auto filtered = m_entries;
+ erase_if(filtered, [&](auto e) {
+ auto locked_device = e.device().lock();
+ return !(e.interface() == interface && locked_device);
+ });
+ return filtered;
+ }
+
+ auto interface_registry::find(interface interface, std::string_view name) const -> kstd::result<entry>
+ {
+ auto found = std::ranges::find_if(
+ m_entries, [&](auto e) { return e.interface() == interface && e.name() == name && e.device().lock(); });
+ if (found == m_entries.cend())
+ {
+ return kstd::failure(make_error_code(kstd::errc::no_such_device));
+ }
+
+ return *found;
+ }
+
+} // namespace kapi::devices
+
+namespace kapi::test_support::devices
+{
+ auto deinit_interface_registry() -> void
+ {
+ kapi::devices::registry.reset();
+ }
+} // namespace kapi::test_support::devices
diff --git a/kernel/kapi/devices/interface_registry.tests.cpp b/kernel/kapi/devices/interface_registry.tests.cpp
new file mode 100644
index 00000000..ffd9f0d6
--- /dev/null
+++ b/kernel/kapi/devices/interface_registry.tests.cpp
@@ -0,0 +1,199 @@
+#include <kapi/devices.hpp>
+
+#include <kstd/memory.hpp>
+
+#include <catch2/catch_test_macros.hpp>
+
+namespace
+{
+ struct probe_device
+ {
+ constexpr auto static id = kapi::devices::interface{"probe"};
+
+ virtual ~probe_device() = default;
+
+ [[nodiscard]] auto virtual get_value() const noexcept -> int = 0;
+ };
+
+ struct const_device
+ {
+ constexpr auto static id = kapi::devices::interface{"flip"};
+
+ virtual ~const_device() = default;
+
+ [[nodiscard]] auto get_constant() const noexcept -> int
+ {
+ return 0;
+ }
+ };
+
+ struct test_device final : kapi::devices::device, probe_device
+ {
+ explicit test_device(int value, const_device & const_device)
+ : device{0, 0, "probeable"}
+ , m_value{value}
+ , m_const_device{&const_device}
+ {}
+
+ auto init() -> bool override
+ {
+ return true;
+ }
+
+ [[nodiscard]] constexpr auto get_value() const noexcept -> int override
+ {
+ return m_value;
+ }
+
+ auto query_interface(kapi::devices::interface interface) -> void * override
+ {
+ if (interface == probe_device::id)
+ {
+ return static_cast<probe_device *>(this);
+ }
+ if (interface == const_device::id)
+ {
+ return m_const_device;
+ }
+
+ return kapi::devices::device::query_interface(interface);
+ }
+
+ private:
+ int m_value;
+ const_device * m_const_device;
+ };
+
+} // namespace
+
+SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry]")
+{
+ GIVEN("An empty registry, a device, and an interface the device implements by inheritance")
+ {
+ auto registry = kapi::devices::interface_registry{};
+ auto free_standing_interface = const_device{};
+ auto device = kstd::make_shared<test_device>(128, free_standing_interface);
+
+ THEN("Publishing an interface without a name fails")
+ {
+ REQUIRE_FALSE(registry.publish<probe_device>(device, ""));
+ }
+
+ WHEN("publishing the interface for the device")
+ {
+ CHECK(device->is_a<probe_device>());
+ CHECK(device->is_a<const_device>());
+ auto published = registry.publish(device, "probe0", device->as<probe_device>());
+
+ THEN("publishing is successful")
+ {
+ REQUIRE(published);
+ }
+
+ THEN("publishing the same device and interface with a different name fails")
+ {
+ REQUIRE_FALSE(registry.publish(device, "probe1", device->as<probe_device>()));
+ }
+
+ THEN("publishing a second interface for the same device succeeds")
+ {
+ REQUIRE(registry.publish<const_device>(device, "probe0"));
+ }
+
+ THEN("publishing a free standing second interface for the same device succeeds")
+ {
+ REQUIRE(registry.publish(device, "probe0", &free_standing_interface));
+ }
+
+ AND_WHEN("getting all devices implementing that interface")
+ {
+ auto probeable_devices = registry.all(probe_device::id);
+
+ THEN("there is exactly one such device")
+ {
+ REQUIRE(probeable_devices.size() == 1);
+ }
+
+ THEN("the name of the device is 'probe0'")
+ {
+ REQUIRE(probeable_devices[0].name() == "probe0");
+ }
+
+ THEN("the returned device pointer is lockable")
+ {
+ REQUIRE(probeable_devices[0].device().lock());
+ }
+
+ THEN("the returned implementation equals the result of device::as")
+ {
+ REQUIRE(probeable_devices[0].implementation() == device->as<probe_device>());
+ }
+
+ THEN("the interface provided function can be invoked")
+ {
+ auto implementation = probeable_devices[0].as<probe_device>();
+ REQUIRE(implementation->get_value() == device->get_value());
+ }
+ }
+
+ THEN("find finds the published capability by name")
+ {
+ REQUIRE(registry.find<probe_device>("probe0"));
+ }
+
+ THEN("find for an unpublished capability does not find a device")
+ {
+ REQUIRE_FALSE(registry.find<const_device>("probe0"));
+ }
+
+ THEN("find for an unpublished device does not find a device")
+ {
+ REQUIRE_FALSE(registry.find<probe_device>("probe1"));
+ }
+
+ THEN("withdrawing an interface for a device removes it from the registry")
+ {
+ registry.unpublish(*device, probe_device::id);
+ REQUIRE_FALSE(registry.find<probe_device>("probe0"));
+ }
+ }
+
+ WHEN("the device is destroyed without withdrawing it")
+ {
+ CHECK(registry.publish(device, "probe0", device->as<probe_device>()));
+ device.reset();
+
+ THEN("querying all does no longer report it")
+ {
+ REQUIRE(registry.all(probe_device::id).empty());
+ }
+
+ THEN("find() no longer finds it")
+ {
+ REQUIRE_FALSE(registry.find<probe_device>("probe0"));
+ }
+ }
+ }
+
+ GIVEN("no device has ever been published")
+ {
+ auto registry = kapi::devices::interface_registry{};
+
+ THEN("all() returns an empty vector")
+ {
+ REQUIRE(registry.all(probe_device::id).empty());
+ }
+ }
+
+ GIVEN("a null device")
+ {
+ auto registry = kapi::devices::interface_registry{};
+ auto device = kstd::shared_ptr<kapi::devices::device>{};
+ auto interface = const_device{};
+
+ THEN("publishing the interface for the device fails")
+ {
+ REQUIRE_FALSE(registry.publish(device, "probe0", &interface));
+ }
+ }
+}
diff --git a/kernel/kernel/devices/storage/ram_disk/device.cpp b/kernel/kernel/devices/storage/ram_disk/device.cpp
index 2b1c02a2..eff6114d 100644
--- a/kernel/kernel/devices/storage/ram_disk/device.cpp
+++ b/kernel/kernel/devices/storage/ram_disk/device.cpp
@@ -7,7 +7,6 @@
#include <kstd/cstring.hpp>
#include <kstd/format.hpp>
-#include <kstd/string.hpp>
#include <cstddef>
diff --git a/kernel/kernel/test_support/state_reset_listener.cpp b/kernel/kernel/test_support/state_reset_listener.cpp
index 6bb7537c..cbb8ef7c 100644
--- a/kernel/kernel/test_support/state_reset_listener.cpp
+++ b/kernel/kernel/test_support/state_reset_listener.cpp
@@ -9,7 +9,9 @@
#include <kapi/cio.hpp>
#include <kapi/cpu.hpp>
+#include <kapi/devices.hpp>
#include <kapi/memory.hpp>
+#include <kapi/test_support/devices.hpp>
#include <catch2/catch_test_case_info.hpp>
#include <catch2/interfaces/catch_interfaces_reporter.hpp>
@@ -27,6 +29,7 @@ struct state_reset_listener : Catch::EventListenerBase
kapi::cio::init();
kapi::cpu::init();
kapi::memory::init();
+ kapi::devices::init();
}
void testCaseEnded(Catch::TestCaseStats const &) override
@@ -39,6 +42,8 @@ struct state_reset_listener : Catch::EventListenerBase
kernel::tests::memory::deinit();
kernel::tests::cpu::deinit();
kernel::tests::cio::deinit();
+
+ kapi::test_support::devices::deinit();
}
};