ARM 驱动 1.22

news2024/11/15 5:50:37

linux内核等待队列wait_queue_head_t

头文件

  include <linux/wait.h>

定义并初始化

wait_queue_head_t r_wait;

init_waitqueue_head(&cm_dev->r_wait);

wait_queue_head_t 表示等待队列头,等待队列wait时,会导致进程或线程被休眠,一个等待队列头中可以有很多的等待队列元素。每个元素绑定一个进程或者线程。这里绑定进程或者线程的目的,是为了在执行wakeup时,知道应该唤醒谁。

Linux 字符设备驱动开发基础——read()、write() 相关函数解析

Linux字符设备驱动中,用户程序使用read()write() 相关函数时,内核会调用驱动程序中的的file_operations结构体中对应的read()write()函数。

file_operations,其是一个函数指针的集合,用于存放我们定义的用于操作设备的函数的指针,如果我们不定义,它默认保留为NULL。其中有最重要的几个函数,分别是open()read()write()ioctl(),下面分别对其进行解析。

1. 打开和关闭设备函数

(1)打开设备

int (*open) (struct inode *, struct file *);

在操作设备前必须先调用open函数打开文件,可以干一些需要的初始化操作。当然,如果不实现这个函数的话,驱动会默认设备的打开永远成功。打开成功时open返回0。

(2)关闭设备

int (*release) (struct inode *, struct file *);

当设备文件被关闭时内核会调用这个操作,当然这也可以不实现,函数默认为NULL。关闭设备永远成功。

2. read()、write() 函数

2.1 read() 函数

函数原型:

<span style="color:#000000"><span style="background-color:#282c34"><code class="language-c">ssize_t <span style="color:#999999">(</span><span style="color:#669900">*</span>read<span style="color:#999999">)</span> <span style="color:#999999">(</span><span style="color:#c678dd">struct</span> file <span style="color:#669900">*</span>filp<span style="color:#999999">,</span> <span style="color:#c678dd">char</span> __user <span style="color:#669900">*</span>buffer<span style="color:#999999">,</span> size_t size<span style="color:#999999">,</span> loff_t <span style="color:#669900">*</span>p<span style="color:#999999">)</span><span style="color:#999999">;</span> 
</code></span></span>

参数含义:

  • filp:待操作的设备文件file结构体指针;
  • buffer:为对应放置所读数据的缓冲区指针(即用户空间内存地址);
  • size:为要读取的数据长度;
  • p:为读的位置相对于文件开头的偏移,在读取信息后,这个指针一般都会移动,移动的值为要读取信息的长度值;
  • __user:是一个空的宏,主要用来显示的告诉程序员它修饰的指针变量存放的是用户空间的地址。

返回值:
成功实际读取的字节数,失败返回负值。
如果该操作为空,将使得read系统调用返回负EINVAL失败,正常返回实际读取的字节数。

 两个函数的作用分别是 从设备中获取数据发送数据给设备,应用程序中与之对应的也有 write() 函数及 read() 函数:

<span style="color:#000000"><span style="background-color:#282c34"><code class="language-c">len <span style="color:#669900">=</span> <span style="color:#61aeee">read</span><span style="color:#999999">(</span>fd<span style="color:#999999">,</span>buf<span style="color:#999999">,</span>len <span style="color:#999999">)</span>
<span style="color:#c678dd">static</span> ssize_t <span style="color:#61aeee">hello_read</span><span style="color:#999999">(</span><span style="color:#c678dd">struct</span> file <span style="color:#669900">*</span>filep<span style="color:#999999">,</span> <span style="color:#c678dd">char</span> __user <span style="color:#669900">*</span>buf<span style="color:#999999">,</span> size_t len<span style="color:#999999">,</span> loff_t <span style="color:#669900">*</span>pos<span style="color:#999999">)</span>
</code></span></span>
<span style="color:#000000"><span style="background-color:#282c34"><code class="language-c">len <span style="color:#669900">=</span> <span style="color:#61aeee">write</span><span style="color:#999999">(</span>fd<span style="color:#999999">,</span>buf<span style="color:#999999">,</span>size<span style="color:#999999">)</span>
<span style="color:#c678dd">static</span> ssize_t <span style="color:#61aeee">hello_write</span><span style="color:#999999">(</span><span style="color:#c678dd">struct</span> file <span style="color:#669900">*</span>filep<span style="color:#999999">,</span> <span style="color:#c678dd">const</span> <span style="color:#c678dd">char</span> __user <span style="color:#669900">*</span>buf<span style="color:#999999">,</span> size_t len<span style="color:#999999">,</span> loff_t <span style="color:#669900">*</span>pos<span style="color:#999999">)</span>
</code></span></span>

