Linux キャラクター デバイスは、「/dev」ディレクトリに配置されます。キャラクタ デバイスとは、バイト単位でのみ読み取りおよび書き込みが可能なデバイスを指します。通常、各キャラクタ デバイスまたはブロック デバイスは、「/dev」ディレクトリ内のデバイス ファイルに対応し、各デバイス ファイルには main/Devices が必要です。同じマイナー デバイス番号とメジャー デバイス番号は類似したデバイスであり、同じドライバーを使用します。
#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。
Linux システムは、デバイスを キャラクター デバイス、ブロック デバイス、ネットワークの 3 つのカテゴリに分類します。デバイス の 3 つのカテゴリのうち、キャラクタ デバイスは比較的単純です。アプリケーションはキャラクタ デバイス ファイルを通じてキャラクタ デバイスにアクセスします。この講義では主にキャラクタ デバイスについて紹介します。ブロック デバイスやネットワーク デバイスに興味がある場合は、関連情報を参照してください。そしてそれを深く理解します。
キャラクター デバイスとは、バイトごとの読み取りと書き込みのみが可能なデバイスを指します。デバイス内の特定のデータはランダムに読み取ることができず、データは順番に読み取る必要があります。キャラクター デバイスはストリーム指向のデバイスであり、一般的なキャラクター デバイスには、マウス、キーボード、シリアル ポート、コンソール、LED などがあります。
通常、各キャラクタ デバイスまたはブロック デバイスは、/dev ディレクトリ内の デバイス ファイル に対応し、各デバイス ファイルには main/同じマイナー デバイス番号とメジャー デバイス番号を持つデバイスは類似したデバイスであり、同じドライバーを使用します。
Linux ユーザーレベル プログラムは、ドライバーを使用してキャラクター デバイスを操作したり、デバイス ファイルを通じてデバイスをブロックしたりします。
cat /proc/devicesコマンドを使用すると、現在ロードされているデバイス ドライバーのメジャー デバイス番号を表示できます。
#/dev ディレクトリでコマンド
ls -l
#一般的なデバイス ファイルについては次のように説明します:
/dev/hd[a-t]:IDE设备 /dev/sd[a-z]:SCSI设备 /dev/fd[0-7]:标准软驱 /dev/md[0-31]:软raid设备 /dev/loop[0-7]:本地回环设备 /dev/mem:内存 /dev/null:无限数据接收设备,相当于黑洞 /dev/zero:无限零资源 /dev/tty[0-63]:虚拟终端 /dev/ttyS[0-3]:串口 /dev/lp[0-3]:并口 /dev/console:控制台 /dev/fb[0-31]:framebuffer /dev/cdrom => /dev/hdc /dev/modem => /dev/ttyS[0-9] /dev/pilot => /dev/ttyS[0-9]
3. デバイス ファイルを作成するにはどうすればよいですか?
デバイス ファイルを作成するには 2 つの方法があります。1 つはシステム コール mknod() を使用する方法です。プログラミングでこの関数を呼び出すと、新しいデバイス ファイル名を作成できます。もう 1 つは mknod コマンドを使用する方法です。1 つ目は mknod コマンドを使用する方法です。コマンドのパラメータはデバイス ファイル名、2 番目のパラメータはデバイス タイプです。たとえば、c はキャラクタ デバイスを表し、3 番目と 4 番目のパラメータはデバイス ファイルのメジャー デバイス番号とマイナー デバイス番号です。たとえば、 231と0。メジャー デバイス番号とマイナー デバイス番号の組み合わせによってデバイスを一意に決定します。同じデバイスの異なる種類のメジャー デバイス番号は同じですが、マイナー デバイス番号は異なります。たとえば、ハードディスクの複数のパーティションには、異なるマイナー デバイス番号: デバイス番号により、デバイス ファイルとドライバーを関連付けることができます。ファイル名: 作成するデバイス ファイルの名前; タイプ: デバイス タイプ、c文字デバイスを表し、b はブロックデバイスを表します;
struct cdev { struct kobject kobj; // 内嵌内核对象 struct module *owner; //该字符设备所在的内核模块 const struct file_operations *ops; //文件操作结构体 struct list_head list; //已注册字符设备链表 dev_t dev; //由主、次设备号构成的设备号 unsigned int count;//同一主设备号的次设备号的个数 };
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, loff_t *); ssize_t (*write) (struct file *, const char *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); };
ユーザー プロセスがデバイス ファイルに対して読み取りや書き込みなどの操作を実行すると、システム コールはデバイス ファイルのメジャー デバイス番号を通じて対応するデバイス ドライバーを見つけ、そのデバイス ファイルの対応する関数ポインターを読み取ります。その後、制御が関数に渡され、これが Linux デバイス ドライバーの動作の基本原理です。
#5. キャラクターデバイスとファイルシステム間のインターフェイス図に示すように、Linux カーネルでは、左端にある cdev 構造体はキャラクター デバイスを記述するために使用され、そのメンバー dev_t はデバイス番号 (メジャー デバイス番号とマイナー デバイス番号に分けられる) を定義するために使用されます。キャラクタ デバイスの一意性を決定する; そのメンバ dev_t を通じて メンバ file_operations は、キャラクタ デバイス ドライバによって仮想ファイル システム VFS に提供されるインターフェイス関数 (共通の open()、read()、write() など) を定義します。これらの関数は実際にハードウェア デバイスを操作します。
前の図に基づいて、この図を見てみましょう。キャラクタ デバイス ドライバは、カーネル モジュールの形式でカーネルにロードされます。最初に、モジュール ロード関数が押します。静的または動的メソッド デバイス番号 を取得し、キャラクタ デバイス 初期化関数 が cdev と file_operations 間の接続 を確立し、 登録関数を通じてシステムに追加します。 登録を完了するための cdev。ロードに対応してモジュールがアンロードされるとき、cdev はログアウトする必要があり、デバイス番号が解放されます。
ユーザー プログラムでは、カーネル内のドライバーによって実装されたこれらの関数を、open()、read()、write() などのシステム コールを通じて呼び出すことができます。このようにして、ユーザー モードとカーネル ドライバー間のパスが開きます。メジャー デバイス番号は、デバイス ファイルに接続されているドライバーを識別するために使用され、デバイス タイプを反映するために使用されます。 セカンダリ デバイス番号は、どのデバイスが操作されているかを識別し、同じタイプのデバイスを区別するためにドライバーによって使用されます。誰もが入学時に学生証を持ち、卒業・退学時にその学生証が解放されるのと同じように、登録時に端末番号を申請し、ログアウト時に端末番号を解放します。
6.2 ユーザー空間およびカーネル空間データの送信 read() 関数がユーザープログラムで呼び出される場合、それはカーネル空間に落ちます。実際には、カーネル空間のバッファー内のデータは、カーネルの copy_to_user() 関数を通じてユーザー空間のバッファーにコピーされる必要があります。 write() 関数を呼び出すとき カーネルは、copy_from_user() 関数を呼び出すことによって、ユーザー空間データをカーネル バッファにコピーします。
関連する推奨事項: 「
Linux ビデオ チュートリアル以上がLinux キャラクターデバイスはどこに配置されていますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。