misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 platform 总线驱动中,实现复杂的驱动。
所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号,MISC 设备驱动就用于解决此问题。MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用MISC 设备驱动可以简化字符设备驱动的编写。我们需要向 Linux 注册一个 miscdevice 设备,miscdevice是一个结构体,定义在文件 include/linux/miscdevice.h 中,内容如下:
57 struct miscdevice {
58 int minor; /* 子设备号 */
59 const char *name; /* 设备名字 */
60 const struct file_operations *fops; /* 设备操作集 */
61 struct list_head list;
62 struct device *parent;
63 struct device *this_device;
64 const struct attribute_group **groups;
65 const char *nodename;
66 umode_t mode;
67 };
定义一个 MISC 设备(miscdevice 类型)以后我们需要设置 minor、name 和 fops 这三个成员变量。
13 #define PSMOUSE_MINOR 1
14 #define MS_BUSMOUSE_MINOR 2 /* unused */
15 #define ATIXL_BUSMOUSE_MINOR 3 /* unused */
16 /*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */
17 #define ATARIMOUSE_MINOR 5 /* unused */
18 #define SUN_MOUSE_MINOR 6 /* unused */
......
52 #define MISC_DYNAMIC_MINOR 255
我们在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口。
name 就是此 MISC 设备名字,当此设备注册成功以后就会在/dev 目录下生成一个名为 name的设备文件。
fops 就是字符设备的操作集合,MISC 设备驱动最终是需要使用用户提供的 fops操作集合。
int misc_register(struct miscdevice * misc)
函数参数和返回值含义如下:
misc:要注册的 MISC 设备。
返回值:负数,失败;0,成功。
以前我们需要自己调用一堆的函数去创建设备,现在我们可以直接使用 misc_register 一个函数来完成这些步骤。
int misc_deregister(struct miscdevice *misc)
函数参数和返回值含义如下:
misc:要注销的 MISC 设备。
返回值:负数,失败;0,成功。
29 #define MISCBEEP_NAME "miscbeep" /* 名字 */
30 #define MISCBEEP_MINOR 144 /* 子设备号 */
31 #define BEEPOFF 0 /* 关蜂鸣器 */
32 #define BEEPON 1 /* 开蜂鸣器 */
33
34 /* miscbeep 设备结构体 */
35 struct miscbeep_dev{
36 dev_t devid; /* 设备号 */
37 struct cdev cdev; /* cdev */
38 struct class *class; /* 类 */
39 struct device *device; /* 设备 */
40 struct device_node *nd; /* 设备节点 */
41 int beep_gpio; /* beep 所使用的 GPIO 编号 */
42 };
43
44 struct miscbeep_dev miscbeep; /* beep 设备 */
53 static int miscbeep_open(struct inode *inode, struct file *filp)
54 {
55 ..............
56 return 0;
57 }
static ssize_t miscbeep_write(struct file *filp,
const char __user *buf,
size_t cnt, loff_t *offt)
{
....................
return 0;
}
89 /* 设备操作函数 */
90 static struct file_operations miscbeep_fops = {
91 .owner = THIS_MODULE,
92 .open = miscbeep_open,
93 .write = miscbeep_write,
94 };
95
96 /* MISC 设备结构体 */
97 static struct miscdevice beep_miscdev = {
98 .minor = MISCBEEP_MINOR,
99 .name = MISCBEEP_NAME,
100 .fops = &miscbeep_fops,
101 };
109 static int miscbeep_probe(struct platform_device *dev)
110 {
/*
获取设备节点
获取节点中的某个属性
等等一些操作
*/
................
135 /* 一般情况下会注册对应的字符设备,但是这里我们使用 MISC 设备
136 * 所以我们不需要自己注册字符设备驱动,只需要注册 misc 设备驱动即可
137 */
138 ret = misc_register(&beep_miscdev);
139 if(ret < 0){
140 printk("misc device register failed!\r\n");
141 return -EFAULT;
142 }
143
144 return 0;
145 }
148 * @description : remove 函数,移除 platform 驱动的时候此函数会执行
149 * @param - dev : platform 设备
150 * @return : 0,成功;其他负值,失败
151 */
152 static int miscbeep_remove(struct platform_device *dev)
153 {
...................
156
157 /* 注销 misc 设备驱动 */
158 misc_deregister(&beep_miscdev);
159 return 0;
160 }
162 /* 匹配列表 */
163 static const struct of_device_id beep_of_match[] = {
164 { .compatible = "atkalpha-beep" },
165 { /* Sentinel */ }
166 };
167
168 /* platform 驱动结构体 */
169 static struct platform_driver beep_driver = {
170 .driver = {
171 .name = "imx6ul-beep", /* 驱动名字 */
172 .of_match_table = beep_of_match, /* 设备树匹配表 */
173 },
174 .probe = miscbeep_probe,
175 .remove = miscbeep_remove,
176 };
178 /*
179 * @description : 驱动入口函数
180 * @param : 无
181 * @return : 无
182 */
183 static int __init miscbeep_init(void)
184 {
185 return platform_driver_register(&beep_driver);
186 }
187
188 /*
189 * @description : 驱动出口函数
190 * @param : 无
191 * @return : 无
192 */
193 static void __exit miscbeep_exit(void)
194 {
195 platform_driver_unregister(&beep_driver);
196 }
197
198 module_init(miscbeep_init);
199 module_exit(miscbeep_exit);
200 MODULE_LICENSE("GPL");
201 MODULE_AUTHOR("alex");
第 29~94 行,标准的字符设备驱动。
第 97~101 行,MISC 设备 beep_miscdev,第 98 行设置子设备号为 144,第 99 行设置设备名字为“miscbeep”,这样当系统启动以后就会在/dev/目录下存在一个为“miscbeep”的设备文件。
第 100 行,设置 MISC 设备的操作函数集合,为 file_operations 类型。
第 109~145 行,platform 框架的 probe 函数,当驱动与设备匹配以后此函数就会执行,最后在 138 行通过 misc_register 函数向 Linux 内核注册MISC 设备,也就是前面定义的 beep_miscdev。
第 152~160 行,platform 框架的 remove 函数,在此函数中调用 misc_deregister 函数来注销MISC 设备。
第 163~196,标准的 platform 驱动。