Kapitel 3. Zeichen-Treiber

Inhalt
Das Design von scull
Major- und Minor-Nummern
Datei-Operationen
Die Struktur file
open und release
Die Verwendung von Speicher in scull
Ein kurze Einführung in Race Conditions
read und write
Die neuen Geräte ausprobieren
Das Device-Dateisystem
Abwärtskompatibilität
Schnellreferenz

In diesem Kapitel werden wir einen vollständigen Zeichen-Gerätetreiber schreiben. Wir nehmen einen Zeichen-Treiber, weil diese Treiber-Klasse für die meisten einfachen Hardware-Geräte geeignet ist. Außerdem sind sie leichter zu verstehen als beispielsweise Block-Treiber. Das Endziel ist es dabei, einen modularisierten Zeichen-Treiber zu schreiben, aber wir werden in diesem Kapitel nicht auf Probleme der Modularisierung eingehen.

Während des ganzen Kapitels werden wir Code-Fragmente vorstellen, die aus einem echten Gerätetreiber stammen: scull, was für Simple Character Utility for Loading Localities steht. scull ist ein Zeichen-Treiber, der einen Speicherbereich so anspricht, als würde es sich um ein Gerät handeln. Als Nebeneffekt aus diesem Verhalten kann, solange es um scull geht, der Begriff Gerät mit der Bedeutung “der Speicherbereich, der von scull verwendet wird” benutzt werden.

Es ist ein Vorteil von scull, daß der Treiber nicht von irgendwelcher Hardware abhängt, weil ja jeder Computer über Speicher verfügt. scull arbeitet einfach nur auf einem Stück Speicher, das mit kmalloc alloziert wird. Jeder kann scull kompilieren und starten; scull ist portabel über alle Rechnerarchitekturen hinweg, auf denen Linux läuft. Auf der anderen Seite macht das Gerät natürlich nichts Nützliches, außer daß es die Schnittstelle zwischen dem Kernel und Zeichen-Treibern demonstriert und den Benutzer einige Tests starten läßt.

Das Design von scull

Beim Schreiben eines Treibers besteht der erste Schritt darin, die Funktionen (den Mechanismus) zu definieren, den der Treiber den Benutzerprogrammen bieten wird. Weil unser Gerät ein Teil des Computerspeichers ist, können wir damit machen, was wir wollen. Es kann sich um ein Gerät mit sequentiellem oder wahlfreiem Zugriff handeln, um ein Gerät oder viele usw.

Damit scull als nützliches Muster eines richtigen Treibers für richtige Geräte dienen kann, werden wir Ihnen zeigen, wie Sie mehrere Geräte-Abstraktionen auf dem Computerspeicher aufsetzen können, alle mit eigenen Charakteristika (einer sogenannten Personality).

Der Quellcode von scull implementiert die folgenden Geräte. Jedes Gerät, das vom Modul implementiert wird, wird als ein Typ bezeichnet:

scull0-3

Vier Geräte, die aus vier Speicherbereichen bestehen, die alle global und persistent sind. Global bedeutet hier, daß auf allen Dateideskriptoren die gleichen Daten benutzt werden, wenn das Gerät mehr als einmal geöffnet wird. Persistent bedeutet, daß die Daten nicht verlorengehen, wenn das Gerät geschlossen und wieder geöffnet wird. Es macht Spaß, mit so einem Gerät zu arbeiten, weil man auf das Gerät mit konventionellen Befehlen wie cp, cat und der Shell-I/O-Umleitung zugreifen und es testen kann. Wir werden die Interna des Gerätes in diesem Kapitel untersuchen.

scullpipe0-3

Vier FIFO-Geräte, die wie Pipes arbeiten. Ein Prozeß liest die Daten, die ein anderer Prozeß schreibt. Wenn mehrere Prozesse von demselben Gerät lesen wollen, dann konkurrieren sie um die Daten. Die Interna von scullpipe werden zeigen, wie blockierendes und nicht-blockierendes Lesen und Schreiben implementiert werden kann. Das funktioniert auch, ohne auf Interrupts auszuweichen. Obwohl echte Treiber ihre Geräte mittels Hardware-Interrupts synchronisieren, ist es dennoch wichtig, sich mit blockierenden und nicht-blockierenden Operationen zu beschäftigen. Auch kann dieses Thema unabhängig von Interrupts behandelt werden (über die wir in Kapitel 9 sprechen werden).

scullsingle, scullpriv, sculluid, scullwuid

Diese Geräte ähneln scull0, haben aber einige Einschränkungen hinsichtlich der Zeitpunkte, zu denen ein open zugelassen ist. Das erste Gerät (scullsingle) erlaubt nur jeweils einem Prozeß, auf das Gerät zuzugreifen, während scullpriv privat zur jeweiligen virtuellen Konsole (oder X-Terminalsitzung) ist, weil Prozesse auf jeder Konsole und jedem Terminal einen anderen Speicherbereich als Prozesse aus anderen Konsolen bekommen. sculluid und scullwuid können mehrfach geöffnet werden, aber nur von jeweils einem Benutzer. Die erste Version gibt “Gerät besetzt” zurück, wenn ein anderer Benutzer das Gerät sperrt, während die letzte ein blockierendes open implementiert. Diese Varianten von scull stellen mehr “Policy” als “Mechanismus” dar, sind aber trotzdem interessant, weil manche Geräte eine derartige Verwaltung benötigen.

Jedes der scull-Geräte demonstriert verschiedene Features des Treibers und zeigt auch verschiedene Schwierigkeiten auf. In diesem Kapitel werden wir die Interna von scull0-3 besprechen; die fortgeschritteneren Geräte kommen dann in Kapitel 5 zur Sprache: scullpipe wird in the Section called Eine Beispiel-Implementation: scullpipe in Kapitel 5 beschrieben, die anderen Geräte in the Section called Zugriffskontrolle auf Gerätedateien in Kapitel 5.