Linux驱动开发(1)概念、环境与代码框架 - 实践

news/2025/9/22 20:43:39/文章来源:https://www.cnblogs.com/lxjshuju/p/19105997

一、驱动概念

驱动与底层硬件直接打交道,充当了硬件与应用软件中间的桥梁。

1、具体任务

        (1)读写设备寄存器(实现控制的方式)

        (2)完成设备的轮询、中断处理、DMA通信(CPU与外设通信的方式)

        (3)进行物理内存向虚拟内存的映射(在开启硬件MMU的情况下)

2、驱动的定位

        Linux系统主要部分:内核、shell、文件系统、应用程序。

        内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。分层设计的思想让程序间松耦合,有助于适配各种平台。驱动的上面是系统调用下面是硬件。

3、驱动的分类

Linux驱动分为三个基础大类:字符设备驱动,块设备驱动,网络设备驱动

(1)字符设备
        字符(char)设备是个能够像字节流(类似文件)一样被访问的设备。
        对字符设备发出读/写请求时,实际的硬件I/O操作一般紧接着发生。
        字符设备驱动程序通常至少要实现open、close、read和write系统调用。
        比如我们常见的lcd、触摸屏、键盘、led、串口等等,他们一般对应具体的硬件都是进行出具的采集、处理、传输。
(2)块设备
        一个块设备驱动程序主要通过传输固定大小的数据(一般为512或1k)来访问设备。
        块设备通过buffer cache(内存缓冲区)访问,可以随机存取,即:任何块都可以读写,不必考虑它在设备的什么地方。
        块设备可以通过它们的设备特殊文件访问,但是更常见的是通过文件系统进行访问。
        只有一个块设备可以支持一个安装的文件系统。
        比如我们常见的电脑硬盘、SD卡、U盘、光盘等。
(3)网络设备
        任何网络事务都经过一个网络接口形成,即一个能够和其他主机交换数据的设备。
        访问网络接口的方法仍然是给它们分配一个唯一的名字(比如eth0),但这个名字在文件系统中不存在对应的节点。
        内核和网络设备驱动程序间的通信,完全不同于内核和字符以及块驱动程序之间的通信,内核调用一套和数据包传输相关的函(socket函数)而不是read、write等。
        比如我们常见的网卡设备、蓝牙设备。

4、驱动的功能

        (1)对设备初始化和释放

        (2)把数据从内核传送到硬件和从硬件读取数据

        (3)读取应用程序传送给设备文件的数据和回送应用程序请求的数据

        (4)检测和处理设备出现的错误

二、环境搭建——以树莓派开发板为例

        树莓派是ARM架构的开发板。在烧录好系统之后(树莓派的系统烧录是将系统烧录进sd卡),配置无线网络(用于和开发的计算机进行通信)。

        下一步,通信成功之后,就要在自己的计算机(以下简称PC)上进行开发。大致的流程如下:

1、安装交叉编译工具链

        先去软件源刷新一下最新的软件清单:

sudo apt-get update

        然后安装交叉编译器以及相应的一些依赖工具:

sudo apt-get install gcc-arm-linux-gnueabihf build-essential bc bison flex libssl-dev

(1)交叉编译器 gcc-arm-linux-gnueabihf

(2)build-essential

(3)其他工具

(4)交叉编译器的选择

①选择标准

②交叉编译器命名规则

2、下载对应内核源码

        对应的,开发板上烧录的是什么系统,就需要下载对应的内核源码,这里是为了后续驱动开发做准备。

git clone --depth=1 --single-branch -b rpi-5.10.y https://github.com/raspberrypi/linux.git

3、获取开发板内核配置文件

        每个开发板对应的系统有差异,所以配置文件所在的地方也有差异。这里采用的是安装内核头文件从而获取内核配置文件的方式。

sudo apt-get install raspberrypi-kernel-headers

        安装完成之后,会得到一个目录:

/usr/src/linux-headers-$(uname -r)/

        这里uname-r作为参数,表示的是正在运行的 Linux 操作系统的内核版本。

        接下来讲整个目录打包,通过网络传到云服务器上

cd /usr/src
tar czf linux-headers.tar.gz linux-headers-$(uname -r)
scp linux-headers.tar.gz @:~/

        在云服务器上解压:(这里以放到~/目录下为例,实际可以放到一个更干净的目录下)

tar xzf linux-headers.tar.gz -C ~/

4、写驱动的makefile

        对于解压后的内核的头文件,需要做的就是在写驱动的makefile的时候放到KDIR里面。

obj-m += mydriver.o
KDIR := /home/xxx/linux-headers-5.10.63-v7l+   # 解压的内核头文件目录
PWD  := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules

        这样就能正常编译驱动文件了。

三、驱动编译的两种方式

1、编译进内核

        将驱动编译进 Linux 内核中,当 Linux 内核启动的时就会自动运行驱动程序。

2、编译成模块

        将驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用相应命令加载驱动模块。

        内核模块是Linux内核向外部提供的一个插口;内核模块是具有独立功能的程序,他可以被单独编译,但不能单独运行。他在运行时被链接到内核作为内核的一部分在内核空间运行;内核模块便于驱动、文件系统等的二次开发。

