[笔记]Linux平台设备与驱动匹配创作机制详解

0:前言

        在最近项目中涉及到了linux的驱动层与应用层之间的交互,在项目过程中发现对这两个层级之间应该怎么相互交互还不胜了解,因此本片笔记对这个驱动层与应用层之间的相互交互进行记录学习;在Linux内核开发中,设备树(Device Tree,DTS)与Platform驱动之间的匹配是一个关键机制,它实现了硬件描述与驱动代码的解耦。

该篇笔记手机通过学习下列文章进行学习的

        1:《MX6U嵌入式Linux驱动开发指南V1.71》

 1:核心概念关系

        在Linux内核中,总线(Bus)、设备(Device)和驱动(Driver) 是设备模型的核心概念,而设备树(Device Tree, DTS) 是一种硬件描述机制。

        1.1:总线(Bus)、设备(Device)与驱动(Driver)的关系

  • 总线(Bus)

    • 一种抽象层,负责管理设备和驱动的匹配逻辑。

    • 例如:platform_bus_type(虚拟总线)、PCI_bus_type(物理总线)。

    • 功能

      • 注册设备和驱动。

      • 触发设备和驱动的匹配(通过match()函数)。

      • 管理设备和驱动的生命周期。

  • 设备(Device)

    • 表示硬件设备的内核对象(如struct platform_device)。

    • 包含硬件资源(地址、中断等)和元数据(名称、ID等)。

  • 驱动(Driver)

    • 实现设备操作的内核模块(如struct platform_driver)。

    • 定义设备匹配规则(如compatible字符串)和操作接口(如probe()/remove())。

匹配流程:

设备注册 → 总线发现设备 → 遍历驱动列表 → 调用驱动的match() → 匹配成功 → 调用驱动的probe()
驱动注册 → 总线发现驱动 → 遍历设备列表 → 调用驱动的match() → 匹配成功 → 调用驱动的probe()

        1.2. Platform总线的特殊性

Platform总线的角色
  • 虚拟总线

    • 用于管理无物理总线的设备(如SoC内部外设:UART、GPIO、定时器等)。

    • 总线名称为platform,对应的设备为platform_device,驱动为platform_driver

  • 设备来源

    1. 设备树(主流方式)

      • 内核将设备树中的节点(如compatible = "vendor,device")转换为platform_device

    2. 旧式硬编码

      • 通过platform_device_register()手动注册(常见于未使用设备树的旧内核)。

设备树与Platform总线的关系
  • 设备树的作用

    • 静态描述硬件信息(如寄存器地址、中断号)。

    • 被内核解析后生成platform_device,并注册到platform总线。

    • 设备树本身不是总线,而是总线上设备的“数据源”。(一开始搞混了以为总线就是设备树) 

    • 设备树 ≠ 总线,但设备树为Platform总线提供了设备信息。

关键流程:

设备树节点 → 内核解析 → 生成platform_device → 注册到platform总线 → 与platform_driver匹配

        1.3. 设备树的本质

设备树的功能
  • 硬件描述文件

    • 提供硬件资源的抽象描述(如reginterrupts)。

    • 支持动态配置(同一内核镜像适配不同硬件版本)。

  • 与总线的独立性

    • 设备树可以描述多种总线的设备(如platformi2cspi)。

例如:

// Platform设备
uart@1000 { compatible = "ns16550"; reg = <0x1000 0x100>; };

// I2C设备
i2c@2000 {
    compatible = "vendor,i2c-controller";
    eeprom@50 { compatible = "microchip,24c02"; reg = <0x50>; };
};
设备树与总线的协作
  • Platform设备

    • 设备树节点通过compatible匹配platform_driver

  • 其他总线设备

    • 设备树节点可能对应其他总线类型(如I2C、SPI),由各自总线控制器处理。

2:匹配触发流程

        2.1:设备树编译

// 示例:mydevice节点
mydevice@12340000 {
    compatible = "vendor,mydev-1.0";
    reg = <0x12340000 0x1000>;
    interrupts = <0 45 4>;
};

        2.2:内核初始化阶段

               (1): 解析DTB文件生成device_node结构体

                (2):将compatible匹配的节点转换为platform_device

        2.3:驱动注册阶段

static const struct of_device_id mydev_ids[] = {
    { .compatible = "vendor,mydev-1.0" },
    {}
};

static struct platform_driver mydev_driver = {
    .probe = mydev_probe,
    .driver = {
        .name = "mydev",
        .of_match_table = mydev_ids,
    },
};
module_platform_driver(mydev_driver);

        2.4:匹配过程

        (1):驱动加载时遍历所有未绑定的platform_device

        (2):通过compatible字符串精确匹配

        (3):成功则调用驱动的probe()函数

        整体流程可以梳理为:

DTS节点 → 内核解析 → Platform Device ↔ 匹配机制 ↔ Platform Driver

3:示例分析(以zynq_7000.dtsi为例子)

该实例使用的是官网linux-6.12.20的源码,路径\linux-6.12.20\arch\arm\boot\dts\xilinx\zynq-7000.dtsi下的dtsi文件;以其中的pmu驱动为例子:

	pmu@f8891000 {
		compatible = "arm,cortex-a9-pmu";
		interrupts = <0 5 4>, <0 6 4>;//type=0(SPI), number=5(中断号), flags=4(触发方式)
		interrupt-parent = <&intc>;
		reg = <0xf8891000 0x1000>,
		      <0xf8893000 0x1000>;
	};
		intc: interrupt-controller@f8f01000 {
			compatible = "arm,cortex-a9-gic";
			#interrupt-cells = <3>;
			interrupt-controller;
			reg = <0xF8F01000 0x1000>,
			      <0xF8F00100 0x100>;
		};

首先dts中的compatible匹配对应

static const struct of_device_id armpmu_of_device_ids[] = {
    { .compatible = "arm,cortex-a9-pmu",  .data = armv7_a9_pmu_init },
    {}
};

        然后就是interrupts参数对应的是使用的中断,在现在一般的arm架构中使用的中断都为gic中断,具体可以查询dtsi设备树文件中的interrupt-parent = <&intc> 的intc功能:

        3.1:interrupts属性:

编码格式解析:

每个中断描述符为

  • type0表示SPI(Shared Peripheral Interrupt)

GIC中断类型

GIC中断分为三类:

类型 名称 设备树中的type字段 中断号范围 用途 设备树示例
SPI Shared Peripheral 0 32-1020 外设共享中断(如UART、PMU) <0 116 4>
PPI Private Peripheral 1 16-31 CPU私有中断(如本地定时器) <1 13 0xf01>
SGI Software Generated (不通过设备树配置) 0-15 核间软件触发中断(如IPI) 无设备树定义
  • number:GIC中断号(需查表确认)

  • flags4表示高电平触发(ARM文档定义)

Zynq-7000中断映射验证:
  1. 查阅TRM Table 7-3

    中断源 GIC中断号
    PMU Interrupt (CPU0) 5
    PMU Interrupt (CPU1) 6

你可能感兴趣的:(笔记,linux,架构,arm开发,学习)