前言
在前边三节的基础上,粗略的分析一下,上层应用调用到驱动程序的过程,分为下面几个方面:
1.字符设备驱动本身
2.mknod的作用
3.open的调用过程
正文
字符设备驱动本身
start_kernel(kernel-3.10\init\main.c)//启动内核
vfs_caches_init(totalram_pages);
---------
vfs_caches_init (kernel-3.10\fs\dcache.c)
inode_init(); //节点初始化
chrdev_init();//字符设备 (kernel-3.10\fs\Char_dev.c)
//得到一个kobj_map 类型的cdev_map,用户字符设备的设备号
cdev_map = kobj_map_init(base_probe, &chrdevs_lock);
//涉及到cdev_map的一些操作函数:cdev_add cdev_del chrdev_open。
mknod
mknod 命令简历一个目录项和一个特殊文件的对应索引点。
mknod的系统调用过程,看参考文献。
在这个过程中,会调用 init_special_inode 这个函数,
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) (kernel-3.10\fs\Inode.c)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) {
inode->i_fop = &def_chr_fops; // 这个给inode的i_fop 赋值为 def_chr_fops,
inode->i_rdev = rdev; //inode->i_rdev 赋值为设备号
}
def_chr_fops的内容
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
const struct file_operations def_chr_fops = {
.open = chrdev_open,
.llseek = noop_llseek,
};
可以看出def_chr_fops是一个 file_operations类型的变量,其有个成员open,被赋值为 chrdev_open
/*
* Called every time a character special file is opened
*/
static int chrdev_open(struct inode *inode, struct file *filp)
{
struct cdev *p;
struct cdev *new = NULL;
int ret = 0;
spin_lock(&cdev_lock);
p = inode->i_cdev; //节点中得到字符设备
if (!p) {
struct kobject *kobj;
int idx;
spin_unlock(&cdev_lock);
kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); // 当调用这个的opend的时候,会根据设备号在cdev_map中查找设备
if (!kobj)
return -ENXIO;
new = container_of(kobj, struct cdev, kobj);
spin_lock(&cdev_lock);
/* Check i_cdev again in case somebody beat us to it while
we dropped the lock. */
p = inode->i_cdev;
if (!p) {
inode->i_cdev = p = new;
list_add(&inode->i_devices, &p->list);
new = NULL;
} else if (!cdev_get(p))
ret = -ENXIO;
} else if (!cdev_get(p))
ret = -ENXIO;
spin_unlock(&cdev_lock);
cdev_put(new);
if (ret)
return ret;
ret = -ENXIO;
filp->f_op = fops_get(p->ops);
if (!filp->f_op)
goto out_cdev_put;
if (filp->f_op->open) {
ret = filp->f_op->open(inode, filp); //调用字符设备的open函数
if (ret)
goto out_cdev_put;
}
return 0;
out_cdev_put:
cdev_put(p);
return ret;
}
open的调用过程
应用程序调用open,会 调用系统的sys_open函数
最终会调用到
struct file *dentry_open(const struct path *path, int flags,const struct cred *cred)(kernel-3.10\fs\Open.c)
f->f_flags = flags;
f->f_path = *path;
rror = do_dentry_open(f, NULL, cred);
struct inode *inode;
inode = f->f_inode = f->f_path.dentry->d_inode;
f->f_op = fops_get(inode->i_fop);//获得设备节点对应的fops结构体。会是def_chr_fops 这个结构体
if (!open && f->f_op)
open = f->f_op->open; // 会调用def_chr_fops结构体的open,即chrdev_open。调用过程,看 mknod 部分的介绍
总结
使用mknod 创建节点,在创建过程中的def_chr_fops的open,会起一个 中转的作用。 在调用open打开设备的时候,
会调用到设备本身的open函数,实现打开设备的功能。
目前的代码,我们是手动的调用mknod创建节点。除了手动创建设备节点,linux还提供了 class_create(),device_create自动创建设备文件结点
参考文献
字符设备文件的打开
Linux系统调用(syscall)原理
Linux内核源代码情景分析-系统调用mknod
class_create(),device_create自动创建设备文件结点
作者:u013377887 发表于2017/5/18 20:02:52 原文链接
阅读:263 评论:0 查看评论