一. misc结构体
struct miscdevice { int minor; //次设备号 const char *name; //设备名 const struct file_operations *fops; //操作函数集 struct list_head list; //链表头 struct device *parent; //父设备设备文件 struct device *this_device; //设备文件 const char *nodename; // mode_t mode; // };
二. 设备号
misc设备的主设备号为10
#define MISC_MAJOR 10
三. misc设备系统的初始化 misc_init
static int __init misc_init(void) { int err; #ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_class = class_create(THIS_MODULE, "misc"); //创建目录"/sys/class/misc" err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) goto fail_remove; err = -EIO; if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) //注册为字符设备,捆绑操作函数集 goto fail_printk; misc_class->devnode = misc_devnode; return 0; fail_printk: printk("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: remove_proc_entry("misc", NULL); return err; }
再看一下register_chrdev
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops) { return __register_chrdev(major, 0, 256, name, fops); }
这里直接根据主设备号创建256个设备,256=2^8,所以它是把所有的杂项设备都给注册成字符设备了
misc_fops作为这所有misc设备捆绑的操作函数集
static const struct file_operations misc_fops = { .owner = THIS_MODULE, .open = misc_open, .llseek = noop_llseek, };
在misc_open中,也就是我们打开misc设备的时候,misc_open方法会为我们捆绑自定义的操作函数集
static int misc_open(struct inode * inode, struct file * file) { int minor = iminor(inode); //根据设备节点获取次设备号 struct miscdevice *c; int err = -ENODEV; const struct file_operations *old_fops, *new_fops = NULL; mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { //遍历misc_list查看次设备是否注册(misc_list元素在设备注册时添加) if (c->minor == minor) { new_fops = fops_get(c->fops); //获取自定义的操作函数集 break; } } if (!new_fops) { //若找不到则再找一次,还不行error mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { new_fops = fops_get(c->fops); break; } } if (!new_fops) goto fail; } err = 0; old_fops = file->f_op; //获取指向旧的设备操作函数集(misc_fops)指针 file->f_op = new_fops; //文件操作函数集指针指向新的操作函数集 if (file->f_op->open) { //若存在open方法 file->private_data = c; err=file->f_op->open(inode,file); //则调用其自定义的open方法 if (err) { fops_put(file->f_op); file->f_op = fops_get(old_fops); } } fops_put(old_fops); //释放旧的函数集指针 fail: mutex_unlock(&misc_mtx); return err; }
四. misc设备注册 misc_register
int misc_register(struct miscdevice * misc) { struct miscdevice *c; dev_t dev; int err = 0; INIT_LIST_HEAD(&misc->list); //初始化链表头 mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { //遍历misc_list if (c->minor == misc->minor) { //查看设备号是否被占用 mutex_unlock(&misc_mtx); return -EBUSY; } } if (misc->minor == MISC_DYNAMIC_MINOR) { //判断是否指定要动态分配次设备号 int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); //查找可用次设备号 if (i >= DYNAMIC_MINORS) { mutex_unlock(&misc_mtx); return -EBUSY; } misc->minor = DYNAMIC_MINORS - i - 1; //分配次设备号 set_bit(i, misc_minors); //设置占用标志位 } dev = MKDEV(MISC_MAJOR, misc->minor); //根据主次设备号获取设备号 misc->this_device = device_create(misc_class, misc->parent, dev,misc, "%s", misc->name); //添加设备文件"/dev/xxx" if (IS_ERR(misc->this_device)) { int i = DYNAMIC_MINORS - misc->minor - 1; if (i < DYNAMIC_MINORS && i >= 0) clear_bit(i, misc_minors); err = PTR_ERR(misc->this_device); goto out; } /* * Add it to the front, so that later devices can "override" * earlier defaults */ list_add(&misc->list, &misc_list); //将设备链表头添加到misc_list中 out: mutex_unlock(&misc_mtx); return err; }
五. misc设备注销 misc_deregister
int misc_deregister(struct miscdevice *misc) { int i = DYNAMIC_MINORS - misc->minor - 1; //通过次设备号计算出位标志 if (WARN_ON(list_empty(&misc->list))) return -EINVAL; mutex_lock(&misc_mtx); list_del(&misc->list); //从misc_list删除设备链表头 device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); //删除设备节点 if (i < DYNAMIC_MINORS && i >= 0) clear_bit(i, misc_minors); //清除位标志 mutex_unlock(&misc_mtx); return 0; }
六. misc简单实例
#include <linux/fs.h> #include <linux/module.h> #include <linux/miscdevice.h> static int test_open(struct inode * inode, struct file * filp) { return 0; } static const struct file_operations test_fops = { .owner = THIS_MODULE, .open = test_open, }; static struct miscdevice misc_dev={ .minor=MISC_DYNAMIC_MINOR, .name="misc_test", .fops=&test_fops }; static int __init test_init(void) { return misc_register(&misc_dev); } static void __exit test_exit(void) { misc_deregister(&misc_dev); } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL");
七. 查看misc信息的方法
加载模块后
lsmod |grep test test 829 0
ls -l /dev/misc_test crw-rw---- 1 root root 10, 54 2012-12-18 10:28 /dev/misc_test
ls -l /sys/class/misc/ |grep misc_test lrwxrwxrwx 1 root root 0 2012-12-18 10:33 misc_test -> ../../devices/virtual/misc/misc_test
cat /proc/misc |grep misc_test 54 misc_test