Linux驱动开发

一、驱动分类

Linux中包含三大类驱动:字符设备驱动、块设备驱动和网络设备驱动。其中字符设备驱动是最大的一类驱动,因为字符设备最多,从led到I2C、SPI、音频等都属于字符设备驱动。块设备驱动和网络设备驱动都要比字符设备驱动复杂。因为其比较复杂,所以半导体厂商都已经帮我们写好了,大部分情况下都是可以直接使用的。所谓的块设备驱动就是存储器设备的驱动,比如EMMC、NAND、SD卡和U盘等存储设备

二、字符设备驱动开发

字符设备驱动是Linux驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的。我们先来了解Linux下的应用程序是如何调用驱动程序的,如下图:

应用程序运行在用户空间,而Linux驱动属于内核的一部分,因此驱动运行于内核空间。open、close、write和read等这些函数是由C库提供的,在LInux系统中,系统调用作为C库的一部分。

三、Linux设备号

1、设备好的组成

为了方便管理,Linux中每个设备都有一个设备号,设备号由主设备号和次设备号两部分组成,主设备号表示某一个具体的驱动,次设备号表示使用这个驱动的各个设备。Linux提供了一个名为dev_t的数据类型表示设备号,dev_t定义在include/linux/types.h里面。dev_t其实是unsigned int类型,是一个32位的数据类型。其中高12位是主设备号,低20位是次设备号,因此Linux系统中主设备号范围是0~4095

设备号的操作函数

MAJOR用于从dev_t中获取主设备号,将dev_t右移20位即可
MINOR用于从dev_t中获取次设备号,取dev_t的低20位即可
MKDEV用于将给定的主设备号和次设备号的值组合成dev_t类型的设备号

2、设备号的分配

静态设备号:注册字符设备需要给设备指定一个设备号,这个设备号可以是驱动开发者静态指定的设备号,但是要注意该设备号没有被内核开发者分配掉。使用cat/proc/devices命令即可查看当前系统中已经使用的设备号

使用register_chrdev函数注册字符设备的时候只需要给定一个主设备号即可

/* 注册字符设备驱动 */
retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);

这是老版本字符设备注册函数,其0~1048575(2^20-1)这个区间的次设备号全部设置为0

动态分配设备号:使用设备号的时候向linux内核申请,需要几个就申请几个,由linux内核分配设备可以使用的设备号。在注册字符设备之前先申请一个设备号,系统会自动给你一个没有被使用的设备号,这样就避免了冲突,卸载驱动的时候释放掉这个设备号即可

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

dev:保存申请到的设备号

baseminor:次设备号起始地址,alloc_chrdev_region可以申请一段连续的多个设备号,这些设备好的主设备号一样,但是次设备号不同,次设备号以baseminor为起始地址开始递增。一般baseminor为0,也就是次设备号从0开始

count:要申请的设备号数量

name:设别名字

如果给定了设备的主设备号和次设备号就使用如下所示函数来注册设备号

int register_chrdev_region(dev_t from, unsigned count, const char *name)
参数 from 是要申请的起始设备号,也就是给定的设备号
参数 count 是要申请的数量,一般都是一个
参数 name 是设备名字

一般采用动态分配设备号,模板如下

/* 注册字符设备驱动 */
/* 1、创建设备号 */
if (newchrled.major) 
{        
    /*  定义了设备号 */
    newchrled.devid = MKDEV(newchrled.major, 0);
    register_chrdev_region(newchrled.devid, NEWCHRLED_CNT, NEWCHRLED_NAME);
} 
else 
{        
    /* 没有定义设备号 */
    alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_CNT, NEWCHRLED_NAME);    /* 申请设备号 */
    newchrled.major = MAJOR(newchrled.devid);    /* 获取分配号的主设备号 */
    newchrled.minor = MINOR(newchrled.devid);    /* 获取分配号的次设备号 */
}
printk("newcheled major=%d,minor=%d\r\n",newchrled.major, newchrled.minor);    

注销设备号

void unregister_chrdev_region(dev_t from, unsigned count)

四、模块注册与卸载

Linux驱动有两种运行方式,第一种是将驱动编译进Linux内核中,当Linux内核启动的时候就会自动运行驱动程序。第二种是将驱动编写成模块(Linux下模块扩展名为ko),在Linux内核启动以后使用相应命令加载驱动模块

模块有加载和卸载两种操作,模块的加载和卸载注册函数如下

module_init(xxx_init); //注册模块加载函数
module_exit(xxx_exit); //注册模块卸载函数

