Heim > System-Tutorial > LINUX > Hauptteil

Zwei spezielle Gerätetreiber-Frameworks im Linux-Kernel: Misc-Subsystem und 3+2+1-Geräteerkennungs-Treiber-Framework

WBOY
Freigeben: 2024-02-12 18:21:10
nach vorne
898 Leute haben es durchsucht

Das Misc-Subsystem ist ein einfaches und flexibles Gerätetreiber-Framework im Linux-Kernel. Es kann zum Implementieren einiger Gerätetreiber verwendet werden, die nicht zu anderen Subsystemen gehören, z. B. Zeichengeräte, virtuelle Geräte, Hybridgeräte usw. Der Vorteil des Misc-Subsystems besteht darin, dass es einfach und benutzerfreundlich ist. Es muss nicht viel Code geschrieben werden und es müssen nur einige grundlegende Betriebsfunktionen implementiert werden. Das Misc-Subsystem weist jedoch auch einige Mängel auf, z. B. die Unfähigkeit, mehrere Geräteinstanzen, Gerätebäume und Hot-Swapping zu unterstützen. Um diese Probleme zu lösen, wird in diesem Artikel ein neues Gerätetreiber-Framework vorgestellt: das 3+2+1-Geräteerkennungs-Treiber-Framework, das auf der Kombination aus verschiedenen Subsystemen und Plattform-Subsystemen basiert und mehr Funktionen und Features erreichen kann.

Zwei spezielle Gerätetreiber-Frameworks im Linux-Kernel: Misc-Subsystem und 3+2+1-Geräteerkennungs-Treiber-Framework

Verwendung von Sonstigem

In Linux gibt es drei Hauptkategorien von Geräten: Zeichen-, Netzwerk- und Blockgeräte. Beispielsweise sind Zeichengeräte in viele Kategorien unterteilt, und das von diesen Kategorien verwendete Hauptgerät ist markiert In der Datei gibt es aber trotzdem Dutzende Millionen Hardware, und es gibt immer Fische, die durch das Netz schlüpfen. Für diese Charaktergeräte, die schwer zu klassifizieren sind, verwendet Linux „gemischte“ Geräte, um sie einheitlich zu beschreiben , und weisen Sie ihnen ein gemeinsames Hauptgerät Nr. 10 zu. Verwenden Sie diese Gerätenummer nur zur Unterscheidung von Geräten. Zu diesen Geräten gehören hauptsächlich Zufallszahlengeneratoren, LCDs, Taktgeneratoren usw. Darüber hinaus erstellt misc, wie viele Subsysteme, die auch cdev neu kapseln, auch automatisch Gerätedateien, wodurch die Verwendung von class_create() und device_create() bei jedem Schreiben der cdev-Schnittstelle entfällt.

Verschiedene im Kernel bereitgestellte Objekte:

//include/linux/miscdevice.h
 55 struct miscdevice  {    
 56         int minor;
 57         const char *name;
 58         const struct file_operations *fops;
 59         struct list_head list;
 60         struct device *parent;
 61         struct device *this_device;
 62         const char *nodename;
 63         umode_t mode;
 64 };
Nach dem Login kopieren

Wir müssen die

fops-Schnittstelle nur wie ein Zeichengerät implementieren und ihm einen Minor geben. Wenn der Minor das Makro MISC_DYNAMIC_MINOR (eigentlich 255) verwendet, weist der Kernel automatisch eine Minor-Gerätenummer zu, und andere Kernel haben die Vereinbarung bereits umgesetzt. Die Nebengerätenummer finden Sie unter **"include/linux/miscdevice.h"**. Sobald alles fertig ist, verwenden Sie einfach die folgende API, um sich beim Kernel zu registrieren/abzumelden

178 int misc_register(struct miscdevice * misc)
238 int misc_deregister(struct miscdevice *misc)
Nach dem Login kopieren

sonstige Analyse

Ist es einfach, Sonstiges zu verwenden? Obwohl Sparrow klein und gut ausgestattet ist, können wir die darin enthaltenen vielschichtigen Ideen aufgrund der optimierten Struktur von misc leicht erfassen. Die Entwurfsmethode von misc spiegelt sich in vielen Subsystemen wider, die cdev als Schnittstelle verwenden Die klaren Unterteilungen zwischen ihnen sind: Die Schichtidee ist eine der beiden Säulen von Linux-Treibern (die andere ist die Trennung).

Wir können aus den Designideen lernen und die Qualität unserer Fahrer verbessern. Als nächstes analysieren wir kurz den internen Mechanismus verschiedener Dinge.

misc_init

Als Subsystem von Linux führt das Misc-Subsystem die Vorbereitungsarbeiten während des Linux-Startvorgangs durch, die hauptsächlich Folgendes umfassen:

Initialisieren der Datenstruktur, Erstellen der entsprechenden Klasse, Erstellen, Initialisieren und Registrieren des CDev-Objekts im Kernel usw. . Mit diesen Grundlagen können wir programmieren und dabei die vielen Vorteile von Sonstiges nutzen.

//drivers/char/misc.c
56 static const struct file_operations misc_fops = {
157         .owner          = THIS_MODULE,
158         .open           = misc_open,
159         .llseek         = noop_llseek,
160 };
268 static int __init misc_init(void)
269 {
272 #ifdef CONFIG_PROC_FS
273         proc_create("misc", 0, NULL, &misc_proc_fops);
274 #endif
275         misc_class = class_create(THIS_MODULE, "misc");
281         if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
282                 goto fail_printk;
283         misc_class->devnode = misc_devnode;
284         return 0;
292 }
293 subsys_initcall(misc_init);   
Nach dem Login kopieren

misc_init() –293–>Das sonstige Subsystem wird beim Systemstart initialisiert
–273–>Abhängig von der Systemkonfiguration muss möglicherweise die /proc-Schnittstelle bereitgestellt werden
–275–>Erstellen Sie in /sysfs eine Klasse mit dem Namen misc
–281–>Unter Verwendung der statischen Hauptgerätenummer (10) und des gekapselten Methodensatzes misc_fops erstellt register_chrdev() intern ein CDev-Objekt und verwendet diese beiden Parameter, um es zu initialisieren und beim Kernel zu registrieren für alle Die Gerätenummer des promiskuitiven Geräts. Informationen zur Beziehung zwischen cdev-Objekten und Gerätenummern finden Sie unter cdev_map.
–158–>fops, die vom cdev-Objekt von misc verwendet werden, ist offensichtlich derselbe wie bei gewöhnlichen Zeichengeräten, 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 }
Nach dem Login kopieren

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 }
Nach dem Login kopieren

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等接口识别的信息,以及其他数据都放这里
};
Nach dem Login kopieren

2个数据结构

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

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)
Nach dem Login kopieren

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

Das obige ist der detaillierte Inhalt vonZwei spezielle Gerätetreiber-Frameworks im Linux-Kernel: Misc-Subsystem und 3+2+1-Geräteerkennungs-Treiber-Framework. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:lxlinux.net
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!