之前已经体验过得方法有:
1、查询:耗资源
2、中断:read函数会一直等待,不返回
3、poll机制:指定超时时间
这三种方式共同点为:应用程序主动去读或者查询按键是否按下,所以下面将要使用驱动程序主动上报的方式,即异步通知
使用信号signal来通讯
举例:进程间发送信号
kill -9 PID——即kill进程将信号“9”发送给PID进程
#include <stdio.h>
#include <signal.h>
void my_signal_fun(signum)
{
static int cnt = 0;
printf("signal = %d, %d times\n", signum, ++cnt);
}
int main(int argc, char **argv)
{
signal(SIGUSR1, my_signal_fun);
while(1)
{
sleep(1000);
}
}
编译运行,则会一直在while1中休眠,使用kill -USR1 PID可以调用打印语句
使用要点:
1、注册一个信号处理函数
2、谁发出
3、发给谁处理
4、怎么发出信号
在实验中要达到的目标:
按下按键时,驱动去通知应用程序,那么这就要求,应用和驱动要联系起来
1、应用程序,注册信号处理函数
2、谁发:驱动程序
3、发给谁:应用程序,但是应用程序需要告诉内核自己的pid号,内核再告诉驱动
4、怎么发:驱动程序调用某个函数——kill_fasync
待续————
在中断唤醒程序 wake_up_interruptible(&button_waitq);后添加发送信号的函数
kill_fasync(&button_async, SIGIO, POLL_IN);
这个函数引入了rtc_async_queue类型的结构体
添加定义static struct fasync_struct *button_async;
这个是发送的代码,所以其中必须要指定发到哪儿,在这个结构体中应该会指定
static struct file_operations third_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = third_drv_open,
.read = third_drv_read,
.release = third_drv_close,
.poll = third_drv_poll,
.fasync = fifth_drv_fasync,
};
接着实现fifth_drv_fasync函数
staitc int fifth_drv_fasync (int fd, struct file *filpm, int on)
{
return fasync_helper(fd, filp, on, &button_async);
}
现在问题就是,这个fasync函数什么时候会被应用程序调用
int fd;
void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, 1);
printf("key_val: 0x%x\n", key_val);
}
int main(int argc, char ** argv)
{
unsigned char key_val;
int ret;
int Oflags;
以下是重点部分,分别是注册信号处理函数,将应用的pid告诉内核和驱动程序,设置flag为异步通知模式。
signal(SIGIO, my_signal_fun);
fcntl(fd, F_SETOWN, getpid());
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);
fd = open("/dev/buttons", O_RDWR);
if (fd<0)
{
printf("can't open\n");
}
while(1)
{
sleep(1000);
}
return 0;
}
这个时候,应用程序中的read函数并不是主动执行的,而是在信号处理函数中执行的,只有当驱动程序中的fasync函数被调用时,才会通知应用程序调用执行。
内核会做一些初始化的工作
return fasync_helper(fd, filp, on, &button_async);