Linux カーネル デバイス ドライバー 高度な文字デバイス ドライバーのメモ

Linux カーネル デバイス ドライバー 高度な文字デバイス ドライバーのメモ
/******************
 * 高度な文字デバイス ドライバー *********************/

(1)ioctl

ほとんどのドライバーでは、デバイスの読み取りと書き込みに加えて、デバイス ドライバーを通じてさまざまな種類のハードウェア制御を実行する機能も必要です。たとえば、メディアの取り出し、ボーレートの変更などです。これらの操作は、同じ名前のシステム コールを実装する ioctl メソッドによってサポートされます。

ユーザー空間では、ioctl システム コールのプロトタイプは次のようになります。

  • int ioctl(int fd, unsigned long cmd, ...);
  • fd: デバイスファイル記述子を開く
  • cmd: コマンド
  • 3 番目のパラメータ: コマンドに応じて、整数、ポインタ、またはなしになります。
  • 「...」メソッドはコンパイラ エラーを回避するためにのみ使用されます。

ドライバーの ioctl メソッドのプロトタイプは、ユーザー空間バージョンとは少し異なります。

int (*ioctl) (構造体inode *inode,
構造体ファイル *filp、
符号なし整数 cmd、
符号なしロング引数);
inode/filp: ユーザー空間のfdに対応
cmd: ユーザー空間から送信されたcmdに対応します
arg: 渡されたcmdパラメータに対応する

ほとんどの ioctl 実装には、cmd パラメータに基づいて対応する操作を選択するための switch ステートメントが含まれています。ユーザー空間とカーネル空間のコマンド番号は一貫している必要があります。

(2)ioctlコマンド番号を選択する

ioctl コードを書く前に、さまざまなコマンドに対応する番号を選択する必要があります。 Linux ではこのコマンド番号がシステム全体で一意である必要があるため、単純に 0 または 1 から始まる番号を選択することはできません。 Linux カーネルは、ドライバの ioctl 番号を選択するために規則を使用します。include/asm/ioctl.h および Documentation/ioctl-number.txt を参照できます。

ioctl 番号は 32 ビット長です。Linux ではこれを 4 つの部分に分割します。ioctl 番号を構築するために必要なマクロは <linux/ioctl.h> で定義されています。

  • 8 ビットのマジックナンバーを入力します。実際には、ドライバーの番号を選択することです。 ioctl-number.txtを参照してください
  • 8桁の序数。
  • 方向 2 ビット。データ転送の方向を定義します。 _IOC_NONE (データ転送なし)、_IOC_READ|_IOC_WRITE (双方向データ転送) など。この方向はユーザー向けであるため、IOC_READ はデバイスからデータを読み取ることを意味し、ドライバーはユーザー空間にデータを書き込む必要があることに注意してください。
  • サイズは14ビットです。関係するユーザー データのサイズ。

<linux/ioctl.h>のマクロを使用してioctl番号を構築することができます。

  • _IO(タイプ, 番号)
  • _IOR(タイプ、番号、データ型)
  • _IOW(タイプ,番号,データ型)

戻り値

システムコールの場合、正の戻り値が最初に保護され、負の値はエラーと見なされ、ユーザー空間でエラー変数を設定するために使用されます。 ioctl メソッドを呼び出すときに未定義の ioctl 番号が渡された場合、システムによって返されるエラー値は -ENVAL および -ENOTTY になります。

(3)ブロッキング操作と非ブロッキング操作

読み取りや書き込みなどの操作の場合、デフォルトの操作はブロッキングであり、その特性は次のとおりです。

*プロセスが read を呼び出しても読み取るデータがない場合、プロセスはブロックする必要があります。データが到着すると、データ量が count パラメータで指定されたデータ量より少ない場合でも、プロセスが起動され、データが呼び出し元に返されます。

*プロセスが write を呼び出してもバッファにスペースがない場合、このプロセスはブロックされ、読み取りプロセスとは異なる待機キューでスリープする必要があります。ハードウェア デバイスにデータが書き込まれ、出力バッファの一部が解放されると、プロセスが起動され、書き込み呼び出しが成功します。

場合によっては、この機能を変更して非ブロッキングにし、デバイスに読み取りまたは書き込みするデータがあるかどうかに関係なく、読み取り/書き込みメソッドがすぐに返されるようにする必要があります。

