linux设备文件实现

  Linux将一些硬件设备抽象成文件,使得程序员可以用文件系统的接口对设备进行访问,这是unix类系统的一大特色。那么这个抽象是怎么实现的呢?这首先要归功于VFS,它将文件的概念抽象提升成一种可以进行输入输出操作的对象。这样它就不仅仅能表示磁盘上的普通文件,也可以表示某种设备。设备文件主要有字符设备文件和块设备文件两种。网络设备由于其自身的特殊性,不能用设备文件来表示。那么具体VFS是怎么将某个设备文件和某个设备联系起来的呢?这要分两个部分进行说明,一是设备文件的创建,一是设备文件的访问。下面分别讨论。

  设备文件的创建和普通磁盘文件创建的方法不同,touch命令并不能创建设备文件。设备文件要用mknod命令来创建。该命令格式为:mknod [OPTION]... NAME TYPE [MAJOR MINOR],一般来说需要指定NAME(设备文件的名称),TYPE(设备文件的类型,c为字符设备,b为块设备),MAJOR MINOR就是设备的主次设备号了。这个操作在VFS中会创建两个重要的对象,一是在创建设备文件的目录中会增加一个dentry,其中会记录该设备文件的名称和指向设备文件inode的指针。这个对象是用于根据设备名称定位到设备文件的inode。另外一个就是创建了一个inode,会将设备的主次设备号存放在inode->irdev中,另外还有一个重要的设置就是inode->i_fop,对字符设备会设置成&def_chr_fops,块设备设置成&def_blk_fops。这个设置对设备文件的访问非常重要,在下面分析。

  正如普通文件的访问一样,设备文件的访问也要先执行open,然后才可以进行其它read,write等操作。open操作会在VFS中创建一个重要对象file,它代表一个文件打开实例。一个文件可以被打开多次,也就可以有多个file对象与同一个inode关联。对于文件访问file->f_op成员是关键。它是file_operations类型,其中是对文件的各种操作集合,比如open,read,write,ioctl等。每个支持设备文件的设备驱动都要实现一个file_operations的对象。open函数负责将设备驱动的file_operations对象设置到file->f_op上。它首先通过调用dentry_open()函数将file->f_op设置成上面讨论的inode->i_fop,然后立即执行file->f_op->open。对于字符设备也就是执行&def_chr_fops->open,对于块设备就是&def_blk_fops->open。这种缺省的操作不可能满足各种设备的不同需求。因此它的主要作用是根据inode->irdev(存放设备的主次设备号)找到具体的设备驱动,进而用设备驱动实现的file_operations对象设置file->f_op对象,然后执行设备驱动提供的open函数。下面看一下&def_chr_fops->open的代码吧,如下:

369 static int chrdev_open(struct inode *inode, struct file *filp)
370 {
371     struct cdev *p;
372     struct cdev *new = NULL;
373     int ret = 0;
374
375     spin_lock(&cdev_lock);
376     p = inode->i_cdev; /*mknod未填充该成员,所以一定为空*/
377     if (!p) {
378         struct kobject *kobj;
379         int idx;
380         spin_unlock(&cdev_lock);

            /*根据设备号查询到具体的字符设备驱动*/

381         kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
382         if (!kobj)
383             return -ENXIO;
384         new = container_of(kobj, struct cdev, kobj);
385         spin_lock(&cdev_lock);
386         /* Check i_cdev again in case somebody beat us to it while
387            we dropped the lock. */
388         p = inode->i_cdev;
389         if (!p) {
390             inode->i_cdev = p = new;
391             list_add(&inode->i_devices, &p->list);
392             new = NULL;
393         } else if (!cdev_get(p))
394             ret = -ENXIO;
395     } else if (!cdev_get(p))
396         ret = -ENXIO;
397     spin_unlock(&cdev_lock);
398     cdev_put(new);
399     if (ret)
400         return ret;
401
402     ret = -ENXIO;

        /*将具体驱动实现的file_operations传递到file->f_op中*/
403     filp->f_op = fops_get(p->ops);
404     if (!filp->f_op)
405         goto out_cdev_put;
406

        /*执行具体设备驱动的open函数*/
407     if (filp->f_op->open) {
408         ret = filp->f_op->open(inode,filp);
409         if (ret)
410             goto out_cdev_put;
411     }
412
413     return 0;
414
415  out_cdev_put:
416     cdev_put(p);
417     return ret;
418 }

执行完open后,设备驱动实现的file_operations对象就挂接到file->f_op上了,VFS和具体的设备驱动就关联上了,以后对设备文件的各种访问直接通过file->f_op传递到具体的设备驱动上。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值