当前位置: 首页 > news >正文

Linux总线,设备和驱动关系以及匹配机制解析

在 Linux 内核中,总线(Bus)、设备(Device)和驱动(Driver) 构成了设备模型的核心,它们之间的关系以及匹配机制是实现硬件抽象、设备发现和驱动加载的关键。其核心思想是 “分离”“基于约定的匹配”

核心关系:

  1. 总线(Bus):

    • 角色: 充当媒介管理者
    • 职责:
      • 定义一种连接设备的方式(如 PCI、USB、I2C、SPI、平台总线等)。
      • 提供一组标准操作struct bus_type),用于枚举、探测、管理挂载在其上的设备和驱动。
      • 维护两个重要的内核链表:设备链表驱动链表(所有注册到该总线类型的设备和驱动都会被分别加入这些链表)。
      • 实现设备与驱动的匹配逻辑(这是最关键的功能)。
      • 当新设备添加或新驱动注册时,负责在各自的链表上进行扫描匹配
      • 提供设备的热插拔事件通知机制。
  2. 设备(Device):

    • 角色: 代表一个物理或虚拟的硬件实体
    • 职责:
      • 包含描述该硬件特征的信息(struct device 或更具体的如 struct pci_dev, struct usb_device)。
      • 这些信息是匹配的关键依据,通常包括:
        • 设备标识符: Vendor ID, Device ID, Subsystem ID, Class Code (PCI/USB), 兼容字符串 (设备树/ACPI)。
        • 资源信息: I/O 端口地址、内存映射地址(MMIO)、中断号(IRQ)、DMA 通道等。
      • 通过 device_register() 或总线特定的注册函数(如 pci_device_register(), platform_device_register()向所属的总线注册自己
      • 当成功匹配到一个驱动后,会被“绑定”到该驱动。
  3. 驱动(Driver):

    • 角色: 包含控制特定类型设备的代码。
    • 职责:
      • 实现设备的初始化、配置、数据传输、电源管理、中断处理等操作(struct device_driver 或更具体的如 struct pci_driver, struct platform_driver)。
      • 声明它能支持哪些设备。这是通过一个设备 ID 表id_table)或兼容性字符串列表of_match_table, acpi_match_table)来实现的。
      • 包含一个核心的 probe() 函数。当总线匹配到一个设备和该驱动时,总线会调用驱动的 probe() 函数。probe() 负责:
        • 检查设备是否真的是该驱动能控制的(二次验证)。
        • 分配驱动特定的数据结构。
        • 初始化硬件(配置寄存器、申请资源 IRQ, IO, DMA)。
        • 注册设备到内核框架(如网络设备注册 netif_register(),块设备注册 blk_register(),字符设备注册 cdev_add() 等)。
      • 包含 remove() 函数(设备断开或驱动卸载时调用)以及其他可选函数(suspend, resume, shutdown 等)。
      • 通过 driver_register() 或总线特定的注册函数(如 pci_driver_register(), platform_driver_register()向所属的总线注册自己

总结关系图:

                   +---------------------+|        Bus          | <--- (管理)| (e.g., pci_bus_type,|      | 维护设备列表|   platform_bus_type)|      | 维护驱动列表+----------+----------+      | 实现匹配逻辑|                 |+------------------+-----------------+|                                   |
+----------v----------+             +----------v----------+
|      Device         |             |      Driver         |
| (struct device,     |             | (struct device_driver,|
|  pci_dev, etc.)     |             |  pci_driver, etc.)   |
| - Vendor/Device ID  | <---(匹配)--| - id_table          |
| - Resources (IRQ,   |             | - probe() function  |
|   MMIO)             |             | - remove() function |
| - Compatible strings|             +---------------------+
+---------------------+

驱动和设备的匹配机制:

匹配过程是总线类型(struct bus_type)的核心职责,由其 .match() 方法(通常是 bus_type.match)实现。匹配发生在以下两种主要场景:

  1. 新设备注册: 当一个设备(dev)向总线注册时:

    • 总线会遍历其驱动链表上的所有已注册驱动(drv)。
    • 对每个驱动 drv,调用总线类型的 .match(dev, drv) 方法。
    • 如果 .match() 返回成功(非零),表示找到一个匹配的驱动。
    • 总线随后会尝试将设备 dev 绑定到这个驱动 drv(通常会异步调度执行驱动的 probe() 函数)。
  2. 新驱动注册: 当一个驱动(drv)向总线注册时:

    • 总线会遍历其设备链表上的所有已注册设备(dev)。
    • 对每个设备 dev,调用总线类型的 .match(dev, drv) 方法。
    • 如果 .match() 返回成功(非零),表示找到一个匹配的设备。
    • 总线随后会尝试将设备 dev 绑定到这个新注册的驱动 drv(调用驱动的 probe())。

.match() 方法如何工作?

.match() 方法的具体实现取决于总线类型。以下是常见总线匹配方式的原理:

  1. 基于 ID Table 的精确匹配 (PCI, USB 等):

    • 驱动定义一个静态数组 id_table(如 struct pci_device_id mydrv_pci_ids[]struct usb_device_id mydrv_usb_ids[])。
    • 表中每一项包含驱动支持的设备的精确标识符(Vendor ID, Device ID, Subvendor ID, Subdevice ID, Class, Class Mask 等)。
    • 总线(如 pci_bus_type.matchpci_match_device)的工作:
      • 提取设备 dev 的标识符(从 PCI 配置空间读取)。
      • 遍历驱动 drvid_table
      • 将设备标识符与 id_table 中的每一项进行比较(通常支持掩码匹配)。
      • 如果找到一项完全匹配(考虑掩码),.match() 返回成功(匹配项的指针,非 NULL)。
    • 关键点: 匹配基于精确的数字 ID。
  2. 基于兼容字符串的模糊匹配 (设备树 - DT, ACPI, 平台设备):

    • 设备端: 设备(通常是 platform_device 或通过 DT/ACPI 描述的设备)在其属性中声明一个或多个 compatible 字符串。这些字符串描述了设备的硬件兼容性(如 "vendor,chip-model", "generic-name")。
    • 驱动端: 驱动定义一个 of_match_table(用于 DT)或 acpi_match_table(用于 ACPI),其中包含一个或多个 of_device_id / acpi_device_id 结构体。每个结构体包含一个或多个该驱动支持的 compatible 字符串。
    • 总线(如 platform_bus_type.match 通常最终调用 of_driver_match_deviceacpi_driver_match_device)的工作:
      • 获取设备 devcompatible 字符串列表。
      • 遍历驱动 drvof_match_table / acpi_match_table
      • 对于表中的每一项,将其包含的 compatible 字符串与设备的所有 compatible 字符串依次比较(从最具体到最通用)。
      • 如果找到完全相同的字符串.match() 返回成功(匹配项的指针)。
    • 关键点: 匹配基于字符串比较。驱动可以声明支持多个兼容字符串(按优先级),设备也可以声明多个兼容字符串(从最具体到最通用)。第一个找到的完全匹配字符串决定了匹配。这提供了很大的灵活性,允许一个驱动支持多个相似硬件,或者一个设备可以被更通用的驱动支持。
  3. 名称匹配 (较旧/简单的平台设备):

    • 设备在注册时指定一个名称(platform_device.name)。
    • 驱动在注册时也指定一个名称(platform_driver.driver.name)。
    • 总线(platform_bus_type.match 的简单实现)直接比较 dev->namedrv->driver.name。如果相同,则匹配。
    • 这种方式不够灵活,现在更推荐使用兼容字符串匹配。
  4. ACPI ID 匹配 (ACPI):

    • 类似于 ID Table 匹配,但使用 ACPI 定义的硬件标识符 (HID, CID, UID 等)。
    • 驱动定义 acpi_match_table 包含支持的 ACPI 设备 ID。
    • 总线匹配函数比较设备的 ACPI ID 和驱动支持的 ID。

匹配成功后的绑定 (probe):

  • 一旦总线 .match() 方法确认设备和驱动匹配,总线核心会调用驱动的 probe() 函数,并将匹配的设备作为参数传递给它。
  • probe() 函数是驱动初始化的核心:
    • 它执行硬件特定的初始化(检查设备是否真的存在且功能正常 - 二次确认)。
    • 申请所需的资源(IRQ, I/O 内存, DMA 缓冲区)。
    • 初始化设备硬件(配置寄存器)。
    • 将设备注册到相应的内核子系统(如网络栈、输入子系统、块层、字符设备框架等)。
    • 通常会将一个指向驱动特定数据结构的指针存储在 dev->driver_data 中,以便后续驱动函数(如 remove, interrupt)使用。
  • 如果 probe() 成功返回 (0),设备和驱动就被认为是绑定在一起了。
  • 如果 probe() 失败(返回错误码),绑定过程失败,设备会回到未绑定状态,总线可能会继续尝试匹配其他驱动(如果该设备支持多个驱动)。

关键特性:

  • 动态性: 设备和驱动可以在系统运行的任何时候注册(热插拔、模块加载)。
  • 延迟匹配/绑定: 设备和驱动可以按任意顺序注册。如果设备先注册但当时没有匹配的驱动,它会被放在总线的设备链表上等待。当匹配的驱动稍后注册时,总线会自动触发匹配和绑定。反之亦然(驱动先注册,等待设备)。
  • 多对一支持: 一个驱动通常可以支持多个设备(只要它们符合驱动 id_tablecompatible 字符串的定义)。
  • 抽象层: 总线层将设备发现的细节(如扫描 PCI 配置空间、解析设备树)与驱动核心逻辑隔离开。驱动只需要关心它支持什么设备以及如何操作它们。

总结:

Linux 设备模型通过总线、设备、驱动三者的分离,实现了硬件的抽象和动态管理。总线是核心协调者,它维护设备和驱动的列表,并负责实现匹配逻辑。匹配主要基于设备提供的标识信息(精确 ID 或兼容字符串)与驱动声明的支持信息id_tableof_match_table / acpi_match_table)之间的比较。匹配成功后,驱动的 probe() 函数被调用,完成设备的初始化和向内核子系统的注册,最终使设备可用。这套机制是 Linux 支持海量硬件并实现热插拔和模块化驱动的基石。

