首页系统综合问题linux驱动开发第2讲:应用层的write如何调用到驱动中的write

linux驱动开发第2讲:应用层的write如何调用到驱动中的write

时间2022-12-22 19:51:52发布分享专员分类系统综合问题浏览266

今天小编给各位分享write的知识,文中也会对其通过linux驱动开发第2讲:应用层的write如何调用到驱动中的write和linux驱动程序如何调用等多篇文章进行知识讲解,如果文章内容对您有帮助,别忘了关注本站,现在进入正文!

内容导航:

  • linux驱动开发第2讲:应用层的write如何调用到驱动中的write
  • linux驱动程序如何调用
  • linux驱动程序中write绑定函数未被调用
  • 关于linux的write函数
  • 一、linux驱动开发第2讲:应用层的write如何调用到驱动中的write

    关注“技术简说”,带你一步一步学习linux内核驱动。

    在linux操作系统中,一切皆是文件:文件是文件,目录是文件,设备是文件,socket套接字是文件,管道也是文件。

    linux操作系统用文件抽象出了这一切,文件成为了以上这些实体的编程接口。正由于此,基于linux的编程变成了面向文件的编程,对于linux应用程序开发者而言,简直是爽的不要不要的。

    但是,对于内核开发者而言,却是未必。虽然应用层可以用open, write,read操纵一切,但是在内核里面,却需要不同的部分(或者说驱动)来真正实现这一切。

    本文接着linux驱动开发第1讲:带你编写一个最简单的字符设备驱动,来讲述linux应用程序中的write()函数如何调用到hello驱动里的write()函数,并顺道回答上一讲最后的几个遗留问题。

    先上一张图简单说明下调用流程:

    应用层-->系统调用-->驱动

    任何一个可以正常使用的函数,如果你的应用程序里没有定义,那么肯定定义在c库里。而c库怎么做会视情况而定。像一些字符处理函数,c库里会实现它们;但是像write函数,c库只会做一些检查,然后就陷入write的系统调用,系统调用会通过软中断的方式陷入到内核空间里去执行。

    应用空间和内核空间是彼此隔离的,互相看不到对方,也无法访问对方的数据,这是为了安全。所以就write函数而言,当从用户空间通过系统调用进入到内核空间以后,内核需要通过copy_from_user函数才能把应用程序传给write的数据拷贝到内核空间,之后内核空间才能对此数据进行处理。

    整个流程,上图表现的已经非常明显,但是问题也是有的,操作系统中的系统调用最终是如何知道应该调用哪个驱动里的write函数呢?在linux驱动开发第1讲:带你编写一个最简单的字符设备驱动里,我们确实看到当执行测试程序的时候,当调用测试程序里的open, write和read函数的时候,分别调用到了hello驱动里的hello_open, hello_write和hello_read函数,难道这是一个巧合吗?

    当然不是!

    我们先从逻辑上说明这个问题。

    如果我们没有记错,在hello驱动里,有定义主次设备号:

    int reg_major  =  232;    int reg_minor =   0;int hello_init(void){       devNum = MKDEV(reg_major, reg_minor);gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);    gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL);    ...    cdev_init(gDev, gFile);    cdev_add(gDev, devNum, 3);}

    在hello_init里,我们把主设备号232和此设备号0组合成了devNum。

    cdev_init(gDev, gFile); 建立了gDev和gFile的逻辑关系;

    cdev_add(gDev, devNum, 3); 建立了gDev和devNum的逻辑关系;

    其实你翻开代码看细节会发现,以上两句代码其实建立了gFile和devNum的对应关系,也就是file_operations和devNum的对应关系,也就是建立了file_operation和主次设备号(232,0)的对应关系。

    注意:在linux里,在应用层用文件句柄也就是fd表示一个打开的文件,但是在内核里用struct file 表示一个打开的文件,用struct file_operations表示对该文件的操作。fd和struct file是一一对应的,而struct file和struct file_operations也是一一对应的。这是struct file_operations的结构体定义:

    struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*fasync) (int, struct file *, int);  ...};

    在上一讲的例子里,我们打开的文件名字是/dev/hello,这是一个设备文件,对应的主次设备号分别为232和0。所以,当你打开/dev/hello之后,就已经建立了这个文件和hello驱动里的 struct file 的对应关系,也就建立了这个文件和hello驱动里的struct file_operations的对应关系。

    好,了解以上的背景之后,我们来看看代码。

    我们从内核里write系统调用的实现部分开始阅读:

    相关的代码在:fs/read_write.c

    备注:SYSCALL_开头表示是系统调用。

    关键代码在vfs_write。所以,我们继续跟进入:

    继续跟入__vfs_write:

    ssize_t __vfs_write(struct file *file, const char __user *p, size_t count,    loff_t *pos){if (file->f_op->write)return file->f_op->write(file, p, count, pos);else if (file->f_op->write_iter)return new_sync_write(file, p, count, pos);elsereturn -EINVAL;

    关键代码在这里:

    if (file->f_op->write)return file->f_op->write(file, p, count, pos);

    上面提到建立了/dev/hello和file_operations的关系。所以这里其实就是判断hello驱动里有没有定义write函数,如果有,那就调用hello驱动里的write函数。

    所以,按照如上的路径,应用程序里的write就顺利的调用到了hello驱动里的write函数。因为我们驱动里的hello_write和hello_read里都返回了0。所以,应用程序里的write和read也返回了0。

    ssize_t hello_write(struct file *f, const char __user *u, size_t s, loff_t *l){    printk(KERN_EMERG"hello_write\r");    return 0;}ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l){    printk(KERN_EMERG"hello_read\r");          return 0;}

    如果你想让测试程序里的write和read返回非零值,只要把驱动里的return 0,改为任意值就好了,大家可以自己测试一下。

    关注“技术简说”,带你一步一步开发linux内核驱动。

    一、linux驱动程序如何调用

    驱动程序工作在
    内核空间
    ,由内核来调用
    比如某硬件的驱动程序中实现了hd_write()函数,则用户在
    用户空间
    打开这硬件的设备文件并调用
    系统调用
    函数write()时,内核就调用hd_write()函数。

    二、linux驱动程序中write绑定函数未被调用

    你试试不用KERN_NOTICE,直接printk

    三、关于linux的write函数

    1.功能
    将数据写入已打开的文件内
    2.相关函数
    open,read,fcntl,close,lseek,sync,fsync,fwrite
    3.表头文件
    #include
    4.定义函数
    ssize_t
    write
    (int
    fd,const
    void
    *
    buf,size_t
    count);
    5.函数说明
    write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。当然,文件读写位置也会随之移动。
    6.返回值
    如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
    7.错误代码
    eintr
    此调用被信号所中断。
    eagain
    当使用不可阻断i/o
    时(o_nonblock),若无数据可读取则返回此值。
    ebadf
    参数fd非有效的文件描述词,或该文件已关闭。

    关于write的问题,通过《linux驱动程序中write绑定函数未被调用》、《关于linux的write函数》等文章的解答希望已经帮助到您了!如您想了解更多关于write的相关信息,请到本站进行查找!

    爱资源吧版权声明:以上文中内容来自网络,如有侵权请联系删除,谢谢。

    write
    奇瑞QQ冰淇淋值不值得购买?看完立刻种草 我的电脑蓝屏,代码是0x000009,网上查说是找不到特定磁盘,具体企本顺热是什么原因?