我们在按键中断实验的基础上来完成阻塞IO的实验,在上一章的按键中断实验中,我们通过read函数while循环的方式读取按键状态,这种方法缺点很明显,会导致有很高的CPU占用率。我们来看一下通过while循环的方式CPU的使用率,使用上一章的key_irq.ko模块和key_irq_test应用程序,先加载驱动模块,然后执行应用程序:
modprobe key_irq
./key_irq_test /dev/imx6uirq &
使用“top”命令查看key_irq_test程序的CPU使用率,如图 1所示:
可以看到key_irq_test程序的CPU使用率为97.2%,仅仅是一个按键程序就会导致这么高的CPU使用率效率是非常低的。所以一般是不会采用这种方法的,只是在实验中使用一下,在本节中我们就是用阻塞IO来实现一下。
1 驱动程序编写
本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/11_key_waitqueue
创建key_waitqueue.c文件,在key_irq.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/semaphore.h>
15 #include <linux/timer.h>
16 #include <linux/of_irq.h>
17 #include <linux/irq.h>
18 #include <asm/mach/map.h>
19 #include <asm/uaccess.h>
20 #include <asm/io.h>
21
22 #define IMX6UIRQ_CNT 1 /* 设备号个数 */
23 #define IMX6UIRQ_NAME "blockio" /* 名字 */
24 #define KEY0VALUE 0X01 /* KEY0 按键值 */
25 #define INVAKEY 0XFF /* 无效的按键值 */
26 #define KEY_NUM 1 /* 按键数量 */
27
28 /* 中断 IO 描述结构体 */
29 struct irq_keydesc {
30 int gpio; /* gpio */
31 int irqnum; /* 中断号 */
32 unsigned char value; /* 按键对应的键值 */
33 char name[10]; /* 名字 */
34 irqreturn_t (*handler)(int, void *); /* 中断服务函数 */
35 };
36
37 /* imx6uirq 设备结构体 */
38 struct imx6uirq_dev{
39 dev_t devid; /* 设备号 */
40 struct cdev cdev; /* cdev */
41 struct class *class; /* 类 */
42 struct device *device; /* 设备 */
43 int major; /* 主设备号 */
44 int minor; /* 次设备号 */
45 struct device_node *nd; /* 设备节点 */
46 atomic_t keyvalue; /* 有效的按键键值 */
47 atomic_t releasekey; /* 标记是否完成一次完成的按键 */
48 struct timer_list timer; /* 定义一个定时器*/
49 struct irq_keydesc irqkeydesc[KEY_NUM]; /* 按键 init 述数组 */
50 unsigned char curkeynum; /* 当前 init 按键号 */
51
52 wait_queue_head_t r_wait; /* 读等待队列头 */
53 };
54
55 struct imx6uirq_dev imx6uirq; /* irq 设备 */
56
57 /* @description : 中断服务函数,开启定时器
58 * 定时器用于按键消抖。
59 * @param - irq : 中断号
60 * @param - dev_id : 设备结构。
61 * @return : 中断执行结果
62 */
63 static irqreturn_t key0_handler(int irq, void *dev_id)
64 {
65 struct imx6uirq_dev *dev = (struct imx6uirq_dev*)dev_id;
66
67 dev->curkeynum = 0;
68 dev->timer.data = (volatile long)dev_id;
69 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(10));
70