四、驱动框架

1、模块加载函数

module_init(xxx_init);

        module_init 函数用来向 Linux 内核注册一个模块加载函数,参数 xxx_init 就是需要注册的具体函数(理解是模块的构造函数),当加载驱动的时, xxx_init 这个函数就会被调用。

2、模块卸载函数

module_exit(xxx_exit);

        module_exit函数用来向 Linux 内核注册一个模块卸载函数,参数 xxx_exit 就是需要注册的具体函数(理解是模块的析构函数),当使用“rmmod”命令卸载具体驱动的时候 xxx_exit 函数就会被调用

3、模块许可证明

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

4、模块参数(可选)

        模块参数是一种内核空间与用户空间的交互方式,只不过是用户空间 --> 内核空间单向的,他对应模块内部的全局变量

5、模块信息(可选)

MODULE_AUTHOR("songwei") //添加模块作者信息

6、模块打印printk

printk在内核中用来记录日志信息的函数,只能在内核源码范围内使用。和printf非常相似。
printk函数主要做两件事情:①将信息记录到log中 ②调用控制台驱动来将信息输出

printk打印等级

printk 可以根据日志级别对消息进行分类,一共有 8 个日志级别:

#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"  /* 调试信息 */

        以下代码就是设置“gsmi: Log Shutdown Reason\n”这行消息的级别为 KERN_EMERG。

printk(KERN_DEBUG"gsmi: Log Shutdown Reason\n");

        如果使用 printk 的时候不显式的设置消息级别,那 么printk 将会采用默认级别MESSAGE_LOGLEVEL_DEFAULT,默认为 4

        对于控制台打印出的日志,如果代码中的打印等级低于默认控制台打印等级,则不会打印到控制台中。在 include/linux/printk.h 中有个宏 CONSOLE_LOGLEVEL_DEFAULT,定义如下:

#define CONSOLE_LOGLEVEL_DEFAULT 7

        CONSOLE_LOGLEVEL_DEFAULT 控制着哪些级别的消息可以显示在控制台上,此宏默认为 7,意味着只有优先级高于 7 的消息才能显示在控制台上。

        这个就是 printk 和 printf 的最大区别,可以通过消息级别来决定哪些消息可以显示在控制台上。默认消息级别为 4,4 的级别比 7 高,所示直接使用 printk 输出的信息是可以显示在控制台上的。

        但是,所有打印的信息,不管优先级多少,都可以通过dmesg显示,必要时可以通过管道筛选:dmesg | grep hello

7、模块操作命令

(1)加载模块

①insmod XXX.ko
        为模块分配内核内存、将模块代码和数据装入内存、通过内核符号表解析模块中的内核引用、调用模块初始化函数(module_init)
        insmod要加载的模块有依赖模块,且其依赖的模块尚未加载,那么该insmod操作将失败
②modprobe XXX.ko
        加载模块时会同时加载该模块所依赖的其他模块,提供了模块的依赖性分析、错误检查、错误报告
        modprobe 提示无法打开“modules.dep”这个文件 ,输入 depmod 命令即可自动生成 modules.dep

(2)卸载模块

rmmod XXX.ko

(3)查看模块信息

  • lsmod
    • 查看系统中加载的所有模块及模块间的依赖关系
  • modinfo (模块路径)
    • 查看详细信息,内核模块描述信息,编译系统信息

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

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

相关文章

9月22号

今天下午学习了Java的简单语法,学习了分解的思想

php企业网站源码下载哈尔滨 建设网站 科技

在AX4总线标准中,AXI4-Lite主要由向她址映射型通信。TEMAC的管理法口采用AXI4-Lite标准接口,TEMAC核的AX14-Lite接口信号如表1所示,根据AX14-Lite标准,接口角色分为主接口(Maser Interface)和从接口(Slave Interface)。主接口为通…

0.5*8 边形 != 式

之前会过,现在怎么就不会了Itst,神。感觉四边形不等式方面的理论学这么多就够了。 子矩阵指选出若干行和若干列,行列交点构成的矩阵;连续子矩阵指选取的行连续且列连续的子矩阵。 四边形不等式 对于矩阵 \(A\),若…

微信商城网站建设多少钱中国建筑网官网查询人员证书查

MySQL是一个广泛使用的开源关系型数据库管理系统,用于存储和管理大量数据。对于那些需要使用MySQL的管理员和开发人员来说,用户权限管理是确保数据库安全性的至关重要的一环。在本篇技术博客中,我们将深入探讨MySQL的用户权限管理&#xff0c…

初级程序员与网站开发广东网站建设专业公司

简介: 最佳实践,以DLA为例子。DLA致力于帮助客户构建低成本、简单易用、弹性的数据平台,比传统Hadoop至少节约50%的成本。其中DLA Meta支持云上15种数据数据源(OSS、HDFS、DB、DW)的统一视图,引入多租户、元…

成都网站设计服务商大连海洋大学工程建设信息网

