• linux 设备树of函数学习笔记


    上一篇对dts设备树有了初步的了解,完全手写设备树目前还打不到这样的实力,还好的就是技术的开放性,很多设备都有dts模板,可以更改适配。​

    活动地址:CSDN21天学习挑战赛

    学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您:
    想系统/深入学习某技术知识点…
    一个人摸索学习很难坚持,想组团高效学习…
    想写博客但无从下手,急需写作干货注入能量…
    热爱写作,愿意让自己成为更好的人…

    ​本篇文章讲述的是设备树的解析函数,就是of系列函数,参考网址:

    DeviceTree Kernel API — The Linux Kernel documentation

    Linux device tree API (programs.wiki)

    在学习这部分知识的时候,发现很多人都写好了,资料也特别多,想看源码的话,参考下面的链接:包含了各个版本的linux内核代码,每一个函数参考起来会跳来跳去,充分体现了数据结构组织的好,代码写得少的哲学关系。

    of.h - include/linux/of.h - Linux source code (v2.6.39.4) - Bootlin

    根据上课所用的教学PPT,大约有这么多函数。

     以下内容为翻译的wiki,可以直接看原文,只是为了学习和打卡,望读者见谅。

    Linux内核采用设备树后,驱动需要获取设备树的属性。 Linux内核提供了一系列API函数供驱动获取设备树的属性。 Linux 内核中的“Of_” 从设备树 API 开始。

    首先看一下device_node结构体定义:

    1. struct device_node {
    2. const char *name;
    3. const char *type;
    4. phandle phandle; // 这是一个u32的数据
    5. char *full_name;
    6. struct property *properties;
    7. struct property *deadprops; /* removed properties */
    8. struct device_node *parent;
    9. struct device_node *child;
    10. struct device_node *sibling;
    11. struct device_node *next; /* next device of same type */
    12. struct device_node *allnext; /* next in list of all nodes */
    13. struct proc_dir_entry *pde; /* this node's proc directory */
    14. struct kref kref;
    15. unsigned long _flags;
    16. void *data;
    17. #if defined(CONFIG_SPARC)
    18. char *path_component_name;
    19. unsigned int unique_id;
    20. struct of_irq_controller *irq_trans;
    21. #endif
    22. };

    1.获取设备节点API
    在内核中,设备是以节点的形式附加到设备树上的,所以要获取设备信息,首先要获取设备节点。

    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。

    1.2、of_find_node_by_type函数
    of_find_node_by_type函数通过节点类型获取设备节点

    struct device_node *of_find_node_by_type(struct device_node *from,const char *type)

    From:指定从哪里开始搜索设备节点。 如果为 NULL,则从根节点开始搜索。
    type:要查找的设备节点的类型,device_type属性值。
    成功返回设备节点结构,失败返回NULL。

    1.3、of_find_compatible_node函数
    of_find_compatible_node函数通过节点的compatible属性和类型获取设备节点

    struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compatible)

    From:指定从哪里开始搜索设备节点。 如果为 NULL,则从根节点开始搜索。
    type:要查找的设备节点的类型。 如果为 NULL,则类型将被忽略。
    Compatible:要查找的设备节点的兼容属性名称。
    成功返回设备节点结构,失败返回NULL。

    1.4、of_find_node_by_path函数
    of_find_node_by_path函数通过路径名获取设备节点

    struct device_node *of_find_node_by_path(const char *path)

    Path: path name
    The device node structure is returned successfully, and NULL is returned for failure.

    2.获取父子节点API

    2.1,of_get_parent function

    struct device_node *of_get_parent(const struct device_node *node)

    Node:要查找的父节点的节点
    该节点的父节点返回成功,失败则返回NULL

    2.2,of_get_next_child function
    of_get_next_child函数可以循环遍历子节点

    1. struct device_node *of_get_next_child(const struct device_node *node,
    2. struct device_node *prev)

    node:父节点
    prev:上一个子节点,即从哪个子节点开始搜索。 NULL 表示从第一个开始搜索。
    返回值是找到的下一个子节点.

    3.提取设备树属性API
    设备树中的属性在内核中以结构的形式表示。 下面是属性结构.

    1. struct property {
    2. char *name; // name
    3. int length; // length
    4. void *value; // Attribute value
    5. struct property *next; // Next attribute
    6. unsigned long _flags;
    7. unsigned int unique_id;
    8. struct bin_attribute attr;
    9. };

    3.1 of_find_property function

    of_find_property function能够获得指定的属性

    1. struct property *of_find_property(const struct device_node *np,
    2. const char *name,
    3. int *lenp)

    np: device node
    Name: attribute name
    lenp: attribute length
    example:

    of_find_property(client->dev.of_node, "linux,gpio-keymap",&proplen)

    上述代码段通过of_find_属性函数获取设备中属性“Linux, GPIO keymap”的值。

    3.2,of_property_read_u32_index function

    of_property_read_u32_index 读取设备树中属性为 32 位无符号的值。 您可以指定要读取的标签。

    1. int of_property_read_u32_index(const struct device_node *np,
    2. const char *propname,
    3. u32 index, u32 *out_value)

    np:设备节点
    propname:属性名称
    index:标签,读取数字
    out_value; 读出值
    返回值:0 读取成功,-EINVAL 表示属性不存在,-ENODATA 表示没有数据可读取,-EOVERFLOW 表示属性值列表太小。

    3.3,of_property_read_u8_array of_property_read_u16_array of_property_read_u32_array of_property_read_u64_array

    of_property_read_u8_array
    of_property_read_u16_array
    of_property_read_u32_array
    of_property_read_u64_array
    These four functions can read unsigned data at one time, such as address data in reg attribute.

    1. int of_property_read_u8_array(const struct device_node *np,
    2. const char *propname, u8 *out_values, size_t sz)
    3. int of_property_read_u16_array(const struct device_node *np,
    4. const char *propname, u16 *out_values, size_t sz)
    5. int of_property_read_u32_array(const struct device_node *np,
    6. const char *propname, u32 *out_values,
    7. size_t sz)
    8. int of_property_read_u64_array(const struct device_node *np,
    9. const char *propname, u64 *out_values,
    10. size_t sz)

    np:设备节点
    propname:属性名称
    out_values:读出值
    sz:读取多少数据
    返回值:0,读取成功,-EINVAL表示该属性不存在,-ENODATA表示不存在
    有数据要读取,- EOVERFLOW 表示属性值列表太小。

    3.4,of_property_read_u8 of_property_read_u16 of_property_read_u32 of_property_read_u64

    1. int of_property_read_u8(const struct device_node *np,
    2. const char *propname,
    3. u8 *out_value)
    4. int of_property_read_u16(const struct device_node *np,
    5. const char *propname,
    6. u16 *out_value)
    7. int of_property_read_u32(const struct device_node *np,
    8. const char *propname,
    9. u32 *out_value)
    10. int of_property_read_u64(const struct device_node *np,
    11. const char *propname,
    12. u64 *out_value)

    这些函数用于读取属性值
    np:设备节点
    propname:属性名称
    out_values:读出值
    返回值:0,读取成功,-EINVAL表示该属性不存在,-ENODATA表示不存在
    有数据要读取,- EOVERFLOW 表示属性值列表太小。

    3.5,of_property_read_string

    of_property_read_string is used to get the string

    1. int of_property_read_string(struct device_node *np, const char *propname,
    2. const char **out_string)

    np:设备节点
    propname:属性名称
    out_string:读取字符串
    返回值:0,读取成功,负值,读取失败。

    3.6,of_n_addr_cells
    of_n_addr_cells is used to get the address_cells attribute value

    int of_n_addr_cells(struct device_node *np)

    np:设备节点
    返回值:#address 单元格属性的获取值。

    3.7,of_n_size_cells

    of_n_size_cells is used to get the size cells attribute value

    int of_n_size_cells(struct device_node *np)

    np:设备节点
    返回值:#size 个单元格属性的获取值。

    4.其他常用的设备树API函数
    IIC、SPI、GPIO等外设都有自己的寄存器地址,而这些寄存器地址实际上是一组内存空间。 Linux内核提供了设备树的一些API函数来获取这些寄存器地址。

    4.1 获取设备资源
    Linux内核将寄存器、中断等信息描述为一组内存资源,用一个结构体表示

    1. struct resource {
    2. resource_size_t start; // Starting address
    3. resource_size_t end; // End address
    4. const char *name; // name
    5. unsigned long flags; // attribute
    6. struct resource *parent, *sibling, *child;
    7. };

    flags 用于表示资源类型,可以包括以下资源类型

    1. #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
    2. #define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
    3. #define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */
    4. #define IORESOURCE_MEM 0x00000200
    5. #define IORESOURCE_REG 0x00000300 /* Register offsets */
    6. #define IORESOURCE_IRQ 0x00000400
    7. #define IORESOURCE_DMA 0x00000800
    8. #define IORESOURCE_BUS 0x00001000
    9. #define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
    10. #define IORESOURCE_READONLY 0x00004000
    11. #define IORESOURCE_CACHEABLE 0x00008000
    12. #define IORESOURCE_RANGELENGTH 0x00010000
    13. #define IORESOURCE_SHADOWABLE 0x00020000
    14. #define IORESOURCE_SIZEALIGN 0x00040000 /* size indicates alignment */
    15. #define IORESOURCE_STARTALIGN 0x00080000 /* start field is alignment */
    16. #define IORESOURCE_MEM_64 0x00100000
    17. #define IORESOURCE_WINDOW 0x00200000 /* forwarded by bridge */
    18. #define IORESOURCE_MUXED 0x00400000 /* Resource is software muxed */
    19. #define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
    20. #define IORESOURCE_DISABLED 0x10000000
    21. #define IORESOURCE_UNSET 0x20000000 /* No address assigned yet */
    22. #define IORESOURCE_AUTO 0x40000000
    23. #define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */

    of_ address_ to_ The resource function is used to obtain resources

    1. int of_address_to_resource(struct device_node *node, int index,
    2. struct resource *r)

    节点:设备节点
    index:获取的资源数量
    r:获取资源结构
    返回值:0,成功; 负值,失败。

    4.1、of_iomap
    of_iomap函数用于映射内存地址,将物理地址映射到虚拟地址。 过去没有设备树的时候,内存地址映射通常需要两步。 首先platform_get_resource获取资源,然后ioremap进行地址映射。 现在有了设备树,可以直接使用of_iomap同时进行资源获取和地址映射。

    1. void __iomem *of_iomap(struct device_node *np, int index)
    2. {
    3. struct resource res;
    4. if (of_address_to_resource(np, index, &res))
    5. return NULL;
    6. return ioremap(res.start, resource_size(&res));
    7. }

    np:设备节点
    index:你想获取哪个资源
    返回值:内存映射后的虚拟内存首地址。 如果为NULL,则表示内存映射失败。

    ========================================================================

    实际上内核写好了这些函数,所以我们学习的时候,可以不求甚解,会用就行。

  • 相关阅读:
    web手势库Alloyfinger
    如何从800万数据中快速捞出自己想要的数据?
    构造函数_XMLHttpRequest
    PowerShell:在代理服务器后面使用 PowerShell
    蓝牙技术|我国已成为全球最大新能源车市场,蓝牙技术起到重要作用
    软考高级系统架构设计师系列论文十八:论软件三层结构的设计
    Redis 配置文件信息中文翻译版
    技术速递|Java on Azure Tooling 5月更新 - Java 对 Azure 容器应用程序的入门指南支持
    【 C++ 】AVL树
    JVM基础03_运行时数据区
  • 原文地址:https://blog.csdn.net/weixin_41579872/article/details/126138811