Weitere Treiberklassen


... [ Seminar Linux und Apache ] ... [ Thema Gerätetreiber unter Linux 2.4 ] ... [ Treiberdesign ] ...

Übersicht: weitere Treiberklassen


SCSI

Das SCSI-Subsystem (Small Computers System Interface) macht nach außen nicht den Eindruck, als ob viel passiert wäre, aber es wurde in grossen Teilen neu geschrieben. Es werden einige neue SCSI-Controller unterstützt.
Jedes Gerät am SCSI-Bus erscheint in /dev entweder als Character- oder als Blockorientiertes Gerät. Die interne Organisation ist aber anders.
So wie Netzwerkkarten dem Netzwerk-Subsystem hardware-bezogene Funktionalität zur Verfügung stellt, so stellt der SCSI-Controller dem SCSI-Subsystem den Zugriff auf das jeweilige Interface-Kabel zur Verfügung. SCSI ist ein Kommunikationsprotokoll zwischen Computer und Peripheriegeräten, wobei jedes Gerät auf das gleiche Protokoll antwortet, unabhängig vom Controller-Board.
Der Linux-Kernel schließt eine SCSI-Implementation ein, bei der die Dateioperationen auf das Protokoll gemappt werden. Der Treiberprogrammierer muß das Mapping zwischen SCSI-Abstraktion und dem physikalischen Kabel implementieren. Das Mapping hängt vom SCSI-Controller ab, es ist völlig unabhängig von den angehängten Geräten.


PCI

PCI hat sich im Laufe der Zeit auf allen möglichen Architekturen etabliert, nicht zuletzt wegen seiner Vorteile: Plug & Play, Plattformunabhängigkeit und hohen Übertragungsraten. PCI-Geräte arbeiten ohne Jumper und werden automatisch beim Booten konfiguriert. Darum muß ein PCI-Treiber die Informationen zur Konfiguration beschaffen können, um die Initialisierung abzuschliessen. Jedes PCI-Gerät wird durch eine Busnummer, eine Gerätenummer und eine Funktionsnummer identifiziert.
Theoretisch sind bis zu 256 Busse möglich, von denen jeder 32 Geräte hosten kann, in der Praxis werden diese Möglichkeiten aber nicht ausgeschöpft.
Ein PCI-Board kann außerdem mehrere Funktionalitäten besitzen, z.B. ein audio device mit CD-ROM-Drive.

Es gibt drei Adressräume: Speicher, I/O-Ports und Konfigurationsregister. Die ersten beiden werden von allen Geräten am PCI-Bus gemeinsam genutzt, der letztere adressiert einen Slot zur Zeit, sodaß es beim Zugriff auf die Konfiguration keine Konflikte gibt.
Ein Treiber benutzt Speicher und I/O-Regionen über inb, readb usw. Transaktionen zur Konfiguration werden über spezielle Kernelfunktionen ausgeführt.
Jeder PCI-Slot hat vier Interrupt-Pins, und jede Gerätefunktion kann einen davon benutzen, ohne sich darum zu kümmern, wie er zur CPU geroutet ist.

Jede Speicher- und I/O-Adressregion kann durch Konfigurations-Transaktionen remappt werden. Das heißt, das die Firmware die PCI-Hardware beim Systemboot (oder später, hot pluggable) initialisiert und dabei diese Regionen auf unterschiedliche Adressen mappt, um Kollisionen zu vermeiden. Diese Adressen können aus dem Konfigurationsspeicher gelesen werden, sodaß der Linuxtreiber seine Geräte ohne Überprüfung ansprechen kann.
Der Konfigurationsspeicher hat 256 Bytes für jede Gerätefunktion, und das Layout der Register ist standardisiert. Vier Bytes enthalten eine eindeutige Funktions-ID, anhand derer ein Treiber sein Gerät identifizieren kann. Neben dem normalen Treibercode muß ein PCI-Treiber also in der Lage sein, auf den Konfigurationsspeicher zuzugreifen.

Der Treiberprogrammierer braucht nur in seltenen Fällen auf diesen zugreifen.
Das Suchen und Identifizieren des Gerätes führt das PCI-Subsystem des Kernels durch. Dieses legt für jedes Gerät, welches am PCI-Bus angeschlossen ist, eine Datenstruktur (struct pci_dev) an, in der die notwendigen Informationen abgelegt sind. Hier finden sich auch die Adressen der Speicherbereiche wieder, die vom Gerät im Konfigurationsspeicher angegeben sind. Da das Betriebssystem unter Umständen die Geräte nicht mit der dort angegebenen Adresse in den Adressraum der CPU mappt, sollte man ohnehin nur die Werte verwenden, die in der jeweiligen Datenstruktur abgelegt sind.

Mit Linux 2.4 kam ein PCI-Treiber-Interface, das für ältere Kernel-Versionen nicht kompatibel ist. Es sollte für neue Treiber benutzt werden. Alternativ gibt es rückwärtskompatible Header, Makros und Funktionen.

