linux驱动开发学习笔记二十二:MISC驱动

一、简介

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 这三个成员变量。

  • minor 表示子设备号,MISC 设备的主设备号为 10,这个是固定的,需要用户指定子设备号,Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号定义在include/linux/miscdevice.h 文件中,如下所示:
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操作集合。

二、miscdevice的注册和注销
  • 当设置好 miscdevice 以后就需要使用 misc_register 函数向系统中注册一个 MISC 设备,此函数原型如下:
int misc_register(struct miscdevice * misc)

函数参数和返回值含义如下:
misc:要注册的 MISC 设备。
返回值:负数,失败;0,成功。

以前我们需要自己调用一堆的函数去创建设备,现在我们可以直接使用 misc_register 一个函数来完成这些步骤。

  • 当我们卸载设备驱动模块的时候需要调用 misc_deregister 函数来注销掉 MISC 设备,函数原型如下:
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 驱动。

你可能感兴趣的:(#,Linux驱动开发学习笔记,linux)