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查看卸载模块是否成功
相关文章:
Linux驱动开发
一、驱动分类Linux中包含三大类驱动:字符设备驱动、块设备驱动和网络设备驱动。其中字符设备驱动是最大的一类驱动,因为字符设备最多,从led到I2C、SPI、音频等都属于字符设备驱动。块设备驱动和网络设备驱动都要比字符设备驱动复杂。因为其比…...
32--Vue-前端开发-Vue语法之组件化开发
一、vue语法回顾 购物车的例子 eg1:计算商品价格(掌握对象的迭代方法) <!DOCTYPE html> <html lang="en"> <head>...
打怪升级之CFileDialog类介绍
CFileDialog类 CFileDialog封装用于文件打开操作或文件保存操作的常见对话框。信息来源自Windows官方文档:https://learn.microsoft.com/zh-cn/cpp/mfc/reference/cfiledialog-class?viewmsvc-170 这里重点介绍几个常用的函数功能: 构造函数 explic…...
配天智造自主原创数字工厂:百余名员工人均创收122万
配天智造(832223)2022年度报告显示,报告期内公司实现营业收入1.3亿元,同比增长52%,归属于挂牌公司股东的净利润3867万元,同比增长28.11%。而这家公司全部在职员工仅有107人,人均创收约为122万。…...
COLMAP
简介:在使用instant-ngp过程中需要使用COLMAP得到模型的必要输入,比如模型需要的相机外参我们就可以通过COLMAP中的sparse reconstruction稀疏重建得到;而对于depth map深度图我们则需要dense reconstruction稠密重建得到,下面我们…...
2023-3-8 刷题情况
礼盒的最大甜蜜度 题目描述 给你一个正整数数组 price ,其中 price[i] 表示第 i 类糖果的价格,另给你一个正整数 k 。 商店组合 k 类 不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼盒中任意两种糖果 价格 绝对差的最小值。 返回礼盒的 最大 甜蜜度。…...
关于长连接服务器和客户端之间要加入心跳的一些讨论
在之前的章节里深入浅出TCPIP之深入浅出TCPIP之TCP重传机制 我们都知道了TCPIP协议栈有个默认的TCP心跳机制,这个心跳机制是和socket绑定的,可以对指定的套接字开启协议栈的心跳检测机制。默认情况下,协议栈的心跳机制对socket套接字是关闭的,如果要使用需要人为开启的。 比…...
LeetCode——1590. 使数组和能被 P 整除
一、题目 给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1…...
12N65-ASEMI高压MOS管12N65
编辑-Z 12N65在TO-220封装里的静态漏极源导通电阻(RDS(ON))为0.68Ω,是一款N沟道高压MOS管。12N65的最大脉冲正向电流ISM为48A,零栅极电压漏极电流(IDSS)为10uA,其工作时耐温度范围为-55~150摄氏度。12N65功耗&#x…...
cushy-serial 一个轻量级Python serial库
本文自笔者博客: https://www.blog.zeeland.cn/archives/rgoihgxcoci3 简介 cushy-serial是一个轻量级的Serial框架,初衷是希望使Serial编程变得更加简单、快捷,因此,相较于传统的pyserial,该框架可以更加快速地构建起一个serial…...
音视频开发系列(7)——Opengl常用Api介绍part1
GLES20.glTexParameteri GLES20.glTexParameteri是OpenGL ES 2.0用于设置纹理过滤器和纹理包装模式的函数。它有三个参数: target参数 target参数指定要设置纹理参数的纹理目标,根据不同的target值,glTexParameteri函数的行为也会有所不同…...
linux时间的特殊用法
今天介绍linux下Date时间命令相关的特殊用法 date (当前的时间) 修改系统当前时间: date -s "2022-6-20 9:33:50" 昨天的时间是我们比较常用的: date -d "yesterday" %Y%m%d ( 昨天的时间) date -d "1 day ago" %Y%m%d …...
axios 封装,API接口统一管理
分享一个自己封装的 axios 网络请求 主要的功能及其优点: 将所有的接口放在一个文件夹中管理(api.js)。并且可以支持动态接口,就是 api.js 文件中定义的接口可以使用 :xx 占位,根据需要动态的改变。动态接口用法模仿…...
SpringBoot使用Redis实现缓存
目录 实现步骤 1. 在 pom.xml 配置文件中添加如下依赖 2. 在 application.properties 中添加如下配置 3. 新建 RedisConfig.class,继承 CachingConfigurerSupport,添加如下方法 4. 新建 RedisService.class 添加如下方法 注意:cacheKey…...
[失业前端恶补算法]JavaScript leetcode刷题top100(三)
专栏声明:只求用最简单的,容易理解的方法通过,不求优化,不喜勿喷 今天更新五个 easy 难度题目: 相交链表 题面 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个…...
Spark RDD的设计与运行原理
一、Spark RDD概念 一个RDD就是一个分布式对象集合,本质上是一个只读的分区记录集合,每个RDD可以分成多个分区,每个分区就是一个数据集片段,并且一个RDD的不同分区可以被保存到集群中不同的节点上,从而可以在集群中的…...
Golang的下载与安装
Windows系统 进入golang官方下载网站:所有版本 - Go 编程语言如图所示 下载后打开您下载的 MSI 文件,然后按照提示安装 Go。 验证是否已安装 Go。...
广州蓝景分享—8大Web前端开发的趋势
2023 年 1 月 11 日,2022 年度 StateOfJS 调查结果正式公布!StateOfJS 是前端生态圈中比较有影响力的且规模较大的数据调查。本文就来解读一下 2022 年 StateOfJS 的调查结果! JavaScript 发展很快,但似乎 JavaScript 开发人员的…...
Java学习-MySQL-创建数据库表
Java学习-MySQL-创建数据库表 SHOW DATABASESUSE school CREATE TABLE IF NOT EXISTS student( id INT(10) NOT NULL AUTO_INCREMENT COMMENT 学号, name VARCHAR(30) NOT NULL DEFAULT 匿名 COMMENT 姓名, pws VARCHAR(20) NOT NULL DEFAULT 123456 COMMENT 密码, sex VARCHA…...
Ethercat学习-GD32以太网学习
文章目录1、GD32F4以太网简介2、以太网模框图简介3、以太网主要模块介绍SMI接口RMII接口与MII接口DMA控制器4、以太网配置流程5、其他1、GD32F4以太网简介 GD32F4系列以太网模块包含10/100Mbps以太网MAC,数据的收发都通过DMA进行操作,支持MII࿰…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
