昨天我们已经实现了中断查询的方式实现GPIO按键驱动程序,但是,有一个缺点就是,当我们把应用程序放在后台执行时,即便没有按键,应用程序while循环中的read函数也不断的在运行,严重的导致了CPU资源的浪费。
本文中,我们在前面按键查询驱动程序的基础上来修改。
大概介绍一下设计思路吧:
和前面的差不多,当我们加载驱动时,首先在init函数中,对GPIO功能进行模式设置,都设置为GPIO模式,然后申请GPIO引脚的内存,
接着,当我们应用程序使用ioctl函数的gpio_input命令时,将所有的GPIO引脚设置为输入,并且22K上拉模式,当应用程序使用read函数读取时,如果按键没有按下,则会在read函数中睡眠(可被中断唤醒),交出CPU的使用权,当按键按下时,首先会在中断程序中进行唤醒操作,在read函数中接着运行,读取GPIO引脚的电平,并且将数据从内核空间传递到用户空间中,并且打印出来。
最后,当我们不要用驱动程序时,rsmod会调用exit函数,释放所有我们已经申请的GPIO资源。
好了,大概的思路就是这样,和前面的查询驱动程序,差不多,只不过就加了一个中断,和睡眠而已。
附上驱动程序代码:
1 /******************************
2 linux key_query
3 *****************************/
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
19 #include 'mx257_gpio.h'
20 #include 'mx25_pins.h'
21 #include 'iomux.h'
22
23 #define Driver_NAME 'key_interrupt'
24 #define DEVICE_NAME 'key_interrupt'
25
26 #define GPIO2_21 MX25_PIN_CLKO
27 #define GPIO3_15 MX25_PIN_EXT_ARMCLK
28 #define GPIO2_10 MX25_PIN_A24
29 #define GPIO2_11 MX25_PIN_A25
30 #define GPIO2_8 MX25_PIN_A22
31 #define GPIO2_9 MX25_PIN_A23
32 #define GPIO2_6 MX25_PIN_A20
33 #define GPIO2_7 MX25_PIN_A21
34 //command
35 #define key_input 0
36 #define version 1
37
38 //interrupt head
39 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait);
40 static volatile unsigned char ev_press;
41
42 static int major=0;
43
44 //auto to create device node
45 static struct class *drv_class = NULL;
46 static struct class_device *drv_class_dev = NULL;
47
48
49 /* 应用程序对设备文件/dev/key_query执行open(...)时,
50 * 就会调用key_open函数*/
51 static int key_open(struct inode *inode, struct file *file)
52 {
53 printk('<0>function open!nn');
54
55 return 0;
56 }
57
58 /* 中断程序key_irq */
59 static irqreturn_t key_irq(int irq, void *dev_id)
60 {
61 //发生了中断
62 printk('<0>function interrupt key_irq!nn');
63 ev_press = 1;
64 wake_up_interruptible(&key_interrupt_wait);
65
66 return IRQ_RETVAL(IRQ_HANDLED);
67 }
68
69
70 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
71 {
72 int ret;
73 //nt cnt=0;
74 unsigned char key_vals[8];
75
76 //如果按键没有按下,没有中断,休眠
77 wait_event_interruptible(key_interrupt_wait,ev_press);
78
79 // reading the pins value
80 key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0;
81 key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0;
82 key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0;
83 key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0;
84 key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0;
85 key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0;
86 key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0;
87 key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0;
88
89 ret = copy_to_user(buff,key_vals,sizeof(key_vals));
90 if(ret){
91 ;
92 }
93 ev_press = 0;
94 //printk('<0>%04d key pressed: %d %d %d %d %d %d %d %dn',cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5],key_vals[6],key_vals[7]);
95
96 return sizeof(key_vals);
97 }
98
99 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
100 {
101 printk('<0>function write!nn');
102
103 return 1;
104 }
105
106 static int key_release(struct inode *inode, struct file *filp)
107 {
108 printk('<0>function release!nn');
109 //释放中断
110 free_irq(IOMUX_TO_IRQ(GPIO2_21), (void *)1);
111 //free_irq(IOMUX_TO_IRQ(GPIO3_15), (void *)1);
112 free_irq(IOMUX_TO_IRQ(GPIO2_11), (void *)1);
113 free_irq(IOMUX_TO_IRQ(GPIO2_10), (void *)1);
114 free_irq(IOMUX_TO_IRQ(GPIO2_9), (void *)1);
115 //free_irq(IOMUX_TO_IRQ(GPIO2_8), (void *)1);
116 free_irq(IOMUX_TO_IRQ(GPIO2_7), (void *)1);
117 free_irq(IOMUX_TO_IRQ(GPIO2_6), (void *)1);
118 return 0;
119 }
120
121 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
122 {
123 int ret;
124 printk('<0>function ioctl!nn');
125 switch (command) {
126 case key_input:
127 //设置所有的引脚为输入
128 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21));
129 gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15));
130 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10));
131 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11));
132 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8));
133 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9));
134 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6));
135 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7));
136 printk('<0>have setting all pins to gpio input mod !n');
137 //设置GPIO引脚为上拉模式
138 mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
139 mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
140 //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
141 mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
142 mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
143 mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
144 mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
145 //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU);
146
147 //设置GPIO引脚中断 ,下降沿触发
148 request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_7', (void *)1);
149 request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_6', (void *)1);
150 request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_9', (void *)1);
151 request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_10', (void *)1);
152 request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_11', (void *)1);
153 request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_21', (void *)1);
154 //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO3_15', (void *)1);
155 //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_8', (void *)1);
156 printk('<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !n');
157
158 break;
159 case version:
160 printk('<0>hello,the version is 0.1.0nn');