linux驱动开发之字符设备框架 -调用过程分析

前言

在前边三节的基础上,粗略的分析一下,上层应用调用到驱动程序的过程,分为下面几个方面:
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自动创建设备文件结点

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值