15-描述设备树中的设备如何与驱动匹配

快速链接:
.
👉👉👉 Linux内核驱动面试-百问百答-[目录] 👈👈👈

在这里插入图片描述
在Linux内核中,设备树(Device Tree)是一种描述硬件的方式,尤其在嵌入式系统和ARM架构中被广泛使用。设备树使用一种名为设备树源(Device Tree Source, DTS)的语法来描述系统的硬件布局,包括设备和它们的属性。内核使用设备树来了解系统中存在的硬件,并相应地加载和配置驱动程序。以下是设备树中设备与驱动匹配的机制及其详细过程:

1. 设备树的基本结构

设备树是一个树状结构,根节点是系统的根,每个节点表示一个设备或总线。每个节点包含一组属性,描述设备的特性和配置。

一个简单的设备树节点示例如下:

uart0: serial@101f1000 {
    compatible = "ns16550a";
    reg = <0x101f1000 0x1000>;
    interrupt-parent = <&intc>;
    interrupts = <5>;
};

2. 设备树编译

设备树源文件(.dts)需要编译成二进制设备树(Device Tree Blob, DTB)文件。编译过程使用设备树编译器(DTC)。

dtc -I dts -O dtb -o device_tree.dtb device_tree.dts

编译后的DTB文件会被加载到内核启动过程中,以便内核读取和解析。

3. 内核解析设备树

内核在启动时会加载DTB文件,并根据设备树中的信息初始化硬件。内核会将设备树的每个节点与相应的驱动进行匹配。

4. 匹配机制

设备树节点与驱动匹配主要通过compatible属性进行。驱动程序通过指定支持的compatible字符串,告诉内核哪些设备节点与其匹配。

设备树节点中的compatible属性

每个设备节点都有一个compatible属性,用于描述该设备的类型及其兼容的驱动。

uart0: serial@101f1000 {
    compatible = "ns16550a";
    ...
};
驱动程序中的of_device_id结构

驱动程序中使用of_device_id结构来定义匹配的设备树节点。

static const struct of_device_id uart_of_match[] = {
    { .compatible = "ns16550a" },
    {},
};
MODULE_DEVICE_TABLE(of, uart_of_match);

5. 注册和匹配驱动

驱动程序会在初始化时注册一个平台驱动(platform driver)或总线驱动,并将of_device_id匹配表传递给内核。

驱动初始化和注册
static int uart_probe(struct platform_device *pdev) {
    // 驱动初始化代码
    return 0;
}

static int uart_remove(struct platform_device *pdev) {
    // 驱动卸载代码
    return 0;
}

static struct platform_driver uart_driver = {
    .driver = {
        .name = "uart_driver",
        .of_match_table = uart_of_match,
    },
    .probe = uart_probe,
    .remove = uart_remove,
};

module_platform_driver(uart_driver);

6. 设备绑定和驱动加载

当内核解析设备树时,会遍历每个节点,检查compatible属性,并与所有已注册驱动的of_match_table进行匹配。如果匹配成功,内核会调用驱动的probe函数,绑定设备和驱动,并进行设备初始化。

设备绑定过程
  1. 内核启动时加载DTB:内核加载设备树二进制文件(DTB),并开始解析。
  2. 遍历设备树节点:内核遍历设备树的每个节点,读取每个节点的compatible属性。
  3. 匹配驱动:内核将节点的compatible属性与所有已注册驱动的of_match_table进行匹配。
  4. 调用probe函数:如果找到匹配的驱动,内核会调用该驱动的probe函数,将设备信息传递给驱动进行初始化。
  5. 设备初始化:驱动在probe函数中初始化设备,设置设备寄存器,分配资源,创建设备节点等。

示例:UART设备驱动匹配

设备树节点
uart0: serial@101f1000 {
    compatible = "ns16550a";
    reg = <0x101f1000 0x1000>;
    interrupt-parent = <&intc>;
    interrupts = <5>;
};
驱动代码
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>

static const struct of_device_id uart_of_match[] = {
    { .compatible = "ns16550a" },
    {},
};
MODULE_DEVICE_TABLE(of, uart_of_match);

static int uart_probe(struct platform_device *pdev) {
    // 驱动初始化代码
    printk(KERN_INFO "UART device matched and probed\n");
    return 0;
}

static int uart_remove(struct platform_device *pdev) {
    // 驱动卸载代码
    printk(KERN_INFO "UART device removed\n");
    return 0;
}

static struct platform_driver uart_driver = {
    .driver = {
        .name = "uart_driver",
        .of_match_table = uart_of_match,
    },
    .probe = uart_probe,
    .remove = uart_remove,
};

module_platform_driver(uart_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple UART Driver");
MODULE_VERSION("1.0");

通过以上步骤,设备树中的设备节点可以与相应的驱动程序匹配,并在内核启动过程中自动加载和初始化。设备树和驱动匹配机制使得硬件描述与驱动代码分离,简化了硬件平台的适配和管理。

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码改变世界ctw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值