\section{Typen von Geräten}

Man unterscheidet üblicherweise bei Massenspeichern zwischen
Character- und Blockdevices (\cite{Crow97}, Kap. 15.1.3), die auch im Namensraum des Dateisystems
vorkommen und dem Dateisystem, sowie Sockets und dafür verwendete
Netzwerkinterfaces. (An\-mer\-kung: letzteres trifft vor allem auf Unix
zu, so sind Ein-/Ausgabegeräte bei anderen Betriebs\-systemen nicht zwingend
benutzertransparent).

Blockorientierte Geräte ordnen Daten in Blöcken, während
zeichenorientierten Geräten ein beliebig langer Strom von Zeichen
übergeben werden kann.

Alle Gerätenamen, die hier verwendet werden, stammen aus FreeBSD
3.4. Einige andere Unices, vor allem Linux, weisen starke Unterschiede
bei der Benennung von Geräten auf.

\subsection{Zeichenorientierte Geräte}

Beinahe jedes Gerät (außer Netzwerkinterfaces) besitzt eine
Schnittstelle, mit der es als zeichenorientiertes Gerät angesprochen
werden kann. Dazu gehören (unter Unix) z.B. {\ttfamily /dev/ttyX}
(ursprünglich \emph{Teletype}, also Fernschreiber \cite{Step99}),
{\ttfamily /dev/lpt0} (ursprünglich \emph{Line Printer}), {\ttfamily /dev/rsa0} (erstes
SCSI-Bandlaufwerk, \emph{Raw Sequential Access}), {\ttfamily
  /dev/rwd0} (roher Zugriff auf erste Festplatte, \emph{Raw Winchester
  Disk}) oder {\ttfamily /dev/null} (das Datengrab). 

Alle Beschränkungen der Hardware werden durch die zeichenorientierte
Schnitt\-stelle weitergegeben, worauf natürlich Anwendungen Rücksicht
nehmen müssen. Dadurch liegen zeichenorientierte Geräte näher am Modell
des Datenstroms als andere.
\\\\
Typischerweise stehen folgende Aufrufe an den Gerätetreiber zur
Verfügung \emph{(Hier 4.4BSD, aus \cite{McKu96}, andere Unix-Systeme
  mit leichten Änderungen)}:\\\\

                                % tabular: einfache Tabelle, hier
                                % benutzt, um Begriffe zu erklären

\begin{tabular}{lp{9cm}}

  \emph{open \& close} &
  Öffnen oder Schließen des zeichenorientierten Gerätes. Im Gegensatz
  zu blockorientierten Geräten gewähren sie den direkten Zugriff auf
  das Medium.\\\\

%\end{tabular}
%\\\\
%\begin{tabular}{lp{9cm}}
  
  \emph{read} &
  Daten von einem Gerät lesen. Beim rohen Zugriff auf blockorientierte
  Geräte bedeutet dies lediglich den Aufruf der
  \emph{physio()}-Routine mit gerätespezifischen Parametern. Bei
  Terminalgeräten wird die Leseanfrage sofort an den Terminaltreiber
  weitergegeben. Bei anderen Geräten bedeutet der Leseaufruf, daß die
  benötigten Daten in den Adressraum des Kernels kopiert werden, bevor
  sie an das Gerät weitergegeben werden.\\\\
  
  \emph{write} &
  Daten auf ein Gerät schreiben. Symmetrisch zum \emph{read}-Aufruf.\\\\
  
  \emph{ioctl} &
  Operationen ausführen, die sich vom Lesen oder Schreiben
  unterscheiden. Dieser Eintrag war ursprünglich dazu bestimmt, einen
  Mechanismus zum Auslesen und Ändern von Parametern von
  Terminalgeräten zur Verfügung zu stellen. 4.4BSD definiert eine
  Reihe von Operationen, die von jedem Bandlaufwerk unterstützt
  werden. Dazu gehören: Positionieren, Statusrückgabe, Schreiben von
  Dateiendmarken und das Sperren von Bandlaufwerken.\\\\

  \emph{select} &
  Überprüfen des Gerätes, ob Daten zum Lesen vorhanden sind oder Platz
  zum Schreiben frei ist. Dies wird vom \emph{select}-Systemaufruf
  verwendet, um die Deskriptoren von Gerätedateien zu prüfen. Für den
  rohen Zugriff auf Blocklaufwerke ist dieser Eintrag bedeutungslos,
  da der Zugriff ungepuffert erfolgt. \\\\

  \emph{stop} &
  Stoppt das Schreiben auf ein Gerät. Dieser Eintrag wird nur für
  Geräte benutzt, die vom Terminaltreiber angesprochen werden. Bei
  diesen Geräten bedeutet der Aufruf ein Abbruch der Übertragung, wenn
  z.B. der Terminaltreiber ein Stoppzeichen, z.B. {\ttfamily \^{ }S} empfängt.\\\\

  \emph{mmap} &
  Wandelt den Versatz einer Gerätedatei in eine Speicheradresse
  um. Dieser Eintrag wird vom Virtual-Memory-System  aufgerufen, um
  eine logische in eine physikalische Adresse umzuwandeln. Wandelt
  z.B. einen Versatz in {\ttfamily /dev/mem} in eine Speicheradresse
  um.\\\\

  \emph{reset} &
  Zurücksetzen des Gerätezustandes nach dem Reset des
  Gerätebusses. Die \emph{reset}-Routine ruft den Treiber des
  Busadapters auf, wenn der Reset des Busses erfolgte
  (z.B. SCSI). Vom Gerätetreiber wird dann erwartet, dass er die
  Hardware in einen bekannten Zustand versetzt, üblicherweise in den
  Zustand, der nach dem Booten vorhanden war.\\
  
