linux驱动:(17)设备树中常用的of操作函数

目录

device_node结构体

property结构体

获取设备树节点里面的资源步骤

函数

of_find_node_by_path函数

of_get_parent函数

of_get_next_child函数

of_property_read_uX函数

 of_property_read_uX_array函数

of_property_read_string函数

of_get_named_gpio函数

实例

读取节点的名称

读取节点的compatible属性(u32)

读取节点的reg属性(u32数组)

读取节点的ststus属性(字符串)


在设备树中如何获取到寄存器的值呢,linux提供了几个函数,在 include/linux/of.h 中

都是以 of 开头的

device_node结构体

设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的其他属性信息,必须先获取到这个设备的节点。Linux 内核使用 device_node 结构体来描述一个节点,此结构体定义在文件 include/linux/of.h 中,定义如下

struct device_node{
    const char *name;//节点名字
    const char *type;//设备类型
    phandle phandle;
    const char *full_name;//节点全名
    struct fwnode_handle fwnode;
    struct property *properties;//属性
    struct property *deadprops;//removed属性
    struct device_node *parent;//父节点
    struct device_node *child;//子节点
    struct device_node *sibling;
    struct kobject kobj;
    unsigned long_flags;
    void *data;
    #if defined(CONFIG_SPACE)
        const char *path_component_name;
        unsigned int unique_id;
        struct of_irg_controller *irg_trans;
    #endif
}

property结构体

节点的属性信息里面保存了驱动所需要的内容,因此对于属性值的提取非常重要,Linux内核中使用结构体 property 表示属性,此结构体同样定义在文件 include/linux/of.h 中,内容如下:

struct property{
    char *name;//属性名字
    int length;//属性长度
    void *value;//属性值
    struct property *next;//下一个属性
    unsigned long_flags;
    unsigned int unique_id;
    struct bin_attribute attr;
}

获取设备树节点里面的资源步骤

  • 查找我们要找的节点
  • 获取我们需要的属性

函数

of_find_node_by_path函数

  • 作用:函数通过路径来查找指定的节点
  • 原型
    inline struct device_node *of_find_node_by_path(const char *path)
  • 参数
    • path:带有全路径的节点名,可以使用节点的别名
  • 返回值:返回找到的节点,失败返回NULL

of_get_parent函数

  • 作用:用于获取指定节点的父节点
  • 原型
    struct device_node *of_get_parent(const struct device_node *node)
  • 参数
    • node:要查找的父节点的节点
  • 返回值:找到的父节点

of_get_next_child函数

  • 作用:用迭代的方式查找子节点
  • 原型
    struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev)
  • 参数
    • node:要查找的父节点的节点
    • prev:前一个子节点,
  • 返回值:找到的父节点

of_property_read_uX函数

X可以为8,16,32,64

  • 作用:分别读取u8,u16,u32,u64类型的属性值
  • 原型
int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)
int of_property_read_u16(const struct device_node *np,const char *propname,u16 *out_value)
int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value)
int of_property_read_u64(const struct device_node *np,const char *propname,u64 *out_value)
  • 参数
    • np:设备节点
    • proname:要读取的属性名字
    • out_vlaue:读取到的数组值
  • 返回值:0读取成功,负数读取失败

 of_property_read_uX_array函数

X可以为8,16,32,64

  • 作用:分别读取属性中的数组数据
  • 原型
    int of_property_read_u8_array(const struct device_node *np,const char *propname,u8 *out_values,size_t sz)
    int of_property_read_u16_array(const struct device_node *np,const char *propname,u16 *out_values,size_t sz)
    int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_values,size_t sz)
    int of_property_read_u64_array(const struct device_node *np,const char *propname,u64 *out_values,size_t sz)
    
  • 参数
    • np:设备节点
    • proname:要读取的属性名字
    • out_vlaue:读取到的数组值
    • sz:读取数组的元素数量
  • 返回值:0读取成功,负数读取失败  

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读取成功,负数读取失败

of_get_named_gpio函数

  • 作用:此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio1 3 GPIO_ACTIVE_LOW>的属性信息转换为对应的GPIO 编号(后面第19章节会用到)
  • 原型
    int of_get_named_gpio(struct device_node *np,const char *propname,int index)
  • 参数
    • np:设备节点
    • propname:包含要获取 GPIO 信息的属性名
    • index:因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO 的编号,如果只有一个 GPIO 信息的话此参数为 0。
  • 返回值:成功返回到的 GPIO 编号,失败返回一个负数。

实例

在linux驱动:(16)在设备树添加自定义节点中我们写了一个自定义节点