ファイルを非ブロッキングに設定する場合は、filp​​->f_flags の O_NONBLOCK フラグを設定する必要があります。非ブロッキング ファイルを扱う場合、非ブロッキングの戻りを EOF と間違えやすいため、アプリケーションは stdio 関数を呼び出すときに非常に注意する必要があります。そのため、errno を常にチェックする必要があります。

(4)非同期通知

a. 非同期通知の役割

ほとんどの場合、ブロッキング操作と非ブロッキング操作、および select メソッドの組み合わせにより、デバイスを効果的に照会できますが、この手法が効率的でない場合もあります。特定のランダムな状況やまれにしか発生しない状況 (キーボードで CTRL+C を入力するなど) が発生した場合は、非同期通知が必要になります。

b. ユーザー空間プログラムで非同期通知を開始する方法

ファイルの非同期通知メカニズムを開始するには、ユーザー プログラムは次の 2 つの手順を実行する必要があります。

  • 01.デバイスファイルの「所有者」としてプロセスを指定します。プロセスが fcntl システム コールを使用して F_SETOWN コマンドを実行すると、所有者プロセスのプロセス ID が filp->f_owner に保存されます。この手順は、カーネルが誰に通知するかを認識するために必要です。
  • 02. 非同期通知メカニズムを実際に開始するには、ユーザー プログラムでデバイス内の FASYNC フラグも設定する必要があります。これは、fchtl コマンド F_SETFL によって実行されます。これら 2 つの手順を実行すると、デバイス ファイルは新しいデータが到着したときに SIGIO 信号を要求できるようになります。シグナルは、file->f_owner に格納されているプロセス (負の場合はプロセス グループ) に送信されます。すべてのデバイスが非同期通知をサポートしているわけではなく、アプリケーションでは通常、ソケットと端末のみが非同期通知機能を備えていると想定しています。

(5)ドライバーに非同期通知を実装する方法

a. カーネル内のユーザー空間操作の対応

  • 01. F_SETOWNを設定するときは、file->f_ownerに値を割り当てます。
  • 02. F_SETFLを実行してFASYNCを開始すると、ドライバーのfasyncメソッドが呼び出されます。このメソッドは、filp​​->f_flags の FASYNC フラグ (ファイルが開かれるとデフォルトでクリアされます) が変更されるたびに呼び出されます。
  • 03. データが到着すると、カーネルは非同期通知に登録されているすべてのプロセスにSIGIO信号を送信します。

b. デバイス構造体にfasync_structポインタを追加する

この構造体は <linux/fs.h> で定義されています:

構造体fasync_struct {
int マジック;
整数fa_fd;
構造体 fasync_struct *fa_next;
構造体ファイル *fa_file;
};

c. ドライバーが呼び出す2つの関数

これら 2 つの関数は <linux/fs.h> で宣言されています。

/fs/fcntl.c で定義されています。

プロトタイプは次のとおりです。

  • 01. int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
  • 02. void kill_fasync(struct fasync_struct **fa, int sig, int band);

開いているファイルの FASYNC フラグが変更されると、関連付けられているプロセスのリストにファイルを追加または削除するために fasync_helper が呼び出され、データが到着すると kill_fasync が関連付けられているすべてのプロセスに通知します。

d. 例

01. デバイスタイプにfasync_struct動的データ構造を定義する

構造体my_pipe{
  struct fasync_struct *async_queue; /* 非同期読み取り構造体*/
......
};

02. ドライバーのfasync関数はfasync_helperを呼び出す

int my_fasync(fasync_file fd、構造体ファイル *filp、int モード)
{
  my_pipe *dev = filp->private_data;
  fasync_helper(fd, filp, mode, &dev->async_queue) を返します。
}

03. 非同期通知条件が満たされたらkill_fasyncを呼び出す

非同期通知は読み取りプロセス用なので、kill_fasync は write を使用して送信する必要があります。

kill_fasync を呼び出して、デバイス上の非同期キュー async_queue に登録されているすべてのプロセスに SIGIO シグナルを送信します。

