Linux-驱动积累

Linux 设备驱动概述​

Linux 设备驱动是内核与硬件交互的核心桥梁,负责屏蔽硬件细节、提供统一操作接口。其以内核模块为主要存在形式,支持动态加载 / 卸载,核心功能涵盖硬件初始化、中断处理、电源管理及数据传输,是嵌入式 Linux 系统实现硬件控制的关键组件。

一.Device Tree

2.1 设备树的核心价值​

设备树是种硬件描述语言,早年用于 PowerPC,后来因 ARM 设备的问题普及。​

早期 ARM 设备多且硬件配置乱(不同厂商、型号的外设地址、中断号都不同)。传统 Linux 得给每款设备写专属 BSP,把硬件信息硬编码进内核,导致内核臃肿、编译慢、维护难。​

设备树则把硬件描述抽成 DTS/dtsi 文件,编译成 DTB 后由 bootloader 加载。内核读 DTB 就知硬件配置,不用改源码就能适配不同设备。​

现在它成了 ARM、RISC-V 的标准,让同一内核兼容多硬件,移植维护更简单。

2.2 设备树四大核心要素(含 dtsi)​

设备树的完整工作流依赖四大关键要素,其中dtsi是实现硬件描述复用的核心,具体如下:​

要素​

全称​

格式 / 类型​

核心作用​

文件扩展名​

DTS​

Device Tree Source​

文本文件​

描述特定单板的硬件细节(如板级外设、引脚配置)​

.dts​

DTSI​

Device Tree Source Include​

文本文件​

存放多个 DTS 共享的通用硬件描述(如 SOC 内核、通用外设),实现代码复用​

.dtsi​

DTC​

Device Tree Compiler​

编译工具​

将 DTS(含引用的 dtsi)编译为内核可解析的二进制文件​

无(工具命令为dtc)​

DTB​

Device Tree Blob​

二进制文件​

内核启动时解析的硬件描述文件,由 DTS 经 DTC 编译生成​

.dtb​

关键关系链路​

通用硬件描述(dtsi) → 被特定单板描述(DTS)引用 → 经DTC编译 → 生成内核可解析文件(DTB) → 内核启动时加载解析,获取硬件信息。

2.3 设备树基本结构

一个典型的 DTS 文件结构如下:

/dts-v1/;
#include "skeleton.dtsi"  // 包含公共定义/ {model = "My Development Board";compatible = "myboard,rev1";#address-cells = <1>;#size-cells = <1>;memory {reg = <0x80000000 0x20000000>;  // 起始地址和大小};chosen {bootargs = "console=ttyS0,115200 root=/dev/mmcblk0";};soc {#address-cells = <1>;#size-cells = <1>;compatible = "simple-bus";ranges;uart0: serial@12340000 {compatible = "ns16550a";reg = <0x12340000 0x100>;interrupts = <5 0>;clock-frequency = <1843200>;};i2c0: i2c@12350000 {compatible = "nxp,pca9548";reg = <0x12350000 0x100>;#address-cells = <1>;#size-cells = <0>;/* I2C设备 */};};
};

主要元素说明:

  • /:根节点
  • compatible:兼容性字符串,用于内核匹配相应的设备驱动
  • reg:寄存器地址信息,格式为<地址 长度>
  • interrupts:中断信息
  • #address-cells#size-cells:指定子节点 reg 属性的地址和长度字段数量

2.4设备树在驱动中的应用

在设备驱动中,可以通过以下函数获取设备树中的信息:

// 获取属性值
ssize_t of_property_read_string(struct device_node *np,const char *propname,const char **out_string);// 读取整数属性
int of_property_read_u32(struct device_node *np,const char *propname,u32 *out_value);// 获取reg属性
int of_address_to_resource(struct device_node *dev,int index,struct resource *r);// 匹配compatible字符串
const struct of_device_id *of_match_device(const struct of_device_id *matches,struct device *dev);

platform平台驱动中使用设备树匹配的示例:

static const struct of_device_id my_driver_of_match[] = {{ .compatible = "myvendor,mydevice" },{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_driver_of_match);static struct platform_driver my_driver = {.probe = my_probe,.remove = my_remove,.driver = {.name = "my-driver",.of_match_table = my_driver_of_match,},
};
module_platform_driver(my_driver);

2.5 api函数

二.字符设备驱动框架

2.1 字符设备注册顺序

1.驱动模块加载与删除 (module_init 和 module_exit) - > 2.编写模块加载的函数->3.给字符设备注册主设备号与次设备号->4.初始化一个字符设备cdev并且将其添加进linux系统->5.创建一个抽象类 ->创建设备节点(使得设备能够自动在/dev目录下生成)

2.2 api函数

1.驱动模块加载:module_init(function)

2.驱动模块删除:module_exit(function)

3.字符设备号

(1)手动:

MKDEV(ma,mi)   + register_chrdev_region(dev_t from, unsigned count, const char *name)

注:其中ma为主设备号 mi为次设备号

(2)自动,但得确定次设备号:

int register_chrdev_region(dev_t from, unsigned count, const char *name)

(3)注销:unregister_chrdev_region(devid, unsigned num);

4.初始化字符设备

初始化:void cdev_init(struct cdev *cdev, const struct file_operations *fops)
删除:void cdev_del(struct cdev *p)

5.字符设备

添加:int cdev_add(struct cdev *p, dev_t dev, unsigned count)
6.类
创建:struct class *class_create (struct module *owner, const char *name)
删除:void class_destroy(struct class *cls);
7.设备
创建:      
struct device *device_create(struct class    *class,
                                              struct device *parent,
                                              dev_t         devt,
                                              void  *drvdata,
                                              const char       *fmt, ...)

销毁:        void device_destroy(struct class *class, dev_t devt)

2.3 示例

#define GPIOLED_CNT         1
#define GPIOLED_NAME        "gpioled"
#define LEDON               1
#define LEDOFF              0struct gpioled_dev{dev_t devid;struct cdev cdev;struct class *class;struct device *device;int major;int minor;struct device_node  *nd;int led_gpio;
};static int __init led_init(void)
{int ret;if(gpioled.major){gpioled.devid = MKDEV(gpioled.major,0);register_chrdev_region(gpioled.devid,GPIOLED_CNT,GPIOLED_NAME);}else{alloc_chrdev_region(&gpioled.devid,0,GPIOLED_CNT,GPIOLED_NAME);gpioled.major = MAJOR(gpioled.devid);gpioled.minor = MINOR(gpioled.devid);}printk("major = %d,minor = %d",gpioled.major,gpioled.minor);gpioled.cdev.owner = THIS_MODULE;cdev_init(&gpioled.cdev,&gpioled_fops);cdev_add(&gpioled.cdev,gpioled.devid,GPIOLED_CNT);gpioled.class = class_create(THIS_MODULE,GPIOLED_NAME);if(IS_ERR(gpioled.class)){return PTR_ERR(gpioled.class);}gpioled.device = device_create(gpioled.class,NULL,gpioled.devid,NULL,GPIOLED_NAME);if(IS_ERR(gpioled.device)){return PTR_ERR(gpioled.device);}return 0;
}static void __exit led_exit(void)
{cdev_del(&gpioled.cdev);unregister_chrdev_region(gpioled.devid,GPIOLED_CNT);device_destroy(gpioled.class,gpioled.devid);class_destroy(gpioled.class);
}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GARY");

三.操作gpio

3.1

3.2

3.3

3.4

四.input子系统

五linux中断

5.1 设备树编写

先观察dtsi里面的intc中断控制节点

intc: interrupt-controller@00a01000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x00a01000 0x1000>,
<0x00a02000 0x100>;
};

发现它有三个cell :

第一个cell对应的是中断类型,0 :SPI 中断,1 :PPI 中断。

第二个cell对应的是中断号 ,对于spi(0~987) 对于ppi(0~15)

第三个cell对应的是中断类型,1:上升沿触发 2:下降沿触发 4:高电平触发 5:低电平触发

接着,举一个例子

fxls8471@1e {compatible = "fsl,fxls8471";reg = <0x1e>;position = <0>;interrupt-parent = <&gpio5>;interrupts = <0 8>;
};

