aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-07-23 21:09:34 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-23 21:46:16 +0200
commitfbc31c3e385363f9eaba93238756a739e09ce873 (patch)
tree05343a458fb1e40df5babb46bca4a217fe6d1503
parentcb87b4dd8e874d5d7b219487ca38f55756c205df (diff)
downloadkernel-fbc31c3e385363f9eaba93238756a739e09ce873.tar.xz
kernel-fbc31c3e385363f9eaba93238756a739e09ce873.zip
kapi: add driver registry
-rw-r--r--kapi/kapi/devices/bus.hpp5
-rw-r--r--kapi/kapi/devices/device.hpp27
-rw-r--r--kapi/kapi/devices/driver_registry.hpp51
-rw-r--r--kapi/kapi/devices/manager.hpp6
-rw-r--r--kapi/kapi/test_support/devices.hpp1
-rw-r--r--kernel/CMakeLists.txt1
-rw-r--r--kernel/kapi/devices.cpp19
-rw-r--r--kernel/kapi/devices/bus.cpp5
-rw-r--r--kernel/kapi/devices/device.cpp29
-rw-r--r--kernel/kapi/devices/driver_registry.cpp135
10 files changed, 277 insertions, 2 deletions
diff --git a/kapi/kapi/devices/bus.hpp b/kapi/kapi/devices/bus.hpp
index 6356e166..0e654072 100644
--- a/kapi/kapi/devices/bus.hpp
+++ b/kapi/kapi/devices/bus.hpp
@@ -41,6 +41,11 @@ namespace kapi::devices
[[nodiscard]] auto children() const -> std::span<kstd::shared_ptr<device> const>;
+ //! Get this bus's protocol facet, if present.
+ //!
+ //! @return this bus's protocol facet if it has one, nullptr otherwise.
+ [[nodiscard]] virtual auto protocol() -> struct bus_protocol *;
+
protected:
//! Enumerate the devices on the bus.
//!
diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp
index 6ffd052d..c1b2065b 100644
--- a/kapi/kapi/devices/device.hpp
+++ b/kapi/kapi/devices/device.hpp
@@ -14,6 +14,15 @@ namespace kapi::devices
//! @addtogroup kapi-devices-kernel-defined
//! @{
+ enum struct state
+ {
+ uninitialized,
+ present,
+ bound,
+ failed,
+ removed,
+ };
+
/**
* @brief Base device identified by a name.
*/
@@ -65,6 +74,21 @@ namespace kapi::devices
//! @return a shared pointer to the parent bus, or nullptr if this device has no parent.
[[nodiscard]] auto parent() const -> kstd::shared_ptr<struct bus>;
+ //! Get this devices current state.
+ [[nodiscard]] auto state() const noexcept -> state;
+
+ //! Set the lifecycle state of this device.
+ auto set_state(enum state state) -> void;
+
+ //! Bind this device to the given driver.
+ auto bind_driver(kstd::weak_ptr<struct driver> driver) -> void;
+
+ //! Get the driver data associated with this device.
+ [[nodiscard]] auto driver_data() const -> kstd::shared_ptr<void> const &;
+
+ //! Set the driver data for this device.
+ auto set_driver_data(kstd::shared_ptr<void> data) -> void;
+
protected:
auto virtual query_interface(interface interface) -> void *;
@@ -75,6 +99,9 @@ namespace kapi::devices
kstd::string m_name;
kstd::weak_ptr<bus> m_parent;
+ devices::state m_state{state::uninitialized};
+ kstd::weak_ptr<struct driver> m_driver{};
+ kstd::shared_ptr<void> m_driver_data{};
};
//! @}
diff --git a/kapi/kapi/devices/driver_registry.hpp b/kapi/kapi/devices/driver_registry.hpp
new file mode 100644
index 00000000..26a81678
--- /dev/null
+++ b/kapi/kapi/devices/driver_registry.hpp
@@ -0,0 +1,51 @@
+#ifndef TEACHOS_KAPI_DEVICES_DRIVER_REGISTRY_HPP
+#define TEACHOS_KAPI_DEVICES_DRIVER_REGISTRY_HPP
+
+#include <kapi/devices/device.hpp>
+#include <kapi/devices/driver.hpp>
+
+#include <kstd/memory.hpp>
+#include <kstd/vector.hpp>
+
+namespace kapi::devices
+{
+
+ //! @addtogroup kapi-devices-kernel-defined
+ //! @{
+
+ struct driver_registry
+ {
+ driver_registry() = default;
+
+ auto static init() -> void;
+
+ auto static get() -> driver_registry &;
+
+ //! Register a new driver.
+ //!
+ //! The driver will be tried against all devices in the device tree that are not yet bound by a different driver.
+ //!
+ //! @param driver The driver to register.
+ auto add(kstd::shared_ptr<driver> driver) -> void;
+
+ //! Notify the registry about a new device having been attached to the device tree.
+ //!
+ //! The device will be tried against all currently registered drivers.
+ //!
+ //! @param device The device that was attached.
+ auto device_attached(kstd::shared_ptr<device> const & device) -> void;
+
+ private:
+ //! Try to bind a given device against every currently registered driver, if it is not bound yet.
+ //!
+ //! Driver matching will occur in driver registration order. The highest priority driver will win.
+ auto try_bind(kstd::shared_ptr<device> const & device) -> void;
+
+ kstd::vector<kstd::shared_ptr<driver>> m_drivers;
+ };
+
+ //! @}
+
+} // namespace kapi::devices
+
+#endif \ No newline at end of file
diff --git a/kapi/kapi/devices/manager.hpp b/kapi/kapi/devices/manager.hpp
index 5b620b27..de6ebf97 100644
--- a/kapi/kapi/devices/manager.hpp
+++ b/kapi/kapi/devices/manager.hpp
@@ -6,6 +6,7 @@
#include <kapi/devices/device.hpp>
#include <kstd/memory.hpp>
+#include <kstd/vector.hpp>
#include <string_view>
@@ -33,6 +34,11 @@ namespace kapi::devices
//! @return a shared pointer to the device iff. the device was found and is still alive, nullptr otherwise.
auto find_device(std::string_view name) -> kstd::shared_ptr<device>;
+ //! Get all currently registered devices.
+ //!
+ //! @return every device current reachable through the registry.
+ [[nodiscard]] auto all() -> kstd::vector<kstd::shared_ptr<device>>;
+
//! @}
} // namespace kapi::devices
diff --git a/kapi/kapi/test_support/devices.hpp b/kapi/kapi/test_support/devices.hpp
index ab0911fc..b4d410d6 100644
--- a/kapi/kapi/test_support/devices.hpp
+++ b/kapi/kapi/test_support/devices.hpp
@@ -5,6 +5,7 @@ namespace kapi::test_support::devices
{
auto deinit() -> void;
auto deinit_interface_registry() -> void;
+ auto deinit_driver_registry() -> void;
} // namespace kapi::test_support::devices
#endif
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
index 72994449..d3e0c015 100644
--- a/kernel/CMakeLists.txt
+++ b/kernel/CMakeLists.txt
@@ -16,6 +16,7 @@ target_sources("kernel_lib" PRIVATE
"kapi/devices/cpu.cpp"
"kapi/devices/device.cpp"
"kapi/devices/driver.cpp"
+ "kapi/devices/driver_registry.cpp"
"kapi/devices/error.cpp"
"kapi/devices/interface_registry.cpp"
"kapi/filesystem.cpp"
diff --git a/kernel/kapi/devices.cpp b/kernel/kapi/devices.cpp
index 8f3011fe..5eed1b87 100644
--- a/kernel/kapi/devices.cpp
+++ b/kernel/kapi/devices.cpp
@@ -2,6 +2,7 @@
#include <kernel/devices/root_bus.hpp>
+#include <kapi/devices/driver_registry.hpp>
#include <kapi/system.hpp>
#include <kapi/test_support/devices.hpp>
@@ -9,6 +10,7 @@
#include <kstd/memory.hpp>
#include <kstd/print.hpp>
#include <kstd/string.hpp>
+#include <kstd/vector.hpp>
#include <string_view>
#include <utility>
@@ -29,6 +31,7 @@ namespace kapi::devices
}
interface_registry::init();
+ driver_registry::init();
root_bus = kstd::make_shared<kernel::devices::root_bus>();
register_device(root_bus);
@@ -85,6 +88,21 @@ namespace kapi::devices
return found->second.lock();
}
+ auto all() -> kstd::vector<kstd::shared_ptr<device>>
+ {
+ auto result = kstd::vector<kstd::shared_ptr<device>>{};
+
+ for (auto const & [name, weak_device] : device_tree)
+ {
+ if (auto device = weak_device.lock())
+ {
+ result.push_back(std::move(device));
+ }
+ }
+
+ return result;
+ }
+
} // namespace kapi::devices
namespace kapi::test_support::devices
@@ -92,6 +110,7 @@ namespace kapi::test_support::devices
auto deinit() -> void
{
deinit_interface_registry();
+ deinit_driver_registry();
kapi::devices::root_bus.reset();
}
diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp
index 179a04a8..6c659ef5 100644
--- a/kernel/kapi/devices/bus.cpp
+++ b/kernel/kapi/devices/bus.cpp
@@ -68,6 +68,11 @@ namespace kapi::devices
return {m_devices.data(), m_devices.size()};
}
+ auto bus::protocol() -> struct bus_protocol *
+ {
+ return nullptr;
+ }
+
auto bus::enumerate() -> bool
{
return true;
diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp
index 540d37b7..cbbd5405 100644
--- a/kernel/kapi/devices/device.cpp
+++ b/kernel/kapi/devices/device.cpp
@@ -22,9 +22,29 @@ namespace kapi::devices
return m_parent.lock();
}
- auto device::set_parent(kstd::weak_ptr<bus> parent) -> void
+ auto device::state() const noexcept -> enum state
{
- m_parent = parent;
+ return m_state;
+ }
+
+ auto device::set_state(enum state state) -> void
+ {
+ m_state = state;
+ }
+
+ auto device::bind_driver(kstd::weak_ptr<struct driver> driver) -> void
+ {
+ m_driver = driver;
+ }
+
+ auto device::driver_data() const -> kstd::shared_ptr<void> const &
+ {
+ return m_driver_data;
+ }
+
+ auto device::set_driver_data(kstd::shared_ptr<void> data) -> void
+ {
+ m_driver_data = data;
}
auto device::query_interface(interface) -> void *
@@ -32,4 +52,9 @@ namespace kapi::devices
return nullptr;
}
+ auto device::set_parent(kstd::weak_ptr<bus> parent) -> void
+ {
+ m_parent = parent;
+ }
+
} // namespace kapi::devices \ No newline at end of file
diff --git a/kernel/kapi/devices/driver_registry.cpp b/kernel/kapi/devices/driver_registry.cpp
new file mode 100644
index 00000000..67da9877
--- /dev/null
+++ b/kernel/kapi/devices/driver_registry.cpp
@@ -0,0 +1,135 @@
+#include <kapi/devices/driver_registry.hpp>
+
+#include <kapi/devices/bus.hpp>
+#include <kapi/devices/bus_protocol.hpp>
+#include <kapi/devices/device.hpp>
+#include <kapi/devices/driver.hpp>
+#include <kapi/devices/manager.hpp>
+#include <kapi/system.hpp>
+#include <kapi/test_support/devices.hpp>
+
+#include <kstd/memory.hpp>
+#include <kstd/print.hpp>
+#include <kstd/system_error.hpp>
+#include <kstd/vector.hpp>
+
+#include <algorithm>
+#include <cstdint>
+#include <functional>
+#include <optional>
+#include <utility>
+
+namespace kapi::devices
+{
+
+ namespace
+ {
+ constinit auto static registry = std::optional<driver_registry>{};
+
+ struct candidate
+ {
+ std::uint32_t priority;
+ kstd::shared_ptr<driver> driver_handle;
+ };
+ } // namespace
+
+ auto driver_registry::init() -> void
+ {
+ if (registry.has_value())
+ {
+ system::panic("[kernel] Device driver registry has already been initialized.");
+ }
+
+ registry.emplace();
+ }
+
+ auto driver_registry::get() -> driver_registry &
+ {
+ if (!registry)
+ {
+ system::panic("[kernel] Device driver registry has not been initialized.");
+ }
+
+ return *registry;
+ }
+
+ auto driver_registry::add(kstd::shared_ptr<driver> driver) -> void
+ {
+ m_drivers.emplace_back(std::move(driver));
+
+ for (auto const & device : kapi::devices::all())
+ {
+ if (device->state() != state::bound)
+ {
+ try_bind(device);
+ }
+ }
+ }
+
+ auto driver_registry::device_attached(kstd::shared_ptr<device> const & device) -> void
+ {
+ try_bind(device);
+ }
+
+ auto driver_registry::try_bind(kstd::shared_ptr<device> const & device) -> void
+ {
+ if (!device || device->state() == state::bound)
+ {
+ return;
+ }
+
+ auto parent = device->parent();
+ auto protocol = parent ? parent->protocol() : nullptr;
+ if (!protocol)
+ {
+ return;
+ }
+
+ auto candidates = kstd::vector<candidate>{};
+
+ for (auto const & driver : m_drivers)
+ {
+ auto match = protocol->match(*device, *driver);
+ if (match)
+ {
+ candidates.push_back({.priority = *match, .driver_handle = driver});
+ }
+ else if (match.error() != kstd::errc::not_supported)
+ {
+ kstd::println(kstd::print_sink::stderr, "[OS:DRV] match() failed for device {}: {}", device->name(),
+ match.error().message());
+ }
+ }
+
+ std::ranges::stable_sort(candidates, std::ranges::greater{}, &candidate::priority);
+
+ for (auto const & candidate : candidates)
+ {
+ auto probed = candidate.driver_handle->probe(*device);
+ if (probed)
+ {
+ device->bind_driver(candidate.driver_handle);
+ device->set_state(state::bound);
+ kstd::println("[OS:DRV] Bound device {} (priority {})", device->name(), candidate.priority);
+ return;
+ }
+
+ kstd::println(kstd::print_sink::stderr, "[OS:DRV] probe() failed for device {} (priority {}): {}", device->name(),
+ candidate.priority, probed.error().message());
+ }
+
+ if (!candidates.empty())
+ {
+ device->set_state(state::failed);
+ }
+ }
+
+} // namespace kapi::devices
+
+namespace kapi::test_support::devices
+{
+ auto deinit_driver_registry() -> void
+ {
+ kapi::devices::registry.reset();
+ }
+} // namespace kapi::test_support::devices \ No newline at end of file