ssize_t my_write(構造体ファイル*filp、const char *buf、size_t count、
        オフセット(f_pos)
{
......
(dev->async_queue) の場合
    kill_fasync(&dev->async_queue、SIGIO、POLL_IN); 
    ......
}

04. ファイルを閉じるときにfasyncメソッドを呼び出す必要があります

アクティブな非同期リーダーのリストからファイルを削除するには、ファイルを閉じるときに fasync メソッドを呼び出す必要があります。

リリースを呼び出します: scull_p_fasync(-1​​, filp, 0);

要約する

以上がこの記事の全内容です。この記事の内容が皆様の勉強や仕事に何らかの参考学習価値をもたらすことを願います。123WORDPRESS.COM をご愛顧いただき、誠にありがとうございます。これについてもっと知りたい場合は、次のリンクをご覧ください。

以下もご興味があるかもしれません:
  • Linux コードを Windows に移植する簡単な方法
  • Linux カーネル デバイス ドライバーのメモリ管理に関する注意事項
  • Linux カーネル デバイス ドライバー カーネル時間管理に関する注意事項
  • Linux カーネル デバイス ドライバー キャラクタ デバイス ドライバー ノート
  • Linux カーネル デバイス ドライバー仮想ファイル システムに関する注意事項
  • Linux カーネル デバイス ドライバー システム コールに関する注意事項
  • Linux カーネル デバイス ドライバー カーネル デバッグ テクニカル ノート集
  • Linux カーネル デバイス ドライバー カーネル リンク リストの使用上の注意
  • Linux カーネル デバイス ドライバー proc ファイル システム ノート
  • Linux カーネル デバイス ドライバー Linux カーネル モジュールの読み込みメカニズム メモの概要
  • Linux カーネル デバイス ドライバー アドレス マッピングに関する注意事項
  • Linux カーネル デバイス ドライバー Linux カーネル 基本メモの概要
  • 新しいカーネルをLinuxシステムに移植する手順

<<:  JavaScriptは、ユーザーがチェックボックスをオンにする必要があるプロトコルの例を実装します。

>>:  MySql5.7.18 の文字セット構成の詳細なグラフィック説明

推薦する

Navicat for MySQL 15 登録とアクティベーションの詳細なチュートリアル

1. Navicat for MySQL 15をダウンロードするhttps://www.navica...

InnoDB のアーキテクチャと機能の詳細な説明 (InnoDB ストレージ エンジンの読書メモの要約)

背景スレッド•マスタースレッドコア バックグラウンド スレッドは主に、バッファー プール データをデ...

Nginx でバージョン番号を隠したり偽造したりする方法

1. デフォルトでアクセスするには、curl コマンドを使用します。 # curl -I http:...

jsはウォーターフォールフローのボトムアウトによるデータの動的ロードを実現します

この記事では、ウォーターフォールフローが底に達したときにデータを動的にロードするためのjsの具体的な...

MySQL の連結で複数の一重引用符と三重引用符を使用する際の問題

文字列を動的に連結する場合、文字連結を使用することが多いです。次のような連結の引用符の意味がわかりま...

Docker デプロイメント MySQL8 クラスター (マスター 1 台とスレーブ 2 台) の実装手順

目次1. CentOS 7.9 20にDockerをインストールする2. MySQL クラスターをデ...

JS ES の新機能、変数分離割り当て

目次1. 配列の分離割り当て1.1 配列分離割り当てとは何ですか? 1.2 配列分離割り当てに失敗し...

MySQLの7種類のログの概要

MySQL には次のログ ファイルがあります。 1: 再実行ログ2: ロールバックログ(元に戻すログ...

HTML ウェブページのメタビューポート属性の説明

HTML メタビューポート属性の説明ビューポートとはモバイル ブラウザは、Web ページを仮想の「ウ...

Windows 10 で Hyper-V サービスをシャットダウンするいくつかの方法

VMware Workstation を使用して Windows 10 で仮想マシンを開くと、VMw...

Win10 構成 Tomcat 環境変数チュートリアル図

設定する前に、次の操作を行う必要があります。 1. まずjdk bloggerをインストールします。...

JSを使用して画像を効果的に圧縮する方法

目次序文変換関係具体的な実装file2DataUrl(ファイル、コールバック) file2Image...

Link と @import の違いを詳しく見る

ページで CSS を使用する主な方法は、スタイル属性値をインラインで追加する方法、ページ ヘッダーで...

MySQL データベース アカウントの作成、認証、データのエクスポートおよびインポート操作の例

この記事では、MySQL データベースでのアカウントの作成、認証、データのエクスポートおよびインポー...

MySQL データベースのマスター・スレーブ レプリケーションと読み取り/書き込み分離

目次1. マスタースレーブレプリケーションマスタースレーブレプリケーション3スレッドマスタースレーブ...