blob: ce15b6d8095b48359e98b2e12d95e6301096a9ee (
plain)
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
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2026 Richard Qin */
/*
* drivers/base/driver.cc — driver_register / driver_unregister.
*
* Mirrors Linux drivers/base/driver.c. Registers a device_driver on
* its bus and tries to bind any unbound matching devices.
*
* Reference: docs/specs/storage_stack.md §4.3
*/
#include <lume/device.h>
#include <lume/container_of.h>
#include <lume/klog.h>
#include <lume/kprintf.h>
#include <lume/errno.h>
/* Implemented in core.cc — bind a device to a driver on its bus.
* Returns 1 on success, 0 on no-match-or-probe-fail. */
int device_try_bind(device* dev, device_driver* drv);
int driver_register(device_driver* drv)
{
if (drv == nullptr || drv->bus == nullptr) {
return -EINVAL;
}
if (!drv->bus->registered) {
kprintf("[driver] register '%s' fail: bus '%s' not registered\n",
drv->name != nullptr ? drv->name : "?",
drv->bus->name != nullptr ? drv->bus->name : "?");
return -ENODEV;
}
drv->bus_node.init();
drv->devices.init();
LockGuard g(drv->bus->lock);
list_add_tail(&drv->bus_node, &drv->bus->drivers);
/* Try to bind any unbound devices already on the bus. */
list_node* cur = drv->bus->devices.next;
while (cur != &drv->bus->devices) {
device* dev = list_entry<device, &device::bus_list>(cur);
cur = cur->next;
if (dev->driver == nullptr) {
device_try_bind(dev, drv);
}
}
return 0;
}
void driver_unregister(device_driver* drv)
{
if (drv == nullptr || drv->bus == nullptr) {
return;
}
LockGuard g(drv->bus->lock);
/* Unbind every device bound to this driver. */
while (!drv->devices.is_empty()) {
list_node* first = drv->devices.next;
device* dev = list_entry<device, &device::driver_list>(first);
if (drv->remove != nullptr) {
drv->remove(dev);
}
list_del_init(&dev->driver_list);
dev->driver = nullptr;
}
list_del_init(&drv->bus_node);
}
|