1、Linux设备驱动分类:
1、字符设备:
字符设备指那些必须以串行顺序依次进行访问的设备,如触摸屏、磁带驱动器、鼠标等。
2、块设备:
块设备可以用任意顺序进行访问,以块为单位进行操作,如硬盘、软驱等。字符设备不经过系统的快速缓冲,而块设备经过系统的快速缓冲.但是,字符设备和块设备并没有明显的界限,如对于Flash设备,符合块设备的特点,但是我们仍然可以把它作为一个字符设备来访问。
3、网络设备 :
网络设备面向数据包的接受和发送而设计,他不对应文件系统的节点,内核与网络设备的通讯和内核与字符以及块设备的通讯是完全不同的。
2、驱动设计的最基本的两个结构体
1、file结构体
struct file结构体定义在/linux/include/linux/fs.h(Linux 2.6.26内核)中
struct file {
/*
* fu_list becomes invalid after file_free is called and queued via
* fu_rcuhead for RCU freeing
*/
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */
#ifdef CONFIG_SMP
int f_sb_list_cpu;
#endif
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;
u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data;
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,struct file的指针通常被命名为file或filp。以下是对结构中的每个数据成员的解释:
一、
union { struct list_head fu_list; struct rcu_head rcuhead; }f_u;其中的struct list_head定义在 linux/include/linux/list.h中,原型为:
struct list_head { struct list_head *next, *prev; }; 用于通用文件对象链表的指针。 struct rcu_head定义在linux/include/linux/rcupdate.h中,其原型为: /** * struct rcu_head – callback structure for use with RCU * @next: next update requests in a list * @func: actual update function to call after the grace period. */ struct rcu_head { struct rcu_head *next; void (*func)(struct rcu_head *head); }; RCU(Read-Copy Update)是Linux 2.6内核中新的锁机制,具体在这里有介绍:http://www.ibm.com/developerworks/cn/linux/l-rcu/
二、
struct path f_path; 被定义在linux/include/linux/namei.h中,其原型为: struct path { struct vfsmount *mnt; struct dentry *dentry; }; 在早些版本的内核中并没有此结构,而是直接将path的两个数据成员作为struct file的数据成员, struct vfsmount *mnt的作用是指出该文件的已安装的文件系统, struct dentry *dentry是与文件相关的目录项对象。三、
const struct file_operations *f_op; 被定义在linux/include/linux/fs.h中,其中包含着与文件关联的操作,如: 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 *); 等。当打开一个文件时,内核就创建一个与该文件相关联的struct file结构,其中的*f_op就指向的是 具体对该文件进行操作的函数。例如用户调用系统调用read来读取该文件的内容时,那么系统调用read最终会陷入内核调用sys_read函数,而sys_read最终会调用于该文件关联的struct file结构中的f_op->read函数对文件内容进行读取。四、
atomic_t f_count; atomic_t被定义为: typedef struct { volatile int counter; } atomic_t; volatile修饰字段告诉gcc不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。 本质是int类型,之所以这样写是让编译器对基于该类型变量的操作进行严格的类型检查。此处f_count的作用是记录对文件对象的引用计数,也即当前有多少个进程在使用该文件。五、
unsigned int f_flags; 当打开文件时指定的标志,对应系统调用open的int flags参数。驱动程序为了支持非阻塞型操作需要检查这个标志。六、
mode_t f_mode; 对文件的读写模式,对应系统调用open的mod_t mode参数。如果驱动程序需要这个值,可以直接读取这个字段。 mod_t被定义为: typedef unsigned int __kernel_mode_t; typedef __kernel_mode_t mode_t;七、
loff_t f_pos; 当前的文件指针位置,即文件的读写位置。 loff_t被定义为: typedef long long __kernel_loff_t; typedef __kernel_loff_t loff_t;八、
struct fown_struct f_owner; struct fown_struct在linux/include/linux/fs.h被定义,原型为: struct fown_struct { rwlock_t lock; /* protects pid, uid, euid fields */ struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ uid_t uid, euid; /* uid/euid of process setting the owner */ int signum; /* posix.1b rt signal to be delivered on IO */ }; 该结构的作用是通过信号进行I/O时间通知的数据。九、
unsigned int f_uid, f_gid; 标识文件的所有者id,所有者所在组的id.十、
struct file_ra_state f_ra; struct file_ra_state结构被定义在/linux/include/linux/fs.h中,原型为: struct file_ra_state { pgoff_t start; /* where readahead started */ unsigned long size; /* # of readahead pages */ unsigned long async_size; /* do asynchronous readahead when there are only # of pages ahead */ unsigned long ra_pages; /* Maximum readahead window */ unsigned long mmap_hit; /* Cache hit stat for mmap accesses */ unsigned long mmap_miss; /* Cache miss stat for mmap accesses */ unsigned long prev_index; /* Cache last read() position */ unsigned int prev_offset; /* Offset where last read() ended in a page */ }; 文件预读状态,文件预读算法使用的主要数据结构,当打开一个文件时,f_ra中出了perv_page(默认为-1)和ra_apges(对该文件允许的最大预读量)这两个字段外,其他的所有西端都置为0。十一、
unsigned long f_version; 记录文件的版本号,每次使用后都自动递增。十二、
#ifdef CONFIG_SECURITY void *f_security; #endif 此处我的理解是如果在编译内核时配置了安全措施,那么struct file结构中就会有void *f_security数据项,用来描述安全措施或者是记录与安全有关的信息。十三、
void *private_data; 系统在调用驱动程序的open方法前将这个指针置为NULL。驱动程序可以将这个字段用于任意目的,也可以忽略这个字段。驱动程序可以用这个字段指向已分配的数据,但是一定要在内核释放file结构前的release方法中清除它。十四、
#ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; spinlock_t f_ep_lock; #endif /* #ifdef CONFIG_EPOLL */ 被用在fs/eventpoll.c来链接所有钩到这个文件上。其中f_ep_links是文件的事件轮询等待者链表的头,f_ep_lock是保护f_ep_links链表的自旋锁。 十五、struct address_space *f_mapping; struct address_space被定义在/linux/include/linux/fs.h中,此处是指向文件地址空间的指针。在驱动开发中,文件读/写模式mode、标志f_flags都是设备驱动关心的内容,而私有数据指针private_data在折本驱动中被广泛使用,大多被指向设备驱动自定义用于描述设备的结构体。 驱动程序中常用如下类似的代码来检测用户打开文件的读写方式:
if (file->f_mode & FMODE_WRITE) //用户要求可写 { } if (file->f_mode & FMODE_READ) //用户要求可读 { } 下面的代码可用于判断以阻塞还是非阻塞方式打开设备文件: if (file->f_flags & O_NONBLOCK) //非阻塞 pr_debug(“open:non-blockingn”); else //阻塞 pr_debug(“open:blockingn”);2、inode结构体
struct file结构体定义在/linux/include/linux/fs.h(Linux 2.6.26内核)中
struct inode {
struct hlist_node i_hash;
struct list_head i_list; /* backing dev IO list */
struct list_head i_sb_list;
struct list_head i_dentry;
unsigned long i_ino;
atomic_t i_count;
unsigned int i_nlink;
uid_t i_uid;
gid_t i_gid;
dev_t i_rdev;
unsigned int i_blkbits;
u64 i_version;
loff_t i_size;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
blkcnt_t i_blocks;
unsigned short i_bytes;
umode_t i_mode;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
struct mutex i_mutex;
struct rw_semaphore i_alloc_sem;
const struct inode_operations *i_op;
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
struct file_lock *i_flock;
struct address_space *i_mapping;
struct address_space i_data;
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];
#endif
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
};
__u32 i_generation;
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
struct hlist_head i_fsnotify_marks;
#endif
unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned int i_flags;
atomic_t i_writecount;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
void *i_private; /* fs or device private pointer */
};
VFS inode包含文件访问权限,属主、组、大小……等一系列的信息。他是Linux管理文件的最基本单位,也是文件系统连接任何目录和文件的桥梁