Linux驱动开发笔记(五)——设备树(下)——OF函数

一、OF函数定义

第6.8讲 Linux设备树详解-绑定文档以及OF函数_哔哩哔哩_bilibili

《指南》43.9部分

        设备树的功能就是描述设备信息,帮助驱动开发。那么驱动如何获取设备信息?获取这些信息的函数linux直接提供,都定义在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/include/linux/of.h文件中。这些函数统一以of开头,也称为OF函数。

1.1 查找节点

        设备树上的设备都是一个个节点。要获取某个设备信息,需要先找到这个设备节点。Linux内核使用device_node结构体来描述一个节点:

// 定义在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/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_SPARC)const char *path_component_name;unsigned int unique_id;struct of_irq_controller *irq_trans;
#endif
};

1.1.1 of_find_node_by_name

        通过名字查找节点。名字是完整的node-name@unit-address,不是只有前半部分node-name,也不是label。

struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
// from:   从哪个节点开始查找。为NULL表示从根节点开始查找整个设备树
// name:   要查找节点的名字。名字不要包含label!   
// return: 找到的节点。返回NULL表示未找到

1.1.2 of_find_node_by_type

        通过device_type类型查找。不过现在device_type已经弃用,这个函数也很少再用。

struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
// from:   从哪个节点开始查找。为NULL表示从根节点开始查找整个设备树
// type:   要查找节点的device_type字符串
// return: 找到的节点。返回NULL表示未找到

1.1.3 of_find_compatible_node

        通过兼容性列表compatible查找

struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compat);
// from:   从哪个节点开始查找。为NULL表示从根节点开始查找整个设备树
// type:   要查找节点的device_type字符串。可以为NULL,表示忽略device_type属性
// compat: 要查找节点的compatible属性列表
// return: 找到的节点。返回NULL表示未找到
// eg: struct device_node *node;node = of_find_compatible_node(NULL, NULL, "arm,cortex-a7"); // 查找整个设备树上兼容arm,cortex-a7的设备节点

1.1.4 of_find_matching_node_and_match

        通过匹配列表查找

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
// return:  找到的节点。返回NULL表示未找到

1.1.5 of_find_node_by_path

        通过路径查找。这个路径指的是设备节点在设备树中的路径,不是文件路径。

static inline struct device_node *of_find_node_by_path(const char *path)
// path:   带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是根节点下backlight节点的全路径。 
// return: 找到的节点。返回NULL表示未找到
//eg:
struct device_node *np;
np = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000");

1.2 查找父/子节点

1.2.1 of_get_parent

获取指定节点的父节点

struct device_node *of_get_parent(const struct device_node *node)
// node  : 要查找父节点的节点
// return: 找到的父节点。NULL表示未找到

1.2.2 of_get_next_child

获取指定节点的子节点

struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)
// node  : 要查找子节点的节点
// prev  : 前一个子节点。一个节点下有很多子节点,可以设置从哪一个子节点开始查找
//         可以设置为NULL,表示从第一个子节点开始
// return: 找到的子节点

1.3 提取属性值

        通过前面两类函数找到了目标节点,现在可以开始获得指定节点的具体属性了。

1.3.1 of_find_property

        查找指定的属性。

static inline struct property *of_find_property(const struct device_node *np,const char *name, int *lenp)
// np    : 节点
// name  : 属性名
// lenp  : 属性值的字节长度,一般写NULL即可
// return: 找到的属性

Linux内核中使用结构体property表示属性,其中property结构为:

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

 1.3.2 of_property_count_elems_of_size

        获取属性中元素的数量。比如reg属性值(如reg = <0x80000000 0x20000000>;)是一个数组,那么使用此函数可以获取到这个数组的大小(2)。

int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)
// np       : 节点
// proname  : 需要统计元素数量的属性名字
// elem_size:每一个元素的size
// return   : 得到的属性元素数量

1.3.3 of_property_read_u32_index

        用于从属性中获取指定索引的u32类型数据值。

        比如某个属性有多个u32类型的值,那么就可以使用此函数来获取指定索引的数据值。

