【改进信号量】IMX257实现GPIO-IRQ中断按键获取键值驱动程序
2015-02-18 李海沿
前面我们使用POLL查询方式来实现GPIO-IRQ按键中断程序
这里我们来使用信号量,让我们的驱动同时只能有一个应用程序打开。
一、首先在前面代码的基础上来一个简单的信号
1.定义一个全局的整形变量
2.在打开函数中,每次进入打开函数canopen都自减1,
3.当我们不使用时,在realease 中canopen自加1
4.这样就实现了一个简单的信号量,我们编译,测试
当我们使用两个应用程序来同时打开设备时,看看会发生什么:
可以发现,由于我们后台已经打开一个应用程序了,所以,如果此时我们再用另外一个应用程序打开的话,则会报错,can't open
好了,到这里,我们已经基本上实现了一个简陋的信号量程序。
附上驱动代码
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 //信号量定义 58 static int canopen = 1; 59 60 //interrupt head 61 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait); 62 static volatile unsigned char ev_press; 63 64 static int major=0; 65 66 //auto to create device node 67 static struct class *drv_class = NULL; 68 static struct class_device *drv_class_dev = NULL; 69 70 71 /* 应用程序对设备文件/dev/key_query执行open(...)时, 72 * 就会调用key_open函数*/ 73 static int key_open(struct inode *inode, struct file *file) 74 { 75 printk("<0>function open!\n\n"); 76 if(--canopen != 0) 77 { 78 canopen ++; 79 return -EBUSY; 80 } 81 82 return 0; 83 } 84 85 /* 中断程序key_irq */ 86 static irqreturn_t key_irq(int irq, void *dev_id) 87 { 88 struct pin_desc * pindesc = (struct pin_desc *)dev_id; 89 //发生了中断 90 //printk("<0>function interrupt key_irq!\n\n"); 91 //获取按键键值 92 if(gpio_get_value(IOMUX_TO_GPIO(pindesc->pin))){ 93 /* 按下 */ 94 key_val = pindesc->key_val; 95 }else{ 96 key_val = 0x80 | pindesc->key_val; 97 } 98 printk("<0>get key 0x%x",key_val); 99 ev_press = 1; 100 wake_up_interruptible(&key_interrupt_wait); 101 102 return IRQ_RETVAL(IRQ_HANDLED); 103 } 104 105 106 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 107 { 108 int ret; 109 //如果按键没有按下,没有中断,休眠 110 //wait_event_interruptible(key_interrupt_wait,ev_press); 111 112 ret = copy_to_user(buff,&key_val,sizeof(key_val)); 113 if(ret){ 114 ; 115 } 116 ev_press = 0; 117 return sizeof(key_val); 118 119 //int cnt=0; 120 //unsigned char key_vals[8]; 121 122 /* 123 // reading the pins value 124 key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0; 125 key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0; 126 key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0; 127 key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0; 128 key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0; 129 key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0; 130 key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0; 131 key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0; 132 133 //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]); 134 */ 135 } 136 137 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 138 { 139 printk("<0>function write!\n\n"); 140 141 return 1; 142 } 143 144 static int key_release(struct inode *inode, struct file *filp) 145 { 146 canopen ++; 147 printk("<0>function release!\n\n"); 148 //释放中断 149 free_irq(IOMUX_TO_IRQ(GPIO2_21), &pins_desc[6]); 150 //free_irq(IOMUX_TO_IRQ(GPIO3_15),&pins_desc[7]); 151 free_irq(IOMUX_TO_IRQ(GPIO2_11), &pins_desc[5]); 152 free_irq(IOMUX_TO_IRQ(GPIO2_10), &pins_desc[4]); 153 free_irq(IOMUX_TO_IRQ(GPIO2_9), &pins_desc[3]); 154 //free_irq(IOMUX_TO_IRQ(GPIO2_8), &pins_desc[2]); 155 free_irq(IOMUX_TO_IRQ(GPIO2_7), &pins_desc[1]); 156 free_irq(IOMUX_TO_IRQ(GPIO2_6), &pins_desc[0]); 157 return 0; 158 } 159 160 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 161 { 162 int ret; 163 printk("<0>function ioctl!\n\n"); 164 switch (command) { 165 case key_input: 166 //设置所有的引脚为输入 167 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21)); 168 gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15)); 169 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10)); 170 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11)); 171 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8)); 172 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9)); 173 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6)); 174 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7)); 175 printk("<0>have setting all pins to gpio input mod !\n"); 176 //设置GPIO引脚为上拉模式 177 mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 178 mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 179 //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 180 mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 181 mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 182 mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 183 mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 184 //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 185 186 //设置GPIO引脚中断 ,下降沿触发 187 request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", &pins_desc[0]); 188 request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", &pins_desc[1]); 189 request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", &pins_desc[3]); 190 request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[4]); 191 request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", &pins_desc[5]); 192 request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", &pins_desc[6]); 193 //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO3_15", &pins_desc[7]); 194 //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_8", &pins_desc[2]); 195 printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !\n"); 196 197 break; 198 case version: 199 printk("<0>hello,the version is 0.1.0\n\n"); 200 break; 201 default: 202 printk("<0>command error \n"); 203 printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;\n"); 204 printk("<0>command: <key_input> <version>\n\n"); 205 return -1; 206 } 207 return 0; 208 } 209 static unsigned key_poll(struct file *file,poll_table *wait) 210 { 211 unsigned int mask = 0; 212 //程序不立即睡眠,而是继续等待 213 poll_wait(file,&key_interrupt_wait,wait); 214 //如果按键按下 215 if(ev_press) 216 mask |= POLLIN | POLLRDNORM; 217 218 return mask; 219 } 220 221 /* 这个结构是字符设备驱动程序的核心 222 * 当应用程序操作设备文件时所调用的open、read、write等函数, 223 * 最终会调用这个结构中指定的对应函数 224 */ 225 static struct file_operations key_fops = { 226 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 227 .open = key_open, 228 .read = key_read, 229 .write = key_write, 230 .release= key_release, 231 .ioctl = key_ioctl, 232 .poll = key_poll, 233 }; 234 235 /* 236 * 执行insmod命令时就会调用这个函数 237 */ 238 static int __init key_irq_init(void) 239 { 240 printk("<0>\nHello,this is %s module!\n\n",Driver_NAME); 241 //register and mknod 242 major = register_chrdev(0,Driver_NAME,&key_fops); 243 drv_class = class_create(THIS_MODULE,Driver_NAME); 244 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/ 245 246 //set all pins to GPIO mod ALF5 247 mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5); 248 mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5); 249 mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5); 250 mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5); 251 mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5); 252 mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5); 253 mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5); 254 mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5); 255 //request IOMUX GPIO 256 gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21"); 257 gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15"); 258 gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10"); 259 gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11"); 260 gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8"); 261 gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9"); 262 gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6"); 263 gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7"); 264 265 266 return 0; 267 } 268 269 /* 270 * 执行rmmod命令时就会调用这个函数 271 */ 272 static void __exit key_irq_exit(void) 273 { 274 printk("<0>\nGoodbye,%s!\n\n",Driver_NAME); 275 276 unregister_chrdev(major,Driver_NAME); 277 device_unregister(drv_class_dev); 278 class_destroy(drv_class); 279 280 /* free gpios */ 281 mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5); 282 mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5); 283 mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5); 284 mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5); 285 mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5); 286 mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5); 287 mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5); 288 mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5); 289 290 gpio_free(IOMUX_TO_GPIO(GPIO2_21)); 291 gpio_free(IOMUX_TO_GPIO(GPIO3_15)); 292 gpio_free(IOMUX_TO_GPIO(GPIO2_10)); 293 gpio_free(IOMUX_TO_GPIO(GPIO2_11)); 294 gpio_free(IOMUX_TO_GPIO(GPIO2_8)); 295 gpio_free(IOMUX_TO_GPIO(GPIO2_9)); 296 gpio_free(IOMUX_TO_GPIO(GPIO2_6)); 297 gpio_free(IOMUX_TO_GPIO(GPIO2_7)); 298 299 } 300 301 /* 这两行指定驱动程序的初始化函数和卸载函数 */ 302 module_init(key_irq_init); 303 module_exit(key_irq_exit); 304 305 /* 描述驱动程序的一些信息,不是必须的 */ 306 MODULE_AUTHOR("Lover雪"); 307 MODULE_VERSION("0.1.0"); 308 MODULE_DESCRIPTION("IMX257 key Driver"); 309 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 #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 !!!\n"); 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\n"); 41 else{ 42 read(fd,key_val,1); 43 printf("%04d key pressed: 0x%x\n",cnt++,key_val[0]); 44 } 45 } 46 return 0; 47 }
二、改进 原子操作
由于前面的代码中信号量自减和检测信号量不是同时进行的,可能被打断,虽然概率很小,但是,也是有可能会发生。
为了避免这个问题,这里我们使用原子操作来实现信号量的改变。
所谓原子操作,就是不可被打断,从而保证了前面我们所说到的问题。
具体方法如下。
atomic_t v = ATOMIC_INIT(0); //定义原子信号v,并且赋初值为0
atomic_read(atomic_t *v); //返回原子变量的值
void atomic_inc(atomic_t *v); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
int atomic_dec_and_test(atomic_t *v);
//自减操作后测试是否为0,为0则返回true,否则返回false
驱动程序中修改如下:
1. 定义原子信号canopen,并且赋初值1
2.在open函数中检测信号量是否为1,否则就无法打开。
3.在释放函数中信号量值加1
4.编译和测试,可以发现结果和上面的代码一样
附上驱动程序源程序:
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 //信号量定义 58 //static int canopen = 1; 59 //定义原子信号量 60 static atomic_t canopen = ATOMIC_INIT(1); //定义原子信号canopen,并且赋初值1 61 62 //interrupt head 63 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait); 64 static volatile unsigned char ev_press; 65 66 static int major=0; 67 68 //auto to create device node 69 static struct class *drv_class = NULL; 70 static struct class_device *drv_class_dev = NULL; 71 72 73 /* 应用程序对设备文件/dev/key_query执行open(...)时, 74 * 就会调用key_open函数*/ 75 static int key_open(struct inode *inode, struct file *file) 76 { 77 printk("<0>function open!\n\n"); 78 //if(--canopen != 0) 79 if(!atomic_dec_and_test(&canopen)) 80 { 81 //canopen ++; 82 atomic_inc(&canopen); 83 return -EBUSY; 84 } 85 86 return 0; 87 } 88 89 /* 中断程序key_irq */ 90 static irqreturn_t key_irq(int irq, void *dev_id) 91 { 92 struct pin_desc * pindesc = (struct pin_desc *)dev_id; 93 //发生了中断 94 //printk("<0>function interrupt key_irq!\n\n"); 95 //获取按键键值 96 if(gpio_get_value(IOMUX_TO_GPIO(pindesc->pin))){ 97 /* 按下 */ 98 key_val = pindesc->key_val; 99 }else{ 100 key_val = 0x80 | pindesc->key_val; 101 } 102 printk("<0>get key 0x%x",key_val); 103 ev_press = 1; 104 wake_up_interruptible(&key_interrupt_wait); 105 106 return IRQ_RETVAL(IRQ_HANDLED); 107 } 108 109 110 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 111 { 112 int ret; 113 //如果按键没有按下,没有中断,休眠 114 //wait_event_interruptible(key_interrupt_wait,ev_press); 115 116 ret = copy_to_user(buff,&key_val,sizeof(key_val)); 117 if(ret){ 118 ; 119 } 120 ev_press = 0; 121 return sizeof(key_val); 122 123 //int cnt=0; 124 //unsigned char key_vals[8]; 125 126 /* 127 // reading the pins value 128 key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0; 129 key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0; 130 key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0; 131 key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0; 132 key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0; 133 key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0; 134 key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0; 135 key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0; 136 137 //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]); 138 */ 139 } 140 141 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 142 { 143 printk("<0>function write!\n\n"); 144 145 return 1; 146 } 147 148 static int key_release(struct inode *inode, struct file *filp) 149 { 150 //canopen ++; 151 atomic_inc(&canopen); 152 printk("<0>function release!\n\n"); 153 //释放中断 154 free_irq(IOMUX_TO_IRQ(GPIO2_21), &pins_desc[6]); 155 //free_irq(IOMUX_TO_IRQ(GPIO3_15),&pins_desc[7]); 156 free_irq(IOMUX_TO_IRQ(GPIO2_11), &pins_desc[5]); 157 free_irq(IOMUX_TO_IRQ(GPIO2_10), &pins_desc[4]); 158 free_irq(IOMUX_TO_IRQ(GPIO2_9), &pins_desc[3]); 159 //free_irq(IOMUX_TO_IRQ(GPIO2_8), &pins_desc[2]); 160 free_irq(IOMUX_TO_IRQ(GPIO2_7), &pins_desc[1]); 161 free_irq(IOMUX_TO_IRQ(GPIO2_6), &pins_desc[0]); 162 return 0; 163 } 164 165 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 166 { 167 int ret; 168 printk("<0>function ioctl!\n\n"); 169 switch (command) { 170 case key_input: 171 //设置所有的引脚为输入 172 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21)); 173 gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15)); 174 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10)); 175 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11)); 176 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8)); 177 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9)); 178 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6)); 179 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7)); 180 printk("<0>have setting all pins to gpio input mod !\n"); 181 //设置GPIO引脚为上拉模式 182 mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 183 mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 184 //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 185 mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 186 mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 187 mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 188 mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 189 //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 190 191 //设置GPIO引脚中断 ,下降沿触发 192 request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", &pins_desc[0]); 193 request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", &pins_desc[1]); 194 request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", &pins_desc[3]); 195 request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[4]); 196 request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", &pins_desc[5]); 197 request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", &pins_desc[6]); 198 //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO3_15", &pins_desc[7]); 199 //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_8", &pins_desc[2]); 200 printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !\n"); 201 202 break; 203 case version: 204 printk("<0>hello,the version is 0.1.0\n\n"); 205 break; 206 default: 207 printk("<0>command error \n"); 208 printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;\n"); 209 printk("<0>command: <key_input> <version>\n\n"); 210 return -1; 211 } 212 return 0; 213 } 214 static unsigned key_poll(struct file *file,poll_table *wait) 215 { 216 unsigned int mask = 0; 217 //程序不立即睡眠,而是继续等待 218 poll_wait(file,&key_interrupt_wait,wait); 219 //如果按键按下 220 if(ev_press) 221 mask |= POLLIN | POLLRDNORM; 222 223 return mask; 224 } 225 226 /* 这个结构是字符设备驱动程序的核心 227 * 当应用程序操作设备文件时所调用的open、read、write等函数, 228 * 最终会调用这个结构中指定的对应函数 229 */ 230 static struct file_operations key_fops = { 231 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 232 .open = key_open, 233 .read = key_read, 234 .write = key_write, 235 .release= key_release, 236 .ioctl = key_ioctl, 237 .poll = key_poll, 238 }; 239 240 /* 241 * 执行insmod命令时就会调用这个函数 242 */ 243 static int __init key_irq_init(void) 244 { 245 printk("<0>\nHello,this is %s module!\n\n",Driver_NAME); 246 //register and mknod 247 major = register_chrdev(0,Driver_NAME,&key_fops); 248 drv_class = class_create(THIS_MODULE,Driver_NAME); 249 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/ 250 251 //set all pins to GPIO mod ALF5 252 mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5); 253 mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5); 254 mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5); 255 mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5); 256 mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5); 257 mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5); 258 mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5); 259 mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5); 260 //request IOMUX GPIO 261 gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21"); 262 gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15"); 263 gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10"); 264 gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11"); 265 gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8"); 266 gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9"); 267 gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6"); 268 gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7"); 269 270 271 return 0; 272 } 273 274 /* 275 * 执行rmmod命令时就会调用这个函数 276 */ 277 static void __exit key_irq_exit(void) 278 { 279 printk("<0>\nGoodbye,%s!\n\n",Driver_NAME); 280 281 unregister_chrdev(major,Driver_NAME); 282 device_unregister(drv_class_dev); 283 class_destroy(drv_class); 284 285 /* free gpios */ 286 mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5); 287 mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5); 288 mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5); 289 mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5); 290 mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5); 291 mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5); 292 mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5); 293 mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5); 294 295 gpio_free(IOMUX_TO_GPIO(GPIO2_21)); 296 gpio_free(IOMUX_TO_GPIO(GPIO3_15)); 297 gpio_free(IOMUX_TO_GPIO(GPIO2_10)); 298 gpio_free(IOMUX_TO_GPIO(GPIO2_11)); 299 gpio_free(IOMUX_TO_GPIO(GPIO2_8)); 300 gpio_free(IOMUX_TO_GPIO(GPIO2_9)); 301 gpio_free(IOMUX_TO_GPIO(GPIO2_6)); 302 gpio_free(IOMUX_TO_GPIO(GPIO2_7)); 303 304 } 305 306 /* 这两行指定驱动程序的初始化函数和卸载函数 */ 307 module_init(key_irq_init); 308 module_exit(key_irq_exit); 309 310 /* 描述驱动程序的一些信息,不是必须的 */ 311 MODULE_AUTHOR("Lover雪"); 312 MODULE_VERSION("0.1.0"); 313 MODULE_DESCRIPTION("IMX257 key Driver"); 314 MODULE_LICENSE("GPL");
三、改进 信号量
前面的代码中,如果驱动程序已经有一个应用程序在使用是,如果是另一个驱动程序再次来申请,则会报错can't open直接退出,我们如何让其不退出呢,而是在等待队列中等待信号量呢?
使用信号量,方法如下:
struct semaphore sem; //定义信号量
void sema_init(struct semaphore *sem, int val); //初始化信号量
void init_MUTEX(struct semaphore *sem); //初始化信号量为0
void down(struct semaphore *sem); //获取信号量
int down_interruptible(struct semaphore *sem);
int down_trylock(struct semaphore *sem); //获取信号量,不成功则返回
void up(struct semaphore *sem); //释放信号量
操作步骤:
1.定义信号量
2.在init函数中初始化信号量
3.和前面一样在open函数中申请信号量
4.在release函数中释放信号量
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 //信号量定义 58 //static int canopen = 1; 59 //定义原子信号量 60 //static atomic_t canopen = ATOMIC_INIT(1); //定义原子信号canopen,并且赋初值1 61 //定义信号量 62 struct semaphore canopen; //定义一个信号量 63 64 //interrupt head 65 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait); 66 static volatile unsigned char ev_press; 67 68 static int major=0; 69 70 //auto to create device node 71 static struct class *drv_class = NULL; 72 static struct class_device *drv_class_dev = NULL; 73 74 75 /* 应用程序对设备文件/dev/key_query执行open(...)时, 76 * 就会调用key_open函数*/ 77 static int key_open(struct inode *inode, struct file *file) 78 { 79 printk("<0>function open!\n\n"); 80 down(&canopen); //申请信号量 81 //if(--canopen != 0) 82 /*if(!atomic_dec_and_test(&canopen)) 83 { 84 //canopen ++; 85 atomic_inc(&canopen); 86 return -EBUSY; 87 }*/ 88 89 return 0; 90 } 91 92 /* 中断程序key_irq */ 93 static irqreturn_t key_irq(int irq, void *dev_id) 94 { 95 struct pin_desc * pindesc = (struct pin_desc *)dev_id; 96 //发生了中断 97 //printk("<0>function interrupt key_irq!\n\n"); 98 //获取按键键值 99 if(gpio_get_value(IOMUX_TO_GPIO(pindesc->pin))){ 100 /* 按下 */ 101 key_val = pindesc->key_val; 102 }else{ 103 key_val = 0x80 | pindesc->key_val; 104 } 105 printk("<0>get key 0x%x",key_val); 106 ev_press = 1; 107 wake_up_interruptible(&key_interrupt_wait); 108 109 return IRQ_RETVAL(IRQ_HANDLED); 110 } 111 112 113 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 114 { 115 int ret; 116 //如果按键没有按下,没有中断,休眠 117 //wait_event_interruptible(key_interrupt_wait,ev_press); 118 119 ret = copy_to_user(buff,&key_val,sizeof(key_val)); 120 if(ret){ 121 ; 122 } 123 ev_press = 0; 124 return sizeof(key_val); 125 126 //int cnt=0; 127 //unsigned char key_vals[8]; 128 129 /* 130 // reading the pins value 131 key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0; 132 key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0; 133 key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0; 134 key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0; 135 key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0; 136 key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0; 137 key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0; 138 key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0; 139 140 //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]); 141 */ 142 } 143 144 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 145 { 146 printk("<0>function write!\n\n"); 147 148 return 1; 149 } 150 151 static int key_release(struct inode *inode, struct file *filp) 152 { 153 //canopen ++; 154 //atomic_inc(&canopen); 155 up(&canopen); 156 printk("<0>function release!\n\n"); 157 //释放中断 158 free_irq(IOMUX_TO_IRQ(GPIO2_21), &pins_desc[6]); 159 //free_irq(IOMUX_TO_IRQ(GPIO3_15),&pins_desc[7]); 160 free_irq(IOMUX_TO_IRQ(GPIO2_11), &pins_desc[5]); 161 free_irq(IOMUX_TO_IRQ(GPIO2_10), &pins_desc[4]); 162 free_irq(IOMUX_TO_IRQ(GPIO2_9), &pins_desc[3]); 163 //free_irq(IOMUX_TO_IRQ(GPIO2_8), &pins_desc[2]); 164 free_irq(IOMUX_TO_IRQ(GPIO2_7), &pins_desc[1]); 165 free_irq(IOMUX_TO_IRQ(GPIO2_6), &pins_desc[0]); 166 return 0; 167 } 168 169 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 170 { 171 int ret; 172 printk("<0>function ioctl!\n\n"); 173 switch (command) { 174 case key_input: 175 //设置所有的引脚为输入 176 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21)); 177 gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15)); 178 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10)); 179 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11)); 180 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8)); 181 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9)); 182 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6)); 183 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7)); 184 printk("<0>have setting all pins to gpio input mod !\n"); 185 //设置GPIO引脚为上拉模式 186 mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 187 mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 188 //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 189 mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 190 mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 191 mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 192 mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 193 //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 194 195 //设置GPIO引脚中断 ,下降沿触发 196 request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", &pins_desc[0]); 197 request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", &pins_desc[1]); 198 request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", &pins_desc[3]); 199 request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[4]); 200 request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", &pins_desc[5]); 201 request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", &pins_desc[6]); 202 //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO3_15", &pins_desc[7]); 203 //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_8", &pins_desc[2]); 204 printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !\n"); 205 206 break; 207 case version: 208 printk("<0>hello,the version is 0.1.0\n\n"); 209 break; 210 default: 211 printk("<0>command error \n"); 212 printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;\n"); 213 printk("<0>command: <key_input> <version>\n\n"); 214 return -1; 215 } 216 return 0; 217 } 218 static unsigned key_poll(struct file *file,poll_table *wait) 219 { 220 unsigned int mask = 0; 221 //程序不立即睡眠,而是继续等待 222 poll_wait(file,&key_interrupt_wait,wait); 223 //如果按键按下 224 if(ev_press) 225 mask |= POLLIN | POLLRDNORM; 226 227 return mask; 228 } 229 230 /* 这个结构是字符设备驱动程序的核心 231 * 当应用程序操作设备文件时所调用的open、read、write等函数, 232 * 最终会调用这个结构中指定的对应函数 233 */ 234 static struct file_operations key_fops = { 235 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 236 .open = key_open, 237 .read = key_read, 238 .write = key_write, 239 .release= key_release, 240 .ioctl = key_ioctl, 241 .poll = key_poll, 242 }; 243 244 /* 245 * 执行insmod命令时就会调用这个函数 246 */ 247 static int __init key_irq_init(void) 248 { 249 printk("<0>\nHello,this is %s module!\n\n",Driver_NAME); 250 //register and mknod 251 major = register_chrdev(0,Driver_NAME,&key_fops); 252 drv_class = class_create(THIS_MODULE,Driver_NAME); 253 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/ 254 sema_init(&canopen,1); //初始化信号量为1 255 256 //set all pins to GPIO mod ALF5 257 mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5); 258 mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5); 259 mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5); 260 mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5); 261 mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5); 262 mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5); 263 mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5); 264 mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5); 265 //request IOMUX GPIO 266 gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21"); 267 gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15"); 268 gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10"); 269 gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11"); 270 gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8"); 271 gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9"); 272 gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6"); 273 gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7"); 274 275 276 return 0; 277 } 278 279 /* 280 * 执行rmmod命令时就会调用这个函数 281 */ 282 static void __exit key_irq_exit(void) 283 { 284 printk("<0>\nGoodbye,%s!\n\n",Driver_NAME); 285 286 unregister_chrdev(major,Driver_NAME); 287 device_unregister(drv_class_dev); 288 class_destroy(drv_class); 289 290 /* free gpios */ 291 mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5); 292 mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5); 293 mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5); 294 mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5); 295 mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5); 296 mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5); 297 mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5); 298 mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5); 299 300 gpio_free(IOMUX_TO_GPIO(GPIO2_21)); 301 gpio_free(IOMUX_TO_GPIO(GPIO3_15)); 302 gpio_free(IOMUX_TO_GPIO(GPIO2_10)); 303 gpio_free(IOMUX_TO_GPIO(GPIO2_11)); 304 gpio_free(IOMUX_TO_GPIO(GPIO2_8)); 305 gpio_free(IOMUX_TO_GPIO(GPIO2_9)); 306 gpio_free(IOMUX_TO_GPIO(GPIO2_6)); 307 gpio_free(IOMUX_TO_GPIO(GPIO2_7)); 308 309 } 310 311 /* 这两行指定驱动程序的初始化函数和卸载函数 */ 312 module_init(key_irq_init); 313 module_exit(key_irq_exit); 314 315 /* 描述驱动程序的一些信息,不是必须的 */ 316 MODULE_AUTHOR("Lover雪"); 317 MODULE_VERSION("0.1.0"); 318 MODULE_DESCRIPTION("IMX257 key Driver"); 319 MODULE_LICENSE("GPL");
四、改进 应用程序不阻塞,属性O_NONBLOCK
实现不阻塞操作,在开打开文件是,要加入属性O_NONBLOCK
1.在应用程序中:加入属性O_NONBLOCK
2.接下来就是在驱动程序中实现对O_NONBLOCK的解析
首先注释前面信号量操作相关的代码:
在read函数中,我们用file结构体来获取我们的flag
if(filp->f_flags & O_NONBLOCK) //判断是否设置O_NONBLOCK
如果定义了,则不再会运行代码
wait_event_interruptible(key_interrupt_wait,ev_press);
那也就不会阻塞
3.为了让应用程序不会运行太快,这里增加一个延时5s
4.编译测试
附上驱动程序代码:
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 //信号量定义 58 //static int canopen = 1; 59 //定义原子信号量 60 //static atomic_t canopen = ATOMIC_INIT(1); //定义原子信号canopen,并且赋初值1 61 //定义信号量 62 //struct semaphore canopen; //定义一个信号量 63 64 //interrupt head 65 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait); 66 static volatile unsigned char ev_press; 67 68 static int major=0; 69 70 //auto to create device node 71 static struct class *drv_class = NULL; 72 static struct class_device *drv_class_dev = NULL; 73 74 75 /* 应用程序对设备文件/dev/key_query执行open(...)时, 76 * 就会调用key_open函数*/ 77 static int key_open(struct inode *inode, struct file *file) 78 { 79 printk("<0>function open!\n\n"); 80 // down(&canopen); //申请信号量 81 //if(--canopen != 0) 82 /*if(!atomic_dec_and_test(&canopen)) 83 { 84 //canopen ++; 85 atomic_inc(&canopen); 86 return -EBUSY; 87 }*/ 88 89 return 0; 90 } 91 92 /* 中断程序key_irq */ 93 static irqreturn_t key_irq(int irq, void *dev_id) 94 { 95 struct pin_desc * pindesc = (struct pin_desc *)dev_id; 96 //发生了中断 97 //printk("<0>function interrupt key_irq!\n\n"); 98 //获取按键键值 99 if(gpio_get_value(IOMUX_TO_GPIO(pindesc->pin))){ 100 /* 按下 */ 101 key_val = pindesc->key_val; 102 }else{ 103 key_val = 0x80 | pindesc->key_val; 104 } 105 printk("<0>get key 0x%x",key_val); 106 ev_press = 1; 107 wake_up_interruptible(&key_interrupt_wait); 108 109 return IRQ_RETVAL(IRQ_HANDLED); 110 } 111 112 113 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 114 { 115 int ret; 116 if(filp->f_flags & O_NONBLOCK){ 117 if(!ev_press) 118 return -EAGAIN; 119 }else{ 120 //如果按键没有按下,没有中断,休眠 121 wait_event_interruptible(key_interrupt_wait,ev_press); 122 } 123 ret = copy_to_user(buff,&key_val,sizeof(key_val)); 124 if(ret){ 125 ; 126 } 127 ev_press = 0; 128 return sizeof(key_val); 129 130 //int cnt=0; 131 //unsigned char key_vals[8]; 132 133 /* 134 // reading the pins value 135 key_vals[0] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_6)) ? 1 : 0; 136 key_vals[1] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_7)) ? 1 : 0; 137 key_vals[2] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_8)) ? 1 : 0; 138 key_vals[3] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_9)) ? 1 : 0; 139 key_vals[4] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_10)) ? 1 : 0; 140 key_vals[5] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_11)) ? 1 : 0; 141 key_vals[6] = gpio_get_value(IOMUX_TO_GPIO(GPIO2_21)) ? 1 : 0; 142 key_vals[7] = gpio_get_value(IOMUX_TO_GPIO(GPIO3_15)) ? 1 : 0; 143 144 //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]); 145 */ 146 } 147 148 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) 149 { 150 printk("<0>function write!\n\n"); 151 152 return 1; 153 } 154 155 static int key_release(struct inode *inode, struct file *filp) 156 { 157 //canopen ++; 158 //atomic_inc(&canopen); 159 //up(&canopen); 160 printk("<0>function release!\n\n"); 161 //释放中断 162 free_irq(IOMUX_TO_IRQ(GPIO2_21), &pins_desc[6]); 163 //free_irq(IOMUX_TO_IRQ(GPIO3_15),&pins_desc[7]); 164 free_irq(IOMUX_TO_IRQ(GPIO2_11), &pins_desc[5]); 165 free_irq(IOMUX_TO_IRQ(GPIO2_10), &pins_desc[4]); 166 free_irq(IOMUX_TO_IRQ(GPIO2_9), &pins_desc[3]); 167 //free_irq(IOMUX_TO_IRQ(GPIO2_8), &pins_desc[2]); 168 free_irq(IOMUX_TO_IRQ(GPIO2_7), &pins_desc[1]); 169 free_irq(IOMUX_TO_IRQ(GPIO2_6), &pins_desc[0]); 170 return 0; 171 } 172 173 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg) 174 { 175 int ret; 176 printk("<0>function ioctl!\n\n"); 177 switch (command) { 178 case key_input: 179 //设置所有的引脚为输入 180 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_21)); 181 gpio_direction_input(IOMUX_TO_GPIO(GPIO3_15)); 182 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10)); 183 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_11)); 184 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_8)); 185 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_9)); 186 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_6)); 187 gpio_direction_input(IOMUX_TO_GPIO(GPIO2_7)); 188 printk("<0>have setting all pins to gpio input mod !\n"); 189 //设置GPIO引脚为上拉模式 190 mxc_iomux_set_pad(GPIO2_6, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 191 mxc_iomux_set_pad(GPIO2_7, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 192 //mxc_iomux_set_pad(GPIO2_8, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 193 mxc_iomux_set_pad(GPIO2_9, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 194 mxc_iomux_set_pad(GPIO2_10, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 195 mxc_iomux_set_pad(GPIO2_11, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 196 mxc_iomux_set_pad(GPIO2_21, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 197 //mxc_iomux_set_pad(GPIO3_15, PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | PAD_CTL_PUE_PULL | PAD_CTL_22K_PU); 198 199 //设置GPIO引脚中断 ,下降沿触发 200 request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", &pins_desc[0]); 201 request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", &pins_desc[1]); 202 request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", &pins_desc[3]); 203 request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", &pins_desc[4]); 204 request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", &pins_desc[5]); 205 request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", &pins_desc[6]); 206 //request_irq(IOMUX_TO_IRQ(GPIO3_15), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO3_15", &pins_desc[7]); 207 //request_irq(IOMUX_TO_IRQ(GPIO2_8), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_8", &pins_desc[2]); 208 printk("<0>have setting all pins to gpio interrupt mod by IRQF_TRIGGER_FALLING !\n"); 209 210 break; 211 case version: 212 printk("<0>hello,the version is 0.1.0\n\n"); 213 break; 214 default: 215 printk("<0>command error \n"); 216 printk("<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;\n"); 217 printk("<0>command: <key_input> <version>\n\n"); 218 return -1; 219 } 220 return 0; 221 } 222 static unsigned key_poll(struct file *file,poll_table *wait) 223 { 224 unsigned int mask = 0; 225 //程序不立即睡眠,而是继续等待 226 poll_wait(file,&key_interrupt_wait,wait); 227 //如果按键按下 228 if(ev_press) 229 mask |= POLLIN | POLLRDNORM; 230 231 return mask; 232 } 233 234 /* 这个结构是字符设备驱动程序的核心 235 * 当应用程序操作设备文件时所调用的open、read、write等函数, 236 * 最终会调用这个结构中指定的对应函数 237 */ 238 static struct file_operations key_fops = { 239 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 240 .open = key_open, 241 .read = key_read, 242 .write = key_write, 243 .release= key_release, 244 .ioctl = key_ioctl, 245 .poll = key_poll, 246 }; 247 248 /* 249 * 执行insmod命令时就会调用这个函数 250 */ 251 static int __init key_irq_init(void) 252 { 253 printk("<0>\nHello,this is %s module!\n\n",Driver_NAME); 254 //register and mknod 255 major = register_chrdev(0,Driver_NAME,&key_fops); 256 drv_class = class_create(THIS_MODULE,Driver_NAME); 257 drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME); /*/dev/key_query*/ 258 //sema_init(&canopen,1); //初始化信号量为1 259 260 //set all pins to GPIO mod ALF5 261 mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5); 262 mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5); 263 mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5); 264 mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5); 265 mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5); 266 mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5); 267 mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5); 268 mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5); 269 //request IOMUX GPIO 270 gpio_request(IOMUX_TO_GPIO(GPIO2_21), "GPIO2_21"); 271 gpio_request(IOMUX_TO_GPIO(GPIO3_15), "GPIO3_15"); 272 gpio_request(IOMUX_TO_GPIO(GPIO2_10), "GPIO2_10"); 273 gpio_request(IOMUX_TO_GPIO(GPIO2_11), "GPIO2_11"); 274 gpio_request(IOMUX_TO_GPIO(GPIO2_8), "GPIO2_8"); 275 gpio_request(IOMUX_TO_GPIO(GPIO2_9), "GPIO2_9"); 276 gpio_request(IOMUX_TO_GPIO(GPIO2_6), "GPIO2_6"); 277 gpio_request(IOMUX_TO_GPIO(GPIO2_7), "GPIO2_7"); 278 279 280 return 0; 281 } 282 283 /* 284 * 执行rmmod命令时就会调用这个函数 285 */ 286 static void __exit key_irq_exit(void) 287 { 288 printk("<0>\nGoodbye,%s!\n\n",Driver_NAME); 289 290 unregister_chrdev(major,Driver_NAME); 291 device_unregister(drv_class_dev); 292 class_destroy(drv_class); 293 294 /* free gpios */ 295 mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5); 296 mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5); 297 mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5); 298 mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5); 299 mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5); 300 mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5); 301 mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5); 302 mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5); 303 304 gpio_free(IOMUX_TO_GPIO(GPIO2_21)); 305 gpio_free(IOMUX_TO_GPIO(GPIO3_15)); 306 gpio_free(IOMUX_TO_GPIO(GPIO2_10)); 307 gpio_free(IOMUX_TO_GPIO(GPIO2_11)); 308 gpio_free(IOMUX_TO_GPIO(GPIO2_8)); 309 gpio_free(IOMUX_TO_GPIO(GPIO2_9)); 310 gpio_free(IOMUX_TO_GPIO(GPIO2_6)); 311 gpio_free(IOMUX_TO_GPIO(GPIO2_7)); 312 313 } 314 315 /* 这两行指定驱动程序的初始化函数和卸载函数 */ 316 module_init(key_irq_init); 317 module_exit(key_irq_exit); 318 319 /* 描述驱动程序的一些信息,不是必须的 */ 320 MODULE_AUTHOR("Lover雪"); 321 MODULE_VERSION("0.1.0"); 322 MODULE_DESCRIPTION("IMX257 key Driver"); 323 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 #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 | O_NONBLOCK); 29 if(fd < 0){ 30 printf("can't open !!!\n"); 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 printf("%04d key pressed: 0x%x\n",cnt++,key_val[0]); 40 sleep(5); 41 /*if(ret == 0) 42 printf("time out\n"); 43 else{ 44 read(fd,key_val,1); 45 printf("%04d key pressed: 0x%x\n",cnt++,key_val[0]); 46 }*/ 47 } 48 return 0; 49 }
总结一下:
前面的这几种方法都是很简单的,如果熟练了单片机程序的话,在驱动程序的基础上理解这个信号量,是很简单的,加油!
对了,差点忘了,今天是除夕,在这里给爱好者们拜一个年:
新年快乐!祝大家学习顺利,心想事成,happy new year!!!
* 博客园: http://www.cnblogs.com/lihaiyan/
* 邮箱:1063385677@qq.com
* QQ: 1063385677
* Copyright ©2014 Lover雪儿
********************************************
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。