字符设备驱动框架的编写

news2024/11/26 15:48:55

一. 简介

我们在学习裸机或者 STM32 的时候关于驱动的开发就是初始化相应的外设寄存器,在 Linux 驱动开发中,肯定也是要初始化相应的外设寄存器。
只是在 Linux 驱动开发中, 我们需要按照其规定的框架来编写驱动,所以说学 Linux 驱动开发重点是学习其驱动框架。

本文继上一篇文章的学习,前面几篇文章对字符设备驱动进行了简单的了解。文章地址如下:

字符设备驱动开发基础-CSDN博客

本文学习字符设备驱动的开发,主要学习字符设备驱动模块的加载与卸载。

二.  编写字符设备驱动框架

1.  Linux驱动的运行方式

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

选择驱动运行方式

在调试驱动时,一般都选择将其编译 为(.ko)模块,这样我们修改驱动以后,只需要编译一下驱动代码即可,不需要编译整个 Linux 代码。 而且在调试的时候只需要加载或者卸载驱动模块即可,不需要重启整个系统。总之,将驱动编 译为模块最大的好处就是方便开发,当驱动开发完成,确定没有问题以后就可以将驱动编译进 Linux 内核中。

2.   驱动的加载与卸载

模块有加载和卸载两种操作,我们在编写驱动时,需要注册这两种操作函数,模块的加载和 卸载注册函数如下:
module_init(xxx_init);   //注册模块加载函数
module_exit(xxx_exit);   //注册模块卸载函数
module_init() 函数用来向 Linux 内核注册一个模块加载函数,参数 xxx_init 就是需要注册的具体函数,当使用 “ insmod ” 命令加载驱动时, xxx_init() 这个函数就会被调用。
module_exit() 函数用来向 Linux 内核注册一个模块卸载函数,参数 xxx_exit 就是需要注册的具体函数,当使 用 “ rmmod ” 命令卸载具体驱动时, xxx_exit() 函数就会被调用。

3.  编写字符设备驱动框架

(1)  在 ubuntu系统下,创建一个存放驱动代码工程的目录,我这里在自己之前创建的正点原子文件目录下创建:

用 vscode软件打开 上面创建的工程目录 1_chrdevbase。通过 vscode在 目录 1_chrdevbase下创建一个 .c文件,命名为 chrdevbase.c,如下所示:

(2)  使用 vscode软件再打开 Linux内核源码,这里使用之前我更改的 NXP官方的 Linux内核源码。

Linux内核源码一般都会有使用到 驱动模块加载与卸载注册函数的。

在 Linux内核源码工程中,搜索 module_init() 函数与 module_eixt() 函数:

可以看到,Linux内核源码中,很多地方有调用到 module_init() 函数。当然也会调用到 module_exit()函数。

可以打开一个调用 module_init()函数的 .c文件,模仿 如何调用 module_init()函数。这里打开 aes_glue.c 文件,aes_glue.c文件中涉及 module_init()与 module_exit()函数的代码:

.......................................
static int __init aes_init(void)
{
	return crypto_register_alg(&aes_alg);
}

static void __exit aes_fini(void)
{
	crypto_unregister_alg(&aes_alg);
}

module_init(aes_init);
module_exit(aes_fini);
.......................................

模仿上面驱动模块的加载与卸载函数,编写 我的 chrdevbase.c 文件,再根据 上面 aes_glue.c中头文件添加相应的头文件,chrdevbase.c 文件的代码如下:

#include <linux/module.h>

/*
*  驱动模块入口函数
*/
static int __init chrdevbase_init(void)
{
	return 0;
}

/*
*  驱动模块出口函数
*/
static void __exit chrdevbase_exit(void)
{
	;
}

/*
* 驱动模块的入口与出口函数
*/
module_init(chrdevbase_init); /* 入口 */
module_exit(chrdevbase_exit); /* 出口 */

(3) 设置vscode软件中 1_chrdevbase工程的 头文件路径。具体设置 Linux内核源码路径。

不设置的话,vscode可能会提示一些错误,一些函数也找不到函数定义。

将正点原子提供的 Linux驱动例程中,01_chrdevbase工程代码中 .vscode文件及其下的文件都拷贝到 现在的 工程下。我这里没有安装 FTP客户端,所以,没办法拷贝文件夹。所以,可以在我1_chrdevbase工程下首先创建 .vscode目录,再在 .vscode目录下分别创建文件,将正点原子提供的 01_chrdevbase工程代码中 .vscode目录下文件的内容分别拷贝到相应文件。

.vscode目录下,创建如下两个文件:

编写驱动的时候注意事项:

