字符设备驱动之结构体

https://blog.csdn.net/tigerjibo/article/details/6412469
大部分驱动程序操做都涉及到三个重要的内核数据结构,分别是file_operations、file和inode,它们定义在<linux/fs.h>node

一、file_operations:是一个函数指针的集合
1>应用程序和VFS之间的接口是系统调用,而VFS与磁盘文件系统以及普通设备之间的接口是file_operations结构体成员函数。file_operations结构体中成员函数是字符设备驱动与内核的接口,是用户空间对linux进行系统调用的最终落实者,这个结构体包含对文件打开,关闭,读写,控制的一系列成员函数
2>因为字符设备的上层没有磁盘文件系统,因此字符设备的file_operations成员函数就直接由设备驱动提供了,file_operations正是字符设备驱动的核心
3>对于块设备而言,ext2,fat,jffs2等文件系统中会实现对VFS的file_operations成员函数,设备驱动层看不到file_operations的存在。磁盘文件系统和设备驱动会将磁盘上的文件的访问最终转换成对磁盘上柱面和扇区的访问
4>file_operations的成员:linux

static const struct file_operations XXX_fops =
{
.owner = THIS_MODULE,
.llseek = XXX_llseek,
.open = XXX _open,
.read = XXX _read,
.write = XXX _write,
.ioctl = XXX _ioctl,
.release = XXX _release,
};编程

1>struct module owner:第一个file_operations成员根本不是一个操做,它是一个指向拥有这个结构的模块的指针。这个成员用来在他的操做还在被使用时阻止模型被卸载。几乎全部程序中,它被简单初始化为THIS_MODULE,一个<linux/module.h>中定义的宏
2> loff_t (
llseek) (struct file *, loff_t, int);
文件定位函数,合法时返回文件的当前位置,不合法返回-EINVAL
第一个参数为file指针
第二个为请求偏移量
第三个为文件定位的起始地址:通常为0或1,0表示文件开头,1表示当前位置数据结构

3> ssize_t (read) (struct file , char __user , size_t, loff_t );读函数,利用copy_to_user()函数让内核读取用户空间的数据,并返回访问的字节数
4> ssize_t (write) (struct file , const char __user , size_t, loff_t );写函数利用copy_from_user()函数让用户向文件写入数据,并返回写入的字节数
5> int (ioctl) (struct inode , struct file , unsigned int, unsigned long);执行I/O控制命令
6> int (
open) (struct inode , struct file );打开文件
7>int (release) (struct inode , struct file *);关闭文件函数

  1. struct file:文件结构体
    1>文件结构体表明一个打开的文件(设备对应于设备文件),系统中每一个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时建立,并传递给在文件上进行操做的任何函数。在文件的全部实例都关闭以后,内核释放这个数据结构
    2>字符设备驱动用到的变量,文件读写模型mode,标识f_flags都是设备关系的内容,而私有数据指针private_data在设备驱动中被普遍使用,大多数被用于指向设备驱动自定义的设备结构体
    3>struct file

struct file {
940 /
941
fu_list becomes invalid after file_free is called and queued via
942 * fu_rcuhead for RCU freeing
943 /
951 const struct file_operations
f_op;
957 unsigned int f_flags;
958 fmode_t f_mode;
959 loff_t f_pos;
960 struct fown_struct f_owner;
969 void *private_data;
970
979};.net

