当前位置: 首页 > news >正文

嵌入式Linux驱动开发 —— 从DTS到代码的桥梁与简单OF系列API(5)

接前一篇文章:嵌入式Linux驱动开发 —— 从DTS到代码的桥梁与简单OF系列API(4)

内存映射 API:如何将设备树地址转换为可访问的虚拟地址

前面讲了如何从设备树里读取地址值,但那些只是物理地址(或者总线地址)。驱动程序要访问这些地址,还需要把它们映射到内核虚拟地址空间。这一步通常用ioremap()来完成。

但OF API提供了更便捷的方法,把“读reg属性”和“ioremap”两步合成一步。

of_iomap:一步到位的地址映射

这是驱动里最常用的函数之一:

void __iomem *of_iomap(struct device_node *np, int index);

参数说明:

  • np:设备节点
  • index:reg属性的索引(从0开始)

返回值是映射后的内核虚拟地址,失败返回NULL

这个函数会自动完成以下步骤:

1)从reg属性里读取第index组地址;

2)处理地址转换(如果需要的话);

3)调用ioremap()建立映射。

我们的LED驱动用它来映射所有寄存器地址:

/* 5. 使用 of_iomap 进行寄存器地址映射 */ led.ccm_ccgr1 = of_iomap(led.device_tree_node, 0); led.sw_mux_gpio = of_iomap(led.device_tree_node, 1); led.sw_pad_gpio = of_iomap(led.device_tree_node, 2); led.gpio_dr = of_iomap(led.device_tree_node, 3); led.gpio_gdir = of_iomap(led.device_tree_node, 4); if (!led.ccm_ccgr1 || !led.sw_mux_gpio || !led.sw_pad_gpio || !led.gpio_dr || !led.gpio_gdir) { pr_err("ioremap failed!\n"); of_node_put(led.device_tree_node); return -ENOMEM; }

这里连续调用了5次of_iomap(),每次传入不同的索引。这些索引对应reg属性里的5组地址:

reg = < 0X020C406C 0X04 /* 索引 0: CCM_CCGR1_BASE */ 0X020E0068 0X04 /* 索引 1: SW_MUX_GPIO1_IO03_BASE */ 0X020E02F4 0X04 /* 索引 2: SW_PAD_GPIO1_IO03_BASE */ 0X0209C000 0X04 /* 索引 3: GPIO1_DR_BASE */ 0X0209C004 0X04 >; /* 索引 4: GPIO1_GDIR_BASE */

注意这里有个重要的错误处理:我们检查了所有映射是否成功,只要有一个失败就报错退出。这点很重要,因为部分成功会导致后续代码访问空指针,引发内核panic。

of_get_address:获取地址原始数据

有时候你不想直接映射,而是想先拿到地址的原始数据,这时候可以用of_get_address()

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags);

参数说明:

  • dev:设备节点
  • index:reg属性的索引
  • size:输出参数,返回地址长度
  • flags:输出参数,返回标志(比如IORESOURCE_MEM)

返回值是读取到的地址数据指针(大端格式的u32数组),失败返回NULL

这个函数返回的是设备树里的原始数据,可能还需要地址转换才能变成CPU物理地址。

of_translate_address:地址转换

设备树里的地址有时是总线地址,需要转换成CPU物理地址:

u64 of_translate_address(struct device_node *dev, const __be32 *in_addr);

参数说明:

  • dev:设备节点
  • in_addr:of_get_address()拿到的地址

返回值是转换后的物理地址,如果是OF_BAD_ADDR表示转换失败。

of_address_to_resource:转换成标准资源结构

Linux内核用struct resource统一描述各种资源。这个函数把设备树里的reg直接转成resource

int of_address_to_resource(struct device_node *dev, int index, struct resource *r);

参数说明:

  • dev:设备节点
  • index:reg属性的索引
  • r:出的resource结构体

返回值是0表示成功,负值表示失败。

这个函数在某些场景下很实用,比如你需要把地址信息传递给其它子系统时。但在简单的字符设备驱动里,直接用of_iomap()往往更方便。

资源管理 API:如何正确释放引用

到这里我们讲的都是"获取"资源的 API,但Linux内核编程有个黄金法则:有获取就必须有释放。OF API也不例外。

of_node_put:释放节点引用

