linux驱动——设备树

news2024/11/24 7:35:14

1:初识设备树

1.1 什么是设备树,设备树的意义

        设备树(Device Tree)是 Linux 内核中用于描述硬件设备的一种数据结构。它为操作系统提供了一种抽象的方法,使其能够识别和配置硬件设备,而无需将硬件细节硬编码到内核中。设备树最常用于嵌入式系统和其他复杂硬件平台上,尤其是在 ARM 架构下。

        使用设备树的目的就是去精华、优化内核的重复代码。

设备树文件存放的位置:
        统一放在内核架构文件夹里面/boot/dts 里面
        以 32bit ARM 芯片 内核/arch/arm/boot/dts
        以 64bit ARM 芯片 内核/arch/arm64/boot/dts/rockchip
        我所使用的开发板为rk3588s所对应的设备文件:
                ls *dtb 当前设备树谁被编译成了 二进制文件
                确定我使用的设备文件:
                        rk3588s-yyt.dts
设备树的意义:
        降低了内核的重复性和臃肿性。

2:设备树的模型

        因为有了设备树之后,几乎芯片的所有的驱动,甚至是 CPU 的频率 时钟 电压都采用了这
种方式。写一个通用的驱动,通过设备树传参,带来不同的效果
设备树的模型类似 树状结构体 最开始处就是 根节点 ,往下延申各种节点信息

3:常见节点

在设备树文件中主要由分为三类文件:

dts:

        用户所修改裁剪的设备树文件

dtsi:

        相当于头文件->一般被dtsi包含

dtb:

        会被 DTC工具编译成二进制文件,编译完成后的文件名称一般和设备树一样。

设备树内部的内容分为两个关键的点:

       3. 1 设备树的所有的信息都被归纳为节点(node)

                以一个LED灯的为例:

led: led{
    compatible = "led";
    gpios =<&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>,
    <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
    status = "okay";
};

节点一般用{}引用,节点都属于根节点内部的子节点。

        3.2 设备节点里面的内容

                节点里面的内容被称之为属性。

                compatible = "led";
                status = "okay";

        规范为:

                1、节点的属性结尾用;

                2、一个属性的多个属性之间用,分隔

                3、属性一般有两种可能:字符串 数字

        3.3 特殊节点  

设备树里面常见的特殊节点:
        / :
                所有的设备树的起始一定是 / 根节点
        aliases:
                定义一些节点的别名
        chosen:
                这个大部分情况下无用
        可以当作给内核的传参->类似 uboot 的 bootargs

4:常见属性

节点里面常见属性:
        name:(已被弃用)
                就是个标签作用,基本没有其他的作用了
        model:
                真标签,为了给别人看你写的设备的作用
                里面会写厂商的名字 芯片 型号....
        compatible:(最重要属性没有之一)
                他是节点的真标识,他也是驱动匹配的方法,表示、名字
                驱动怎么找到设备树从而获取设备树信息
                全靠 compatible ->字符串
        status: (重点之一)
                表示设备树的状态
                        "disalbed"->该信息失效/失能
                        "okay

5:查找节点

在内核中查找节点有三种接口函数:

函数的功能:获取设备树节点 通过 name
函数头文件: <linux/of.h>
函数的原型:
        

struct device_node *of_find_node_by_name(
                struct device_node *from,
                const char *name
        );


函数的参数:
        from:
                你要从哪个节点往下搜寻
                一般传入 NULL ->代表从 根节点往下搜索!
        name:
                你要搜寻的节点的名字
        举个节点为例子:
        hehehe {
                compatible = "hehe","test_hehe";
                status = "disabled";
                testnum = <0xFFFF>;
                };
节点名字 "hehehe"
函数返回值:
        返回的就是在内核的节点抽象的结构体

函数的功能:获取设备的节点->通过 compatible 获取节点
函数头文件:同上
函数的原型:
       

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


函数的参数:
        from:
                从哪个节点往下查找 /->NULL
        type:
                NULL
        compatible:
        你想查找的节点对应 compatible 属性值
函数返回值:
        返回值即为你要的节点


函数的功能:通过路径寻找节点
函数头文件:同上
函数的原型:
        

struct device_node *of_find_node_by_path(const char *path)


函数的参数:
        path:
                提供节点的绝对路径->/开始
