韦东山Linux驱动入门实验班(2)hello驱动---驱动层与应用层通讯,以及自动产生设备节点

 

前言

(1)学习韦东山老师的Linux,因为他讲的很精简,以至于很多人听不懂。接下来我讲介绍韦东山老师的驱动实验班的第二个Hello程序。

(2)注意,请先学习完视频再来看这个教程!本文仅供入门学习!如需深入,请搜索其他博客!

(3)因为上一个教程已经讲的很详细了,所以很多内容不会重复讲解,只会说明区别的地方。所以阅读本教程之前建议先阅读:韦东山Linux驱动入门实验班(1)hello驱动

(4)gitee仓库;GitHub仓库;

本教程与上一个教程区别

这一篇中的应用层代码和上一篇是一模一样的。所以本文的所有代码都是针对驱动层的!如果应用层代码不理解,可以看上一篇博客!

区别1---驱动层与应用层数据交互

区别讲解

(1)

<1>我们在阅读编写上一个程序的时候,有没有发现一个问题。就是说,我们无论给驱动程序写入什么,最终读取出来的都是一个奇怪的符号。这个是为什么呢?

<2>因为,应用层和驱动层是完全隔绝开来的,应用层无法直接访问驱动层中的各种变量。因为这个操作系统的是要给很多开发者使用的,而这些开发者,可能有些人水平不够,或者是想恶意破坏。那么就会存在一个问题,如果这些人给驱动程序写入了一些错误数据,就容易让整个系统崩溃。所以驱动层和应用层是隔绝的,应用层无法直接访问驱动层,同理,驱动层也无法直接访问应用层

<3>驱动层和应用层是怎么隔离的呢?首先,应用层发出请求,想访问驱动层。这个时候这条指令将会传递给CPU,CPU读取指令之后将信息发给MMU(内存管理单元)。这个时候,MMU将会发现,应用层发起请求,想访问驱动层,于是MMU将会把这个请求杀死。

<4>应用层和驱动层是隔离的。那么如果我硬要驱动层跟应用层进行交互,怎么办呢?于是就可以使用两个函数:copy_from_user(驱动层得到应用层数据);copy_to_user(驱动层发数据给应用层)

(3)应用层和驱动层有交互函数。那么驱动层怎么跟硬件交互呢?在我们编写单片机程序的时候,可以直接使用寄存器编写程序,也可以使用官方提供的库函数。而Linux中,我们也是两种办法,第一种是使用寄存器直接控制,第二种就是使用子系统函数。每个寄存器都有一个地址,我们将这个称之为物理地址。但是我们的驱动程序不能直接使用物理地址,他必须是使用ioremap函数,返回一个虚拟地址,用指针存放。之后,我们就可以通过这个指针操作寄存器了。

4f19c74769384ff29c7d741a5b4c59ed.png (1117×104)

代码实操

(1)咱们这里有两个函数都有改动,分成两部分讲。

(2)hello_read():

<1>unsigned long len = size > 100 ? 100 : size;

这一部分用于判断传入驱动层给应用层发送的字符是否大于100个,如果大于100个字符,那么就只发送100个字符。如果驱动层给应用层发送的字符小于100个,那么就发送实际数量的字符数。

<2>copy_to_user(buf, hello_buf, len);

1,我们copy_to_user()函数咱们上面介绍了,是驱动层用于给应用层发送数据的函数。第一个参数是最终发送到应用层的数据,因为我们hello_read()函数的第二个参数是buf,所以copy_to_user()第一个参数传入buf。

2,copy_to_user()的第二个参数是驱动层需要发送给应用层的数据,这个是需要我们自己在驱动层创建无符号字符数组hello_buf[]。hello_buf[]这个数组负责存放驱动层和应用层的交互信息。

3,copy_to_user()的第三个参数是需要传输的字符数量。如果传输的字符大于100,那么就只传输100个字符。如果传输的字符小于100个,那么就按照需要传输的字符数量传输。

