• Linux 应用层open调用驱动层open过程


    内核版本: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:以上的缩进都表示包含于上一个函数中之内。

  • 相关阅读:
    C语言I博客作业09
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    C语言I博客作业04
    C语言II博客作业03
    C语言II博客作业02
    C语言II博客作业01
    C语言I学期总结
  • 原文地址:https://www.cnblogs.com/lialong1st/p/7756674.html
Copyright © 2020-2023  润新知