(1) 编译驱动时需要用到 Linux内核源码!因此,需要解压缩 Linux内核源码。因为驱动代码中可能会调用到Linux内核源码中的一些函数。

同时,还需要编译linux内核源码,得到zImage和 .dtb设备树文件。需要使用编译后得到的zImage和 .dtb设备树文件来启动系统。

使用的Linux内核源码包:

这里使用正点原子第三期我编译的 Linux内核源码,也就是 在 NXP官方提供的 Linux内核源码更改后的 Linux内核源码包。

我这里的 Linux内核源码所在路径为:

/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga

更改 .vscode目录下 c_cpp_propertities.json文件下的 Linux源码路径:

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/include", 
                "/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include", 
                "/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/include/generated/"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "clang-x64"
        }
    ],
    "version": 4
}

下一篇文章学习对工程进行编译,并加载与卸载字符驱动模块。

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

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

相关文章

【网络安全】网络防护之旅 - Java安全机制探秘与数字证书引爆网络防线

&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《网络安全之道 | 数字征程》⏰墨香寄清辞&#xff1a;千里传信如电光&#xff0c;密码奥妙似仙方。 挑战黑暗剑拔弩张&#xff0c;网络战场誓守长。 目录 &#x1f608;1. 初识网络安…

机场信息集成系统系列介绍(3):机场运行核心数据库(AODB)

目录 1、背景&#xff1a;什么是AODB 2、AODB包括哪些内容 3、AODB还应该适配哪些场景 4、一点点拓展 机场运行核心数据库&#xff08;AODB&#xff09;Airport Operation DataBase 1、背景&#xff1a;什么是AODB 在机场繁重的航班保障和旅客服务背后&#xff0c;庞大的…

centos安装了curl却报 -bash: curl: command not found

前因 我服务器上想用curl下载docker-compress&#xff0c;发现没有curl命令&#xff0c;就去下载安装&#xff0c;安装完成之后&#xff0c;报-bash: curl: command not found 解决方法 [rootcentos ~]# rpm -e --nodeps curl warning: file /usr/bin/curl: remove failed: …

非常好用的C++跨平台网络通信Mongoose,随笔记录

简介 Mongoose 是一个 C/C 网络库。它实现了事件驱动&#xff0c; TCP、UDP、HTTP、WebSocket、MQTT 的非阻塞 API。它连接设备 并将它们带到网上。自 2004 年以来&#xff0c;一些开源和商业 产品已经利用了它。它甚至运行在 国际空间站&#xff01; Mongoose 使嵌入式网络编…

【数据结构】(堆)Top-k|堆排序

目录 概念&#xff1a; 堆的实现 构建 初始化 销毁 插入元素 往上调整 删除堆顶元素 往下调整 返回堆顶元素 返回有效个数 是否为空 堆排序 Top-k问题 ​编辑 创建数据 堆top-k 概念&#xff1a; 堆是将数据按照完全二叉树存储方式存储到一维数组中&#xff…

Python实验项目9 :网络爬虫与自动化

实验 1&#xff1a;爬取网页中的数据。 要求&#xff1a;使用 urllib 库和 requests 库分别爬取 http://www.sohu.com 首页的前 360 个字节的数据。 # 要求&#xff1a;使用 urllib 库和 requests 库分别爬取 http://www.sohu.com 首页的前 360 个字节的数据。 import urllib.r…

网络 / day02 作业

1. TCP和UDP通信模型 1.1 TCP server #include <myhead.h>#define PORT 9999 #define IP "192.168.250.100"int main(int argc, const char *argv[]) {//1. create socketint sfd -1;if( (sfd socket(AF_INET, SOCK_STREAM, 0 ))-1 ){perror("socke…

YOLOv5改进 | SPPF | 将RT-DETR模型AIFI模块和Conv模块结合替换SPPF(全网独家改进)

一、本文介绍 本文给大家带来是用最新的RT-DETR模型中的AIFI模块来替换YOLOv5中的SPPF。RT-DETR号称是打败YOLO的检测模型&#xff0c;其作为一种基于Transformer的检测方法&#xff0c;相较于传统的基于卷积的检测方法&#xff0c;提供了更为全面和深入的特征理解&#xff0c…

机器学习 | KNN算法

一、KNN算法核心思想和原理 1.1、怎么想出来的&#xff1f; 近朱者赤&#xff0c;近墨者黑&#xff01; 距离决定一切、民主集中制 1.2、基本原理 —— 分类 k个最近的邻居 民主集中制投票分类表决与加权分类表决 1.3、基本原理 —— 回归 计算未知点的值决策规则不同均值法与…