当你用of_find_xxx()系列函数获取了一个device_node指针后,你就有了对这个节点的引用。内核用引用计数来管理这些节点,当你用完后必须调用of_node_put()来释放引用:

void of_node_put(struct device_node *node);

参数node是你要释放的节点指针。

我们的LED驱动在出错处理和反初始化函数里都用到了它:

/* 出错处理 */ ret = of_property_read_u32_array(led.device_tree_node, "reg", regdata, 10); if (ret < 0) { pr_err("reg property read failed!\n"); of_node_put(led.device_tree_node); /* 释放节点引用 */ return -EINVAL; } /* 反初始化函数 */ void led_hw_deinit(void) { /* ... 先 unmap 所有地址 ... */ if (led.device_tree_node) { of_node_put(led.device_tree_node); led.device_tree_node = NULL; } }

这里有个小技巧:我们在释放引用后把指针设为NULL。这样即使deinit()函数被多次调用,也不会 double-free。

你可能会问:of_find_property()需要配合of_node_put()吗?答案是:不需要property结构体是device_node的一部分,它的生命周期由节点管理。你只需要在用完整个节点后调用一次of_node_put()就行了。

更多内容请看下回。

http://www.jsqmd.com/news/990916/

相关文章:

  • 别再只会用函数发生器了!手把手教你用STM32驱动AD9959模块输出可调信号(附完整代码)
  • Hydro OJ插件系统深度体验:从用户到贡献者,我是如何给评测机加‘Buff’的
  • 英雄联盟自动化工具箱:5个核心功能提升游戏效率
  • 数据的加密与解密(07:45)
  • 从原理到代码:手把手用Python复现D-InSAR二轨法核心流程(附Jupyter Notebook)
  • MATLAB人脸考勤工具包:摄像头实时识别+GUI操作+打卡记录自动生成
  • 别再死记硬背了!用Python代码一步步拆解谓词公式到子句集(附Skolem化实现)
  • 通义比GITHUB Copilot差了10倍
  • 【优化求解】基于高级粒子群优化、超球动力学和突变的齿轮传动设计解决方案附matlab代码
  • 告别卡顿!用RK3588+QT+MPP打造四路RTSP监控大屏(附完整代码)
  • 别再死记硬背Zookeeper命令了!用Curator 5.5.0 + Spring Boot 3.x实战分布式锁(附12306抢票源码)
  • 大华IPC设备C++接入工具包:含Linux/Windows双平台SDK库与云台控制示例
  • 动量注意力机制:Transformer架构的动力学视角改进
  • 威海黄金回收避坑指南 2026年6月最新金价与靠谱店铺推荐 - 余生黄金回收
  • SAP成本核算实战:手把手教你用BUS2044的BAPI批量处理成本估算(附TCODE对照表)
  • 用Spark GraphX分析社交网络:手把手教你计算好友关系和最短路径(附完整代码)
  • MATLAB斜齿轮参数化建模与VFEM兼容网格生成工具(含抛物线修形及啮合特性分析)
  • 2026年6月上海闲置黄金处置攻略与变现时机分析 - 润富黄金回收
  • 独立开发者必看:如何用 Claude 快速构建一个 Chrome 插件原型 | 实战攻略
  • 别再硬算!用Python的SciPy库5行代码搞定‘翻译任务分配’这类指派问题
  • 致远OA漏洞检测终极指南:12大安全漏洞一键扫描与利用
  • 2026年城市照明行业3大核心痛点解析:实用解决方案汇总
  • MATLAB车牌识别小工具:带GUI界面,支持本地BMP图一键识别与字符高亮显示
  • AVI视频一键拆解成单帧图片的小巧Windows工具
  • GD32F103C8T6 Flash扇区级IAP升级工程(Keil MDK,含Bootloader与App双区划分)
  • API接口数据抓取终极指南:Easy-scraping-tutorial教你高效获取结构化数据
  • 2026年成都专线物流公司排行:成都零担物流/成都上门接货的物流公司/成都专线托运/五大服务商核心能力对比 - 优质品牌商家
  • 基于相关熵的眼动注视点定位MATLAB工具包,含测试图集与核心函数源码
  • 2026年杭州闲置黄金变现指南 避坑技巧+正规回收门店详解 - 润富黄金回收
  • 用 Rust 写 AI Agent 是什么体验?ADK-Rust 框架深度解析