您当前的位置: 首页 >  嵌入式

正点原子

暂无认证

  • 2浏览

    0关注

    382博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【正点原子Linux连载】第五十七章 Linux MISC驱动实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

正点原子 发布时间:2021-09-23 10:07:36 ,浏览量:2

1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子Linux感兴趣的同学可以加群讨论:935446741 4)关注正点原子公众号,获取最新资料更新 在这里插入图片描述 第五十七章 Linux MISC驱动实验

misc的意思是混合、杂项的,因此MISC驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用MISC驱动。MISC驱动其实就是最简单的字符设备驱动,通常嵌套在platform总线驱动中,实现复杂的驱动,本章我们就来学习一下MISC驱动的编写。

57.1 MISC设备驱动简介 所有的MISC设备驱动的主设备号都为10,不同的设备使用不同的从设备号。随着Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号,MISC设备驱动就用于解决此问题。MISC设备会自动创建cdev,不需要像我们以前那样手动创建,因此采用MISC设备驱动可以简化字符设备驱动的编写。我们需要向Linux注册一个miscdevice设备,miscdevice是一个结构体,定义在文件include/linux/miscdevice.h中,内容如下:

示例代码57.1.1 miscdevice结构体代码
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文件中,如下所示:
示例代码57.1.2 预定义的MISC设备子设备号
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以后就需要使用misc_register函数向系统中注册一个MISC设备,此函数原型如下: int misc_register(struct miscdevice * misc) 函数参数和返回值含义如下: misc:要注册的MISC设备。 返回值:负数,失败;0,成功。 以前我们需要自己调用一堆的函数去创建设备,比如在以前的字符设备驱动中我们会使用如下几个函数完成设备创建过程:

示例代码57.1.3 传统的创建设备过程
1 alloc_chrdev_region();    	/* 申请设备号 	*/
2 cdev_init();          		/* 初始化cdev  */
3 cdev_add();               	/* 添加cdev  	*/
4 class_create();           	/* 创建类 		*/
5 device_create();      		/* 创建设备 		*/
现在我们可以直接使用misc_register一个函数来完成示例代码57.1.3中的这些步骤。当我们卸载设备驱动模块的时候需要调用misc_deregister函数来注销掉MISC设备,函数原型如下:

int misc_deregister(struct miscdevice *misc) 函数参数和返回值含义如下: misc:要注销的MISC设备。 返回值:负数,失败;0,成功。 以前注销设备驱动的时候,我们需要调用一堆的函数去删除此前创建的cdev、设备等等内容,如下所示:

示例代码57.1.4 传统的删除设备的过程
1 cdev_del();						/*  删除cdev 	*/
2 unregister_chrdev_region(); 	/* 注销设备号 	*/
3 device_destroy();     			/* 删除设备 		*/
4 class_destroy();      			/* 删除类 		*/
现在我们只需要一个misc_deregister函数即可完成示例代码57.1.4中的这些工作。关于MISC设备驱动就讲解到这里,接下来我们就使用platform加MISC驱动框架来编写beep蜂鸣器驱动。

57.2 硬件原理图分析 本章实验我们只使用到IMX6U-ALPHA开发板上的BEEP蜂鸣器,因此实验硬件原理图参考14.3小节即可。 57.3 实验程序编写 本实验对应的例程路径为:开发板光盘-> 2、Linux驱动例程-> 17_misc。 本章实验我们采用platform加misc的方式编写beep驱动,这也是实际的Linux驱动中很常用的方法。采用platform来实现总线、设备和驱动,misc主要负责完成字符设备的创建。 57.3.1 修改设备树 本章实验我们需要用到蜂鸣器,因此需要在imx6ull-alientek-emmc.dts文件中创建蜂鸣器设备节点,这里我们直接使用46.3.1小节创建的beep这个设备节点即可。 57.3.2 beep驱动程序编写 新建名为“19_miscbeep”的文件夹,然后在19_miscbeep文件夹里面创建vscode工程,工作区命名为“miscbeep。新建名为miscbeep.c的驱动文件,在miscbeep.c中输入如下所示内容:

示例代码57.3.2.1 miscbeep.c文件代码段
1   #include 
2   #include 
3   #include 
4   #include 
5   #include 
6   #include 
7   #include 
8   #include 
9   #include 
10  #include 
11  #include 
12  #include 
13  #include 
14  #include 
15  #include 
16  #include 
17  #include 
18  #include 
19  /***************************************************************
20  Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
21  文件名  		: miscbeep.c
22  作者      	: 左忠凯
23  版本      	: V1.0
24  描述      	: 采用MISC的蜂鸣器驱动程序。
25  其他      	: 无
26  论坛      	: www.openedv.com
27  日志      	: 初版V1.0 2019/8/20 左忠凯创建
28  ***************************************************************/
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设备 				*/
45  
46  /*
47   * @description  	: 打开设备
48   * @param – inode	: 传递给驱动的inode
49   * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
50   *                    一般在open的时候将private_data指向设备结构体。
51   * @return        	: 0 成功;其他 失败
52   */
53  static int miscbeep_open(struct inode *inode, struct file *filp)
54  {
55      filp->private_data = &miscbeep; /* 设置私有数据 */
56      return 0;
57  }
58  
59  /*
60   * @description  	: 向设备写数据 
61   * @param - filp 	: 设备文件,表示打开的文件描述符
62   * @param - buf  	: 要写给设备写入的数据
63   * @param - cnt 	: 要写入的数据长度
64   * @param - offt 	: 相对于文件首地址的偏移
65   * @return       	: 写入的字节数,如果为负值,表示写入失败
66   */
67  static ssize_t miscbeep_write(struct file *filp, 
const char __user *buf, size_t cnt, loff_t *offt)
68  {
69      int retvalue;
70      unsigned char databuf[1];
71      unsigned char beepstat;
72      struct miscbeep_dev *dev = filp->private_data;
73  
74      retvalue = copy_from_user(databuf, buf, cnt);
75      if(retvalue beep_gpio, 0);	/* 打开蜂鸣器 	*/
83      } else if(beepstat == BEEPOFF) {
84          gpio_set_value(dev->beep_gpio, 1);	/* 关闭蜂鸣器 	*/
85      }
86      return 0;
87  }
88  
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 };
102 
103  /*
104   * @description	: flatform驱动的probe函数,当驱动与
105   *                    设备匹配以后此函数就会执行
106   * @param - dev 	: platform设备
107   * @return      	: 0,成功;其他负值,失败
108   */
109 static int miscbeep_probe(struct platform_device *dev)
110 {
111     int ret = 0;
112 
113     printk("beep driver and device was matched!\r\n");
114     /* 设置BEEP所使用的GPIO */
115     /* 1、获取设备节点:beep */
116     miscbeep.nd = of_find_node_by_path("/beep");
117     if(miscbeep.nd == NULL) {
118         printk("beep node not find!\r\n");
119         return -EINVAL;
120     } 
121 
122     /* 2、 获取设备树中的gpio属性,得到BEEP所使用的BEEP编号 */
123     miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpio", 
0);
124     if(miscbeep.beep_gpio             
关注
打赏
1665308814
查看更多评论
0.0408s