设备驱动程序学习(一)基本数据结构出处:http://blog.csdn.net/HEYUTAO007/archive/2010/07/15/5738219.aspx 1 Struct inodefile_operations 中的大多数操作都将inode 做为第一个参数。Linux 的VFS 是对物理文件系统,物理设备的一个封装。Inode 结构就是VFS 与下层模块对话的重要结构。文件系统由子目录和文件构成。每个子目录或文件只能由唯一的inode 描述。每个设备也是用inode 来描述的。inode 是LINUX 管理文件系统的最基本单位,也是文件系统连接任何子目录、任何文件,设备的桥梁。也就是说,整个文件系统树就是由代表任何子目录、任何文件,设备的inode 组成的。 struct inode { kdev_t i_dev; /* 文件所在设备的设备号,第一个IDE 硬盘为0x0301 */ unsigned long i_ino; /* 外存inode 的节点号, (i_dev,i_ino) 在VFS 中是唯一的 */ umode_t i_mode;/* 表示文件类型以及存取权限 */ nlink_t i_nlink;/* 连接到该文件的link 数 */ uid_t i_uid; /* 用户标识号 */ gid_t i_gid; /* 用户组标识号 */ kdev_t i_rdev;/* 根设备的设备号 */ off_t i_size;/* 文件长度 */ time_t i_atime;/* 文件访问时间 */ time_t i_mtime; /* 文件修改时间 */ time_t i_ctime; /* 文件创建时间 */ unsigned long i_blksize;/* 以字节为单位的块大小,一般为1024 字节 */ unsigned long i_blocks; /* 文件块数 */ unsigned long i_version; unsigned long i_nrpages;/* 文件在内存中所占页数 */ struct semaphore i_sem; /* 信号量 */ struct inode_operations *i_op; /* 指向一组针对该文件的操作函数, 见fs.h */ struct super_block *i_sb; /* 指向内存中 VFS 的超级块 */ struct wait_queue *i_wait; /* 在该文件上的等待队列 */ struct file_lock *i_flock; struct vm_area_struct *i_mmap; struct page *i_pages; /* 由文件占用页面构成的单向链, 通过它可访问内存中的文件数据 */ struct dquot *i_dquot[MAXQUOTAS]; struct inode *i_next, *i_prev; /* inode 资源管理中使用的链表指针 */ struct inode *i_hash_next, *i_hash_prev; /* inode cache 的链表指针 */ struct inode *i_bound_to, *i_bound_by; struct inode *i_mount; /* 指向下挂文件系统的 inode 的根目录 */ unsigned long i_count; /* 引用记数,0 表示是空闲inode */ unsigned short i_flags; unsigned short i_writecount; unsigned char i_lock; /* 对inode 加锁标志 */ unsigned char i_dirt; unsigned char i_pipe; unsigned char i_sock; unsigned char i_seek; unsigned char i_update; unsigned char i_condemned; union { /* 各类文件系统inode 的特定信息 */ ............ struct ext2_inode_info ext2_i; ............ } u; }; 对于设备管理而言,主要用到的是inode 结构的 kdev I_rdev 字段。 2 Struct kdev_t文件系统中,字符设备是通过名字来访问的。通常字符设备都在/dev 下。 在系统内部,每个字符设备都用设备号来表示。设备号由主, 副设备号来表示。 主设备号表示与设备对应的设备驱动程序。如:设备/dev/zero 和 /dev/null 都用1 作为主设备号,表示他们使用相同的设备驱动程序。 副设备号只供驱动程序使用。通常一个驱动程序控制几个设备,它通过副设备号来辨别他们。 typedef unsigned short kdev_t; 但是,我们可以把它看作: typedef struct { unsigned short major, minor; } kdev_t; 内核提供了一组宏来操作kdev_t 结构: MAJOR(kdev_t dev) : extract the major number from a kdev_t structure MINOR(kdev_t dev) : extract the minor number from a kdev_t structure MKDEV( int ma, int mi):return a kdev_t built from major and minor numbers 旧版本的内核dev_t 对应kdev_t 3 struct device_struct内核中有两张表。一张表用于字符设备驱动程序,另一张用于块设备驱动程序。这两张表用来保存指向file_operations 结构的指针,设备驱动程序内部的函数地址就保存在这一结构中。定义在文件fs/devices.c中: struct device_struct { const char * name; struct file_operations * fops; }; static struct device_struct chrdevs[MAX_CHRDEV]; static struct device_struct blkdevs[MAX_BLKDEV]; 内核用主设备号作为索引访问file_operations 结构,因而能访问驱动程序内的子程序。 其实块设备表和字符设备表使用了相同的数据结构。在某些系统中,这些设备表也称作设备开关表,不同的是它们直接定义了一组函数指针进行对设备的管理。而这里系统用文件操作(file_operations )代替了那组开关。file_operations 是文件系统与设备驱动程序之间的接口,系统特殊文件在建立的时候并没有把两者对应起来,只是把设备的缺省文件结构和inode 节点结构赋给设备文件,而真正的对应定义在系统启动之后,当设备被打开时时才进行的。 操作blkdev_open 和chrdev_open 定义在文件devices.c 中,它们的基本功能是当设备文件初次打开时,根据该文件的inode 节点信息找到设备真正的文件操作接口,然后更新原来的设备表项;最后再调用该设备的open 操作。 /include/linux/major.h 中定义了设备表的长度。设备表中不同的表项表示不同种类的设备,也就是说,LINUX系统分别支持各128 种不同的块设备和字符设备。 4 Struct file_operations对于字符设备来说,file_operations{} 是唯一的函数接口。内核通过file_operations 结构来访问driver 的功能。这也是linux 的OO 思想的体现之一。file_operations 的定义在文件<linux/fs.h> 中。 每个字符设备都有一个file_operatioins 结构。这个结构指向一组操作函数(open,read… ). 每个函数的定义由设备驱动提供。当然,有些标准操作某些设备并不支持,这时,file_operatons 结构中对应表项为NULL (. 随着linux 内核的不断升级,file_operatioins 结构也不断变大。最新的版本中,甚至函数原型也发生了一些变化。当然,新版本总会向下兼容的。)
注 释 基于kernel 2.6.15 5 Struct file<linux/fs.h> 中定义的file 结构是设备驱动程序中用到的仅次于file_operations 的数据结构。这里的file 结构和用户程序用到的FILE 结构不同。它们定义在不同的空间。 一个file 结构代表一个”打开的文件”,它在文件被打开时被创建,然后被传给要对文件进行操作的函数,知道文件被关闭。一个打开的文件和一个磁盘上的文件不同,磁盘文件用inode 表示。 下面讨论一些重要的域: mode_t f_mode ; 文件的读写模式由f_mode 的FMODE_READ 和FMODE_WRITE 控制。在ioctl 函数中需要通过此位控制文件的读写权限。当然,read ,write 函数不需要检查f_mode 因为读写权限的检查是由内核在调用他们之前进行的。 loff_t f_pos 当前的读写位置。Loff_t 是一个64 位的值。 unsigned short f_flags; 也是文件的一些标志。如:O_RDONLY,O_NONBLOCK 和O_SYNC. 驱动程序必须检查f_flags 以进行非阻塞操作。读写操作控制必须用f_mode. struct inode * f_inode; 所打开的文件对应的inode, struct file_operations * f_op; 对打开的文件的处理函数。一般在打开文件或设备初始化时由内核赋值。可以动态的修改此结构来改变文件的处理函数。 void *private_data; open 系统调用把此指针设为NULL, 然后再调用驱动程序的open 函数。驱动程序可以自由得使用,甚至忽略它。
struct file { mode_t f_mode; loff_t f_pos; unsigned short f_flags; unsigned short f_count; unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; struct file *f_next, *f_prev; struct fown_struct f_owner; struct inode * f_inode; struct file_operations * f_op; unsigned long f_version; void *private_data; /* needed for tty driver, and maybe others */ }; |
|