<3> return len; 最终返回传输的字符数量。与原来的 return size;不同在于, return size;是没有加上最多传输100个字符的限制

(3)hello_write():

<1>与hello_read()的一样变化。

<2>copy_from_user(hello_buf, buf, len);

1,copy_from_user()函数和copy_to_user()函数使用方法类似的。只不过copy_from_user()函数是用于应用层给驱动层发送信号。

2,copy_from_user()的第一个参数是目的地址,所以需要传入hello_buf。第二个参数是起始地址,所以需要传入buf。第三个参数与copy_to_user()一样。

<3>最终返回值的改变与hello_read()的一样变化。

(4)最后强调一下,这个代码会有两个警告ignoring return value of ‘copy_from_user’, declared with attribute warn_unused_result ignoring return value of ‘copy_to_user’, declared with attribute warn_unused_result。这两个警告翻译过来就是忽略使用warn_unused_result属性声明的' copy_from_user '的返回值 和 忽略使用warn_unused_result属性声明的' copy_to_user '的返回值

这两个警告是什么意思呢?有什么影响?很简单copy_from_user和copy_to_user是存在返回值的。而我们没有接收这两个函数的返回值,所以会存在警告,无需理会。

static unsigned char hello_buf[100]; //存放驱动层和应用层交互的信息

/*
 *传入参数 :
	 *filp :要读的文件
	 *buf :读的数据放在哪里
	 *size :读多大数据
	 *offset :偏移值(一般不用)
 *返回参数 :读到的数据长度	
*/
static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
	//判断size是否大于100,如果大于100,len=100,否则len=size
    unsigned long len = size > 100 ? 100 : size;
	/*__FILE__ :表示文件
	 *__FUNCTION__ :当前函数名
	 *__LINE__ :在文件的哪一行
	*/
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	/* 作用 : 驱动层发数据给应用层
	 * buf  : 应用层数据
	 * hello_buf : 驱动层数据
	 * len  :数据长度
	*/
    copy_to_user(buf, hello_buf, len);

    return len;
}
/*
 *传入参数 :
	 *filp :要写的文件
	 *buf :写入的数据来自于buf
	 *size :写多大数据
	 *offset :偏移值(一般不用)
 *返回参数 :写的数据长度	
*/
static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
	//判断size是否大于100,如果大于100,len=100,否则len=size
    unsigned long len = size > 100 ? 100 : size;
	/*__FILE__ :表示文件
	 *__FUNCTION__ :当前函数名
	 *__LINE__ :在文件的哪一行
	*/
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	/* 作用 : 驱动层得到应用层数据
	 * buf  : 应用层数据
	 * hello_buf : 驱动层数据
	 * len  :数据长度
	*/
    copy_from_user(hello_buf, buf, len);

    return len;
}

结果演示

(1)与上一个博客一样流程:

<1>Ubuntu下make编译

<2>打开开发板,输入mount -t nfs -o nolock,vers=3  192.168.5.11:/home/book/nfs_rootfs  /mnt共享文件

<3>内核打印可以选中打开或者不打开:

关闭内核打印:echo "0 4 0 7" > /proc/sys/kernel/printk
打开内核打印:echo "7 4 1 7" > /proc/sys/kernel/printk

<4>insmod hello_drv.ko装载驱动

<5>cat /proc/devices:查看当前已经被使用掉的设备号(注意,这里的设备号之后的创建设备节点需要用到)

<6> mknod  /dev/xyz c 240 0 (xyz可以为任意名字,设备号与上面的有关,0表示次设备号,随便填)

<7>在应用层调用设备节点,如./hello_test /dev/xyz  123

<8>卸载驱动程序: rmmod 驱动程序

<9>删除设备节点:rm  /dev/xyz

(2) 关闭内核打印演示结果

(3)打开内核打印演示结果

区别二---自动创建设备节点

讲解

(1)咱们有没有发现一个问题,驱动装载流程太长了。我们能不能自动创建一个设备节点,然后自己删除呢?答案是可以的,不然我也不会提及。

