私はLinuxドライバー開発を始めたばかりで、概念的な質問があります。これは、他の新参者もカーネル開発に役立つと思います。
Linux Device Driversの本を読んでいて、Ch。本の3。これまで、/dev
フォルダー内のファイルにopen
、close
などのコマンドを発行することにより、ユーザースペースがカーネル機能にアクセスできることを確認しました。
制御を共有するもう1つの方法は、/sys
のファイルを使用する方法です。この場合、sys
ファイルの読み取りまたは書き込みは、ドライバーと通信できます。
各メソッドのユースケースは何ですか?それらは同じタスクへの2つのアプローチですか? 1つは別の制限がありますか?誰かが一方が他方よりも役立つかもしれない実用的な例を誰かが共有できますか?
ここで他の質問を読んだところ、dev
とsys
について説明されました。これは役に立ちますが、両方の違いと使用方法について、もう少し詳しく知りたいと思っていました。
大まかに:
/dev
には、以前のUnixシステムではカーネルと対話する唯一の方法であったデバイスノードが含まれています。 blockデバイスとcharacterデバイスの2つのタイプがあります。対応するAPIは、ブロックベースのI/O(ある種のディスク)または文字ベースのI/O(たとえば、シリアルポート)を可能にするものに適合しています。
/sys
(および/proc
)は後に追加されました。おそらく Plan 9 OSに触発されました。それらは完全なディレクトリサブツリーを提供し、これらのサブツリーのファイルエントリには、読み取り時、または書き込み時に内部状態を設定するときのカーネルモジュールの内部状態を説明するテキストが含まれています。
したがって、一般的なアプリケーションは次のようになります。
ある種のストレージデバイス用のカーネルドライバーを書きたいですか?使う /dev
ノードはデバイス自体にアクセスし、/sys
(または/proc
)エントリを使用して、ストレージへのアクセス方法を微調整します。
/sys
の対象範囲は、第14章「Linuxデバイスモデル」にあります。それは一緒に遊ぶためのいくつかのサンプルコードを提供します。しかし、この本はよりコード駆動型のアプローチであり、設計原則がどのように見えるかを尋ねるのに役立つと思います。
最初の答えは、あなた自身を選ばないということです。あるタイプのデバイス用のドライバーを作成するとき、カーネルにはすでに同じタイプのデバイスの多くの例があります。既存のデバイスと同等のコードパターンを使用します。 (最新のドキュメントはコード自体です。多くのカーネルインターフェイスには完全なドキュメントや最新のドキュメントがありません。申し訳ありません!)
これが、デバイスドライバーを作成する主な理由です。さまざまなデバイスごとにさまざまな詳細をコーディングする必要なく、プログラムが使用できる一貫したインターフェースを提供しています。
これは、より一般的なアドバイスを無効にします。 Linuxのサブシステム(デバイスのタイプなど)が「間違っている」ように見える方法を使用しているが、一貫してそうしている場合は、そのサブシステムのドライバーを作成するときにも一貫していて「間違っている」必要があります。
データパスには/ dev /を使用する必要があります。本の別のセクションで説明されているネットワークデバイスを除きます。
/ dev /特殊ファイルは、標準化されたUNIX操作に使用する必要があります:read()
、write()
、poll()
/select()
、mmap()
。 ioctl()
sがunixまたはlinuxで効果的に標準化されている場合も望ましいです。これらのいくつかのシステムコール(およびいくつかの派生バリアント)は、ほとんどすべての場合に使用されます。それらに慣れ始めてください:)。 ioctl()
は、ここでエスケープハッチです。これを使用して、ドライバーに他の操作をいくつでも定義させることができます。
sysfs書き込みは、構成パラメーターのために、はるかに少ないケースで使用する必要があります。それらはプレーンテキスト形式である必要があり、単一の値のみが含まれている必要があります。[*]異なるsysfsファイルが多すぎないようにする必要があります。あなたはそれらの限界を素早く見始めることができます。
また、sysfsファイルは基本的に変数を読み取る必要があると言うこともできます(変数は書き込み可能であってもなくてもかまいません)。それらを読んでハードウェアが動作することはないと思います。あなたはすでにこれらの線に沿って考えていたと思います。
Sysfsファイルの利点は、実験に非常に便利なことです。シェルコマンドを使用して、それらの一覧表示、読み取り、書き込みを簡単に行うことができます。これも危険です。実験的な状態でsysfsファイルを公開しないように注意する必要があります。他の人があなたのsysfsファイルに依存し始めると、ユーザーのスクリプトを壊すような方法で何かを変更したい場合、カーネルのメンテナは非常に不幸になります。
Sysfs(ディレクトリ階層とシンボリックリンク)をトラバースすることも、デバイスがどのように編成されているかを確認するのに役立ちます。
また、sysfsの変更を概念的に監視することは、プログラムが新しいデバイスを検出する方法です(たとえば、プラグインされたとき)。技術的には、これらのイベントはファイルシステム自体を通じて配信されませんが、各イベントは特定のsysfsディレクトリを指します。
Udevデーモンはこれらのイベントを待機します。通常のプログラムは、必要に応じてudev/libudevに依存する傾向があります。たとえば、udevルールは、イベントの受信時にsysfsディレクトリ内のいくつかのファイルを読み書きする場合があります。新しく検出されたデバイスの設定を変更します。
既存の例を見ることは非常に良い考えです。おそらく1つの例だけを見てはならず、それが他の場所でも同じように機能すると仮定します。
Dirktが言うように、/dev/sda
のようなブロックストレージデバイスへのアクセスは、/dev
の非常に標準化された使用法です。最大物理IO /sys/class/block/sda/
で公開されているサイズなどのいくつかのパラメータ-queue
サブディレクトリを確認してください。
多くのsysfsファイルは、カーネルツリーDocumentation/ABI/*/sysfs-*
に文書化されています。例: https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block
「キャラクターデバイス」はあまり具体的ではないことに注意してください。基本的に、ブロックデバイスでもネットワークデバイスでもないデバイスに使用されます:-)。まったく新しいクラスのデバイスを実装する必要がある場合は、まったく新しいタイプのキャラクターデバイスを定義し、ioctl()
操作の新しいセットを定義するという恐ろしい仕事をしなければならないでしょう。
自分のシステムで定義されている他のいくつかのタイプのデバイスを確認するために、/sys/class/
を調べ始める場合があります。
/sys/
には、/dev/
デバイスのリストも含まれますが、名前ではなくデバイス番号でリストされます。 ls -l /sys/dev/char/
およびls -l /sys/dev/block/
を参照してください。これは、udev
が/dev
を管理する方法を説明するのに役立ちます。/dev
に表示されるすべてのデバイスは、/sys
のオブジェクトとしてリストされます。[**]
[*] sysfs uevent
ファイルには複数の値が含まれており、実際にはコア機能です。ただし、ueventファイルを使用して内部の値を変更することはできません。つまり、これは単にuevent
を見て、私のアドバイスが間違っているとは考えないでください。このようなファイルを自分で定義しないでください。デバイスドライバーはuevent
ファイルに行を追加できます。 Ithink良い例は、udev
ルールでテストしたい非常に便利な識別プロパティがある場合です。
[**] /dev/pts/0
は実際には別のファイルシステム「devpts」によって実装されるため、/sys
などは/dev/pts/0
にリストされていません。非常に特殊なケースとして、/dev/pts/0
を無視してください。私がこれを結論付けた答えはありますが、私が言ったことに何かを追加することは本当にないと思います。それはここにあります: 端末を開いたときにTTYは常に使用されますか? 。