diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-07-16 14:16:33 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-07-16 14:16:33 +0200 |
| commit | a6166befa7421be233ece97e184139870bbc0af7 (patch) | |
| tree | 905c5a876911d0ec2bf7270f6ba0e75b8680eb7c /kapi | |
| parent | d04cb84074b6cdb3d36f5d5e1e22dbc9294724f7 (diff) | |
| download | kernel-a6166befa7421be233ece97e184139870bbc0af7.tar.xz kernel-a6166befa7421be233ece97e184139870bbc0af7.zip | |
kapi: introduce device interfaces
Diffstat (limited to 'kapi')
| -rw-r--r-- | kapi/kapi/devices.hpp | 40 | ||||
| -rw-r--r-- | kapi/kapi/devices/device.hpp | 23 | ||||
| -rw-r--r-- | kapi/kapi/devices/interface.hpp | 31 | ||||
| -rw-r--r-- | kapi/kapi/devices/interface_registry.hpp | 150 | ||||
| -rw-r--r-- | kapi/kapi/test_support/devices.hpp | 10 |
5 files changed, 250 insertions, 4 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 |
