7.5. Systemintegration

Die Realisierung von Treibern in Modulform hat nicht nur – da sie die ständigen Reboots vermeiden helfen – für die Entwicklung selbst Vorteile. Insbesondere während des normalen Betriebs sparen sie Ressourcen; schließlich sind nur die Treiber geladen, die auch benötigt werden.

Da jedoch die Auswahl, das Laden und auch das Konfigurieren des Treibers dem normalen Nutzer nicht zugemutet werden können, muss dieser Prozess automatisiert werden. In Linux sind dazu eine Reihe von Mechanismen eingebaut worden, die

  1. einen Treiber auswählen, wenn eine Applikation auf eine Hardware zugreifen möchte, deren Treiber noch nicht geladen ist (modprobe) und

  2. einen Treiber auswählen, wenn eine neue Hardware erkannt wird (hotplug).

7.5.1. Modutils

Greift eine Applikation auf eine Hardware zu, für die bisher kein Treiber geladen ist, startet der Kernel zunächst auf Applikationsseite modprobe (siehe Abbildung Automatisches Laden von Treibern). Modprobe bekommt vom Kernel mitgeteilt, auf welches Gerät, genauer auf welche Major-Nummer und auf welchen Gerätetyp (Block- oder Chardevice) zugegriffen werden soll. Der Treiberentwickler kann den Namen des Programms (modprobe) über die Datei /proc/sys/kernel/modprobe auslesen bzw. einstellen. Damit modprobe den zugehörigen Treiber laden und betriebsbereit bekommen kann, muss es:

  1. den zugehörigen Treiber,

  2. mögliche Optionen,

  3. abhängige Module (die beispielsweise vorher zu laden sind) und

  4. notwendige User-Programme zur Konfiguration oder auch zum normalen Betrieb des Gerätes kennen.

Abbildung 7-9. Automatisches Laden von Treibern

All diese Informationen sind in der Datei /etc/modprobe.conf abgelegt. Die Syntax der Datei ist einfach. In jeder Zeile ist ein Kommando spezifiziert – mit Ausnahme der Leerzeilen und der mit Hashmark (#) beginnenden Kommentarzeilen.

Folgende Kommandos sind definiert:

Die Module selbst werden bei der Installation eines Kernels in einem Verzeichnis mit dem Namen /lib/modules/<Kernelversion>/ abgelegt. Hier spannt sich ein Baum auf, der für die unterschiedlichen Subsysteme (z.B. Netzwerk) eigene Verzeichnisse enthält, die schließlich die Module bzw. Treiber enthalten. Modprobe nutzt im Übrigen zum eigentlichen Laden des Moduls das in diesem Buch verwendete Programm insmod.

Gibt es zwischen Modulen Abhängigkeiten (zum Beispiel bei geschachtelten Modulen, bei denen das eine Modul Funktionalitäten bietet, auf die das andere Modul aufsetzen kann), nimmt modprobe darauf Rücksicht. Die Abhängigkeiten sind in der Datei modules.dep unterhalb des Modulverzeichnisses /lib/modules/<Kernelversion>/ beschrieben. Die Datei wird mit Hilfe des Programms depmod erstellt.

7.5.2. Hotplug

Auch der zweite Fall, dass der Kernel für ein neues Gerät einen Treiber sucht, wird unterstützt. Identifiziert der Kernel bzw. eines seiner Subsysteme ein neues Gerät, wird das hotplug-Programm aufgerufen. Der Name des Programms kann durch Schreiben der Datei (/proc/sys/kernel/hotplug) festgelegt werden. Als Parameter bekommt dieses Programm (hotplug) die Hardware- respektive Geräte-Identifikation (siehe beispielsweise PCI) übergeben.

Abbildung 7-10. Hotplug-Mechanismus

Aufgrund dieser Geräte-Identifikation kann hotplug zunächst das Subsystem (z.B. PCI oder USB) ermitteln, über welches das Gerät angekoppelt ist. Für jedes Subsystem existiert ein Skript, das aufgerufen wird und den zu ladenden Gerätetreiber bestimmt (siehe Abbildung Hotplug-Mechanismus). Die Skripte selbst befinden sich unterhalb des Verzeichnisses /etc/hotplug/ und werden nach dem Subsystem und dem Zusatz ».agent« benannt (z.B. »pci.agent« oder »usb.agent«).

Die Bestimmung des Gerätetreibers erfolgt ebenfalls aufgrund der Geräte-Identifikation. Sämtliche im System bekannten Geräte sind dazu in einer Tabelle zusammen mit dem Namen des zugehörigen Treibers aufgelistet. Diese Tabelle wird bei der Generierung des Kernels automatisch erstellt. Jeder Treiber muss seinen Beitrag zur Erstellung der Tabelle dergestalt leisten, dass er die Geräte, für die er zuständig ist, bekannt gibt. Hierzu dient das Makro »MODULE_DEVICE_TABLE«. Diesem werden zwei Parameter übergeben. Der erste Parameter gibt das Subsystem an. Gegenwärtig stehen die folgenden Subsysteme zur Auswahl:

Der zweite Parameter ist die Liste mit den unterstützten Geräte-Identifikationen. Der Aufruf von MODULE_DEVICE_TABLE sieht damit beispielhaft folgendermaßen aus:

static const struct pci_device_id __devinitdata mm_pci_ids[] = { {
    .vendor =  PCI_VENDOR_ID_MICRO_MEMORY,
    .device =  PCI_DEVICE_ID_MICRO_MEMORY_5415CN,
    }, {
    .vendor =  PCI_VENDOR_ID_MICRO_MEMORY,
    .device =  PCI_DEVICE_ID_MICRO_MEMORY_5425CN,
    }, {
    .vendor =  PCI_VENDOR_ID_MICRO_MEMORY,
    .device =  PCI_DEVICE_ID_MICRO_MEMORY_6155,
    }, {
    .vendor	=  0x8086,
    .device	=  0xB555,
    .subvendor=0x1332,
    .subdevice=0x5460,
    .class	=  0x050000,
    .class_mask=0,
    }, { /* end: all zeroes */ }
};

MODULE_DEVICE_TABLE(pci, mm_pci_ids);

Das Makro MODULE_DEVICE_TABLE sorgt dafür, dass die Geräteidentifikationen vom Linker so zum Treiber gebunden werden, dass sie vom Programm depmod ausgewertet werden können. Depmod erstellt aus dieser Information unterhalb des Verzeichnisses »/lib/modules/<Kernelversion>/« für jedes Subsystem eine Datei, die mit dem String »modules« beginnt und eine Erweiterung hat, die mit dem Namen des Subsystems und dem String »map« endet. Beispiel: »modules.pcimap« oder »modules.usbmap«

Exportiert ein Treiber die von ihm bedienten Geräte nicht auf diese Weise, kann eine Tabelle im Hotplug-Verzeichnis (/etc/hotplug/) immer noch von Hand erstellt werden. Solche Listen heißen dann beispielsweise »usb.handmap« oder »pci.handmap«.

Darüber hinaus gibt es aber auch die entgegengesetzte Situation, dass ein Modul nicht geladen werden soll, obwohl ein entsprechender Eintrag in den »Maps« vorhanden ist. In diesem Fall wird das Modul in die Datei »blacklist« (ebenfalls im Hotplug-Verzeichnis zu finden) eingetragen.


Lizenz