#include #include #include #include #include #include #include #include #include #include #include #include namespace kapi::devices { bus::bus(kstd::string const & name) : device{name} {} bus::bus(kstd::string const & name, bus_protocol & protocol) : device{name} , m_protocol{&protocol} {} bus::~bus() { auto children = m_devices; for (auto const & child : children) { remove_child(*child); } } auto bus::add_child(kstd::shared_ptr child) -> void { { auto guard = kstd::lock_guard{m_lock}; child->set_parent(kstd::static_pointer_cast(shared_from_this())); } if (!kapi::devices::device_registry::get().add(child)) { kapi::system::panic("[OS:DEV] Failed to register child device {}", child->name()); } auto attached = kstd::shared_ptr{}; { auto guard = kstd::lock_guard{m_lock}; attached = m_devices.emplace_back(std::move(child)); } attached->set_state(state::present); driver_registry::get().device_attached(attached); } auto bus::remove_child(device & device) -> bool // NOLINT(misc-no-recursion) { auto lifeline = kstd::shared_ptr{}; { auto guard = kstd::lock_guard{m_lock}; auto found = std::ranges::find_if(m_devices, [&](auto const & d) { return d.get() == &device; }); if (found == m_devices.end()) { return false; } lifeline = *found; m_devices.erase(found); } do_remove_child(*lifeline); return true; } [[nodiscard]] auto bus::children() const -> kstd::vector> { auto guard = kstd::lock_guard{m_lock}; return m_devices; } auto bus::query_facet(kapi::capabilities::facet_id facet) -> void * { if (facet == bus::id) { return this; } else if (facet == bus_protocol::id) { return m_protocol; } return device::query_facet(facet); } auto bus::do_remove_child(device & device) -> void // NOLINT(misc-no-recursion) { if (device.state() == state::removed) { return; } if (auto child_bus = device.facet()) { auto grandchildren = kstd::vector>{}; { auto guard = kstd::lock_guard{child_bus->m_lock}; // NOTE: this could be more efficient one vector::assign is implemented. grandchildren = kstd::vector(child_bus->m_devices.begin(), child_bus->m_devices.end()); } for (auto & grandchild : grandchildren) { child_bus->remove_child(*grandchild); } } device.set_state(state::removed); if (auto bound_driver = device.bound_driver()) { bound_driver->unbind(device); } facet_registry::get().withdraw_all_for(device); device_registry::get().remove(device); device.set_parent(kstd::weak_ptr{}); } } // namespace kapi::devices