內核版本: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:以上的縮進都表示包含於上一個函數中之內。