要弄明白这个问题,我们得从最基本的原理开始。我们知道,驱动程序运行在内核 空间中,应用程序运行
在用户空间中,两者是不能直接通信的。但在实际应用中,在设备已经准备好的时 候,我们希望通知用户
程序设备已经ok,用户程序可以读取了,这样应用程序就不需要一直查询该设备 的状态,从而节约了资源
,这就是异步通知。
好,那下一个问题就来了,这个过程如何实现呢?简单,两方面的工作。
一 驱动方面:
1. 在设备抽象的数据结构中增加一个struct fasync_struct的指针
2. 实现设备操作中的fasync函数,这个函数很简单,其主体就是调用内核的fasync_helper函数。
3. 在需要向用户空间通知的地方(例如中断中)调用内核的kill_fasync函数。
呵呵,简单吧,就三点。其中fasync_helper和kill_fasync都是内核函数,我们只需要调用就可以了。在
1中定义的指针是一个重要参数,fasync_helper和 kill_fasync会使用这个参数。
二 应用层方面
1. 利用signal的SIGIO信号的处理函数my_signal_fun
2. fcntl的F_SETOWN指令设置当前进程为设备文件owner
3. fcntl的F_SETFL指令设置FASYNC标志
完成了以上的工作的话,当内核执行到kill_fasync函数,用户空间SIGIO函数的处理函数就会被调用了。
呵呵,看起来不是很复杂把,让我们结合具体代码看看就更明白了。
驱动层:
中断处理函数
{
.........
kill_fasync (&button_async, SIGIO, POLL_IN);
.........
}
int fifth_drv_fasync(int fd, struct file *filp, int on)
{
printk("fifth_drv_fasync\n");
fasync_helper(fd, filp, on, &button_async);
//初始化button_async结构体
return 0;
}
static struct file_operations fifth_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = fifth_drv_open,
.read =
fifth_drv_read,
.release=
fifth_drv_close,
.poll = fifth_drv_poll,
.fasync = fifth_drv_fasync,
};
应用层:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
int fd;
void my_signal_fun(int signum)
{
unsigned char key_value;
read(fd,&key_value,1);
printf("key_value =0x%0x\n",key_value);
}
int main(int argv, char **argc)
{
int Oflags;
fd = open("/dev/buttons",O_RDWR);
if(fd < 0)
{
printf("can't open device\n");
}
signal(SIGIO,my_signal_fun);
//注册信号处理函数
fcntl(fd, F_SETOWN, getpid());
//告诉驱动 app的进程id
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);
//初始化驱动的异步结构体button_async
while(1)
{
sleep(1000);
}
return 0;
}