我们知道,应用程序工作在用户空间,而驱动工作在内核空间,二者不能直接通信的,那我们用何种方法进行通信呢?下面介绍一下内核中的 memcpy—copy_from_usercopy_to_user,虽然说内核中不能使用C库提供的函数,但是内核也有一个memcpy函数,用法跟C库中的一样。

2.3 copy_from_user函数与copy_to_user函数

从字面意义上理解:user是指用户,即用户空间。

file_operations结构体中实现的write函数,即2.2中的write() 函数中,用户空间向内核空间拷贝(写)数据需要使用copy_from_user函数。而用户空间从内核空间读取数据需要使用copy_to_user函数。两个函数定义在arch/arm/include/asm/uaccess.h中。

两个函数定义:

<span style="color:#000000"><span style="background-color:#282c34"><code class="language-c"><span style="color:#c678dd">static</span> <span style="color:#c678dd">inline</span> <span style="color:#c678dd">int</span> <span style="color:#61aeee">copy_from_user</span><span style="color:#999999">(</span><span style="color:#c678dd">void</span> <span style="color:#669900">*</span>to<span style="color:#999999">,</span> <span style="color:#c678dd">const</span> <span style="color:#c678dd">void</span> __user <span style="color:#c678dd">volatile</span> <span style="color:#669900">*</span>from<span style="color:#999999">,</span> <span style="color:#c678dd">unsigned</span> <span style="color:#c678dd">long</span> n<span style="color:#999999">)</span><span style="color:#999999">{</span>
	<span style="color:#61aeee">__chk_user_ptr</span><span style="color:#999999">(</span>from<span style="color:#999999">,</span> n<span style="color:#999999">)</span><span style="color:#999999">;</span>
	<span style="color:#61aeee">volatile_memcpy</span><span style="color:#999999">(</span>to<span style="color:#999999">,</span> from<span style="color:#999999">,</span> n<span style="color:#999999">)</span><span style="color:#999999">;</span>
	<span style="color:#c678dd">return</span> <span style="color:#98c379">0</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>

<span style="color:#c678dd">static</span> <span style="color:#c678dd">inline</span> <span style="color:#c678dd">int</span> <span style="color:#61aeee">copy_to_user</span><span style="color:#999999">(</span><span style="color:#c678dd">void</span> __user <span style="color:#c678dd">volatile</span> <span style="color:#669900">*</span>to<span style="color:#999999">,</span> <span style="color:#c678dd">const</span> <span style="color:#c678dd">void</span> <span style="color:#669900">*</span>from<span style="color:#999999">,</span> <span style="color:#c678dd">unsigned</span> <span style="color:#c678dd">long</span> n<span style="color:#999999">)</span><span style="color:#999999">{</span>
	<span style="color:#61aeee">__chk_user_ptr</span><span style="color:#999999">(</span>to<span style="color:#999999">,</span> n<span style="color:#999999">)</span><span style="color:#999999">;</span>
	<span style="color:#61aeee">volatile_memcpy</span><span style="color:#999999">(</span>to<span style="color:#999999">,</span> from<span style="color:#999999">,</span> n<span style="color:#999999">)</span><span style="color:#999999">;</span>
	<span style="color:#c678dd">return</span> <span style="color:#98c379">0</span><span style="color:#999999">;</span>
<span style="color:#999999">}</span>
</code></span></span>

可以看到两个函数均是调用了 _memcpy() 函数:

static void volatile_memcpy(volatile char *to, const volatile char *from, unsigned long n){ while (n--) *(to++) = *(from++); }

其实在这里,我们可以思考,既然拷贝的功能上面的_memcpy() 函数就可以实现,为什么还要封装成 copy_to_user()copy_from_user()呢?

答案是_memcpy() 函数是有缺陷的,譬如我们在用户层调用函数时传入的不是字符串,而是一个不能访问或修改的地址,那样就会造成系统崩溃。

出于上面的原因,内核和用户态之间交互的数据时必须要先对数据进行检测,如果数据是安全的,才可以进行数据交互。上面的函数就是memcpy的改进版,在memcpy功能的基础上加上的检查传入参数的功能,防止有些人有意或者无意的传入无效的参数。

static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
 

参数:

  • to:目标地址(内核空间)
  • from:源地址(用户空间)
  • n:将要拷贝数据的字节数

返回值:
成功返回0,失败返回没有拷贝成功的数据字节数

static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n)

