Linux上probe流程理解

1.简介

  在实际开发中,我们通过配置设备树里面的compatible属性,在将这个platform_driver注册到系统platform总线上时, 通过compatible属性匹配时,就会自动调用probe函数,进行platform_driver的初始化工作。在probe之前,其实有一些操作过程已经默认被执行了, 其整体流程如下:

2.platform_device生成时机

  platform_device是自动在早期生成的。

2.1) 设备树解析时机

内核启动早期

  • bootloader传递dtb给内核
  • 内核入口->setup_arch->of_scan_flat_dt/unflatten_device_tree
  • 把dtb解析成内核device_node树 ##### 2.2) 变换成platform_device   在arch/xxx/kernel/setup.c 里面of_platform_populate阶段
  • a)遍历device_tree所有节点
  • b)对根总线下、没有父总线的节点(如:串口、gpio、i2c控制器、触摸屏控制器)
  • c)调用of_platform_device_create--->生成platform_device
  • d)在调用platform_device_add--->挂到platform_bus_type总线上。   备注:在内核启动很早阶段(init之前),设备树里面所有platform类型设备就已经 生成了platform_device,插入内核设备链表、sysfs。也就是driver注册前,所有platform_device都已经存在了。 ### 3.driver注册 ##### 1)驱动注册入口

    module_platform_driver(xxx_driver);
          platform_driver_register&xxx_driver);
          ->driver_register(&pdrv->driver)
              bus_add_driver
                  driver_attach(drv)
                      bus_for_each_dev(drv->bus,NULL,drv,__driver_attach)
    

    ##### 2)核心动作   遍历platform总线上所有的device。 bus_for_each_dev会把 platform_bus上所有 struct device(即所有platform_device) 逐个拿出来比对。

    __driver_attach(dev,drv)
              driver_match_device(drv,dev)
                  drv->bus->match(dev,drv)    //platform_match
    

    ##### 3)platform_match 匹配顺序   代码路径:driver/base/platform.c

    static 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);
    
          // 1. 优先:driver_override(强制绑定)
          if (pdev->driver_override)
              return !strcmp(pdev->driver_override, drv->name);
    
          // 2. 设备树:of_match_table 匹配 compatible
          //设备树compatible->of_match_table(最常用)
          if (of_driver_match_device(dev, drv))
              return 1;
    
          // 3. ACPI
          if (acpi_driver_match_device(dev, drv))
              return 1;
    
          // 4. platform_driver 的 id_table 匹配
          if (pdrv->id_table)
              return platform_match_id(pdrv->id_table, pdev) != NULL;
    
          // 5. 最后:name 完全相等匹配(旧方式)
          return !strcmp(dev_name(dev), drv->name);
      }
    

    ### 4.匹配成功   成功后,调用流程。

    __driver_attach 
              device_bind_driver
                  driver_probe_device
                      really_probe
                          pdrv->probe(pdev)
    

      匹配成功后,驱动核心driver core主动调用probe 开发者,只负责注册driver,剩下内核遍历、匹配、调用probe全部自动完成 这个probe是在进程上下文,不是中断上下文,不是内核线程。 在多设备时,按照deive在总线链表上的顺序匹配,逐个probe,先匹配到先probe。 没有匹配成功的driver注册成功(返回0)不会调用probe,这个driver就静静在系统里面,等待未来出现的device 设备:

  • platform_device 一直存在
  • 没有驱动绑定 /sys/devices/.../driver目录不存在
  • 不会有任何初始化,硬件存于默认/未管理状态 动态情况:
  • 新设备被加入总线(比如热插拔,模块创建设备)
  • 内核会再次扫描所有driver,尝试匹配并probe。 ### 5.汇总 platform_device:内核早期解析设备树时就全部建好并挂到 platform 总线。 platform_driver 注册时:内核在当前进程上下文,遍历总线所有 device,用 platform_match 按顺序匹配。 匹配成功 → 内核主动调用 probe(进程上下文);失败 → driver 待命,设备无驱动绑定。