1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
#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/device_registry.hpp>
#include <kapi/devices/driver.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::device_registry::get().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)
{
device->bind_driver(candidate.driver_handle);
device->set_state(state::probing);
auto probed = candidate.driver_handle->probe(*device);
if (probed)
{
device->set_state(state::bound);
kstd::println("[OS:DRV] Bound device {} (priority {})", device->name(), candidate.priority);
return;
}
device->bind_driver(kstd::weak_ptr<driver>{});
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
|