http://blog.csdn.net/huntinux/article/details/8699611
1)中断
在驱动中注册中断使用request_irq函数。参数依次为:中断号,中断处理函数, 中断触发方式和处理方式, 中断名字, 传递给中断处理函数的参数。
- static int key_drv_open(struct inode *inode, struct file *file)
- {
- printk("key_drv_open-interrupt-poll");
- request_irq(IRQ_EINT8, key_irq, IRQF_TRIGGER_FALLING, "k1", (void *)&keys[0]); //k1
- request_irq(IRQ_EINT11, key_irq, IRQF_TRIGGER_FALLING, "k2", (void *)&keys[1]); //k2
- return 0;
- }
- irqreturn_t key_irq(int irq, void * dev_id)
- {
- struct key_desc *p = (struct key_desc *)dev_id;
- key_val = p->val;
- ev_press = 1;
- wake_up_interruptible(&key_waitq);
- return 0;
- }
在程序退出的时候不要忘记将中断还回,这要用到free_irq函数,对于这个例子释放IRQ的代码为:
- free_irq(IRQ_EINT8, (void *)&keys[0]);
- free_irq(IRQ_EINT11, (void *)&keys[1]);
用户使用read函数的时候会调用驱动的相应函数,这里为
- static int key_drv_read(struct file *file, char __user *buf, size_t count, loff_t *loff)
- {
- wait_event_interruptible(key_waitq, ev_press);
- ev_press = 0;
- copy_to_user(buf, &key_val, sizeof(key_val));
- return 0;
- }
可以发现,用户在调用read函数的时候,驱动中对应的函数key_drv_read函数会使用wait_event_interruptible函数将进程挂起, 直到用户按下按键,ev_press变成1的时候(这个过程为: 用户按下按键--》发生中断--》进入中断处理函数key_irq--》将进程唤醒,并设置ev_press为1, 记录按键数值---》key_drv_read将按键数值返回),这时数据就绪,返回给用户即可。
2)poll
关于poll机制: 见文章最下面
首先, 在file_operation结构中填写驱动自己的poll函数
- static unsigned key_drv_poll(struct file *file, struct poll_table_struct *wait)
- {
- unsigned int mask = 0;
- poll_wait(file, &key_waitq, wait);
- if(ev_press)
- mask |= POLLIN | POLLRDNORM;
- return mask;
- }
- //file_operations
- static struct file_operations key_drv_fops = {
- .owner = THIS_MODULE,
- .open = key_drv_open,
- .read = key_drv_read,
- .release = key_drv_close,
- .poll = key_drv_poll,
- };
我们驱动中的poll函数会调用poll_wait函数将当前进程加入到key_waitq中(这个与中断中用到的队列为同一个)
用户程序使用poll函数来等待我们的程序一段时间,如果在指定事件内没有发生指定事件(这里为按键是否按下),那么就返回一个数值,这里为mask。
如果在等待事件内用户按下了按键,那么就进入中断处理函数,将en_press改为1, 然后key_drv_poll将返回数值改为: mask |= POLLIN | POLLRDNORM。
这样用户程序就可以根据不同的返回值来判断是否可以从设备中读取数据。
3)用户程序 或 测试程序:
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <poll.h>
- #define DEVNAME "/dev/keysintpoll"
- int main(){
- int fd;
- int val;
- struct pollfd fds[1];
- int ret;
- fd = open(DEVNAME, O_RDWR);
- if(fd < 0){
- perror(DEVNAME);
- return -1;
- }
- fds[0].fd = fd;
- fds[0].events = POLLIN;
- while(1){
- ret = poll(fds, 1, 5000);
- if(0 == ret){
- printf("time out.\n");
- }else{
- read(fd, &val, sizeof(val));
- printf("key value = %d\n", val);
- }
- }
- return 0;
- }
从用户执行程序开始进行分析:
用户程序调用poll
...... 省略若干过程
---->驱动程序的poll函数,这里为 key_drv_poll
---->poll_wait 将进程放入到队列key_waitq中(注意这里并没有将进程挂起, 真正的挂起操作在内核的do_sys_poll中完成,详细情况见下面的poll机制分析)
---->如果指定时间内用户没有按下按键(即ev_press没有变成1, 那么就返回0给用户程序,然后用户程序就打印 "time out" )
---->如果指定时间内用户按下了按键,那么就会发生中断,进入中断处理函数,记录相关信息,然后将进程唤醒,并将ev_press设置为1, 中断返回,key_drv_poll
将返回数值改为: POLLIN | POLLRDNORM,即用户程序执行poll得到的返回值不是0 , 表示设备就绪,可以对设备进行读操作
---->用户调用read,会进入驱动相应的read函数,这里为key_drv_read。此时,ev_press已经变成1, 所以不用等待就可以将数据返回给用户。