ホームページ >システムチュートリアル >Linux >Linux カーネルの 2 つの特別なデバイス ドライバー フレームワーク: misc サブシステムと 3+2+1 デバイス認識ドライバー フレームワーク

Linux カーネルの 2 つの特別なデバイス ドライバー フレームワーク: misc サブシステムと 3+2+1 デバイス認識ドライバー フレームワーク

WBOY
WBOY転載
2024-02-12 18:21:10926ブラウズ

misc サブシステムは、Linux カーネルのシンプルで柔軟なデバイス ドライバー フレームワークです。キャラクター デバイス、仮想デバイス、ハイブリッド デバイスなど、他のサブシステムに属さない一部のデバイス ドライバーを実装するために使用できます。 Misc サブシステムの利点は、シンプルで使いやすいことであり、多くのコードを記述する必要がなく、いくつかの基本的な操作機能を実装するだけで済みます。ただし、misc サブシステムには、複数のデバイス インスタンス、デバイス ツリー、ホット スワップをサポートできないなど、いくつかの欠点もあります。これらの問題を解決するために、この記事では新しいデバイス ドライバー フレームワーク、3 2 1 デバイス認識ドライバー フレームワークを紹介します。これは、misc サブシステムとプラットフォーム サブシステムの組み合わせに基づいており、より多くの機能と特徴を実現できます。

Linux カーネルの 2 つの特別なデバイス ドライバー フレームワーク: misc サブシステムと 3+2+1 デバイス認識ドライバー フレームワーク

その他の使用

Linux には、キャラクター デバイス、ネットワーク デバイス、ブロック デバイスという 3 つの主要なデバイス カテゴリがあります。各デバイスは多くのカテゴリに細分化されています。たとえば、キャラクター デバイスは事前に多くのカテゴリに分割されており、これらのカテゴリはファイル内でマークされています主要なデバイス番号はどれですか。それでも、ハードウェアは数千万台あり、常に網をすり抜ける魚がいます。これらの分類が難しい特徴的なデバイスについて、Linux はそれらを均一に記述するために「混合」デバイスを使用します。一般的なメジャー デバイス番号は 10 です。このデバイス番号のみがデバイスを区別するために使用されます ()。これらのデバイスには、主に乱数発生器、LCD、クロック ジェネレータなどが含まれます。さらに、cdev を再カプセル化する多くのサブシステムと同様に、misc もデバイス ファイル を自動的に作成します。これにより、cdev インターフェイスが書き込まれるたびに class_create() と device_create() を使用する必要がなくなります。

カーネルで提供されるその他のオブジェクト:

リーリー

必要なのは、キャラクタ デバイスのように

fops インターフェイスを実装し、それに minor を与えることだけです。マイナーがマクロ MISC_DYNAMIC_MINOR (実際には 255) を使用する場合、カーネルは自動的にマイナー デバイス番号を割り当てます。合意されたマイナー デバイス番号を実装している他のカーネルは、**"include/linux/miscdevice.h"** を参照できます。すべての準備ができたら、次の API を使用してカーネルに登録/ログアウトします。 リーリー

その他の分析

その他は使いやすいですか? Sparrow は小さくて十分な機能を備えていますが、misc の合理化された構造があるからこそ、そこに込められた階層的なアイデアを容易に把握することができます。misc の設計手法は、インターフェイスとして cdev を使用する多くのサブシステムに反映されており、レイヤーの考え方は、Linux ドライバーの 2 つの柱の 1 つです (もう 1 つは分離です)。

設計アイデアから学び、ドライバーの品質を向上させることができます

。次に、misc の内部メカニズムを簡単に分析します。

その他の初期化

Linux のサブシステムとして、misc サブシステムは Linux の起動プロセス中に準備作業を完了します。これには主に

データ構造の初期化、対応するクラスの作成、cdev オブジェクトの作成、初期化、およびカーネルへの登録が含まれます。 、など

。これらの基礎があれば、misc の多くの利点を活用してプログラミングできます。 リーリー