举个例子:
        hehehe 节点为例路径: "/hehehe"
函数返回值:返回的即为节点

6:获取节点属性

函数的功能:通用获取节点属性的信息的函数
函数头文件:同上
函数的原型:
       

 property *of_find_property(
                const struct device_node *np,
                const char *name,
                int *lenp
                )


函数的参数:
        np:
                获取的属性来自哪个节点
        name:
                获取属性的属性名
        lenp:
                获取属性的长度->不提供
函数返回值:
                内核封装的属性返回值的结构体

函数的功能:读取一个 U32 类型属性值
函数头文件:同上
函数的原型:
       

 int of_property_read_u32_index(
                const struct device_node *np,
                const char *propname,
                u32 index,
                u32 *out_value
                )


函数的参数:
        np:
                设备节点
        propname:
                你要查找的属性名
        index:
                索引号,下标号
        out_value:
                把查找到属性值给他放入里面
        函数返回值:
                成功返回 0
                失败返回 非 0

函数的功能:获取属性的字符串信息
函数头文件:同上
函数的原型:
       

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


函数的参数:
        np:
                节点
        propname:
                属性名字
        out_string:
                就会把返回的字符串传入其中
函数返回值:
        成功返回 0
        失败返回 非 0

简单举例:用设备树写一个LED灯的驱动

#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/of.h"
#include "linux/cdev.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/of_gpio.h"
#include "linux/device/class.h"
#include "linux/device.h"
struct class  cls;
struct device_node * node;
dev_t devnum;
struct cdev  xydledcdev;
const struct file_operations ops;
struct xyd_led_gpio{
int gpio_num;
int gpio_flag;
char name[32];
};
struct xyd_led_gpio myxyd_led_info;
int led_open (struct inode *i, struct file *f)
{
	gpio_set_value(myxyd_led_info.gpio_num,myxyd_led_info.gpio_flag);
	return 0;
}
int led_close (struct inode *i, struct file *f)
{
	gpio_set_value(myxyd_led_info.gpio_num,!myxyd_led_info.gpio_flag);
	return 0;
}
static int +__init tree_led_init(void)
{
	//1:先确定设备树LED灯设备信息是否存在
	node = of_find_compatible_node(NULL, NULL,"xyd_led");
	if(node == NULL)
	{
		printk("未成功设置设备树信息\r\n");
		return -EINVAL;
	}
	//2:判断status状态
	const char *  out_string;
	int ret = of_property_read_string(node, "status", &out_string);
	if(ret!=0 || strcmp("okay",out_string))
	{
		printk("信息不全,或者未使能! \r\n");
		return -EINVAL;
	}
	//3.获取设备树的GPIO信息
	myxyd_led_info.gpio_num = of_get_named_gpio(node, "xyd-gpios", 0);
	if(myxyd_led_info.gpio_num < 0)
	{
		printk("该设备树未提供 GPIO 信息! \r\n");
		return -EINVAL;
	}
	//4.获取GPIO的有效点平
	enum of_gpio_flags flags =0;
	of_get_named_gpio_flags(node,"xyd-gpios" , 0,&flags);
	if(flags == OF_GPIO_ACTIVE_LOW)
	{
		myxyd_led_info.gpio_flag=0;	
	}
	else
	{
		myxyd_led_info.gpio_flag=1;
	}
	//5:封装设别名
	sprintf(myxyd_led_info.name,"xyd_led_%d",myxyd_led_info.gpio_num);
	//6:初始化GPIO
	gpio_request(myxyd_led_info.gpio_num,myxyd_led_info.name);
	gpio_direction_output(myxyd_led_info.gpio_num,!myxyd_led_info.gpio_flag);
	//7:申请一个设备号
	alloc_chrdev_region(&devnum, 0,1,myxyd_led_info.name);
	//8:初始化cdev
	ops.open = led_open;
	ops.release = led_close;
	ops.owner= THIS_MODULE;
	cdev_init(&xydledcdev,&ops );
	//9:添加到内核
	cdev_add(&xydledcdev,devnum,1);
	//10:生成类结构体
	cls = class_create(THIS_MODULE,myxyd_led_info.name);
	//11:生成设备文件
	device_create(cls, NULL,devname,NULL,myxyd_led_info.name);
	
	return 0;
}
static void __exit tree_led_exit(void)
{
	//根据倒序的思想
	//1:销毁设备文件
	device_destroy(cls, myxyd_led_info.gpio_num);
	//2:销毁类文件
	class_destroy(cls);
	//3:从内核中删除
	cdev_del(&xydledcdev);
	//4:释放设备号
	unregister_chrdev_region(devnum, 1);
	//5:注销GPIO设备
	gpio_free(myxyd_led_info.gpio_num);
	
	
}
module_init(tree_led_init);
module_exit(tree_led_exit);
MODULE_LICENSE("GPL");

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

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

