Die große Vielfalt der heute eingesetzten Hardware erfordert eine kaum übersichtlichere Anzahl an Treibern und Modulen im Linux-Kernel. Funktioniert die automatische Hardware-Erkennung einmal nicht wie gewohnt, etwa weil die installierte Distribution nicht mehr startet oder eine neu eingebaute Komponente nicht automatisch erkennt, muss der Administrator selbst nach den passenden Kernelmodulen suchen.
Prinzipiell stellen der Kernel und die Modullisten alle nötigen Informationen bereit, um den zum jeweiligen Gerät gehörigen Treiber zu finden angesichts generischer Treiber für ganze Geräteklassen kann die Suche allerdings sehr kompliziert sein.
Die Skripte »pcidetect« für PCI und »usb-detect« für USB von [1] erleichtern den Umgang mit Rettungssystemen, Mini-Distributionen, Rescue-CDs und Embedded-Linux-Installationen, indem sie auflisten, welche Treiber direkt im Kernel einkompiliert sind, welche Module eventuell nachzuladen sind und welche Hardware vom aktuell laufenden Kernel gar nicht unterstützt wird.
Kernel-Interfaces
Die Hardware-Erkennung für PCI, USB und Firewire ist mit ein wenig Hintergrundwissen keine Hexerei und lässt sich mit nahezu jeder beliebigen Programmiersprache realisieren der Autor wählte die Bash für die beiden Beispiel-Skripte von [1]. Alle nötigen Informationen zur Hardware wie Hersteller, Gerät und Geräteklasse stellt der Kernel per SysFS oder Proc zur Verfügung.
Am einfachsten funktioniert die Hardware-Erkennung mit SysFS, da hier anders als beim Proc-Interface keine Binärdaten zu verarbeiten sind.
Bei Sysfs gibt es für jedes PCI-Gerät unterhalb von »/sys/bus/pci/devices« einen symbolischen Link mit der jeweiligen PCI-ID, der auf das entsprechende Geräteverzeichnis unterhalb von »/sys/devices/pci*« zeigt. Der Zugriff über »/sys/bus/pci/devices« gestaltet sich einfacher, weil hier alle PCI-Geräte aller PCI-Busse zusammengefasst sind, während es unterhalb von »/sys/devices« für jeden PCI-Bus ein separates Verzeichnis mit den Geräten gibt.
Das Geräteverzeichnis enthält alle für die Hardware-Erkennung nötigen Daten: »vendor« verrät die Vendor-ID des Geräteherstellers in Hexadezimal-Schreibweise, »device« die Product-ID und »class« die Geräteklasse nach [3]. Die Zeilen 11 bis 16 von Listing 1 lesen die für die Hardwarebestimmung nötigen Daten aus der SysFS-Struktur ein.
Unterhalb von »/proc/bus/pci« sind die Pseudodateien der Geräte nach PCI-Controllern sortiert aufgelistet. Jede Gerätedatei enthält alle Angaben in konzen-trierter Form, die SysFS einzeln bereitstellt. Die Zeilen 18 bis 20 in Listing 1 zeigen den Abschnitt aus dem PCI-Hardware-Erkennungsskript »pcidetect« von [1], der Vendor- und Product-ID sowie den Class Code ermittelt. Eine komplette Beschreibung der Pseudodatei liefert der Artikel aus [4].
PCI-ID-Datenbank
Für die Klartextausgabe von Hersteller und Namen der PCI-Geräte benötigt das Hardware-Erkennungsskript die PCI-ID-Datenbank von [2], die auch der Linux-Kernel und »lspci« verwenden. Die PCI-Datenbank lässt sich sehr einfach parsen, Listing 2 zeigt den entsprechenden Abschnitt aus »pcidetect«. Die Variable »PCIIDCMD« enthält den Befehl zum Ein-lesen der PCI-ID-Datenbank, entweder ein einfaches »cat« der Datei oder einen entsprechenden »wget«-Aufruf.
In der Datei »pci.db« besteht jeder Hersteller- oder Geräte-Eintrag aus einer Zeile, in der die einzelnen Felder per Tabulator getrennt sind. Um jeweils eine komplette Zeile abzuarbeiten, setzt Zeile 1 von Listing 2 die Trennzeichen-Variable »IFS« auf den Zeilenumbruch. Um die Zeilen der Datenbank in ihre Felder aufzuspalten, schreibt Zeile 3 des Listings ein Tabulatorzeichen in die Variable »IFS«. Der »set«-Aufruf in Zeile 4 übernimmt dann die Trennung.
Die Abfrage in Zeile 8, ob die vierte Spalte eine »0« enthält, dient der Qualitätssicherung: Die PCI-Datenbank kann von jedermann erweitert werden, solche neuen Einträge werden mit einer »1« in Spalte 4 gekennzeichnet. Verifizierte Einträge bekommen dann eine »0«. Die Vendor-ID bei Herstellereinträgen und die kombinierte Vendor- und Device-ID bei Geräte-Einträgen sowie die Beschreibung speichern die Zeilen 9 und 13.
01 if [ -e /sys/bus/pci/devices ]; then
02 PCIDevices=/sys/bus/pci/devices/*
03 Method="sysfs"
04 elif [ -e /proc/bus/pci ]; then
05 PCIDevices=/proc/bus/pci/??/*
06 Method="proc"
07 fi
08
09 for device in $PCIDevices; do
10 if [ "$Method" = "sysfs" ]; then
11 read Vendor < ${device}/vendor
12 Vendor=${Vendor:2:4}
13 read Device < ${device}/device
14 Device=${Device:2:4}
15 read Class < ${device}/class
16 Class=${Class:2:4}
17 elif [ "$Method" = "proc" ]; then
18 Vendor=`hexdump -s 0 -n 2 -e '1/2 "%04x"' $device`
19 Device=`hexdump -s 2 -n 2 -e '1/2 "%04x"' $device`
20 Class=`hexdump -s 10 -n 2 -e '1/2 "%04x"' $device`
21 fi
|
01 IFS="${Newline}"
02 for z in `eval ${PCIIDCMD}`; do
03 IFS="${Tab}"
04 set -- $z
05
06 case "$1" in
07 v)
08 if [ "$4" = "0" ]; then
09 declare v${2}=$3
10 fi
11 ;;
12 d)
13 declare d${2}=$3
14 ;;
15 esac
16 done
|