異步通知:linux
驅動程序的所謂異步通知,就是說並非應用程序來對驅動程序操做的,而是驅動程序查詢到有事件發生或者有數據發生變化的時候通知應用程序。角色發生了變化,應用程序由主動改成被動執行。異步
好比按鍵驅動:async
一、有不斷進行查詢引腳狀態的,CPU資源消耗很是的打;函數
二、有中斷操做的,發生按鍵事件後採起執行相關事件處理函數,須要應用程序不斷執行read函數,使得不能去幹其它事情;spa
三、poll機制,改善了中斷方式操做,在應用程序上當沒有事件發生時,會跳去read函數繼續執行其它的任務,知道有事件發生才返回;code
四、異步通知,也即咱們本次講的,讓驅動程序本身告訴咱們事件發生,咱們採起執行。blog
爲了使設備支持異步通知機制,驅動程序中涉及如下3項工做:
1. 支持F_SETOWN命令,能在這個控制命令處理中設置filp->f_owner爲對應進程ID。
不過此項工做已由內核完成,設備驅動無須處理。
2. 支持F_SETFL命令的處理,每當FASYNC標誌改變時,驅動程序中的fasync()函數將得以執行。
驅動中應該實現fasync()函數。
3. 在設備資源可得到時,調用kill_fasync()函數激發相應的信號進程
應用程序:
fcntl(fd, F_SETOWN, getpid()); // 告訴內核,發給誰事件
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC); // 改變fasync標記,最終會調用到驅動的faync > fasync_helper:初始化/釋放fasync_struct資源
相關參考代碼以下:
fifth_drv.c
#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 <unistd.h>
#include <fcntl.h>
/* fifthdrvtest
*/
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;
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);
while (1)
{
sleep(1000);
}
return 0;
}
Makefile
KERN_DIR = /work/system/linux-2.6.22.6 all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += fifth_drv.o
fifthdrvtest.c
#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 <unistd.h> #include <fcntl.h> /* fifthdrvtest */ 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; 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); while (1) { sleep(1000); } return 0; }