05_设备树自定义属性_写入读取验证

设备树自定义属性:写入、读取、验证

依据:2026-10-13《设备树自定义属性》录音,以及学习系统"驱动初级 → 平台设备 → 设备树自定义属性"的 DTS、驱动笔记。录音转写的函数名以笔记中的代码为准。这是课程示例整理,未在你的开发板上重新测试。

一句话看懂

DTS 在设备节点里写属性,驱动匹配到这个节点后,在 probe() 中按"属性名 + 数据类型"读取。 compatible 决定设备与驱动能否匹配;yh_addr/yh_age/yh_infor 是匹配后由驱动自己解析的示例数据。(录音约 00:07---02:14)

text 复制代码
修改 DTS → 编译并让板子加载新 DTB → insmod 模块
     → compatible 匹配 → 内核调用 probe(pdev)
     → pdev->dev.of_node 找到节点
     → of_property_read_* 读取属性 → printk → dmesg 查看

1. DTS 写了什么

老师沿用上一节的 yhai-led-gpiod 节点,再加三个自定义属性:

dts 复制代码
yhai-led-gpiod {
    compatible = "yhai,led_gpiod";
    status = "okay";
    gpios = <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_HIGH>;

    yh_addr  = "chenddu";
    yh_age   = <32>;
    yh_infor = <12 34 0x66>;
};
属性 DTS 类型和本例值 驱动用什么读取
yh_addr 字符串 "chenddu";只是演示字符串,并非 GPIO 物理地址。 of_property_read_string()
yh_age 一个 32 位整数 32。 of_property_read_u32()
yh_infor 三个 32 位整数:12、34、0x66。 of_property_read_u32_array(..., 3)

属性名由示例驱动约定;内核不会自动理解 yh_age 的业务含义。实际项目中的设备专用属性应有清楚的 binding 文档,并按约定使用厂商前缀;这里的 yh_* 是课堂练习名。Linux 设备树 binding 建议

2. 驱动如何找到并读出这三个值

平台总线先用 compatible = "yhai,led_gpiod" 匹配驱动的 of_device_id,成功才调用 led_gpiod_probe(struct platform_device *pdev)。进入 probe() 后:

c 复制代码
struct device_node *np = pdev->dev.of_node;
const char *name;
u32 age;
u32 info[3];

if (!of_property_read_string(np, "yh_addr", &name))
    printk("yh_addr=%s\n", name);

if (!of_property_read_u32(np, "yh_age", &age))
    printk("yh_age=%u\n", age);

if (!of_property_read_u32_array(np, "yh_infor", info, 3))
    printk("yh_infor=%u %u 0x%x\n", info[0], info[1], info[2]);
写法 为什么这样写
pdev->dev.of_node pdev 是指针,用 -> 取其成员;dev 是内嵌结构体,用 . 取 of_node。得到的 np 指向本次匹配的设备树节点。
&name 字符串读取函数要写回一个字符串指针 ,所以传指针变量的地址。成功后 name 指向设备树中的字符串;不是新分配给你的一块内存。
&age 把一个 32 位整数写入 age,需要传变量地址。
info, 3 info 指向数组首元素;3 表示本次读三个 u32 元素。
!of_property_read_*() 这些函数成功返回 0,所以 !0 为真才打印;失败返回负错误码。

%u 按十进制打印无符号整数,%x 按十六进制打印,所以最后一个数会显示为 0x66(若按示例 0x%x 格式打印)。读取 API 会按类型解析设备树数据,驱动不用自己拆 DTB 的原始字节。Linux OF 属性读取 API(录音约 02:14---07:36)

3. 验证时看什么

  1. **先更新 DTB:**保存 DTS,编译 dtbs,把生成的 DTB 放到板子实际启动所用的位置并重新启动。仅重新编译 .ko 不会让旧 DTB 出现新属性。
  2. **再加载驱动:**用匹配板上运行内核的构建目录编译模块,在板上 sudo insmod ./led.ko,然后 sudo dmesg | tail -n 30。
  3. **看结果:**日志中应分别出现 yh_addr 对应 chenddu、yh_age 对应 32、yh_infor 的三项值 12/34/0x66,以及包含 led_gpiod_probe 的信息。老师原代码逐项打印数组,空格和 0x 前缀取决于具体 printk 格式。printk() 不一定直接出现在命令行。(录音约 07:00---07:36)

**不要只看最后的 probe ok 2:**老师代码把三个属性都写在独立的 if 里。即使某个属性不存在或类型不对,那个 if 只会跳过打印,probe() 仍可能返回 0。如果实际驱动必须依赖该属性,就检查返回值并在失败时返回错误;如果属性可选,当前写法适合演示。

这节笔记里的 led_gpiod_probe() 只读取并打印属性,没有调用上一节的 gpiod_get() 点灯 。DTS 中保留 gpios 并不意味着这一版示例驱动已经控制 LED。找不到 probe 日志时,先核对当前加载的 DTB、节点 status 与两处 compatible;能进 probe 但缺少属性日志时,再核对属性名、类型及数组长度。

一分钟复述

设备树节点可以写驱动约定的属性。平台驱动通过 compatible 匹配后,内核把 pdev 传给 probe();pdev->dev.of_node 指向该节点。我按属性类型分别调用 of_property_read_string/u32/u32_array,返回 0 才说明读成功。改了 DTS 要让板子加载新 DTB,查看 dmesg 才能确认读到了值。

上一节:GPIO 通用化。

相关推荐
bksczm2 小时前
MySQL之存储引擎
数据库·mysql
xiaoye-duck3 小时前
《C++ 项目:手写大模型接入 SDK》ChatGPT接口设计(中):全量响应实现和测试
网络·c++·语言模型·chatgpt
大模型最新论文速读3 小时前
text-to-sql:从学术玩具到生产落地
数据库·sql
ManageEngineITSM3 小时前
工单分类怎么设计?类别、子类别与自动分派的实用方法
大数据·服务器·数据库·人工智能·分类·数据挖掘
ClouGence3 小时前
MongoDB 双向同步如何防止数据循环?(附实操指南)
数据库·mongodb
TDengine (老段)3 小时前
TDengine IDMP 十大实用功能(7)
数据库·物联网·时序数据库·tdengine·涛思数据·工业数据·idmp
Decay__3 小时前
15_MySQL 数据同步与迁移方案 —— 复制 / DataX / Canal / 异构同步(对标 Oracle GoldenGate)
运维·数据库·sql·mysql·架构
Linux界最忧郁之人4 小时前
华为云ECS&IMS&AS实战|弹性云服务器、私有镜像、弹性伸缩完整实验
linux·运维·服务器·centos·华为云·openstack
zjx23884 小时前
oracle11g转Gbase8s库SQL常见问题修改
数据库·sql
真上帝的左手4 小时前
30. 技术专题-‌应用框架组件-缓存-Redis
数据库·redis·分布式·缓存·中间件