Unter Linux 2.4 wurden die I/O-Regionen der PCI-Geräte in das generische Ressourcenmanagement integriert. Dadurch ist es nicht mehr notwendig, die Konfigurationsvariablen anzusprechen, um herauszufinden, wo das Gerät gemappt ist.
Folgende Funktionen werden jetzt benutzt:
unsigned long pci_resource_start(struct pci_dev *dev,int bar); unsigned long pci_resource_end(struct pci_dev *dev,int bar); unsigned long pci_resource_flags(struct pci_dev *dev,int bar); Die Ressourcenflags werden in <linux/ioport.h> definiert. Sie definieren Eigenschaften der jeweiligen Ressource.

Die relevanten Funktionen sind:

Die zugehörige Struktur ist pci_driver. Sie enthält ein paar Funktionen und eine Device-ID-Liste.
Die Struktur pci_device_id enthält diverse ID-Felder. Das jeweilige Device wird gegen diese Felder getestet. Jedes Feld kann auf PCI_ANY_ID gesetzt werden und wird dann ignoriert.


USB

Linux unterstützt USB (Universal Serial Bus) endlich brauchbar und damit eine wesentlich breitere Palette an Mäusen, Tastaturen, Druckern usw. Noch ist längst nicht jede unter anderen Betriebssystemen verfügbare Hardware unterstützt, aber die Arbeiten daran laufen und sind zum Teil schon ziemlich weit fortgeschritten.

USB wird seit Kernelversion 2.2.18 unterstützt.
Es gibt zwei Arten von USB-Controllern, derern Treiber beide Teil des Standardkernels sind.

USB-Treiber funktionieren ähnlich den PCI-Treibern: der Treiber registriert sein Gerät im USB-Subsystem. Später werden die Händler- und die Device-ID verwendet, um die Hardware zu identifizieren.

Die zugehörige Datenstruktur ist struct usb_driver, die typischerweise so angewendet wird:
    #include <linux/usb.h>
    static struct usb_driver sample_usb_driver ={
      name:"sample",
      probe:sample_probe,
      disconnect:sample_disconnect,
    };

    int init_module(void){
    /*just register it;returns 0 or error code */
      return usb_register(&sample_usb_driver);
    }

    void cleanup_module(void){
      usb_deregister(&sample_usb_driver);
    }
probe wird vom USB-Kernel-Subsystem jedes Mal aufgerufen, wenn ein neues Gerät am System angeschlossen wird, oder wenn sich beim Laden des Treibers Geräte am Bus befinden, die niemand beansprucht.
Jedes Gerät identifiziert sich selbst durch eine Händler-, eine Geräte- und eine Klassen-ID. sample_probe hat nun die Aufgabe, die erhaltenen Informationen auszuwerten und passende Geräte in Besitz zu nehmen. Dazu gibt diese Funktion einen Pointer zurück, der nicht NULL ist. Dieser Zeiger dient der Identifikation des Gerätes. Gewöhnlich wird das ein Zeiger auf die gerätespezifische Datenstruktur des Treibers sein.
Für die Kommunikation mit dem Gerät muß ein struct urb (USB request block) gefüllt und an usb_submit_urb weitergegeben werden. Das passiert normalerweise in der open-Funktion, die im device special file gespeichert ist.

Nicht jeder USB-Treiber implementiert ein eigenes device special file mit einer major number usw. Geräte, für die der Kernel allgemeinen Support anbietet, haben diese files nicht und kommunizieren anders.
In diesem Fall, z.B. bei Inputgeräten, muß das open callback die Kommunikation aufbauen.


Externe Busse

Neben vielen weiteren Bussen (von ISA (unterstützt jetzt Plug&Play) bis PC104), die hier nicht weiter besprochen werden, gibt es noch eine neuere Entwicklung, die externen Busse. Dazu gehört neben USB FireWire(IEEE1394) für high-bandwidth-Geräte.
Diese Interfaces ähneln den älteren Technologien von PCMCIA/CardBUS und in gewisser Weise auch SCSI.
Diese Busse sind weder 'full-featured' Interface-Busse wie PCI noch stumpfe Kommunikationskanäle, wie es serielle Ports sind.
Die benötigte Software zu klassifizieren ist schwer, weil sie sich in zwei Teile splittet. Man braucht einen Treiber für den Hardware-Controller und einen Treiber für das 'Client'-Gerät.
Außer USB ist der Support dieser Treiber nicht wirklich relevant, oder er ist noch (stark) verbesserungsbedürftig.


I2O

Linux unterstützt jetzt I2O-Geräte (Intelligent Input/Output), eine 'intelligentere' Weiterentwicklung von PCI. I2O stellt eine API auf Gerätelevel zur Verfügung, die es ermöglicht, betriebssystemunabhängige Treiber für Geräte wie Platten, SCSI-Geräte oder Netzwerkkarten zu implementieren. Das Betriebssystem muß lediglich die 'generischen' I2O-APIs verstehen, um Geräte benutzen zu können. Da diese Technik noch relativ neu ist, gibt es momentan allerdings kaum Geräte mit I2O.


... [ Seminar Linux und Apache] ... [ Thema Gerätetreiber unter Linux 2.4] ... [ nach oben ] ... [ Treiberdesign ] ...