http://www.lryc.cn/news/613531.html

相关文章:

  • vue打包号的文件如何快速查找文件打包后的位置
  • Redis 编译错误:缺少静态库文件,如何解决?
  • 在NVIDIA Orin上用TensorRT对YOLO12进行多路加速并行推理时内存泄漏 (中)
  • PoE延长器——突破网络距离限制
  • 数据赋能(386)——数据挖掘——迭代过程
  • PyCharm 图标 c、m、f、F、v、p 的含义
  • 科技云报到:热链路革命:阿卡 CRM 的 GTM 定位突围
  • 健永科技工位RFID读卡器实现生产流水线物料跟踪与柔性化升级
  • 美食广场: 城市胃的便利店
  • MySQL UNION 操作符详细说明
  • 如何在GPU上安装使用Docker
  • SupChains团队:订单生产型供应链销量预测建模案例分享(六)
  • 容器之王--Docker的部署及基本操作演练
  • vLLM:彻底改变大型语言模型推理延迟和吞吐量
  • Aurora MySQL 8.0 性能分析账号创建完整指南
  • 神经网络入门指南:从零理解 PyTorch 的核心思想
  • 跨境电商增长突围:多维变局下的战略重构与技术赋能
  • 从“数字网格”到“空中交警” :星图低空云如何重构低空管理?
  • 鸿蒙 - 分享功能
  • MySql MVCC的原理总结
  • 软件加密工具-DSProtector使用说明
  • 2025年华数杯C题超详细解题思路
  • 旅游mcp配置(1)
  • 多场景两阶段分布式鲁棒优化模型、数据驱动的综合能源系统
  • pybind11 的应用
  • C语言feof函数详解:文件末尾检测的实用工具
  • 【华为机试】113. 路径总和 II
  • 计算机网络1-5:计算机网络的性能指标
  • CSS--:root指定变量,其他元素引用
  • [安卓按键精灵开发工具]本地数据库的初步学习