韦东山驱动视频笔记——3.字符设备驱动程序之poll机制
linux内核版本:linux-2.6.30.4
目的:我们在中断方式的按键应用程序中,如果没有按键按下,read就会永远在那等待,所以如果在这个程序里还想做其他事就不可能了。因此我们这次改进它,让它在等待5秒钟,如果5秒钟内没有按键按下就返回,可以在read后面做其他事,只需要在驱动程序里加入poll机制就可以完成目的。
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/fs.h> 4 #include <linux/init.h> 5 #include <linux/delay.h> 6 #include <asm/uaccess.h> 7 #include <asm/irq.h> 8 #include <asm/io.h> 9 #include <linux/device.h> 10 #include <linux/irq.h> 11 #include <linux/interrupt.h> 12 #include <mach/regs-gpio.h> 13 #include <linux/poll.h> 14 15 static struct class *fourth_drv_class; 16 static struct class_device *fourth_drv_class_dev; 17 18 static volatile unsigned long *gpfcon; 19 static volatile unsigned long *gpfdat; 20 static int major; 21 22 struct pin_desc 23 { 24 unsigned int pin; 25 unsigned int key_val; 26 }; 27 28 static unsigned char key_val; 29 30 static struct pin_desc pins_desc[4] = 31 { 32 {S3C2410_GPF1, 0x01}, 33 {S3C2410_GPF4, 0x02}, 34 {S3C2410_GPF2, 0x03}, 35 {S3C2410_GPF0, 0x04}, 36 }; 37 38 static DECLARE_WAIT_QUEUE_HEAD(button_waitq); 39 static volatile int ev_press = 0; 40 41 static irqreturn_t buttons_irq(int irq, void *dev_id) 42 { 43 struct pin_desc *pin = (struct pin_desc *)dev_id; 44 unsigned int pinval; 45 pinval = s3c2410_gpio_getpin(pin->pin); 46 47 if (pinval) 48 { 49 //松开 50 key_val = 0x80 | pin->key_val; 51 } 52 else 53 { 54 //按下 55 key_val = pin->key_val; 56 } 57 58 wake_up_interruptible(&button_waitq); 59 ev_press = 1; 60 61 return IRQ_HANDLED; 62 } 63 64 65 static int fourth_drv_open(struct inode *inode, struct file *file) 66 { 67 request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S1", &pins_desc[0]); 68 request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S2", &pins_desc[1]); 69 request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S3", &pins_desc[2]); 70 request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S4", &pins_desc[3]); 71 return 0; 72 } 73 74 75 static ssize_t fourth_drv_read(struct file *file, char __user *buf, 76 size_t count, loff_t *ppos) 77 { 78 if (count != 1) 79 return -EINVAL; 80 /*如果没有按键动作,休眠*/ 81 wait_event_interruptible(button_waitq, ev_press); 82 83 84 /*如果有按键动作发生,返回键值*/ 85 copy_to_user(buf, &key_val, 1); 86 ev_press = 0; 87 return 1; 88 } 89 90 static int fourth_drv_release(struct inode *inode, struct file *file) 91 { 92 free_irq(IRQ_EINT1, &pins_desc[0]); 93 free_irq(IRQ_EINT4, &pins_desc[1]); 94 free_irq(IRQ_EINT2, &pins_desc[2]); 95 free_irq(IRQ_EINT0, &pins_desc[3]); 96 return 0; 97 } 98 99 static unsigned int fourth_drv_poll(struct file *file, poll_table *wait) 100 101 { 102 unsigned int mask = 0; 103 104 /*这并不会休眠,只是把当前进程挂到队列里*/ 105 poll_wait(file, &button_waitq, wait); 106 107 if (ev_press) 108 { 109 mask |= (POLLIN | POLLRDNORM); 110 } 111 return mask; 112 } 113 114 115 static struct file_operations fourth_fops = { 116 .owner = THIS_MODULE, 117 .open = fourth_drv_open, 118 .read = fourth_drv_read, 119 .poll = fourth_drv_poll, 120 .release = fourth_drv_release, 121 }; 122 123 int fourth_init() 124 { 125 int ret; 126 major = register_chrdev(0, "fourth_drv", &fourth_fops); 127 fourth_drv_class = class_create(THIS_MODULE, "fourth_drv"); 128 device_create(fourth_drv_class, NULL, MKDEV(major, 0), NULL, "buttons"); 129 130 gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); 131 gpfdat = gpfcon + 1; 132 133 return 0; 134 } 135 static void fourth_exit() 136 { 137 unregister_chrdev(major, "fourth_drv"); 138 device_destroy(fourth_drv_class, MKDEV(major, 0)); 139 class_destroy(fourth_drv_class); 140 iounmap(gpfcon); 141 } 142 143 module_init(fourth_init); 144 module_exit(fourth_exit); 145 146 MODULE_LICENSE("GPL");
测试程序:
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 #include <poll.h> 6 7 /* fourthdrvtest 8 */ 9 int main(int argc, char **argv) 10 { 11 int fd; 12 unsigned char key_val; 13 int ret; 14 struct pollfd fds[1]; 15 16 17 fd = open("/dev/buttons", O_RDWR); 18 if (fd < 0) 19 { 20 printf("can't open!\n"); 21 } 22 23 fds[0].fd = fd; 24 fds[0].events = POLLIN; 25 while (1) 26 { 27 ret = poll(fds, 1, 5000); 28 if (ret == 0) 29 { 30 printf("time out!\n"); 31 } 32 else 33 { 34 read(fd, &key_val, 1); 35 printf("key_val === 0x%x\n", key_val); 36 } 37 } 38 39 return 0; 40 }
运行效果: