当前位置: 首页 > news >正文

【linux-IMX6ULL-字符设备驱动简单框架实验】

目录

  • 1. 字符设备驱动简介
    • 1.1 重要函数
    • 1.2 简单框架代码流程
    • 1.3 linux中关于驱动的重要命令
  • 2. 字符设备驱动简单框架编写
    • 2.1 添加LICENSE信息
    • 2.2 驱动模块的入口与出口
    • 2.3 入口和出口函数的编写
    • 2.4 设备操作结构体定义
      • 2.4.1 结构体函数内容填充
  • 3. 应用程序简介:
  • 4. 应用程序的编写思路

1. 字符设备驱动简介

  目前的驱动开发一般是分为三类,第一类就是字符设备驱动、块设备驱动、和网络驱动三类,其中字符设备驱动是最多最杂的,现在对字符设备驱动进行一个简要的介绍:
  字符设备驱动,是指那些以字节流进行数据传输的设备、IIC、SPI、LCD、按键、例如键盘、鼠标、打印机等,其中包含以下几个关键的部分:

  1. 设备注册和注销:通过设备注册使设备能被系统识别;注销则相反;
  2. 数据操作函数:通常包含open,read,write,realse等;
  3. 中断处理:处理设备产生的中断,以响应特定事件;

   通过字符型设备驱动,可以使系统方便统一管理不同的设备,这样就可以给上层应用提供相应的接口函数,方便应用程序与设备之间进行数据交换和通信;



   本次的实验是通过简单的实验建立一个设备驱动开发的基本框架,为后续的学习打下基础,其中会列出重要的函数以及重要的挂载指令,当然其中有一些函数是比较老的,例如要手动分配设备号,但是为了便于学习目前就以简单的为主,因为越是抽象的越简单,但是越抽象就越难以理解;

1.1 重要函数

  这里只是把本实验相关的重要函数给罗列出来了,主要的作用就是对本次实验的一个总结,如果没有做个这个实验,那么看着没啥感觉的;例如我下面罗列函数的顺序就是我们在编写驱动实验时整个流程的顺序,首先就是注册入口和出口函数,其次就是编写入口和出口函数,再次就是编写文件结构体的对应相关的函数内容;

  • MODULE-LICENSE("GPL"): 表示该内核模块遵循的许可协议是通用公共许可(GPL)。指定许可协议非常重要,它明确了该模块在使用、分发等方面的权利和限制。如果不写这个的话就会导致在装载设备驱动时出现警告;
  • module_init(*****_init):模块的入口函数,进行初始化,也就是加载模块时第一个就是运行这个函数注册的函数*******;对模块进行初始化设置;
  • module_exit(*****_exit):模块的出口函数,对模块进行卸载时就会执行这个函数注册的函数*******;
  • static int __init *****_init(void):设备加载函数,进行模块的初始化和加载的设置;这个函数要被入口函数进行注册后起作用
  • register_chrdev(unsigned int major, const char *name, const struct file_operations *fops):对设备进行注册;
  • static int __exit *****_exit(void):设备卸载函数、进行模块的卸载时这个函数内部的程序就会执行,不过要被出口函数进行注册
  • unregister_chrdev(unsigned int major, const char *name):对模块进行卸载;
  • static const struct file_operations **_fops : struct file_operations是一个很重要的结构体,其中定义了很多与文件操作有关的函数指针,例如read,write,realse,open等等,这些函数可以按需进行填充,这样就方便与设备之间进行文件的操作;下面进行实验时会进行一个详细的说明;

1.2 简单框架代码流程

  代码实验编写流程:


在这里插入图片描述


