平台总线的结构及框架分析

  • 平台总线是linux系统虚拟出来的一种总线,是一个内核子系统,负责管理 platform_device(硬件描述)和 platform_driver(驱动代码),使它们先分离.后搭档

平台总线(Platform Bus)

  • 平台总线(Platform Bus)是内核的一条“虚拟”总线。它不像 PCI、USB 那样是物理上存在的总线,而是为了解决一类特殊设备的驱动问题而设计的 软件机制。这类设备通常是 SoC (System on Chip) 芯片内部集成的、不可被自动识别的外设,比如 I2C 控制器、SPI 控制器、GPIO 控制器等。

platform_device 与总线和外设的交互:

  • 系统启动,内核解析设备树。
  • 内核创建platform-bus……
  • 内核在设备树里读到一段描述 I2C 控制器硬件的节点(包含了寄存器地址、中断号,以及最重要的 compatible = “vendor,i2c-controller-v1”;)。
  • 内核根据这个节点,创建并注册一个 platform_device 到平台总线。
  • I2C 控制器驱动(platform_driver)在加载时,会告诉平台总线:“我能处理 compatible 是 “vendor,i2c-controller-v1” 的设备”。
  • 平台总线看到两者匹配,于是调用 I2C 控制器驱动的 .probe 函数。
  • 在 I2C 控制器驱动的 .probe 函数中,驱动程序会执行一系列初始化操作,其中最重要的一步是调用 i2c_add_adapter() 或 i2c_add_numbered_adapter()。这个函数调用,才是在内核中“建立”或“注册”了一条 I2C 总线(即一个 i2c_adapter)。这条逻辑上的总线就代表了那条物理的 I2C 总线。内核里的 i2c_adapter 就是物理 I2C 总线在软件层面的抽象。
  • 设备间交互
  • “其他设备驱动”(比如 I2C 温度传感器驱动)不直接调用 I2C 控制器驱动里的 ops。这是一个分层概念。
    - 正确的交互方式:
    - I2C 控制器驱动把它实现底层 I/O 操作的 ops(struct i2c_algorithm)注册给了 I2C 总线核心。
    - I2C 温度传感器驱动想通信时,它调用的是 I2C 总线核心提供的标准、统一的 API,如 i2c_master_send() 和 i2c_master_recv()。
    - I2C 总线核心在收到这些 API 调用后,会找到对应的 i2c_adapter,然后去调用这个 adapter 在注册时提供的 ops 里的具体函数,最终由 I2C 控制器驱动的代码来操作硬件。

