嵌入式核心及驅動開發之學習筆記(十) 非同步通訊+中斷實現讀取資料
阿新 • • 發佈:2018-11-27
對於linux一切都是檔案,驅動裝置在應用層也是以檔案的形式進行讀寫。之前學了阻塞、非阻塞、多路複用的方式讀裝置,它們都需要應用主動讀取。那麼應用層有沒有一種方式,當底層將資料準備好了,應用程式自動處理這些資料?通過非同步通訊可以實現,這有寫類似硬體層的中斷概念
驅動層(準備好了資料) --> 傳送特定訊號 --> 應用程式(跳轉到與之匹配的函式入口) --> 處理資料.....
非同步通訊:區別同步通訊,就是呼叫我(函式),我(函式)沒有接收完資料或者沒有得到結果之前,我不會返回
參考一篇文章:簡述同步IO和非同步IO的區別
應用層實現
signal將SIGIO訊號和處理函式catch_signale關聯;將程序設定成SIGIO屬主程序,讓其可以接受底層驅動的SIGIO訊號;個flag或上這個FASYNC巨集,他作用的話就是呼叫FASYNC函式。
// 1,設定訊號處理方法 signal(SIGIO,catch_signale); // 2,將當前程序設定成SIGIO的屬主程序 fcntl(fd, F_SETOWN, getpid()); // 3,將io模式設定成非同步模式 int flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FASYNC );
//key_test.c #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <poll.h> #include <signal.h> #define KEY_ENTER 28 struct key_event{ int code; // 按鍵的型別 int value; // 狀態 }; struct key_event event; //接收按鍵裝置資料 static int fd; void catch_signale(int signo) { if(signo == SIGIO) { printf("we got sigal SIGIO\n"); // 讀取資料 read(fd, &event, sizeof(struct key_event)); if(event.code == KEY_ENTER) { if(event.value) { printf("APP__ key enter pressed\n"); }else { printf("APP__ key enter up\n"); } } } } int main(int argc, char *argv[]) { fd = open("/dev/key0", O_RDWR); if(fd < 0) { perror("open"); exit(1); } // 1,設定訊號處理方法 signal(SIGIO,catch_signale); // 2,將當前程序設定成SIGIO的屬主程序 fcntl(fd, F_SETOWN, getpid()); // 3,將io模式設定成非同步模式 int flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | FASYNC ); while(1) { // 可以做其他的事情 printf("I am waiting......\n"); sleep(1); } close(fd); return 0; }
驅動層
1.在file_operations中 fasync指向key_drv_fasync函式
const struct file_operations key_fops = {
.open = key_drv_open,
.read = key_drv_read,
.write = key_drv_write,
.release = key_drv_close,
.poll = key_drv_poll,
.fasync = key_drv_fasync,
};
2.實現介面
int key_drv_fasync(int fd, struct file *filp, int on)
{
//只需要呼叫一個函式記錄訊號該傳送給誰
return fasync_helper(fd, filp, on, &key_dev->faysnc);
}
3.在適當的情況(有資料),傳送訊號
kill_fasync(&key_dev->faysnc, SIGIO, POLLIN);
結果展示