ARM 驱动 1.22

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>可以查看各杂项设备。

inline函数

内联函数
语法
只需要在函数的最前面加一句 inline ,如下:

inline int add(int a, int b)
{
    return a + b;
}
概念
以 inline 修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。

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

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

相关文章

倍增算法笔记

主要应用场景 RMQ&#xff1a;区间最值问题 LCA&#xff1a;最近公共祖先问题 RMQ问题——区间最值 如果用数组f[N]存储,用数组a[i][j]表示从第i个数起连续 2^j 个数中的最大值,[i,i 2^j - 1],显然a[i][0] f[i],则很容易得到状态转移方程: a[i][j] max(a[i][j - 1], a[i …

读书笔记-《数据结构与算法》-摘要11[Divide and Conquer - 分治法]

在计算机科学中&#xff0c;分治法是一种很重要的算法。分治法即『分而治之』&#xff0c;把一个复杂的问题分成两个或更多的相同或相似的子问题&#xff0c;再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解&#xff0c;原问题的解即子问题的解的合并。这个思…

电商API接口|爬虫案例|采集某东商品评论信息

前言&#xff1a; 平常大家都有网上购物的习惯&#xff0c;在商品下面卖的好的产品基本都会有评论&#xff0c;当然也不排除有刷评论的情况&#xff0c;因为评论会影响我们的购物决策。今天主要分享用pythonre正则表达式获取京东商品评论。API接口获取京东平台商品详情SKU数据…

11k+ star 一款不错的笔记leanote安装教程

特点 支持普通模式 支持markdown模式 支持搜索 安装教程 1.安装mongodb 1.1.下载 #下载 cd /opt wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.1.tgz 1.2解压 tar -xvf mongodb-linux-x86_64-3.0.1.tgz 1.3配置mongodb环境变量 vim /etc/profile 增…

电脑可以连接wifi,甚至可以qq聊天,但就是不能用浏览器上网,一直显示未检测出入户网线的解决方案

今天回到家&#xff0c;准备办公却发现电脑可以连接wifi&#xff0c;甚至可以qq聊天&#xff0c;但就是不能用浏览器上网&#xff0c;一直显示未检测出入户网线的解决方案&#xff0c;小白也可以看懂 以下有几种解决方案&#xff0c;不妨都试试&#xff0c;估计可以解决95%的相…

C#-前后端分离连接mysql数据库封装接口

C#是世界上最好的语言 新建项目 如下图所示选择框红的项目 然后新建 文件夹 Common 并新建类文件 名字任意 文件内容如下 因为要连接的是mysql数据库 所以需要安装 MySql.Data.MySqlClient 依赖; using MySql.Data.MySqlClient; using System.Data;namespace WebApplication1.…

Django 为应用定制化admin独立后台

定制后界面 在应用目录下找到admin.py并进行编辑 from django.contrib.admin import AdminSite from .models import Question,Choiceclass PollsAdminSite(AdminSite):site_header"Admin-site-header"site_title"admin-site-title"index_title"admi…

Conda 使用environment.yml创建一个新的Python项目

Conda系列&#xff1a; 翻译: Anaconda 与 miniconda的区别Miniconda介绍以及安装Conda python运行的包和环境管理 入门Conda python管理环境environments 一 从入门到精通Conda python管理环境environments 二 从入门到精通Conda python管理环境environments 三 从入门到精通…

Ansible自动化运维(三)Playbook 模式详解

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

未来已来:OJAC诚邀您与张立赛博士解锁GPT Store的无限潜力!

亲爱的伙伴们&#xff01;本月31日晚上8:30&#xff0c;我们近屿智能OJAC的培训讲师——哈尔滨工业大学博士毕业生、前之江实验室资深研究员张立赛博士&#xff0c;将为我们带来一场深度技术更新讲座&#xff0c;深度探讨GPT Store的最新发展。 本次讲座将从GPT Store的基本概念…

什么是互联网打工人都需要知道的API?电商API是什么?

