linux 驱动倾向于分层设计, 所以每个具体的设备都可以找到它归属的类型, 从而可以套到它相应的架构里面去, 只需要实现它最底层的那部分。 但是也有部分字符设备, 确实不知道它属于哪种类型, 一般推荐采用 miscdevice 的框架结构。
misc意思是混合的杂项的, 所以 misc 设备驱动也叫做杂项设备驱动, 当板子上的某个设备没有办法分类时, 可以用 misc 设备驱动。它通常嵌套在 platform 总线驱动中, 配合总线驱动达到更复杂, 多功能的效果。 杂项设备是字符设备的一种, 杂项设备可以自动生成设备节点。
所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。主设设备号相同就可以节省内核的资源, 在内核中大概可以找到 200 多处使用 miscdevice 框架结构的驱动。
MISC 设备会自动创建 cdev,不需要手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写。需要向 Linux 注册一个 miscdevice 设备, miscdevice是一个结构体,定义在文件 include/linux/miscdevice.h 中
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 设备(miscdevice 类型)后,需要设置 minor、 name 和 fops 三个成员变量。 minor 表示子设备号, MISC 设备的主设备号为 10,需要用户指定子设备号, Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号定义在include/linux/miscdevice.h 文件中。
name是此 MISC 设备名字,当此设备注册成功以后就会在/dev 目录下生成一个名为 name的设备文件。 fops是字符设备的操作集合, MISC设备驱动是需要使用用户提供的 fops操作集合。
当创建好 miscdevice 结构体后, 使用 misc_register 函数向系统中注册一个 misc 设备
int misc_register(struct miscdevice * misc)
misc:要注册的 MISC 设备
返回值: 负数,失败; 0,成功
在以前的字符设备驱动中会使用如下几个函数完成设备创建过程:
alloc_chrdev_region(); /* 申请设备号 */
cdev_init(); /* 初始化 cdev */
cdev_add(); /* 添加 cdev */
class_create(); /* 创建类 */
device_create(); /* 创建设备 */
所以,杂项设备驱动简化了很多字符设备驱动的步骤。
在设备驱动的卸载函数中, 使用 misc_deregister 函数来注销掉 misc 设备
int misc_deregister(struct miscdevice *misc)
misc:要注销的 MISC 设备
返回值: 负数,失败; 0,成功
以前注销设备驱动的时,需要调用一堆的函数去删除此前创建的 cdev、设备等等内容
cdev_del(); /* 删除 cdev */
unregister_chrdev_region(); /* 注销设备号 */
device_destroy(); /* 删除设备 */
class_destroy(); /* 删除类 */
注册杂项设备四个步骤:
①填充 miscdevice 结构体
②填充 file_operations 结构体③填充platform_driver结构体(使用platform)
④注册杂项设备并生生成设备节点