Vue2-动态组件案例

1.component介绍 说明&#xff1a; Type: string | ComponentDefinition | ComponentConstructor Explanation: String: 如果你传递一个字符串给 is&#xff0c;它会被视为组件的名称&#xff0c;用于动态地渲染不同类型的组件。这是一个在运行时动态切换组件类型的常见用例。…

西南科技大学数字电子技术实验六(智力竞赛抢答器的设计及FPGA实现)FPGA部分

一、实验目的 进一步掌握D触发器&#xff0c;分频电路&#xff0c;多谐振荡电器&#xff0c;CP时钟脉冲元等单元电路的设计。 二、实验原理 三、程序清单&#xff08;每条语句必须包括注释或在开发窗口注释后截图&#xff09; 逻辑代码&#xff1a; module contend ( inpu…

OpenCV 1.1:读取本地图片显示灰度图及CV版本

imread方法加载图像 imread 功能是加载图像文件成为一个 Mat 对象&#xff0c;其中第一个参数表示图像文件名称&#xff0c;第二个参数表示加载的图像是什么类型&#xff0c;支持常见的三个参数值IMREAD_UNCHANDED(<0) 表示加载原图&#xff0c;不做任何改变IMREAD_GRAYSCA…

Docker插件和扩展:深入Docker功能的完整指南

Docker作为一种流行的容器化技术&#xff0c;不仅令应用程序的部署更为便捷&#xff0c;同时也提供了丰富的插件和扩展机制&#xff0c;以满足更多复杂场景下的需求。本文将深入研究Docker的插件和扩展&#xff0c;提供更为详实和全面的示例代码&#xff0c;助力读者更好地理解…

DPO讲解

PPO算法的pipeline冗长&#xff0c;涉及模型多&#xff0c;资源消耗大&#xff0c;且训练极其不稳定。DPO是斯坦福团队基于PPO推导出的优化算法&#xff0c;去掉了RW训练和RL环节&#xff0c;只需要加载一个推理模型和一个训练模型&#xff0c;直接在偏好数据上进行训练即可&am…

计算机出现xinput1_3.dll缺失、五种详细解决方案

在电脑使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是xinput1_3.dll丢失。这个错误提示通常会导致游戏或其他应用程序无法正常运行。那么&#xff0c;xinput1_3.dll文件到底是什么&#xff1f;它丢失会对电脑产生什么影响&#xff1f;本文将为您详…

1688订单详情对接及实现方案

一、引言 1688作为中国最大的B2B电子商务平台之一&#xff0c;提供了丰富的商品信息和订单详情。通过与1688订单详情接口的对接&#xff0c;电商企业可以实时获取订单详细信息&#xff0c;以便更好地了解客户需求、优化运营策略以及提高服务质量。本文将详细介绍如何实现1688订…

《数据结构、算法与应用C++语言描述》-机器调度-最长处理时间(LPT)-堆应用

机器调度 完整可编译运行代码见&#xff1a;Github::Data-Structures-Algorithms-and-Applications/_28LongestProcessingTime 问题描述 一个工厂具有 m台一模一样的机器。我们有n 个任务需要处理。设作业i的处理时间为 t i t_i ti​&#xff0c;这个时间包括把作业放入机器…

【PostgreSQL】从零开始:(十二)PostgreSQL-数据库对象关系及定义

从图中我们可以看出服务器对象的关系 现在我们来了解它们的定义 数据库服务器(Server) 数据库服务器是一种用来存储、管理和查询大量数据的服务器。它是一个独立的计算机系统&#xff0c;运行数据库管理系统&#xff08;DBMS&#xff09;软件&#xff0c;并提供对数据库的访问…

【ECMAScript笔记二】运算符分类,流程控制(顺序结构、分支结构、循环结构)

文章目录 4 运算符4.1 算术运算符4.2 递增和递减运算符4.3 比较运算符4.4 逻辑运算符4.5 赋值运算符4.6 运算优先级 5 流程控制5.1 顺序结构5.2 分支结构5.2.1 if 语句5.2.2 switch 语句 5.3 循环结构5.3.1 for循环5.3.2 while循环5.3.3 do while循环5.3.4 continue和break 5.4…

数据科学知识库

​ 我的博客是一个技术分享平台&#xff0c;涵盖了机器学习、数据可视化、大数据分析、数学统计学、推荐算法、Linux命令及环境搭建&#xff0c;以及Kafka、Flask、FastAPI、Docker等组件的使用教程。 在这个信息时代&#xff0c;数据已经成为了一种新的资源&#xff0c;而机…