Linuxデバイスノードとは何ですか

青灯夜游
リリース: 2022-04-18 20:10:58
オリジナル
6903 人が閲覧しました

Linux デバイス ノードは、アプリケーションとデバイス ドライバー間のブリッジであり、カーネルとユーザー層を接続するハブである「/dev」に作成されます。ハードウェアの i ノードに相当します。ディスクとレコード ハードウェア デバイスの場所と情報。デバイス ノードを使用すると、ユーザーはハードウェアを介してカーネルと通信し、デバイスの読み取りと書き込み、その他の操作を実行できます。

Linuxデバイスノードとは何ですか

#このチュートリアルの動作環境: linux5.9.8 システム、Dell G3 コンピューター。

デバイス ノードとは

人々間のコミュニケーションの架け橋となるのは言語です。同様に、アプリケーションとデバイス ドライバーも通信するためにブリッジを必要とします。このブリッジがデバイス ノードです。

Linux システムの場合、すべての IO リソースはファイル、ディレクトリ、ハードディスク、デバイスなどを含むファイルです。キーボードはコンピュータ システムの入力デバイスであり、オペレーティング システムもそれをファイルから抽象化します。ユーザーがキーボードから入力したデータを取得したい場合は、キーボードが提供するデバイス ノードを読み取るだけで済みます。 。

Linux システムでは、キーボードが入力デバイスとして使用され、それに対応するデバイス ノードは「/dev/input」の下にあります。このフォルダーには、event で始まるファイルが多数あり、これらはすべての入力デバイスのデバイス ノードです。どのデバイス ノードがキーボードであるかを判断するにはどうすればよいですか?キーボードを Raspberry Pi に接続し、ターミナルを開き、「sudo cat /dev/input/event0」を実行し、キーボードをタップします。出力がない場合は、出力のあるノードが見つかるまで次のノードに変更し、次にこのノードを見つけます。はキーボードに対応するデバイスノードです。

デバイスノードは/dev配下に作成され、カーネルとユーザー層を接続するハブであり、対応するインターフェースのどのIDにデバイスが接続されているかを意味します。これはハードディスクの i ノードに相当し、ハードウェア デバイスの場所と情報を記録します。

Linux では、すべてのデバイスがファイル形式で /dev ディレクトリに保存されます。アクセスするには、デバイス ノードは Linux カーネルによるデバイスの抽象化です。、デバイス ノードはファイルです。アプリケーションは、特定のドライバーから独立した標準化された一連の呼び出しを通じてデバイスにアクセスします。ドライバーは、これらの標準呼び出しを実際のハードウェア固有の操作にマッピングする責任があります。

デバイス ノードの役割

デバイス ノードにより、ユーザーはハードウェアを介してカーネルと通信し、デバイスの読み取りと書き込み、その他の操作を実行できるようになります

Linux では、デバイスは通常のファイルのように存在し、デバイスへのアクセスはファイルへのアクセスと同じです。

メジャー デバイス番号はデバイスのタイプを表し、マイナー デバイス番号は同じタイプのデバイスの異なる個体を表します。おそらくデバイス ノードの存在形式を知らないかもしれません

デバイス ノードの存在形式

さらに、Linux には別の概念があります。 i ノードとブロック (ハードディスク側) ブロックとノード ハードディスク内の i ノードはファイルまたはフォルダーに相当します このファイルの下にファイルの場所が記録されます ファイルの場所はブロックに合わせて配置されますたとえば、一部のシステムのサイズは 4K ですが、inode のサイズは制限されているため、1 つのファイルは 4G を超えることはできないと言われています。私の個人的な理解では、Linux ドライバーのノードは、ハードウェア デバイスの位置やその他の情報を記録し、ユーザーがアクセスする必要があるときに使用できる、ハードディスクの i ノードに似たものとみなすことができます。デバイスノードに記録された情報を参照してデバイスにアクセスする

デバイスノードからデータを取得する方法

オペレーティングシステムがIOをファイルに抽象化する理由は次のとおりです。利点は、統合インターフェイスを介してこのファイルにアクセスし、さまざまなデバイスと通信できることです。これらの統合インターフェイスは、ファイル操作のためにオペレーティング システムによって提供される一連のシステム コール (オープン関数、読み取り関数、書き込み関数など) です。たとえば、デバイスからデータを取得する必要がある場合、read 関数を呼び出して、そのデバイスに対応するデバイス ノードを読み取るだけで済みますが、当然、読み取る前に、まず open 関数を呼び出してデータを開く必要があります。ここで、例としてキーボード入力を取得してみましょう。

1. デバイス ノードを開く

デバイス ノードのデータを読み取る前に、まず open 関数を呼び出してデバイス ノードを開く必要があります。 open関数の具体的な使い方はリンク先を参照してください。簡単に説明すると以下のとおりです。