相关文章

QT-五子棋游戏

QT-五子棋游戏 一、演示效果二、核心代码三、下载链接 一、演示效果 二、核心代码 #include "GameModel.h" #include <time.h> #include <stdlib.h>GameModel::GameModel(){}void GameModel::startGame(GameType type){gameType type;//初始化棋盤game…

【备忘录模式】设计模式系列:掌握状态回溯的艺术(设计详解)

文章目录 备忘录设计模式详解引言1. 设计模式概述2. 备忘录模式的基本概念2.1 备忘录模式的定义2.2 备忘录模式的关键角色 3. 备忘录模式的实现原理3.1 备忘录模式的工作流程3.2 模式的优缺点分析3.3 与其他模式的对比 4. 实际案例分析4.1 游戏状态保存与恢复4.2 文档编辑器撤销…

19529 照明灯安装

### 详细分析 这个问题可以通过二分查找和贪心算法来解决。我们需要找到一个最大值&#xff0c;使得在这个最大值下&#xff0c;能够在给定的坐标上安装 k 个照明灯&#xff0c;并且相邻的照明灯之间的距离至少为这个最大值。 ### 思路 1. **排序**&#xff1a;首先对给定的…

S3C2440中断处理

一、中断处理机制概述 中断是CPU在执行程序过程中&#xff0c;遇到急需处理的事件时&#xff0c;暂时停止当前程序的执行&#xff0c;转而执行处理该事件的中断服务程序&#xff0c;并在处理完毕后返回原程序继续执行的过程。S3C2440提供了丰富的中断源&#xff0c;包括内部中…

微信小程序:开发工具修改js编译后还是旧的js逻辑

1、清理所有缓存&#xff0c;重新导入项目 2、语法存在问题无法编译,导致内存堆积&#xff0c;无法自动编译 3、npm 存在问题&#xff0c;可以重新构建 4、有时候编译器也没报错都是一切正常&#xff0c;但是编译后依然不是最新。这个时候需要考虑下电脑是否存在问题&#xff0…

使用gitee存储项目

gitee地址&#xff1a;Gitee - 基于 Git 的代码托管和研发协作平台 创建gitee远程仓库 将远程仓库内容拉取到本地仓库 复制下面这个地址 通过小乌龟便捷推送拉取代码&#xff1a;https://blog.csdn.net/m0_65520060/article/details/140091437

Ubuntu | 解决 VMware 中 Ubuntu 虚拟机磁盘空间不足的问题

目录 一、存在的问题二、解决的步骤第一步&#xff1a;扩展磁盘空间第二步&#xff1a;查看磁盘空间使用情况第三步&#xff1a;安装分区工具第四步&#xff1a;启动分区工具第五步&#xff1a;修改挂载文件夹的读写权限第六步&#xff1a;扩展文件系统大小第七步&#xff1a;验…

Prometheus2:被监控机器安装node_exporter与配置

1. 下载node_exporter [rootlocalhost ~]# wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz 2. 解压缩 [rootlocalhost ~]# tar -zxvf node_exporter-1.8.2.linux-amd64.tar.gz 3. 复制到/usrl/local路…

sed命令用法与案例

在Linux操作系统中&#xff0c;sed&#xff08;stream editor&#xff09;是一种功能强大的文本处理工具&#xff0c;用于执行文本的查找、替换、删除、新增等操作。sed命令以其简洁的语法和高效的执行速度&#xff0c;在自动化脚本和文本处理中扮演着重要角色。本文将探讨sed命…

探索串行通信的奥秘:Python中的pyserial库

