前言:
Misc 的意思是混合、杂项的,因此misc设备也叫做杂项设备(杂散设备)。Linux系统中大多数设备都有自己归属的类型,例如按键、触摸屏属于输入设备,Linux系统有input子系统框架专门处理这类设备,同样的对于LED设备,有LED驱动框架专门处理LED设备;但是对于adc、蜂鸣器等设备,无法明确其属于什么类型,所以一般把这类设备归属为 misc 设备,对misc设备一般推荐使用misc驱动框架编写驱动程序。
MISC 设备驱动简介
所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号,MISC 设备驱动就用于解决此问题。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 文件中,如下所示:
#define PSMOUSE_MINOR 1 #define MS_BUSMOUSE_MINOR 2 /* unused */ #define ATIXL_BUSMOUSE_MINOR 3 /* unused */ /*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */ #define ATARIMOUSE_MINOR 5 /* unused */ #define SUN_MOUSE_MINOR 6 /* unused */ #define APOLLO_MOUSE_MINOR 7 /* unused */ #define PC110PAD_MINOR 9 /* unused */ ...... #define MISC_DYNAMIC_MINOR 255
我们在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口。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_register 一个函数来完成上述的这些步骤。当我们卸载设备驱动模块的时候需要调用 misc_deregister 函数来注销掉 MISC 设备,函数原型如下:
int misc_deregister(struct miscdevice *misc)
函数参数和返回值含义如下:
misc:要注销的 MISC 设备。
返回值:负数,失败;0,成功。
以前注销设备驱动的时候,我们需要调用一堆的函数去删除此前创建的 cdev、设备等等内容,如下所示:
cdev_del(); /* 删除 cdev */ unregister_chrdev_region(); /* 注销设备号 */ device_destroy(); /* 删除设备 */ class_destroy(); /* 删除类 */
现在我们只需要一个 misc_deregister 函数即可完成
整个流程示例如下
一.修改设备树
test2_0: test2@43c00000 { compatible = "xlnx,test2-1.0"; reg = <0x43c00000 0x10000>; interrupt-parent = <&intc>; interrupts = <0 53 4>; };
二.驱动层修改
和普通的驱动相比增加了misc部分
#define DRIVER_NAME "1553drv" /* Simple example of how to receive command line parameters to your module. Delete if you don't need them */ // unsigned myint = 0xdeadbeef; // char *mystr = "default"; // module_param(myint, int, S_IRUGO); // module_param(mystr, charp, S_IRUGO); struct RT_local { int irq; unsigned long mem_start; unsigned long mem_end; void __iomem *base_addr; }; static struct file_operations RT_fops = { .read=RT_read, // .unlocked_ioctl=RT_ioctl, .fasync = RT_fasync_ops, .release = RT_release, }; static struct miscdevice RT_misc = { .minor = MISC_DYNAMIC_MINOR, .name = DRIVER_NAME, .fops = &RT_fops, };
RT_probe中增加
misc_register(&RT_misc);
三.应用层demo
正常编写就可以了