1.3 linux中关于驱动的重要命令

  • lsmod:显示有哪些模块被加载了,也就是显示所有的加载模块
  • lsmod:显示有哪些模块被加载了,也就是显示所有的加载模块
  • depmod:更新模块的依赖关系,也就是新加载一个模块时,要先运行一下这个命令,不然有错误
  • modprob ***.ko:这个命令的作用就是加载模块***.ko
  • mknod /dev/*** c 200 0:mknod:手动创建节点的命令。/dev/*** :创建设备的名称。c:字符型设备。200:主设备号,自己指定。0:次设备号,自己指定。
  • cat /proc/devices:这个命令的作用是查看所有加载的模块,显示所有设备号等;
  • rmmod ***.ko:卸载模块***.ko;
  • cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq:这个命令是显示当成CPU的频率;

2. 字符设备驱动简单框架编写

  上面已经介绍了驱动编写的则整体流程,以及介绍了重要的加载驱动的一些linux的命令,因此下面的代码就不做过多的介绍:

2.1 添加LICENSE信息

  我们需要在代码中添加LICENSE信息,否则编译会出错,不过我们还可以添加一些其他的信息,例如作者,邮箱等等;

MODULE_LICENSE("GPL");

2.2 驱动模块的入口与出口

  linux的驱动有两种加载形式,一就是编译进linux内核中,当内核启动,驱动也启动,另一种方法就是把启动编译成模块也就***.ko文件,通过insmode或者modprob的命令进行加载模块,这样做的好处就是便于调试,而且不用重启linux内核;代码如下,下面两个函数的作用就是对模块进行加载和卸载,并在加载和卸载函数中对字符设备进行注册,如我们裸机编程中系统中断函数对中断服务函数的注册一样;

/* * 模块入口和出口函数注册*/ 
module_init(chrdevbase_init);/*入口,加载模块*/
module_exit(chrdevbase_exit);/*出口,卸载模块*/

2.3 入口和出口函数的编写

  注意,入口函数是通过__init来修饰(注意是两个杠),而对于出口函数通过__exit进行修饰,在出入口函数中对设备进行注册,CHRDEVBASE_MAJOR是设备号,CHREEVBAScE_NAME是设备名,chrdevbase_fops是文件操作结构体;出口函数是类似的;

#define CHRDEVBASE_MAJOR 200  
#define CHREEVBASE_NAME "chrdevbase"static int __init chrdevbase_init(void)
{printk("chrdevbase_init3\r\n");/*注册字符设备*/register_chrdev(CHRDEVBASE_MAJOR, CHREEVBASE_NAME,&chrdevbase_fops);return 0;
}
static void __exit chrdevbase_exit(void)
{printk("chrdevbase_exit\r\n");unregister_chrdev(CHRDEVBASE_MAJOR,CHREEVBASE_NAME);
}

2.4 设备操作结构体定义

  对于设备的操作file_operations结构体,也称为文件操作结构体,这也是为什么linux下一切皆文件,我们的操作大部分都是通过文件来进行管理,我们可能用不到那么多的功能,因此我们要用到什么功能就进行对应的添加和书写就行,代码如下,注意这里使用的是=:

static const struct file_operations chrdevbase_fops={.owner	= THIS_MODULE,.open	= chrdevbase_open,.release	= chrdevbase_release,.read	= chrdevbase_read,.write	=	chrdevbase_write,
};

2.4.1 结构体函数内容填充

  可以看到,我们对上面的文件操作结构体中定义了四个函数指针,分别是:chrdevbase_open、chrdevbase_release、chrdevbase_read、chrdevbase_write,接下来就是对这四个函数进行内容填充:

static char readbuf[100];/*读缓冲*/
static char writebuf[100];
static char kerneldata[]={"kernel data!"};/************/
static ssize_t chrdevbase_read(struct file * file, char * buf, size_t count, loff_t *off)
{int ret=0;memcpy(readbuf,kerneldata,sizeof(kerneldata));ret = copy_to_user(buf,readbuf,count);if(ret<0){printk("Error!");}else{}return 0;
}
/************/
static ssize_t chrdevbase_write(struct file * file, const char * buf, size_t count,loff_t *off)
{int ret =0;ret = copy_from_user(writebuf,buf,count);printk("Kernel recevdata:%s\r\n",writebuf);if(ret = 0){printk("Kernel recevdata:%s\r\n",writebuf);}return 0;
}
static int chrdevbase_release(struct inode * inode, struct file * file)
{printk("chrdevbase_ralease\r\n");return 0;
}
static int chrdevbase_open(struct inode * inode, struct file * file)
{printk("chrdevbase_open\n");return 0;
}

3. 应用程序简介:

  当驱动程序编写完毕后,要通过应用程序进行调用驱动函数的一些接口函数,这些功能的实现是在应用程序中实现的,这样就实现了应用程序与驱动程序的分离可以这样类比,我们写应用程序就相当于我们在windows系统上写C程序,我们写C程序时也没有关注下层,这就是一种分离,不过这两者是可以相互进行数据交换的,不过要用特定的方法;注意驱动程序和应用程序的编译是不一样的:对于应用程序的编译是下面的指令:

  • arm-linux-gnueabihf-gcc ***APP.c -o ***APP:应用程序的编译指令
  • $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules:驱动程序的编译:Make部分核心指令

   从上面的编译指令中就可以看出区别,对于驱动的编译要用到一系列的库,这些库包含板子的信息,以及一些arm中的一些库等等,最终生成一个驱动模块,属于下层的驱动文件;
  而对于应用程序的编译则是用到了一个.c文件以及基础库,就像我们编译C语言一样,只不过我们写一个hello.c文件用的是gcc编译器,生成的是x86架构的可执行文件,同理,我们使用arm-linux-gnueabihf-gcc交叉编译器生成的是arm架构的可执行文件,这明显是上层的应用程序,不过我们写上层应用程序时通过传参命令的形式就可以与下层的驱动进行数据文件交换;