static inline int of_property_read_u32_index(const struct device_node *np,const char *propname, u32 index, u32 *out_value)
// np       : 节点
// proname  : 要读取的属性名
// index    : 要读取的值的索引
// out_value: 读取到的值
// return   : 0成功。负值失败:-EINVAL属性不存在,-ENODATA表示要读取的数据,-EOVERFLOW属性值列表太小

1.3.4 of_property_read_u8_array

        用于读取一个u8类型数组属性的所有数据。

        类似的函数还有of_property_read_u16_array、of_property_read_u32_array、of_property_read_u64_array,表示不同的数组类型。

int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)
// np        : 节点
// propname  : 要读取的属性名
// out_values: 读取到的数组
// sz        : 要读取的数组元素数量
// return    : 0成功。负值失败:-EINVAL属性不存在,-ENODATA没有要读取的数据,-EOVERFLOW属性值列表太小。

1.3.5 of_property_read_u8

        除了数组属性以外,很多属性只有一个整形值。该函数用于读取这种只有一个u8整形值的属性。

        类似的函数还有of_property_read_u16、of_property_read_u32、of_property_read_u64。

int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)
// np        : 节点
// propname  : 要读取的属性名
// out_values: 读取到的值
// return    : 0成功。负值失败:-EINVAL属性不存在,-ENODATA没有要读取的数据,-EOVERFLOW属性值列表太小。

1.3.6 of_property_read_string

        用于读取字符串类型属性的值

int of_property_read_string(struct device_node *np,const char *propname, const char **out_string)
// np        : 节点
// propname  : 要读取的属性名
// out_string: 读取到的字符串
// return    : 0成功。负值失败

1.3.7 of_n_addr_cells

        获取#size-cells的值

int of_n_addr_cells(struct device_node *np);
// np    : 节点
// return: 获取到的#size-cells的值

1.3.8 of_n_size_cells

        获取#size-cells的值

int of_n_size_cells(struct device_node *np)、
// np    : 节点
// return: 获取到的#size-cells的值

二、OF函数实际使用

第6.9讲 Linux设备树详解-OF函数操作实验_哔哩哔哩_bilibili

2.1 文件结构

        新建实验4文件夹4_dtsof,直接将之前实验3文件夹3_newchrled里的Makefile、newchrled.c、.vscode复制到新的文件夹里。将newchrled.c改名为dtsof.c。

        用vscode打开4_dtsof,将工作区另存为。

4_DTSOF (工作区)
├── .vscode
│   ├── c_cpp_properties.json
│   └── settings.json
├── 4_dtsof.code-workspace
├── Makefile
└── dtsof.c

        将Makefile中的obj-m修改为obj-m := dtsof.o

2.2 dtsof.c

2.2.1获取backlight的compatible属性值

imx6ull-alientek-emmc.dts中backlight的定义如下:

	backlight {compatible = "pwm-backlight";pwms = <&pwm1 0 5000000>;brightness-levels = <0 4 8 16 32 64 128 255>;default-brightness-level = <6>;status = "okay";};

 编写dtsof.c,获取backlight的compatible属性值:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>/* 模块入口 */
static int __init dtsof_init(void){int ret = 0;struct device_node *backlight_nd; // 节点指针struct property *comppro;         // 属性指针// 查找backlight节点 // 路径为/backlight   定义在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts/imx6ull-alientek-emmc.dtsbacklight_nd = of_find_node_by_path("/backlight"); //路径查找if(backlight_nd == NULL){ // 失败ret = -EINVAL;goto fail_findnd; // 错误处理}// 查找backlight属性comppro = of_find_property(backlight_nd, "compatible", NULL); // 属性名查找if(comppro == NULL){ret = -EINVAL;goto fail_finpro; // 错误处理} else {printk("compatible = %s\r\n",(char*)comppro->value);}return 0;fail_finpro:   // 查找属性失败
fail_findnd:  // 查找节点失败printk("failed\r\n");return ret;
}/* 模块出口 */
static void __exit dtsof_exit(void){}/* 注册入口出口*/
module_init(dtsof_init);
module_exit(dtsof_exit);
MODULE_LICENSE("GPL");

