From cb87b4dd8e874d5d7b219487ca38f55756c205df Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 23 Jul 2026 18:52:24 +0200 Subject: kapi: introduce driver and bus protocol --- kapi/kapi/devices.hpp | 3 ++ kapi/kapi/devices/bus_protocol.hpp | 43 ++++++++++++++++++++ kapi/kapi/devices/driver.hpp | 80 ++++++++++++++++++++++++++++++++++++++ kapi/kapi/devices/error.hpp | 36 +++++++++++++++++ kernel/CMakeLists.txt | 2 + kernel/kapi/devices/driver.cpp | 19 +++++++++ kernel/kapi/devices/error.cpp | 48 +++++++++++++++++++++++ 7 files changed, 231 insertions(+) create mode 100644 kapi/kapi/devices/bus_protocol.hpp create mode 100644 kapi/kapi/devices/driver.hpp create mode 100644 kapi/kapi/devices/error.hpp create mode 100644 kernel/kapi/devices/driver.cpp create mode 100644 kernel/kapi/devices/error.cpp diff --git a/kapi/kapi/devices.hpp b/kapi/kapi/devices.hpp index 5c3d1b63..d66afc96 100644 --- a/kapi/kapi/devices.hpp +++ b/kapi/kapi/devices.hpp @@ -3,9 +3,12 @@ #include // IWYU pragma: export #include // IWYU pragma: export +#include // IWYU pragma: export #include // IWYU pragma: export #include // IWYU pragma: export #include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export #include // IWYU pragma: export #include // IWYU pragma: export #include // IWYU pragma: export diff --git a/kapi/kapi/devices/bus_protocol.hpp b/kapi/kapi/devices/bus_protocol.hpp new file mode 100644 index 00000000..2e4e6993 --- /dev/null +++ b/kapi/kapi/devices/bus_protocol.hpp @@ -0,0 +1,43 @@ +#ifndef TEACHOS_KAPI_DEVICES_BUS_PROTOCOL_HPP +#define TEACHOS_KAPI_DEVICES_BUS_PROTOCOL_HPP + +// IWYU pragma: private, include + +#include +#include +#include + +#include + +#include + +namespace kapi::devices +{ + + //! Bus specific behavior. + //! + //! A bus protocol defines how a bus discovers its attached children, and how drivers are matched against devices. It + //! it a pure behavioral mixin. + struct bus_protocol + { + //! Allow safe destruction through base pointers. + virtual ~bus_protocol() = default; + + //! Discover the child devices, and busses, attached to the bus using this protocol. + //! + //! @param bus The bus to enumerate. + virtual auto enumerate(bus & bus) -> void = 0; + + //! Determine whether a given drivers is a candidate to bind a given device. + //! + //! @param device The device to test. + //! @param driver The driver to match against the device. + //! @return The match priority (higher == better match), of the device<->driver pairing, and error if the driver + //! doesn't match the device at all. + [[nodiscard]] virtual auto match(device const & device, driver const & driver) const + -> kstd::result = 0; + }; + +} // namespace kapi::devices + +#endif \ No newline at end of file diff --git a/kapi/kapi/devices/driver.hpp b/kapi/kapi/devices/driver.hpp new file mode 100644 index 00000000..fde5068c --- /dev/null +++ b/kapi/kapi/devices/driver.hpp @@ -0,0 +1,80 @@ +#ifndef TEACHOS_KAPI_DEVICES_DRIVER_HPP +#define TEACHOS_KAPI_DEVICES_DRIVER_HPP + +// IWYU pragma: private, include + +#include +#include + +#include + +#include +#include + +namespace kapi::devices +{ + + //! @addtogroup kapi-devices-kernel-defined + //! @{ + + //! The base type for all device drivers. + //! + //! Drivers model the behavior necessary to drive a device or bus. They are stateless logic and are thus never + //! attached to a bus or the device tree. + struct driver + { + //! Enable safe destruction through base pointers. + virtual ~driver() = default; + + //! Try to claim and initialize a device. + //! + //! This function must be called after a bus protocol has matched a device and selected this driver as the best + //! available one. + //! + //! @param device The device to probe. + //! @return Nothing on success, an error otherwise. If an error is returned, the device remains unbound. + [[nodiscard]] virtual auto probe(device & device) -> kstd::result = 0; + + //! Release a device from this driver. + //! + //! This function must undo any initialization performed by a previous probe. It is intended to be called when a + //! device is removed from the device tree. Alternatively, unbinding may be requested by user-space, essentially + //! allowing a different driver to claim this device. + //! + //! @param device The device to release. + virtual auto unbind(device & device) -> void = 0; + + //! Retrieve this drivers implementation of a given capability interface. + //! + //! @return A pointer to this drivers implementation of the requested interface, nullptr if this driver does not + //! support the requested interface. + template + [[nodiscard]] auto as() -> InterfaceType * + { + return static_cast(query_interface(InterfaceType::id)); + } + + //! Check if this driver implements a given capability interface. + //! + //! @return true iff. this driver implements the requested capability interface, false otherwise. + template + [[nodiscard]] auto is_a() const noexcept -> bool + { + return query_interface(InterfaceType::id) != nullptr; + } + + //! Get the major number associated with this driver, if any. + //! + //! Drivers that want to claim an auto-populated device node in devfs must override this function. + [[nodiscard]] virtual auto claimed_major() const -> std::optional; + + protected: + //! Return a pointer to the implementation of the given interface if this driver supports it. + virtual auto query_interface(interface interface) -> void *; + }; + + //! @} + +} // namespace kapi::devices + +#endif \ No newline at end of file diff --git a/kapi/kapi/devices/error.hpp b/kapi/kapi/devices/error.hpp new file mode 100644 index 00000000..b4812550 --- /dev/null +++ b/kapi/kapi/devices/error.hpp @@ -0,0 +1,36 @@ +#ifndef TEACHOS_KAPI_DEVICES_ERROR_HPP +#define TEACHOS_KAPI_DEVICES_ERROR_HPP + +// IWYU pragma: private, include + +#include + +#include + +namespace kapi::devices +{ + + enum struct driver_match_errc + { + //! The driver did not match on the given device. + no_match = 1, + }; + + [[nodiscard]] auto driver_match_category() noexcept -> kstd::error_category const &; + + [[nodiscard]] constexpr auto inline make_error_code(driver_match_errc error) noexcept -> kstd::error_code + { + return kstd::error_code{static_cast(error), driver_match_category()}; + } + +} // namespace kapi::devices + +namespace kstd +{ + template<> + struct is_error_code_enum : std::true_type + { + }; +} // namespace kstd + +#endif \ No newline at end of file diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 9d3a83e2..72994449 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -15,6 +15,8 @@ target_sources("kernel_lib" PRIVATE "kapi/devices/bus.cpp" "kapi/devices/cpu.cpp" "kapi/devices/device.cpp" + "kapi/devices/driver.cpp" + "kapi/devices/error.cpp" "kapi/devices/interface_registry.cpp" "kapi/filesystem.cpp" "kapi/interrupts.cpp" diff --git a/kernel/kapi/devices/driver.cpp b/kernel/kapi/devices/driver.cpp new file mode 100644 index 00000000..c6b5e056 --- /dev/null +++ b/kernel/kapi/devices/driver.cpp @@ -0,0 +1,19 @@ +#include + +#include +#include + +namespace kapi::devices +{ + + auto driver::claimed_major() const -> std::optional + { + return std::nullopt; + } + + auto driver::query_interface(interface) -> void * + { + return nullptr; + } + +} // namespace kapi::devices diff --git a/kernel/kapi/devices/error.cpp b/kernel/kapi/devices/error.cpp new file mode 100644 index 00000000..9d814fbe --- /dev/null +++ b/kernel/kapi/devices/error.cpp @@ -0,0 +1,48 @@ +#include + +#include + +#include +#include + +namespace kapi::devices +{ + + namespace + { + struct driver_match_category_t final : kstd::error_category + { + [[nodiscard]] auto name() const noexcept -> std::string_view override + { + return "driver_match"; + } + + [[nodiscard]] auto message(int value) const noexcept -> std::string_view override + { + switch (static_cast(value)) + { + case driver_match_errc::no_match: + return "driver does not match this device"; + default: + return "unknown driver matching error"; + } + } + + [[nodiscard]] auto default_error_condition(int value) const noexcept -> kstd::error_condition override + { + if (value == std::to_underlying(driver_match_errc::no_match)) + { + return make_error_condition(kstd::errc::not_supported); + } + return kstd::error_category::default_error_condition(value); + } + + } constexpr driver_match_category_instance{}; + } // namespace + + auto driver_match_category() noexcept -> kstd::error_category const & + { + return driver_match_category_instance; + } + +} // namespace kapi::devices \ No newline at end of file -- cgit v1.2.3