From e6d79751cd37f2cbe0d4bd721e59a4ca0d072a55 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 24 Jul 2026 01:12:48 +0200 Subject: kapi: let drivers choose their major number --- kapi/kapi/devices/device.hpp | 4 ++ kapi/kapi/devices/driver.hpp | 3 +- kapi/kapi/devices/interface_registry.hpp | 4 +- kernel/kapi/devices/device.cpp | 5 ++ kernel/kapi/devices/interface_registry.cpp | 10 ++-- kernel/kapi/devices/interface_registry.tests.cpp | 4 +- kernel/kernel/devices/storage.cpp | 2 +- .../kernel/filesystem/device_number_registry.cpp | 61 +++++++++++++++++++--- kernel/kernel/filesystem/file_type_bindings.hpp | 10 ++-- 9 files changed, 78 insertions(+), 25 deletions(-) diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp index 70c5bd15..c26a4701 100644 --- a/kapi/kapi/devices/device.hpp +++ b/kapi/kapi/devices/device.hpp @@ -3,6 +3,7 @@ // IWYU pragma: private, include +#include #include #include @@ -74,6 +75,9 @@ namespace kapi::devices //! Set the lifecycle state of this device. auto set_state(enum state state) -> void; + //! Get the driver, if any, currently bound to this device. + [[nodiscard]] auto bound_driver() const noexcept -> driver *; + //! Bind this device to the given driver. auto bind_driver(kstd::weak_ptr driver) -> void; diff --git a/kapi/kapi/devices/driver.hpp b/kapi/kapi/devices/driver.hpp index 254f7977..837b47e4 100644 --- a/kapi/kapi/devices/driver.hpp +++ b/kapi/kapi/devices/driver.hpp @@ -3,7 +3,6 @@ // IWYU pragma: private, include -#include #include #include @@ -17,6 +16,8 @@ namespace kapi::devices //! @addtogroup kapi-devices-kernel-defined //! @{ + struct device; + //! 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 diff --git a/kapi/kapi/devices/interface_registry.hpp b/kapi/kapi/devices/interface_registry.hpp index 9fad91e6..ae8b5c1a 100644 --- a/kapi/kapi/devices/interface_registry.hpp +++ b/kapi/kapi/devices/interface_registry.hpp @@ -30,9 +30,9 @@ namespace kapi::devices , m_implementation{implementation} {} - [[nodiscard]] constexpr auto device() const noexcept -> kstd::weak_ptr + [[nodiscard]] constexpr auto device() const noexcept -> kstd::shared_ptr { - return m_device; + return m_device.lock(); } [[nodiscard]] constexpr auto name() const noexcept -> kstd::string const & diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp index cbbd5405..4c63f6a4 100644 --- a/kernel/kapi/devices/device.cpp +++ b/kernel/kapi/devices/device.cpp @@ -32,6 +32,11 @@ namespace kapi::devices m_state = state; } + auto device::bound_driver() const noexcept -> driver * + { + return m_driver.lock().get(); + } + auto device::bind_driver(kstd::weak_ptr driver) -> void { m_driver = driver; diff --git a/kernel/kapi/devices/interface_registry.cpp b/kernel/kapi/devices/interface_registry.cpp index 8882e8db..da3d080a 100644 --- a/kernel/kapi/devices/interface_registry.cpp +++ b/kernel/kapi/devices/interface_registry.cpp @@ -46,7 +46,7 @@ namespace kapi::devices auto interface_registry::do_publish(kstd::shared_ptr device, kstd::string name, interface interface, void * implementation) -> kstd::result { - erase_if(m_entries, [interface](auto e) { return e.interface() == interface && e.device().expired(); }); + erase_if(m_entries, [interface](auto e) { return e.interface() == interface && !e.device(); }); if (!device || !implementation || name.empty()) { @@ -54,7 +54,7 @@ namespace kapi::devices } auto published = std::ranges::any_of(m_entries, [&](auto const & entry) { - return entry.interface() == interface && entry.device().lock().get() == device.get(); + return entry.interface() == interface && entry.device().get() == device.get(); }); if (published) @@ -70,7 +70,7 @@ namespace kapi::devices auto interface_registry::unpublish(device const & device, interface interface) -> void { erase_if(m_entries, [&](auto e) { - auto locked_device = e.device().lock(); + auto locked_device = e.device(); return e.interface() == interface && locked_device && locked_device.get() == &device; }); } @@ -79,7 +79,7 @@ namespace kapi::devices { auto filtered = m_entries; erase_if(filtered, [&](auto e) { - auto locked_device = e.device().lock(); + auto locked_device = e.device(); return !(e.interface() == interface && locked_device); }); return filtered; @@ -88,7 +88,7 @@ namespace kapi::devices auto interface_registry::find(interface interface, std::string_view name) const -> kstd::result { auto found = std::ranges::find_if( - m_entries, [&](auto e) { return e.interface() == interface && e.name() == name && e.device().lock(); }); + m_entries, [&](auto e) { return e.interface() == interface && e.name() == name && e.device(); }); if (found == m_entries.cend()) { return kstd::failure(make_error_code(kstd::errc::no_such_device)); diff --git a/kernel/kapi/devices/interface_registry.tests.cpp b/kernel/kapi/devices/interface_registry.tests.cpp index 78cd7ecf..100954ea 100644 --- a/kernel/kapi/devices/interface_registry.tests.cpp +++ b/kernel/kapi/devices/interface_registry.tests.cpp @@ -114,9 +114,9 @@ SCENARIO("Publishing and finding a device", "[kapi][devices][interface_registry] REQUIRE(probeable_devices[0].name() == "probe0"); } - THEN("the returned device pointer is lockable") + THEN("the returned device pointer is valid") { - REQUIRE(probeable_devices[0].device().lock()); + REQUIRE(probeable_devices[0].device()); } THEN("the returned implementation equals the result of device::as") diff --git a/kernel/kernel/devices/storage.cpp b/kernel/kernel/devices/storage.cpp index d5508270..cfdf3ec2 100644 --- a/kernel/kernel/devices/storage.cpp +++ b/kernel/kernel/devices/storage.cpp @@ -29,6 +29,6 @@ namespace kernel::devices::storage return nullptr; } - return block_devices.front().device().lock(); + return block_devices.front().device(); } } // namespace kernel::devices::storage \ No newline at end of file diff --git a/kernel/kernel/filesystem/device_number_registry.cpp b/kernel/kernel/filesystem/device_number_registry.cpp index 430da00a..058ae322 100644 --- a/kernel/kernel/filesystem/device_number_registry.cpp +++ b/kernel/kernel/filesystem/device_number_registry.cpp @@ -12,13 +12,21 @@ #include #include +#include #include #include namespace { constinit auto static instance = std::optional{}; -} + + struct driver_group + { + kapi::devices::driver const * bound_driver; + std::uint8_t major; + kstd::vector published; + }; +} // namespace namespace kernel::filesystem { @@ -88,17 +96,54 @@ namespace kernel::filesystem for (auto const & binding : file_type_bindings) { - auto next_minor = decltype(kapi::filesystem::device_number::minor){}; + auto groups = kstd::vector{}; for (auto const & published : m_interface_registry->all(binding.interface)) { - if (auto device = published.device().lock()) + auto device = published.device(); + if (!device) + { + continue; + } + + auto bound_driver = device->bound_driver(); + if (!bound_driver) + { + continue; + } + + auto claimed = bound_driver->claimed_major(); + if (!claimed) + { + continue; + } + + auto found_group = + std::ranges::find_if(groups, [&](auto const & group) { return group.bound_driver == bound_driver; }); + + if (found_group == groups.end()) + { + groups.push_back({.bound_driver = bound_driver, .major = *claimed, .published = {}}); + found_group = groups.end() - 1; + } + + found_group->published.push_back(published); + } + + for (auto const & group : groups) + { + auto next_minor = decltype(kapi::filesystem::device_number::minor){}; + + for (auto const & published : group.published) { - m_entries.emplace_back(kapi::filesystem::device_number{.major = binding.major, .minor = next_minor}, // - binding.posix_type, // - published.name(), // - published.device()); - ++next_minor; + if (auto device = published.device()) + { + m_entries.emplace_back(kapi::filesystem::device_number{.major = group.major, .minor = next_minor}, // + binding.posix_type, // + published.name(), // + published.device()); + ++next_minor; + } } } } diff --git a/kernel/kernel/filesystem/file_type_bindings.hpp b/kernel/kernel/filesystem/file_type_bindings.hpp index e33d5086..94f6a763 100644 --- a/kernel/kernel/filesystem/file_type_bindings.hpp +++ b/kernel/kernel/filesystem/file_type_bindings.hpp @@ -7,24 +7,22 @@ #include #include -#include namespace kernel::filesystem { - //! A binding between an interface, a posix special file type, and a major number. + //! A binding between an interface, a posix special file type struct file_type_binding // NOLINT(cppcoreguidelines-pro-type-member-init) { kapi::devices::interface interface; file_type posix_type; - std::uint8_t major; }; - //! Predefined bindings for interface + file type + major number. + //! Predefined bindings for interface + file type //! - //! This array associates reserved major numbers with file types and interfaces. + //! This array associates published interfaces with files types. constexpr auto inline file_type_bindings = std::array{ - file_type_binding{kapi::devices::block_device::id, file_type::block, block_major_numbers::ram_disk}, + file_type_binding{kapi::devices::block_device::id, file_type::block}, }; } // namespace kernel::filesystem -- cgit v1.2.3