参数:

  • to:目标地址(用户空间)
  • from:源地址(内核空间)
  • n:将要拷贝数据的字节数

返回值:

成功返回0,失败返回没有拷贝成功的数据字节数

 Linux中将设备分为三大类:字符设备(I2C、USB、SPI等)、块设备(存储器相关的设备如EMMC、SD卡、U盘等)和网络设备(网络相关的设备WIFI等)。

杂项设备归属于字符设备,每个设备节点都有主设备号和次设备号 ,设备号是识别设备的一种方式,Linux系统中有很多杂项设备,而杂项设备的主设备号固定为10。                                   使用命令<cat /proc/misc>可以查看各杂项设备。

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

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

相关文章

最新版的Tuxera NTFS 2024 支持macOS 12系统

备受期待的Tuxera NTFS 2024 Mac中文版终于上线了&#xff0c;小编第一时间为您带来&#xff01;Tuxera NTFS 2024 中文版是一款非常好用的NTFS读写工具&#xff0c;可以让您完整的读写兼容NTFS格式驱动器&#xff0c;对磁盘进行访问、编辑、存储和传输文件等。同时还包括开源磁…

电脑存储位置不够怎么办

电脑内存不够怎么办&#xff01;&#xff01;&#xff01; 我前段时间经常因为电脑D盘内存不够而苦恼&#xff08;毕竟电脑内存就那么丁点&#xff0c;C盘作为系统盘不能随便下东西的情况下&#xff0c;就只能选择其他盘进 方法一&#xff1a;检查电脑硬盘的分区情况&#xf…

git内部原理

git内部原理 介绍目录结构说明 介绍 项目的本地仓库中&#xff0c;包含一个隐藏的.git目录&#xff0c;其不同的文件产生都源于git的各种不同命令造成&#xff0c;文件目录如下所示&#xff1a; 目录结构说明 上面最核心重要的为object目录&#xff0c;目录最主要有三个对象…

设置代码模板创建sql映射文件、Mybatis主配置文件

目录 1、Sql映射&#xff08;Sql Mapper&#xff09;文件的介绍 2、Mybatis的主配置文件的介绍 3、通过代码模板创建Sql映射文件 4、通过代码模板创建Mybatis主配置文件 1、Sql映射&#xff08;Sql Mapper&#xff09;文件的介绍 <?xml version"1.0" encod…

AI教我学编程之C#类的基本概念(1)

前言 在AI教我学编程之C#类型 中&#xff0c;我们学习了C#类型的的基础知识&#xff0c;而类正是类型的一种. 目录 区分类和类型 什么是类&#xff1f; 对话AI 追问 实操 追踪属性的使用 AI登场 逐步推进 提出疑问 药不能停 终于实现 探索事件的使用 异步/交互操作 耗时操…

全面分析vcomp140.dll丢失的修复方法,快速解决dll报错问题

vcomp140.dll文件的丢失可能会引发一系列系统运行和软件功能上的问题。作为Microsoft Visual C Redistributable Package的一部分&#xff0c;vcomp140.dll是一个至关重要的动态链接库文件&#xff0c;它的缺失可能导致某些应用程序无法正常启动或执行。具体来说&#xff0c;当…

今年想考CISP的一定要看完❗️

&#x1f3af;国家注册信息安全专业人员&#xff08;英文名称Certified Information Security Professional&#xff0c;简称“CISP"&#xff09;&#xff0c;是由中国信息安全测评中心于2002年推出的、业内公认的国内信息安全领域zqw的gj级认证&#xff0c;是国家对信息安…

【C++】list容器迭代器的模拟实现

list容器内部基本都是链表形式实现&#xff0c;这里的迭代器实现的逻辑需要注意C语言中指针的转换。 list容器如同数据结构中的队列&#xff0c;通常用链式结构进行存储。在这个容器中&#xff0c;我们可以模仿系统的逻辑&#xff0c;在头结点后设置一个“ 哨兵 ”&#xff0c;…

WPF多值转换器