我们生活在一个科技主导的世界。在这里&#xff0c;数据无处不在。作为许多不同产品的用户&#xff0c;我们所追寻的不再是某一个能将工作完成的最佳产品&#xff0c;而是一个不仅能有效完成工作&#xff0c;同时也与我们所使用的其他工具完美兼容的产品。因此&#xff0c;了解…

欧氏、曼哈顿、马氏距离

马氏距离&#xff08;Mahalanobis Distance&#xff09;、欧氏距离&#xff08;Euclidean Distance&#xff09;、曼哈顿距离&#xff08;Manhattan Distance&#xff09;是常用的距离度量方式&#xff0c;它们在数据分析、模式识别、聚类等领域中经常被使用。 欧氏距离&#…

3D建模素材网站的特点有哪些?

3D建模素材网站的特点主要包括丰富多样的模型种类、高质量的模型、实时预览功能、易于使用、价格合理以及社区互动等。这些特点使得3D建模素材网站成为设计师们不可或缺的资源之一&#xff0c;帮助他们快速高效地完成设计工作。 那么3D建模素材网站的特点有哪些? 1、模型种类丰…

【漏洞复现】上海冰峰ICEFLOW VPN信息泄露漏洞

Nx01 产品简介 上海冰峰计算机网络技术有限公司是国内VPN、流量管理、行为管理、链路负载均衡、下一代防火墙设备供应商和IT价值解决方案提供商。冰峰网络reporter系统是一套数据报表管理系统。 Nx02 漏洞描述 上海冰峰计算机网络技术有限公司ICEFLOW VPN Router系统存在信息泄…

eNSP学习——利用单臂路由实现VLAN间路由

目录 原理概述 实验内容 实验目的 实验步骤 实验拓扑 实验编址 配置步骤 创建VLAN并配置Access、Trunk接口 配置路由器子接口和IP地址 配置路由器子接口封装VLAN 测试结果 原理概述 在以太网中&#xff0c;通常会使用VLAN技术隔离二层广播域来减少广播的影响&#…

langchain + hugginface入门体验

简介 本文记录一次使用langchain调用openai并部署在huggingface上的经历 安装环境依赖 我的python版本是3.9 pip install langchain pip install openai代码 app.py import streamlit as st # from langchain_community.chat_models import ChatOpenAI from langchain_openai …

w23靶场安装

一、实验环境 服务器&#xff1a;phpstudyv8.1.13 靶场&#xff1a;Bees、sdcms、cpms、khbc二、实验目的 提供一个靶场环境 三、实验步骤 bees靶场安装 1.启动小皮的apache和mysql 2.在小皮V8.1.1.3版本上创建bees网站&#xff0c;选择的php版本最好在5.x&#xff0c;不…

聚道云软件连接器:打通金蝶云星空与招商银行CBS,提升企业财务和银行业务效率

【客户介绍】 某企业是一家从事电子商务的企业&#xff0c;随着业务的不断扩大&#xff0c;对于财务管理和银行业务的需求也越来越高。该企业希望能够实现财务和银行业务的自动化处理&#xff0c;提高工作效率。由于业务的不断发展&#xff0c;企业面临着越来越多的资金管理挑…

强化学习14——DDPG算法

在线策略算法的样本效率比较低&#xff0c;而在DNQ算法中&#xff0c;做到了离线策略学习&#xff0c;但是只能处理动作空间有限的环境。如果动作空间无限&#xff0c;可将动作空间离散化&#xff0c;但比较粗糙&#xff0c;无法惊喜控制。深度确定性策略梯度DDPG&#xff08;d…

网站SSL证书怎么获取?

获取SSL证书的途径通常包括以下几种&#xff1a; 1. 通过受信任的证书颁发机构&#xff08;CA&#xff09;购买&#xff1a; - 你可以直接从知名的证书颁发机构如JoySSL、GeoTrust、DigiCert等处购买。 - 这些机构提供不同类型的SSL证书&#xff0c;包括域名验证(DV)、组…