文章目录 探索串行通信的奥秘&#xff1a;Python中的pyserial库背景&#xff1a;为何选择pyserial&#xff1f;pyserial是什么&#xff1f;如何安装pyserial&#xff1f;pyserial的五个简单函数场景应用&#xff1a;pyserial在实际中的使用常见bug及解决方案总结 探索串行通信的…

HR招聘,如何解决招聘需求不明确的问题

在HR招聘过程中&#xff0c;遇到招聘需求不明确的问题时&#xff0c;可以通过一系列措施来明确需求&#xff0c;提高招聘效率和质量。同时&#xff0c;在线人才测评、职业性格测试、认知能力测试和心理健康测试等工具也可以作为辅助手段&#xff0c;帮助HR更准确地评估候选人。…

【大模型从入门到精通33】开源库框架LangChain RAG 系统中的问答技术3

这里写目录标题 理论问答过程的三个主要阶段传递文档片段至 LM 上下文窗口的局限性及策略向量数据库的重要性RetrievalQA 链的作用MapReduce 与 Refine 的区别分布式系统中的实际考量实验的重要性RetrievalQA 链的主要限制对话记忆的重要性 实践初始化向量数据库设置 Retrieval…

GD32双路CAN踩坑记录

GD32双路CAN踩坑记录 目录 GD32双路CAN踩坑记录1 问题描述2 原因分析3 解决办法4 CAN配置参考代码 1 问题描述 GD32的CAN1无法进入接收中断&#xff0c;收不到数据。 注&#xff1a;MCU使用的是GD32E50x&#xff0c;其他型号不确定是否一样&#xff0c;本文只以GD32E50x举例说…

【Docker】gitea的ssh容器直通

本文首发于 ❄️慕雪的寒舍 1.跟着文档走 gitea的安装比较简单&#xff0c;直接使用官方文档中的docker-compose文件即可。如果想实现ssh容器直通&#xff0c;需要对这个docker-compose文件做一定修改。 如果你还没有安装docker&#xff0c;参考本站教程 linux安装docker&…

QT-贪吃蛇小游戏

QT-贪吃蛇小游戏 一、演示效果二、核心代码三、下载链接 一、演示效果 二、核心代码 #include "Food.h" #include <QTime> #include <time.h> #include "Snake.h"Food::Food(int foodSize):foodSize(foodSize) {coordinate.x -1;coordinate.…

多线程(4)——单例模式、阻塞队列、线程池、定时器

1. 多线程案例 1.1 单例模式 单例模式能保证某个类在程序中只存在唯一一份实例&#xff0c;不会创建出多个实例&#xff08;这一点在很多场景上都需要&#xff0c;比如 JDBC 中的 DataSource 实例就只需要一个 tip&#xff1a;设计模式就是编写代码过程中的 “软性约束”&am…

系统稳定性建设的深度剖析与未来展望

一、系统稳定性的重要意义 系统稳定性是系统正常运行的关键&#xff0c;其缺失会导致严重后果&#xff0c;如经济损失、用户流失等。 以在线学习平台为例&#xff0c;如果系统频繁出现卡顿、掉线等问题&#xff0c;影响用户的学习体验&#xff0c;导致用户流失&#xff0c;平…

【HTML】从0开始构建HTML页面

1、HTML文档基本格式 1.1、!DOCTYPE:文档类型声明 1.2、html:根标签 1.3、head:头部标签 1.4、body:主体标签 2、头部相关标签 2.1、< title> < title>标签用于定义HTML页面的标题&#xff0c;即给网页取一个名字&#xff0c;必须位于< head>标签之内。 …

Programmatically add website content to OpenAI with C#

题意&#xff1a;使用 C# 以编程方式将网站内容添加到 OpenAI。 问题背景&#xff1a; Our goal is to have a ChatGPT answer questions about our websites content. 我们的目标是让 ChatGPT 回答关于我们网站内容的问题。 We are trying to integrate something similar t…

设计模式笔记01(java版)

文章目录 设计模式概述学习设计模式的必要性设计模式分类创建型模式结构型模式行为型模式 UML类图概述类图的作用类图表示法类的表示方式类与类之间关系的表示方式1&#xff0c;单向关联2&#xff0c;双向关联3&#xff0c;自关联聚合关系组合关系依赖关系继承关系实现关系 软件…