对设备树、DTS语法、设备树中常用函数 的认识(简单总结)

2024-09-04 05:04

本文主要是介绍对设备树、DTS语法、设备树中常用函数 的认识(简单总结),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        设备树(Device Tree)是一种数据结构,用于描述硬件的板级设备信息。它由一系列被命名的节点(node)和属性(property)组成,这些节点和属性共同构成了描述硬件设备的树形结构。设备树主要用于嵌入式系统和复杂硬件平台的开发中,特别是当硬件设备的种类和数量众多,且每个设备都有其独特的配置和特性时。

1、设备树的主要组成部分

  1. DTS(Device Tree Source)文件

    • DTS文件是设备树的源码文件,采用ASCII文本格式编写,文件扩展名为.dts。
    • DTS文件通过树形结构描述板级设备信息,如CPU数量、内存基地址、外设接口(如IIC、SPI)上连接的设备等。
    • 每个设备在DTS文件中表示为一个节点,节点通过属性来描述设备信息,属性是键值对的形式。
  2. DTSI(Device Tree Include)文件

    • DTSI文件类似于C语言中的头文件,用于描述SOC级别的内部外设信息,如CPU架构、主频、外设寄存器地址范围等。
    • DTS文件可以引用DTSI文件,以减少代码冗余,便于维护和共享。
  3. DTC(Device Tree Compiler)工具

    • DTC工具用于将DTS文件编译成二进制格式的DTB(Device Tree Blob)文件。
    • DTC工具的源码位于Linux内核的scripts/dtc目录下。
  4. DTB(Device Tree Blob)文件

    • DTB文件是DTS文件编译后的二进制文件,由Linux内核解析。
    • DTB文件包含了设备树的完整信息,用于在系统启动阶段配置和初始化硬件设备。

2、设备树的作用

  • 分离硬件描述与内核代码:设备树将硬件描述信息与内核代码分离,避免了硬编码方式带来的问题,如内核臃肿、修改硬件信息需重新编译内核等。
  • 简化硬件适配:对于同一SOC的不同主板,只需更换设备树文件即可实现无差异支持,无需更换内核文件。
  • 提高系统可移植性:设备树的使用使得Linux系统更容易移植到不同的硬件平台上。

3、设备树的使用方法

  1. 编写DTS文件

    • 根据硬件平台的实际情况,编写描述板级设备信息的DTS文件。
    • 使用设备树语法定义节点和属性,确保信息的准确性和完整性。
  2. 编译DTS文件

    • 使用DTC工具将DTS文件编译成DTB文件。编译过程通常在系统编译阶段完成。
    • 编译命令示例:make dtbs(在Linux内核源码根目录下执行)
  3. 加载DTB文件

    • 在系统启动阶段,bootloader负责加载启动镜像并提取其中的DTB文件。
    • Bootloader将DTB文件传递给内核,内核根据其中的设备树信息来配置和初始化硬件设备。
  4. 内核解析DTB文件

    • 内核在接收到DTB文件后,会对其进行解析。
    • 解析过程中,内核会根据设备树中的节点和属性来创建对应的设备对象,并为它们设置相应的属性和配置。
  5. 设备树匹配与驱动加载

    • 内核在解析设备树的过程中,会根据设备节点的“compatible”属性来匹配相应的驱动程序。
    • 一旦找到匹配的驱动程序,内核就会将其加载并用于设备的初始化和管理。

综上所述,设备树是Linux系统中一种非常重要的硬件描述机制,它通过树形结构描述板级设备信息,简化了硬件适配过程,提高了系统的可移植性和灵活性。在使用设备树时,需要掌握DTS文件的编写方法、DTC工具的使用以及内核对DTB文件的解析过程。

4、DTS语法

        DTS(Device Tree Source)是一种基于文本的描述硬件设备的语言,它允许开发者以一种结构化的方式来定义硬件的配置信息。DTS语法相对简单但严格,以下是对DTS语法的详细解析:

一、文件结构

DTS文件采用树状结构来组织设备信息,每个文件通常包含一个根节点(/),根节点下可以有多个子节点,子节点下还可以有更深层次的子节点,以此类推。

二、节点(Node)

节点是DTS文件的基本组成单元,用于表示硬件设备或总线。节点的基本语法如下:

