Wei Dongshanuboot_kernel_rootファイルシステムスタディノート5.10-レッスン005_characterデバイスdriver_section010_characterデバイスドライバー非同期通知

アプリケーション:ハードウェアステータスをアクティブに読み取る①クエリ
方式:非常にリソースを消費する②割り込み
方式:読み取り関数は常にスリープし、決して返さない
③poll:スリープ時間を指定します

ドライバーはアプリケーションをトリガーし、アプリケーションはそれを再度読み取ります
。④非同期通知信号デバイスの準備が整うと、デバイスはアプリケーションにアクセスをアクティブに通知します。このように、非ブロッキングIOを使用するアプリケーションは、デバイスがアクセス可能かどうかをポーリングする必要がなく、CPU消費を削減するという目的を達成します。ハードウェアの「割り込み」の概念と同様に、より正確な用語は「信号駆動型非同期IO」です。信号:ソフトウェアレベルでの割り込みメカニズムのシミュレーションです。
原則として、プロセスは信号(ソフトウェア層)<==>(ハードウェア層)を受信し、プロセッサは割り込みを受信します。

Killコマンド:Linuxのkillコマンドは、指定されたプロセスの操作を終了する(プロセスを終了する)ために使用され、Linuxでのプロセス管理の一般的なコマンドです。通常、Ctrl + Cキーを使用してフォアグラウンドプロセスを終了できますが、バックグラウンドプロセスの場合は、killコマンドを使用して終了する必要があります。プロセスを取得するには、ps / pidof / pstree / topなどのツールを使用する必要があります。 PIDを入力し、killコマンドを使用してプロセスを強制終了します。killコマンドは、指定されたシグナルをプロセスに送信することにより、対応するプロセスを終了します。デフォルトでは、TERM信号番号15が使用されます。TERMシグナルは、シグナルをキャッチできないすべてのプロセスを終了します。シグナルをキャプチャできるプロセスの場合、killシグナル番号9を使用して、プロセスを強制的に「kill」します。
kill -USER1(シグナル)PID(指定されたプロセス番号)
例:
1。プロセス番号を表示します
ここに画像の説明を挿入
2. kill -USER1 833

  1. 目標:ボタンが押されると、ドライバーはアプリケーションに通知します
  2. 信号処理機能を登録しますか?応用
  3. 誰が合図したのですか?ドライバーシグナリング
  4. 誰に?アプリケーション、アプリケーションはドライバーにそのPID番号を伝える必要があります
  5. 送信方法は?ドライバーはkill_fasyn関数を呼び出して送信します

以下の実装コードを見てください

デバイスが非同期通知メカニズムをサポートするようにするために、次の3つのタスクがドライバーに含まれます。

  1. F_SETOWNコマンドをサポートし、この制御コマンド処理で対応するプロセスIDとしてfilp-> f_ownerを設定できます。ただし、この作業はカーネルによって完了されており、デバイスドライバーを処理する必要はありません。
  2. F_SETFLコマンドの処理をサポートします。FASYNCフラグが変更されると、ドライバーのfasync()関数が
    実行されます。fasync()関数はドライバーに実装する必要があります。
  3. デバイスリソースが利用可能な場合は、kill_fasync()関数を呼び出して、対応するシグナルをトリガーします

ドライバー

  1. 構造を定義します。static struct fasync_struct *button_async;
  2. 割り込み処理機能:
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
    
    
	...
	kill_fasync (&button_async, SIGIO, POLL_IN);//发送的信号类型:SIGIO
	...
}

誰がbutton_async構造を初期化しますか?

  1. fifth_drv_fasync関数の初期化button_async構造
static struct file_operations sencod_drv_fops = {
    
    
    .owner   =  THIS_MODULE,   
    .open    =  fifth_drv_open,     
	.read	 =	fifth_drv_read,	   
	.release =  fifth_drv_close,
	.poll    =  fifth_drv_poll,
	.fasync	 =  fifth_drv_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);//这里初始化button_async结构体
}
  1. fifth_drv_fasync関数はいつ呼び出されますか?アプリプログラムがドライバーを呼び出す.fasyncときに呼び出されます。
//把自己的进程号pid告诉驱动程序;
//支持 F_SETOWN 命令,能在这个控制命令处理中设置 filp->f_owner 为对应进程 ID。不过此项工作已由内核完成,设备驱动无须处理。
 app > fcntl(fd,F_SETOWN,pid) 
 //读出F_GETFL
 //支持 F_SETFL 命令的处理,每当 FASYNC 标志改变时,驱动程序中的 fasync()函数将得以执行。驱动中应该实现 fasync()函数。
 app > Oflags = fcntl(fd,F_GETFL)
 app > fcnl(fd,F_SETFL,oflags | FASYNC)

2番目のアプリケーション

  1. 信号応答関数と応答信号タイプを宣言します
//信号响应函数:my_signal_fun
//相应信号类型:SIGIO
signal(SIGIO, my_signal_fun);
  1. 信号応答関数の定義
//从fd中读取按键值到key_val
void my_signal_fun(int signum)
{
    
    
	unsigned char key_val;
	read(fd, &key_val, 1);
	printf("key_val: 0x%x\n", key_val);
}

ドライバーの割り込みサービス機能が信号を検出すると、その信号をアプリプログラムに直接送信し、アプリプログラムは信号処理機能にジャンプしますmy_signal_fun

//发给谁?
//把自己的进程号pid告诉驱动程序;
//getpid()函数表示获取的进程号
fcntl(fd, F_SETOWN, getpid());

//改变FASYNC标记,最终会调用到驱动的fasync > fasync_helper:初始化/释放fasync_struct
//驱动程序中的 fasync()函数将得以执行
Oflags = fcntl(fd, F_GETFL); 
fcntl(fd, F_SETFL, Oflags | FASYNC);//设置文件描述符标志

fasync_helper関数の3つの簡単な分析

呼び出し:fasync_helper (fd, filp, on, &button_async)
関数:構造button_async初期化
関数のプロトタイプ宣言します。

int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
int fd= fd;
struct file * filp = filp;
int on = on;
struct fasync_struct **fapp = &button_async

関数定義:

int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{
    
    
	...
	//1. 参数on控制,如果为on分配一个结构体new
	if (on) {
    
    
		new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
		if (!new)
			return -ENOMEM;
	}
	write_lock_irq(&fasync_lock);
	for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
    
    
		if (fa->fa_file == filp) {
    
    
			if(on) {
    
    
				fa->fa_fd = fd;
				kmem_cache_free(fasync_cache, new);
			} else {
    
    
				*fp = fa->fa_next;
				kmem_cache_free(fasync_cache, fa);
				result = 1;
			}
			goto out;
		}
	}
	//与1.对应,刚刚分配的结构体new进行初始化后,赋给fapp即&button_async
	if (on) {
    
    
		new->magic = FASYNC_MAGIC;
		new->fa_file = filp;
		new->fa_fd = fd;
		new->fa_next = *fapp;
		*fapp = new;
		result = 1;
	}
out:
	write_unlock_irq(&fasync_lock);
	return result;
}

おすすめ

転載: blog.csdn.net/xiaoaojianghu09/article/details/104334782