# VSCODE终端
make
sudo cp dtsof.ko /home/for/linux/nfs/rootfs/lib/modules/4.1.15/ -f# 串口
cd lib/modules/4.1.15/
modprobe dtsof.ko
depmod
modprobe dtsof.ko  # 可以看到输出:compatible = pwm-backlight
rmmod dtsof.ko

2.2.2获取backlight的所有属性值

        上面的代码只简单演示了一下使用OF函数获取compatible属性值。要获取backlight的所有属性值,完整代码如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/slab.h>/* 模块入口 */
static int __init dtsof_init(void){int ret = 0;struct device_node *backlight_nd;// 节点指针struct property *comppro;        // 保存compatible属性const char* status;              // 保存status属性u32 default_brightness_level;    // 保存default-brightness-level属性u32 count = 0;                   // 保存brightness-levels属性的元素数量u32 *brightness_levels;          // 保存brightness-levels属性的数据u8 i = 0;                        // 给for循环用的// 1.查找backlight节点======================================================================// 路径为/backlight   // 定义在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts/imx6ull-alientek-emmc.dtsbacklight_nd = of_find_node_by_path("/backlight"); //路径查找if(backlight_nd == NULL){ // 失败ret = -EINVAL;goto faile_findnd;}// 2.查找backlight属性======================================================================// 获取compatible属性(属性名查找)comppro = of_find_property(backlight_nd, "compatible", NULL);if(comppro == NULL){ret = -EINVAL;goto fail_finpro;} else {printk("compatible = %s\r\n",(char*)comppro->value);}// 获取status属性(读取字符串)ret = of_property_read_string(backlight_nd, "status", &status);if(ret < 0){goto fail_finprs;} else {printk("status = %s\r\n", status);}// 获取default-brightness-level属性(读取u32)ret = of_property_read_u32(backlight_nd, "default-brightness-level", &default_brightness_level);if(ret < 0){goto fail_read32;} else {printk("default-brightness-level = %d\r\n", default_brightness_level);}// 获取brightness-levels的元素个数(读取元素个数)count = of_property_count_elems_of_size(backlight_nd, "brightness-levels", sizeof(u32));if(count < 0){goto fail_readele;} else {printk("brightness-level elems size = %d\r\n", count);// 获取brightness-levels的数据(读取u32数组)brightness_levels = kmalloc(count * sizeof(u32), GFP_KERNEL); // 内存申请if(!brightness_levels){ goto fail_mem;}ret = of_property_read_u32_array(backlight_nd, "brightness-levels", brightness_levels, count);if(ret < 0){goto fail_readarr; // 错误处理统一放到goto里面去,因此这里不释放内存,而是放到goto去处理} else {printk("brightness-level elems = ");for(i=0;i<count;i++){printk("%d ",brightness_levels[i]);}printk("\r\n");kfree(brightness_levels);}}return 0;/* 错误处理 */
// 这里goto只是演示一下格式,并不详细处理fail_readarr:  // 读取brightness-levels数据失败kfree(brightness_levels); //释放内存
fail_mem:          // 内存分配失败
fail_readele:      // 读取元素数量失败
fail_read32:       // 读取default-brightness-level失败
fail_finprs:       // 读取status失败
fail_finpro:       // 查找compatible失败
faile_findnd:      // 查找节点失败printk("failed\r\n");return ret;
}/* 模块出口 */
static void __exit dtsof_exit(void){}/* 注册入口出口*/
module_init(dtsof_init);
module_exit(dtsof_exit);
MODULE_LICENSE("GPL");

        modprobe以后应当能看到以下内容: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91441.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91441.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

8.2-使用字符串存储 UTF-8 编码文本

