一、杂项设备驱动简介
在 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");