(2)如何在让系统实现自动创建设备节点呢?这个时候我们就要讲到两个函数。class_create()和device_create()。

<1>class_create()函数用于动态创建设备的逻辑类,此函数的执行效果就是在目录/sys/class下创建一个新的文件夹,此文件夹的名字为此函数的第二个输入参数,但此文件夹是空的。同时在/sys/devices目录下也会创建新的空文件夹。

<2>device_create()函数就是用于创建设备节点的,第一个参数为class_create()的返回值。class_create()函数不是在/sys/class中创建一个空的文件夹麻,device_create()函数就是在这个空的文件夹中创建一个链接文件。同时在/sys/devices/virtual目录下创建新的逻辑设备目录。这个链接文件,也就是咱们输入mknod命令创建的设备节点。

(3)自动创建了设备节点之后,我们还需要销毁设备节点。那么这个时候又需要使用两个函数了。device_destroy()和class_destroy()。

<1>因为我们创建设备节点的时候,是先注册驱动,再创建逻辑类,最后创建设备节点的。所以销毁的时候需要反过来。先销毁设备节点,再销毁逻辑类,最后卸载驱动。

<2>class_destroy()执行的效果是删除函数__class_create()或宏class_create()在目录/sys/class下创建的逻辑类对应的文件夹。device_destroy()用于销毁设备节点。

代码 

//在命令行输入insmod命令,就是注册驱动程序。之后就会进入这个入口函数
//3,入口函数
static int hello_init(void)
{
	/*将hello_drv这个驱动放在内核的第n项,中间传入的名字不重要,第三个是要告诉内核的驱动
	 *因为我们不知道第n项是否已经存放了其他驱动,就可以放在第0项,然后让系统自动往后遍历存放到空的地方
	 *major为最终存放的第n项,等下卸载程序需要使用。如果不卸载程序,可以不管这个
	*/
    major = register_chrdev(0, "100ask_hello", &hello_drv);
	//如果成功注册驱动,打印
	printk("insmod success!\n");
	
	/******这里相当于命令行输入 mknod  /dev/hello c 240 0 创建设备节点*****/
	
	//创建类,为THIS_MODULE模块创建一个类,这个类叫做hello_class
	hello_class = class_create(THIS_MODULE, "hello_class");
	if (IS_ERR(hello_class))  //如果返回错误
	{
		//打印类创建失败
		printk("failed to allocate class\n");
		//返回错误
		return PTR_ERR(hello_class);
	}
	/*在hello_class类下面创建设备
	 *无父设备的指针
	 *MKDEV传入主设备号major和此设备号0
	 *没有私有数据
	 *输入参数是逻辑设备的设备名,即在目录/dev目录下创建的设备名
	*/
    device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");  /* /dev/hello */

   return 0;
}

//在命令行输入rmmod命令,就是注册驱动程序。之后就会进入这个出口函数
//4,出口函数
static void hello_exit(void)
{
	//销毁hello_class类下面的设备节点
    device_destroy(hello_class, MKDEV(major, 0));
	//销毁hello_class类
    class_destroy(hello_class);
	//卸载驱动程序
	//第一个参数是主设备号,第二个是名字
    unregister_chrdev(major, "100ask_hello");
	//如果成功卸载驱动,打印
	printk("rmmod success!\n");
}

效果演示

(1)演示自动产生设备节点

 (2)现在使用驱动需要的步骤:

<1>Ubuntu下make编译

<2>打开开发板,输入mount -t nfs -o nolock,vers=3  192.168.5.11:/home/book/nfs_rootfs  /mnt共享文件

<3>内核打印可以选中打开或者不打开:

关闭内核打印:echo "0 4 0 7" > /proc/sys/kernel/printk
打开内核打印:echo "7 4 1 7" > /proc/sys/kernel/printk

<4>insmod hello_drv.ko装载驱动

