linux 字符设备——驱动框架(二)
字符设备驱动框架(前言)前面编写了一个简单的linux字符设备驱动。接下来简单地来看一下字符设备驱动的框架。 一、重要的数据结构在linux 字符设备里,有三个比较重要的数据结构,分别是:struct file_operations,struct file 和 struct inode 1、struct file_operations这个结构体是相当于设备的驱动了,实现了字符设备的相关操作函数 /* 只介绍部分struct file_operations结构体的成员 */ struct file_operations { /* struct module 这个成员不是一个操作; 它是一个指向拥有这个结构体的模块指针。 * 这个成员用来在它还被使用时阻止模块被卸载。一般初始化为 THIS_MODULE,*/ struct module *owner; /* llseek 函数用来改变文件中当前的读/写的位置,如果这个函数指针是NULL,内核中 * 缺省的实现通过修改filp->f_pos进行移位 */ loff_t (*llseek) (struct file *,loff_t,int); /* read函数用来从设备中获取数据。如果这个函数指针是NULL,以 -EINVAL 失败返回给 * read 系统调用,一个非负返回值代表了成功读取的字节数。 */ ssize_t (*read) (struct file *,char __user *,size_t,loff_t *); /* write函数用来发送数据给设备。如果这个函数指针是NULL,以 -EINVAL 失败返回给 * write 系统调用,一个非负返回值代表了成功读取的字节数。 */ ssize_t (*write) (struct file *,const char __user *,loff_t *); /* poll 函数是: poll,epoll 和 select 这三个系统调用的后端。这三个系统调用都用作查询对一个 * 或者多个文件描述符的读或写是否会阻塞。poll函数应返回一个位掩码指示是否非阻塞的读或 * 者写是可能的。并且给内核提供信息,用来使调用的的进程睡眠,直到读写操作变为可能。 * 如果一个驱动的 poll 指针为 NULL,设备假定为不阻塞地可读可写。 */ unsigned int (*poll) (struct file *,struct poll_table_struct *); /* ioctl 函数 为 ioctl() 系统调用提供了发出设备特定命令的方法 * 如果一个驱动的 ioctl 指针为 NULL,对于任何未事先定义的请 * 求返回 -ENOTTY,系统调用返回一个错误 */ int (*ioctl) (struct inode *,struct file *,unsigned int,unsigned long); /* mmap 用来请求将设备内存映射到进程的地址空间,* 如果这个指针是 NULL,mmap 系统调用返回 -ENODEV. */ int (*mmap) (struct file *,struct vm_area_struct *); /* open成员是 open 系统调用的后端,通常是对设备文件进行的第一个操作 * 如果这个指针是 NULL,设备打开一直成功,但是你的驱动不会得到通知. */ int (*open) (struct inode *,struct file *); /* release成员是 close系统调用的后端,在文件结构被释放时引用这个操作。 * 如同open,release成员也可以为NULL。 */ int (*release) (struct inode *,struct file *); /* fasync这个操作用来通知设备它的 FASYNC 标志的改变(异步通知) * 如果这个成员是 NULL,驱动不支持异步通知。 */ int (*fasync) (int,int); }; 2、struct file这个结构体描述的是打开的一个文件,每打开一个文件就会有一个struct file结构体来进行管理 /* 只介绍部分struct file结构体的成员 */ struct file { /* 文件模式确定文件是可读的或者是可写的(或者都是),* 通过位 FMODE_READ 和FMODE_WRITE 描述 */ mode_t f_mode; /* 文件当前的读写位置. 如果驱动需要知到文件中的当前位置,可以读这个值,但是不应该改变它。 * 在fops 的 read 和 write 以最后的一个参数传入,来代替直接使用f_pos成员,在fops的llseek方法中 * 通过改变f_pos 成员来改变,文件的读写位置 */ loff_t f_pos; /* 文件的标志。例如 O_REONLY,O_NONBLOCK,和 O_SYNC。驱动通过检查O_NONBLOCK标志 * 来查看是否请求非阻塞操作,其他标志一般比较少用。 */ unsigned int f_flags; /* 和文件关联的操作*/ const struct file_operations *f_op; /* 这个成员通常用来指向分配的数据,通常在fops->open 成员函数里面指定。 * 如果使用了这个成员必须在fops->release 成员中释放。 */ void *private_data; }; 3、struct inodeinode 结构用来描述磁盘上一个文件。inode 结构包含大量关于文件的信息,但这个结构只有 2 个成员对于编写驱动代码有用 /* 只介绍部分struct inode结构体的成员 */ struct inode { /* 对于代表设备文件的节点,这个成员包含实际的设备编号. */ dev_t i_rdev; union { struct pipe_inode_info *i_pipe; /* 当节点指的是一个块设备文件时,代表块设备。*/ struct block_device *i_bdev; /* 当节点指的是一个字符设备文件时,代表字符设备。*/ struct cdev *i_cdev; }; } 二、linux 源代码框架分析系统调用的到内核驱动的调用过程如下(以 open 系统调用为例,其他的系统调用类似) 三、框架图<念念有余>这位博主有一张比较详细的框架图,所以直接引用过来了 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |