韦东山驱动视频笔记——4.字符设备驱动程序之异步通知

linux内核版本:linux-2.6.30.4 

目的:我们前面写的几个驱动程序不管是查询方式、中断方式还是poll方式,都要求我们应用程序去主动的查询,看有没有按键发生,要想实现不需要让应用程序主动去查询,而是按键产生后,由驱动主动告诉应用,就要实现异步通知方式。

为了使设备支持异步通知机制,驱动程序中涉及以下3项工作:

1.支持F_SETOWN命令,能在这个控制命令处理中设置file->f_owner为对应进程ID,不过此项工作已由内核完成,设备驱动无须处理

2.支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行,驱动中应该实现fasync()函数

3.在设备资源可获得时,调用kill_fasync()函数激发相应的信号

  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 *fifth_drv_class;  
 16 static struct class_device  *fifth_drv_class_dev;  
 17   
 18 static volatile unsigned long *gpfcon;  
 19 static volatile unsigned long *gpfdat;  
 20 static int major;  
 21   
 22   
 23 struct pin_desc   
 24 {  
 25     unsigned int pin;  
 26     unsigned int key_val;  
 27 };  
 28   
 29 static unsigned char key_val;  
 30   
 31 static struct pin_desc pins_desc[4] =   
 32 {  
 33     {S3C2410_GPF1, 0x01},  
 34     {S3C2410_GPF4, 0x02},  
 35     {S3C2410_GPF2, 0x03},  
 36     {S3C2410_GPF0, 0x04},  
 37 };  
 38   
 39 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  
 40 static volatile int ev_press = 0;  
 41 static struct fasync_struct *button_async;  
 42   
 43   
 44 static irqreturn_t buttons_irq(int irq, void *dev_id)  
 45 {  
 46     struct pin_desc *pin = (struct pin_desc *)dev_id;  
 47     unsigned int pinval;  
 48     pinval = s3c2410_gpio_getpin(pin->pin);  
 49   
 50     if (pinval)  
 51     {  
 52         //松开  
 53         key_val = 0x80 | pin->key_val;  
 54     }  
 55     else  
 56     {  
 57         //按下  
 58         key_val = pin->key_val;  
 59     }  
 60   
 61     wake_up_interruptible(&button_waitq);  
 62     ev_press = 1;  
 63     kill_fasync(&button_async, SIGIO, POLL_IN);  
 64       
 65     return IRQ_HANDLED;  
 66 }  
 67   
 68   
 69 static int fifth_drv_open(struct inode *inode, struct file *file)  
 70 {  
 71     request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S1", &pins_desc[0]);  
 72     request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S2", &pins_desc[1]);  
 73     request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S3", &pins_desc[2]);  
 74     request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "S4", &pins_desc[3]);  
 75     return 0;  
 76 }  
 77   
 78   
 79 static ssize_t fifth_drv_read(struct file *file, char __user *buf,  
 80             size_t count, loff_t *ppos)  
 81 {  
 82     if (count != 1)  
 83         return -EINVAL;  
 84     /*如果没有按键动作,休眠*/  
 85     wait_event_interruptible(button_waitq, ev_press);  
 86       
 87   
 88     /*如果有按键动作发生,返回键值*/  
 89     copy_to_user(buf, &key_val, 1);  
 90     ev_press = 0;  
 91     return 1;  
 92 }  
 93   
 94 static int fifth_drv_release(struct inode *inode, struct file *file)  
 95 {  
 96     free_irq(IRQ_EINT1, &pins_desc[0]);  
 97     free_irq(IRQ_EINT4, &pins_desc[1]);  
 98     free_irq(IRQ_EINT2, &pins_desc[2]);  
 99     free_irq(IRQ_EINT0, &pins_desc[3]);  
100     return 0;  
101 }  
102   
103 static unsigned int fifth_drv_poll(struct file *file, poll_table *wait)  
104   
105 {  
106     unsigned int mask = 0;  
107   
108     /*这并不会休眠,只是把当前进程挂到队列里*/  
109     poll_wait(file, &button_waitq, wait);  
110   
111     if (ev_press)  
112     {  
113         mask |= (POLLIN | POLLRDNORM);  
114     }  
115     return mask;  
116 }  
117   
118 static int fifth_drv_fasync(int fd, struct file *file, int on)  
119 {  
120     printk("driver:fifth_drv_fasync\n");  
121     return fasync_helper(fd, file, on, &button_async);  
122 }  
123   
124 static struct file_operations fifth_fops = {  
125     .owner = THIS_MODULE,  
126     .open = fifth_drv_open,  
127     .read = fifth_drv_read,  
128     .poll = fifth_drv_poll,  
129     .fasync = fifth_drv_fasync,  
130     .release  = fifth_drv_release,  
131 };  
132   
133 int fifth_init()  
134 {  
135     int ret;  
136     major = register_chrdev(0, "fifth_drv", &fifth_fops);  
137     fifth_drv_class = class_create(THIS_MODULE, "fifth_drv");  
138     device_create(fifth_drv_class, NULL, MKDEV(major, 0), NULL, "buttons");  
139   
140     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);  
141     gpfdat = gpfcon + 1;  
142       
143     return 0;  
144 }  
145 static void fifth_exit()  
146 {  
147     unregister_chrdev(major, "fifth_drv");  
148     device_destroy(fifth_drv_class, MKDEV(major, 0));  
149     class_destroy(fifth_drv_class);  
150     iounmap(gpfcon);  
151 }  
152   
153 module_init(fifth_init);  
154 module_exit(fifth_exit);  
155   
156 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 #include <signal.h>  
 7 #include <sys/types.h>  
 8 #include <unistd.h>  
 9 #include <fcntl.h>  
10   
11 /* fifthdrvtest  
12   */  
13     
14 int fd;  
15   
16 void my_signal_func(int signum)  
17 {  
18     unsigned char key_val;  
19     read(fd, &key_val, 1);  
20     printf("key_val ===0x%x\n", key_val);  
21 }  
22 int main(int argc, char **argv)  
23 {  
24     unsigned char key_val;  
25     int ret, oflags;  
26       
27     signal(SIGIO, my_signal_func);  
28       
29     fd = open("/dev/buttons", O_RDWR);  
30     if (fd < 0)  
31     {  
32         printf("can't open!\n");  
33     }  
34   
35     fcntl(fd, F_SETOWN, getpid());  
36     oflags = fcntl(fd, F_GETFL);  
37     fcntl(fd, F_SETFL, oflags|FASYNC);  
38     while (1)  
39     {  
40         sleep(1000);  
41     }  
42       
43     return 0;  
44 }  

运行效果:

 

 

posted @ 2013-08-08 11:20  linux_rookie  阅读(549)  评论(0编辑  收藏  举报