inux 内核通过设备树配备驱动

1. Platform_device_register() 是注册平台设备的函数,它的实现实际上会调用 platform_device_add()
2.platform_device_add() 核心功能是将 platform_device 添加到平台总线中。

  1. 设置设备的总线类型

    • 将 pdev->dev.bus 设置为 &platform_bus_type,表示该设备属于 platform_bus 类型。
    • platform_bus_type 是一个全局变量,定义了 platform 总线的行为。
    struct bus_type platform_bus_type = { 
    .name = "platform", 
    .match = platform_match, // 用于设备与驱动匹配
    };
  2. 设置设备名字

    • 如果设备没有定义 release 回调函数,则调用 dev_set_name() 给设备设置一个名字(一般是 pdev->name)。
  3. 调用 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() 的完整流程如下:

  1. 检查设备结构体是否有效。
  2. 设置设备的层次关系(父设备、名字等)。
  3. 将设备的 kobject 添加到内核设备模型。
  4. 与总线关联,调用 bus_add_device()
  5. 自动匹配设备与驱动,调用 device_attach()
  6. 为设备创建用户空间属性接口(sysfs 文件)。
  7. 发送 KOBJ_ADD 事件,通知用户空间设备已添加。

通过这些步骤,设备被完整地注册到内核的设备模型中,并与总线和驱动程序建立了关联。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值