[label:]node-name[@unit-address]{  [properties definitions];  [child nodes];  
};
  • label:可选的标签,用于方便地引用节点。
  • node-name:节点名称,由数字、大小写字母、逗号(,)、点(.)、下划线(_)等组成,且必须以字母开头。
  • unit-address:可选的设备地址,用于唯一标识具有相同节点名的不同设备。
  • properties definitions:节点的属性定义,描述设备的特性和参数。
  • child nodes:子节点,节点下可以嵌套子节点,形成树状结构。

三、属性(Property)

属性用于描述节点的特性和参数,其基本语法如下:

[label:]property-name = value;
  • label:可选的标签,用于引用属性。
  • property-name:属性名称。
  • value:属性值,可以是字符串、整数、数组等类型。

属性值的具体表示方式如下:

  • 字符串:用双引号(")括起来,如compatible = "arm,cortex-a7";
  • 整数:用尖括号(< >)括起来,如reg = <0x1000 0x100>;。64位整数由两个32位整数表示,如<0x00000001 0x00000000>
  • 数组:用尖括号括起来的整数列表,如interrupts = <17 0xc>;
  • 字节序列:用方括号([ ])括起来的字节列表,每个字节用两个十六进制数表示,如local-mac-address = [00 00 12 34 56 78];

四、特殊属性和节点

1. compatible属性

用于指定设备的兼容信息,通常由制造商和设备型号组成,如compatible = "fsl,imx6ull-gpmi-nand";。这个属性是驱动和设备匹配的关键。

2. status属性

表示设备的运行状态,可选值包括okaydisabledfail等。

3. #address-cells和#size-cells属性

        这两个属性的值都是无符号 32 位整形, #address-cells #size-cells 这两个属性可以用在任
何拥有子节点的设备中,用于描述子节点的地址信息。 #address-cells 属性值决定了子节点 reg
性中地址信息所占用的字长 (32 ) #size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性
都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度, reg 属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>
每个“ address length ”组合表示一个地址范围,其中 address 是起始地址, length 是地址长
度, #address-cells 表明 address 这个数据所占用的字长, #size-cells 表明 length 这个数据所占用
的字长。

4. reg属性

用于描述设备的地址范围,格式通常为reg = <address length [address2 length2] ...>;

5.ranges属性

        ranges属性的值可以为空,或者按照(child-bus-address, parent-bus-address, length)的格式编写的数字矩阵。每个元素代表一个地址映射项,包含三部分:子地址(child-bus-address)、父地址(parent-bus-address)和地址空间长度(length)。

6. chosen节点

chosen节点不表示一个实际的硬件设备,而是用于向内核传递启动参数,如bootargs

7. aliases节点

aliases节点用于定义别名,方便在设备树中引用其他节点。 

五、包含dtsi文件和宏定义

        DTS文件可以包含dtsi文件,类似于C语言中的头文件包含。dtsi文件通常包含一些通用的设备树定义,可以在多个DTS文件中共享。此外,DTS文件还可以使用宏定义来简化属性的编写,这些宏定义通常定义在专门的头文件中。

六、编译与反编译

        DTS文件需要通过设备树编译器(dtc)编译成设备树二进制文件(dtb),才能被内核解析。同时,dtb文件也可以通过dtc反编译回dts文件,以便于修改和调试。

七、DTS语法举例

/ {  model = "Example Board with Example Device";  compatible = "generic-board", "vendor,example-device";  // Memory节点,描述物理内存的布局  memory@80000000 {  device_type = "memory";  reg = <0x80000000 0x40000000>; // 起始地址0x80000000,大小0x40000000(1GB)  };  // Cpus节点,描述CPU信息  cpus {  #address-cells = <1>;  #size-cells = <0>;  cpu@0 {  device_type = "cpu";  compatible = "arm,cortex-a9";  reg = <0>; // 标识CPU核心0  enable-method = "psci"; // 启用方法,使用PSCI协议  status = "okay";  };  };  // Chosen节点,用于传递系统指定的运行时参数给内核  chosen {  bootargs = "console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait";  };  // Aliases节点,定义别名以便更方便地引用设备树中的其他节点  aliases {  serial0 = &uart0;  ethernet0 = &eth0;  };  // 串口(UART)设备节点  uart0: uart@40002000 {  compatible = "ns16550";  reg = <0x40002000 0x1000>;  interrupts = <18>;  clock-frequency = <1843200>;  };  // 以太网设备节点  eth0: ethernet@40008000 {  compatible = "smc,smc91111";  reg = <0x40008000 0x1000>;  interrupts = <23>;  mac-address = [00 12 34 56 78 9A];  fixed-link {  speed = <100>;  full-duplex;  };  };  // I2C控制器节点  i2c1: i2c@40020000 {  compatible = "i2c-compatible";  reg = <0x40020000 0x1000>;  #address-cells = <1>;  #size-cells = <0>;  // I2C设备节点(EEPROM)  eeprom@50 {  compatible = "eeprom-compatible";  reg = <0x50>;  };  };  // 另一个串口设备节点,用于展示不同的设备实例  serial@40080000 {  compatible = "ns16550";  reg = <0x40080000 0x1000>;  interrupts = <18>;  clock-frequency = <1843200>;  };  
};

详细介绍

  1. 根节点(/`)
    • model:设备的型号或名称。
    • compatible:设备的兼容性字符串,用于匹配驱动程序。
  2. 内存节点 (memory@80000000):
    • device_type: 指明了这是一个内存设备。
    • reg: 描述了内存的物理地址和大小,这里是起始地址0x80000000,大小为0x40000000(即1GB)。
  3. CPU节点 (cpus):
    • #address-cells 和 #size-cells: 描述了CPU子节点中reg属性的地址单元和大小单元的数量。
    • cpu@0: 描述了第一个CPU核心的信息。
      • device_type: 指明了这是一个CPU设备。
      • compatible: 描述了CPU兼容的类型,这里是“arm,cortex-a9”。
      • reg: 标识了CPU核心的编号,这里是0。
      • enable-method: 描述了启用CPU的方法,这里是使用PSCI协议。
      • status: 描述了CPU的状态,这里是“okay”,表示正常。
  4. Chosen节点 (chosen):
    • bootargs: 传递了系统指定的运行时参数给内核,包括控制台设置、根文件系统设置等
  5. Aliases节点 (aliases):
    • 定义了别名以便更方便地引用设备树中的其他节点,如serial0引用uart0ethernet0引用eth0
  6. 串口(UART)设备节点 (uart0: uart@40002000):
    • compatible: 描述了UART设备兼容的类型,这里是“ns16550”。
    • reg: 描述了UART设备的物理地址和大小。
    • interrupts: 描述了UART设备使用的中断号。
    • clock-frequency: 描述了UART设备的时钟频率。
  7. 以太网设备节点 (eth0: ethernet@40008000):
    • compatible: 描述了以太网设备兼容的类型,这里是“smc,smc91111”。
    • reg: 描述了以太网设备的物理地址和大小。
    • interrupts: 描述了以太网设备使用的中断号。
    • mac-address: 描述了以太网设备的MAC地址。
    • fixed-link: 描述了以太网设备的固定链接属性,如速度和是否全双工。

        在这个DTS例子中,定义了设备的型号、兼容性、CPU、内存、串行通信和I2C控制器等硬件设备的信息。这些信息被编译成设备树二进制文件(DTB),并在系统启动时由内核解析,用于配置和初始化硬件设备。

八、DTS追加信息

        在DTS(Device Tree Source)根节点外中追加信息,通常涉及对现有的DTS文件进行编辑,以添加新的设备节点、属性或修改现有节点的配置。以下是一些步骤和注意事项,用于在DTS中追加信息:

1. 确定追加位置

        首先,需要确定在DTS文件中追加信息的具体位置。这通常取决于要添加的设备类型以及它在硬件系统中的位置。例如,如果要添加一个连接到I2C总线的传感器,你需要在I2C控制器的子节点下添加一个新的子节点。

2. 编辑DTS文件

        使用文本编辑器打开DTS文件,然后按照设备树的语法规则添加新的节点或属性。在添加新节点时,需要注意节点命名、属性格式以及可能的依赖关系。

例如,要在I2C控制器下添加一个温度传感器节点,可以添加类似以下内容的代码:

&i2c1 { /* 假设i2c1是已经存在的I2C控制器节点 */  status = "okay";  temp_sensor@48 {  compatible = "vendor,temp-sensor";  reg = <0x48>;  interrupts = <&gpio 24 IRQ_TYPE_EDGE_FALLING>; /* 假设温度传感器通过GPIO触发中断 */  };  
};

        在这个例子中,temp_sensor@48是新添加的温度传感器节点,@48指定了它在I2C总线上的地址。compatible属性用于指定温度传感器的兼容性字符串,以便内核能够找到正确的驱动程序。reg属性指定了设备在I2C总线上的地址,而interrupts属性(如果适用)指定了设备的中断配置。

3. 编译DTS文件

        修改完DTS文件后,需要使用设备树编译器(DTC)将其编译成设备树二进制文件(DTB)。这通常通过内核的构建系统来完成,可以使用make dtbs命令(在内核源码目录下)来编译所有DTS文件。

4. 部署DTB文件

        编译生成的DTB文件需要被部署到目标系统的适当位置,以便在启动时由Bootloader加载到内存中,并由内核解析。

5. 验证和调试

        在部署了修改后的DTB文件后,重新启动系统以验证新添加的设备是否按预期工作。可以使用/proc/device-tree目录下的文件来检查内核是否正确地解析了设备树,并使用适当的驱动程序来配置和管理硬件设备。

注意事项

  • 在修改DTS文件时,请确保遵循设备树的语法规则,以避免编译错误。
  • 如果不确定某个属性的用途或格式,请参考相应的绑定文档或内核文档。
  • 在修改设备树之前,最好备份原始文件,以便在出现问题时可以恢复。
  • 某些设备可能需要特定的配置步骤或额外的驱动程序支持才能正常工作。请确保已经完成了所有必要的配置和安装步骤。

九、节点命名规范

一、命名格式

        设备树中的节点名字通常遵循“node-name@unit-address”的格式,但并非所有节点都必须包含单元地址(unit-address)。这个格式允许节点名字清晰地描述节点的功能和位置。

  • node-name:节点名字,为ASCII字符串,应该能够清晰地描述出节点的功能。例如,“uart1”就表示这个节点是UART1外设。
  • @unit-address:单元地址,一般表示设备的地址或寄存器首地址。如果某个节点没有地址或者寄存器,这个部分可以省略。

        此外,还有一种常见的格式是在节点名字前使用标签(label)和冒号(:)进行标识,即“[label:]node-name[@unit-address]”。引入标签的目的是为了方便访问节点,可以直接通过&label来访问该节点,而不需要输入完整的节点名字。

二、字符限制

设备树中的节点名字长度通常为1到31个字符,且仅由特定的字符集组成。这些字符包括字母(A-Z, a-z)、数字(0-9)以及下划线(_)等。特殊字符(如空格、斜杠等)通常不被允许出现在节点名字中。

三、命名逻辑

节点名字的命名应遵循一定的逻辑,以便于理解和维护。以下是一些建议的命名逻辑:

  • 描述性功能:节点名字应尽可能描述其功能或用途,如“uart”、“gpio”、“ethernet”等。
  • 唯一性:在同一设备树中,节点名字应该是唯一的,以避免混淆。
  • 继承性:如果节点之间存在父子关系,子节点的名字可以在一定程度上继承父节点的特性或功能描述,但应确保唯一性。
  • 简洁性:在保持描述性功能的前提下,节点名字应尽量简洁明了,避免使用过长或过于复杂的名字。

四、其他注意事项

  • 大小写敏感:在设备树中,节点名字是大小写敏感的,因此在命名和引用时需要注意大小写的一致性。
  • 避免使用保留字:在命名节点时,应避免使用设备树语法中的保留字,如/(根节点路径)、#(用于特殊属性名)等。
  • 遵循惯例:在遵循上述规范的基础上,还可以参考行业内的命名惯例或标准,以提高设备树的兼容性和可移植性。

5、设备树常用 OF 操作函数

5.1. 查找节点

1 of_find_node_by_name 函数
of_find_node_by_name 函数通过 节点名字查找 指定的节点,函数原型如下:
struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        name:要查找的节点名字。
        返回值:找到的节点,如果为 NULL 表示查找失败
2 of_find_node_by_type 函数
of_find_node_by_type 函数通 过 device_type 属性查找 指定的节点,函数原型如下:
struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        type:要查找的节点对应的 type 字符串,也就是 device_type 属性值。
        返回值:找到的节点,如果为 NULL 表示查找失败.
3 of_find_compatible_node 函数
of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找 指定的节点,
函数原型如下:
struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL ,表示
忽略掉 device_type 属性。
        compatible: 要查找的节点所对应的 compatible 属性列表。
        返回值:找到的节点,如果为 NULL 表示查找失败
4 of_find_matching_node_and_match 函数
of_find_matching_node_and_match 函数通过 of_device_id 匹配表来查找指定的节点,函数原
型如下:
struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match)
函数参数和返回值含义如下:
        from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
        matches of_device_id 匹配表,也就是在此匹配表里面查找节点。
        match: 找到的匹配的 of_device_id
        返回值:找到的节点,如果为 NULL 表示查找失败
5 of_find_node_by_path 函数
of_find_node_by_path 函数 通过路径来查找 指定的节点,函数原型如下:
inline struct device_node *of_find_node_by_path(const char *path)
函数参数和返回值含义如下:
        path:带有全路径的节点名,可以使用节点的别名,比如“ /backlight ”就是 backlight 这个
节点的全路径。
        返回值:找到的节点,如果为 NULL 表示查找失败

5.2 查找父/子节点的函数

1 of_get_parent 函数
of_get_parent 函数用于获取指定节点的父节点 (如果有父节点的话) ,函数原型如下:
struct device_node *of_get_parent(const struct device_node *node)
函数参数和返回值含义如下:
        node:要查找的父节点的节点。
        返回值:找到的父节点。
2 of_get_next_child 函数
of_get_next_child 函数用 迭代的方式查找子节点 ,函数原型如下:
struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)
函数参数和返回值含义如下:
        node:父节点。
        prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为
NULL ,表示从第一个子节点开始。
        返回值:找到的下一个子节点。

5.3 提取属性值的函数

1 of_find_property 函数
of_find_property 函数用于 查找指定的属性 ,函数原型如下:
property *of_find_property(const struct device_node *np, const char *name, int *lenp)
函数参数和返回值含义如下:
        np:设备节点。
        name: 属性名字。
        lenp:属性值的字节数
        返回值:找到的属性
2 of_property_count_elems_of_size 函数
of_property_count_elems_of_size 函数用 于获取属性中元素的数量 ,比如 reg 属性值是一个
数组,那么使用此函数可以获取到这个数组的大小,此函数原型如下:
int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 需要统计元素数量的属性名字。
        elem_size:元素长度。
        返回值:得到的属性元素数量。
3 of_property_read_u32_index 函数
of_property_read_u32_index 函数用于从属性中获取指定标号的 u32 类型数据值 ( 无符号 32
) ,比如某个属性有多个 u32 类型的值,那么就可以使用此函数来获取指定标号的数据值,此
函数原型如下:
int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        index:要读取的值标号。
        out_value:读取到的值
        返回值:0 读取成功,负值,读取失败, -EINVAL 表示属性不存在, -ENODATA 表示没有要读取的数据, -EOVERFLOW 表示属性值列表太小。
4 of_property_read_xxx_arry 函数
        函数中的 xxx 分别是读取属性中 u8、u16、u32 u64 类型的数组数据,比如大多数的 reg
性都是数组数据,可以使用这 4 个函数一次读取出 reg 属性中的所有数据。这四个函数的原型
如下:
int of_property_read_xxx_array(const struct device_node *np, const char *propname, xxx*out_values, size_t sz)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        out_value:读取到的数组值,分别为 u8 u16 u32 u64
        sz: 要读取的数组元素数量。
        返回值:0 ,读取成功,负值,读取失败, -EINVAL 表示属性不存在, -ENODATA 表示没
有要读取的数据, -EOVERFLOW 表示属性值列表太小
5 of_property_read_xxx  函数
        有些属性只有一个整形值,这四个函数就是用于读取这种只有一个整形值的属性, XXX 可以是分别用于读取 u8、u16、u32 u64 类型属性值,函数原型如下:
int of_property_read_ xxx (const struct device_node *np, const char *propname, xxx *out_value)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        out_value:读取到的数组值。
        返回值:0 ,读取成功,负值,读取失败, -EINVAL 表示属性不存在, -ENODATA 表示没有要读取的数据, -EOVERFLOW 表示属性值列表太小。
6 of_property_read_string 函数
of_property_read_string 函数用于读取属性中字符串值,函数原型如下:
int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)
函数参数和返回值含义如下:
        np:设备节点。
        proname: 要读取的属性名字。
        out_string:读取到的字符串值。
        返回值:0 ,读取成功,负值,读取失败
7 of_n_addr_cells 函数
of_n_addr_cells 函数用于获取 #address-cells 属性值,函数原型如下:
int of_n_addr_cells(struct device_node *np)
函数参数和返回值含义如下:
        np:设备节点。
        返回值:获取到的 #address-cells 属性值。
8 of_n_size_cells 函数
of_size_cells 函数用于获取 #size-cells 属性值,函数原型如下:
int of_n_size_cells(struct device_node *np)
函数参数和返回值含义如下:
        np:设备节点。
        返回值:获取到的 #size-cells 属性值。

5.4其他常用的函数

1 of_device_is_compatible 函数
of_device_is_compatible 函数用于查看节点的 compatible 属性是否有包含 compat 指定的字
符串,也就是检查设备节点的兼容性,函数原型如下:
int of_device_is_compatible(const struct device_node *device, const char *compat)
函数参数和返回值含义如下:
        device:设备节点。
        compat:要查看的字符串。
        返回值:0 ,节点的 compatible 属性中不包含 compat 指定的字符串;正数,节点的 compatible 属性中包含 compat 指定的字符串。
2 of_get_address 函数
of_get_address 函数用于获取地址相关属性,主要是“ reg ”或者“ assigned-addresses ”属性
值,函数原型如下:
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags)
函数参数和返回值含义如下:
        dev:设备节点。
        index:要读取的地址标号。
        size:地址长度。
        flags:参数,比如 IORESOURCE_IO IORESOURCE_MEM
        返回值:读取到的地址数据首地址,为 NULL 的话表示读取失败。
3 of_translate_address 函数
of_translate_address 函数负责将从设备树读取到的地址转换为物理地址,函数原型如下:
u64 of_translate_address(struct device_node *dev,const __be32*in_addr)
函数参数和返回值含义如下:
        dev:设备节点。
        in_addr:要转换的地址。
        返回值:得到的物理地址,如果为 OF_BAD_ADDR 的话表示转换失败
4 of_address_to_resource 函数
of_address_to_resource 函数是从设 备树里面提取资源值,但是本质上就是将 reg 属性值,然后将其转换为 resource 结构体类型, 函数原型如下所示
int of_address_to_resource(struct device_node *dev, int index, struct resource *r)
函数参数和返回值含义如下:
        dev:设备节点。
        index:地址资源标号。
        r:得到的 resource 类型的资源值。
        返回值:0 ,成功;负值,失败
5 of_iomap 函数
of_iomap 函数用于直接内存映射,在驱动程序的编写中会通过 ioremap 函数来完成物理地址到虚拟地址的映射,采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址,不需要使用 ioremap 函数了。当然也可以使用 ioremap 函数来完成物理地址到虚拟地址 的内存映射,只是在采用设备树以后,大部分的驱动都使用 of_iomap 函数了。 of_iomap 函数本 质上也是将 reg 属性中地址信息转换为虚拟地址,如果 reg 属性有多段的话,可以通过 index 参 数指定要完成内存映射的是哪一段, of_iomap 函数原型如下:
void __iomem *of_iomap(struct device_node *np, int index)
函数参数和返回值含义如下:
        np:设备节点。
        index reg 属性中要完成内存映射的段,如果 reg 属性只有一段的话 index 就设置为 0
        返回值:经过内存映射后的虚拟内存首地址,如果为 NULL 的话表示内存映射失败。

小结

        到此对于设备树的相关认识就大致总结到这里,在设备树的相关知识中,个人认为重点内容有如下几点:设备树语法、设备树的操作函数、等内容。

这篇关于对设备树、DTS语法、设备树中常用函数 的认识(简单总结)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1135066

相关文章

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

使用PyQt5编写一个简单的取色器

《使用PyQt5编写一个简单的取色器》:本文主要介绍PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16进制颜色编码,一款跟随鼠标刷新图像的RGB和16... 目录取色器1取色器2PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16

四种简单方法 轻松进入电脑主板 BIOS 或 UEFI 固件设置

《四种简单方法轻松进入电脑主板BIOS或UEFI固件设置》设置BIOS/UEFI是计算机维护和管理中的一项重要任务,它允许用户配置计算机的启动选项、硬件设置和其他关键参数,该怎么进入呢?下面... 随着计算机技术的发展,大多数主流 PC 和笔记本已经从传统 BIOS 转向了 UEFI 固件。很多时候,我们也

Oracle的to_date()函数详解

《Oracle的to_date()函数详解》Oracle的to_date()函数用于日期格式转换,需要注意Oracle中不区分大小写的MM和mm格式代码,应使用mi代替分钟,此外,Oracle还支持毫... 目录oracle的to_date()函数一.在使用Oracle的to_date函数来做日期转换二.日

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

Java 枚举的常用技巧汇总

《Java枚举的常用技巧汇总》在Java中,枚举类型是一种特殊的数据类型,允许定义一组固定的常量,默认情况下,toString方法返回枚举常量的名称,本文提供了一个完整的代码示例,展示了如何在Jav... 目录一、枚举的基本概念1. 什么是枚举?2. 基本枚举示例3. 枚举的优势二、枚举的高级用法1. 枚举