<5>在应用层调用设备节点,如./hello_test /dev/xyz  123

<6>卸载驱动程序: rmmod 驱动程序

 

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

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

相关文章

iptables防火墙2

文章目录 iptables防火墙21 SNAT1.1 原理1.2 应用环境1.3 转换前提条件1.4 SNAT转换 2 DNAT2.1 原理2.2 应用环境2.3 转换前提条件 3 SNAT转换3.1 先配置作为网关服务器的虚拟机3.2 修改ens33的网卡3.3 修改ens36的网卡3.4 开启PC2网关服务器的路由转发功能3.5 永久开启3.6 配置…

【Midjourney】Midjourney 辅助工具 ② ( 自定义命令工具 | 设置颜色 | 设置材质 | 设置随机种子 | 设置图片链接 )

文章目录 一、Midjourney Prompt Tool 自定义命令工具1、设置颜色参数2、设置材质参数3、设置随机种子参数4、设置图片链接 Midjourney 提示词命令 可以使用 辅助工具 进行生成 , 辅助工具如下 : Midjourney Prompt Tool 自定义命令工具Midjourney Prompt Generator 命令生成器…

前端开发推荐vscode安装什么插件?

前言 可以参考一下下面我推荐的插件&#xff0c;注意&#xff1a;插件的目的是用于提高开发的效率&#xff0c;节约开发的时间&#xff0c;像类似检查一些bug、拼写错误等这些可以使用插件快速的识别&#xff0c;避免在查找错误上浪费过多的时间&#xff0c;但切记不要过度依赖…

【Python Power BI】零基础也能轻松掌握的学习路线与参考资料

Python和Power BI是现代数据分析和可视化领域中最受欢迎的工具之一&#xff0c;Python是一种高级编程语言&#xff0c;广泛用于数据科学和分析&#xff0c;而Power BI是一种业务智能工具&#xff0c;用于创建交互式大屏幕和实时报表。Python和Power BI的结合使用可以为数据科学…

探索编程的极限:挑战炫技代码

程序员常常被视为具有超强技术能力的人才&#xff0c;而他们手中的代码也往往充满了令普通人惊叹的炫技操作。作为程序员的我&#xff0c;将和大家分享一些炫技的代码写法 一、编程语言介绍 本人主攻Java。下面我将介绍一下Java语言。 Java是一种广泛使用的高级编程语言&…

字符串、字符串列表,倒序生成字典。

带数字的字符串以数字为key倒序生成字典&#xff0c;字符串列表按其元素索引为key倒序生成字典。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简…

什么是护网?护网怎么参加?

一、什么是护网行动&#xff1f; 护网行动是以公安部牵头的&#xff0c;用以评估企事业单位的网络安全的活动。 具体实践中。公安部会组织攻防两方&#xff0c;进攻方会在一个月内对防守方发动网络攻击&#xff0c;检测出防守方&#xff08;企事业单位&#xff09;存在的安全…

叮咚买菜业绩大幅低于预期,2023年前景堪忧

来源l&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 叮咚买菜2023年第一季度业绩低于预期 叮咚买菜&#xff08;DDL&#xff09;于5月12日公布了2023年第一季度财报。 财报显示&#xff0c;叮咚买菜的收入同比下降了-8%&#xff0c;从2022年第一季度的54.44亿元人民币下滑…

Shell基础

目录 第1章 Shell概述 第2章 Shell脚本入门 第3章 变量 3.1 系统预定义变量 3.2 自定义变量 3.3 特殊变量 3.3.1 $n 3.3.2 $# 3.3.3 $*、$ 3.3.4 $&#xff1f; 第4章 运算符 第5章 条件判断 第6章 流程控制&#xff08;重点&#xff09; 6.1 if判断 6.2 case语…

广和通携手有人物联网完成5G SUL辅助上行功能验证