背景&#xff1a;实现Slider拖动可以调整rgb 单转换器&#xff1a;WPF中数据绑定转换器Converter-CSDN博客 在View中&#xff1a; <StackPanel Orientation"Vertical"><Slider x:Name"slider_R" Minimum"0" Maximum"255" Wi…

阿里云优惠券领取入口、使用教程,2024优惠券更新

阿里云优惠代金券领取入口&#xff0c;阿里云服务器优惠代金券、域名代金券&#xff0c;在领券中心可以领取当前最新可用的满减代金券&#xff0c;阿里云百科aliyunbaike.com分享阿里云服务器代金券、领券中心、域名代金券领取、代金券查询及使用方法&#xff1a; 阿里云优惠券…

CentOS 7安装全解析:适合初学者的指导

目录 前言 一.centos安装 1.下载镜像文件 2.安装 二.远程连接&#xff0c;换源 1.下载并且使用MobaXtermMobaXterm free Xserver and tabbed SSH client for Windows (mobatek.net)https://mobaxterm.mobatek.net/ 远程连接 2.换源 前言 在当今的信息化时代&#xff0c…

SpikingJelly笔记之IFLIF神经元

文章目录 前言一、脉冲神经元二、IF神经元1、神经元模型2、神经元仿真 三、LIF神经元1、神经元模型2、神经元仿真 总结 前言 记录整合发放(integrate-and-fire, IF)神经元与漏电整合发放(leaky integrate-and-fire, LIF)神经元模型&#xff0c;以及在SpikingJelly中的实现方法…

mybatis----动态Sql

1.if标签 通过if标签构建动态条件&#xff0c;通过其test属性的true或false来判断该添加语句是否执行。 mapper接口 public interface AccountMapper {List<Account> selectAllByCondition(Account account); } 映射文件 <select id"selectAllByCondition&q…

《文苑》文学艺术文化期刊投稿邮箱投稿方式

《文苑》杂志是国家新闻出版总署批准的正规期刊&#xff0c;本刊致力于中华优秀传统文化、文化旅游、文学艺术、哲学社会科学等方面的理论和实践研究&#xff0c;集理论性、艺术性、指导性于一体&#xff0c;是广大文化、哲学、社会科学工作者交流科研成果、传递学术思想的重要…

(蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)

能够表示为某个整数的平方的数字称为“平方数 虽然无法立即说出某个数是平方数&#xff0c;但经常可以断定某个数不是平方数。因为平方数的末位只可能是:0,1,4,5,6,9 这 6 个数字中的某个。所以&#xff0c;4325435332 必然不是平方数。 如果给你一个 2 位或 2 位以上的数字&am…

【Linux】基本指令收尾

文章目录 日期查找打包压缩系统信息Linux和Windows互传文件 日期 这篇是基本指令的收尾了&#xff0c;还有几个基本指令我们需要说一下 首先是Date&#xff0c;它是用来显示时间和日期 直接输入date的话显示是有点不好看的&#xff0c;所以我们可以根据自己的喜欢加上分隔符&…

MATLAB解决考研数学一题型(上)

闲来无事&#xff0c;情感问题和考研结束后的戒断反应比较严重&#xff0c;最近没有什么写博文的动力&#xff0c;抽空来整理一下考研初试前一直想做的工作——整理一下MATLAB解决数学一各题型的命令~ 本贴的目录遵循同济版的高数目录~ 目录 一.函数与极限 1.计算双侧极限 2…

如何理解 GO 语言的接口 - 鸭子模型

个人认为&#xff0c;要理解 Go 的接口&#xff0c;一定先了解下鸭子模型。 鸭子模型 那什么鸭子模型&#xff1f; 鸭子模型的解释&#xff0c;通常会用了一个非常有趣的例子&#xff0c;一个东西究竟是不是鸭子&#xff0c;取决于它的能力。游泳起来像鸭子、叫起来也像鸭子…

Kafka-服务端-网络层

Reactor模式 Kafka网络层采用的是Reactor模式&#xff0c;是一种基于事件驱动的模式。熟悉Java编程应该了解JavaNIO提供了实现Reactor模式的API。常见的单线程Java NIO的编程模式如图所示。 为了满足高并发的需求&#xff0c;也为了充分利用服务器的资源&#xff0c;服务端需要…

Wimdows如何修改自己权限不够的文件

使用管理员身份运行cmd cd 文件目录 cd C:\Windows\System32\drivers\etc 打开文件 notepad 文件名 进行修改&#xff0c;保存就能成功&#xff01;