按键驱动增加poll机制

poll机制的原理

运用层中的open会调用sys_open,那我们的运用程序中的poll也会调用到我们的sys_poll

sys_poll又会调用到do_sys_poll(.... , ...... ,&timeout_jiffies); 最后一个参数就是超时参数

do_sys_poll又会调用到

poll_initwait(&table);

poll_initwait>init_poll_funcptr(&pwp->pt,__pollwait); >pt->qproc=qproc//table->gproc=__pollwait

do_poll(nfds,head,&table,timeout)

do_poll里面做的事情是:

一来便有一个死循环

for(::)

{

if(do_poll(pfd,pt){ >mask=file->f_op->poll(file,pwait);return mask;//调用驱动中的poll函数

 count++;//如果驱动中的poll函数返回的不是0的话,那么count就++。

pt=NULL;


break的条件是1.count非0

  2.超时

  3.有信号等待处理

if(count || !*timeout || signal_pending(current)) //如果count不等于0的话就跳出了这个死循环,返回到应用程序里面去了,

break;

假设这些条件都不成立的话,就会休眠,休眠__timeout这么一段时间

__timeout=schedule_timeout(__timeout);//休眠

休眠这段时间之后,没什么事件发生,又会重新开始运行那个for循环,但是到达if条件的时候因为timeout等于0而返回

}


驱动中的pollwait(filp,&button_waitq,p);

就是把当前这个进程挂到button_waitq队列里面去 ,只是放到这个进程里面去,并不会休眠,休眠是在__timeout=schedule_timeout(__timeout)这里开始休眠的,如果当前有数据返还给用户的话,就是 mask |= POLLIN | POLLRDNORM; 否则的话就返回0. 如果返回0的话上面的count++就不会执行。


驱动代码如下

#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/gpio.h>
#include<linux/cdev.h>
#include <linux/poll.h>
int key_id;
struct cdev cdev;
dev_t devno;


/*等待队列头*/
wait_queue_head_t key_qaq;
/*中断事件标志,中断服务程序将它置为1,read函数将它置为0*/
unsigned int wait_val=0;
struct class *my_class;




static irqreturn_t key_func(int irq,void *dev_id)
{
key_id=(int)dev_id;


/*唤醒*/
wait_val=1;
wake_up(&key_qaq);




return 0;
}


static int key_open(struct inode *inode,struct file *file)
{


request_irq(IRQ_EINT(16),key_func,IRQF_TRIGGER_FALLING,"k1",1);
request_irq(IRQ_EINT(17),key_func,IRQF_TRIGGER_FALLING,"k2",2);
request_irq(IRQ_EINT(18),key_func,IRQF_TRIGGER_FALLING,"k3",3);
request_irq(IRQ_EINT(19),key_func,IRQF_TRIGGER_FALLING,"k4",4);
request_irq(IRQ_EINT(24),key_func,IRQF_TRIGGER_FALLING,"k5",5);
request_irq(IRQ_EINT(25),key_func,IRQF_TRIGGER_FALLING,"k6",6);
request_irq(IRQ_EINT(26),key_func,IRQF_TRIGGER_FALLING,"k7",7);
request_irq(IRQ_EINT(27),key_func,IRQF_TRIGGER_FALLING,"k8",8);


return 0;
}


static int key_close(struct inode *inode,struct file *file)
{


free_irq(IRQ_EINT(16),1);
free_irq(IRQ_EINT(17),2);
free_irq(IRQ_EINT(18),3);
free_irq(IRQ_EINT(19),4);
free_irq(IRQ_EINT(24),5);
free_irq(IRQ_EINT(25),6);
free_irq(IRQ_EINT(26),7);
free_irq(IRQ_EINT(27),8);


return 0;
}


ssize_t key_read(struct file *filp, char __user *buf, size_t size,loff_t *pos)
{
/*如果没有按键按下,休眠,让出CPU*/
wait_event(key_qaq,wait_val);
/*如果有按键按下*/
copy_to_user(buf,&key_id,sizeof(key_id)); 
wait_val=0;


return 0;
}




static unsigned key_poll(struct file *file, poll_table *wait)
{
unsigned int mask=0;
poll_wait(file,&key_qaq,wait);/*不会立即休眠,只是挂在那个队列上面去*/
if(wait_val)
mask |= POLLIN | POLLRDNORM;


return mask;
}


static struct file_operations key_fops =
{
.owner = THIS_MODULE,
.open = key_open,
.release = key_close,
.read = key_read,
.poll = key_poll,
};




static int __init key_poll_init(void)
{
cdev_init(&cdev,&key_fops);
alloc_chrdev_region(&devno, 0 , 1 , "mykey_poll");
cdev_add(&cdev, devno, 1);
my_class = class_create(THIS_MODULE, "key_poll_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
device_create(my_class, NULL, devno,NULL,"key_poll_driver");


init_waitqueue_head(&key_qaq);
return 0;
}


static void key_poll_exit(void)
{
device_destroy(my_class,devno);
class_destroy(my_class);
cdev_del(&cdev);
unregister_chrdev_region(devno,1);
}


module_init(key_poll_init);
module_exit(key_poll_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EIGHT_FIVE");

测试程序如下

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<poll.h>
int main(int argv,char **argc)
{
int fd;
int buf;
int ret;
struct pollfd fds[1];//poll 可以同时查询多个文件,我们这里只查询一个文件。
fd=open("/dev/key_poll_driver",0x666);
fds[0].fd=fd;
fds[0].events=POLLIN;//表示我们期待得到这个值用来表示有数据可读
while(1)
{
ret=poll(fds,1,5000);//第一个是查询文件,第二个是查询文件的数目,第三个参数是超时函数,以毫秒为单位,5000ms就是5s
if(ret==0)//如果为0的话表示有超时
{
printf("timeout\n");
}
else
{
read(fd,&buf,4);
printf("key_val =%d\n",buf);
}
}
return 0;


}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值