使用字符串存储 UTF-8 编码文本 我们在第4章讨论过字符串&#xff0c;但现在将更深入地探讨它们。新手 Rustacean 常常因为三个原因而卡在字符串上&#xff1a;Rust 倾向于暴露可能的错误、字符串比许多程序员想象的要复杂得多&#xff0c;以及 UTF-8。这些因素结合起来&#x…

以AI大模型重构教育新生态,打造“教-学-练-辅-评”一体化智能平台

在《中国教育现代化2035》与“教育新基建”政策驱动下&#xff0c;教育数字化转型已进入深水区。如何将AI技术深度融合于教学全流程&#xff0c;实现从“标准化”到“个性化”的跨越&#xff1f;文渊智阁推出的 AI教学大模型建设方案 &#xff0c;以“数据驱动AI潜能&#xff0…

AI在法律合同内容比对的应用实例

在商业世界的复杂交易中&#xff0c;合同是至关重要的法律保障。然而&#xff0c;随着业务的扩展&#xff0c;合同数量呈指数级增长&#xff0c;合同条款也日趋复杂。对于法务和商务团队来说&#xff0c;如何高效、准确地进行合同比对&#xff0c;成为一个亟待解决的难题。传统…

【Maven】Maven多模块拆分与依赖隔离 的终极深度解析,从 原子级配置 到 企业级架构设计,涵盖 8大核心维度

Maven多模块拆分与依赖隔离 的终极深度解析&#xff0c;从 原子级配置 到 企业级架构设计&#xff0c;涵盖 8大核心维度一、模块化工程结构设计&#xff08;黄金法则&#xff09;1. 分层架构模板2. 依赖流向控制矩阵二、依赖隔离的原子级配置1. 严格依赖管理&#xff08;父POM&…

大模型流式长链接场景下 k8s 优雅退出 JAVA

一、 java bootstrap.yml bootstrap.yml 启动文件增加timeout-per-shutdown-phase spring:lifecycle:timeout-per-shutdown-phase: 30m# 这个值是故意设置这么大的&#xff0c;因为现在推理服务支持深度思考# 为了保证用户侧的连接不被断开&#xff0c;因此我们需要设置超大 g…

uni-app用css编写族谱树家谱树

需求背景&#xff1a;公司接到一个项目&#xff0c;是需要做一个族谱微信小程序&#xff0c;需要有族谱树&#xff0c;且可以添加家族人员。 灵感来源&#xff1a;在插件市场中下载了作者 羊羊不想写代码 的插件tree-list族谱&#xff0c;树形列表&#xff0c;可缩放滑动 - DC…

思途JSP学习 0731

继0730&#xff0c;我们对项目做最后的升级一、删除功能1、新增复选框辅助删除条目的选择修改我们的list.jsp和list.js在列表的第一列增加一列选择框2、给复选框添加全选与行点击选择功能在行选择功能中&#xff0c;因为此时的选择框还未生成&#xff0c;所以我们将事件委托给他…

某讯视频风控参数逆向分析

文章目录1. 写在前面2. 接口分析3. 加密分析4. 扣JS代码【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力…

[Broken IOS] 配置CLI | 终端用户界面TUI

链接&#xff1a;https://palera.in/ docs&#xff1a;palera1n palera1n 是一款专为 Jailbroken苹果设备 设计的强大工具&#xff0c;支持运行 iOS/iPadOS/tvOS 15.0 及更新系统 的 iPhone、iPad 和 Apple TV。 该工具通过 DFU 模式 下的底层 USB 通信引导设备&#xff0c;…

论文阅读|ArxiV 2024|Mamba进一步研究|VSSD

论文地址&#xff1a;pdf 代码地址&#xff1a;code 文章目录1.研究背景与动机2. 核心方法2.1 预备知识:mamba-ssm2.2 非因果状态空间对偶性2.3 视觉状态空间对偶性模型3. 实验结果3.1 图像分类任务3.2 目标检测任务3.3 语义分割任务3.4 消融实验4.局限性与结论4.1 局限性4.2 结…

Flutter中 Provider 的基础用法超详细讲解(二)之ChangeNotifierProvider

