linux驱动read函数 copytouser,Linux驱动编程 step-by-step (五)主要的文件操作方法实现...

主要的文件操作方法实现

文件操作函数有很多的操作接口,驱动编程需要实现这些接口,在用户编程时候系统调用时候会调用到这些操作

structfile_operations {

...

loff_t (*llseek) (structfile *, loff_t,int);

ssize_t (*read) (structfile *,char__user *,size_t, loff_t *);

ssize_t (*write) (structfile *,constchar__user *,size_t, loff_t *);

int(*open) (structinode *,structfile *);

int(*release) (structinode *,structfile *);

...

};

以上只列出了主要的操作,下面会依次介绍:

本次的测试代码上传在:char_step2

结构体:

首先 我们会模拟写一个不操作任何设备,而仅仅是存储的一个驱动。

定义自己的一个结构体为:

structsimple_dev{

chardata[MAX_SIMPLE_LEN];

loff_t count;

structsemaphore semp;

};

data 保存数据, count表示文件的数据有效的位置, semp是一个信号量锁,在以后的编程中使用,

之后的程序中结构体也会做相应的变化,以适应linux编写驱动的习惯

open方法:

打开设备并进一步初始化工作,在没有定义open方法时内核以一种默认的方式打开设备,保证每次都能正确打开。

open方法中有有struct inode参数,包含了设备号,程序中可以使用次设备号得到正操作的设备

在struct file中主要的操作是private_data指针,他可以传递任何自己创建的结构。

总得说来open方法的作用有3

1、获得操作的设备(通过设备号)

2、进一步的初始化设备

3、初始化file结构体的private_data

staticintsimple_open(structinode *inodp,structfile *filp)

{

structsimple_dev *temp_dev = NULL;

intminor = 0;

#if SIMPLE_DEBUG

printk(KERN_INFO "In %s \n", __func__);

#endif

minor = iminor(inodp);//获得操作的设备的次设备号

if(minor > DEV_COUNT-1){

printk(KERN_ERR "the char dev in invalid \n");

return-ENODEV;

}

#if SIMPLE_DEBUG

printk(KERN_INFO "the minor is  %d \n", minor);

#endif

temp_dev = &char2_dev[minor];//获得真正操作的设备

/* 进一步 初始化设备 因为是操作一个模拟的设备 故省去*/

filp->private_data = temp_dev; //初始化 private_data

return0;

}

release方法:

主要是对open进一步初始化的操作的反操作

比如open时候分配了内存,在release时就需要释放它等

例子中因为操作内存设备,故在release时无需做什么事

read方法:

read 是把设备中的数据传递给调用者

主要步骤

1、检测偏移量有效(有些设备驱动不需要检测)

2、检测用户空间地址有效

3、将数据传给用户(在此步骤中调用的函数可能会自己检测步骤2)

4、调整偏移量

5、返回读到的数据长度

(read write 用法相对灵活,不要依赖上边的步骤,设备驱动程序要根据设备特性去设计此方法)

这里先介绍一个会检测用户空间地址是否有效的copy函数

用户调用read读设备,而在内核空间就是将数据传给用户,是一个to的操作

unsignedlong__must_check copy_to_user(void__user *to,constvoid*from, unsignedlongn)

__must_check表述必须检测其返回值,操作成功返回0,不成功返回负的错误码

to是用户空间指针 也就是read函数传入的用户空间的指针,

from指向设备要传送的数据

n标识传入长度

0818b9ca8b590ca3270a3433284dd417.png

上图是 摘自LDD3上的经典视图, 应该比较能说明read的方法

staticssize_t simple_read(structfile *filp,char__user *userstr,size_tcount, loff_t *loff)