读取节点的名称

  • 新建一个结构体指针来存放我们获取到的节点信息
  • 用of_find_node_by_path函数查找路径下的节点保存到结构体里
  • 输出出来
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>

struct device_node *test_device_node;


static int driver_inti(void)
{
    printk("driver hello \n");
    //获取节点的名称
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node==NULL)
    {
        printk("of_find_node_by_path error \n");
        return -1;
    }
    printk("test_device_node is %s\n",test_device_node->name);
    return 0;
}
static void driver_exit(void)
{
    printk("byb byb \n");
}

module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");

编译成ko,然后放到开发板中加载,就可以打印出test节点的名称

读取节点的compatible属性(u32)

  • 定义属性结构体
  • 调用函数获取
  • 打印属性的名字和数据
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>

int size;

struct device_node *test_device_node;
struct property *test_node_property;


static int driver_inti(void)
{
    printk("driver hello \n");
    //获取节点的名称
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node==NULL)
    {
        printk("of_find_node_by_path error \n");
        return -1;
    }
    printk("test_device_node is %s\n",test_device_node->name);
    //读取节点的compatible属性
    test_node_property = of_find_property(test_device_node,"compatible",&size);
    if (test_node_property==NULL)
    {
        printk("of_find_property error \n");
        return -1;
    }
    printk("of_find_property is %s\n",test_node_property->name);
    printk("compatible is %s\n",(char *)test_node_property->value);
    return 0;
}
static void driver_exit(void)
{
    printk("byb byb \n");
}

module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");

编译成ko,然后放到开发板中加载,就可以打印出test节点的名称和compatible属性和compatible属性的值

读取节点的reg属性(u32数组)

  • 定义u32位的数组,因为reg属性我们定义的是32位,数组长度为2
  • 调用函数来获取到数据放到数组中
  • 打印
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>

int size;
u32 out_value[2]={0};

struct device_node *test_device_node;
struct property *test_node_property;


static int driver_inti(void)
{
    printk("driver hello \n");
    //获取节点的名称
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node==NULL)
    {
        printk("of_find_node_by_path error \n");
        return -1;
    }
    printk("test_device_node is %s\n",test_device_node->name);
    //读取节点的compatible属性
    test_node_property = of_find_property(test_device_node,"compatible",&size);
    if (test_node_property==NULL)
    {
        printk("of_find_property error \n");
        return -1;
    }
    printk("of_find_property is %s\n",test_node_property->name);
    printk("compatible is %s\n",(char *)test_node_property->value);
    //读取节点的 reg 属性
    int ret;
    ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
    if (ret < 0)
    {
        printk("of_property_read_u32_array error \n");
        return -1;
    }
    printk("out_value[0] is 0x%08x\n",out_value[0]);
    printk("out_value[1] is 0x%08x\n",out_value[1]);
    return 0;
}
static void driver_exit(void)
{
    printk("byb byb \n");
}

module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");

编译成ko,然后放到开发板中加载,就可以打印出test节点的名称和compatible属性和compatible属性的值,并输出reg中的两个值

读取节点的ststus属性(字符串)

  • 定义字符串指针
  • 调用函数获取属性的值放到指针里
  • 打印
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>

int size;
u32 out_value[2]={0};
const char* str;

struct device_node *test_device_node;
struct property *test_node_property;


static int driver_inti(void)
{
    printk("driver hello \n");
    //获取节点的名称
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node==NULL)
    {
        printk("of_find_node_by_path error \n");
        return -1;
    }
    printk("test_device_node is %s\n",test_device_node->name);
    //读取节点的compatible属性
    test_node_property = of_find_property(test_device_node,"compatible",&size);
    if (test_node_property==NULL)
    {
        printk("of_find_property error \n");
        return -1;
    }
    printk("of_find_property is %s\n",test_node_property->name);
    printk("compatible is %s\n",(char *)test_node_property->value);
    //读取节点的 reg 属性
    int ret;
    ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
    if (ret < 0)
    {
        printk("of_property_read_u32_array error \n");
        return -1;
    }
    printk("out_value[0] is 0x%08x\n",out_value[0]);
    printk("out_value[1] is 0x%08x\n",out_value[1]);
    //读取节点的 status 属性
    ret = of_property_read_string(test_device_node,"status",&str);
    if (ret < 0)
    {
        printk("of_property_read_string error \n");
        return -1;
    }
    printk("of_property_read_string is &s\n",str);
    return 0;
}
static void driver_exit(void)
{
    printk("byb byb \n");
}

module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");

编译成ko,然后放到开发板中加载,就可以打印出test节点的名称和compatible属性和compatible属性的值,并输出reg中的两个值,并输出status属性的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码农小白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值