Skip to content

第一百三十九章:总线

合道期

涉及内核源码:

林小源沿着设备山脉的一条大路继续前行,路面上刻着各种总线的标志——PCI、USB、I2C、platform。每种标志的颜色不同,PCI 是深蓝色,USB 是白色,I2C 是绿色,platform 是橙色。

"总线到底是什么?"林小源问守山老者。

老者还没来得及回答,一个身穿深蓝色铠甲的中年人从 PCI 路口走了出来。他的铠甲上刻着一张巨大的匹配表——左边是设备列表,右边是驱动列表,中间是无数根连接线。

"我是总线。"中年人说,声音沉稳有力,"设备和驱动之间的纽带。没有我,设备永远找不到自己的驱动,驱动也永远找不到自己能控制的设备。"

"你怎么匹配的?"林小源问。

"每种总线有自己的匹配规则。"中年人指向 PCI 路口,"PCI 总线用 Vendor ID 和 Device ID 匹配——设备的身份证号跟驱动的 id_table 对上了,就算匹配成功。"他又指向 USB 路口,"USB 总线用 Vendor/Product ID。"指向 I2C 路口,"I2C 用设备地址。"最后指向 platform 路口,"platform 总线用设备树的 compatible 字符串。"

c
/*
 * 总线类型:
 *
 * PCI 总线:
 *   连接 CPU 和外设
 *   通过 Vendor/Device ID 匹配
 *
 * USB 总线:
 *   连接 USB 设备
 *   通过 Vendor/Product ID 匹配
 *
 * I2C 总线:
 *   低速设备
 *   通过设备地址匹配
 *
 * platform 总线:
 *   集成在 SoC 中的设备
 *   通过设备树匹配
 *
 * 总线的职责:
 *   - 管理设备和驱动的匹配
 *   - 提供设备枚举
 *   - 处理电源管理
 */

printf("=== 总线 — 连接设备和驱动 ===\n\n");

printf("总线类型:\n\n");

printf("PCI 总线:\n");
printf("  连接 CPU 和外设\n");
printf("  通过 Vendor/Device ID 匹配\n\n");

printf("USB 总线:\n");
printf("  连接 USB 设备\n");
printf("  通过 Vendor/Product ID 匹配\n\n");

printf("I2C 总线:\n");
printf("  低速设备\n");
printf("  通过设备地址匹配\n\n");

printf("platform 总线:\n");
printf("  集成在 SoC 中的设备\n");
printf("  通过设备树匹配\n\n");

printf("--- 总线的职责 ---\n");
printf("1. 匹配:\n");
printf("   设备注册时找驱动\n");
printf("   驱动注册时找设备\n\n");
printf("2. 枚举:\n");
printf("   扫描总线上的设备\n\n");
printf("3. 电源管理:\n");
printf("   管理设备电源状态\n\n");

printf("--- 匹配过程 ---\n");
printf("设备注册:\n");
printf("  device_register(dev)\n");
printf("  → bus_for_each_drv()\n");
printf("  → match(dev, drv)\n");
printf("  → probe(dev)\n\n");
printf("驱动注册:\n");
printf("  driver_register(drv)\n");
printf("  → bus_for_each_dev()\n");
printf("  → match(dev, drv)\n");
printf("  → probe(dev)\n");

"你说有四种总线——PCI、USB、I2C、platform。"林小源掰着手指,"它们有什么区别?为什么需要这么多总线?"

中年人笑了:"因为不同的设备有不同的连接方式。"

他指着 PCI 路口:"PCI 是高速总线,连接 CPU 和外设——网卡、显卡、RAID 控制器。这些设备性能要求高,需要高速的总线连接。"

指向 USB 路口:"USB 是通用接口,什么设备都能插——键盘、鼠标、U盘、摄像头。它的优势是通用性和热插拔。"

指向 I2C 路口:"I2C 是低速总线,只需要两根线——SDA 和 SCL。适合传感器、EEPROM、RTC 这些低速设备。引脚少,布线简单。"

最后指向 platform 路口:"platform 总线最特殊——它连接的设备不是插上去的,而是直接集成在 SoC 芯片里的。UART 控制器、I2C 控制器、GPIO 控制器——这些设备跟 CPU 在同一块芯片上,不需要外部总线。"

"所以 platform 总线其实不是一条物理总线?"

"对。"中年人点头,"platform 总线是逻辑上的总线。它的设备通过设备树描述,而不是通过物理扫描发现。这也是为什么 platform 设备需要用 compatible 字符串来匹配驱动。"

"每种总线的 函数不一样,"林小源说,"那总线本身是怎么注册的?"

"用 。"中年人说,"每种总线类型定义一个 结构体,里面有 等回调函数。然后调用 注册到内核。"

他伸手在空中画了一个结构体:

c
struct bus_type {
    const char *name;
    int (*match)(struct device *dev, struct device_driver *drv);
    int (*probe)(struct device *dev);
    void (*remove)(struct device *dev);
    // ...
};

"match 是核心。"中年人说,"当设备或驱动注册时,总线调用 match 来判断它们是否匹配。PCI 的 match 比较 Vendor/Device ID,platform 的 match 比较 compatible 字符串。match 返回 1 表示匹配成功,返回 0 表示不匹配。"

"匹配成功后呢?"

"调用 probe。"中年人说,"probe 是驱动的初始化入口——映射寄存器、分配资源、注册中断。匹配只是'认识',probe 才是'开始工作'。"

林小源看着那四种总线的路口,心中渐渐清晰:总线是设备模型的中枢神经——它定义了匹配规则,管理着设备和驱动的配对,是整个设备模型能够自动运转的关键。


道藏笔记

内核启示

总线连接设备和驱动。

总线类型:

  • PCI — CPU 和外设
  • USB — USB 设备
  • I2C — 低速设备
  • platform — SoC 集成设备

总线的职责:

  • 匹配 — 设备和驱动的匹配
  • 枚举 — 扫描设备
  • 电源管理 — 管理电源状态

总线是"纽带"——连接设备和驱动。


破关试炼

总线之试

驱动世界要登记一条新的总线时,本章提到的注册函数是什么?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道