一、基础知识:http://www.aminglinux.com/bbs/thread-6833-1-1.html 一、grep用grep把passwd文档中包含root或者‘500’的行过滤出来,并在过滤出来的行前面加上行号.grep -n root\|500 passwdr.o 如r1o,rto都满足该条件,.表示匹配…

万联芯城网站建设班级网站 建设模板

点击蓝字关注我们01.调试相关的宏在Linux使用gcc编译程序的时候,对于调试的语句还具有一些特殊的语法。gcc编译的过程中,会生成一些宏,可以使用这些宏分别打印当前源文件的信息,主要内容是当前的文件、当前运行的函数和当前的程序…

徐州网站建设新闻网站分站是怎么做的

在正文开始之前,请先来回答一下这个问题: 题目:输入为3个文件,a.txt 300MB,b.txt 100MB,c.txt 58.MB,使用MapReduce的example程序,计算Wordcount,请问,应该有多少个MapTask&#xf…

网站数据不变重新安装wordpress湖北微网站建设报价

本文资源来源自:中国新闻网转自公众号:科奖中心“创新的力量蕴藏在全社会之中,创新的资源理应向全社会开放。”全国政协委员,民盟中央常委、宁夏区委会主委冀永强近日接受中新社记者采访时表示,应积极鼓励探索“科研悬…

兰州网站建设多少钱创建免费网站需要的工具

1、数据仓库工作流调度 1.1 调度工具部署 工具部署链接 1.2 新数据生成 1.2.1 用户行为日志 1、启动日志采集通道,包括Kafka、Flume等 (1)启动Zookeeper zk.sh start(2)启动Kafka kf.sh start(3&…

高端品牌网站建设兴田德润在哪儿门户网站的建立

点击上方蓝字关注“汪宇杰博客”导语在我们生活的年代,博客并不稀奇,甚至可以说是随处可见。从最早的搜狐、新浪博客,再到每个人都曾记录青春的 QQ 空间,再到现在的 Vlog 与 Plog,似乎拥有一个自己的博客并不是什么难事…

网站如何优化关键词排名网站建设在线视频

引子: 最近在一篇文章中了解到EFF(电子前哨基金会)为了推广https协议,成立了一个letsencrypt项目,可以发放免费的证书,此证书可以被大多数主流浏览器所信任,这个邪恶的念头一爆发,就让我走上了一条坎坷的不…

题解:AT_agc052_c [AGC052C] Nondivisible Prefix Sums

题意:很简单了,不再赘述。 做法: 首先去掉一种很明显不行的方案即数的和为 \(P\) 的倍数,那不为 \(P\) 的倍数的有多少种呢? 因为不像正常的一样有 \(a_i=0\),不能说每次后面怎么填都有唯一一个对应,我们考虑记…

寻路算法

寻路算法 寻路算法核心特性对比总表算法 代价函数 f(n) 数据结构 是否保证最短路径? 优点 缺点 搜索行为比喻BFS (隐含 f(n) = g(n), 且权值=1) 队列 是 (等权图) 简单,保证最短路径(步数最少) 效率低,无方向性,…

2025年9月22日 - 20243867孙堃2405

今天我全天有课,早八是统一建模语言,第二节是算法与数据结构,下午只有一门课JAVA语言的学习,老师告诉我们要有一个设计的思路,主要的想法就是复杂问题简单化,就是把一个大问题分解成小而易解决的问题来完成

day 1

今天上课学了数据结构和java和统一建模语言,然后自学了并查集和二叉树,练了几道模板题,希望可以提升编码能力早日可以参加算法比赛。

东莞英文建站网站改备案

【来源】 题目3 : 活动中心 【分析】 本题採用的是三分法。 输入的一组点中找出左右边界。作为起始边界。 while(右边界-左边界<精度){将左右边界构成的线段均匀分成3段&#xff0c;推断切割点的距离关系&#xff0c;抹去距离大的一段。更新左右边界。 } 输出左(右)边界 【…

网站开发程序是什么建立免费空间网站

印刷电路板将布线区域划分成nm个方格如图a所示。精确的电路布线问题要求确定连接方格a的中点到方格b的中点的最短布线方案。在布线时&#xff0c;电路只能沿直线或直角布线&#xff0c;如图b所示。为了避免线路相交&#xff0c;已布了线的方格做了封锁标记&#xff0c;其它线路…

南京有哪些做网站的公司规范网站建设

在Python中调用C/C&#xff1a;cython及pybind11 转自&#xff1a;https://zhuanlan.zhihu.com/p/442935082 Python写起来非常方便, 但面对大量for循环的时候, 执行速度有些捉急. 原因在于, python是一种动态类型语言, 在运行期间才去做数据类型检查, 这样效率就很低(尤其是大规…

视频网站建设解决方案做照片书的模板下载网站

完全二叉树介绍完全二叉树应用场景完全二叉树和满二叉树的区别完全二叉树代码示例拓展 完全二叉树介绍 完全二叉树&#xff08;Complete Binary Tree&#xff09;是一种特殊的二叉树&#xff0c;它的定义是&#xff1a;如果设二叉树的深度为h&#xff0c;除第h层外&#xff0c…