1> fmode_t f_mode:经过宏 FMODE_READ 和 FMODE_WRITE.肯定文件是可读/可写/可读写。你可能想在你的open或者ioctl函数中检查这个成员的读写许可,可是你不须要检查读写许可,由于内核在调用你的方法以前检查。当文件尚未为那种存取而打开时读或者写的企图被拒绝,驱动甚至不知道这个状况。
2>unsigned int f_flags:这些是文件标志, 例如 O_RDONLY, O_NONBLOCK, 和 O_SYNC. 驱动应当检查 O_NONBLOCK 标志来看是不是请求非阻塞操做;其余标志不多使用. 全部的标志在头文件 <linux/fcntl.h> 中定义.
3> void private_data:open系统调用设置这个指针为Null,在为驱动调用open以前,你能够自由使用这个成员或者忽略它;你可使用这个成员来指向分配的数据,可是接着你必须记住在内核销毁文件结构以前,在release方法中释放那个内存。private_data是一个有用的资源,在系统调用间保留状态信息。
4> loff_t f_pos:当前读写位置。loft_t在全部平台都是64位(ggc术语是long long)。驱动能够读这个值,若是它须要知道文件中的当前位置,可是正常地不该该改变它; 读和写应当使用它们做为最后参数而收到的指针来更新一个位置, 代替直接做用于 filp->f_pos. 这个规则的一个例外是在 llseek 方法中, 它的目的就是改变文件位置.
5> struct file_operations
f_op: 和文件关联的操做. 内核安排指针做为它的 open 实现的一部分, 接着读取它当它须要分派任何的操做时. filp->f_op 中的值从不禁内核保存为后面的引用; 这意味着你可改变你的文件关联的文件操做, 在你返回调用者以后新方法会起做用. 例如, 关联到主编号 1 (/dev/null, /dev/zero, 等等)的 open 代码根据打开的次编号来替代 filp->f_op 中的操做. 这个作法容许实现几种行为, 在同一个主编号下而没必要在每一个系统调用中引入开销. 替换文件操做的能力是面向对象编程的"方法重载"的内核对等体指针

4>驱动程序中常常会使用以下相似的代码来检测用户打开文件的读写方式。对象

if (flie->f_mode & FMODE_WRITE)//用户要求可写
{blog

}
4>用下面的代码判断以阻塞仍是非阻塞方式打开设备文件
if (file->f_flags & O_NONBLOCK)//非阻塞
{接口

}
else //阻塞
{

}

3.struct inode 结构

虚拟文件系统中的每一个文件都关联到一个inode,用于管理文件的属性(包含文件访问权限,属主,组,大小,生成时间,访问时间,最后修改时间等信息,它是Linux管理文件系统的最基本单位,也是文件系统链接任何子目录,文件的桥梁)

struct inode {
741 /* RCU path lookup touches following: /
742 umode_t i_mode;
766 dev_t i_rdev;
786 struct list_head i_devices;
787 union {
788 struct pipe_inode_info
i_pipe;
789 struct block_device i_bdev;
790 struct cdev
i_cdev;
791 };
812 void i_private; / fs or device private pointer /
};
1>i_mode:为惟一地标示与一个设备文件关联的设备,内核在i_mode中存储了文件类型(面向块/字符)
2>i_rdev:存储了主从设备号。主从设备号在内核中合并为一种变量类型dev_t
3>i_fop:是一组函数指针的集合,包括许多文件操做如打开/读取/写入等,这些由虚拟文件系统使用来处理块设备。
4>内核会根据inode标示块设备仍是字符设备,来使用i_bdev或者i_cdev指向更多具体的信息。对于表明设备文件的节点,这个成员包含实际的设备编号
5>struct cdev
i_dev:struct cdev是内核的内部结构,表明字符设备;这个成员包含一个指针,指向这个结构, 当节点指的是一个字符设备文件时.

4.cdev结构体

在linux中使用cdev结构体描述字符设备,cdev结构体定义:

12struct cdev {
13 struct kobject kobj;
14 struct module owner; 15 const struct file_operations ops; 16 struct list_head list; 17 dev_t dev; 18 unsigned int count; 19}; 1>kobj是一个嵌入在该结构中的内核对象。它用于该数据结构的通常管理(是一个重要的数据结构,后在后面对其进行详细的介绍) 2>owner指向提供驱动程序的模块 3>ops是一组文件操做,实现了与硬件通讯的具体操做

相关文章
相关标签/搜索