関数宣言:

int open(const char *pathname, int flags);
ログイン後にコピー

インクルードするヘッダファイル:

  #include <fcntl.h>
ログイン後にコピー

パラメータ:

* 第一パラメータ(const char) * pathname): 開かれるファイル パスを示します

* 2 番目のパラメータ (int フラグ): ファイルを開く方法を示します (例: "O_RDONLY" - 読み取り専用で開きます。"O_WRONLY" -)書き込み専用オープン ; "O_RDWR" - 読み取り、書き込みオープンなど。

戻り値:

オープンに成功すると、読み取りや書き込みなどの関数で使用するためにファイルのファイル記述子が返されます。それ以外の場合は、-1 が返されます。

したがって、キーボードのデバイス ファイル (「/dev/input/even10」であると仮定します) を開くには、次のコードが必要です:

  int keys_fd;
    keys_fd = open("/dev/input/even10", O_RDONLY);
    if(keys_fd <= 0)
    {
        printf("open /dev/input/event10 device error!\n");
        return -1;
    }
ログイン後にコピー

2、デバイス ノードのデータを読み取ります。

デバイスノードの読み取りにはread関数を使用する必要がありますので、具体的な使用方法についてはリンクを参照してください。簡単な説明は次のとおりです:

関数宣言:

  ssize_t read(int fd, void *buf, size_t count);
ログイン後にコピー

需要包含的头文件:

  #include <unistd.h>
ログイン後にコピー

参数:

* 第一个参数(int fd):要打开文件的文件描述符,来源一般是上述open函数的返回值。

* 第二个参数(void *buf):读取到的数据存放的起始位置指针

* 第三个参数(size_t count):要读取的数据字节数

返回值:

* 如果读取成功,则返回实际读取到的字节数

* 如果读取失败,则返回-1

* 如果返回值小于第三个参数count,则表示已经读取到文件结尾,返回值表示实际读取的字节数。

在读取键盘的例子中,我们循环读取键盘设备的文件节点,并将设备保存到一个char buf[24]的数组中去。具体代码如下:

char buf[24];
while(1)
{
    if(read(keys_fd, buf, 24) == 24)
    {
        // 成功的从设备节点中获取到了24个字节
        ...
    }
}
ログイン後にコピー

根据read函数用法,当要读取24个字节,且read函数的返回值是24时,表示成功的从设备节点中获取到了24个字节。

3、分析从设备节点获取的数据

为什么这里要从键盘的设备驱动获取24个字节呢?这是因为正常情况下,从键盘设备节点获取的数据实际上是一个struct input_event结构。其定义为:

struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};
ログイン後にコピー

显然,上述结构体的大小为24。

  这里需要理解的是:设备节点是设备驱动程序提供的,且设备节点的数据是设备驱动写入的,而且写入时,是以上述结构的规则写入的,这是双方通过约定好的,那么应用程序去设备节点中读取数据之后,也需要按照上述结构去解析数据。那这个结构具体是什么意思呢?

* struct timeval time:其大小为16个字节,具体意义暂时不考虑。

* __u16 type:其大小为2个字节,表示input设备的类型,比如:EV_KEY表示上报的是键盘类型的数据,EV_REL表示相对路径,鼠标就属于这种类型,还是其他等等。

* __u16 code:其大小为2个字节,表示事件的代码。比如,如果type为EV_KEY,那么该代码code为设备键盘代码。code值实际上是应用程序和驱动程序约定好的一些固定的值,它可取的值位于include/uapi/linux/input-event-codes.h中。举例来讲,根据Linux源码下的include/uapi/linux/input-event-codes.h文件的第91行#define KEY_Q 16,如果键盘上按下或松开了Q键,那么键盘的驱动程序上报的code值应该是16;反之,如果应用程序获取到的值是19,那么,表示用户按下或松开了键盘上的Q键。

* __s32 value:其大小为4个字节,事件的值。如果事件的类型代码是EV_KEY,当按键按下时值为1,松开时值为0;

根据上述解释,我们可以添加以下代码来解析从设备节点中获取的数据。

if(t.type == EV_KEY)                // 我们只关心input event类型为EV_KEY(按键)的消息
    if(t.value == 0 || t.value == 1)
    {
        printf("key %d %s\n", 
        t.code,                     // t.code表示按下或松开了哪个按键
        (t.value) ? "Pressed" : "Released");   // t.value表示按下还是松开了相应的按键
    }
ログイン後にコピー

4、关闭设备节点

在从设备节点获取数据完成后,务必调用close函数,来关闭设备节点。即

close(keys_fd);
ログイン後にコピー

相关推荐:《Linux视频教程

以上がLinuxデバイスノードとは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート