八.poll系统调用操作接口函数
当程序需要进行对多个文件读写时,如果某个文件没有准备好,则系统就会处于读写阻塞的状态,这影响了其他文件的读写,为了避免读写阻塞,一般可以在应用程序中使用poll或者select函数。当poll函数返回时,会给出一个文件是否可读写的标志,应用程序根据不同的标志读写相应的文件,实现非阻塞的读写,poll()函数通过poll系统调用,调用对应设备驱动的poll()接口函数,poll返回不同的标志,告诉主进程文件是否可以读写,这些返回标志存放在include\asm\poll.h中
标志
含义
POLLIN
如果设备无阻塞的读,就返回该值
POLLRDNORM
通常的数据已经准备好,可以读了,就返回
该值。通常的做法是会返回(POLLLIN|POLLRDNORA)
POLLRDBAND
如果可以从设备读出带外数据,就返回该值,它只可在Linux内核的某些网络代码中使用,通常不用在设备驱动程序中
POLLPRI
如果可以无阻塞的读取高优先级(带外)数据,就返回该值,返回该值会导致select报告文件发生异常,以为select八带外数据当作异常处理
POLLHUP
当读设备的进程到达文件尾时,驱动程序必须返回该值,依照select的功能描述,调用select的进程被告知进程时可读的。
POLLERR
如果设备发生错误,就返回该值。
POLLOUT
如果设备可以无阻塞地些,就返回该值
POLLWRNORM
设备已经准备好,可以写了,就返回该值。通常地做法是(POLLOUT|POLLNORM)
POLLWRBAND
于POLLRDBAND类似
在本章地驱动程序中,Keypad_poll()函数在缓冲区有新数据时(当head!=tail),返回一个POLLIN|POLLRDNORM,告诉主进程有新的
九.在设备驱动中实现异步通知
虽然大多数时候阻塞型和非阻塞型操作的组合及poll方法可以有效查询设备是否可以读写,但是如果驱动程序能避免主动的查询,改主动为被动的信号通知触发,则可以提高程序的效率,这也就是异步通知的目的。异步通知向进程发送SIGIO信号,通知访问设备的进程,表示该设备已经准备好IO读写了。
之后就是如何实现异步通知的问题了,要启动异步通知,必须执行两个步骤:首先,须要制定某个作为文件的“属主”。文件属主的进程ID保存在filp->f_owner中,这可以通过fcntl()系统调用执行F_SETOWN命令设置。此外,用户程序还必须曙色之设备的FASYNC标志,以真正启动异步通知机制。这里的FASYNC标志也使用fcntl()设置。
在完成这两个步骤之后,当新数据到达时就会产生一个SIGNO信号,此信号发送到存放在filp->owner中的进程。
从驱动的角度看,则主要时通过调用两个内核提供的函数来实现就是了。他们分别是:int fasync_helper()和void kill_fasync();这两个函数定义在:include\Linux\fs\fcntl.h
要实现异步,驱动中只要如下编写即可
static struct fasync_struct *fasync;//首先是定义一个结构体
static int Keypad_release(struct inode *inode,struct file *filp)
{
Keypad_fasync(-1,filp,0);//这是一个异步通知
。。。。。。。
}
static int Keypad_fasync(int fd,struct file *filp,int on)
{
int retval;
retval=fasync_helper(fd,filp,on,&fasync);
if(retval<0)
return retval;
return 0;
}
到此为止,键盘驱动已经介绍完了,接下来就介绍下一个利用使用驱动的应用实例了。
以下程序的主体是一个条件循环,每次循环执行一次,就读取一次键值。
1。打开Keypad设备
#define DEV_NAME "/dev/Keypad"
int fb=0;
fb=open(DEV_NAME,O_RNONLY);
if(!fb){
printf("Error:cannot open Keypad device.\n");
exit(1);
}
printf("The Keypad device was opened successfully.\n");
}
2.读取键值
unsigned long keydata[2];
int input=1;
while(input!=0)
{
if(read(fd,(char*)keydata,sizeof(keydata))==-1){
printf("Error reading the keypad data");
close(fb);
exit(2);
}
if(keydata[0]){
switch(keydata[1]){
case 1:printf("KEYPUSED 1");//1键被按下
input=0;////下此循环退出
break;
。。。。。。。。。。。。。。。。。。
}
}
}
3。关闭Keypad设备
close(fb);
printf("Good bye Keypad");
键盘驱动到此介绍完毕!