上一次用中断来实现按键驱动程序里面,如果我们一直没有按键按下触发中断应用程序会一直的在休眠,现在我们想让它隔一段时间就返回一个值要怎么做呢,这就是POLL机制,我们可以用poll机制来实现它,下面来分析一下这个poll机制:
我们知道当我们应用程序open,write..时,驱动程序里面也会有相应的open,write等函数(其实是产生了一个软中断,swi异常处理函数指针被组织成了一个表格,swi指令机器码的位[23:0]被用来索引,这样通过不同的swi
index指令就可以调用不同的swi异常处理函数,它们被称为系统调用,比如sys_open,sys_read,sys_poll等);那poll也是一样的,当我们应用程序poll时,驱动程序也会有一个poll,那我们现在就从sys_poll入手来分析poll机制是怎样的;
应用程序:poll
内核:sys_poll
do_sys_poll(.....,struct timespec *end_time)
poll_initwait(&table);
init_poll_funcptr(&pwq->pt,
__pollwait);>(table->qproc =
__pollwait)pt->qproc = qproc;
do_poll(nfds, head, &table,
end_time);
for (;;)
{
for (; pfd != pfd_end; pfd++) {
if (do_pollfd(pfd, pt)) {>mask =
file->f_op->poll(file, pwait);
//驱动poll
mask = poll_wait(file, &button_waitq, wait)
mask = __pollwait (filp,&button_waitq, p);
//把当前进程挂到button_waitq队列中
count++;//如果返回mask非0count++
pt = NULL;
//break条件count非0,timed_out非0
if (count || timed_out)
break;
}
}
if (end_time
&& !to) {
expire
= timespec_to_ktime(*end_time);
to = &expire;
}
timed_out = 1;//表示休眠结束,就会在上面跳出这个死循环
}
大致流程就是这样,不同内核版本所用的处理函数不一样,下面来总结一下大体流程
(1)应用程序poll时会调用内核syy_poll,sys_poll调用do_sys_poll;
(2)do_sys_poll再调用 poll_initwait(&table);来进行一些初始化,初始化结果是pt->qproc
= qproc; =table->qproc =
__pollwait ,这在后面调用驱动力poll时用到;
(3)然后调用 do_poll(nfds, head, &table,
end_time),进入一个死循环,在里面调用do_pollfd(pfd,
pt),这个函数其实就是调用 mask
= file->f_op->poll(file,
pwait),也就是调用我们驱动程序的poll,驱程序会调用poll_wait(file,
&button_waitq,
wait),跟踪下去就知道这个函数最后会调用p->qproc(filp, wait_address,
p),也就是我们第二部初始化了p->qproc(filp, wait_address,
p),所以这里是调用 __pollwait (filp,&button_waitq,
p),它实现功能是把当前进程挂到button_waitq队列中 还没有休眠;
(4)如果驱动poll返回一个非0的值,上面count++,这也就说明了有按键按下了,上面就会break跳出循环,返回一个非0值;
(5)如果驱动poll返回一个0,说明我们没按下按键,这是就会往下执行 if
(end_time &&
!to),to初始化时0,我们在应用程序时回传进一个 end_time ,end_time不是0时if (end_time
&& !to) {
expire = timespec_to_ktime(*end_time);
to = &expire;
}
会一直在这里循环,当她数到0时跳出;
(6)然后就是 timed_out = 1,由上面if (count ||
timed_out)可知,这时也会跳出这个死循环,这时会返回0;
下面我们先看我们应用程序:
#include
#include
#include
#include
#include //要把这个头文件加进来
int main()
{
int fd=-1;
unsigned char key;
int ret;//用来接收返回值
struct pollfd fds[1]; //定义一个struct
pollfd 结构体 //struct pollfd
{
// int fd; //short events;
//short revents;
};
fd = open("/dev/ccc",O_RDWR);
if(fd<0)
{
printf("can't open /dev/ccc\n");
return -1;
}
fds[0].fd = fd;//用来指定查询的驱动程序
fds[0].events =
POLLIN;//期待返回值,表示有数据等待读取,也就是说按键按下了
while(1)
{
ret =
poll(fds,1,5000);//查询一个文件,超时时间为5S
if(ret == 0)
{