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

来源:互联网 发布:优梵艺术家具 知乎 编辑:程序博客网 时间:2024/05/30 05:21

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

     

一、 打开和关闭设备函数

a -- 打开设备

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

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

b -- 关闭设备      

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

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

这两个函数已经讲过,这里不再赘述,主要看下面几个函数


二、read()、write() 函数

        现在把 read()、write() 两个函数放一起讲,因为两个函数非密不可分的,先看一下两个函数的定义 

a -- read() 函数

   函数原型         ssize_t (*read) (struct file * filp, char __user * buffer, size_t    size , loff_t * p);    参数含义

 filp       :为进行读取信息的目标文件,

 buffer  :为对应放置信息的缓冲区(即用户空间内存地址);

 size     :为要读取的信息长度;

 p          :为读的位置相对于文件开头的偏移,在读取信息后,这个指针一般都会移动,

                 移动的值为要读取信息的长度值

b -- write() 函数

   函数原型         ssize_t (*write) (struct file * filp, const char __user *   buffer, size_t count, loff_t * ppos);    参数含义

filp      :为目标文件结构体指针;

buffer :为要写入文件的信息缓冲区;

count  :为要写入信息的长度;

ppos   :为当前的偏移位置,这个值通常是用来判断写文件是否越界

         

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

    len = read(fd,buf,len)

    len = write(fd,buf,size)

static ssize_t hello_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)

static ssize_t hello_write(struct file *filep, const char __user *buf, size_t len, loff_t *pos)



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

        下面看一下copy_from_user() 及 copy_to_user() 函数的定义:

static inline int copy_from_user(void *to, const void __user volatile *from, unsigned long n){__chk_user_ptr(from, n);volatile_memcpy(to, from, n);return 0;}static inline int copy_to_user(void __user volatile *to, const void *from,       unsigned long n){__chk_user_ptr(to, n);volatile_memcpy(to, from, n);return 0;}
可以看到两个函数均是调用了_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_to_user(void __user *to, const void *from, unsigned long n)static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
用法:

和memcpy的参数一样,但它根据传参方向的不同分开了两个函数。

"to"是相对于内核态来说的。所以,to函数的意思是从from指针指向的数据将n个字节的数据传到to指针指向的数据。

"from"也是相对于内核来说的。所以,from函数的意思是从from指针指向的数据将n个字节的数据传到to指针指向的数据

返回值:函数的返回值是指定要读取的n个字节中还剩下多少字节还没有被拷贝。

注意:

一般的,如果返回值不为0时,调用copy_to_user的函数会返回错误号-EFAULT表示操作出错。当然也可以自己决定。


又到了摆实例的时候了,这里只列出部分代码,看看这两个函数的用法:

static ssize_t hello_read(struct file *filep, char __user *buf, size_t len, loff_t *pos){if(len>64){len =64;}if(copy_to_user(buf,temp,len)){return -EFAULT;}return len;}static ssize_t hello_write(struct file *filep, const char __user *buf, size_t len, loff_t *pos){if(len>64){len = 64;}if(copy_from_user(temp,buf,len)){return -EFAULT;}printk("write %s\n",temp);return len;}
测试程序:

#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>char buf[]="111232342342342";char temp[64]={0};main(){    int fd,len;    fd = open("/dev/hello",O_RDWR);    if(fd<0)    {        perror("open fail \n");        return ;    }    write(fd,buf,strlen(buf));    len=read(fd,temp,sizeof(temp));    printf("len=%d,%s \n",len,temp);    close(fd);}


      到这里open、close、read、write四个函数已经学完,下面我们来看一下四个函数使用时,到底经历了一个怎样的过程:

注:箭头方向是从调用的一方指向受作用的一方

    

    

   





1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑剪切到u盘然后打不开了怎么办 淘宝未满十八岁限制购买物品怎么办 网上飞机订票手机号填写错了怎么办 室外回填土都是砂土压不实怎么办 王牌车新车储气筒漏气查不到怎么办 顺丰快递保价后商品出现问题怎么办 未保价快递丢失没有价值证明怎么办 安卓手机谷歌地图怎么用不了怎么办 ae模板版本太高打不开怎么办 苹果手机高德地图信号弱怎么办 网上订好火车票后没赶上火车怎么办 丰巢快递柜没收到短信怎么办 被不同号码骚扰电话打个不停怎么办 手机注册被骚扰电话打个不停怎么办 网贷不停的打骚扰电话怎么办 发改委的可研报告过期了怎么办 买到没有预售证的房子怎么办 网上买的学生票取不出来怎么办 买完学生票发现打折没次数了怎么办 动车晚点方向来反了怎么办 身份证购买高铁票过不了审核怎么办 手机购买高铁票身份核验失败怎么办 在高铁上如果有人占了座位该怎么办 网上买的高铁票改签怎么办 临沂村委会强行征收我的土地怎么办 学籍验证码连续输入三次错误怎么办 社保在上海个税在外地居转户怎么办 父母已经有英国签证孩子的怎么办 营运车辆被撞不肯赔务工费怎么办 欧米茄外壳上装表带的孔穿了怎么办 淘宝上买了电子产品坏了怎么办 研究生人才补助申请期限过了怎么办 一个小孩亲妈愿意养躲起来怎么办 网银转账名字打错了怎么办 百世快递邮东西到长春件丢失怎么办 三色吸顶灯有一色不亮了怎么办 超级试驾车超出取车行政区域怎么办 护士电子化注册激活码搞丢了怎么办 香港地铁地铁错买了特惠票怎么办 湖北软考证书领取没有准考证怎么办 哈罗单车电动车骑着没电了怎么办