內核版本:3.0.8
open、close、read、write、ioctl等等都是類似。
==========================================================================================
驅動層:
struct file_operations fops =
{
.open = xxx_open,
.release = xxx_close,
.read = xxx_read,
.write = xxx_write,
...
};
struct cdev {
struct module *owner;
const struct file_operations *ops; //文件操作對象
struct list_head list;
dev_t dev; //設備號
...
};
// 申請設備號,創建文件操作結構體 struct file_operations fops
static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops);
// 創建字符設備對象結構體 struct cdev,將 fops 賦值給 cdev
struct cdev *cdev;
cdev->ops = fops;
// 將設備號賦值給 cdev, 將 cdev 注冊到鏈表cdev_map
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
p->dev = dev;
kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
// cdev 結構體中包含 file_operations 和 設備號 dev_t。
// 創建字符設備類
struct class *__class_create(struct module *owner, const char *name, struct lock_class_key *key);
// 在類中創建一個設備, /dev 目錄下會生成一個文件,名稱為 led
// 系統自動為此文件分配 inode 節點(linux系統是通過 inode 節點來查找文件),節點中包含此字符設備的設備號 dev_t
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata,"led");
// 每一個文件都有一個inode
struct inode {
umode_t i_mode;//就是權限
uid_t i_uid; //用戶
gid_t i_gid; //用戶組
dev_t i_rdev; //設備號
loff_t i_size; //大小
... ...
}
==========================================================================================
應用層:
// 打開驅動中創建的設備,open 會調用VFS層中的 sys_open();
int open("/dev/led", int flags, mode_t mode);
// 調用 sys_open() 的過程,詳見 http://blog.csdn.net/hxmhyp/article/details/22699669 ,感謝這位朋友細心講解
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode);
==========================================================================================
VFS層:
// open會調用內核中的 sys_open(),這個函數是經過變換得來的,參數與open完全吻合
// 參數1:函數名,
// 參數2:文件名類型
// 參數3:文件名
// 參數4:打開標志類型
// 參數5:打開文件標志
// 參數6:文件權限類型
// 參數7:文件權限
int sys_open(open, const char __user *, filename, int, flags, int, mode)
// 每個文件都對應一個 struct file 結構體,打開一個文件,系統都會將 struct file 添加到 struct fdtable 的數組中
struct fdtable {
unsigned int max_fds;
struct file __rcu **fd; /* current fd array */
fd_set *close_on_exec;
fd_set *open_fds;
struct rcu_head rcu;
struct fdtable *next;
};
// 返回的文件描述符就是此文件的 struct file 在數組中的下標,從3開始(stdin-0 stdout-1 stderr-2)
struct file {
struct path f_path; // 文件路徑
const struct file_operations *f_op; // 文件操作對象
unsigned int f_flags; //文件標志
fmode_t f_mode; // 文件權限
loff_t f_pos; // 文件當前偏移量
void *private_data; // 私有數據
... ...
}
// 通過 struct file 中的文件路徑 f_path 得到文件的 inode 節點
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
static inline void fsnotify_open(struct file *file)
struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
// 通過 inode 節點獲取文件設備號
// 遍歷 cdev 鏈表,獲取設備號,與此文件的設備號相同表示匹配成功
// 將匹配成功的 cdev 結構體中的 file_operations 賦值給此文件的 struct file,從而關聯到驅動層中的 xxx_open
==========================================================================================
// 應用層 ---> 驅動層 // open ---> xxx_open // close ---> xxx_open // read ---> xxx_open // write ---> xxx_open
ps:以上的縮進都表示包含於上一個函數中之內。
