之前使用的中断+poll机制都是应用程序主动去调用read函数,有另外一种方法就是当按键按下时驱动触发应用程序取读取键值,该方法叫做异步通知。
进程之间要发信号需要明确:
①注册一个信号处理函数(在应用程序里)
②哪个进程发信号(驱动程序)
③哪个进程接收信号(应用程序,应用程序要告诉驱动程序PID即应用程序的进程号)
④怎么发送信号(驱动程序里使用)
1.代码
2.用到的库函数
a.驱动程序里:
1、kill_fasync(struct fasync_struct **fp, int sig, int band)原型
void kill_fasync(struct fasync_struct **fp, int sig, int band)
{
/* First a quick test without locking: usually
* the list is empty.
*/
if (*fp) {
read_lock(&fasync_lock);
/* reread *fp after obtaining the lock */
__kill_fasync(*fp, sig, band);
read_unlock(&fasync_lock);
}
}
使用;
kill_fasync(&button_async_queue, SIGIO, POLL_IN);
SIGIO:代表可以对IO口进行读写操作,还可以有其他值,在asm-arm/signal.h文件里定义其他值
POLL_IN:代表有数据已读取
2.定义全局变量:
static struct fasync_struct *button_async_queue;
3.对上面定义的结构体进行初始化:
static int fifth_drv_fasync(int fd, struct file *filp, int on)
{
return fasync_helper(fd, filp, on, &button_async_queue);
}
/* fasync_helper会进行初始化 */
之后在file_operations多定义一个成员函数 例:.fasync = fifth_drv_fasync
4.在中断服务程序里调用kill_fasync( )函数
b.应用程序里:
1.信号注册函数signal( ):将用户写的处理函数注册到内核里面
signal(SIGIO, signal_fun);
SIGIO:同上
signal_fun:自己写的处理函数
2.决定发给谁,如何调用
/* 得到进程号之后告诉内核应该发给哪个进程 */
fcntl(fd, F_SETOWN, getpid());
/* 标志位预改变 */
oflags = fcntl(fd, F_GETFL);
/* 改变tasync标记,最终会调用到驱动程序的
* fasync > fasync_helper:初始化/释放fasync_struct
*/
fcntl(fd, F_SETFL, oflags | FASYNC);
/* “fcntl(fd, F_SETFL, Oflags | FASYNC);”接口被调用时,
* 在函数中的“fasync_helper()”就会被调用
*/
3.信号处理函数
void signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, 1);
printf("key_val:0x%x\n", key_val);
}