{

structsimple_dev *dev = NULL;

intdata_remain = 0;

interr;

#if SIMPLE_DEBUG

printk(KERN_INFO "In %s \n", __func__);

#endif

dev         = filp->private_data;

data_remain = dev->count - *loff;

if(MAX_SIMPLE_LEN 

{

printk(KERN_ERR "the offset is illegal in func %s \n",__func__ );

return-EINVAL;

}

elseif(data_remain <= 0)

{

printk(KERN_WARNING "there was not much data in the device\n");

return0;

}

else

{

if(count > data_remain)

{

#if SIMPLE_DEBUG

printk(KERN_INFO "the data is less than the user want to read\n");

#endif

count = data_remain;

}

else

{

}

}

err = copy_to_user(userstr, (dev->data)+(*loff), count); //调用内核函数进行数据拷贝,它会检测用户地址是否有效

if(err != 0)

{

printk(KERN_ERR "an error occured when copy data to user\n");

returnerr;

}

else

{

#if SIMPLE_DEBUG

printk(KERN_INFO "data copy to user OK\n");

#endif

*loff = *loff + count; //调整偏移量

returncount;//返回写入的数据量

}

}

write方法:

与read类似 它是从用户传数据给设备驱动

从内核空间看就是一个从用户空间取数据 是一个from操作

long__must_check strncpy_from_user(char*dst,constchar__user *src,longcount)

dst 驱动保存数据的地址

src 用户空间传入的数据

count 标识数据长度

staticssize_t simple_write(structfile *filp,constchar__user *userstr,size_tcount, loff_t *loff)

{

structsimple_dev *dev = NULL;

interr;

intremain_space = 0;

#if SIMPLE_DEBUG

printk(KERN_INFO "In %s\n",__func__);

#endif

dev          = filp->private_data;

if(MAX_SIMPLE_LEN <= *loff)//检测偏移量

{

printk(KERN_ERR "the offset is illegal in func %s\n", __func__);

return-EINVAL;

}

else

{

remain_space = MAX_SIMPLE_LEN - *loff;

if(count > remain_space)

{

#if SIMPLE_DEBUG

printk(KERN_WARNING "the data is to long to write to the device\n");

#endif

count = remain_space;

}

else

{

}

}

err = copy_from_user((dev->data)+(*loff),userstr,count);//取得数据

if(err != 0)

{

printk(KERN_ERR "an error occured when copy data from user\n");

returnerr;

}

else

{

#if SIMPLE_DEBUG

printk(KERN_INFO "data copy from user OK\n");

#endif

*loff = *loff + count; //跳着偏移

if(*loff > dev->count)

{

dev->count = *loff;

}

else

{

}

returncount;//返回写入的数据量

}

}

lseek方法:

根据用户传入的参数调整文件偏移

mode

SEEK_SET

从文件起始处开始偏移

SEEK_CUR

从文件当前位置计算偏移

SEEK_END

从文件末尾计算偏移

file结构的f_pos保存了文件的偏移量

在调整文件偏移后需要 更新file中得f_pos成员

staticloff_t simple_llseek(structfile *filp, loff_t loff,intmode)

{

structsimple_dev *dev = NULL;

loff_t tmp_len;

#if SIMPLE_DEBUG

printk(KERN_INFO "In %s\n",__func__);

#endif

dev          = filp->private_data;

switch( mode )

{

caseSEEK_SET:

if( loff 

{

printk(KERN_ERR "can't move above file line %d \n", __LINE__);

return-1;

}

elseif(loff > dev->count)

{

printk(KERN_ERR "offset is too long line %d\n", __LINE__);

return-1;

}

else

{

filp->f_pos = loff;

}

break;

caseSEEK_CUR:

if((tmp_len = filp->f_pos+loff) 

{

printk(KERN_ERR "can't move above file line %d \n", __LINE__);

return-1;

}

elseif(tmp_len > dev->count)

{

printk(KERN_ERR "offset is too long line %d\n", __LINE__);

return-1;

}

else

{

filp->f_pos = tmp_len;

}

break;

caseSEEK_END:

if((tmp_len = dev->count+loff ) 

{

printk(KERN_ERR "can't move above file line %d \n", __LINE__);

return-1;

}

elseif(tmp_len > dev->count)

{

printk(KERN_ERR "offset is too long line %d\n", __LINE__);

return-1;

}

else

{

filp->f_pos = tmp_len;

}

break;

default:

printk(KERN_INFO "illigal lseek mode! \n");

return-1;

break;

}

returnfilp->f_pos;

}

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

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

相关文章

基于光线追踪的渲染中景深(Depth of field)效果的实现

图形学离线渲染中常用的透视摄像机模型时根据小孔成像的原理建立的&#xff0c;其实现通常是从向成像平面上发射ray&#xff0c;并把trace这条ray的结果作为成像平面上对应交点的采样结果。即&#xff1a; 图片来自《Fundamentals of Computer Graphics》 现实中的镜头拍摄的图…

带你制作百词斩单词表读写插件

上篇博文简单的介绍了一下Chrome插件&#xff0c;今天就与大家分享一下我做的这款有实际意义的插件吧。 做这款插件主要是用百词斩站点进行单词学习时&#xff0c;遇到的一点点闹心事儿。在单词表中不能听发音。也不能练习拼写。所以才忍无可忍的做了这么一款插件。自我感觉还是…

iphone各机型参数对比_带你了解新款iPhone 12系列四款机型

2020年10月14日凌晨1&#xff1a;00&#xff0c;苹果召开新品发布会&#xff0c;发布了新款iPhone 12系列手机&#xff0c;“果粉”们期待已久的iPhone 12终于来了。iPhone 12系列手机共有四款机型&#xff0c;分别是iPhone 12 mini、iPhone 12、iPhone 12 Pro、iPhone 12 Pro …

高并发第一弹:准备阶段 了解高并发

高并发第一弹:准备阶段 了解高并发 首先需要知道什么并发, 什么是高并发. 并发: 关于并发的学习&#xff0c;可以从JDK提供的并发包为核心开始&#xff0c;许多其他的类和封装都是对其进行扩展或者补充&#xff0c;我们来看一下Java并发包(java.util.concurrent包&#xff0c;简…

matlab立体坐标定位_【半导光电】基于光电探测器的激光章动定位算法(二)

今日光电有人说&#xff0c;20世纪是电的世纪&#xff0c;21世纪是光的世纪&#xff1b;知光解电&#xff0c;再小的个体都可以被赋能。欢迎来到今日光电&#xff01;----与智者为伍 为创新赋能----1. 章动定位算法实验前&#xff0c;首先需要对光路进行调节&#xff0c;保证经…

Android:支持多选的本地相册

前段时间在做一个动态发布功能&#xff0c;需要用到图片上传。一开始直接调用的系统相册和相机&#xff0c;由于系统相机不支持多选&#xff0c;就花点时间做了个本地相册&#xff0c;在此开源下。 先上截图&#xff0c;依次为选择相册界面、相册详情界面、查看图片大图界面 相…

心灵与大脑

2019独角兽企业重金招聘Python工程师标准>>> http://blog.sina.com.cn/s/blog_6f034fc30102f2tg.html 转载于:https://my.oschina.net/chirnson/blog/832011

python入门心得_记初学python的一些心得

人生苦短&#xff0c;我用python&#xff01; 其实我自学python也很长一段时间了&#xff0c;但总是去更换学习资料&#xff0c;搞的现在学的不是很好&#xff0c;因为没更换次资料都要从头开始学起&#xff0c;那么分享下我的学习战况吧&#xff0c;不是很好&#xff0c;还将就…

16.U-boot的工作流程分析-2440

16.U-boot的工作流程分析-2440 分析的流程&#xff1a; 程序入口 第一阶段程序分析 第二阶段程序分析 2440开发板&#xff1a; 1.uboot的入口&#xff1a; 要看uboot工程的入口&#xff0c;首先打开顶层目录的Makefile&#xff1a; Uboot所支持的开发板&#xff0c;在顶层的Ma…

如何使用Redis做MySQL的缓存

应用Redis实现数据的读写&#xff0c;同时利用队列处理器定时将数据写入mysql。 同时要注意避免冲突&#xff0c;在redis启动时去mysql读取所有表键值存入redis中&#xff0c;往redis写数据时&#xff0c;对redis主键自增并进行读取&#xff0c;若mysql更新失败&#xff0c;则需…

psychopy 与脑电打码 eeg

2019独角兽企业重金招聘Python工程师标准>>> 实验程序就不放了&#xff0c;这里主要放如何向串口发送打码的代码 实际上&#xff0c;给脑电打码的本质就是向串口发送一个字符&#xff0c;脑电的程序会自动在收到该字符的同时在脑电数据上进行标记。以下代码打开了一…

mysql -- 索引的使用

普通索引&#xff1a;用于提升查询速度唯一索引&#xff1a;用于提升查询速度&#xff0c;还要求字段值不得重复主键索引&#xff1a;唯一性且不为空的索引全文索引&#xff1a;用于大量文本搜索中建立的索引虽然索引有好处&#xff0c;但是凡是都有俩面性&#xff0c;提高效率…

surface pro 7 linux,微软 Surface Pro、Studio、Laptop 全线更新

今晨&#xff0c;微软在纽约的秋季新品发布会上&#xff0c;发布了 Surface Pro 6、Laptop 2 以及最顶级的 Studio 2 三款备受期待的 Surface 产品。至此&#xff0c;包括年初的 Surface Book 2 在内&#xff0c;完成了2018 年 Surface 产品线所有升级计划。当然这场规模不算大…

dremwere怎样让多个图片并列排放_PPT图片布局不好看?六步教你,看完就会。

我们平时很多场合需要演示讲解时&#xff0c;少不了使用PPT。尤其目前白领层人士&#xff0c;项目总结、产品介绍、调研报告…无时无刻不被PPT包围&#xff0c;又无时无刻不被PPT设计所困恼。诚然设计好看实用的PPT需要高质量素材资源和坚实的文字功底。但在处理美化PPT时&…

ThreadLocal 你到底是个什么鬼

2019独角兽企业重金招聘Python工程师标准>>> 很多文章都拿它跟同步机制作比较&#xff0c;我觉得这个思路对于理解这个东西完全没有作用。 ThreadLocal跟synchronize这类东西作比较&#xff0c;是很多文章的套路&#xff0c;我感觉这么比较&#xff0c;就跟比较重载…

grep 显示包含两个关键字_linux三剑客之-grep

一、grep简介1.介绍全局查找正则表达式并且打印结果行的命令。2.输入一个文件或者一个标准输入(stdin),或者是一个“-”连字符()。3.输出打印在屏幕上4.grep家族扩展命令egrep、fgrep二、 Grep命令的应用1.命令格式grep [选项] 模式 [文件…]例如&#xff1a;grep root /etc/pa…

Python装饰器的实现原理

Python中的装饰器是通过利用了函数特性的闭包实现的&#xff0c;所以在说装饰器之前&#xff0c;我们需要先了解函数特性&#xff0c;以及闭包是怎么利用了函数特性的。 1.函数特性 Python中的函数特性总的来说有四点: 1.函数作为变量传递 def add(x):return x 1a add 2.函数…

opengl 安装_如何使得支持 OpenGL 的 Flatpak 应用和游戏在专有 Nvidia 图形驱动下工作 | Linux 中国...

一些支持 OpenGL 并打包为 Flatpak 的应用和游戏无法使用专有 Nvidia 驱动启动。本文将介绍如何在不安装开源驱动(Nouveau)的情况下启动这些 Flatpak 应用或游戏。-- Logix这有个例子。我在我的 Ubuntu 18.04 桌面上使用专有的 Nvidia 驱动程序 (nvidia-driver-390)&#xff0c…

RequireJS入门(一)

RequireJS由James Burke创建&#xff0c;他也是AMD规范的创始人。 RequireJS会让你以不同于往常的方式去写JavaScript。你将不再使用script标签在HTML中引入JS文件&#xff0c;以及不用通过script标签顺序去管理依赖关系。 当然也不会有阻塞&#xff08;blocking&#xff09;的…

Oracle数据库中游标的游标的使用

本人不喜欢说概念啥的&#xff0c;就直接说明使用方法吧 案例1&#xff1a; 1 DECALRE2 --声明游标3 CURSOR C_USER(C_ID NUMBER) IS4 SELECT NAME FROM USER WHERE TYPEID C_ID;5 V_NAME C_USER%rowtype; --定义游标变量6 BEGIN7 OPEN C_USER(变量值); …