\end{tabular}

\subsection{Blockorientierte Geräte}

Festplatten sind ein typisches Beispiel für blockorientierte
Geräte. Platten untescheiden sich in Details, bieten aber
grundsätzlich die gleichen Funktionen, nämlich das Lesen und Schreiben
von Blöcken fester Größe (meist zwischen 512 und 4096 Bytes) an bestimmte Adressen.
\\\\
Typischerweise stehen folgende Aufrufe an den Gerätetreiber zur
Verfügung \emph{(Hier 4.4BSD, aus \cite{McKu96}, andere Unix-Systeme
  mit leichten Änderungen)}:
\\\\

\begin{tabular}{lp{9cm}}

  \emph{open} & 
  Öffnen des Gerätetreibers um auf eine bevorstehende
  E/A-Operation vorzubereiten. \emph{open} wird aufgerufen, wenn der
  Systemaufruf \emph{open} erfolgt oder intern, wenn ein auf dem Gerät
  befindliches Dateisystem in den Verzeichnisbaum eingehängt werden
  soll.

  Die \emph{open()}-Routine wird zunächst die Verfügbarkeit des
  entsprechenden Gerätes feststellen, so z.B. ob das Gerät während der
  Konfiguration anwesend war und -- bei Disketten- oder Bandlaufwerken
  -- ob ein Medium anwesend ist.\\\\

  \emph{strategy} & 
  Startet eine Lese- oder Schreiboperation und
  liefert sofort einen Rückgabewert. E/A-Anfragen an ein Dateisystem
  auf einem Gerät oder von dem Dateisystem werden vom System in die
  Aufrufe an \emph{bread()} und \emph{bwrite()} übersetzt. Diese
  Block-E/A-Routinen rufen wiederum die \emph{strategy}-Routine auf,
  mit der Anfrage Daten zu lesen oder zu schreiben, die sich nicht im
  Cache befinden. 

  Jeder Aufruf an die \emph{strategy}-Routine übergibt
  einen Pointer an eine \emph{buf}-Struktur, die die Parameter für
  eine E/A-Anfrage enthält. Treten mehrere Anfragen gleichzeitig auf,
  muß der Aufrufende warten, bis die andere E/A-Anfrage beendet ist.\\\\



  \emph{close} &
  Schließe ein Gerät. Die \emph{close}-Routine wird üblicherweise dann
  aufgerufen, wenn die letzte E/A-Anfrage an das Gerät bedient
  ist. Plattenlaufwerke haben nichts zu tun, wenn das Gerät
  geschlossen wird, während Geräte, die nur eine gleichzeitige Anfrage
  erlauben, das Gerät wieder freigeben müsen.
  
  Das Schließen eines (blockorientierten) Bandlaufwerkes schreibt
  üblicherweise eine Dateiendmarke und veranlasst das Laufwerk
  dann, das Band zurückzuspulen.

  Das Schließen eine CD-Laufwerkes gibt z.B. den Auswurf wieder frei.
  \\\\

\end{tabular}
\\\\
\begin{tabular}{lp{9cm}}

  \emph{dump} &
  Schreibt den Inhalt des Hauptspeichers auf ein Laufwerk. Der Aufruf
  von \emph{dump} sichert den Inhalt des flüchtigen Speichers auf
  einem nichtflüchtigen Medium. Das Betriebssystem veranlasst einen
  \emph{dump} automatisch, wenn es einen unbehebbaren Fehler
  feststellt und vor einen Crash steht.

  Der Inhalt des Dumps kann für eine Postmortem-Analyse des Fehlers
  benutzt werden, der den Absturz verursacht hat. Die
  \emph{dump}-Routine wird mit der höchstmöglichen Priorität
  aufgerufen; folglich muß lediglich den Status des Gerätes überprüft 
  und nicht auf einen Interrupt gewartet werden. Üblicherweise unterstützen die
  Treiber aller Plattencontroller und einiger Bandlaufwerke diesen
  Aufruf.\\\\

  \emph{psize} & 
  Liefert die Größe einer Festplattenpartition. Dem Treiber wird die
  logische Einheit übergeben, als Rückgabe wird die Größe dieser
  Partition erwartet (üblicherweise als Produkt der Anzahl der Blöcke
  einer Partition und der Blockgröße). Dieser Eintrag wird während der
  Bootstrap-Prozedur benutzt, um den Platz für einen Crash-Dump zu
  bestimmen und um die Größe eines Swap-Bereiches zu bestimmen.\\
  
\end{tabular}

\subsection{Pseudodevices}

Pseudodevices sind spezielle Geräte, die nicht als Hardware
existieren. In der Regel dienen sie dazu entweder nicht (mehr)
vorhandene Hardware (Terminals) nachzubilden oder spezielle
Datenströme zu erzeugen oder ``versickern'' zu lassen. 

Beispiele für Pseudodevices sind {\ttfamily /dev/pty0} (das erste
Pseudoterminal), {\ttfamily /dev/null} (das ``Datengrab'', alles, was
auf dieses Device geschrieben wird ver\-sickert im Nichts), {\ttfamily
  /dev/urandom} (erzeugt einen endlosen Strom von Zufallszahlen) oder
{\ttfamily /dev/zero} (erzeugt einen endlosen Strom von Nullen). 

Gemeinsam ist all diesen Geräten, dass sie sich genauso ansprechen
lassen wie normale zeichenorientierte Geräte und im Bedarfsfall
einfach gegen ``echte'' Geräte, z.B. einen echten
Zufallszahlengenerator ausgetauscht werden können.   
