一、杂项设备驱动简介
在 Linux 中,把无法归类的五花八门的设备定义成杂项设备。相较于字符设备,杂项设备有以下两个优点:
(1)节省主设备号:杂项设备的主设备号固定为 10,而字符设备不管是动态分配还是静态分配设备号,都会消耗一个主设备号,进而造成了主设备号浪费。当系统中注册了多个 misc 设备驱动时,只需使用子设备号进行区分即可。
(2)使用简单:当使用普通的字符设备驱动时,如果开发人员需要导出操作接口给用户空间,就需要注册对应的字符驱动,并创建字符设备 class 从而自动在/dev 下生成设备节点,而 misc驱动只需要将基本信息通过结构体传递给相应处理函数即可。
二、总体框架图
三、杂项设备相关函数
杂项设备miscdevice 结 构 体
struct miscdevice {int minor; /* 子设备号 需要用户填写*/const char *name; /* 设备名 需要用户填写*/const struct file_operations *fops; /* 设备操作集 需要用户填写*/struct list_head list;struct device *parent;struct device *this_device;const struct attribute_group **groups;const char *nodename;umode_t mode;
};
定义一个 misc 设备,一般只需要填充 minor、name、fops 这三个成员变量。
- minor 指次设备号,通常情况下将该参数设置为MISC_DYNAMIC_MINOR,表示自动分配子设备号。
- name 表示 misc 设备的名字。misc 设备驱动注册成功之后,会在 dev 目录下生成名为 name的设备节点。
- fops 指向了 file_operations 的结构体,表示字符设备的操作集合。
杂项设备的注册
函数原型:int misc_register(struct miscdevice *misc);
函数作用:基于misc_class构造一个设备,将miscdevice结构挂载到misc_list列表上,并初始化与linux设备模型相关的结构。进而起到杂项设备注册的作用。
参数含义:misc: 杂项设备的结构体指针
函数返回值:申请成功返回 0,申请失败返回负数
杂项设备的卸载
函数原型:int misc_deregister(struct miscdevice *misc);
函数作用:从 mist_list 中删除 miscdevice,进而起到杂项设备卸载的作用。
参数含义:misc: 杂项设备的结构体指针
函数返回值:卸载成功返回 0,申请失败返回负数
四、实例代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>static int cdev_test_open(struct inode * inode, struct file * file){printk("This is cdev_test_open!\n");return 0;
}static ssize_t cdev_test_read(struct file * file, char __user *buf, size_t size, loff_t *off){printk("This is cdev_test_read!\n");return 0;
}static ssize_t cdev_test_write(struct file * file, const char __user * buf, size_t size, loff_t *off){printk("This is cdev_test_write!\n");return 0;
}static int cdev_test_release(struct inode * inode, struct file * file){printk("This is cdev_test_release!\n");return 0;
}struct file_operations cdev_test_ops={.owner = THIS_MODULE, // 文件操作结构体.open = cdev_test_open,.read = cdev_test_read,.write = cdev_test_write,.release = cdev_test_release,
};struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "test",.fops = &cdev_test_ops
};static int chardev_init(void){int ret; //返回值判断ret = misc_register(&misc_dev); //注册杂项设备if (ret < 0){printk("misc_register failed\r\n");}printk("misc_register ok\r\n");return 0;
}static void chardev_exit(void){misc_deregister(&misc_dev); //卸载杂项设备printk("chardev_exit!\n");
}module_init(chardev_init);
module_exit(chardev_exit);MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("ZSY");
MODULE_VERSION("V1.0");