2007-11-28 by heyl
/* * linux/fs/devices.c * * (C) 1993 Matthias Urlichs -- collected common code and tables. * * Copyright (C) 1991, 1992 Linus Torvalds * * Added kerneld support: Jacques Gelinas and Bjorn Ekwall * (changed to kmod) */ 看到这儿注释,不难理解这里为啥不搭边...
这里是char dev的天下?想起了block_dev 的相关结构,倒是和这个有点类似. struct device_struct { const char * name; struct file_operations * fops; }; 和blkdev是不同的,存储的是name和fops. static struct { const char *name; struct block_device_operations *bdops; } blkdevs[MAX_BLKDEV];
static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED; static struct device_struct chrdevs[MAX_CHRDEV];
int get_device_list(char * page) : 获取char dev 和block dev的列表,极尽简单.
static struct file_operations * get_chrfops(unsigned int major, unsigned int minor) : 从char获取file ops, char dev 直接面对file,真是素面朝天的做法,比起block dev的七拐八拐直接多了.这个函数无非就是如果是tty照顾到了kmod. 参考major.h,里边是 所有已知设备的major number.
chardev的注册函数,真是直白,我们需要这样子的代码. int register_chrdev(unsigned int major, const char * name, struct file_operations *fops) int unregister_chrdev(unsigned int major, const char * name)
/* * Called every time a character special file is opened */ int chrdev_open(struct inode * inode, struct file * filp) { int ret = -ENODEV;
filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if (filp->f_op) { ret = 0; if (filp->f_op->open != NULL) { lock_kernel(); ret = filp->f_op->open(inode,filp); unlock_kernel(); } } return ret; }
/* * 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... */ static struct file_operations def_chr_fops = { open: chrdev_open, };
def注册到inode的i_fops, 通denty_open这个file ops转移到filep->f_ops. struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f; ..... f->f_op = fops_get(inode->i_fop); }
接下来就是一个很知名的函数了: void init_special_inode(struct inode *inode, umode_t mode, int rdev) { inode->i_mode = mode; if (S_ISCHR(mode)) { inode->i_fop = &def_chr_fops; inode->i_rdev = to_kdev_t(rdev); } else if (S_ISBLK(mode)) { /*block dev 有两个dev和之对应*/ inode->i_fop = &def_blk_fops; inode->i_rdev = to_kdev_t(rdev); /*kdev,一个int, 系统中所有dev的统一handler*/ inode->i_bdev = bdget(rdev); /* block_device pointer */ } else if (S_ISFIFO(mode)) inode->i_fop = &def_fifo_fops; else if (S_ISSOCK(mode)) inode->i_fop = &bad_sock_fops; /*sock使用另外的soket标准接口和文件系统相区别*/ else printk(KERN_DEBUG "init_special_inode: bogus imode (%o)\n", mode); }
搜索init_special_inode的调用者,我们知道不是所有的文件系统都支持设备文件的, 比如vfat就免谈了.
剩下的函数看看名字好了. const char * kdevname(kdev_t dev) const char * cdevname(kdev_t dev) static int sock_no_open(struct inode *irrelevant, struct file *dontcare) static struct file_operations bad_sock_fops = { open: sock_no_open };
不想我们从这里得窥char device的一角, chardev 直接实现一个file ops给文件系统,倒是省心了不少. 比block dev干净许多啊.
|