1. Einführung in den Plattformbus1.1. Trennung und Schichtung von Linux-Treibern1.1.1. Trennung der Linux-TreiberLassen Sie uns zunächst über die Trennung der Linux-Treiber sprechen. Das Linux-Betriebssystem unterstützt die Ausführung auf verschiedenen CPU-Typen. Da jede CPU unterschiedliche Gerätetreiber hat, hat sich im Linux-Kernel eine große Menge Code angesammelt. Diese Codes haben ungefähr die gleiche Beschreibung desselben Geräts, was den Kernel-Code sehr redundant macht. Nehmen wir als Beispiel die CPU, die MPU6050 über I2C steuert: Aus der Abbildung können wir ersehen, dass jede Plattform über einen Satz Host-Treiber und einen Satz Gerätetreiber verfügt. Da der I2C-Controller jeder Plattform unterschiedlich ist, muss jede Plattform ihren eigenen Host-Treiber haben. Der von allen verwendete MPU6050 ist jedoch derselbe, sodass es durchaus möglich ist, einen Satz Gerätetreibercodes gemeinsam zu nutzen. Das verbesserte Framework sieht wie folgt aus: Dies gilt natürlich nur für das MPU6050-Gerät unter I2C. In der Praxis werden viele Geräte definitiv unter I2C montiert. Basierend auf dieser Idee können wir das Framework wie folgt erhalten: Bei der tatsächlichen Entwicklung wird der I2C-Hosttreiber vom Halbleiterhersteller geschrieben, und der Gerätetreiber wird ebenfalls vom Gerätehersteller geschrieben. Wir müssen nur Geräteinformationen bereitstellen, z. B. an welche I2C-Schnittstelle das Gerät angeschlossen ist und wie hoch die I2C-Geschwindigkeit ist. Dies entspricht dem Entfernen der Geräteinformationen aus dem Gerätetreiber. Der Gerätetreiber verwendet außerdem Standardmethoden zum Abrufen von Geräteinformationen (z. B. das Abrufen von Geräteinformationen aus dem Gerätebaum). Dies entspricht dem Treiber, der nur für das Ansteuern verantwortlich ist, und dem Gerät (der Information), das nur für das Gerät verantwortlich ist. Sie müssen nur einen Weg finden, die beiden zusammenzuführen. Der Bus ist derjenige, der diese Zusammenführungsarbeit erledigt, was das Bus-Treiber-Geräte-Modell in Linux darstellt. Das Strukturdiagramm sieht wie folgt aus: 1.2. Plattformbasiertes ModellOben haben wir über die Trennung von Gerätetreibern gesprochen und das Bus-Treiber-Gerätemodell erhalten. Dieser Bus ist das, was ich normalerweise I2C, SPI, USB und andere Busse nenne. Das Problem besteht jedoch darin, dass einige Geräte nicht über einen bestimmten Bus laufen müssen. Hier kommt der Plattformbus ins Spiel. Dabei ist zu beachten, dass es sich beim Plattformbus um einen virtuellen Bus handelt, der sich von Bussen wie USB, SPI und I2C unterscheidet. Es wird als virtuell bezeichnet, da das SoC und einige Peripheriegeräte wie LEDs, Timer und Summer über den Speicheradressraum angesprochen werden, die CPU also keinen Bus zur Kommunikation mit diesen Geräten benötigt und in der Hardware daher kein solcher Bus vorhanden ist. Der Kernel benötigt jedoch eine einheitliche Verwaltung dieser Geräte. Daher wird für die Geräte, die direkt über den Speicher angesprochen werden, ein virtueller Plattformbus erstellt und alle Geräte, die direkt über den Speicher angesprochen werden, werden diesem virtuellen Bus zugeordnet. Vorteile des Plattformbusses: 1. Über den Plattformbus können Sie alle auf dem Plattformbus montierten Geräte durchlaufen. 2. Trennen Sie das Gerät und den Treiber. Über den Plattformbus werden das Gerät und der Treiber separat registriert. Da eine Prüffunktion vorhanden ist, kann der zum Gerät passende Treiber jederzeit erkannt werden. Wenn die Übereinstimmung erfolgreich ist, wird der Treiber beim Kernel registriert. 3. Ein Treiber kann von mehreren Geräten desselben Typs verwendet werden. Diese Funktion wird dadurch erreicht, dass während der Treiberregistrierung ein Vorgang zum Durchlaufen von Geräten stattfindet. 2. Plattform-Framework2.1. PlattformbusDer Linux-Kernel verwendet die bus_type-Struktur zur Darstellung des Busses. Die von uns verwendeten I2C-, SPI- und USB-Geräte werden alle mithilfe dieser Struktur definiert. Der Aufbau ist wie folgt: /* include/linux/device.h */ Struktur bus_type { const char *name; /* Busname*/ const char *Gerätename; Strukturgerät *dev_root; Struktur Geräteattribut *dev_attrs; const struct attribute_group **bus_groups; /* Busattribute*/ const struct attribute_group **dev_groups; /* Geräteattribute*/ const struct attribute_group **drv_groups; /* Treiberattribute*/ int (*match)(struct device *dev, struct device_driver *drv); /* Gerätetreiber-Matching-Funktion*/ int (*uevent)(Struktur Gerät *dev, Struktur kobj_uevent_env *env); int (*probe)(Strukturgerät *dev); int (*entfernen) (Strukturgerät *dev); void (*shutdown)(Struktur Gerät *dev); int (*online) (Strukturgerät *dev); int (*offline) (Struktur Gerät *dev); int (*suspend) (Struktur Gerät *dev, pm_message_t Status); int (*fortsetzen)(Struktur Gerät *dev); Konstantenstruktur dev_pm_ops *pm; const-Struktur iommu_ops *iommu_ops; Struktur subsys_private *p; Struktur lock_class_key lock_key; }; Der Plattformbus ist eine Konstante vom Typ bus_type. Er wird als Konstante bezeichnet, weil dieser Variable vom Linux-Kernel ein Wert zugewiesen wurde und die ihren Strukturmitgliedern entsprechenden Funktionen ebenfalls im Kernel geschrieben wurden. Die Definition lautet wie folgt: /* Treiber/Basis/Plattform.c */ Struktur Bustyp Plattformbustyp = { .name = "Plattform", .dev_groups = Plattform-Entwicklergruppen, .match = platform_match, /* Matching-Funktion */ .uevent = Plattform_uevent, .pm = &platform_dev_pm_ops, }; Das platform_match in platform_bus_type ist die Funktion, die wir zuvor zum Abgleichen von Treibern und Geräten erwähnt haben. Die Funktion ist wie folgt definiert: /* Treiber/Basis/Plattform.c */ statische int platform_match(Struktur Gerät *dev, Struktur Gerätetreiber *drv) { Struktur Plattformgerät *pdev = zum_Plattformgerät(dev); Struktur platform_driver *pdrv = to_platform_driver(drv); /*Wenn driver_override gesetzt ist, nur an den passenden Treiber binden*/ wenn (pdev->Treiber_Override) gibt !strcmp(pdev->Treiber_Override, drv->Name) zurück; /* Die kompatible Matching-Tabelle in der of_match_table des Gerätebaums OF-Typ Matching Driver Base Class wird mit dem kompatiblen Attribut jedes Geräteknotens im Gerätebaum verglichen. Wenn sie gleich sind, bedeutet dies, dass der Abgleich erfolgreich war*/ wenn (von_Treiber_zu_Gerät_passen(dev, drv)) Rückgabe 1; /* ACPI-Übereinstimmung */ wenn (acpi_driver_match_device(dev, drv)) Rückgabe 1; /* id_table entspricht dem id_table-Array im Plattformtreiber, in dem viele ID-Informationen gespeichert werden*/ wenn (pdrv->id_table) gibt platform_match_id(pdrv->id_table, pdev) zurück != NULL; /* Beim Namensabgleich werden die Namensinformationen im Plattformtreiber und im Gerät direkt und grob verglichen*/ Rückgabewert (strcmp(pdev->name, drv->name) == 0); } Wir können es genauso gut in der Schwebe halten, wann und wo diese Matching-Funktion verwendet wird. 2.2 Plattformtreiber2.2.1 、 PlattformtreiberdefinitionDer Plattformtreiber wird durch die Struktur platform_driver dargestellt, deren Inhalt folgender ist: /* include/linux/platform_device.h */ Struktur Plattformtreiber { int (*probe)(struct platform_device *); /* Der Plattformtreiber führt diese Prüffunktion aus, nachdem er das Plattformgerät abgeglichen hat*/ int (*entfernen) (Struktur platform_device *); void (*Herunterfahren) (Struktur Plattformgerät *); int (*suspendieren) (Struktur platform_device *, pm_message_t Status); int (*fortsetzen)(Struktur platform_device *); struct device_driver driver; /* Treiber-Basisklasse*/ const struct platform_device_id *id_table; /* id_table-Tabelle*/ bool verhindert_aufgeschobene_Probe; }; Die const struct platform_device_id *id_table in platform_driver ist die id_table-Tabelle, die verwendet wird, wenn der Plattformbus den Treiber und das Gerät mithilfe der id_table-Tabellenabgleichsmethode abgleicht. Diese id_table-Tabelle ist eigentlich ein Array, und jeder Elementtyp darin ist platform_device_id. platform_device_id ist eine Struktur mit folgendem Inhalt: Struktur platform_device_id { Zeichenname [PLATTFORMNAME_GRÖSSE]; kernel_ulong_t Treiberdaten; }; In platform_driver ist driver eine Treiberbasisklasse, die den grundlegendsten Attributen des Treibers entspricht. Die Attribute unter verschiedenen Bussen werden in der platform_driver-Struktur gespeichert. Der Inhalt der Treiber-Basisklassenstruktur device_driver ist: /* include/linux/device.h */ Struktur Gerätetreiber { const char *name; /* Die vierte Methode zum Abgleichen von Geräten und Treibern über den Plattformbus besteht darin, die Namensfelder der beiden direkt und grob abzugleichen*/ Struktur bus_type *bus; Strukturmodul *Eigentümer; const char *mod_name; bool unterdrücken_binden_attrs; const struct of_device_id *of_match_table; /* Vom Treiber verwendete Matching-Tabelle bei Verwendung des Gerätebaums*/ Konstante Struktur acpi_device_id *acpi_match_table; int (*probe) (Strukturgerät *dev); int (*entfernen) (Strukturgerät *dev); void (*shutdown) (Strukturgerät *dev); int (*suspend) (Struktur Gerät *dev, pm_message_t Status); int (*fortsetzen) (Strukturgerät *dev); const struct attribute_group **Gruppen; Konstantenstruktur dev_pm_ops *pm; Struktur driver_private *p; }; Of_match_table im Treiber ist auch eine Matching-Tabelle. Diese Matching-Tabelle wird vom Plattformbus verwendet, um den Treiber und das Gerät mithilfe des Gerätebaums abzugleichen. Es ist auch ein Array. Die Array-Elemente sind alle vom Typ of_device_id. Die Struktur dieses Typs ist wie folgt: /* include/linux/mod_devicetable.h */ Struktur of_device_id { Zeichenname[32]; Zeichentyp[32]; char compatible[128]; /* Bei Verwendung des Gerätebaum-Matchings wird der kompatible Attributwert des Geräteknotens mit dem kompatiblen jedes Elements in of_match_table verglichen. Wenn sie gleich sind, bedeutet dies, dass das Gerät und der Treiber erfolgreich übereinstimmen*/ const void *Daten; }; 2.2.2, PlattformtreiberregistrierungNachdem Sie den Plattformtreiber mit der platform_driver-Struktur definiert haben, verwenden Sie die Funktion platform_driver_register, um den Plattformtreiber beim Linux-Kernel zu registrieren. Der allgemeine Ablauf der Funktion ist wie folgt: Plattformtreiberregister (DRV) -> __Plattformtreiberregister -> drv->driver.probe = platform_drv_probe; /* Weise die Funktion platform_drv_probe der Probe-Funktion der Treiber-Basisklasse dryer im Plattformtreiber zu*/ -> driver_registe (&drv->driver) /* Registrieren Sie den Basisklassentreiber des Treibers beim Linux-Kernel */ -> ...... -> drv->driver->probe /* Abschließend die Probe-Funktion der Treiber-Basisklasse driver ausführen, Tatsächlich handelt es sich um die oben angegebene Funktion platform_drv_probe*/ -> Plattform_Treiberprobe -> drv->probe /* Die Funktion platform_drv_probe führt die Probefunktion des Plattformtreibers drv aus*/ In der obigen Analyse haben wir den Schritt von driver_register (&drv->driver) zu drv->driver->probe durch Auslassungspunkte ersetzt. Lassen Sie uns das nun analysieren: Treiberregister(&drv->Treiber) -> bus_add_driver /* Treiber zum Bus hinzufügen */ -> Treiber_Anhängen -> bus_for_each_dev /* Suche nach jedem Gerät unter dem Bus, d. h. Durchquerungsvorgang */ -> __driver_attach /* Jedes Gerät ruft diese Funktion auf*/ -> driver_match_device /* Prüfen, ob es übereinstimmt */ -> Rufen Sie die Match-Funktion unter Bus-> Driver_probe_device auf. /* Führen Sie diese Funktion nach erfolgreichem Matching aus*/ -> wirklich_probe -> drv->probe /* Führe die Probefunktion unter drv aus*/ Gemäß dem Funktionsablauf driver_register wissen wir, dass die Bus-Match-Funktion hier durchlaufen und verwendet wird, was eine Frage beantwortet, die wir zuvor gestellt haben: Wo wird die Bus-Match-Funktion verwendet? Sobald der Match erfolgreich ist, wird er in die Testfunktion des Treibers eingegeben. Aus dem Funktionsablauf von platform_driver_register können wir eine Schlussfolgerung ziehen: Der Prozess der Registrierung des Plattformtreibers beim Linux-Kernel umfasst einen Prozess des Durchlaufens der Treiber- und Geräteübereinstimmung. Nach einer erfolgreichen Übereinstimmung wird schließlich die Prüffunktion des Plattformtreibers ausgeführt. Die Prüffunktion des Treiberbasisklassentreibers und die Funktion platform_drv_probe im Prozess sind lediglich Übergangsfunktionen, um diesen Zweck zu erreichen. Es ist erwähnenswert, dass die Plattform-Treiber-Testfunktion, die letztendlich ausgeführt wird, von uns geschrieben wurde, sodass die Initiative wieder in unseren Händen liegt. 2.3, Plattformausrüstung2.3.1 、 PlattformgerätedefinitionWenn die von uns verwendete Linux-Version den Gerätebaum unterstützt, beschreiben Sie das Gerät im Gerätebaum. Wenn der Gerätebaum nicht unterstützt wird, müssen wir das Plattformgerät definieren. Ein Punkt, den wir hierbei berücksichtigen müssen, ist, dass die Matching-Funktion unter dem Bus zuerst den Gerätebaum, dann die ID_table-Tabelle und dann das Namensfeld abgleicht. Wenn der Gerätebaum unterstützt wird, können Sie die Geräteinformationen direkt im Gerätebaumknoten ändern. Wenn der Kernel gestartet wird, durchläuft er automatisch die Gerätebaumknoten. Wenn die Übereinstimmung erfolgreich ist, wird automatisch ein Plattformgerät zur Verwendung im nächsten Schritt generiert. Wenn es sich nicht um einen Gerätebaum handelt, wird dieses Plattformgerät vom Entwickler geschrieben. Hier verwenden wir nicht den Gerätebaum, sondern definieren das Plattformgerät selbst. Das Plattformgerät wird durch die platform_device-Struktur dargestellt, die wie folgt definiert ist: /* include/linux/platform_device.h */ Struktur Plattformgerät { const char *name; /* Gerätename, muss mit dem Namen des entsprechenden Plattformtreibers übereinstimmen, Andernfalls kann das Gerät nicht mit dem entsprechenden Treiber übereinstimmen*/ Int-ID; bool id_auto; Strukturgeräte-Entwicklungstool; u32 Anzahl_Ressourcen; Strukturressource *Ressource; const struct platform_device_id *id_eintrag; char *driver_override; /* Treibername, um eine Übereinstimmung zu erzwingen */ /* MFD-Zellenzeiger */ Struktur mfd_cell *mfd_cell; /* Architekturspezifische Ergänzungen */ Struktur pdev_archdata archdata; }; 2.4. Plattform-Matching-ProzessDer Vorgang des Zuordnens des Plattformbusses zum Treiber und zum Gerät wurde oben bereits ausführlich beschrieben. Lassen Sie uns das Ganze nun zusammenfassen und noch einmal durchgehen. Wie bereits erwähnt, wird die Zuordnung von Treibern und Geräten unter dem Bus durch die Match-Funktion unter dem Bus erreicht. Die Match-Funktionen, die den verschiedenen Bussen entsprechen, sind definitiv unterschiedlich. Darüber müssen wir uns keine Gedanken machen, da der Kernel sie schreiben wird. Die Match-Funktion, die dem von uns verwendeten Plattformbus entspricht, ist die Funktion platform_match. Lassen Sie uns diese Funktion analysieren: Plattformübereinstimmung -> of_driver_match_device /* Gerätebaum-Matching */ -> acpi_driver_match_device /* ACPI-Abgleich */ -> Plattform_Übereinstimmungs-ID /* Plattform_Treiber->ID_Tabellenübereinstimmung*/ -> strcmp(pdev->name, drv->name) /* Name stimmt überein*/ Durch eine einfache Analyse der obigen Matching-Funktion wissen wir, dass die Matching-Funktion zuerst den Gerätebaum, dann die ID_Table-Tabelle und anschließend das Namensfeld mit roher Gewalt abgleicht. Bei Linux-Versionen, die Gerätebäume unterstützen, können wir direkt einen Gerätebaumabgleich durchführen. Wenn der Gerätebaum nicht unterstützt wird, müssen wir das Plattformgerät definieren und dann die id_tabale-Tabelle oder die Namensübereinstimmung verwenden. Im Allgemeinen wird die Namensübereinstimmung ausgewählt. Schauen wir uns nun den Matching-Prozess unter den Bedingungen des Gerätebaums genauer an: of_driver_match_device /* Die Funktion wird im Allgemeinen für den Gerätebaum verwendet, was uns auch einen Hinweis gibt*/ ->des_übereinstimmenden_Gerätes (antriebs->der_übereinstimmenden_Tabelle, Gerät) -> des_Übereinstimmungsknotens -> __von_Übereinstimmungsknoten -> __des_Gerätes_ist_kompatibel -> __of_find_property(device, "compatible", NULL) /* Holt den kompatiblen Eigenschaftswert*/ Aus der obigen Analyse wissen wir, dass der Matching-Prozess letztendlich die kompatible Eigenschaft in der of_match_table der Treiberbasisklasse mit der kompatiblen Eigenschaft im Gerätebaumknoten vergleicht. Dies ist ein Mechanismus, der den Gerätebaum mit dem Plattformbus verbindet, wodurch der Zweck erreicht wird, Geräteinformationen in den entsprechenden Knoten des Gerätebaums zu schreiben und den Treiber separat zu schreiben. Dies ist die Treibertrennung, über die wir zuvor gesprochen haben. 3. ZusammenfassungIm eigentlichen Entwicklungsprozess müssen wir kein Plattformbusmodell schreiben, da es bereits im Kernel für uns definiert wurde. Unsere Analyse des Plattformbusmodells dient hauptsächlich dazu, herauszufinden, wie Treiber und Geräte abgeglichen werden, das heißt, wie wir den entsprechenden Treiber finden, wenn wir ein Gerät einfügen, oder wie wir das entsprechende Gerät finden, wenn wir einen Treiber einfügen, und schließlich die Prüffunktion aufzurufen. Tatsächlich ist es egal, ob der Treiber zuerst und das Gerät später kommt oder ob das Gerät zuerst und der Treiber später kommt: Das erste, was nach der endgültigen Übereinstimmung zu tun ist, ist die Ausführung der Prüffunktion des Treibers. So können wir die Wendungen der emotionalen Verstrickung in der Mitte getrost ignorieren und uns direkt auf die endgültige Prüffunktion konzentrieren. Dies ist das Ende dieses Artikels mit der detaillierten Erklärung des Plattformbusses des Linux-Treibers. Weitere relevante Inhalte zum Plattformbus des Linux-Treibers finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den verwandten Artikeln weiter unten. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! |
<<: Der Unterschied zwischen HTML-Name-ID und Klasse_PowerNode Java Academy
>>: Detaillierte Erläuterung der mysql5.6 Master-Slave-Einrichtung und asynchroner Probleme
MySQL Installer bietet eine benutzerfreundliche, ...
Inhaltsverzeichnis 1. Datenbank-Engpass 2. Unterb...
Vorwort Ich habe vor Kurzem MySQL 5.7 installiert...
1. Führen Sie zuerst die Select-Anweisung aus, um...
1|0 Kompilieren Sie den Kernel (1) Führen Sie den...
Möglicherweise verwenden Sie hier Include-Dateien,...
Als ich kürzlich jQuery lernte, stieß ich auf die...
Wenn Sie möchten, dass die gesamte Benutzeroberfl...
Inhaltsverzeichnis 1. Übersicht 2. Definieren Sie...
MySQL-Downloads für alle Plattformen sind unter M...
Zweck Verstehen Sie die Rolle von nextTick und me...
Problembeschreibung (die folgende Diskussion besc...
Detaillierte Erläuterung des Konfigurationsprozes...
Inhaltsverzeichnis Portainer verwaltet mehrere Do...
Inhaltsverzeichnis Join-Syntax: 1. InnerJOIN: (In...