【改进】IMX257实现GPIO-IRQ中断按键获取键值驱动程序
2015-02-18 李海沿
一、使用struct pin_desc 管理按键的值
1.定义结构体
2.将前面我们申请中断时写的(void *)1修改为 &pins_desc[n]
在ioctl中,设置中断中修改
在key_release中释放中修改
3.在中断程序中利用我们定义的struc pins_desc判断并得到按键的值
4.得到按键键值后,唤醒程序,在read函数中返回键值
附上驱动源程序:
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 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 struct pin_desc{ 39 unsigned int pin; 40 unsigned int key_val; 41 }; 42 //当按键按下时,键值分别为 以下值 43 struct pin_desc pins_desc[8] = { 44 {GPIO2_6, 0x01}, 45 {GPIO2_7, 0x02}, 46 {GPIO2_8, 0x03}, 47 {GPIO2_9, 0x04}, 48 {GPIO2_10, 0x05}, 49 {GPIO2_11, 0x06}, 50 {GPIO2_21, 0x07}, 51 {GPIO3_15, 0x08}, 52 }; 53 //定义一个全局变量,用于保存按下的键值 54 static unsigned int key_val; 55 56 //interrupt head 57 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait); 58 static volatile unsigned char ev_press; 59 60 static int major=0; 61 62 //auto to create device node 63 static struct class *drv_class = NULL; 64 static struct class_device *drv_class_dev = NULL; 65 66 67 /* 应用程序对设备文件/dev/key_query执行open(...)时, 68 * 就会调用key_open函数*/ 69 static int key_open(struct inode *inode, struct file *file) 70 { 71 printk("<0>function open!\n\n"); 72 73 return 0; 74 } 75 76 /* 中断程序key_irq */ 77 static irqreturn_t key_irq(int irq, void *dev_id) 78 { 79 struct pin_desc * pindesc = (struct pin_desc *)dev_id; 80 //发生了中断 81 //printk("<0>function interrupt key_irq!\n\n"); 82 //获取按键键值 83 if(gpio_get_value(IOMUX_TO_GPIO(pindesc->pin))){ 84 /* 按下 */ 85 key_val = pindesc->key_val; 86 }else{ 87 key_val = 0x80 | pindesc->key_val; 88 } 89 printk("<0>get key 0x%x",key_val); 90 ev_press = 1; 91 wake_up_interruptible(&key_interrupt_wait); 92 93 return IRQ_RETVAL(IRQ_HANDLED); 94 } 95 96 97 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 98 { 99 int ret; 100 //如果按键没有按下,没有中断,休眠 101 wait_event_interruptible(key_interrupt_wait,ev_press); 102 103 ret = copy_to_user(buff,&key_val,sizeof(key_val)); 104 if(ret){ 105 ; 106 } 107 ev_press = 0; 108 return sizeof(key_val); 109 110 //int cnt=0; 111 //unsigned char key_vals[8]; 112 113 /* 114 // reading the pins value 115 key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0; 116 key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0; 117 key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0; 118 key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0; 119 key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0; 120 key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0; 121 key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0; 122 key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0; 123 124 //printk("<0>%04d key pressed: %d %d %d %d %d %d %d %d\n",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]); 125 */ 126 } 127 128 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 129 { 130 printk("<0>function write!\n\n"); 131 132 return 1; 133 } 134 135 static int key_release(struct inode *inode, struct file *filp) 136 { 137 printk("<0>function release!\n\n"); 138 //释放中断 139 free_irq(IOMUX_TO_IRQ(GPIO2_21), &pins_desc[6]); 140 //free_irq(IOMUX_TO_IRQ(GPIO3_15),&pins_desc[7]); 141 free_irq(IOMUX_TO_IRQ(GPIO2_11), &pins_desc[5]); 142 free_irq(IOMUX_TO_IRQ(GPIO2_10), &pins_desc[4]); 143 free_irq(IOMUX_TO_IRQ(GPIO2_9), &pins_desc[3]); 144 //free_irq(IOMUX_TO_IRQ(GPIO2_8), &pins_desc[2]); 145 free_irq(IOMUX_TO_IRQ(GPIO2_7), &pins_desc[1]); 146 free_irq(IOMUX_TO_IRQ(GPIO2_6), &pins_desc[0]); 147 return 0; 148 } 149 150 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 151 { 152 int ret; 153 printk("<0>function ioctl!\n\n"); 154 switch (command) { 155 case key_input: 156 //设置所有的引脚为输入 157 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21)); 158 gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15)); 159 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10)); 160 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11)); 161 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8)); 162 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9)); 163 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6)); 164 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7)); 165 printk("<0>have setting all pins to gpio input mod !\n"); 166 //设置GPIO引脚为上拉模式 167 mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 168 mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 169 //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 170 mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 171 mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 172 mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 173 mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 174 //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 175 176 //设置GPIO引脚中断 ,下降沿触发 177 request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", &pins_desc[0]); 178 request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", &pins_desc[1]); 179 request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", &pins_desc[3]); 180 request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[4]); 181 request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", &pins_desc[5]); 182 request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", &pins_desc[6]); 183 //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO3_15", &pins_desc[7]); 184 //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_8", &pins_desc[2]); 185 printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !\n"); 186 187 break; 188 case version: 189 printk("<0>hello,the version is 0.1.0\n\n"); 190 break; 191 default: 192 printk("<0>command error \n"); 193 printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;\n"); 194 printk("<0>command: <key_input> <version>\n\n"); 195 return -1; 196 } 197 return 0; 198 } 199 200 /* 这个结构是字符设备驱动程序的核心 201 * 当应用程序操作设备文件时所调用的open、read、write等函数, 202 * 最终会调用这个结构中指定的对应函数 203 */ 204 static struct file_operations key_fops = { 205 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 206 .open = key_open, 207 .read = key_read, 208 .write = key_write, 209 .release= key_release, 210 .ioctl = key_ioctl, 211 }; 212 213 /* 214 * 执行insmod命令时就会调用这个函数 215 */ 216 static int __init key_irq_init(void) 217 { 218 printk("<0>\nHello,this is %s module!\n\n",Driver_NAME); 219 //register and mknod 220 major = register_chrdev(0,Driver_NAME,&key_fops); 221 drv_class = class_create(THIS_MODULE,Driver_NAME); 222 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/ 223 224 //set all pins to GPIO mod ALF5 225 mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5); 226 mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5); 227 mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5); 228 mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5); 229 mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5); 230 mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5); 231 mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5); 232 mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5); 233 //request IOMUX GPIO 234 gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21"); 235 gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15"); 236 gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10"); 237 gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11"); 238 gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8"); 239 gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9"); 240 gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6"); 241 gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7"); 242 243 return 0; 244 } 245 246 /* 247 * 执行rmmod命令时就会调用这个函数 248 */ 249 static void __exit key_irq_exit(void) 250 { 251 printk("<0>\nGoodbye,%s!\n\n",Driver_NAME); 252 253 unregister_chrdev(major,Driver_NAME); 254 device_unregister(drv_class_dev); 255 class_destroy(drv_class); 256 257 /* free gpios */ 258 mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5); 259 mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5); 260 mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5); 261 mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5); 262 mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5); 263 mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5); 264 mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5); 265 mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5); 266 267 gpio_free(IOMUX_TO_GPIO(GPIO2_21)); 268 gpio_free(IOMUX_TO_GPIO(GPIO3_15)); 269 gpio_free(IOMUX_TO_GPIO(GPIO2_10)); 270 gpio_free(IOMUX_TO_GPIO(GPIO2_11)); 271 gpio_free(IOMUX_TO_GPIO(GPIO2_8)); 272 gpio_free(IOMUX_TO_GPIO(GPIO2_9)); 273 gpio_free(IOMUX_TO_GPIO(GPIO2_6)); 274 gpio_free(IOMUX_TO_GPIO(GPIO2_7)); 275 276 } 277 /* 这两行指定驱动程序的初始化函数和卸载函数 */ 278 module_init(key_irq_init); 279 module_exit(key_irq_exit); 280 281 /* 描述驱动程序的一些信息,不是必须的 */ 282 MODULE_AUTHOR("Lover雪"); 283 MODULE_VERSION("0.1.0"); 284 MODULE_DESCRIPTION("IMX257 key Driver"); 285 MODULE_LICENSE("GPL");
附上应用程序代码:
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 14 #include "mx257_gpio.h" 15 16 #define key_input 0 17 #define version 1 18 19 20 int main(int argc, char **argv) 21 { 22 int fd; 23 int i=0,cnt=0; 24 unsigned char key_val[1]; 25 26 fd = open("/dev/key_interrupt",O_RDWR); 27 if(fd < 0){ 28 printf("can't open !!!\n"); 29 } 30 ioctl(fd,version,NULL); 31 ioctl(fd,key_input,NULL); 32 while(1){ 33 read(fd,key_val,sizeof(key_val)); 34 printf("%04d key pressed: 0x%x\n",cnt++,key_val[0]); 35 } 36 return 0; 37 }
结果如图所用 insmod key_interrupt.ko
后台运行应用程序 ./test/key_test &
查看中断 cat /proc/interrupts
ps,查看我们后台的进程号,使用kill函数时,驱动程序会自动进入release函数,释放中断号。
********************************************
* 博客园: http://www.cnblogs.com/lihaiyan/
* 邮箱:1063385677@qq.com
* QQ: 1063385677
* Copyright ©2014 Lover雪儿
********************************************
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
* 博客园: http://www.cnblogs.com/lihaiyan/
* 邮箱:1063385677@qq.com
* QQ: 1063385677
* Copyright ©2014 Lover雪儿
********************************************
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。