可以知道它是对应gpio5,低电平触发的中断

5.2 中断的顺序

 1.获取中断号(可从设备树或者使用的gpio_to_irq获取)->2.注册中断->3,编写中断复位函数

5.3

六.linux remap系统

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

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

相关文章

软考-系统架构设计师 决策支持系统(DSS)详细讲解

个人博客&#xff1a;blogs.wurp.top 一、DSS的核心概念与定位 1. 什么是DSS&#xff1f; DSS是一个交互式的、计算机化的系统&#xff0c;旨在帮助决策者利用数据和模型来解决半结构化&#xff08;Semi-structured&#xff09; 或非结构化&#xff08;Non-structured&#…

《Python 实战:构建一个可扩展的订单管理系统,从基础操作到架构思维》

《Python 实战:构建一个可扩展的订单管理系统,从基础操作到架构思维》 一、引言:用代码管理商业的脉搏 在数字化浪潮席卷各行各业的今天,订单管理系统已成为电商、物流、零售等领域的核心支撑。它不仅承载着交易数据,更是企业运营效率的体现。而 Python,以其简洁优雅的…

【计算机网络】生产问题排查:如何使用Wireshark抓包/读取抓包文件进行网络分析

1 缘起 有一次,公司同事A让同事B看一次请求日志, 同事B说先抓一次包看看请求是否进入服务器-某个服务, 我知道这个事情后,也“参观”了抓包过程, 上面的事件只是一个小插曲,紧接着的第二件事才是写本篇文章的真正动机: 同一天,同事C让同事D配置个服务代理(某种上网方…

网格dp|

lc3665class Solution {public:int uniquePaths(vector<vector<int>>& grid) {const int MOD 1000000007;int m grid.size(), n grid[0].size();vector memo(m, vector(n, array<int, 2>{-1, -1})); // -1 表示没有计算过auto dfs [&](this auto…

烦人的Nano 编辑器,如何退出呢?

对于不熟悉 nano 编辑器的人来说&#xff0c;它的退出方式确实有点反直觉。别担心&#xff0c;这是几乎所有新手都会遇到的困惑。 退出 Nano 编辑器的正确方法 记住这个黄金法则&#xff1a;ctrl键是你的朋友&#xff01; 1. 正常保存并退出&#xff08;最常用&#xff09; 按 …

IDM(Internet Download Managerv 6.38)破除解版下载!IDM 下载器永久免费版!提升下载速度达5倍!安装及使用

软件介绍 IDM&#xff08;Internet Download Manager&#xff09;是一款功能强大的 Windows 平台专业下载加速工具&#xff0c;可加速下载速度、调度任务、续传下载、管理文件。可使下载速度提升至普通浏览器的 5 倍以上&#xff0c;最高可加速 8 倍。IDM 支持 HTTP、FTP、HTTP…

学习Java29天(tcp多发多收)但是无解决客户端启动多个问题

180/189今天看了一些ip的东西WLAN的ip是路由器随机分配的&#xff08;DHCP&#xff09;

Photoshop - Ps Camera Raw 滤镜

使用Adobe Photoshop Camera Raw滤镜对图像进行快速和可逆的编辑。Camera Raw滤镜将图像拖入Photoshop工作区&#xff0c;或者点击菜单栏-文件-打开来打开图像。选中图像的对应的图层&#xff0c;点击菜单栏-滤镜-Camera Raw滤镜&#xff0c;弹出Camera Raw滤镜面板。使用Camer…

Node.js(4)—— http模块基础

下面我们来学nodejs中的http模块。在此之前&#xff0c;你需要有一定的网络知识储备&#xff0c;能知道http&#xff0c;IP&#xff0c;端口是什么并且它们之间的关系。如果还不清楚或比较模糊&#xff0c;可以查看下面的文章&#xff1a; HTTP协议与IP 下面我们开始学习。 目…

后端去拿数据怎么拿?

简单来说&#xff0c;Entity 和 DTO 代表了数据在不同层次和场景下的不同形态和目的。它们最根本的区别在于&#xff1a;职责和目的不同。一句话概括Entity&#xff1a;代表数据库中的表&#xff0c;是业务逻辑的核心&#xff0c;与持久化&#xff08;数据库&#xff09;紧密相…

从源码角度来学习Activit的启动流程

免责声明&#xff1a;本文是本人的学习记录文档&#xff0c;有问题可以评论区指出&#xff0c;谢谢 一、从Launcher点击桌面图标&#xff0c;拉起app进程&#xff08;不同进程间拉组件&#xff09; 从桌面点击icon图标拉起进程&#xff0c;这个就涉及到很多逻辑了&#xff0c;我…

pgAdmin介绍(PostgreSQL数据库管理软件)数据库客户端、PG客户端、PostgreSQL客户端

文章目录**1. 安装 pgAdmin****1.1 下载****1.2 安装步骤&#xff08;以 Windows 为例&#xff09;**1. **运行安装程序**&#xff1a;双击下载的 .exe 文件。2. **接受协议**&#xff1a;点击 Next&#xff0c;勾选 I accept the agreement。3. **选择安装路径**&#xff1a;默…

桌面GIS软件FlatGeobuf转Shapefile代码分享

桌面GIS软件FlatGeobuf转Shapefile代码分享1、后端代码分享2、前端代码分享分享完成

【Bluedroid】A2DP Source 音频传输停止流程及资源管理机制(btif_a2dp_source_stop_audio_req)

本文深入剖析Android蓝牙协议栈中A2DP音频传输停止流程,涵盖从用户请求触发、工作线程调度、资源释放到性能统计的全链路实现。通过分析btif_a2dp_source_stop_audio_req到btif_a2dp_source_audio_tx_stop_event的代码执行路径,揭示多线程环境下的竞争规避策略、硬件抽象层(H…

1-ruby介绍、环境搭建、运行 hello world 程序

1-ruby介绍、环境搭建、运行 hello world 程序 Ruby 简介 Ruby 是一种开源的、面向对象的、解释型的动态编程语言&#xff0c;由 Yukihiro “Matz” Matsumoto 于 1995 年发布。主要特点包括&#xff1a; 纯面向对象&#xff1a;所有东西都是对象动态类型&#xff1a;变量不…

PPO、DPO和GRPO的区别

一、 核心思想一句话概括 首先&#xff0c;我们用三个比喻来快速理解它们的核心思想&#xff1a;PPO (近端策略优化)&#xff1a; 「比武招亲」 模型&#xff08;AI&#xff09;通过试错和与裁判&#xff08;奖励模型&#xff09;的互动来学习。它生成多个回答&#xff0c;裁判…

使用组合子构建抽象语法树

引言 组合子&#xff08;Combinator&#xff09;是一种函数式编程中的概念&#xff0c;它允许我们通过组合简单的函数来构建复杂的逻辑。在解析器和抽象语法树&#xff08;AST&#xff09;的构建中&#xff0c;组合子提供了一种简洁且模块化的方法。本文将介绍如何使用组合子来…

20.27《24GB显卡轻松训练ChatGLM3-6B!QLoRA极速微调实战指南》

24GB显卡轻松训练ChatGLM3-6B!QLoRA极速微调实战指南 import torch from transformers import AutoModel, AutoTokenizer, BitsAndBytesConfig# 配置4-bit量化参数 bnb_config = BitsAndBytesConfig(load_in_4bit=True,bnb_4bit_use_double_quant=True

JSP 输出语法全面解析

JSP 输出语法全面解析 JSP 提供了多种输出内容到响应流的方式&#xff0c;每种方式都有其特定的使用场景和特点。以下是 JSP 输出语法的详细解析。 总结 JSP直接编写普通字符串 翻译到service方法的out.write(“这里面”) <%%> 翻译到service方法体内部&#xff0c;里面是…

前端学习——CSS

前面我们已经学习过来HTML。但是对于前端网页来说&#xff0c;HTML只是网页的骨架。而只是使用HTML的网页是十分简陋的&#xff0c;一般没办法应用于实际应用。因此我们还要学习CSS对网页进行美化。 相关代码已经上传至gitee&#xff1a;前端学习代码: 前端学习&#xff0c;喜欢…