4. 应用程序的编写思路

  编写测试APP就是编写Linux应用程序,需要用到C库和文件操作相关的一些函数,open、read、write 和 close 这四个函数;这些函数可以根据下面的命令进行找详细帮助:“man 1”通常是用户命令的手册页;“man 2”一般是系统调用的手册页;“man 3”可能是 C 库函数的手册页;

wyj@BK:~$ man 2 read
wyj@BK:~$ man 2 write
wyj@BK:~$ man 2 close
wyj@BK:~$ man 2 open

  因此在应用程序中编写程序就是如何对驱动程序进行调用和使用,不过要注意的是对于驱动的编写属于内核态,而对于应用程序的编写属于应用态,应用态不能直接操作内核态,要通过一定的程序从而间接操作内核态

int mian(int argc,char *argv[])
{int ret = 0;int fd = 0;char *filename;char readbuf[100];char writebuf[100];static char usrdata[]={"Usr data!Usr data!Usr data!"};filename=argv[1];fd = open(filename, O_RDWR);if(fd<0){printf("Can't open file %s\r\n",filename);}/*read*/if(atoi(argv[2])==1){ret=read(fd, readbuf, 50); printf("\r\nAPP read data:%s\r\n",readbuf);}/*write*/if(atoi(argv[2])==2){memcpy(writebuf,usrdata,sizeof(usrdata));ret = write(fd, writebuf,50);}/*close*/ret = close(fd);if(ret<0){printf("Can't close %s\r\n",filename);}return 0;
}

相关文章:

【linux-IMX6ULL-字符设备驱动简单框架实验】

目录 1. 字符设备驱动简介1.1 重要函数1.2 简单框架代码流程1.3 linux中关于驱动的重要命令 2. 字符设备驱动简单框架编写2.1 添加LICENSE信息2.2 驱动模块的入口与出口2.3 入口和出口函数的编写2.4 设备操作结构体定义2.4.1 结构体函数内容填充 3. 应用程序简介&#xff1a;4.…...

3D模型旋转显示不全怎么办---模大狮模型网

在3D建模和渲染过程中&#xff0c;我们有时会遇到旋转模型时显示不全的问题。这种情况可能由多种原因造成&#xff0c;包括模型本身的问题、软件设置不当、硬件配置不足等。本文将为您详细介绍几种可能的解决方法&#xff0c;帮助您解决3D模型旋转显示不全的问题。 一、检查模型…...

DLRover:蚂蚁集团开源的AI训练革命

在当前的深度学习领域&#xff0c;大规模训练作业面临着一系列挑战。首先&#xff0c;硬件故障或软件错误导致的停机时间会严重影响训练效率和进度。其次&#xff0c;传统的检查点机制在大规模训练中效率低下&#xff0c;耗时长且容易降低训练的有效时间。资源管理的复杂性也给…...

ubuntu_概念

su(switch user) wget(Web Get) cd(change directory) dpkg(Debian Packager)为 “Debian” 专门开发的套件管理系统&#xff0c;方便软件的安装、更新及移除。 chmod(Change Mode)用于改变文件或目录的权限 ps(Process Status)进程状态 grep(Global Regular Expression Print)…...

Oracle递归查询笔记

