1)资料下载:点击资料即可下载

2)对正点原子Linux感兴趣的同学可以加群讨论:935446741

3)关注正点原子公众号,获取最新资料更新

第五十七章Linux MISC驱动实验

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

57.1 MISC设备驱动简介

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

示例代码57.1.1 miscdevice结构体代码

57struct miscdevice {

58 int minor; /* 子设备号 */

59 constchar*name; /* 设备名字 */

60 conststruct file_operations *fops; /* 设备操作集 */

61 struct list_head list;

62 struct device *parent;

63 struct device *this_device;

64 conststruct attribute_group **groups;

65 constchar*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.2中的这些步骤。当我们卸载设备驱动模块的时候需要调用misc_deregister函数来注销掉MISC设备,函数原型如下:

int misc_deregister(struct miscdevice *misc)

函数参数和返回值含义如下:

misc:要注销的MISC设备。

返回值:负数,失败;0,成功。

以前注销设备驱动的时候,我们需要调用一堆的函数去删除此前创建的cdev、设备等等内容,如下所示:

示例代码57.1.3 传统的删除设备的过程

1 cdev_del(); /* 删除cdev */

2 unregister_chrdev_region(); /* 注销设备号 */

3 device_destroy(); /* 删除设备 */

4 class_destroy(); /* 删除类 */

现在我们只需要一个misc_deregister函数即可完成示例代码57.1.3中的这些工作。关于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 <linux/types.h>

2 #include <linux/kernel.h>

3 #include <linux/delay.h>

4 #include <linux/ide.h>

5 #include <linux/init.h>

6 #include <linux/module.h>

7 #include <linux/errno.h>

8 #include <linux/gpio.h>

9 #include <linux/cdev.h>

10 #include <linux/device.h>

11 #include <linux/of.h>

12 #include <linux/of_address.h>

13 #include <linux/of_gpio.h>

14 #include <linux/platform_device.h>

15 #include <linux/miscdevice.h>

16 #include <asm/mach/map.h>

17 #include <asm/uaccess.h>

18 #include <asm/io.h>

19/***************************************************************

20 Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.

21文件名 : miscbeep.c

22作者 : 左忠凯

23版本 : V1.0

24描述 : 采用MISC的蜂鸣器驱动程序。

25其他 : 无

26论坛 : http://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设备结构体 */

35struct miscbeep_dev{

36 dev_t devid; /* 设备号 */

37struct cdev cdev; /* cdev */

38struct class *class; /* 类 */

39struct device *device; /* 设备 */

40struct device_node *nd; /* 设备节点 */

41int beep_gpio; /* beep所使用的GPIO编号 */

42};

43

44struct 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 */

53staticint miscbeep_open(struct inode *inode,struct file *filp)

54{

55 filp->private_data =&miscbeep;/* 设置私有数据 */

56return0;

57}

58

59/*

60 * @description : 向设备写数据

61 * @param - filp : 设备文件,表示打开的文件描述符

62 * @param - buf : 要写给设备写入的数据

63 * @param - cnt : 要写入的数据长度

64 * @param - offt : 相对于文件首地址的偏移

65 * @return : 写入的字节数,如果为负值,表示写入失败

66 */

67static ssize_t miscbeep_write(struct file *filp,

constchar __user *buf,size_t cnt, loff_t *offt)

68{

69int retvalue;

70unsignedchar databuf[1];

71unsignedchar beepstat;

72struct miscbeep_dev *dev = filp->private_data;

73

74 retvalue = copy_from_user(databuf, buf, cnt);

75if(retvalue <0){

76 printk("kernel write failed!rn");

77return-EFAULT;

78}

79

80 beepstat = databuf[0]; /* 获取状态值 */

81if(beepstat == BEEPON){

82 gpio_set_value(dev->beep_gpio,0); /* 打开蜂鸣器 */

83}elseif(beepstat == BEEPOFF){

84 gpio_set_value(dev->beep_gpio,1); /* 关闭蜂鸣器 */

85}

86return0;

87}

88

89/* 设备操作函数 */

90staticstruct file_operations miscbeep_fops ={

91.owner = THIS_MODULE,

92.open = miscbeep_open,

93.write = miscbeep_write,

94};

95

96/* MISC设备结构体 */

97staticstruct 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 */

109staticint miscbeep_probe(struct platform_device *dev)

110{

111int ret =0;

112

113 printk("beep driver and device was matched!rn");

114/* 设置BEEP所使用的GPIO */

115/* 1、获取设备节点:beep */

116 miscbeep.nd = of_find_node_by_path("/beep");

117if(miscbeep.nd ==NULL){

118 printk("beep node not find!rn");

119return-EINVAL;

120}

121

122/* 2、获取设备树中的gpio属性,得到BEEP所使用的BEEP编号 */

123 miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd,"beep-gpio",

0);

124if(miscbeep.beep_gpio <0){

125 printk("can't get beep-gpio");

126return-EINVAL;

127}

128

129/* 3、设置GPIO5_IO01为输出,并且输出高电平,默认关闭BEEP */

130 ret = gpio_direction_output(miscbeep.beep_gpio,1);

131if(ret <0){

132 printk("can't set gpio!rn");

133}

134

135/* 一般情况下会注册对应的字符设备,但是这里我们使用MISC设备

136 * 所以我们不需要自己注册字符设备驱动,只需要注册misc设备驱动即可

137 */

138 ret = misc_register(&beep_miscdev);

139if(ret <0){

140 printk("misc device register failed!rn");

141return-EFAULT;

142}

143

144return0;

145}

