编辑推荐: |
本文主要介绍了
设备树(DTS)语法详解 + LED控制实战相关内容。希望对您的学习有所帮助。
本文来自于微信公众号深度Linux,由火龙果软件Linda编辑、推荐。 |
|
在嵌入式开发领域,设备树(Device Tree)扮演着极为关键的角色。它如同一份精准的硬件说明书,让操作系统能够清晰识别并高效管理硬件资源。当我们着手为自定义硬件编写设备树时,就如同为新成员量身定制一套专属
“档案”,确保其能无缝融入系统 “大家庭”。
想象一下,你精心设计了一款独特的硬件,满心期待它在系统中发挥作用。但如果没有正确编写设备树,操作系统很可能对其
“视而不见”,让你的心血难以充分施展。那么,如何才能为自定义硬件编写正确的设备树呢?
接下来,我们将通过一系列实战演练,带你逐步攻克这一技术要点,从了解硬件配置的基础信息,到精准修改设备树源文件,再到生成可被系统读取的二进制文件等,每一步都为你详细拆解,助你在自定义硬件开发之路上稳步前行
。
一、设备树初印象:为何而生?
在嵌入式系统的广袤天地中,设备树(Device Tree)宛如一座桥梁,横跨在硬件与软件之间,承担着至关重要的沟通使命。在设备树出现之前,嵌入式系统的开发可没少让开发者们头疼。就拿
ARM 架构来说,不同开发板的硬件信息就像一团乱麻,紧紧地与内核代码交织在一起。想象一下,每更换一次开发板,那密密麻麻的内核代码就得大改特改,移植工作不仅繁琐,还极易出错,维护成本更是高得吓人。
为了化解这些难题,设备树应运而生。它最早在 PowerPC 架构中崭露头角,随后便在 ARM、MIPS
等多种架构中广泛应用,迅速成为嵌入式开发的得力助手。设备树的核心使命,就是将硬件描述从内核代码中剥离出来,实现两者的解耦。如此一来,内核变得更加通用,开发板相关的特定信息则由设备树文件专门负责描述。当我们要将内核移植到新的开发板时,只需对设备树文件进行修改,这极大地降低了移植的难度和工作量,就像是给复杂的开发工作找到了一条捷径。
举个例子,在一个基于 ARM 架构的智能家居控制系统开发中,以往若要适配不同厂家生产的开发板,每个开发板都有独特的硬件配置,如不同的
GPIO 引脚分配、外设接口等。在没有设备树时,针对每一款开发板,内核代码中都要硬编码大量的硬件相关信息,这导致内核代码臃肿不堪,且维护极为困难。一旦硬件稍有变动,例如更换了一个不同型号的传感器,与之相连的引脚发生变化,就需要在冗长的内核代码中四处寻找并修改相关配置,不仅容易遗漏,而且修改过程繁琐,极易引入新的错误。
有了设备树后,情况就大为不同。硬件相关信息被清晰地描述在设备树文件中。若要适配新的开发板,或者更改硬件配置,只需在设备树文件中相应节点处修改属性值即可。比如,要更改传感器连接的
GPIO 引脚,只需在设备树中找到对应的传感器节点,修改其 GPIO 属性值,而无需对内核代码进行大规模改动。这使得开发过程更加灵活高效,同时也提高了代码的可维护性和可移植性
。
1.1设备树在ARM架构的引入
在之前使用 S3C2440 开发板移植 Linux 3.4.2 内核时,修改了很多关于 c 文件去适配开发板,和开发板相关的文件放在arch/arm/mxch-xxx目录下,因此
linux 内核 arm 架构下添加了很多开发板的适配文件:

这些 c 文件仅仅用来适配某款开发板,对于 Linux 内核来说并没有提交什么新功能,但是每适配一款新的开发板就需要一堆文件,导致
Linux 内核越来越臃肿:

终于 Linus 忍不住天天 merge 这些鬼东西,向 arm 社区发出了一封邮件,第一句话就足矣表现不满:"This
whole ARM thing is a f*cking pain in the ass"。
因此,Arm 社区开始引入之前 powerPC 架构就采用的设备树,将描述这些板级信息的文件与 Linux
内核代码分离,Linux 4.x 版本几乎都支持设备树,所有开发板的设备树文件统一放在arch/arm/boot/dts目录中。
1.2什么是设备树
设备树全称 Device Tree,是一种数据结构,用来描述板级设备信息,比如 CPU 数量、外设基地址、总线设备等,如图:

DTS、DTB、DTC三种文件的区别
DTS 是设备树源码文件
DTB 是将DTS 编译以后得到的二进制文件
DTC工具是将dts文件变成编译成dtb的工具,就像.c文件变成成.o需要用到gcc编译器一样。
1.3 设备树编译
①简单粗暴,编译内核
②编译全部设备树文件
③编译指定的设备树文件
二、设备树语法
2.1设备树相关术语全解析
在深入探索设备树的世界之前,先来认识一下那些频繁出现的术语,它们就像是开启设备树大门的钥匙。
DT(Device Tree,设备树):这是一种用于描述计算机系统硬件布局的数据结构,它将系统中的各类硬件组件及其连接关系,以层次化的树状结构呈现出来。可以把它想象成是硬件的
“户口簿”,详细记录着每个硬件设备的 “身份信息” 以及它们之间的 “亲属关系” ,为内核提供了清晰的硬件信息,让内核能够有条不紊地初始化和操作硬件设备。
FDT(Flattened Device Tree,扁平设备树):FDT 是设备树的二进制表示形式,就像是设备树的
“压缩包”。它由设备树编译器(dtc)精心打造而成,是 dts 文件编译后的产物。这种紧凑的存储方式,使其在系统启动时能够快速加载和解析,大大提高了系统启动的效率
,就好比将一本厚厚的书压缩成了一个小巧的文件,携带和读取都更加便捷。
dts(Device Tree Source,设备树源文件):dts 文件是设备树的源文件,以通俗易懂的文本格式编写,是硬件开发人员或系统集成商施展拳脚的舞台。他们通过编写
dts 文件,详细描述系统中的硬件设备及其属性,就像建筑师绘制建筑蓝图一样,为后续的硬件实现和系统开发奠定基础。这个文件就像是设备树的
“初稿”,记录着最原始的硬件描述信息。
dtsi(Device Tree Source Include,设备树源包含文件):dtsi 文件类似于编程中的头文件,是设备树源文件的得力助手。它通常包含一些被多个
dts 文件共享的硬件描述,通过 #include 指令巧妙地融入到具体的 dts 文件中。这样一来,不仅避免了重复代码,还让硬件描述的管理和维护变得更加轻松,就像是一个公共的资源库,各个
dts 文件都可以按需取用其中的内容 。
dtb(Device Tree Blob,设备树二进制文件):dtb 文件是 dts 文件经过编译后生成的二进制文件,包含了设备树的扁平表示形式(FDT)。在系统启动的关键时刻,引导加载程序(如
U-Boot)会将 dtb 文件从存储设备中加载到内存,并恭敬地传递给操作系统内核。内核则依据 dtb
文件中描述的信息,对硬件进行初始化操作,它就像是一份被加密后的硬件说明书,只有内核能够读懂并依据它来配置硬件
。
dtc(Device Tree Compiler,设备树编译器):dtc 是设备树世界中的 “翻译官”,它肩负着将
dts 文件编译为 dtb 文件的重任。不仅如此,在调试和修改设备树时,它还能将 dtb 文件反编译为
dts 文件,为开发者提供了极大的便利。就好比一个语言专家,能够在不同格式的设备树文件之间自由转换
。
这些术语相互协作,共同构建起设备树的生态系统。dts 和 dtsi 文件是设备树的源代码基础,dtc
编译器将它们转换为内核能够识别的 dtb 文件,而 FDT 则是 dtb 文件内部的一种高效存储结构,DT
则是整个硬件描述概念的统称 。
2.2设备树源码藏身何处
在 Linux 内核源码的庞大体系中,设备树源码有着自己专属的 “栖息地”。对于 32 位系统而言,设备树源码通常存放在
“源码 /arch/arm/boot/dts” 目录下;而在 64 位系统中,它们则位于 “源码 /arch/arm64/boot/dts”
目录 。
在这些目录中,你能找到众多以.dts 和.dtsi 为扩展名的文件,它们就像是隐藏在代码海洋中的宝藏,记录着硬件设备的详细信息
。不同架构的设备树文件存放位置和命名规则可能会略有差异,所以在探索时,一定要查阅对应架构的文档或源码,这样才能准确找到所需的设备树文件
。
2.3DTC 工具的神奇用法
DTC 工具作为设备树编译和反编译的利器,掌握它的使用方法至关重要。下面就来看看如何使用 DTC 工具进行设备树的编译和反编译操作
。
(1)编译设备树
基本的编译命令格式为 “dtc -I dts -O dtb -o output_file.dtb
input_file.dts”。其中,“dtc” 是调用设备树编译器;“-I dts” 明确指定输入文件的格式为设备树源文件(DTS),就像是告诉编译器要处理的是哪种类型的
“原材料”;“-O dtb” 指定输出文件的格式为设备树二进制文件(DTB),也就是确定了 “成品”
的格式;“-o output_file.dtb” 则指定了输出文件的名称,让编译器知道要把生成的文件保存成什么名字;“input_file.dts”
自然就是指定输入的设备树源文件了 。
例如,我们有一个名为 “my_device.dts” 的设备树源文件,想要将其编译成二进制文件 “my_device.dtb”,就可以在命令行中输入
“dtc -I dts -O dtb -o my_device.dtb my_device.dts”,按下回车键,DTC
工具就会迅速行动,将 dts 文件编译成 dtb 文件 。
(2)反编译设备树
反编译的命令格式为 “dtc -I dtb -O dts -o example.dts example.dtb”。这里的参数含义与编译时类似,只是输入和输出的格式进行了互换。“-I
dtb” 表示输入文件是设备树二进制文件(DTB),“-O dts” 表示输出文件为设备树源文件(DTS)
。
假设我们有一个 “example.dtb” 的二进制文件,想要查看其原始的设备树描述内容,就可以使用
“dtc -I dtb -O dts -o example.dts example.dtb” 命令,将
dtb 文件反编译成 dts 文件,方便我们进行查看和修改 。
在实际操作过程中,还可能会用到其他一些参数。比如,“-q” 参数可以让编译过程更加安静,减少不必要的提示信息;“-i”
参数可以添加搜索包含文件的路径,方便在编译时找到所需的 dtsi 文件等 。掌握这些参数的用法,能够让我们更加灵活地使用
DTC 工具,应对各种设备树处理的需求 。
三、深入设备树语法殿堂
3.1节点:设备树的基石
节点是设备树的基本组成单元,就像是树状结构中的一个个 “树枝分叉点” ,每个节点都代表着一个硬件设备或组件。节点的命名遵循特定规则,通常以
“node-name@unit-address” 的形式出现 。其中,“node-name” 是节点的名称,一般由字母、数字和下划线组成,用来描述节点所代表的设备类型或功能,如
“uart” 代表串口设备,“i2c” 代表 I2C 总线设备等 。
“unit-address” 则是设备的单元地址,通常表示设备在内存空间或总线上的地址,像 “0x10000000”
这样的十六进制数,它与设备的 “reg” 属性密切相关 。若节点没有地址相关信息,“@unit-address”
部分可以省略 。
每个节点内部可以包含多个属性和子节点。属性以键值对的形式存在,用于描述节点的各种特性;子节点则进一步细化硬件设备的层次结构
。例如,在描述一个 SPI 控制器时,可能会有如下节点:
spi@12340000 { compatible = "fsl,imx6ul-spi"; reg = <0x12340000 0x1000>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <1>; #size-cells = <0>;
spi_device: spi@0 { compatible = "my_spi_device"; reg = <0>; spi-max-frequency = <5000000>; }; };
|
在这个例子中,“spi@12340000” 是 SPI 控制器节点,包含了描述其兼容性、地址、中断等属性
。而 “spi_device: spi@0” 则是 SPI 控制器下的一个子节点,表示连接在该 SPI
总线上的一个设备,有自己的兼容性、设备地址和最大工作频率等属性 。
3.2属性:描述设备的关键
属性是节点的重要组成部分,以 “name = value” 的形式存在,用于详细描述节点所代表设备的各种特性
。属性的值可以是多种数据类型,常见的有以下几种:
32 位无符号整数:用尖括号 “<>” 括起来,如 “interrupts = <17
0xc>”,表示该设备的中断号为 17,触发方式为 0xc(具体含义根据中断控制器的定义) 。
字符串:用双引号 “""” 括起来,如 “compatible ="arm,cortex-a7"”,“compatible”
属性用于驱动与设备的匹配,这里表示该设备与 “arm,cortex-a7” 类型兼容 。
字节数组:用方括号 “[]” 括起来,每个字节用两个十六进制数表示,如 “local-mac-address
= [00 00 12 34 56 78]”,用于表示设备的本地 MAC 地址 。
复合类型:可以是多种值的组合,用逗号 “,” 隔开,如 “example = <0xf00f0000
19>, "a strange property format"” 。
在众多属性中,“compatible” 和 “reg” 属性尤为常用 。“compatible” 属性就像是设备的
“身份证”,用于设备与驱动程序的匹配 。内核在寻找设备驱动时,会根据设备节点的 “compatible”
属性值,在驱动列表中查找与之匹配的驱动 。例如,“compatible = "fsl,imx6ul-spi",
"spi-gpio"”,表示该设备首先尝试匹配 “fsl,imx6ul-spi”
驱动,若找不到,则尝试匹配 “spi-gpio” 驱动 。
“reg” 属性用于描述设备的寄存器地址范围,其值是一系列的 “address size” 对 。“address”
表示设备寄存器的起始地址,“size” 表示地址范围的大小 。这两个值的表示方式由其父节点的 “#address-cells”
和 “#size-cells” 属性决定 。比如,在下面的例子中:
soc { #address-cells = <1>; #size-cells = <1>;
spi@12340000 { reg = <0x12340000 0x1000>; ... }; };
|
由于 “soc” 节点的 “#address-cells = <1>” 和 “#size-cells
= <1>”,所以 “spi@12340000” 节点的 “reg” 属性中,“0x12340000”
用 1 个 32 位整数表示起始地址,“0x1000” 用 1 个 32 位整数表示地址范围大小 。
3.3包含文件:代码复用的利器
在设备树开发中,为了提高代码的复用性和可维护性,常常会使用包含文件(dtsi) 。dtsi 文件类似于
C 语言中的头文件,用于存放被多个 dts 文件共享的设备树描述 。通过使用包含文件,可以避免在多个
dts 文件中重复编写相同的硬件描述代码 。
在 dts 文件中,可以使用 “#include” 指令来引用 dtsi 文件 。例如:
这样,“common.dtsi” 文件中的内容就会被包含到当前 dts 文件中 。除了 dtsi 文件,设备树源文件也可以包含标准的
C 头文件(.h) 。这在需要使用一些宏定义或常量时非常方便 。例如,在 dts 文件中可能会包含如下头文件:
#include <dt-bindings/gpio/gpio.h>
|
通过包含这个头文件,可以在设备树中使用其中定义的 GPIO 相关宏,如 “GPIO_ACTIVE_HIGH”“GPIO_ACTIVE_LOW”
等 。这样不仅提高了代码的可读性,还减少了人为错误 。
3.4节点路径:精准定位节点
在设备树这个庞大的 “家族树” 中,每个节点都有其唯一的路径,就像每个人在家族族谱中都有独特的位置标识一样
。节点路径是从根节点开始,通过各级子节点的名称和地址,以 “/” 分隔组成的 。例如,对于前面提到的
SPI 控制器节点,其路径为 “/soc/spi@12340000” 。
通过节点路径,我们可以在设备树中精准地访问特定节点 。在 Linux 内核中,提供了一系列函数来通过节点路径查找节点
。例如,“of_find_node_by_path (const char *path)” 函数,它接收一个节点路径作为参数,返回对应节点的指针
。假设我们要获取 SPI 控制器节点的信息,就可以使用如下代码:
#include <linux/of.h> #include <linux/device.h>
struct device_node *spi_node; spi_node = of_find_node_by_path("/soc/spi@12340000"); if (spi_node) { // 在这里可以对找到的节点进行操作,如获取属性等 of_node_put(spi_node); }
|
在实际应用中,节点路径常用于设备驱动开发 。驱动程序需要根据设备树中节点的信息来初始化和操作硬件设备,通过节点路径可以快速准确地找到对应的设备节点,从而获取设备的属性和配置信息
。
3.5别名:便捷访问节点
别名就像是设备树节点的 “昵称”,为了更方便地访问设备树中的节点而存在 。通过定义别名,可以使用一个简短的名称来代替冗长的节点路径
。别名的定义通常在设备树的根节点下,使用 “aliases” 属性 。例如:
aliases { spi0 = &spi@12340000; uart1 = &uart@101f0000; };
|
在这个例子中,为 “spi@12340000” 节点定义了别名 “spi0”,为 “uart@101f0000”
节点定义了别名 “uart1” 。这样,在设备树的其他部分,或者在驱动程序中,就可以使用这些别名来代替完整的节点路径
。例如,在驱动程序中,可以使用 “of_find_node_by_phandle (of_parse_phandle
(aliases, "spi0", 0))” 来通过别名 “spi0” 找到对应的
SPI 控制器节点 。
别名的使用不仅提高了设备树的可读性,还使代码更加简洁和易于维护 。特别是在大型设备树中,当需要频繁访问某些节点时,使用别名可以大大减少代码中冗长路径的出现,降低出错的概率
。
3.6复合节点与定义引用:复杂关系的处理
在描述复杂的硬件设备关系时,复合节点和定义引用发挥着重要作用 。复合节点是指一个节点可以包含多个子节点,这些子节点共同描述一个复杂的硬件设备或功能
。例如,在描述一个包含多个功能模块的芯片时,可能会有如下复合节点:
chip@10000000 { compatible = "my_chip"; reg = <0x10000000 0x10000>;
module1: submodule@1000 { compatible = "module1_type"; reg = <0x1000 0x100>; };
module2: submodule@2000 { compatible = "module2_type"; reg = <0x2000 0x200>; }; };
|
在这个例子中,“chip@10000000” 是一个复合节点,包含了 “module1” 和 “module2”
两个子节点,分别描述芯片中的两个不同功能模块 。
定义引用则是通过 “&label” 的方式来引用其他节点 。例如,在前面的例子中,如果有另一个节点需要使用
“module1” 节点的信息,可以这样引用:
other_node { depends_on = <&module1>; // 其他属性和子节点 };
|
这里的 “depends_on = <&module1>” 表示 “other_node”
节点依赖于 “module1” 节点 。通过这种方式,可以清晰地表达硬件设备之间的依赖关系 。
在实际应用中,复合节点和定义引用常用于描述复杂的硬件系统,如片上系统(SoC) 。SoC 通常包含多个处理器核心、各种外设控制器等,通过复合节点和定义引用,可以准确地描述这些组件之间的层次结构和相互关系,为内核提供完整的硬件信息
。
四、实战:设备树实例深度剖析
4.1 GPIO设备树实例详解
以某款基于 ARM 架构的开发板为例,其设备树中 GPIO 设备树节点如下:
gpio0: gpio@10000000 { compatible = "fsl,imx6ul-gpio", "gpio-generic"; reg = <0x10000000 0x1000>; interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; };
|
在这个节点中,“compatible” 属性表明该 GPIO 控制器与 “fsl,imx6ul-gpio”
和 “gpio-generic” 兼容,这使得内核能够准确找到与之匹配的驱动程序 。“reg” 属性指定了
GPIO 控制器的寄存器地址范围,起始地址为 0x10000000,大小为 0x1000 字节 。“interrupts”
属性描述了 GPIO 控制器的中断信息,使用 GIC_SPI 类型的中断,中断号为 66,触发方式为高电平触发
。
“gpio-controller” 属性标识该节点为 GPIO 控制器 。“#gpio-cells
= <2>” 则表示在引用该 GPIO 控制器时,需要两个 32 位的参数 。第一个参数表示
GPIO 的编号,第二个参数表示 GPIO 的触发类型 。例如,在其他节点中引用该 GPIO 控制器的某个引脚时,可能会这样写:
my_device { gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; ... };
|
这里表示使用 “gpio0” 控制器的第 10 号引脚,触发类型为高电平有效
。这种属性设置方式,为系统中其他设备使用 GPIO 提供了清晰的规范和接口 。
4.2 LED设备树实例全解析
假设我们要在开发板上实现一个 LED 驱动,首先在设备树中定义 LED 节点:
leds { compatible = "gpio-leds"; pinctrl-names = "default"; pinctrl-0 = <&led_pins>;
led_red: red_led { label = "red_led"; gpios = <&gpio1 18 GPIO_ACTIVE_LOW>; default-state = "off"; }; };
pinctrl: pinctrl@10000400 { compatible = "fsl,imx6ul-pinctrl"; reg = <0x10000400 0x1000>;
led_pins: ledgrp { fsl,pins = < MX6UL_PAD_GPIO1_IO18__GPIO1_IO18 0x10b0 >; }; };
|
在这个设备树实例中,“leds” 节点的 “compatible = "gpio-leds"”
属性表明这是一个基于 GPIO 的 LED 设备 。“pinctrl-names” 和 “pinctrl-0”
属性用于引脚控制,通过引用 “led_pins” 节点来配置 LED 所使用的引脚 。
“led_red” 子节点定义了一个红色 LED,“label” 属性为其命名,“gpios” 属性指定该
LED 连接到 “gpio1” 控制器的 18 号引脚,且为低电平有效 。“default-state
= "off"” 表示 LED 默认处于熄灭状态 。
在驱动开发中,内核驱动会根据 “compatible” 属性找到对应的 LED 驱动程序 。在驱动的
probe 函数中,通过设备树 API 函数来获取设备树节点信息 。例如,使用 “of_find_node_by_path”
函数找到 “leds” 节点,再通过 “of_get_child_by_name” 函数获取 “led_red”
子节点 。
然后,利用 “of_property_read_u32_array” 函数读取 “gpios” 属性的值,从而获取
LED 所连接的 GPIO 引脚信息 。最后,根据这些信息进行 GPIO 的初始化和 LED 的控制操作
。
4.3自定义设备树节点与驱动匹配实例
假设我们要添加一个自定义的温度传感器设备,首先在设备树中创建自定义节点:
temperature_sensor: sensor@1234 { compatible = "mycompany,temperature-sensor"; reg = <0x1234 0x100>; sensor_type = "temperature"; sampling_rate = <100>; };
|
这个自定义节点 “temperature_sensor” 的 “compatible” 属性设置为
“mycompany,temperature-sensor”,用于与驱动程序进行匹配 。“reg”
属性指定了传感器的寄存器地址范围 。“sensor_type” 和 “sampling_rate”
是自定义属性,分别表示传感器类型和采样率 。
接下来编写对应的内核驱动:
#include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h>
static int my_sensor_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; u32 reg_val, sampling_rate; const char *sensor_type;
if (!np) return -EINVAL;
// 读取reg属性 if (of_property_read_u32(np, "reg", ®_val) != 0) { dev_err(&pdev->dev, "Failed to read reg property\n"); return -EINVAL; }
// 读取sensor_type属性 if (of_property_read_string(np, "sensor_type", &sensor_type) != 0) { dev_err(&pdev->dev, "Failed to read sensor_type property\n"); return -EINVAL; }
// 读取sampling_rate属性 if (of_property_read_u32(np, "sampling_rate", &sampling_rate) != 0) { dev_err(&pdev->dev, "Failed to read sampling_rate property\n"); return -EINVAL; }
// 这里可以根据读取到的属性进行传感器的初始化和操作 dev_info(&pdev->dev, "Sensor initialized: reg = 0x%x, type = %s, sampling_rate = %d\n", reg_val, sensor_type, sampling_rate);
return 0; }
static int my_sensor_remove(struct platform_device *pdev) { // 清理操作 return 0; }
static const struct of_device_id my_sensor_of_match[] = { {.compatible = "mycompany,temperature-sensor"}, {}, }; MODULE_DEVICE_TABLE(of, my_sensor_of_match);
static struct platform_driver my_sensor_driver = { .probe = my_sensor_probe, .remove = my_sensor_remove, .driver = { .name = "mycompany-temperature-sensor-driver", .of_match_table = my_sensor_of_match, }, };
module_platform_driver(my_sensor_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Custom Temperature Sensor Driver");
|
在这个驱动程序中,“my_sensor_of_match” 数组用于匹配设备树中自定义节点的 “compatible”
属性 。“my_sensor_probe” 函数在设备探测时被调用,通过设备树 API 函数读取设备树节点的属性信息,并进行相应的初始化操作
。这样,通过 “compatible” 属性,设备树中的自定义节点与内核驱动成功匹配,驱动能够正确解析设备树属性并对设备进行控制
。 |