1. Platform_device_register()
是注册平台设备的函数,它的实现实际上会调用 platform_device_add()
:
2.platform_device_add()
核心功能是将 platform_device
添加到平台总线中。
-
设置设备的总线类型:
- 将
pdev->dev.bus
设置为&platform_bus_type
,表示该设备属于platform_bus
类型。 platform_bus_type
是一个全局变量,定义了 platform 总线的行为。
struct bus_type platform_bus_type = { .name = "platform", .match = platform_match, // 用于设备与驱动匹配 };
- 将
-
设置设备名字:
- 如果设备没有定义
release
回调函数,则调用dev_set_name()
给设备设置一个名字(一般是pdev->name
)。
- 如果设备没有定义
-
调用
device_add(&pdev->dev)
:- 最关键的步骤:将设备添加到设备模型中,建立与内核设备模型的关联。
3. device_add()
device_add()
是设备模型的核心函数,用于将设备注册到内核的设备层。
4. 总线与设备的关联
当调用 device_add()
时,设备会被挂到总线 platform_bus
下:
pdev->dev.bus = &platform_bus_type
表示设备属于platform_bus
。device_add()
会调用bus_add_device()
将设备挂到总线。- 在
platform_bus
的结构中定义了match
函数,用于匹配设备和驱动。
device_add()
的主要职责是: - 将设备注册到内核的设备模型中,建立设备的层次结构(如父子关系)。
- 将设备与所属总线关联,触发设备与驱动的匹配流程。
- 为设备创建相关的用户空间接口(如
sysfs
文件)。 - 通知用户空间(如
udev
)有新设备被添加。
e. 自动匹配设备与驱动
bus_add_device()
内部会调用 device_attach()
,触发设备与驱动的匹配流程:
C
int bus_add_device(struct device *dev) { struct bus_type *bus = dev->bus; int error = 0; // 自动驱动匹配 if (bus->p->drivers_autoprobe) { error = device_attach(dev); // 关键步骤 } return error; }
device_attach()
device_attach()
是设备模型中用于尝试匹配设备和驱动的函数。- 它会遍历总线上的所有驱动,调用驱动的
match()
函数检查是否与设备匹配。
关键代码:
C
int device_attach(struct device *dev) { return __device_attach(dev, false); } static int __device_attach(struct device *dev, bool allow_async) { struct bus_type *bus = dev->bus; struct device_driver *drv; // 遍历总线上的所有驱动 if (bus && bus->match) { list_for_each_entry(drv, &bus->p->drivers_list, p->drivers_list) { if (bus->match(dev, drv)) { // 匹配设备与驱动 ret = driver_probe_device(drv, dev); // 绑定驱动到设备 break; } } } return ret; }
驱动匹配逻辑
- 总线提供
match()
函数,用来匹配设备与驱动。 - 对于
platform_bus
,匹配逻辑通常是设备名字和驱动名字是否相同。
匹配函数:
C
int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); // 匹配设备名字和驱动名字 return strcmp(pdev->name, pdrv->driver.name) == 0; }
如果匹配成功,就会调用 driver_probe_device()
,将驱动绑定到设备。
f. 创建用户空间接口
C
ret = device_add_groups(dev, dev->groups); if (ret) goto Error;
device_add_groups()
:- 为设备创建相关的属性组(
sysfs
文件)。 - 用户空间可以通过
sysfs
访问设备的属性。
- 为设备创建相关的属性组(
g. 通知用户空间
C
kobject_uevent(&dev->kobj, KOBJ_ADD);
kobject_uevent()
:- 向用户空间发送
KOBJ_ADD
事件,通知设备被添加。 - 用户空间工具(如
udev
)可以捕获这个事件,进行设备的管理和初始化。
- 向用户空间发送
4. 总结流程
device_add()
的完整流程如下:
- 检查设备结构体是否有效。
- 设置设备的层次关系(父设备、名字等)。
- 将设备的
kobject
添加到内核设备模型。 - 与总线关联,调用
bus_add_device()
。 - 自动匹配设备与驱动,调用
device_attach()
。 - 为设备创建用户空间属性接口(
sysfs
文件)。 - 发送
KOBJ_ADD
事件,通知用户空间设备已添加。
通过这些步骤,设备被完整地注册到内核的设备模型中,并与总线和驱动程序建立了关联。