一、设备驱动的重要知识点
- 结构体:
device_driver - 结构体:
driver_attribute - 驱动的注册接口:
driver_register - 驱动属性文件:
driver_create_file
二、驱动注册过程分析 driver_register
文件位置
drivers/base/driver.c

c
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
// 检查总线是否已初始化
if (!drv->bus->p) {
pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n",
drv->name, drv->bus->name);
return -EINVAL;
}
// 检查驱动程序的方法是否需要更新
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
// 检查驱动程序是否已被注册
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv); // 将驱动程序添加到总线
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups); // 添加驱动程序的组属性
if (ret) {
bus_remove_driver(drv); // 移除已添加的驱动程序
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD); // 发送内核对象事件,通知驱动程序添加成功
return ret;
}
EXPORT_SYMBOL_GPL(driver_register);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
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
driver_register 函数的作用是把设备驱动程序添加到对应的总线中,具体流程如下:
- 首先,它会检查总线是否已经正常初始化。如果驱动关联的总线内部指针为"空",说明总线还没准备好,就会报错并返回"参数无效"(
-EINVAL)。 - 接着,它会检查驱动的方法是否需要升级。如果发现驱动和总线的 probe/remove/shutdown 方法同时存在冲突,就会提示开发者需要更新驱动代码,用总线提供的标准方法代替。
- 然后,它会检查是否已经有同名驱动被注册过。通过查找总线中的驱动列表,如果发现重复名称,就会报错并返回"设备忙"(
-EBUSY)。 - 确认无误后,函数会正式将驱动添加到总线中。如果这一步失败,比如资源不足,就会直接返回对应的错误码。
- 成功添加后,会继续注册驱动的属性接口。如果属性注册失败,就会立即撤销之前的操作,把驱动从总线中移除并返回错误。
- 最后,系统会发送一个事件通知,告诉其他模块该驱动已经成功加入系统。
形象理解
整个过程就像给设备驱动办"入网手续":先检查材料是否齐全,再确认没有重复申请,最后完成注册并通知相关部门。每个步骤都会在出错时及时终止流程并反馈具体问题。
三、bus_add_driver
在上面代码中,调用 bus_add_driver 函数将驱动程序添加到总线。我们来详细分析下 bus_add_driver 函数。
文件位置
drivers/base/bus.c
c
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
// 获取总线对象
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
// 分配并初始化驱动程序私有数据
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
// 初始化并添加驱动程序的内核对象
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
// 将驱动程序添加到总线的驱动程序列表
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) { // 默认就是 1
error = driver_attach(drv);
if (error)
goto out_unregister;
}
// 将驱动程序添加到模块
module_add_driver(drv->owner, drv);
// 创建驱动程序的 uevent 属性文件
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n", __func__, drv->name);
}
// 添加驱动程序的组属性
error = driver_add_groups(drv, bus->drv_groups);
if (error) {
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n", __func__, drv->name);
}
// 如果驱动程序不禁止绑定属性文件,则添加绑定属性文件
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
if (error) {
printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name);
}
}
return 0;
out_unregister:
kobject_put(&priv->kobj);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}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
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
1、driver_attach
在上述函数中,使用 driver_attach 函数来探测设备,我们进一步分析下 driver_attach 函数。
文件位置
base/dd.c
c
/**
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*/
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
EXPORT_SYMBOL_GPL(driver_attach);1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
bus_for_each_dev 函数实现如下所示:
文件位置
base/bus.c
c
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while (!error && (dev = next_device(&i)))
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
参数说明
- 总线(bus):要检查的设备总线
- 起始设备(start):从哪个设备开始检查。如果设为"空",就从第一个设备开始
- 附加数据(data):传递给操作函数的额外信息
- 操作函数(fn):要执行的核心操作,需要接收设备和附加数据,返回错误代码
c
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
int ret;
ret = driver_match_device(drv, dev);
if (ret == 0) {
return 0; // 没有匹配
} else if (ret == -EPROBE_DEFER) {
dev_dbg(dev, "Device match requests probe deferral\n");
driver_deferred_probe_add(dev);
} else if (ret < 0) {
dev_dbg(dev, "Bus failed to match device: %d", ret);
return ret;
}
if (driver_allows_async_probing(drv)) {
dev_dbg(dev, "probing driver %s asynchronously\n", drv->name);
device_lock(dev);
if (!dev->driver) {
get_device(dev);
dev->p->async_driver = drv;
async_schedule(__driver_attach_async_helper, dev);
}
device_unlock(dev);
return 0;
}
device_driver_attach(drv, dev); // 同步探测设备并绑定驱动程序
return 0;
}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
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
driver_match_device 函数:
c
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}1
2
3
4
5
2
3
4
5
函数解析
这个 driver_match_device 函数用来判断设备和驱动是否匹配。它的工作流程如下:
检查总线是否有匹配函数
- 如果总线有这个规则:就用这个规则来对比设备和驱动,看看是否匹配。
- 如果总线没提供这个规则:直接认为设备和驱动是匹配的(默认返回成功)。
执行匹配判断
- 如果总线的
match函数返回了 "0"(不匹配):整个函数直接返回 0。 - 如果返回了非零值(比如 1,表示匹配):函数返回 1,表示匹配成功。
- 如果总线的
后续操作 当设备和驱动匹配成功后,会继续执行
device_driver_attach函数,完成驱动和设备的绑定。
c
int device_driver_attach(struct device_driver *drv, struct device *dev)
{
int ret = 0;
__device_driver_lock(dev, dev->parent);
if (!dev->p->dead && !dev->driver)
ret = driver_probe_device(drv, dev);
__device_driver_unlock(dev, dev->parent);
return ret;
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
driver_probe_device 函数:
c
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
pm_runtime_get_suppliers(dev);
if (dev->parent)
pm_runtime_get_sync(dev->parent);
pm_runtime_barrier(dev);
if (initcall_debug)
ret = really_probe_debug(dev, drv);
else
ret = really_probe(dev, drv);
pm_request_idle(dev);
if (dev->parent)
pm_runtime_put(dev->parent);
pm_runtime_put_suppliers(dev);
return ret;
}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
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
really_probe 函数核心逻辑:
c
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = -EPROBE_DEFER;
int local_trigger_count = atomic_read(&deferred_trigger_count);
bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
!drv->suppress_bind_attrs;
if (defer_all_probes) {
dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
return ret;
}
ret = device_links_check_suppliers(dev);
if (ret == -EPROBE_DEFER)
driver_deferred_probe_add_trigger(dev, local_trigger_count);
if (ret)
return ret;
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
re_probe:
dev->driver = drv;
ret = pinctrl_bind_pins(dev);
if (ret)
goto pinctrl_bind_failed;
ret = dma_configure(dev);
if (ret)
goto probe_failed;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev));
goto probe_failed;
}
if (dev->pm_domain && dev->pm_domain->activate) {
ret = dev->pm_domain->activate(dev);
if (ret)
goto probe_failed;
}
// 总线优先于驱动的 probe
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
pinctrl_init_done(dev);
if (dev->pm_domain && dev->pm_domain->sync)
dev->pm_domain->sync(dev);
driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
probe_failed:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
pinctrl_bind_failed:
device_links_no_driver(dev);
devres_release_all(dev);
dma_deconfigure(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
if (dev->pm_domain && dev->pm_domain->dismiss)
dev->pm_domain->dismiss(dev);
pm_runtime_reinit(dev);
// ret 处理省略
done:
atomic_dec(&probe_count);
wake_up_all(&probe_waitqueue);
return ret;
}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
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