platform_device 注册流程代码详细分析

  • 我们最常见的platform_driver_register函数,这其实是一个宏定义,属于函数wrap,该函数设置了驱动的总线,归属权之后,之后进入了driver_register函数。
    • #define platform_driver_register(drv) __platform_driver_register(drv, THIS_MODULE)
  • driver_register 中重点函数是 bus_add_driver,这个函数将驱动挂载到总线上,然后进行匹配。
    • int bus_add_driver(struct device_driver *drv)
      {
          struct subsys_private *sp = bus_to_subsys(drv->bus);
      
          ...
          if (sp->drivers_autoprobe) {
              error = driver_attach(drv);
          ...
      }
      int driver_attach(const struct device_driver *drv)
      {
          /* The (void *) will be put back to const * in __driver_attach() */
          return bus_for_each_dev(drv->bus, NULL, (void *)drv, __driver_attach);
      }
      EXPORT_SYMBOL_GPL(driver_attach);
      static int __driver_attach(struct device *dev, void *data)
      {
          const struct device_driver *drv = data;
          bool async = false;
          int ret;
      
          /*
           * Lock device and try to bind to it. We drop the error
           * here and always return 0, because we need to keep trying
           * to bind to devices and some drivers will return an error
           * simply if it didn't support the device.
           *
           * driver_probe_device() will spit a warning if there
           * is an error.
           */
      
          ret = driver_match_device(drv, dev);
          if (ret == 0) {
              /* no match */
              return 0;
          } else if (ret == -EPROBE_DEFER) {
              dev_dbg(dev, "Device match requests probe deferral\n");
              dev->can_match = true;
              driver_deferred_probe_add(dev);
              /*
               * Driver could not match with device, but may match with
               * another device on the bus.
               */
              return 0;
          } else if (ret < 0) {
              dev_dbg(dev, "Bus failed to match device: %d\n", ret);
              /*
               * Driver could not match with device, but may match with
               * another device on the bus.
               */
              return 0;
          } /* ret > 0 means positive match */
      
          ...
      
          __device_driver_lock(dev, dev->parent);
          driver_probe_device(drv, dev);
          __device_driver_unlock(dev, dev->parent);
      
          return 0;
      }
      // 这里就是判断总线有没有实现自己的match函数,如果没有实现,默认返回1,也就是匹配成功。
      static inline int driver_match_device(const struct device_driver *drv,
                            struct device *dev)
      {
          return drv->bus->match ? drv->bus->match(dev, drv) : 1;
      }
      // platform_bus的结构体是有实现自己的一套match函数的。
      static int platform_match(struct device *dev, const struct device_driver *drv)
      {
          struct platform_device *pdev = to_platform_device(dev);
          struct platform_driver *pdrv = to_platform_driver(drv);
      
          /* When driver_override is set, only bind to the matching driver */
          if (pdev->driver_override)
              return !strcmp(pdev->driver_override, drv->name);
      
          /* Attempt an OF style match first */
          if (of_driver_match_device(dev, drv))
              return 1;
      
          /* Then try ACPI style match */
          if (acpi_driver_match_device(dev, drv))
              return 1;
      
          /* Then try to match against the id table */
          if (pdrv->id_table)
              return platform_match_id(pdrv->id_table, pdev) != NULL;
      
          /* fall-back to driver name match */
          return (strcmp(pdev->name, drv->name) == 0);
      }
      // 首先将通用的device和driver都转换成platform下的设备和驱动。
      // 然后再进行匹配,如果匹配成功,则返回1。
      // 回到__driver_attach函数中,最后调用了driver_probe_device函数。
      // 看名字就知道这个函数应该就跟probe有关了。
      static int driver_probe_device(const struct device_driver *drv, struct device *dev)
      {
          int trigger_count = atomic_read(&deferred_trigger_count);
          int ret;
      
          atomic_inc(&probe_count);
          ret = __driver_probe_device(drv, dev);
          if (ret == -EPROBE_DEFER || ret == EPROBE_DEFER) {
              driver_deferred_probe_add(dev);
      
              /*
               * Did a trigger occur while probing? Need to re-trigger if yes
               */
              if (trigger_count != atomic_read(&deferred_trigger_count) &&
                  !defer_all_probes)
                  driver_deferred_probe_trigger();
          }
          atomic_dec(&probe_count);
          wake_up_all(&probe_waitqueue);
          return ret;
      }
      static int __driver_probe_device(const struct device_driver *drv, struct device *dev)
      {
          int ret = 0;
          
          ...
          if (initcall_debug)
              ret = really_probe_debug(dev, drv);
          else
              ret = really_probe(dev, drv);
          ...
      }
      static int really_probe(struct device *dev, const struct device_driver *drv)
      {
      ...
      re_probe:
        device_set_driver(dev, drv);
      
        /* If using pinctrl, bind pins now before probing */
        ret = pinctrl_bind_pins(dev); // 设置设备所需的引脚
        if (ret)
          goto pinctrl_bind_failed;
      ...
      
          ret = call_driver_probe(dev, drv);
          if (ret) {
              /*
               * If fw_devlink_best_effort is active (denoted by -EAGAIN), the
               * device might actually probe properly once some of its missing
               * suppliers have probed. So, treat this as if the driver
               * returned -EPROBE_DEFER.
               */
              if (link_ret == -EAGAIN)
                  ret = -EPROBE_DEFER;
      
              /*
               * Return probe errors as positive values so that the callers
               * can distinguish them from other errors.
               */
              ret = -ret;
              goto probe_failed;
          }
      // call_driver_probe了
      static int call_driver_probe(struct device *dev, const struct device_driver *drv)
      {
          int ret = 0;
      
          if (dev->bus->probe)
              ret = dev->bus->probe(dev);
          else if (drv->probe)
              ret = drv->probe(dev);
      
          switch (ret) {
          case 0:
              break;
          case -EPROBE_DEFER:
              /* Driver requested deferred probing */
              dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
              break;
          case -ENODEV:
          case -ENXIO:
              dev_dbg(dev, "probe with driver %s rejects match %d\n",
                  drv->name, ret);
              break;
          default:
              /* driver matched but the probe failed */
              dev_err(dev, "probe with driver %s failed with error %d\n",
                  drv->name, ret);
              break;
          }
      
          return ret;
      }
      ...
      }
      // bus->probe也就是platform总线的probe
      static int platform_probe(struct device *_dev)
      {
          struct platform_driver *drv = to_platform_driver(_dev->driver);
          struct platform_device *dev = to_platform_device(_dev);
          int ret;
      
          ...
      
          if (drv->probe) {
              ret = drv->probe(dev);
          }
          ...
      }
      // 整体调用过程
      __platform_driver_register
        => driver_register
          => bus_add_driver
            => driver_attach
              => __driver_attach
                => driver_match_device => bus->match => platform_match
                  => driver_probe_device
                    => __driver_probe_device
                        => really_probe
                          => call_driver_probe
                            => bus->probe => platform_probe
                              => drv->probe
      __platform_driver_register  // 【起点】你写的驱动开始向内核报到
        => driver_register        // 通用驱动注册,把你的驱动包成一个通用的 struct device_driver
          => bus_add_driver       // 【找组织】把驱动挂到对应的总线上(这里是 platform_bus)
            => driver_attach      // 【连连看】开始在总线上寻找匹配的硬件设备(device)
              => __driver_attach  // 对总线上每一个还没驱动的设备,都调用一次这个函数试试
                
                /* 第一关:相亲匹配 (Match) */
                => driver_match_device 
                  => bus->match => platform_match // 【对暗号】对比设备树 compatible 字符串或 ID 
                
                /* 第二关:准备上岗 (Probe) */
                => driver_probe_device     // 匹配成功了!准备正式绑定设备和驱动
                  => __driver_probe_device // 检查设备是否已经挂载、是否需要延迟加载 (Deferred Probe)
                    => really_probe        // 【动真格】这是内核确定要调用 Probe 的最后防线
                      
                      => call_driver_probe // 准备好环境变量和资源,正式发起调用
                        
                        /* 第三关:总线中转 */
                        => bus->probe => platform_probe // 【中间人】总线先做预处理(如电源管理、时钟启动)
                          
                          /* 终点:你的代码 */
                          => drv->probe    // 【最终调用】跳进你写的那个 xxx_probe 函数,开始初始化硬件
      

平台总线的结构及框架分析

https://goko-son626.github.io/post/Platform-bus.html

作者

GoKo Mell

发布于

2024-06-07

更新于

2026-03-09

许可协议

评论

:D 一言句子获取中...