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 の文字セット構成の詳細なグラフィック説明

推薦する

12個のJavascriptテーブルコントロール(DataGrid)が整理されています

DataGrid コントロールの DataSource プロパティがデザイン時に設定されている場合、...

VMware 仮想マシンで Linux の IP アドレスを表示する方法

1. まず、コンピュータのデスクトップにある VMware アイコンをダブルクリックしてソフトウェア...

JavaScript はクリックして画像の形状を変更する (変換アプリケーション) を実装します。

JavaScriptをクリックすると画像の形状が変わります(変形の応用)。参考までに具体的な内容は...

HTML+CSS+JavaScript でシンプルな三目並べゲームを作成する

目次HTMLの実装CSSを追加Javascript部分の実装デモアドレス HTMLの実装まず、hea...

JSタイマーを使用して要素を移動する

JS タイマーを使用して、要素に移動する効果のあるメソッドを作成します。実装のアイデアは、まず要素の...

TypeScript ジェネリックを簡単に説明する方法

目次概要ジェネリック医薬品とはビルドシステムジェネリック医薬品の一般的な理解ジェネリッククラスジェネ...

Docker コンテナのデプロイの試み - マルチコンテナ通信 (node+mongoDB+nginx)

その理由はモッカー プラットフォームを導入したかったので、友人の勧めで既成のプロジェクト api-m...

MySQL での limit の使用方法は何ですか (推奨)

SELECT * FROM テーブル名制限m,n; SELECT * FROM テーブル LIMI...

JavaScript で 2 次元配列を作成するためのヒント

Js での 2 次元配列の作成:まず、JavaScript は 1 次元配列のみをサポートしています...

MySQL最新バージョン8.0.17解凍版インストールチュートリアル

個人的にはインストール版よりも解凍版の方がインストールしやすいと思います。早速、解凍版のインストール...

MySQLのスケジュールタスクが正常に実行できない原因の分析と解決

目次序文原因分析と解決策スケジュールされたタスクを迅速に実行する要約する序文データベースのスケジュー...

ダッシュボードを実装するためのjQueryプラグイン

jQueryプラグインは、参考のためにダッシュボードを実装します。具体的な内容は次のとおりです。一般...

EclipseのプロジェクトをTomcatに追加できない問題を解決する方法

1. プロジェクトを右クリックしてプロパティを選択します2. プロジェクトファセットをクリック3. ...

中国語ウェブコンテンツを紹介する10の経験

<br /> テキスト、シンボル、リンクの 3 つの側面に焦点を当て、主に中国語で、私の...

MySQL count(1)、count(*)、count(field)の違い

目次1. COUNTの初見2. COUNT(フィールド)、COUNT(定数)、COUNT(*)の違い...