分享

设备驱动程序学习(一)基本数据结构

 无衍 2011-09-17
 

设备驱动程序学习(一)基本数据结构

分类: Linux 7人阅读 评论(0) 收藏 举报

设备驱动程序学习(一)基本数据结构

出处:http://blog.csdn.net/HEYUTAO007/archive/2010/07/15/5738219.aspx

1 Struct inode

file_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 作为主设备号,表示他们使用相同的设备驱动程序。

副设备号只供驱动程序使用。通常一个驱动程序控制几个设备,它通过副设备号来辨别他们。
与设备号相关的数据结构为kdev_t Kdev_t 结构主要用来表示一个设备的主设备号和副设备号。它其实只是一个短的非负整数:

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

struct
 
file_operations {

        struct module *owner; 

        // 
指向   该结 构的模  的指  ,避免正在操作  被卸  ,一般  初始化 THIS_MODULES 

        loff_t (*llseek) (struct file *, loff_t, int); 

        // llseek 
用来修改文件当前的  写位置,返回新位置 

        // loff_t 
 一个"  偏移量"。  此函数  针为   seek  用将会以不可  期的方式修改 file  构中的位置  数器。 

        
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

        // 
 设备 中同 步读 取数据。  取成功返回  取的字  数。    NULL     返回-EINVAL 

        ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);

        // 
初始化一个异    取操作,  NULL  全部通  read   

        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

        // 
 设备发 送数据。 

        ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);

        // 
初始化一个异  的写入操作。 

        int (*readdir) (struct file *, void *, filldir_t);

        // 
 用于  取目     设备 文件,  字段  NULL 

        unsigned int (*poll) (struct file *, struct poll_table_struct *);

        // 
返回一个位掩  ,用来指出非阻塞的  取或写入是否可能。 

        
//  pool  义为 NULL  设备 会被 认为 即可  也可写。 

        
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

        // 
提供一 种执  设备 特殊命令的方法。不  置入口点,返回-ENOTTY 

        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

        // 
不使用BLK的文件系  ,将使用此  函数   代替ioctl 

        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

        // 
在64位系  上,32位的ioctl  用,将使用此 函数   代替 

        int (*mmap) (struct file *, struct vm_area_struct *);

        // 
用于  求将 设备 内存映射到  程地址空  。如果无此方法,将 访问 -ENODEV 

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

        // 
如果  空, 设备 的打  操作永  成功,但系  不会通知 驱动 程序 

        // 
由VFS  用,当VFS打  一个文件,即建立了一个新的"struct file",之后  用open方法分配文件  构。open属于struct inode_operations。 

        int (*flush) (struct file *);

        // 
 生在   关闭设备 文件描述符副本,  行并等待,若    NULL ,内核将忽略用 户应 用程序的  求。 

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

        // file 
     ,将  用此指  函数 ,release与open相同可    NULL 

        int (*fsync) (struct file *, struct dentry *, int datasync);

        // 
刷新待  理的数据,如果 驱动 程序没有 实现 ,fsync  用将返回-EINVAL 

        int (*aio_fsync) (struct kiocb *, int datasync);

        // 
  fsync 

        int (*fasync) (int, struct file *, int);

        // 
通知 设备 FASYNC      化,如果 设备 不支持异  通知,  字段可以  NULL 

        int (*lock) (struct file *, int, struct file_lock *);

        // 
实现 文件   设备驱动 常不去 实现 此lock 

        ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);

        ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);

        // readv 
和writev 分散/聚集型的  写操作, 实现进   及多个内存区域的    或写操作。 

        ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);

        // 
实现 sendfile  用的  取部分,将数据从一个文件描述符移到另一个, 设备驱动 通常将其   NULL 

        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

        // 
实现 sendfile  用的另一部分,内核  用将其数据  送到 对应 文件,  次一个数据  设备驱动 通常将其    NULL 

        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

        // 
  程地址空  找到一个合适的位置,以便将底 层设备 中的内存段映射到  位置。大部分驱动 可将其    NULL 

        int (*check_flags)(int);

        // 
   块检查传递给 fcntl(F_SETEL...)  用的   

        int (*dir_notify)(struct file *filp, unsigned long arg);

        // 
 用程序使用fcntl来  求目    通知      方法。 仅对 文件系  有效,驱动 程序不必 实现  

        int (*flock) (struct file *, int, struct file_lock *);

        // 
实现 文件  

};

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 */

};

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多