module_init函数来向Linux内核注册一个模块加载函数,参数xxx_init就是需要注册的具体函数,当使用insmod命令加载驱动的时候,xxx_init这个函数就会被调用

module_exit函数用来向Linux内核注册一个模块卸载函数,参数xxx_exit就是需要注册的函数,当使用rmmod命令卸载驱动的时候xxx_exit就会被调用

五、字符设备注册与注销

当驱动模块加载成功需要注册字符设备,卸载驱动模块的时候也需要注销掉字符设备

static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major, const char *name)

register_chrdev函数用于注册字符设备,unregister_chrdev注销掉字符设备

一般字符设备的注册在驱动模块的入口函数xxx_init中进行,字符设备的注销在驱动模块的出口函数xxx_exit进行

六、LICENSE和作者信息

在驱动中加如LICENSE和作者信息,其中LICENSE是必须添加的,否则的话编译会报错,作者信息可以不添加

MODULE_LICENSE("GPL") //添加模块 LICENSE 信息 ,LICENSE 采用 GPL 协议
MODULE_AUTHOR("mingfei") //添加模块作者信息

七、测试指令

1、加载驱动模块

驱动模块一般挂载在lib/modules/4.1.15目录下,所以需要编写的驱动模块和测试软件复制到根文件系统rootfs/lib/modules/4.1.15目录下,通过tftfp和nfs启动后,在开发板的lib/modules/4.1.15目录下存在驱动模块和测试软件

驱动编译完成以后扩展名是.ko,有两种命令可以加载模块:insmod和modprobe

加载驱动模块

insmod xxx.ko
modprobe xxx.ko

insmod不能解决模块的依赖关系,比如drv.ko依赖first.ko这个模块,就必须先使用insmod命令加载first.ko这个模块,然后再加载drv.ko这个模块

但是modprobe就不会存在这样的问题,modprobe会分析模块的依赖关系,然后会将所有的依赖模块都加载到内核中

若modprobe提示无法打开modules.dep,驱动挂载失败,输入depmod即可自动生成modules.dep

2、创建设备节点文件

驱动加载成功需要在/dev目录下创建一个与之对应设备节点文件,应用程序就是通过操作设备节点文件来完成对具体设备的操作

创建/dev/chrdev设备节点文件
mknod /dev/chrdev c 200 0
mknod:创建节点命令
/dev/chrdev:要创建的节点文件
c:字符设备
200 0:设备的主设备号和次设备号

创建完成以后就会存在/dev/chrdev文件,可以使用ls/dev/chrdev -l命令查看

3、设备测试

运行测试程序

./xxx(程序) 参数1 参数2... (参数传给应用层的main函数)
./chrdevbaseApp /dev/chrdevbase 1 //例如测试对chrdevbase设备的写操作

4、卸载驱动模块

rmmod xxx.ko

卸载后可以使用lsmod查看卸载模块是否成功

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

线程的状态

目录 1.线程状态的种类 2.线程的状态图 3.状态的详细说明 1.线程状态的种类 初始(NEW):新建一个线程,但还没有调用start方法 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态统称为"运行".线程对象创建后,其他线程调用了该对象的start()方法.该…

抽丝剥茧还原真相,记一次神奇的崩溃

作者:靳倡荣 本文详细回放了一个崩溃案例的分析过程。回顾了C多态和类内存布局、pc指针与芯片异常处理、内存屏障的相关知识。 一、不讲“武德”的崩溃 1.1 查看崩溃调用栈 客户反馈了一个崩溃问题,并提供了core dump文件,查看崩溃调用栈如下…

大数据-重新学习hadoop篇(第一天)-未完成

前言:首先这次重新学习为了后面校招,我会把我每天复习学到的一些觉得重要的知识点进行总结下来,持续更新,为实习做准备,加深记忆,从今天开始可能就不会法leetcode的相关题解了,但是每天还是会做…

【动态规划】不同路径,编辑距离题解及代码实现

Halo,这里是Ppeua。平时主要更新C语言,C,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接 我会一直往里填充内容哒! &…

【前端】深入浅出缓存原理

缓存的基本原理 对于前端来说,缓存主要分为浏览器缓存(比如 localStorage、sessionStorage、cookie等等)以及http缓存,也是本文主要讲述的。 当然叫法也不一样,比如客户端缓存大概包括浏览器缓存和http缓存 所谓htt…

“选用育留”,让AI搞定人力资源那点事

人工智能可以渗透应用到各行各业,在人力资源领域,技术已经重构了我们对人力资源的想象力,许多企业都在应用AI技术改善人力工作,人力资源的数智化不仅仅是将一部分日常事务性的工作交由AI处理,节约工作时间,…