近日&#xff0c;广和通5G模组FM650-CN已在商用网络中实现5G SUL上行能力增强&#xff0c;助力有人物联网工业路由器在仿真网络环境中完成SUL辅助上行功能的验证。本次验证成功&#xff0c;意味着FM650-CN已具备SUL辅助上行商用能力&#xff0c;有利于推动更多5G终端支持SUL特性…

AI工具第三期:本周超16款国内精选AI工具分享!

1. 未来百科 未来百科&#xff0c;是一个知名的AI产品导航网站——为发现全球优质AI工具而生。目前已聚集全球2500优质AI工具产品&#xff0c;旨在帮助用户发现全球最好的AI工具&#xff0c;同时为研发AI垂直应用的创业公司提供展示窗口&#xff0c;迎接未来的AI时代。未来百科…

Netty编解码机制(一)

1.编码和解码基本介绍 1>.编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码; 2>.codec(编解码器)的组成部分有两个: decoder(解码器)和 encoder(编码器).encoder(编码器)负责把业务数据转换成字节码数据,而…

什么是数字化?企业为什么要数字化转型

一、什么是数字化&#xff1f; 什么是数字化&#xff1f;在我理解&#xff0c;数字化是一个基于时代科技发展所产生的概念&#xff0c;首先它是一个工具&#xff0c;在企业的经营发展中将信息技术融入到传统的企业模式中&#xff0c;起到了转型的作用。 其次数字化转型是企业…

从复杂到简单:通用CRM客户管理系统改变企业管理方式

一、概述 CRM客户管理系统是通过对客户生命周期的有效管理&#xff0c;是一种重要的客户管理工具&#xff0c;可以帮助企业更好的了解客户的需求&#xff0c;提升客户满意度&#xff0c;优化销售流程、提高销售业绩等&#xff0c;随着数字经济的不断发展和普及&#xff0c;CRM…

第03章 流程控制语句

流程控制语句是用来控制程序中各语句执行顺序的语句&#xff0c;可以把语句组合成能完成一定功能的小逻辑模块。 程序设计中规定的三种流程结构&#xff0c;即&#xff1a; 顺序结构 程序从上到下逐行地执行&#xff0c;中间没有任何判断和跳转。 分支结构 根据条件&#xff0…

mjpg-streamer实现细节分析

mjpg-streamer实现细节分析 文章目录 mjpg-streamer实现细节分析输入初始化input_initinit_videoIninit_v4l2 启动摄像头输入线程cam_threaduvcGrabcompress_yuyv_to_jpegmemcpy_picture 输出初始化output_init启动摄像头输出线程server_thread设置 SO_REUSEADDR 选项。设置 IP…

uvc驱动ioctl分析下

uvc驱动ioctl分析下 文章目录 uvc驱动ioctl分析下uvc_ioctl_enum_input枚举输入uvc_query_ctrl__uvc_query_ctrluvc_ioctl_g_input 获取输入uvc_ioctl_s_input 设置输入uvc_query_v4l2_ctrluvc_ioctl_queryctrl查询控制器uvc_ioctl_query_ext_ctrl查询扩展控制器 uvc_ioctl_g_c…

爬虫基本原理

爬虫基本原理 1.1获取网页1.1.1提取信息1.1.2保存数据 1.2请求1.2.1 请求方法1.2.2 请求网址1.2.3 请求头1.2.4请求体1.3响应 1.1获取网页 爬虫首先要做的工作就是获取网页&#xff0c;这里就是获取网页的源代码。源代码里包含了网页的部分有用信息&#xff0c;所以只要把源代…

【航空和卫星图像中检测建筑物】使用gabor特征和概率的城市区域和建筑物检测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

如何把数据从 TDengine 2.x 迁移到 3.x ?

一.迁移背景&#xff1a; 随着时序数据库&#xff08;Time Series Database&#xff09; TDengine 3.0 的发布至今&#xff0c;我们除了在持续地优化产品质量的本身&#xff0c;也一直在努力地提升用户体验。但由于 3.0 底层有大量的重构优化&#xff0c;导致开源版的 2.0 用户…