目录 一、创建表结构和插入数据 二、查询所有子节点 三、查询所有父节点 四、查询指定节点的根节点 五、查询指定节点的递归路径 六、递归子类 七、递归父类 一、创建表结构和插入数据 CREATE TABLE "REGION" ( "ID" VARCHAR2(36) DEFAULT SYS_GUI…...

FaceFusion源码框架解读

FaceFusion源码框架解读 我的视频讲解&#xff1a;FaceFusion入门教学 FaceFusion官网 FaceFusion是一款开源的AI换脸工具&#xff0c;一款非常好用的换脸工具&#xff0c;操作简单&#xff0c;上手容易。 Facefusion&#xff1a;GitHub - facefusion/facefusion: Next gene…...

React项目知识积累(三)

1.primary-color 公共样式 less文件中的primary-color&#xff0c;会在config.js中的theme中统一写,方便统一更改。 config.js: theme{"primary-color":"#f0f0f0"&#xff0c;"font-size":"16px", }less: .classname{color:primary-…...

前端实现打印功能

1、引入打印相关的库 在您的Vue项目中,需要先安装一个用于打印的库,如print-js。您可以通过以下命令安装&#xff1a; npm install print-js --save2、在组件中引入并使用&#xff0c;在需要实现打印功能的组件中&#xff0c;先import print-js模块&#xff1a; import print…...

创建型模式之工厂模式

文章目录 概述1.简单工厂概念结构图 2.工厂方法概念结构图 3.抽象工厂概念结构图 小结 概述 工厂模式用来创建不同但是相关类型的对象&#xff08;继承同一父类或者接口的一组子类&#xff09;&#xff0c;由给定的参数来决定创建哪种类型的对象。 其实&#xff0c;工厂还可以…...

「动态规划」按摩师

力扣原题链接&#xff0c;点击跳转。 一个有名的按摩师会收到源源不断的预约请求&#xff0c;每个预约都可以选择接或不接。在每次预约服务之间要有休息时间&#xff0c;因此她不能接受相邻的预约。给定一个预约请求序列nums&#xff0c;总共有n个预约&#xff0c;替按摩师找到…...

小程序-滚动触底-页面列表数据无限加载

// index/index.vue <template> <!-- 自定义导航栏 --> <CustomNavbar /> <scroll-view scrolltolower"onScrolltolower" scroll-y class"scroll-view"> <!-- 猜你喜欢 --> <Guess ref"guessRef" /> </s…...

监控上网的软件有哪些?含泪推荐的电脑监控软件

监控上网的软件有很多&#xff0c;企业选择的时候应该遵循什么样的原则呢&#xff1f;鄙人愚见&#xff0c;认为以下四项原则是选择监控软件时首要考虑的。 1、功能需求&#xff1a; 监控软件不应该只是起到控制上网的作用&#xff0c;因为一些泄密行为可能是通过USB接口、打印…...

linux系统防火墙开放端口命令

目录 linux相关命令参考文章1.开放端口1.1 开发单个端口1.2 一次性开放多个端口 2.保存设置3.查看所有开放的端口4.查看防火墙状态 linux相关命令参考文章 管理、设置防火墙规则&#xff08;firewalld&#xff09;: https://download.csdn.net/blog/column/8489557/137911049 i…...

WebGL渲染引擎优化方向——渲染帧率的优化

作者&#xff1a;caven chen 对此内容感兴趣还可以看前文&#xff1a; WebGL渲染引擎优化方向——加载性能优化 前言 WebGL 是一种强大的图形渲染技术&#xff0c;可以在浏览器中快速渲染复杂的 3D 场景。但是&#xff0c;由于 WebGL 的高性能和高质量要求&#xff0c;如果…...

【文献阅读】ESG评级分化和企业绿色创新

ESG评级分化和企业绿色创新 摘要 &#xff08;1&#xff09;本研究通过实证探讨了ESG评级差异是否以及如何影响企业绿色创新。以中国上市公司为样本&#xff0c;我们发现ESG评级差异对企业绿色创新有积极的影响 。经过几次稳健性检查后&#xff0c;该结果仍然成立。 &#xff…...

2024-5-6-从0到1手写配置中心Config之实现配置中心客户端

配置加载原理 在Spring中PropertySource类实现了所有属性的实例化。 启动赋值&#xff1a; 定义自定义属性配置源&#xff0c;从config-server获取全局属性&#xff1b;Spring启动时&#xff0c;插入自定义属性配置源&#xff1b;绑定属性会优先使用&#xff0c;给自定义属性…...

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(十一)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 18 节&#xff09; P18《17.ArkUI-状态管理Observed 和 ObjectLink》 第一件事&#xff1a;嵌套对象的类型上加上 Observed 装饰器…...

Amesim示例篇-案例1:空间中的铝块散热

前言 本文将通过一个案例继续对Thermal库的元件进一步讲解。 案例1&#xff1a;一个300mm*300mm*1000mm&#xff08;长*宽*高&#xff09;的铝板初始温度为45℃&#xff0c;竖直在环境为25℃的空间内静置60min。对流换热系数设置为5W/m2K。本文将通过两种建模方法对铝块的温度…...

深度神经网络——什么是自动编码器?

自动编码器 自动编码器&#xff08;Autoencoders&#xff09;是无监督学习领域中一种重要的神经网络架构&#xff0c;它们主要用于数据压缩和特征学习。 自动编码器的定义&#xff1a; 自动编码器是一种无监督机器学习算法&#xff0c;它通过反向传播进行训练&#xff0c;目标…...

初见flyway

flyway (一种数据库版本控制工具 document) 两种文件 V 和 R V: V 开头是不可重复执行的文件&#xff0c;每次修改完都该更改名称 R: R 开头是可重复执行的文件&#xff0c;需要保证内部sql都是可以重复执行的 名称格式&#xff1a; V__table_name.sql, R__table_name.sql …...

9.6 Go语言入门(数组、切片和指针)

Go语言入门&#xff08;数组、切片和指针&#xff09; 目录五、数组、切片和指针1. 数组1.1 声明和初始化数组1.2 访问和修改数组元素1.3 多维数组 2. 切片2.1 声明和初始化切片2.2 访问和修改切片元素2.3 切片操作2.4 切片的追加和拷贝 3. 指针3.1 声明和初始化指针3.2 指针与…...

Web面试题(一)

一&#xff1a;以前公司的测试流程&#xff1f; &#xff08;&#xff11;&#xff09;问题分析 面试官主要为了考察候选者对软件测试流程的理解和掌握程度。 &#xff08;&#xff12;&#xff09;核心答案讲解 &#xff11;&#xff09;需求分析与评审 &#xff12;&#xff…...

【Crypto】一眼就解密

文章目录 前言一眼就解密解题感悟 前言 Basic写累了&#xff0c;写写别的 一眼就解密 一眼md5试一试 小小flag 拿下&#xff01; 解题感悟 30秒搞定...

虚拟ECU:彻底改变汽车软件开发与测试

汽车开发领域有着垂直性较强的一系列需求&#xff0c;其中最为瞩目的需求之一就是对安全高效的软件测试方法的需求。传统的汽车开发偏向使用硬件原型与真实ECU进行软件测试&#xff0c;但由于硬件设备往往在开发周期的中后阶段才生产完成&#xff0c;给汽车开发带来了成本与时间…...

【SQL Server001】SQLServer2016常用函数实战总结(已更新)

1.熟悉、梳理、总结下SQL Server相关知识体系。 2.日常研发过程中使用较少&#xff0c;随着时间的推移&#xff0c;很快就忘得一干二净&#xff0c;所以梳理总结下&#xff0c;以备日常使用参考 3.欢迎批评指正&#xff0c;跪谢一键三连&#xff01; 总结源文件资源下载地址&am…...

51单片机简单控制180度舵机

代码&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1K9dg2NwRhy49db_O_hqv-g?pwd1234 提取码&#xff1a;1234 一、路线 我在了解这个舵机之前最像想看到的是一个完全的路径。 比如我想学习b站上那个智能门锁&#xff0c;那就得每个模块的基本代码都会才能结合各…...

PCL 常用小知识

文章目录 一、时间计算二、实现类似`pcl::PointCloud::Ptr`和`pcl::PointCloud`的两个类相互转换三、查找点云的x,y,z的极值四、知道需要保存点的索引,从原点云中拷贝点到新点云五、从点云里删除和添加点六、对点云进行全局或局部变换七、链接两个点云字段(两点云大小必须相…...

rbd块设备数据IO流程(client端)

一、rbd内核驱动写入流程 1&#xff09;初始化 首先是rbd驱动的初始化工作&#xff1a;包括验证libceph的兼容性&#xff0c;分配内存&#xff0c;在sysfs中创建块设备控制文件、创建工作队列rbd_wq并调用INIT_WORK初始化它 module_init(rbd_init); static int __init rbd_i…...

数据仓库、数据中台、大数据平台之间的关系

数据行业经常会出现数据仓库、数据中台、大数据平台等概念&#xff0c;容易产生疑问&#xff0c;它们中间是相等&#xff0c;还是包含的关系&#xff1f; 数据中台和数据仓库概念的关系 数据中台概念是包含数据仓库的&#xff0c;数据仓库是数据中台中的一部分&#xff0c;包含…...

python写页面自动截图

from selenium import webdriver def take_screenshot(url, file_path):driver webdriver.Chrome()driver.get(url)driver.save_screenshot(file_path)driver.quit() if __name__ __main__:take_screenshot(http://baidu.com, D:\桌面\wang.png)要安装selenium还要安装google…...