Linux驱动开发简易流程
推荐视频:
正点原子【第四期】手把手教你学 Linux之驱动开发篇
小智-学长嵌入式Linux&Android底层开发入门教程
能力矩阵
基础能力矩阵
熟悉c/c++、熟悉数据结构
熟悉linux系统,Shell脚本,Makefile/cmake/mk
文件IO、多线程、竞争、并发、阻塞、同步、中断、网络
熟悉调试工具,gdb、gdbserver、tcpdump
行业能力矩阵
平台相关:海思/君正/安霸MTK/NXP/高通/全志/瑞芯微/展讯等平台
系统相关:bootloader、kernel、文件系统,定制、移植、开发与适配
Android相关:HAL、Services、Framework
驱动相关:驱动设备模型、GPIO、I2C、SPL、UART、WIFl、LCD、USB
物联网相关:TCP/IP、UDP、COAP、MQTT、HTTP
流媒体相关:RTMP、RTSP、Iive555
视频编码:H264、H265、MJPEG
音频编码:PCM、AAC、G711
流媒体框架:FFMEPG、GStreamer、WebRTC
开发流程
- 编译系统,跑起来(编译从原厂拿来的SDK,看看有没有报错,做好一些必要的ignore管理)
- 按照需求将项目外设逐个调通(遥控,WIFI,蓝牙,LED灯光等等)
- 封装Android接口,让应用能用上驱动(这个一般是移植的芯片厂家的驱动,适配好就行)
- 应用实现(根据客户的需求定制各种功能)
Linux驱动开发思维
1、Liuⅸ下驱动开发直接操作寄存器不现实。
2、根据Linuⅸ下的各种驱动框架进行开发。一定要满足框架,也就是Linux下各种驱动框架的掌握。
3、驱动最终表现就是/dev/xxx文件。打开、关闭、读写。
4、现在新的内核支持设备树,这个一个dts文件,此文件描述了板子的设备信息。
linux驱动开发分类
linux驱动分为三大类:
1、字符设备驱动,最多的。
2、块设备驱动,存储
3、网络设备驱动,
一个设备不说是一定只属于某一个类型。比如USB WIFI,SDIO WIFI,属于网络设备驱动,因为他又有USB和SDIO,因此也属于字符设备驱动。
应用程序和驱动交互原理
用户空间(用户态)和内核空间(内核态):
Linux操作系统内核和驱动程序运行在内核空间、应用程序运行在用户空间。
应用程序想要访问内核资源,怎么办,有三种方法:系统调用、异常(中断)和陷入。我们一般都是系统调用的方式。
Linux 驱动属于内核的一部分,因此驱动运行于内核空间。
![[图片]](https://img-blog.csdnimg.cn/direct/a7991fb42f814dbfae024c945d43c370.png)
当我们在用户空间想要实现对内核的操作,比如使用 open 函数打开/dev/led 这个驱动,因为用户空间不能直接对内核进行操作,因此必须使用一个叫做“系统调用”的方法来实现从用户空间“陷入”到内核空间,这样才能实现对底层驱动的操作。
![[图片]](https://img-blog.csdnimg.cn/direct/0b965abba30d44419263f08cc9776cf1.png)
驱动的加载与卸载
Linux 驱动有两种运行方式。
- 将驱动编译进 Linux 内核中,这样当 Linux 内核启动的时候就会自动运行驱动程序。
- 将驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用“insmod”命令加载驱动模块。
驱动编译完成以后扩展名为.ko,有两种命令可以加载驱动模块:insmod和modprobe。insmod 命令不能解决模块的依赖关系,modprobe 会分析模块的依赖关系,然后会将所有的依赖模块都加载到内核中。驱动模块的卸载使用命令“rmmod”即可
简单看懂驱动代码
/* 驱动入口函数 */ static int __init xxx_init(void) { /* 入口函数具体内容 */ return 0; } /* 驱动出口函数 */ static void __exit xxx_exit(void) { /* 出口函数具体内容 */ } /* 将上面两个函数指定为驱动的入口和出口函数 */ module_init(xxx_init); module_exit(xxx_exit);
设备号的分配
- 静态分配设备号
注册字符设备的时候需要给设备指定一个设备号,这个设备号可以是驱动开发者静态的指定一个设备号,比如选择 200 这个主设备号。有一些常用的设备号已经被 Linux 内核开发者给分配掉了,具体分配的内容可以查看文档 Documentation/devices.txt。
使用“cat /proc/devices”命令即可查看当前系统中所有已经使用了的设备号。 - 动态分配设备号
静态分配设备号需要我们检查当前系统中所有被使用了的设备号,然后挑选一个没有使用的。而且静态分配设备号很容易带来冲突问题,Linux 社区推荐使用动态分配设备号,在注册字符设备之前先申请一个设备号,系统会自动给你一个没有被使用的设备号,这样就避免了冲突。
设备号的申请函数如下:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
注销字符设备之后要释放掉设备号,设备号释放函数如下:
void unregister_chrdev_region(dev_t from, unsigned count)
内核打印
在驱动中可以使用printk 来输出信息,而不用printf。因为在 Linux 内核中没有 printf 这个函数。printk 相当于printf 的孪生兄妹,printf运行在用户态,printk 运行在内核态。在内核中想要向控制台输出或显示一些内容,必须使用printk 这个函数。不同之处在于,printk 可以根据日志级别对消息进行分类,一共有 8 个消息级别,这 8 个消息级别定义在文件 include/linux/kern_levels.h 里面,定义如下:
#define KERN_SOH "\001"
#define KERN_EMERG KERN_SOH "0" /* 紧急事件,一般是内核崩溃 */
#define KERN_ALERT KERN_SOH "1" /* 必须立即采取行动 */
#define KERN_CRIT KERN_SOH "2" /* 临界条件,比如严重的软件或硬件错误*/
#define KERN_ERR KERN_SOH "3" /* 错误状态,一般设备驱动程序中使用 KERN_ERR 报告硬件错误 */
#define KERN_WARNING KERN_SOH "4" /* 警告信息,不会对系统造成严重影响 */
#define KERN_NOTICE KERN_SOH "5" /* 有必要进行提示的一些信息 */
#define KERN_INFO KERN_SOH "6" /* 提示性的信息 */
#define KERN_DEBUG KERN_SOH "7" /* 调试信息 */
一共定义了 8 个级别,其中 0 的优先级最高,7 的优先级最低。如果要设置消息级别,参考如下示例:
printk(KERN_EMERG "gsmi: Log Shutdown Reason\n");
上述代码就是设置“gsmi: Log Shutdown Reason\n”这行消息的级别为 KERN_EMERG。在具体的消息前面加上 KERN_EMERG 就可以将这条消息的级别设置为 KERN_EMERG。
如果使用 printk 的 时 候 不 显 式 的 设 置 消 息 级 别 , 那 么 printk 将 会 采 用 默 认 级 别MESSAGE_LOGLEVEL_DEFAULT,MESSAGE_LOGLEVEL_DEFAULT 默认为 4
在控制台修改内核打印级别:
echo 7 > echo 7 > /proc/sys/kernel/printk
在uboot下改变内核打印级别:
env set loglevel7
env save
编译驱动程序和测试 APP
编译驱动程序
当我们编写完一个驱动程序之后会生成.c文件,比如chrdevbase.c 这个文件。我们需要将其编译为.ko 模块.
- 创建Makefile 文件,然后在其中输入如下内容:
KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek CURRENT_PATH := $(shell pwd) obj-m := chrdevbase.o build: kernel_modules kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
第 1 行,KERNELDIR 表示开发板所使用的 Linux 内核源码目录,使用绝对路径,大家根据自己的实际情况填写即可。
第 2 行,CURRENT_PATH 表示当前路径,直接通过运行“pwd”命令来获取当前所处路径。
第 3 行,obj-m 表示将 chrdevbase.c 这个文件编译为 chrdevbase.ko 模块。
第 8 行,具体的编译命令,后面的 modules 表示编译模块,-C 表示将当前的工作目录切换到指定目录中,也就是 KERNERLDIR 目录。M 表示模块源码目录,“make modules”命令中加入 M=dir 以后程序会自动到指定的 dir 目录中读取模块的源码并将其编译为.ko 文件。
2. Makefile 编写好以后输入“make”命令编译驱动模块,
3. 编译成功以后就会生成一个叫做 chrdevbaes.ko 的文件,此文件就是 chrdevbase 设备的驱动模块。至此,chrdevbase 设备的驱动就编译成功。
编译测试 APP
测试 APP 比较简单,只有一个文件,因此就不需要编写 Makefile 了,直接输入命令编译。
因为测试 APP 是要在 ARM 开发板上运行的,所以需要使用 arm-linux-gnueabihf-gcc 来编译,输入如下命令:
arm-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseApp
编译完成以后会生成一个叫做 chrdevbaseApp 的可执行程序,输入如下命令查看chrdevbaseAPP 这个程序的文件信息:
file chrdevbaseApp
运行测试
-
拷贝文件
![[图片]](https://img-blog.csdnimg.cn/direct/ac8e8b1c3a824e0b9885c6c2497f531d.png)
-
加载 chrdevbase.ko 驱动文件
insmod chrdevbase.ko
或者
modprobe chrdevbase.ko
如果使用 modprobe 加载驱动的话,可能会出现如下的提示:
![[图片]](https://img-blog.csdnimg.cn/direct/e44601488dc341cba0da2ea602b93adb.png)
modprobe 提示无法打开“modules.dep”这个文件,因此驱动挂载失败了。我们不用手动创建 modules.dep 这个文件,直接输入 depmod 命令即可自动生成modules.dep,有些根文件系统可能没有 depmod 这个命令,如果没有这个命令就只能重新配置busybox,使能此命令,然后重新编译 busybox。输入“depmod”命令以后会自动生成 modules.alias、modules.symbols 和 modules.dep 这三个文件,
![[图片]](https://img-blog.csdnimg.cn/direct/fc57a99107d6454f9b9d2d0b19f36262.png)
然后重新使用modprobe 加载 chrdevbase.ko
输入如下命令查看当前系统中有没有 chrdevbase 这个设备:
cat /proc/devices
![[图片]](https://img-blog.csdnimg.cn/direct/a201d80fc7234406a583b820536a7e07.png)
创建设备节点文件
驱动加载成功需要在/dev 目录下创建一个与之对应的设备节点文件,应用程序就是通过操作这个设备节点文件来完成对具体设备的操作。输入如下命令创建/dev/chrdevbase 这个设备节点文件:
mknod /dev/chrdevbase c 200 0
其中“mknod”是创建节点命令,“/dev/chrdevbase”是要创建的节点文件,“c”表示这是个字符设备,“200”是设备的主设备号,“0”是设备的次设备号。创建完成以后就会存在/dev/chrdevbase 这个文件,可以使用“ls /dev/chrdevbase -l”命令查看,
如果 chrdevbaseAPP 想要读写 chrdevbase 设备,直接对/dev/chrdevbase 进行读写操作即可。
设备操作测试
./chrdevbaseApp /dev/chrdevbase 1
![[图片]](https://img-blog.csdnimg.cn/direct/d1cac3be2e5446e8b722e9d3a7b9ec20.png)
./chrdevbaseApp /dev/chrdevbase 2
![[图片]](https://img-blog.csdnimg.cn/direct/df12c5199e024690b25f2eec2b014a96.png)
卸载驱动模块
如果不再使用某个设备的话可以将其驱动卸载掉,比如输入如下命令卸载掉 chrdevbase 这个设备
rmmod chrdevbase.ko
相关文章:
Linux驱动开发简易流程
推荐视频: 正点原子【第四期】手把手教你学 Linux之驱动开发篇 小智-学长嵌入式Linux&Android底层开发入门教程 能力矩阵 基础能力矩阵 熟悉c/c、熟悉数据结构 熟悉linux系统,Shell脚本,Makefile/cmake/mk 文件IO、多线程、竞争、并发…...
基于springboot的靓车汽车销售网站
🍅点赞收藏关注 → 私信领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅一 、设计说明 1.1 研究背景 随…...
爬取涛声网音频
代码展现: 代码详情: import requests import re import os filename 声音// if not os.path.exists(filename): os.mkdir(filename) def down_load(page): for page in range(page): page page1 url https://www.tosound.…...
如何快速且有效的学习自动化测试?
我写一个学习路线吧: 1.学习python基本语法。 2学习路线图 https://www.processon.com/view/link/64e729486ece22263c3e 学习HTML/CSS下的html、xml、webservice三个教程。 3. 然后下一个python的requests库学习写最简单的网络爬虫。知乎上爬虫教程一大堆。 3是…...
openmmlab大模型实战营01
与环境进行交互——智能体更合适 模型微调常见方式 模型评测 模型部署常见问题你 大语言模型本身不具备最新信息和知识的获取,此时需要搭建包含不同模块的智能体框架 智能体:以大语言模型为核心,进行规划、推理和执行...
HarmonyOS-ArkTS基本语法及声明式UI描述
初识ArkTS语言 ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集。因此,在学习ArkTS语言之前,建议开发者具备TS语…...
字符串转成时间的SQL,一个多种数据库通用的函数
select date 2010-10-06 from dual; date 函数,此函数适用于: 1.MySQL数据库 2.Oracle数据库 3.达梦数据库 4.人大金仓数据库...
CMake入门教程【核心篇】查找包(find_package)
😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「本文的内容」:CMake入门教程 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 1.使用方法1.1基本用…...
Stable Diffusion好用的显卡推荐
Stable Diffusion 是一款顶级的人工智能艺术生成工具,以其快速的性能、用户友好的界面和显着的效果而闻名。然而,在沉浸体验之前,有必要验证您的计算机(显卡)是否符合最佳功能所需的严格规范。今天我们将介绍三款高性价…...
Spring 对请求参数的优雅处方式(重写序列化方法)
Spring 对请求参数的优雅处方式(重写序列化方法) 描述前端传参方式介绍代码实现:1、重写序列化方式代码2、设置类自动加载到 Spring 中 描述 在我们日常项目开发过程中,往往会遇到前端请求参数中有空格的情况,前端提交…...
2024年中职“网络安全“—数字调查取证(attack817.pcapng)
目录 1.通过分析数据包找出恶意用户最初访问HTTP服务的包号,将该值作为Flag值提交, Flag格式为flag{xxx}; 2.继续查看数据包文件分析出恶意用户扫描了哪些端口,将全部的端口号按照一定顺序作为Flag值,提示:注意端口…...
如何使用VsCode编译C语言?
下载VsCode (1) 解压到D盘跟目录 (2) 运行[vscode.reg],注册右键菜单 (3) 进入[pack]文件夹,运行[install.bat]。安装基本插件。 下载mingw32 (1) 解压任意目录 (2) 我的电脑右键–高级系统设置–高级–环境变量–系统变量–Path(双击)–空白行(双击)–…...
SpringCloud 和 Linux 八股文第三期五问五答
SpringCloud 和 Linux 八股文第三期五问五答 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的! ⭐点赞⭐收藏⭐不迷路!⭐ 1)Linux常用命令 2)如何查看测试项目的日志 一…...
组件通信方式
组件通信方式有:vuex,ref,父子通信(父传子、子传父),兄弟通信(eventBus), 祖先后代通信(依赖注入) 父传子:父组件内:在子组件标签上设置自定义属…...
kbdnecnt.DLL文件缺失,软件或游戏无法启动运行,怎样快速修复?
不少人都在问“kbdnecnt.DLL文件”是什么?为什么电脑总是报错提示说“kbdnecnt.DLL文件缺失,软件无法启动”? 首先,先来了解“kbdnecnt.DLL文件”是什么? kbdnecnt.DLL是Windows操作系统中的一个动态链接库文件&#…...
Linux账户安全
一.Linux账户与组的基本概念 在Limux操作系统中,每一个文件和程序都归属于一个特定的 “用户”。每个用户都由一个唯一的身份来标识,这个标识称为用户ID (UserID, UID )。系统中的每一个用户也至少需要属于一个“用户分组”,即由系统管理员所…...
深度生成模型之GAN优化目标设计与改进 ->(个人学习记录笔记)
文章目录 深度生成模型之GAN优化目标设计与改进原始GAN优化目标的问题1. JS散度度量问题2. 梯度问题 优化目标的设计与改进1. 最小二乘损失GAN2. Energy-based GAN(EBGAN)3. Wasserstein GAN4. WGAN-GP5. Boundary Equilibrium GAN(BEGAN)6. Loss Sensitive GAN7. Relativeisti…...
程序员如何高效学习技术?
我们相信努力学习一定会有收获,但是方法不当,既让人身心疲惫,也没有切实的回报。 不少朋友每天都阅读技术文章,但是第二天就忘干净了。工作中领导和同事都认可你的沟通和技术能力,但是跳槽面试却屡屡碰壁。面试官问技术…...
一个无经验的大学毕业生,可以转行做软件测试吗?我的真实案例
在转行之前,我一直在思考,当代年轻人的真实生活情况究竟是什么样的。 朝九晚六,无休止的加班,每天往返于公司与家,没有一点点自己的生活,只能从心里面麻痹自己,以求得最后的慰籍。 这就是我之…...
三.Linux无名管道(PIPE)和有名管道(FIFO)的区别
目录 命名管道(Named Pipe): 无名管道(Anonymous Pipe): 总结: 无名管道(Anonymous Pipe)和命名管道(Named Pipe)都是进程间通信的机制&#x…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