到底什么是线程?线程与进程有哪些区别?

上一篇文章我们讲述了什么是进程,进程的基本调度 http://t.csdn.cn/ybiwThttp://t.csdn.cn/ybiwT 那么本篇文章我们将了解一下什么是线程?线程与进程有哪些区别?线程应该怎么去编程? 目录 http://t.csdn.cn/ybiwThttp://t.csdn…

HTTP详解

一,什么是HTTPHTTP(全称为“超文本传输协议”),是一种应用非常广泛的应用层协议,之前在《初识网络原理》的博客(初识网络原理_徐憨憨!的博客-CSDN博客)中,有详细讲解过TCP/IP五层模型,其中应用层描述了数据…

算法---完成任务的最少工作时间段

题目: 你被安排了 n 个任务。任务需要花费的时间用长度为 n 的整数数组 tasks 表示,第 i 个任务需要花费 tasks[i] 小时完成。一个 工作时间段 中,你可以 至多 连续工作 sessionTime 个小时,然后休息一会儿。 你需要按照如下条件…

即时通讯系列-N-客户端如何在推拉结合的模式下保证消息的可靠性展示

结论先行 原则: server拉取的消息一定是连续的原则: 端侧记录的消息的连续段有两个作用: 1. 记录消息的连续性, 即起始中间没有断层, 2. 消息连续, 同时意味着消息是最新的,消息不是过期的。同…

CKA最新考试费用是多少?考试内容是什么?

CKA认证考试是由Linux基金会和云原生计算基金会(CNCF)创建的,以促进Kubernetes生态系统的持续发展。该考试是一种远程在线、有监考、基于实操的认证考试,需要在运行Kubernetes的命令行中解决多个任务。CKA认证考试是专为Kubernetes管理员、云管理员和其他…

YOLOv8初体验:检测、跟踪、模型部署

安装 YOLOv8有两种安装方式,一种是直接用pip命令安装: pip install ultralytics另外一种是通过源码安装: git clone https://github.com/ultralytics/ultralytics cd ultralytics pip install -e .[dev]安装完成后就可以通过yolo命令在命令…

Yolov8详解与实战

文章目录摘要模型详解C2F模块Losshead部分模型实战训练COCO数据集下载数据集COCO转yolo格式数据集(适用V4,V5,V6,V7,V8)配置yolov8环境训练测试训练自定义数据集Labelme数据集摘要 YOLOv8 是 ultralytics …

Git规范

Commit 规范 常见的开源社区 commit message 规范: 比如 Angular 规范: 语义化:commit message 被归为有意义的类型用来说明本次 commit 的类型。 规范化:commit message 遵循预先定义好的规范,比如格式固定、都属…

GIS(地理信息系统/地理信息科学)职称评审三:中科院和人社部职称评审结果公示对比

目录1.前言2.中科院3.人社部3.1 初级、中级3.2 高级、正高级3.3 公示时间4. 证书5. 程序员要不要评职称?6.总结1.前言 我们在前两篇已经讲过了GIS(地理信息系统/地理信息科学)怎么评职称?以及中科院和人社部职称评审所需材料内容对…

Qss样式表语法

QSS样式表语法 更多精彩内容👉个人内容分类汇总 👈👉QSS样式学习 👈文章目录QSS样式表语法[toc]概述一、样式规则二、选择器类型三、子控件四、伪状态五、样式表冲突解决六、级联七、继承八、命名空间中的控件概述 Qt样式表的概念…

2023年了,还是没学会内卷....

先做个自我介绍:我,普本,通信工程专业,现在飞猪干软件测试,工作时长两年半。 回望疫情纪元,正好是实习 毕业这三年。要说倒霉也是真倒霉,互联网浪潮第三波尾巴也没抓住,狗屁造富神…

软件缺陷详解

软件缺陷报告 知识点 软件缺陷的定义缺陷产生的原因如何编写缺陷报告缺陷报告的书写准则 简介 软件测试的目的是为了发现尽可能多的缺陷,这里的缺陷是一种泛称,他可以指功能的错误,也可以指性能低下,或者易用性差等。执行软件…

深度学习必备知识——模型数据集Yolo与Voc格式文件相互转化

在深度学习中,第一步要做的往往就是处理数据集,尤其是学习百度飞桨PaddlePaddle的小伙伴,数据集经常要用Voc格式的,比如性能突出的ppyolo等模型。所以学会数据集转化的本领是十分必要的。这篇博客就带你一起进行Yolo与Voc格式的相互转化&…

力扣-超过经理收入的员工

大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:181. 超过经理收入的员工二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其…