1. 程式人生 > >嵌入式核心及驅動開發之學習筆記(十) 非同步通訊+中斷實現讀取資料

嵌入式核心及驅動開發之學習筆記(十) 非同步通訊+中斷實現讀取資料

對於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);

 

 

結果展示