Linux驱动之异步通知

yuanheci 2023年08月08日 482次浏览

  阻塞与非阻塞是 APP 询问 驱动设备。
  异步通知是 驱动设备 主动通知 APP,可以使用信号来实现(类似于硬件上使用的“中断”,只不过信号是软件层次上的。算是在软件层次上对中断的一种模拟)。

1、流程图

image-1691461634509


2、分析

②:绑定信号与回调函数。使用sighandler_t signal(int signum, sighandler_t handler)
③:把 APP PID 告诉内核。同时,该 PID 会保存到该驱动的内核文件 file 结构体中。
④:读取该驱动程序文件的 Flag
⑤:设置 Flag 里面的 FASYNC 位为 1。当 FASYNC 位发生变化时,该驱动会调用驱动操作 drv_fasync 函数。
⑥:驱动开发者实现的函数。主要是调用 fasync_helper 函数。
⑦:调用 fasync_helper() 函数,主要是把 驱动程序内核文件 file 结构体绑定到 button_async->fa_file 中。而 file 包含了 APPPID。所以发送信号时,只需要使用 button_async 作为参数即可。
⑩:发送信号给对应的 APP。参数为 button_async
注:button_async 结构体由驱动开发者创建,维护。


3、APP 信号编程步骤

①:编写信号处理函数。

static void sig_func(int sig)
{
    int val;
    read(fd, &val, 4);
    printf("get button : 0x%x\n", val);
}

②:绑定信号与处理函数。

signal(SIGIO, sig_func);

③:打开驱动。

fd = open(argv[1], O_RDWR);

④:获取 PID ,告知内核。

fcntl(fd, F_SETOWN, getpid());

⑤:获取进程状态值。

flags = fcntl(fd, F_GETFL);

⑥:当前状态值添加异步功能,触发调用驱动异步处理函数。

fcntl(fd, F_SETFL, flags | FASYNC);

fcntl函数用法详解:

  fcntl函数,也就是file control,提供了对文件描述符的各种操作。另一个常见的控制文件描述符的属性和行为的系统调用是ioctl,而且ioctlfcntl能够执行更多的控制。但是,对于控制文件描述符常见的属性和行为,fcntl函数是由POSIX规范指定的首选方法

  • ioctl()是底层的系统调用(system call),所以跨平台特性不好。
  • fcntl则是被封装的函数,各个OS都是支持的。

fcntl 参数


4、KERNEL 信号编程步骤

①:定义异步结构体。
②:实现异步操作函数,并把该函数填充到设备内核驱动操作结构体中。
该函数内容主要调用 fasync_helper() 函数,初始化异步结构体。(把 file ,内核PID,交给异步结构体)
③:发送信号:kill_fasync

kill_fasync 函数:

  函数原型:void kill_fasync(struct fasync_struct **fp, int sig, int band) :

  • 功能:发送信号给 fp 参数绑定的进程。(by PID)
  • 参考路径:linux-5.12.8\fs\fcntl.c
  • fp:需要操作的 fasync_struct
  • sig:信号类型。
  • band:可读时设置为 POLL_IN;可写时设置为 POLL_OUT。当然该参数还可以填POLL_MSG。以上三个值在应用层接收时,si_code 分别为 0x010x020x03