目录 前言 一、什么是ChangeNotifierProvider? 二、ChangeNotifier的简单用法 1.定义状态类 2.使用ChangeNotifierProvider提供状态 3.获取状态并监听更新 1.Consumer 2.通过API方式获取 1.Provider.of (context) 2.context.watch () 3.context.read () 4.各种获…

2025电商CPS分销与推客系统小程序开发:趋势、架构与实战解析

一、行业趋势&#xff1a;CPS模式与社交电商的深度融合1.1 电商行业新趋势根据《2025年电子商务行业发展趋势预测报告》&#xff0c;社交电商与内容营销已成为核心增长点。消费者行为呈现三大特征&#xff1a;消费习惯转变&#xff1a;线上购物占比超70%&#xff0c;Z世代用户更…

Conda环境下配置的基本命令

功能命令创建环境conda create -n myenv python3.11激活环境conda activate myenv删除环境conda env remove -n myenv复制环境conda create -n newenv --clone myenv列出所有环境conda env list列出环境所有包conda list彻底清除某个 Conda 环境中的所有已安装包&#xff08;但…

Ps2025

快捷键CShs保存CSw存储为S选取叠加选取,A选取减去选区C回车保存路径内容识别 SF5 ADel填充前景色CDel填充背景色A上下 上下行间距A左右 左右字间距C左键丝滑放大缩小CASE盖印图层C}上移一格CG新建组sF6羽化像素钢笔工具打上抹点&#xff0c;按住shift水平拉调增弧度左右两个手柄…

ceph sc 设置文件系统格式化参数

前言 默认的 sc 文件系统 inode 太少,对于小文件场景,往往会出现容量没满,inode 已经用尽的情况,本文说明如何设置 inode。 说明 本文使用的是 rook-ceph 部署的 ceph 作为存储后端。 xfs 文件系统 sc 创建带格式化参数的 xfs 文件系统的 sc allowVolumeExpansion: t…

【LY88】ubuntu下的常用操作

vscode 下载安装包 在安装包所处文件夹空白区域右键调出终端 输入下行命令安装 c后接tab自动补全安装包名称&#xff08;前提是该文件夹中仅这一个c开头文件&#xff0c;否则得再输点字母&#xff0c;保证其可唯一索引到&#xff09; sudo dpkg -i ctab安装完毕后输入code&…

web应用从服务器主动推动数据到客户端的方式

html5 websocket 全双工交互 全双工通信&#xff1a;建立持久连接&#xff0c;服务端和客户端可随时互相发送消息 低延迟&#xff1a;适合实时应用&#xff08;聊天、游戏、股票行情等&#xff09; socket协议是与HTTP协议平级的&#xff0c;websocket协议是建立在TCP协议之上的…

基于Spring Boot实现中医医学处方管理实践

基于Spring Boot实现中医医学处方管理 以下是基于Spring Boot实现中医医学处方管理的相关示例和资源整理,涵盖基础架构、功能模块及实际应用案例: 基础项目结构 Spring Boot中医处方系统通常采用MVC分层设计: 实体类:定义处方、药材、患者等JPA实体 @Entity public clas…

从“人工核验”到“智能鉴防”:护照鉴伪设备的科技革命

“一本伪造护照的查获成本从72小时降至3秒&#xff0c;背后是光学传感、量子加密与多模态AI的十年协同进化。”2025年全球边检口岸查获伪假护照近500份&#xff0c;其中芯片伪造占比首超40%。当造假技术逼近分子级仿制&#xff0c;传统肉眼鉴别彻底失效&#xff0c;多光谱成像、…

无人机飞控系统3D (C++)实践

大疆无人机飞控系统3D模型开发 大疆无人机飞控系统3D模型开发(C++) 核心架构设计 大疆无人机的飞控系统通常采用分层架构,分为硬件抽象层(HAL)、中间件层和应用层。HAL负责与传感器/执行器直接交互,中间件处理数据融合和通信协议,应用层实现核心控制算法。 典型代码结…