146

147/*

148 * @description : remove函数,移除platform驱动的时候此函数会执行

149 * @param - dev : platform设备

150 * @return : 0,成功;其他负值,失败

151 */

152staticint miscbeep_remove(struct platform_device *dev)

153{

154/* 注销设备的时候关闭LED灯 */

155 gpio_set_value(miscbeep.beep_gpio,1);

156

157/* 注销misc设备驱动 */

158 misc_deregister(&beep_miscdev);

159return0;

160}

161

162/* 匹配列表 */

163staticconststruct of_device_id beep_of_match[]={

164{.compatible ="atkalpha-beep"},

165{/* Sentinel */}

166};

167

168/* platform驱动结构体 */

169staticstruct 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};

177

178/*

179 * @description : 驱动入口函数

180 * @param : 无

181 * @return : 无

182 */

183staticint __init miscbeep_init(void)

184{

185return platform_driver_register(&beep_driver);

186}

187

188/*

189 * @description : 驱动出口函数

190 * @param : 无

191 * @return : 无

192 */

193staticvoid __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("zuozhongkai");

第29~94行,标准的字符设备驱动。

第97~101行,MISC设备beep_miscdev,第98行设置子设备号为144,第99行设置设备名字为“miscbeep”,这样当系统启动以后就会在/dev/目录下存在一个名为“miscbeep”的设备文件。第100行,设置MISC设备的操作函数集合,为file_operations类型。

第109~145行,platform框架的probe函数,当驱动与设备匹配以后此函数就会执行,首先在此函数中初始化BEEP所使用的IO。最后在138行通过misc_register函数向Linux内核注册MISC设备,也就是前面定义的beep_miscdev。

第152~160行,platform框架的remove函数,在此函数中调用misc_deregister函数来注销MISC设备。

第163~196,标准的platform驱动。

57.3.3 编写测试APP

新建miscbeepApp.c文件,然后在里面输入如下所示内容:

示例代码57.3.2.2 miscbeepApp.c文件代码段

1 #include "stdio.h"

2 #include "unistd.h"

3 #include "sys/types.h"

4 #include "sys/stat.h"

5 #include "fcntl.h"

6 #include "stdlib.h"

7 #include "string.h"

8/***************************************************************

9 Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.

10文件名 : miscbeepApp.c

11作者 : 左忠凯

12版本 : V1.0

13描述 : MISC驱动框架下的beep测试APP。

14其他 : 无

15使用方法 :./miscbeepApp /dev/miscbeep 0 关闭蜂鸣器

16 ./misdcbeepApp /dev/miscbeep 1 打开蜂鸣器

17论坛 : http://www.openedv.com

18日志 : 初版V1.0 2019/8/20 左忠凯创建

19 ***************************************************************/

20 #define BEEPOFF 0

21 #define BEEPON 1

22

23/*

24 * @description : main主程序

25 * @param - argc : argv数组元素个数

26 * @param - argv : 具体参数

27 * @return : 0 成功;其他失败

28 */

29int main(int argc,char*argv[])

30{

31 int fd, retvalue;

32 char*filename;

33 unsignedchar databuf[1];

34

35 if(argc !=3){

36 printf("Error Usage!rn");

37 return-1;

38 }

39

40 filename = argv[1];

41 fd = open(filename, O_RDWR);/* 打开beep驱动 */

42 if(fd <0){

43 printf("file %s open failed!rn", argv[1]);

44 return-1;

45 }

46

47 databuf[0]= atoi(argv[2]); /* 要执行的操作:打开或关闭 */

48 retvalue = write(fd, databuf,sizeof(databuf));

49 if(retvalue <0){

50 printf("BEEP Control Failed!rn");

51 close(fd);

52 return-1;

53 }

54

55 retvalue = close(fd); /* 关闭文件 */

56 if(retvalue <0){

57 printf("file %s close failed!rn", argv[1]);

58 return-1;

59 }

60 return0;

61}

miscbeepApp.c文件内容和其他例程的测试APP基本一致,很简单,这里就不讲解了。

57.4 运行测试

57.4.1 编译驱动程序和测试APP

1、编译驱动程序

编写Makefile文件,本章实验的Makefile文件和第四十章实验基本一样,只是将obj-m变量的值改为“leddevice.o leddriver.o”,Makefile内容如下所示:

示例代码57.4.1.1 Makefile文件

1 KERNELDIR:= /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek

......

4 obj-m := miscbeep.o

......

11 clean:

12$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

第4行,设置obj-m变量的值为“miscbeep.o”。

输入如下命令编译出驱动模块文件:

make-j32

编译成功以后就会生成一个名为“miscbeep.ko”的驱动模块文件。

2、编译测试APP

输入如下命令编译测试miscbeepApp.c这个测试程序:

arm-linux-gnueabihf-gccmiscbeepApp.c -o miscbeepApp

编译成功以后就会生成miscbeepApp这个应用程序。

57.4.2 运行测试

将上一小节编译出来miscbeep.ko和miscbeepApp这两个文件拷贝到rootfs/lib/modules/4.1.15目录中,重启开发板,进入到目录lib/modules/4.1.15中,输入如下命令加载miscbeep.ko这个驱动模块。

depmod //第一次加载驱动的时候需要运行此命令

modprobe miscbeep.ko //加载设备模块

当驱动模块加载成功以后我们可以在/sys/class/misc这个目录下看到一个名为“miscbeep”的子目录,如图57.4.2.1所示:

图57.4.2.1 misbeep子目录

所有的misc设备都属于同一个类,/sys/class/misc目录下就是misc这个类的所有设备,每个设备对应一个子目录。

驱动与设备匹配成功以后就会生成/dev/miscbeep这个设备驱动文件,输入如下命令查看这个文件的主次设备号:

ls /dev/miscbeep -l

结果如图57.4.2.2所示:

图57.4.2.2 /dev/miscbeep设备文件

从图57.4.2.2可以看出,/dev/miscbeep这个设备的主设备号为10,次设备号为144,和我们驱动程序里面设置的一致。

输入如下命令打开BEEP:

./miscbeepApp /dev/miscbeep 1 //打开BEEP

在输入如下命令关闭LED灯:

./miscbeepApp /dev/miscbeep 0//关闭BEEP

观察一下BEEP能否打开和关闭,如果可以的话就说明驱动工作正常,如果要卸载驱动的话输入如下命令即可:

rmmod miscbeep.ko

韦东山 IMX6ULL和正点原子_正点原子Linux第五十七章Linux MISC驱动实验相关推荐

  1. 【正点原子STM32连载】第五十七章 USB读卡器(Slave)实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1

    1)实验平台:正点原子MiniPro H750开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=677017430560 3)全套实验源码+手册+视频 ...

  2. 基于stm32f429的手写识别_正点原子【STM32-F407探索者】第五十三章 手写识别实验...

    1)资料下载:点击资料即可下载 2)对正点原子Linux感兴趣的同学可以加群讨论:935446741 3)关注正点原子公众号,获取最新资料更新 现在几乎所有带触摸屏的手机都能实现手写识别.本章,我们将 ...

  3. 韦东山 IMX6ULL和正点原子_【预习】韦东山:剥丝抽茧分析Linux中断系统中的重要数据结构...

    导语: 众所周知,目前升级版视频正在录中断系统,已经录到[Linux系统对中断处理的演进],配套文档发布后,颇受学员好评,知乎文章: https://zhuanlan.zhihu.com/p/1130 ...

  4. 实验5-9 使用函数输出水仙花数_正点原子STM32F407探索者开发板资料连载第五十三章 手写识别实验

    1)实验平台:alientek 阿波罗 STM32F767 开发板 2)摘自<STM32F7 开发指南(HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 第五十三章 手写识别实 ...

  5. 【正点原子Linux连载】第三十七章 Linux内核移植 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

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

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  7. 【正点原子FPGA连载】 第十七章 RS485串口通信实验 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  8. 【正点原子FPGA连载】第二十七章DS18B20数字温度传感器实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

    1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...

  9. 【正点原子STM32连载】 第二十七章 RTC实时时钟实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1

    1)实验平台:正点原子MiniPro H750开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=677017430560 3)全套实验源码+手册+视频 ...

最新文章

  1. 【sublime Text】关闭sublime的更新提醒和激活提醒
  2. 三、前端开发-CSS
  3. 【渝粤教育】国家开放大学2018年秋季 0273-22T中国现代文学 参考试题
  4. django本地安装mysql_Ununtu 15.04 安装MySql(Django连接Mysql)
  5. 【Elasticsearch】 Elasticsearch对外提供分词服务实践
  6. 续易crm源码客户资源管理系统crm源码(源代码c#)
  7. linux下如何安装charles
  8. oracle的热备份和冷备份
  9. # 研究杂感 × VOSviewer(第四辑)
  10. 数据结构面试、数据结构考研复试——常见问题以及回答
  11. 2022-2023 物联网毕业设计选题推荐
  12. Hanoi Tower Troubles Again! ZOJ - 1239
  13. 部署NanoDet实现火焰检测
  14. java基础 equals与hashCode
  15. 并发问题中的乐观锁和悲观锁
  16. SDNU-1093.DNA排序
  17. DOSBox使用debug
  18. 玩课网计算机基础课后答案,计算机类MOOC教学研讨会暨中国高校CMOOC联盟云南省工作委员会成立大会在昆明理工大学举行...
  19. 广东迅视资管 长沙青年创客推荐“励”字为2020湖南年度字
  20. long mode 分页_LuLu UI中文文档和演示 » 分页

热门文章

  1. Java腐烂的橘子leetcode
  2. 【华为HCIE证书难考吗?】
  3. Ubuntu 20.04系统安装及初始配置
  4. 猿编程python_猿编程下载-猿编程客户端 v2.12.0.1103 官方版 - 安下载
  5. 淘宝开店指南——商品管理篇
  6. Ubuntu 屏幕颜色校准
  7. macos 打开终端弹出:(eval):export:1: not valid in this context: Fusion.app/Contents/Public
  8. win7 精简板 安装ardunio uno r3驱动
  9. 2009-2020年天猫“双十一”成交额统计情况
  10. java百度地图逆地址解析_百度地图逆地址解析