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,一经查实,立即删除!

相关文章

web开发中的 emmet 效率提升工具

web开发中的 emmet 效率提升工具 可以用来快速生成html 代码。 并且给各种IDE、编辑器提供了插件支持&#xff0c;sublime &#xff0c;webstorm等。 如在webstorm中安装好emmet之后&#xff0c;输入以下文本&#xff0c; #page>div.content[ng-model"user"]ul>…

python二维数组操作_Python二维数组应用与操作

课课家将会在这里为大家详细的介绍一下Python二维数组的相关应用方法以及定义方式&#xff0c;相信朋友们可以从中学习到更多的知识。 Python数组的应用中在实际编程中是一个非常重要的应用技术&#xff0c;作为Python编程人员来说&#xff0c;必须要熟练的掌握这方面的所有应用…

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

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

ubuntu 安装 pycharm

添加源&#xff1a;$ sudo add-apt-repository ppa:mystic-mirage/pycharm安装收费的专业版&#xff1a;$ sudo apt update$ sudo apt install pycharm安装免费的社区版&#xff1a;$ sudo apt update$ sudo apt install pycharm-community卸载&#xff1a;$ sudo apt remove p…

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

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

Linux7改运行级别,Centos7.0修改系统运行级别

首先翻译下ininttab里面的内容&#xff1a;#inittab不再使用时利用系统。#添加配置这会对你的系统没有影响。#Ctrl-Alt-Delete由/usr/lib系统/系统/ctrl-alt-del.target处理#系统使用的目标而不是运行级别。默认情况下&#xff0c;有两个主要目标&#xff1a;#multi-user.targe…

python测试字符串类型的函数_python-02 数据类型 字符串str

字符串str 一、字符串定义 概念&#xff1a;字符串是有序的 不可修改的&#xff0c;元素以引号包围的序列 引号类型&#xff1a;单引号 “”双引号 “ ””三引号 三单引号 print(python) print("python") print(python) print("""python""…

POJ2115 C Looooops(线性同余方程)

无符号k位数溢出就相当于mod 2k&#xff0c;然后设循环x次A等于B&#xff0c;就可以列出方程&#xff1a; $$ CxA \equiv B \pmod {2^k} $$ $$ Cx \equiv B-A \pmod {2^k} $$ 最后就用扩展欧几里得算法求出这个线性同余方程的最小非负整数解。 1 #include<cstdio>2 #incl…

工作测试博客

工作测试博客转载于:https://blog.51cto.com/12559670/1895000

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 …

设置开机自启动服务

一、软链接方法 利用ln -s 命令将/etc/rc.d/init.d/目录下脚本&#xff08;注意执行权限&#xff09;软连接到 rc3目录下&#xff0c;/etc/rc.d/rc3.d 目录也就是我们一般的系统运行级别。ln -s /etc/rc.d/init.d/** /etc/rc.d/rc3.d/S**这里的S代表的是开机自启动服务&#x…

mysql benchmark基准测试

git项目地址&#xff1a; https://github.com/akopytov/sysbench 利用sysbench很容易对mysql做性能基准测试&#xff08;当然这个工具很强大&#xff0c;除了测试主流数据库性能&#xff0c;还能测试其它方面&#xff0c;详情自己看官网项目文档&#xff09; mac上的用法&#…

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

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

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

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

linux系统死机窗口移动不了怎么办,Linux 操作系统死机故障处理方法总结

hai00882008-01-30 15:53我只備份一次,我的磁帶有400G, 備份第二次,磁帶就彈出來,我的tapelist里的內容 20080130151855 DailySet1-01 reuse是不是和我的anmanda.conf的chg-manua(更換磁帶的腳本)l這個腳本有關係,-sh-3.00$ amcheck DailySet1Amanda Tape Server Host Check---…

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;还将就…

罗技键盘linux,logiops,在 Linux下设置罗技鼠标的按键和手势

众所周知&#xff0c;几乎所有的消费级电子产品都不会对 Linux 有太好的支持&#xff0c;罗技当然也不例外。Logitech Options 是罗技办公鼠标的自定义功能驱动&#xff0c;很容易猜到&#xff0c;罗技只提供了Windows和Mac版本。但幸运的是&#xff0c;有人开发出了一个第三方…

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

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