#「

misc_init()

–293–>misc サブシステムはシステム起動時に初期化されます –273–>システム構成によっては、/proc インターフェイスを提供する必要がある場合があります –275–>/sysfs に misc
という名前のクラスを作成します。 –281–>静的メジャー デバイス番号 (10) とカプセル化されたメソッド セット misc_fops を使用して、 register_chrdev() は内部的に cdev オブジェクトを作成し、これらの 2 つのパラメーターを使用してそれを初期化し、カーネルに登録します。この cdev オブジェクトが責任を負いますfor all 無差別デバイスのデバイス番号。 cdev オブジェクトとデバイス番号の関係については、cdev_map を参照してください。
–158–>misc の cdev オブジェクトによって使用される fops. 明らかに、呼び出しプロセスは通常のキャラクター デバイスのプロセス (chrdev_open()->misc_open()) と同じです。

misc_register

接下来,老规矩,我们从”XXX_register”开始分析,在Linux内核中,这些”XXX_register”往往就是一个设备对象注册到内核的接口,是研究当相应对象注册进去之后内核动作的最佳入口。

178 int misc_register(struct miscdevice * misc)
179 {  
180         dev_t dev;
187         if (misc->minor == MISC_DYNAMIC_MINOR) {
188                 int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
193                 misc->minor = DYNAMIC_MINORS - i - 1;
194                 set_bit(i, misc_minors);
195         } 
206         dev = MKDEV(MISC_MAJOR, misc->minor);
208         misc->this_device = device_create(misc_class, misc->parent, dev,
209                                           misc, "%s", misc->name);
210         if (IS_ERR(misc->this_device)) {
211                 int i = DYNAMIC_MINORS - misc->minor - 1;
212                 if (i = 0)
213                         clear_bit(i, misc_minors);
214                 err = PTR_ERR(misc->this_device);
216         }
222         list_add(&misc->list, &misc_list);
226 }

misc_register()
–187–> 如果指定的minor是动态分配,那么进入相关语句块。
–188–> 使dev用位图遍历API-find_first_zero_bit找到最小未用的设备号。
–193–> 得到分配好的次设备号。
–208–> (根据设备号)创建设备文件,使用的是misc_init中创建的misc_class,至此就可以实现misc设备文件的自动创建。就相当与我们在纯粹的cdev驱动中使用class_create()+device_create()创建设备文件。一个设备文件和一个设备号相联系,而misc的所有的设备号都和misc_init创建的cdev对象相联系,所以打开的任何一个misc设备文件首先回调的就是(chrdev_open()->)misc_open()。
–222–> 关键,将这个新分配的misc加入到misc链表中,用于管理所有的misc设备,便于misc_open()提取具体设备的fops。

misc_open

构建的misc子系统,将设备添加到了该子系统中,接下来我们来看一下应用层程序是如何打开一个misc设备的。由于misc也是一种字符设备,所以其提供的接口也是位于/dev中。但是正如misc的定义,其中的设备五花八门却共用同一个主设备号,这就意味着最终被chrdev_open回调的misc_open一定要具备根据被打开的不同文件为file结构准备不同的操作方法这一能力,即在驱动中实现对子设备的识别,或者称之为”多态”。

112 static int misc_open(struct inode * inode, struct file * file)
113 {
114         int minor = iminor(inode);
115         struct miscdevice *c;
116         int err = -ENODEV;
117         const struct file_operations *new_fops = NULL;
121         list_for_each_entry(c, &misc_list, list) {
122                 if (c->minor == minor) {
123                         new_fops = fops_get(c->fops);           
124                         break;
125                 }
126         }
144         replace_fops(file, new_fops);
145         if (file->f_op->open) {
146                 file->private_data = c;
147                 err = file->f_op->open(inode,file);
148         }
152 }

misc_open()
–121–>遍历misc设备链表,根据被打开的设备的次设备号找到设备对象。
–123–>存储这个设备对象的操作方法集unique_fops。
–144–>将misc设备具体的操作方法集unique_fops替换到filp中的f_op中,这个位置原来是misc的cdev对象的fops,filp带着这个unique_fops从open()返回,就实现了不同的设备对应不同的操作方法,即面向对象的”多态”

3+2+1多设备识别驱动模型

通过上述对misc机制的分析,我们不难总结出一个支持设备识别的3+2+1驱动模型(3个函数+2个数据结构+1个封装):

  1. 初始化整个驱动组的**xxx_init()**,通常用模块加载函数或总线的probe函数实现;
  2. 用于注册一个子驱动的**xxx_register()**,需要EXPORT到符号表;
  3. 能够根据传入的inode识别具体的设备并将其操作方法集放到filp中的**xxx_open()**。

+

  1. 用于存储每一个驱动对象的通用链表或数组+priv_data
  2. 用于存储子设备号的位图。

+

  1. 将所有的不同的设备用一个统一的结构进行封装

至此,我们就可以写一写这个3+2+1驱动模型的模板。

1个封装

struct multidevice{
    struct list_head head;
    int minor;
    struct file_operations* fops;
    void *priv;     //私有数据,供read/write等接口识别的信息,以及其他数据都放这里
};

2个数据结构

struct list_head multi_dev_list;
unsigned int minors_map;   //根据设备号数目的不同选数据类型or数组

3个函数

int major,baseminor = 0,max_dev = sizeof(minors_map)*8;
#define DEV_NAME "multi_device"
struct class *cls;
xxx_open(struct inode *inode,struct file *file){
    int minor = iminor(inode);
         struct multidevice *dp;
         const struct file_operations *new_fops = NULL;
                  list_for_each_entry(dp, &multi_dev_list, head) {
                     if (dp->minor == minor) {
                         new_fops = fops_get(dp->fops);           
                         break;
                 }
         }
         replace_fops(file, new_fops);
         if (file->f_op->open) {
                 file->private_data = dp
                 file->f_op->open(inode,file);
         }
}

xxx_init(void){
    dev_t devno,
    INIT_LIST_HEAD(&multi_dev_list);
    init_map(&minors_map);
    struct cdev *multi_cdev = cdev_alloc();
    cdev_init(multi_cdev, multi_fops);
    alloc_chrdev_region(&devno, baseminor, count,DEV_NAME);
    major = MAJOR(devno);
    cdev_add(multi_cdev , devno, count);
    cls = class_create(THIS_MODULE, DEV_NAME);
}
/*---------------下面是给待加驱动用的----------------------*/
xxx_register(struct *multidevice dev){
            dev_t dev;
         if (dev->minor == MISC_DYNAMIC_MINOR) {
                 int i = find_first_zero_bit(minors_map, DYNAMIC_MINORS);
                 dev->minor = DYNAMIC_MINORS - i - 1;
                 set_bit(i, minors_map);
         } 
         dev_t pri_devno = MKDEV(major, dev->minor);
         device_create(multi_class, NULL, pri_devno, "%s", misc->name);
         list_add(dev->head, &multi_dev_list);
}
EXPORT_SYMBOL(xxx_register)

通过本文,我们了解了misc子系统和3+2+1设备识别驱动框架的原理和方法,它们可以用来实现一些特殊的设备驱动,如识别设备,虚拟设备,混合设备等。我们应该根据实际需求选择合适的框架,并遵循一些基本原则,如使用正确的注册和注销函数,使用正确的文件操作结构体,使用正确的设备树节点等。misc子系统和3+2+1设备识别驱动框架是Linux内核中两个有用而灵活的设备驱动框架,它们可以提升设备驱动的兼容性和可扩展性,也可以提升开发者的效率和质量。希望本文能够对你有所帮助和启发。

以上がLinux カーネルの 2 つの特別なデバイス ドライバー フレームワーク: misc サブシステムと 3+2+1 デバイス認識ドライバー フレームワークの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlxlinux.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。