【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序
2015-02-18 李海沿
按键驱动程序中,如果不使用read函数中使程序休眠的,而是还是使用查询方式的话,可以使用Poll函数,来控制一定时间内,如果有按键发生,则立即返回键值。
同时,poll也可以同时监控多个(比如说按键,鼠标,等)一旦发生事件则立即返回。
我们在linux查看帮助:
从帮助中的说明得知,
poll, ppoll - wait for some event on a file descriptor
poll就是监控某个设备的事件。
修改驱动程序
1.增加头文件 #include <linux/poll.h>
2.增加key_poll 方法
static unsigned key_poll(struct file *file,poll_table *wait) |
file_opreation中增加:
.poll = key_poll, |
3.在key_poll函数中设置函数不睡眠
4.此时可以把以前的read函数中的中断睡眠代码注释掉
5.编译代码,测试
附上驱动程序。
1 /****************************** 2 linux key_query 3 *****************************/ 4 #include <linux/module.h> 5 #include <linux/init.h> 6 #include <linux/kernel.h> 7 #include <linux/delay.h> 8 #include <linux/types.h> 9 #include <linux/ioctl.h> 10 #include <linux/gpio.h> 11 #include <linux/fs.h> 12 #include <linux/device.h> 13 #include <linux/uaccess.h> 14 #include <linux/irq.h> 15 #include <linux/wait.h> 16 #include <linux/sched.h>//error: 'TASK_INTERRUPTIBLE' undeclared 17 #include <linux/interrupt.h> 18 #include <linux/poll.h> 19 20 #include "mx257_gpio.h" 21 #include "mx25_pins.h" 22 #include "iomux.h" 23 24 #define Driver_NAME "key_interrupt" 25 #define DEVICE_NAME "key_interrupt" 26 27 #define GPIO2_21 MX25_PIN_CLKO 28 #define GPIO3_15 MX25_PIN_EXT_ARMCLK 29 #define GPIO2_10 MX25_PIN_A24 30 #define GPIO2_11 MX25_PIN_A25 31 #define GPIO2_8 MX25_PIN_A22 32 #define GPIO2_9 MX25_PIN_A23 33 #define GPIO2_6 MX25_PIN_A20 34 #define GPIO2_7 MX25_PIN_A21 35 //command 36 #define key_input 0 37 #define version 1 38 //定义各个按键按下的键值 39 struct pin_desc{ 40 unsigned int pin; 41 unsigned int key_val; 42 }; 43 //当按键按下时,键值分别为 以下值 44 struct pin_desc pins_desc[8] = { 45 {GPIO2_6, 0x01}, 46 {GPIO2_7, 0x02}, 47 {GPIO2_8, 0x03}, 48 {GPIO2_9, 0x04}, 49 {GPIO2_10, 0x05}, 50 {GPIO2_11, 0x06}, 51 {GPIO2_21, 0x07}, 52 {GPIO3_15, 0x08}, 53 }; 54 //定义一个全局变量,用于保存按下的键值 55 static unsigned int key_val; 56 57 //interrupt head 58 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait); 59 static volatile unsigned char ev_press; 60 61 static int major=0; 62 63 //auto to create device node 64 static struct class *drv_class = NULL; 65 static struct class_device *drv_class_dev = NULL; 66 67 68 /* 应用程序对设备文件/dev/key_query执行open(...)时, 69 * 就会调用key_open函数*/ 70 static int key_open(struct inode *inode, struct file *file) 71 { 72 printk("<0>function open! "); 73 74 return 0; 75 } 76 77 /* 中断程序key_irq */ 78 static irqreturn_t key_irq(int irq, void *dev_id) 79 { 80 struct pin_desc * pindesc = (struct pin_desc *)dev_id; 81 //发生了中断 82 //printk("<0>function interrupt key_irq! "); 83 //获取按键键值 84 if(gpio_get_value(IOMUX_TO_GPIO(pindesc->pin))){ 85 /* 按下 */ 86 key_val = pindesc->key_val; 87 }else{ 88 key_val = 0x80 | pindesc->key_val; 89 } 90 printk("<0>get key 0x%x",key_val); 91 ev_press = 1; 92 wake_up_interruptible(&key_interrupt_wait); 93 94 return IRQ_RETVAL(IRQ_HANDLED); 95 } 96 97 98 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 99 { 100 int ret; 101 //如果按键没有按下,没有中断,休眠 102 //wait_event_interruptible(key_interrupt_wait,ev_press); 103 104 ret = copy_to_user(buff,&key_val,sizeof(key_val)); 105 if(ret){ 106 ; 107 } 108 ev_press = 0; 109 return sizeof(key_val); 110 111 //int cnt=0; 112 //unsigned char key_vals[8]; 113 114 /* 115 // reading the pins value 116 key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0; 117 key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0; 118 key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0; 119 key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0; 120 key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0; 121 key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0; 122 key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0; 123 key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0; 124 125 //printk("<0>%04d key pressed: %d %d %d %d %d %d %d %d ",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]); 126 */ 127 } 128 129 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 130 { 131 printk("<0>function write! "); 132 133 return 1; 134 } 135 136 static int key_release(struct inode *inode, struct file *filp) 137 { 138 printk("<0>function release! "); 139 //释放中断 140 free_irq(IOMUX_TO_IRQ(GPIO2_21), &pins_desc[6]); 141 //free_irq(IOMUX_TO_IRQ(GPIO3_15),&pins_desc[7]); 142 free_irq(IOMUX_TO_IRQ(GPIO2_11), &pins_desc[5]); 143 free_irq(IOMUX_TO_IRQ(GPIO2_10), &pins_desc[4]); 144 free_irq(IOMUX_TO_IRQ(GPIO2_9), &pins_desc[3]); 145 //free_irq(IOMUX_TO_IRQ(GPIO2_8), &pins_desc[2]); 146 free_irq(IOMUX_TO_IRQ(GPIO2_7), &pins_desc[1]); 147 free_irq(IOMUX_TO_IRQ(GPIO2_6), &pins_desc[0]); 148 return 0; 149 } 150 151 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 152 { 153 int ret; 154 printk("<0>function ioctl! "); 155 switch (command) { 156 case key_input: 157 //设置所有的引脚为输入 158 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21)); 159 gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15)); 160 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10)); 161 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11)); 162 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8)); 163 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9)); 164 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6)); 165 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7)); 166 printk("<0>have setting all pins to gpio input mod ! "); 167 //设置GPIO引脚为上拉模式 168 mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 169 mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 170 //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 171 mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 172 mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 173 mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 174 mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 175 //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 176 177 //设置GPIO引脚中断 ,下降沿触发 178 request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", &pins_desc[0]); 179 request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", &pins_desc[1]); 180 request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", &pins_desc[3]); 181 request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[4]); 182 request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", &pins_desc[5]); 183 request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", &pins_desc[6]); 184 //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO3_15", &pins_desc[7]); 185 //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_8", &pins_desc[2]); 186 printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING ! "); 187 188 break; 189 case version: 190 printk("<0>hello,the version is 0.1.0 "); 191 break; 192 default: 193 printk("<0>command error "); 194 printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg; "); 195 printk("<0>command: <key_input> <version> "); 196 return -1; 197 } 198 return 0; 199 } 200 static unsigned key_poll(struct file *file,poll_table *wait) 201 { 202 unsigned int mask = 0; 203 //程序不立即睡眠,而是继续等待 204 poll_wait(file,&key_interrupt_wait,wait); 205 //如果按键按下 206 if(ev_press) 207 mask |= POLLIN | POLLRDNORM; 208 209 return mask; 210 } 211 212 /* 这个结构是字符设备驱动程序的核心 213 * 当应用程序操作设备文件时所调用的open、read、write等函数, 214 * 最终会调用这个结构中指定的对应函数 215 */ 216 static struct file_operations key_fops = { 217 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 218 .open = key_open, 219 .read = key_read, 220 .write = key_write, 221 .release= key_release, 222 .ioctl = key_ioctl, 223 .poll = key_poll, 224 }; 225 226 /* 227 * 执行insmod命令时就会调用这个函数 228 */ 229 static int __init key_irq_init(void) 230 { 231 printk("<0> Hello,this is %s module! ",Driver_NAME); 232 //register and mknod 233 major = register_chrdev(0,Driver_NAME,&key_fops); 234 drv_class = class_create(THIS_MODULE,Driver_NAME); 235 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/ 236 237 //set all pins to GPIO mod ALF5 238 mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5); 239 mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5); 240 mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5); 241 mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5); 242 mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5); 243 mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5); 244 mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5); 245 mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5); 246 //request IOMUX GPIO 247 gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21"); 248 gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15"); 249 gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10"); 250 gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11"); 251 gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8"); 252 gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9"); 253 gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6"); 254 gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7"); 255 256 257 return 0; 258 } 259 260 /* 261 * 执行rmmod命令时就会调用这个函数 262 */ 263 static void __exit key_irq_exit(void) 264 { 265 printk("<0> Goodbye,%s! ",Driver_NAME); 266 267 unregister_chrdev(major,Driver_NAME); 268 device_unregister(drv_class_dev); 269 class_destroy(drv_class); 270 271 /* free gpios */ 272 mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5); 273 mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5); 274 mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5); 275 mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5); 276 mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5); 277 mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5); 278 mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5); 279 mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5); 280 281 gpio_free(IOMUX_TO_GPIO(GPIO2_21)); 282 gpio_free(IOMUX_TO_GPIO(GPIO3_15)); 283 gpio_free(IOMUX_TO_GPIO(GPIO2_10)); 284 gpio_free(IOMUX_TO_GPIO(GPIO2_11)); 285 gpio_free(IOMUX_TO_GPIO(GPIO2_8)); 286 gpio_free(IOMUX_TO_GPIO(GPIO2_9)); 287 gpio_free(IOMUX_TO_GPIO(GPIO2_6)); 288 gpio_free(IOMUX_TO_GPIO(GPIO2_7)); 289 290 } 291 292 /* 这两行指定驱动程序的初始化函数和卸载函数 */ 293 module_init(key_irq_init); 294 module_exit(key_irq_exit); 295 296 /* 描述驱动程序的一些信息,不是必须的 */ 297 MODULE_AUTHOR("Lover雪"); 298 MODULE_VERSION("0.1.0"); 299 MODULE_DESCRIPTION("IMX257 key Driver"); 300 MODULE_LICENSE("GPL");
修改应用程序
1.我们首先包含头文件 #include <poll.h>
2.定义结构体
struct pollfd fds[1]; //方括号中为要监控的设备数量 fds[0].fd = fd; //加入要监控的设备描述符 fds[0].events = POLLIN; |
3. 监控的结果是 POLLIN
POLLIN There is data to read.
从帮助得知,一旦时间发送就意思有消息读取,接着,一旦我们poll监控到数据,我们就开始read函数来读取数据。
附上修改后的应用程序代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 #include <termios.h> 8 #include <errno.h> 9 #include <limits.h> 10 #include <asm/ioctls.h> 11 #include <time.h> 12 #include <pthread.h> 13 #include <poll.h> 14 15 #include "mx257_gpio.h" 16 17 #define key_input 0 18 #define version 1 19 20 21 int main(int argc, char **argv) 22 { 23 int fd; 24 int i=0,cnt=0; 25 unsigned char key_val[1]; 26 struct pollfd fds[1]; 27 int ret; 28 fd = open("/dev/key_interrupt",O_RDWR); 29 if(fd < 0){ 30 printf("can't open !!! "); 31 } 32 ioctl(fd,version,NULL); 33 ioctl(fd,key_input,NULL); 34 35 fds[0].fd = fd; 36 fds[0].events = POLLIN; 37 while(1){ 38 ret = poll(fds,1,5000); 39 if(ret == 0) 40 printf("time out "); 41 else{ 42 read(fd,key_val,1); 43 printf("%04d key pressed: 0x%x ",cnt++,key_val[0]); 44 } 45 } 46 return 0; 47 }
运行程序:
可以发现,其实程序时不断的在查询,每5秒之内若是没有时间发生则打印time out,若是有时间发生,则立即读取内核空间的键值。
既然是不断的查询,那我们来看一下,它是不是很耗费CPU资源呢:
后台运行,使用top命令查看cpu使用率
可以发现,函数在不断的运行,每过5s打印time out
使用top命令,查看cpu资源
可以发现,虽然这个程序没有使用中断休眠函数,也是在不断的查询,但是使用poll后,cpu几乎不占用。
kill 杀死后台程序