前言
正在根据韦东山老师的视频和代码来学习写linux驱动,记录笔记在这里,方便复习与查阅
概述
异步通知机制能让驱动主动通知应用程序做某些事,而不需要应用程序不断查询驱动的状态来决定做什么事
如果想要要实现异步通知的功能
驱动程序需要做的事有:
- 新建一个信号并注册它
- 发送信号通知应用程序
应用程序需要做的事有:
- 收到信号后需要执行的函数
- 把这个函数与驱动程序的信号关联起来
疑问
- 应用程序的进程ID是不固定的,驱动如何知道要发送信号给谁?
解答疑问
- 应用程序需要执行某个函数调用驱动的fasync_helper函数
- fasync_helper会关联 应用程序进程 与 驱动程序的信号
- 之后,应用程序执行kill_fasync就能向应用程序进程发送信号
- 应用程序进程会根据信号类型,来执行对应注册的函数
参考资料http://blog.chinaunix.net/uid-20498191-id-1704861.html
知识点扩展
- kill_fasync 、fasync_helper
- signal、SIGIO
- fcntl
- getpid()
signal、SIGIO
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
这个博文写的非常好,可以看一看:
https://blog.csdn.net/weibo1230123/article/details/81505152
getpid()
获取当前pid
fcntl
fcntl函数的作用是改变已打开的文件性质
参考资料:https://www.cnblogs.com/zxc2man/p/7649240.html
个人理解下面几行代码可以 :
1、关联当前信号与进程ID
2、 给文件增加异步通知的文件状态标识
fcntl(fd, F_SETOWN, getpid());
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);
fasync_helper
哪个进程调用了fasync_helper,kill_fasync就向哪个进程发信号
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
kill_fasync用法
button_async通过fasync_helper关联到了应用程序上,kill_fasync根据这个就知道向谁发送数据了
kill_fasync (&button_async, SIGIO, POLL_IN);
贴上相关代码
在驱动程序中
//定义一个fasync_struct 类
static struct fasync_struct *button_async;
//调用这个函数发送信号通知应用程序
kill_fasync (&button_async, SIGIO, POLL_IN);
//fasync_helper作用就是初始化fasync,包括分配内存和设置属性
static int fifth_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: fifth_drv_fasync\n");
return fasync_helper (fd, filp, on, &button_async);
}
//通过file_operations 关联fifth_drv_fasync函数
static struct file_operations sencod_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,
};
在应用程序中
void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, 1);
printf("key_val: 0x%x\n", key_val);
}
signal(SIGIO, my_signal_fun);
fd = open("/dev/buttons", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
fcntl(fd, F_SETOWN, getpid());
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);