Beschreibung des XFS-Konzepts von Mag!X V3.00 / 4.0x / 5.0x
###########################################################

Andreas Kromke
Hannover, den 15.6.96


I Konzepte
==========

Das GEMDOS war bisher der konservativste Teil des Betriebssystems Mag!X. Fr
Netzwerktreiber muten praktisch smtliche DOS- Aufrufe einschlielich
Pexec() nachgebildet werden, ohne auf einer tieferen Ebene eingreifen zu
knnen. In Mag!X 1.x (wie in TOS) war das DOS nicht einmal reentrant, da ein
statisch angelegter Stack verwendet wurde.

In MultiTOS/MiNT wird das Problem dermaen umgangen, da gewissermaen ber
das GEMDOS ein System gelegt wird, das alle hheren Verwaltungsaufgaben
erledigt, andere Dateisysteme einbinden kann und das GEMDOS nur noch als
"dummen" Dateisystemtreiber verwendet. Vorteil dieses Systems ist seine groe
Flexibilitt und Erweiterbarkeit, ein entscheidender Nachteil aber der
gewaltive Overhead bei der Verwendung von "normalen" DOS- Dateisystemen. Dies
sind aber gerade diejenigen, die mit Abstand am hufigsten eingesetzt werden.
Hinzu kommt, da das GEMDOS- Dateisystem mit dem Einsatz von MiNT nichts an
Funktionalitt, Komfort oder Geschwindigkeit gewinnen kann, da ja die alten
Routinen nur mit zustzlichem Overhead ablaufen. Die Dateisystemzugriffe
unter MiNT sind also i.a. nicht reentrant, d.h. jeder Diskettenzugriff legt
wie unter MS-Windows den gesamten Rechner lahm.

Eine weitere Eigenschaft von MiNT ist das Bemhen, die Funktionen, die alle
Dateisysteme gemeinsam haben, in den Kernel zu bernehmen. Dabei bleiben zwar
die Dateisystemtreiber (MiNT-XFSs) kompakt, aber durch den Inode-
orientierten Aufbau der Kernelfunktionen wird den Dateitreibern eine unter
Umstnden ungnstige Struktur aufgezwungen, auerdem sind i.a. viele Aufrufe
des Dateisystemtreibers fr einen DOS- Aufruf notwendig. Schlielich ist der
MiNT- Kernel selbst sehr lang, liegt aber zum groen Teil brach, solange
keine anderen Dateisysteme als DOS eingesetzt werden.

Unter Mag!X wurde ein anderer Ansatz gewhlt, der darin bestand, das gesamte
GEMDOS einschlielich der Lowlevel- Funktionen fr die Sektorpufferung von
Grund auf neu zu schreiben und in insgesamt drei, vier oder fnf Schichten zu
zerlegen, in die von auen (durch nachgeladene Treiber) eingegriffen werden
kann. Als "Nebenwirkung" (dummdeutsch: Nebeneffekt) kam eine Erweiterung der
Funktionalitt des DOS- Dateisystems und ein zustzliches Dateisystem auf
dem logischen Laufwerk U: heraus. Das gesamte Konzept einschlielich der
Zugriffe auf DOS- Dateisysteme ist reentrant und luft im Hintergrund ab. So
ist es mglich, auf Laufwerk A: Dateien zu bearbeiten, ohne den Rechner bei
den Diskettenzugriffen merklich zu bremsen. Dabei ist Mag!X bisher nur um
10k lnger geworden. Im Vergleich zu MiNT wurden aber mehr Funktionen in die
Dateisystemtreiber ausgelagert, was diese zwar lnger macht, aber ihnen die
Mglichkeit gibt, die Funktionen wesentlich effizienter auszufhren. Das
DOS- Dateisystem ist eher noch etwas schneller als langsamer geworden.

Obwohl vollstndig in Assembler realisiert, handelt es sich um ein
objektorientiertes System mit virtuellen Funktionen und mehrstufigen
Vererbungen. Ein Dateideskriptor, wie in der Kernel verwendet und das XFS zur
Verfgung stellt, ist ein Objekt mit speziellen Daten und Funktionen. Das XFS
realisiert aber ein abgeleitetes Objekt mit weiteren Datenfeldern und
Funktionen. Der DFS- Untertreiber des DOS_XFS schlielich mu wiederum
weitere Funktionen und Daten im FD unterbringen und leitet die Klasse weiter
ab. Genauso sieht es mit dem DMD (drive medium descriptor) aus. Der Kernel
bentigt nur wenige Angaben, die unteren Schichten jedoch wesentlich mehr,
aber immer wieder verschiedene.

Die Schichten im einzelnen:

1. Der DOS-Kernel. Er liegt im Mag!X selbst und wird direkt von den Anwender-
   Programmen ber trap #1 aufgerufen. Er enthlt Module fr die
   Speicherverwaltung, fr die Prozeverwaltung und fr die Dateiverwaltung.
   Letztere hat die folgenden "Unterschichten".
2. Das Dateisystem (XFS = extended (?) file system). Sein Aufbau ist
   grundstzlich verschieden von einem MiNT- XFS, erfllt aber denselben
   Zweck.
   Mag!X selbst enthlt auf dem Atari nur ein einziges XFS, das sogenannte
   "DOS_XFS", andere knnen eingebunden werden. Auf dem Mac ist noch ein
   weiteres Dateisystem integriert, das "Mac-XFS".
   Speziell das DOS-XFS greift wieder auf Untertreiber zu:
2a Ein DOS- Dateisystem (DFS) wird vom DOS_XFS aufgerufen. Hier stehen nur
   die Dateifunktionen, whrend die Verzeichnisverwaltung im wesentlichen vom
   DOS_XFS bernommen wird.
   Mag!X enthlt zwei DFSs. Eines fr Laufwerk U:, ein zweites fr FAT-
   Dateisysteme, auf die ber BIOS- Laufwerke zugegriffen wird.
   Weitere DFSs knnen eingebunden werden. Der Aufwand fr ein DFS ist
   wesentlich geringer als fr ein XFS, da viele Funktionen vom DOS_XFS
   bereits ausgefhrt werden. Die wesentliche Voraussetzung ist eine DOS-
   konforme Verzeichnisstruktur (mit 32-Byte-Eintrgen und Dateinamen des
   Formats 8+3).
3. Die Dateitreiber (MX_DEV), die im wesentlichen das Lesen und Schreiben
   einer Datei erledigen. Sie werden vom XFS angelegt und verwaltet, aber
   bei Funktionen wie Fread() und Fwrite() direkt vom Kernel aufgerufen,
   wodurch extrem wenig Overhead entsteht.
   Das DOS_XFS enthlt tatschlich nur einen Dateitreiber. Dieser erledigt
   z.B. bei Schreibzugriffen die Aktualisierung des Verzeichnisses und ruft
   wieder Untertreiber (MX_DDEV) auf.
3a Der Untertreiber MX_DDEV wird nur vom DOS-Dateitreiber des Dateisystems
   DOS_XFS aufgerufen.
   Der Benutzer kann eigene MX_DDEVs ber das Verzeichnis U:\DEV\ einbinden.

Bemerkungen:
- Im Gegensatz zu MiNT sind U:\PROC, U:\DEV usw. keine eigenen Dateisysteme,
  sondern einfach nur Unterverzeichnisse des DFS fr Laufwerk U:. Je nach
  Unterverzeichnis legt das U-DFS verschiedene Dateitypen und -treiber an.
  Da die Verzeichniskontrolle dem DOS_XFS obliegt, werden Schreibzugriffe auf
  z.B. ein Device im Verzeichnis per Dateidatum protokolliert. Das geht sogar
  soweit, da ein Schreibzugriff auf das Wurzelverzeichnis von Laufwerk A:
  automatisch das Dateidatum von U:\A verndert.
  Devices, Pipes und Shared-Memory-Blcke knnen verschoben, gelscht oder
  umbenannt werden. In allen Verzeichnissen von Laufwerk U: knnen symbolische
  Links angelegt werden, z.B. kann man mit "ln -s U:\CON U:\CONSOLE" einen
  Alias fr die Gertedatei CON anlegen. Man kann auch einfach leere Dateien
  anlegen, jedoch keine Ordner, weil das Laufwerk U: keinen Speicher hat.
- Im Gegensatz zu MiNT ist U:\ kein eigenes, spezielles Dateisystem. Es wird
  lediglich darauf geachtet, da nur symbolische Links angelegt werden
  knnen. Die Verzeichnisse U:\A usw. sind lediglich symbolische Links, die
  auch entfernt oder umbenannt werden knnen.
- Alle Verzeichnisse von U: sind z.Zt. auf 32 Eintrge beschrnkt.
- Der Aufbau aller internen Strukturen und die schnelle registerbasierte
  Parameterbergabe und -rckgabe erfordert eine Implementation aller
  Dateisysteme und -treiber in Assembler, zumindest fr die meisten
  Funktionen.
  Aufrufkonventionen sind die von GEMDOS, d.h. d0-d2 und a0-a2 drfen in einer
  Funktion verndert werden.
- Der Aufbau des MX_DDEV- Dateitreibers hat sich seit Mag!X V2.10 gendert.
  Der Beispieltreiber DEV_LPT1 darf unter Mag!X 3.00 nicht verwendet werden.
  Die Konzepte sind jedoch identisch geblieben, nur ein paar Konstanten
  haben sich gendert.

zu symbolischen Links
---------------------

Symbolische Links (in der Benutzerdokumentation in bereinstimmung mit der
Macintosh Nomenklatur auch als Aliase bezeichnet) sind Dateien, die in
irgendeiner Form besonders gekennzeichnet sind und statt Daten einen Pfad
enthalten, der wiederum auf eine andere Datei zeigt. Ein derartiger Pfad kann
auch auf eine nicht (mehr) bzw. noch nicht existierende Datei zeigen. Pfade
knnen absolut oder relativ sein, wobei letztere das Verzeichnis als Bezug
haben, in dem der Link liegt.
Im Speicher werden derartige Links als Strukturen verwaltet:

	{
	WORD n;		/* auf gerade Anzahl aufgerundet, inkl. EOS */
	char path[n];	/* Pfad mit EOS am Ende */
	}

Einige XFS-Funktionen mssen, wenn sie auf einen Symlink stoen, diesen
dereferenzieren, d.h. sie liefern dem Kernel in d0 den Fehlercode ELINK und
in a0 einen Zeiger auf eine Struktur der obigen Form. Der Kernel sorgt dann
fr die Dereferenzierung und die Begrenzung der maximalen Verschachtelung
(falls der Symlink wieder auf einen solchen zeigt).
Die XFS-Funktionen, die ELINK liefern drfen, sind:

xfs_path2DD
xfs_sfirst
xfs_xnext
xfs_fopen
xfs_xattr
xfs_attrib


II Aufbau eines XFS
===================

Weil die Implementation nur in Assembler erfolgen kann, hier der Aufbau eines
XFS in Assembler- Syntax.

     OFFSET

xfs_name:      DS.B      8    /* Name des Dateisystems                     */

     Der Name ist bisher nur Kommentar, er soll irgendwann auch einmal die
     Mglichkeit bieten, festzustellen, welche Treiber installiert sind und
     wie z.B. der fr Laufwerk A: zustndige Treiber heit (d.h. was fr ein
     Dateisystem die Diskette enthlt). Der Name des integrierten XFS lautet
     "DOS_XFS " (Auf 8 Zeichen per Leerstellen erweitert).

xfs_next:      DS.L      1    /* nchster Treiber                          */

     Ist einfach ein Verkettungszeiger auf den nchsten Treiber. Ein neuer
     Treiber wird vorn eingebunden, hat also immer hchste Prioritt. Damit
     ist es z.B. mglich, den integrierten DOS- Treiber zu berladen.

xfs_flags:     DS.L      1    /* Flags laut MiNT                           */

     Reserviert.
     Sollte eigentlich Flags enthalten. Wird jedoch vom Mag!X- Kernel nicht
     verwendet. Also bitte nicht verwenden!

xfs_init:      DS.L      1    /* Initialisierung                           */

     Reserviert.
     Enthlt im Fall Mag!X- interner XFSs deren Initialisierung. Wird bei
     nachgeladenen XFSs nicht verwendet.

xfs_sync:      DS.L      1    /* Synchronisiert Dateisystem                */
                              /* a0 = DMD *d                               */
                              /* -> long errcode                           */

     Der Kernel teilt dem XFS mit, da auf Laufwerk <d> alle Puffer
     zurckzuschreiben sind. bergeben wird in Register a0 ein Zeiger auf
     einen DMD (drive media descriptor). Dieser wird vom Kernel angelegt, der
     Aufbau wird unten beschrieben.
     Zurckgeliefert wird ein Fehlercode. Wenn das XFS keine Pufferverwaltung
     hat (z.B. eine RAMDisk), mu eine 0 geliefert werden.
     Das interne DOS_XFS ruft einfach die gleichlautende DFS- Funktion auf.

xfs_pterm:     DS.L      1    /* Teilt ein Programmende mit                */
                              /* a0 = PD *                                 */
                              /* -> void                                   */

     Diese Funktion wird bei jedem Programmende aufgerufen und gibt dem XFS
     Gelegenheit, internen Strukturen freizugeben oder Locks zu entfernen.
     Die fr den Kernel sichtbaren Dateien (d.h. die, denen ein Handle
     zugeordnet ist), werden vorher vom Kernel geschlossen. Die
     Referenzzhler fr Standardverzeichnisse werden ebenfalls vorher durch
     den Kernel dekrementiert.
     bergeben wird in a0 ein Zeiger auf einen Proze- Deskriptor.

xfs_garbcoll:  DS.L      1    /* garbage collection oder NULL              */
                              /* a0 = DMD *d                               */
                              /* -> d0 = 1L oder 0L                        */

     Der Kernel bentigt dringend internen GEMDOS- Speicher und macht eine
     Mllsammlung (garbage collection).
     Ein XFS, das die interne Speicherverwaltung des Kernels
     nicht verwendet, kann hier einen Nullpointer als Funktion eintragen.
     Achtung: Es sollten mglichst soviele Blcke wie mglich freigegeben
     werden, Rckgabe ist 1, wenn (mindestens) ein Block freigegeben werden
     konnte.
     Bei einer garbage collection durchluft der Kernel die gesamte Liste
     aller angemeldeten logischen Laufwerke. Das XFS wird also so oft um eine
     garbage collect ersucht, wie es zu diesem Zeitpunkt Laufwerke verwaltet.

xfs_freeDD:    DS.L      1    /* DD freigeben                              */
                              /* a0 = DD *                                 */
                              /* -> void                                   */

     Der Kernel hat den Referenzzhler eines DD auf 0 dekrementiert, der DD
     wird also vom Kernel nicht mehr referenziert. Die Funktion wird z.B.
     aufgerufen, wenn der Kernel nach dem Fopen() den Pfad, in dem die
     geffnete Datei liegt und der an xfs_fopen bergeben worden war, nicht
     mehr bentigt.
     XFSs, die keine garbage collection machen, knnen ber diese Funktion
     ihre DDs freigeben.
     Es mu sichergestellt werden, da die root nie freigegeben wird.
     Entweder baut man hier eine spezielle Abfrage ein, oder (eleganter)
     setzt den Referenzzhler der root bei drv_open bereits auf 1.

xfs_drv_open:  DS.L      1    /* initialisiert bzw. testet DMD (Mediach)   */
                              /* a0 = DMD *                                */
                              /* -> d0 = long errcode                      */

     Mag!X untersttzt genau 26 gleichzeitig aktive Dateisysteme, denen die
     Buchstaben 'A'..'Z' zugeordnet sind. Dieser Eintrag hat zwei Aufgaben:

     1. Beim ersten Zugriff auf ein Laufwerk (etwa D:) legt der Kernel einen
        DMD (drive media descriptor) an und "bietet" diesen den XFSs an. Der
        Eintrag d_xfs ist noch ein Nullzeiger, d_drive ist initialisiert
        (zwischen 0 und 25, entsprechend 'A'..'Z').
        Die XFS- Treiber versuchen nun, auf dem Laufwerk "ihr" Dateisystem zu
        erkennen. Falls dies gelingt, mssen d_xfs und d_root initialisiert
        werden, der Rckgabewert ist dann E_OK.
        Achtung: Die root darf whrend der "Lebensdauer" eines gemounteten
                 Dateisystems nicht freigegeben werden. Der Referenzzhler
                 der root sollte mit 1 vorbesetzt werden, um zu verhindern,
                 da er per free_DD freigegeben wird.
                 In den Versionen vor MagiC 4.01 war dies nicht notwendig,
                 weil der Referenzzhler (in unsauberer Weise) vor dem Aufruf
                 von path2DD nicht inkrementiert und nachher dekrementiert
                 wurde.
        Andernfalls wird EDRIVE gemeldet, und der Kernel probiert das nchste
        XFS.

     2. Beim wiederholten Zugriff ist d_xfs bereits initialisiert, und das
        XFS hat die Gelegenheit, auf Mediumwechsel zu testen. Ist alles in
        Ordnung, mu E_OK zurckgegeben werden. Ansonsten mu die
        Diskwechselroutine des Kernels aufgerufen und E_CHNG zurckgegeben
        werden.
        Den Zeiger auf die Diskwechselroutine des Kernels erhlt man bei der
        Installation des XFS.

     Das interne DOS_XFS leitet den Aufruf an die gleichnamige Funktion des
     DFS weiter, d.h. alle DFS- Treiber werden durchprobiert.

xfs_drv_close: DS.L      1    /* erzwingt einen Diskwechsel                */
                              /* a0 = DMD *                                */
                              /* d0 = int mode                             */
                              /* -> d0 = long errcode                      */

     Auch diese Funktion erfllt, abhngig vom <mode>, zwei Aufgaben:

     1. mode == 0:
        Der Kernel bittet das XFS, das Laufwerk, wenn mglich, zu schlieen.
        Wenn dies nicht erlaubt ist, mu EACCDN geliefert werden, sonst sind
        alle Strukturen freizugeben bzw. Caches zurckzuschreiben und E_OK
        als Rckgabewert zu liefern.
        Geffnete Dateien werden bereits vom Kernel erkannt und das Schlieen
        verhindert. Dabei knnen aber nur solche Dateien erkannt werden, die
        ein Handle haben und dem Kernel bekannt sind.
        Der Kernel ruft sicherheitshalber vor Aufruf dieser Funktion xfs_sync
        auf, falls ein Write-Back-Cache verwendet wird.

        Diese Vorgehensweise wird auch dann durchgefhrt, wenn einmal ein
        Mechanismus eingebaut wird, der den Auswurfknopf von
        Wechselplattenlaufwerken oder CD-ROM abfragt und ggf. den Auswurf
        verweigert (meine Sun sagt dann immer: "device busy").

     2. mode == 1:
        Der Kernel erzwingt das Schlieen, das XFS mu E_OK liefern. Es
        drfen keine Caches zurckgeschrieben werden, da das Laufwerk bereits
        ungltig ist.
        (nachdem ein Diskwechsel bereits gemeldet wurde).
        DDs und FDs brauchen nicht freigegeben zu werden, soweit sie vom
        Kernel noch referenziert werden, d.h. der Kernel fhrt auch nach dem
        Diskwechsel noch xfs_freeDD bzw. dev_close aus.

     Das interne DOS_XFS leitet den Aufruf an die gleichnamige Funktion des
     DFS weiter, auerdem werden ggf. XFS- Strukturen freigegeben.


xfs_path2DD:   DS.L      1    /* gibt einen DD zum Pfadnamen zurck        */
                              /* mode = 0: name ist Datei                  */
                              /*      = 1: name ist selbst Verzeichnis     */
                              /* d0 = int mode                             */
                              /* a0 = DD *reldir    akt. Verzeichnis       */
                              /* a1 = char *pathname                       */
                              /* -> d0 = DD *                              */
                              /*    d1 = char *restpfad                    */
                              /* oder                                      */
                              /* -> d0 = ELINK                             */
                              /*    d1 = Restpfad ohne beginnenden '\'     */
                              /*    a0 = FD des Pfades, in dem der         */
                              /*         symbolische Link liegt. Dies ist  */
                              /*         wichtig bei relativen Pfadangaben */
                              /*         im Link.                          */
                              /*    a1 = NULL  Der Pfad stellt den Parent  */
                              /*               des Wurzelverzeichnisses    */
                              /*               dar.                        */
                              /*    oder                                   */
                              /*    a1 = Pfad des symbolischen Links       */

     Der Kernel unterscheidet zwischen zwei Typen von Deskriptoren,
     Dateideskriptoren (FD, file descriptor) und Verzeichnisdeskriptoren (DD,
     directory descriptor), die aber im Aufbau identisch sein knnen (s.u.).
     Diese Funktion liefert zu einem Pfad einen Deskriptor zurck. Der
     Referenzzhler des DD mu jedesmal, wenn er als Funktionswert
     zurckgeliefert wird, um 1 erhht werden, weil er vom Kernel
     referenziert wird. Die Funktion path2DD entspricht einem "ffnen" des
     Pfades, es wird eine Art "Dateihandle" dem Kernel zurckgegeben, das der
     Kernel wieder schlieen mu.
     Das Parsen des Pfades mu immer vom XFS erledigt werden.
     Eingabeparameter:

          <mode>         Legt fest, ob das letzte Pfadelement selbst ein
                         Verzeichnis ist (mode == 1), oder ob der Pfad
                         ermittelt werden soll, in dem diese Datei liegt.

          <reldir>       Das Verzeichnis, von dem aus gesucht werden soll.

          <pathname>     Der Pfadname, ohne Laufwerkbuchstaben und ohne
                         fhrendes '\'.


     Ausgabeparameter:

     1. Fall: Es ist ein Fehler aufgetreten

          <d0>           enthlt den Fehlercode

     2. Fall: Ein Verzeichnisdeskriptor (DD) konnte ermittelt werden

          <d0>           Zeiger auf den DD. Der Referenzzhler des DD wurde
                         vom XFS um 1 erhht.

          <d1>           Zeiger auf den restlichen Dateinamen ohne
                         beginnenden '\' bzw. '/'. Wenn das Ende des Pfades
                         erreicht wurde, zeigt dieser Zeiger auf das
                         abschlieende Nullbyte.

     3. Fall: Das XFS ist bei der Pfadauswertung auf einen symbolischen
              Link gestoen

          <d0>           enthlt den internen Mag!X- Fehlercode ELINK

          <d1>           Zeiger auf den restlichen Pfad ohne
                         beginnenden '\' bzw. '/'

          <a0>           enthlt den DD des Pfades, in dem der symbolische
                         Link liegt. Der Referenzzhler des DD wurde vom XFS
                         um 1 erhht.

          <a1>           ist der Zeiger auf den Link selbst. Ein Link beginnt
                         mit einem Wort (16 Bit) fr die Lnge des Pfads,
                         gefolgt vom Pfad selbst.

                         Achtung: Die Lnge mu INKLUSIVE abschlieendes
                                  Nullbyte und auerdem gerade sein. Der Link
                                  mu auf einer geraden Speicheradresse
                                  liegen.

                         Der Puffer fr den Link kann statisch oder auch
                         flchtig sein, da der Kernel die Daten sofort
                         umkopiert, ohne da zwischendurch ein Kontextwechsel
                         stattfinden kann.

                         Wird a1 == NULL bergeben, wird dem Kernel
                         signalisiert, da der Parent des
                         Wurzelverzeichnisses angewhlt wurde. Befindet sich
                         der Pfad etwa auf U:\A, kann der Kernel auf U:\
                         zurckgehen. Der Wert des Rckgabewert des Registers
                         a0 wird vom Kernel ignoriert, es darf daher kein
                         Rerenzzhler erhht werden.

xfs_sfirst:    DS.L      1    /* Sucht die erste passende Datei            */
                              /* a0 = DD * srchdir                         */
                              /* a1 = char *name   (ohne Pfad)             */
                              /* d0 = DTA *                                */
                              /* d1 = int  attrib                          */
                              /* -> d0 = long errcode                      */
                              /*    a0 = SYMLINK *      (ggf. Symlink)     */

     Wird fr Fsfirst bentigt. MiNT verwendet statt dieser Funktion eine
     Kombination von Dreaddir und Fxattr, wozu aber sehr viele Aufrufe des
     XFS- Treibers notwendig sind. Der reservierte Bereich der DTA kann vom
     XFS frei verwendet werden, falls dieser zu klein ist, mu mit hnlichen
     heuristischen Methoden wie in MiNT vorgegangen werden, d.h. Zeiger in
     die DTA eingetragen werden, die auf fest angelegte Deskriptoren zeigen.
     Diese Deskriptoren knnen aber nur nach heuristischen Methoden
     freigegeben werden, weil man nie wei, ob noch ein Fsnext kommt oder
     nicht.
     Der Kernel ermittelt ber path2DD bereits den vollstndigen Pfad, so da
     nur noch der reine Dateiname in a1 bergeben wird. Wie bei allen DOS-
     Aufrufen, die einen Pfad verarbeiten, mu das XFS darauf achten, da der
     DD fr die Dauer der Bearbeitung geschtzt wird. Das ist besonders dann
     kritisch, wenn das Dateisystem reentrant ist.
     Ist eine gesuchte Datei ein symbolischer Link, mu als Fehlercode in d0
     ELINK und in a0 der Zeiger auf den Link (s.o. bei path2DD) bergeben
     werden. Der Kernel ruft dann einfach Fxattr auf, um die DTA zu fllen.
     Trat ein Diskwechsel auf, ist E_CHNG zurckzugeben, der Kernel
     wiederholt dann automatisch die Funktion. Das gilt auch fr alle anderen
     Funktionen.
     In jedem Fall mu dta_drive korrekt initialisiert werden, z.B. per:
          dta.dta_drive = srchdir->dd_dmd->d_drive;
     Wird E_OK oder ELINK zurckgegeben, ohne da dta_drive initialisiert
     wurde, ist das Resultat unvorhersehbar!

xfs_snext:     DS.L      1    /* Sucht die nchste passende Datei          */
                              /* a0 = DTA *                                */
                              /* a1 = DMD *                                */
                              /* -> d0 = long errcode                      */
                              /*    a0 = SYMLINK *      (ggf. Symlink)     */

     Wird fr Fsnext bentigt. Der Kernel hat aus der DTA bereits das
     zugehrige Dateisystem ermittelt, dessen DMD in a1 bergeben wird. Auch
     hier kann ein symbolischer Link auftreten.

xfs_fopen:     DS.L      1    /* ffnet oder/und erstellt eine Datei       */
                              /* a0 = DD *                                 */
                              /* a1 = char *name   (ohne Pfad)             */
                              /* d0 = int omode    (frs ffnen)           */
                              /* d1 = int attrib   (frs Erstellen)        */
                              /* -> d0 = FD *                              */
                              /*         oder Fehlercode                   */
                              /*    a0 = SYMLINK *      (ggf. Symlink)     */

     Wird fr die Funktionen Fopen und Fcreate verwendet. Der Open-Modus ist
     im niederwertigen Byte anders als in MiNT, weil die MiNT- Modi fr die
     Implementierung der Abfragen ungnstig sind. Beim Aufrufen von Fopen
     ber Trap #1 werden die MiNT- Modi vom Kernel in die internen Modi
     konvertiert. Hier die internen Modi, die vom XFS- Treiber bearbeitet
     werden mssen (NOINHERIT wird nicht untersttzt, weil nach TOS- Konvention
     nur die Handles 0..5 vererbt werden). Ansonsten entspricht das HiByte den
     MiNT- Konventionen:

          OM_RPERM       EQU  1         /* Datei ist zum Lesen geffnet              */
          OM_WPERM       EQU  2         /* Datei ist zum Schreiben geffnet          */
          OM_EXEC        EQU  4         /* Datei ist zum Ausfhren geffnet          */
          OM_APPEND      EQU  8         /* Schreibzugriffe ans Ende (Kernel!)        */
          OM_RDENY       EQU  16        /* andere drfen nicht gleichz. lesen        */
          OM_WDENY       EQU  32        /* andere drfen nicht gleichz. schreiben    */
          OM_NOCHECK     EQU  64        /* KEINE berprfung durch das XFS           */

     Das Bit OM_APPEND wird vom Kernel bei Aufruf von Fwrite() automatisch
     beachtet, der Kernel fhrt vor jedem Schreibzugriff ein Fseek() aus.

     OM_NOCHECK wird vom Kernel gesetzt, wenn eine Datei als Device, d.h.
     als Handle -1,-2,-3 oder -4 geffnet bzw. auf ein solches Handle
     umgelenkt (Fforce) wird.
     Ist dieses Bit gesetzt, sollte das XFS keine Prfung auf mehrfaches ffnen
     der Datei machen (siehe auch unten bei fd_mode), sondern dies dem
     Gertetreiber berlassen.

     Hier die Bits, die wie im MiNT verwendet werden:

          O_CREAT        EQU  $200      /* Datei erstellen, falls nicht existiert */
          O_TRUNC        EQU  $400      /* Datei leeren, falls existiert */
          O_EXCL         EQU  $800      /* nicht ffnen, falls existiert */

     Der Kernel fhrt Fcreate aus als Fopen(O_CREAT+O_RDWR+O_TRUNC). O_COMPAT
     (d.h. nur der TOS- Modus 0, 1 oder 2 angegeben) ist in Mag!X immer
     gleichbedeutend mit O_WDENY.

     Die berprfung der Zugriffsrechte obliegt vollstndig dem XFS, der
     Kernel tut nichts. Das wre auch wenig sinnvoll, da jedes Dateisystem
     seine eigenen Mechanismen und Rechte hat.
     Falls es sich akut notwendig erweisen sollte, werde ich den Kernel um die
     entsprechenden Funktionen erweitern, mit dem ein XFS die uid, gid usw.
     des laufenden Prozesses abfragen knnen.

     Zurckgegeben wird dem Kernel ein Zeiger auf einen geffneten FD, d.h.
     das ffnen des Dateitreibers mu vom XFS durchgefhrt werden. Der
     Referenzzhler des zurckgegebenen FDs ist vom XFS zu erhhen bzw. beim
     ersten ffnen auf 1 zu initialisieren.
     Fr symbolische Links und Diskwechsel gilt dasselbe wie bei xfs_sfirst.

     Fopen wird unter MiNT folgendermaen zurckgefhrt:
     1. per <lookup> Konvertierung pathname->fcookie
     2. per <getxattr> Ermittlung der Zugriffsrechte
     3. Test der Zugriffsrechte durch den Kernel
     4. per <getdev> Ermittlung des Dateitreibers
     5. per <getdev->open> ffnen der Datei
     Dieses Verfahren ist sehr langwierig. DOS gibt beim Suchen der Datei
     bereits einen Zeiger auf den 32-Byte-Verzeichniseintrag zurck, der direkt
     zum berprfen des Attributs und damit der Zugriffsrechte und auch zum
     ffnen der Datei dient.
     Mag!X erwartet daher direkt die Implementation des Fopen- Befehls mit allen
     berprfungen der Zugriffsrechte. Zurckgeliefert wird eine FD- Struktur,
     in die der Dateitreiber eingetragen und dieser geffnet wurde.

xfs_fdelete:   DS.L      1    /* lscht eine Datei                         */
                              /* a0 = DD *                                 */
                              /* a1 = char *name   (ohne Pfad)             */
                              /* -> d0 = long errcode                      */

     Fr Fdelete. Beim Lschen eines Symlinks darf nur dieser gelscht
     werden, nicht etwa eine referenzierte Datei. D.h. der Rckgabewert ELINK
     ist hier _UNZULSSIG_.
     Zugriffsrecht- berprfungen obliegen vollstndig dem XFS.
     Beim Lschen ist darauf zu achten, da keine Datei durch den Kernel
     referenziert sein darf (d.h. fd_refcnt != 0).

xfs_link:      DS.L      1    /* fr Frename und Flink                     */
                              /* a0 = DD *olddir                           */
                              /* a1 = DD *newdir                           */
                              /* d0 = char *oldname                        */
                              /* d1 = char *newname                        */
                              /* d2 = int flag_link                        */
                              /* -> d0 = long errcode                      */

     Wird sowohl fr Frename (d2 = 0) als auch fr Flink (d2 = 1) verwendet.
     Im Fall Frename ist ein neuer Verzeichniseintrag zu erstellen und der
     alte Eintrag (= Verweis auf die Datei) zu lschen oder zu berschreiben.
     Im Fall Flink wird ein weiterer Verweis auf dieselbe Datei angelegt und
     der alte Eintrag nicht gelscht.
     Beide DDs liegen immer auf demselben Dateisystem, haben also denselben
     DMD.
     Wie bei Fdelete ist im Fall eines symbolischen Links dieser umzubenennen
     bzw. ein weiterer Link zu erstellen. D.h. der Rckgabewert ELINK
     ist hier (wie bei xfs_fdelete) _UNZULSSIG_.
     Flink wird vom DOS_XFS nicht untersttzt.

xfs_xattr:     DS.L      1    /* fr Fxattr                                */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = XATTR *                              */
                              /* d1 = int mode                             */
                              /* -> d0 = long errcode                      */
                              /*    a0 = SYMLINK *      (ggf. Symlink)     */

          mode == 0:   Folge symbolischen Links  (d.h. gib ggf. ELINK zurck)
                  1:   Folge nicht  (d.h. erstelle XATTR fr den Link)

     Wird fr Fxattr verwendet.
     Im Fall mode == 0 (d.h. folge symbolischen Links) kann in d0 ELINK und
     in a0 ein Link zurckgegeben werden, andernfalls ist ELINK unzulssig.

xfs_attrib:    DS.L      1    /* fr Fattrib                               */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = int rwflag                           */
                              /* d1 = int attrib                           */
                              /* -> d0 = char attr                         */
                              /*         oder long errcode                 */
                              /*    a0 = SYMLINK *      (ggf. Symlink)     */

     Fr Fattrib. Im Gegensatz zu MiNT fhrt Mag!X diese Funktion nicht auf
     Fxattr zurck, weil dies u.U. einen gewaltigen Overhead bedeutet.
     Hierbei mssen symbolische Links verfolgt werden, d.h. die Rckgabe von
     ELINK ist zulssig.

xfs_chown:     DS.L      1    /* fr Fchown                                */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = uid                                  */
                              /* d1 = gid                                  */
                              /* -> d0 = long errcode                      */
xfs_chmod:     DS.L      1    /* fr Fchmod                                */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = int mode                             */
                              /* -> d0 = long errcode                      */

     ndert Eigner (User-ID und Group-ID) bzw. Zugriffsrechte einer Datei.
     Die Parameter entsprechen der zugehrigen MiNT-Funktion Fchown bzw.
     Fchmod.
     Hier werden symbolische Links nicht verfolgt, d.h. Eigner und Gruppe des
     Symlinks selbst werden modifiziert.
     Diese Funktionen werden vom XFS_DOS nicht untersttzt. 

xfs_dcreate:   DS.L      1    /* erstellt ein Verzeichnis                  */
                              /* a0 = DD *                                 */
                              /* a1 = char *name   (ohne Pfad)             */
                              /* -> d0 = long errcode                      */

     Fr Dcreate.

xfs_ddelete:   DS.L      1    /* lscht ein Verzeichnis                    */
                              /* a0 = DD *                                 */
                              /* -> d0 = long errcode                      */

	Diese Funktion mute ab MagiC 4.01 gendert werden.
	Fr MagiC < 4.01 (Kernelversion < 3) gilt:

     Beim Lschen ist darauf zu achten, da kein Verzeichnis durch den Kernel
     referenziert sein darf auer durch den Aufruf selbst (d.h. es mu
     dd_refcnt == 1 sein).Auerdem ist darauf zu achten, da keine Dateien
     im Verzeichnis liegen. ELINK darf nicht zurckgegeben werden,
     symbolische Links drfen nicht behandelt werden.
     Die Zugriffsberechtigung mu (falls eine existiert) vom XFS geprft
     werden.

	Fr MagiC < 4.01 (Kernelversion >= 3) gilt:

	Wegen Reentranzproblematiken ergeben sich einigen nderungen, wobei
	der Kernel dem XFS Zugriffskontrollen abnimmt und weiterhin der Kernel
	den DD freigibt, nicht das XFS:
	Der Kernel ffnet zunchst mit xfs_path2DD den Parent des zu lschenden
	Verzeichnisses, dann testet er mit xfs_xattr, ob es sich um einen Symlink
	handelt, und lscht ihn ggf. per xfs_fdelete.
	Handelt es sich um ein Verzeichnis, ffnet der Kernel dieses wieder per
	xfs_path2DD (Modus 1) und gibt den Parent wieder per xfs_freeDD frei.
	Die berprfung von dd_refcnt wird vom Kernel durchgefhrt, der Zhler
	kann und mu daher vom XFS ignoriert werden. Das XFS mu nun
	sicherstellen, da das zu lschende Verzeichnis bzw. der DD nicht
	anderweitig geffnet oder benutzt werden knnen (wichtig fr reentrante
	XFSs). Das XFS lscht dann das Verzeichnis, gibt aber den DD nicht (!)
	frei, damit der Kernel im Erfolgsfall (Rckgabe E_OK) vorher seine
	Standardpfade freigeben kann. Der Kernel ruft dann xfs_freeDD auf.
	Wie gehabt, mu das XFS prfen, ob das Verzeichnis leer ist, bzw.
	Zugriffsberechtigungen existieren.

	  Nochmal im Zusammenhang:
	
	  -	Kernel ermittelt zu lschenden DD, prft Referenzzhler.
	  -	xfs_ddelete sperrt den DD. Wenn das nicht geht, wird EACCDN
	  	geliefert.
	  -	xfs_ddelete lscht das Verzeichnis, wenn es leer ist. Der DD
	  	wirkt dabei als Sperre fr parallel laufende Versuche, das
	  	gerade gelschte Verzeichnis zu benutzen.
	  -  xfs_ddelete lt den jetzt ungltigen, aber noch als Sperre
	  	dienenden	DD weiterhin gltig (im Gegensatz zum alten Konzept).
	  -  Der Kernel macht bei Erfolg seine Standardpfade ungltig
	  -	Der Kernel gibt den DD frei.


xfs_DD2name:   DS.L      1    /* gibt den absoluten Pfadnamen zurck       */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = int bufsize                          */
                              /* -> d0 = long errcode                      */

     Fr Dgetpath und Dgetcwd. Nach <name> wird der Pfad kopiert, der zum
     bergebenen Verzeichnis gehrt. Der Pfad mu ohne folgenden '\'
     zurckgegeben werden, d.h. ein Leerstring fr das Wurzelverzeichnis.
     <bufsize> versteht sich, wie berall, inklusive abschlieendes Nullbyte.
     Wenn der Puffer zu klein ist (bufsize kleiner als der Pfad), mu wie in
     MiNT der Fehlercode ERANGE zurckgegeben werden.

xfs_dopendir:   DS.L      1   /* ffnet ein Verzeichnis                    */
                              /* a0 = DD *                                 */
                              /* d0 = int tosflag                          */
                              /* -> d0 = DHD *dhd                          */
                              /*         oder Fehlercode                   */

     Fr Dopendir. Als <tosflag> sind z.Zt. nur 0 und 1 erlaubt.
     Ist <tosflag> == 0, werden Dateinamen nicht abgeschnitten, und die
     ersten 4 Bytes, die von D(x)readdir zurckgegeben werden, enthalten den
     Datei-Index.
     Ist <tosflag> == 1, mu dreaddir die Dateinamen auf 8+3 und Groschrift
     krzen und darf keine Dateikennung zurckgeben.

xfs_dreaddir:   DS.L      1   /* Liest den nchsten Verzeichniseintrag     */
                              /* a0 = DHD *dhd                             */
                              /* d0 = int  size                            */
                              /* a1 = char *buf                            */
                              /* d1 = XATTR *xattr   oder NULL             */
                              /* d2 = long *xr       (wenn xattr != NULL)  */
                              /* -> d0 = long errcode                      */
xfs_drewinddir: DS.L      1   /* Setzt das dirhandle auf den 1. Eintrag    */
                              /* a0 = DHD * dhd                            */
                              /* -> d0 = long errcode                      */
xfs_dclosedir:  DS.L      1   /* Schliet das dirhandle                    */
                              /* a0 = DHD *dhd                             */
                              /* -> d0 = long errcode                      */

     Alle Funktionen wie in MiNT.
     xfs_dreaddir bernimmt sowohl Dreaddir als auch Dxreaddir.

xfs_dpathconf: DS.L      1    /* Ermittle verschiedene Limits              */
                              /* a0 = DD *                                 */
                              /* d0 = int which                            */
                              /* -> d0 = long value                        */

     Wie in MiNT. XFS_DOS ruft direkt den zustndigen DFS- Treiber auf.
     <which> kann folgende Werte annehmen:
          DP_MAXREQ     (-1)       ermittle max. gltigen Wert fr <which>
          DP_IOPEN       (0)       internes Limit fr Anzahl offener Dateien
          DP_MAXLINKS    (1)       maximale Anzahl Links fr eine Datei
          DP_PATHMAX     (2)       maximale Lnge fr vollen Pfadnamen
          DP_NAMEMAX     (3)       maximale Lnge fr Dateinamen
          DP_ATOMIC      (4)       Blockgre
          DP_TRUNC       (5)       Dateinamen-Verkrzung
               liefert:
           DP_NOTRUNC    (0)       Dateinamen nie verkrzt, ggf. ERANGE
           DP_AUTOTRUNC  (1)       Dateinamen auf max. Lnge gekrzt
           DP_DOSTRUNC   (2)       Automatische Verkrzung auf 8+3
          DP_CASE        (6)       Gro-/Kleinschreibung
               liefert:
           DP_CASESENS   (0)       unterschieden
           DP_CASECONV   (1)       immer in Groschrift gewandelt
           DP_CASEINSENS (2)       nicht unterschieden und nicht gewandelt

         ab 21.5.95 wird weiterhin untersttzt:

          DP_MODEATTR    (7)       -> Doku zu MiNT
          DP_XATTRFIELDS (8)       -> Doku zu MiNT



xfs_dfree:     DS.L      1    /* Ermittle Anzahl freier Blcke usw.        */
                              /* a0 = DD *                                 */
                              /* a1 = long[4]                              */
                              /* -> d0 = long errcode                      */

     Fr Dfree. XFS_DOS ruft direkt den zustndigen DFS- Treiber auf.

xfs_wlabel:    DS.L      1    /* Schreibe Disknamen                        */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* -> d0 = long errcode                      */

     Zum (Um-)Benennen von Medien. Wird vom Kernel dann aufgerufen, wenn
     Fcreate mit Attribut 8 durchgefhrt werden. Wird der Diskname, wie
     beim DOS-Dateisystem, als spezielle Datei abgelegt, mssen alle anderen
     pfadbasierten XFS- Funktionen den Disknamen ignorieren.
     Ein leerer Name oder ein aus "\xe5" bestehender (Kompatibilitt zu TOS)
     mu den Disknamen lschen (falls Medien ohne Namen zulssig sind).
     Wird auch fr Dwritelabel() aufgerufen.

xfs_rlabel:    DS.L      1    /* Lies Disknamen                            */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = char *buf                            */
                              /* d1 = int len                              */
                              /* -> d0 = long errcode                      */

     Zum Lesen des Medien-Namens. Wird vom Kernel dann aufgerufen, wenn
     Fsfirst mit (Attribut == 8) durchgefhrt wird. <name> ist
     i.a. "*.*" und kann ignoriert werden. <len> ist die Lnge des Puffers
     <buf>, bei berschreitung mu ERANGE geliefert werden.
     Wird auch fr Dreadlabel() aufgerufen. In diesem Fall ist name == NULL.

xfs_symlink:   DS.L      1    /* erstelle symbolischen Link                */
                              /* a0 = DD * dir                             */
                              /* a1 = char *name                           */
                              /* d0 = char *to                             */
                              /* -> d0 = long errcode                      */

     Fr Fsymlink. Es mu unter dem neuen Namen <name> eine Datei im
     Verzeichnis <dir> erstellt werden, die auf die Datei <to> zeigt.
     Wird vom DOS_XFS untersttzt.

xfs_readlink:  DS.L      1    /* Lies symbolischen Link                    */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = char *buf                            */
                              /* d1 = int  size                            */
                              /* -> d0 = long errcode                      */

     Fr Freadlink.
     Wird vom DOS_XFS untersttzt.

xfs_dcntl:     DS.L      1    /* fr Dcntl                                 */
                              /* a0 = DD *                                 */
                              /* a1 = char *name                           */
                              /* d0 = int cmd                              */
                              /* d1 = long arg                             */
                              /* -> d0 = long errcode                      */

     Fr Dcntl. Jedes XFS sollte FUTIME untersttzen.


III Datenstrukturen
===================

1. Der Gertetreiber (MX_DEV)
-----------------------------

Der Gertetreiber (MX_DEV) wird beim ffnen einer Datei vom XFS in den
Dateideskriptor eingesetzt und vom Kernel direkt aufgerufen. Der
Gertetreiber mu folgende Funktionen bereitstellen:

     OFFSET

dev_close:     DS.L      1    /* a0 = FD *file                             */
                              /* -> d0 = long errcode                      */

     Wenn fd_refcnt nicht schon 0 ist, mu fd_refcnt dekrementiert werden
     (dies mu vom MX_DEV erledigt werden). Bei dieser Gelegenheit sollten
     auch mglicherweise vorhandene Puffer zurckgeschrieben bzw.
     Verzeichniseintrge aktualisiert werden. Wenn fd_refcnt 0 ist, kann der
     FD freigegeben werden.
     Beim Diskwechsel ist fd_refcnt bereits beim Aufruf von dev_close 0,
     d.h. der FD mu einfach nur freigegeben werden.

     Der vom DOS_XFS installierte Dateitreiber schreibt die Verzeichnisdaten
     zurck und ruft dann den MX_DDEV- Untertreiber auf.

dev_read:      DS.L      1    /* a0 = FD *file                             */
                              /* d0 = long count                           */
                              /* a1 = char *buffer                         */
                              /* -> d0 = long amount                       */

     Von Datei <file> werden <count> Bytes in den Puffer <buffer> gelesen.
     Die Anzahl der tatschlich gelesenen Zeichen wird zurckgegeben.

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf direkt an
     den MX_DDEV- Untertreiber weiter.

dev_write:     DS.L      1    /* a0 = FD *file                             */
                              /* d0 = long count                           */
                              /* a1 = char *buffer                         */
                              /* -> d0 = long amount                       */

     Auf Datei <file> werden <count> Bytes aus dem Puffer <buffer>
     geschrieben.
     Die Anzahl der tatschlich geschriebenen Zeichen wird zurckgegeben.

     Der vom DOS_XFS installierte Dateitreiber aktualisiert Zeit und Datum
     der Datei und leitet dann den Aufruf an den MX_DDEV- Untertreiber
     weiter.

dev_stat:      DS.L      1    /* a0 = FD *file                             */
                              /* a1 = MAGX_UNSEL *unselect   oder NULL     */
                              /* d0 = int rwflag                           */
                              /* d1 = long apcode                          */
                              /* -> d0 = long status                       */

     <unselect> ist entweder NULL oder ein Zeiger auf folgende Struktur:

          typedef struct {
               union{
                    void (*unsel) (MAGX_UNSEL *un);
                    long status;
                    }
               long param;
          } MAGX_UNSEL;

     Gibt den Lese-/Schreibstatus der Datei an. Wird z.B. bei Fselect()
     aufgerufen (oder bei Cconos()/Cconis() usw.). Im Gegensatz zu MiNT wird
     hier dem Treiber berlassen, ob er interruptfhig ist oder nicht, d.h.
     ob er in der Lage ist, eine wartende Applikation im Interrupt wieder
     aufzurufen oder nicht. rwflag gibt an, ob Schreib- oder Lesestatus
     abgefragt wird.

     Vorgehensweise:

     Allgemein gilt: Wenn <unselect> ungleich Null ist, mu der Rckgabewert
     nicht nur als Funktionsergebnis (in d0.l), sondern auch in
     unselect->status zurckgegeben werden. Das gilt fr alle Arten von
     Rckgabewerten. In unsel->param kann optional ein Parameter abgelegt
     werden.

     Wenn <apcode> == NULL ist, wird ge-pollt, d.h. die Applikation wird
     nicht schlafengelegt. Also Rckgabe: 0=nicht bereit, 1=bereit,
     <0=Fehler.

     Wenn <apcode> != NULL ist (dann ist auch <unselect> != NULL), wird
     zurckgegeben:

          <0        Fehler
          0         nicht bereit, Gert kann nur polling
          1         bereit
          >0        etwa Zeiger auf eine Funktion, die den Aufweckinterrupt
                    wieder deinstalliert (entspricht in etwa dem unselect
                    in MiNT).

     Falls das Gert nicht bereit ist und interruptfhig ist, geht man
     folgendermaen vor:

     1. unselect mit der Adresse der Aufrumroutine und einem optionalen
        Parameter initialisieren, Prototyp etwa:
        void unselect( a0 = MAGX_UNSEL *un, a1 = void *ap_code );
     2. Interrupt zum Aufwecken installieren, diesem unselect (und damit
        auch den optionalen Parameter) und appl mitteilen.
     3. Zeiger auf Aufrumroutine in d0 zurckgeben.

     Die Interruptroutine macht folgendes:

     1. Der Interrupt trifft ein.
     2. unselect->status wird mit 1 (ok) oder < 0 (nicht ok) beschrieben
        und der Interrupt deaktiviert! Die Applikation wird aufgeweckt mit

          kernel->appl_IOcomplete( a0 = APPL *ap );

     Die Aufrumroutine macht folgendes:

     1. Der Interrupt wird deaktiviert.
     2. in unsel->status wird, falls noch nicht geschehen, eine 1
        (eingetroffen) oder 0 (nicht eingetroffen) oder < 0 (Fehler)
        eingetragen. Es mu sichergestellt werden, da kein IOcomplete und
        kein Schreibzugriff auf unsel anschlieend noch erfolgen kann.
        Ein Wert ungleich 1, aber grer als Null wird immer als Adresse der
        Aufrumroutine interpretiert, diese mu noch aufgerufen werden, wenn
        der Interrupt nicht eingetroffen ist.
        Falls der Interrupt z.B. einen Wert von 2L eintrge, ginge der Kernel
        davon aus, da der Interrupt nicht eingetreten ist und immer noch die
        Adresse der Aufrumroutine in der MAGX_UNSEL- Struktur steht. Ein
        Sprung nach Adresse 2 ist dann aber schnell ziemlich tdlich.

     Die DOS-Funktionen Finstat() und Foutstat() versuchen zunchst, den
     Aufruf auf Fcntl(FIONREAD) bzw. Fcntl(FIONWRITE) zurckzufhren. Wenn
     diese Subfunktion von dev_ioctl nicht existiert (der Dateitreiber mu
     EINVFN liefern!), wird dev_stat aufgerufen. In diesem Fall kann die
     Aussage getroffen werden "Zeichen liegt an" (Wert == 1) bzw. "kein
     Zeichen liegt an" (Wert == 0).

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf direkt an
     den MX_DDEV- Untertreiber weiter.

dev_seek:      DS.L      1    /* a0 = FD *file                             */
                              /* d0 = long where                           */
                              /* d1 = int mode                             */
                              /* -> d0 = long position                     */

     Fr Fseek. <mode> ist, wie im TOS, 0, 1 oder 2. Zurckgegeben wird die
     aktuelle Position des Schreib-/Lesezeigers, Gertetreiber mssen
     hier immer eine 0L zurckgeben.

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf direkt an
     den MX_DDEV- Untertreiber weiter.

dev_datime:    DS.L      1    /* a0 = FD *file                             */
                              /* a1 = int d[2]                             */
                              /* d0 = int setflag                          */
                              /* -> d0 = long errcode                      */

     Fr Fdatime.

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf an
     den MX_DDEV- Untertreiber weiter, wenn die Funktion im MX_DDEV- Treiber
     untersttzt wird (Zeiger != NULL), ansonsten wird die Funktion
     automatisch mit Hilfe der Daten des FD ausgefhrt.

dev_ioctl:     DS.L      1    /* a0 = FD *file                             */
                              /* d0 = int cmd                              */
                              /* a1 = void *buf                            */
                              /* -> d0 = long errcode                      */

     Fr Fcntl.

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf direkt an
     den MX_DDEV- Untertreiber weiter. Bearbeitet werden jedoch vorher
     folgende Funktionen: FSTAT und FUTIME. Diese sollten auch von anderen
     XFSs ausgefhrt werden.
     Jeder Dateitreiber sollte FIONREAD und FIONWRITE untersttzen.

dev_getc:      DS.L      1    /* a0 = FD *file                             */
                              /* d0 = int mode                             */
                              /* -> d0 = unsigned long c                   */

     Wird vom Kernel fr Fgetchar() und die zeichenorientierten Funktionen
     (Cconin, Cconout, Cauxin usw.) verwendet.
     Im Fall eines Gerts kann der Rckgabewert ein Langwort sein (so bei CON
     im Hiword der Scancode der Taste), ansonsten ein Byte (immer als
     "unsigned" erweitert). Bei EOF mu 0x0000FF1A geliefert werden.
     <mode> bedeutet:

          CMODE_COOKED (1)    Bit 0 gesetzt: Steuerzeichen ^C, ^S, ^Q werden
                              verarbeitet.
          CMODE_RAW (0)       Bit 0 nicht gesetzt: "raw" Modus
          CMODE_ECHO (2)      Bit 1 gesetzt: Eingabe wird ge-echo-t

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf an
     den MX_DDEV- Untertreiber weiter, wenn die Funktion im MX_DDEV- Treiber
     untersttzt wird (Zeiger != NULL), ansonsten wird die Funktion
     automatisch auf dev_fread zurckgefhrt.

dev_getline:   DS.L      1    /* a0 = FD *file                             */
                              /* a1 = char *buf                            */
                              /* d1 = long size                            */
                              /* d0 = int mode                             */
                              /* -> d0 = long amount                       */

     Fr zeilenorientierte Eingabe. <mode> wie in dev_getc. Zurckgegeben
     wird die Anzahl der eingegebenen Zeichen ohne Endezeichen o..

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf an
     den MX_DDEV- Untertreiber weiter, wenn die Funktion im MX_DDEV- Treiber
     untersttzt wird (Zeiger != NULL), ansonsten wird die Funktion
     automatisch auf dev_fread zurckgefhrt, die Zeile wird dann mit CR und
     LF beendet, Steuerzeichen (BS oder Del) nicht ausgewertet.

dev_putc:      DS.L      1    /* a0 = FD *file                             */
                              /* d0 = int mode                             */
                              /* d1 = long value                           */
                              /* -> d0 = unsigned long count               */

     Wird vom Kernel fr Fgetchar() und die zeichenorientierten Funktionen
     (Cconout, Cauxout usw.) verwendet.
     Im Fall eines Terminals mu der Rckgabewert 4L sein (d.h. 4 Bytes
     geschrieben, ansonsten 1L, falls erfolgreich geschrieben wurde.
     <mode> bedeutet:

          CMODE_COOKED (1)    Bit 0 gesetzt: Steuerzeichen ^C, ^S, ^Q werden
                              verarbeitet.
          CMODE_RAW (0)       Bit 0 nicht gesetzt: "raw" Modus

     Der vom DOS_XFS installierte Dateitreiber leitet den Aufruf an
     den MX_DDEV- Untertreiber weiter, wenn die Funktion im MX_DDEV- Treiber
     untersttzt wird (Zeiger != NULL), ansonsten wird die Funktion
     automatisch auf dev_fwrite zurckgefhrt.


2. Der Verzeichnisdeskriptor (DD)
---------------------------------

Die Verzeichnisdeskriptoren mssen vom XFS angelegt und verwaltet werden. Alle
Deskriptoren, die dem Kernel bekannt sind (d.h. diejenigen, die fr einen
Proze als Standardpfad verwendet werden) haben Referenzzhler ungleich
Null. Eine Ausnahme bildet nur der DD fr das Wurzelverzeichnis eines
Laufwerks; hier ist der Referenzzhler immer 0, egal ob ein Proze das
Wurzelverzeichnis als Standardverzeichnis hat oder nicht.
Fr den Kernel sieht ein DD folgendermaen aus, diese Eintrge mssen vom XFS
angelegt werden:

dd_dmd:        DS.L      1    /* 0x00: Zeiger auf DMD                      */

     Hier steht das zugehrige Dateisystem.

dd_refcnt:     DS.W      1    /* 0x04: Ref.zhler fr Standardpfade        */

     Der Referenzzhler. Dieser Eintrag wird nur vom Kernel verwendet, mu
     vom XFS beim Erstellen eines DD auf 0 initialiert (bei der root am
     besten auf 1, s.o. bei xfs_drv_open) und bei jeder bergabe an den Kernel
     (-> xfs_path2DD) um 1 inkrementiert werden.

     D.h. da xfs_path2DD beim Zurckgeben eines neuen DD (der also vom Kernel
     sonst nicht referenziert wird) den Referenzzhler auf 1 setzen mu.

     Wenn der Referenzzhler ungleich 0 ist, hat der Kernel Zeiger auf diesen
     DD, und er darf keinesfalls vom XFS freigegeben werden.
     Der Kernel zhlt den Referenzzhler jedesmal um 1 herunter, wenn er
     einen DD nicht mehr bentigt. Erreicht der Zhler dabei Null, wird
     xfs_freeDD aufgerufen. Das XFS kann dann den DD freigeben oder
     ansonsten erst beim Aufruf von xfs_garbcoll (der "garbage collection")
     oder bei xfs_drv_close.
     Achtung: Die root darf whrend der "Lebensdauer" eines gemounteten
              Dateisystems nicht freigegeben werden. Der Referenzzhler
              der root sollte mit 1 vorbesetzt werden, um zu verhindern,
              da er per free_DD freigegeben wird.


3. Der Dateideskriptor (FD)
---------------------------

Die Dateideskriptoren mssen vom XFS angelegt und verwaltet werden. Alle
Deskriptoren, die dem Kernel bekannt sind, haben Referenzzhler ungleich
Null. Fr den Kernel sieht ein FD genauso aus wie ein DD, weshalb im DOS_XFS
die gleiche Datenstruktur verwendet wird.
Fr den Kernel sieht ein FD folgendermaen aus, diese Eintrge mssen vom XFS
angelegt werden:

fd_dmd:        DS.L      1    /* 0x00: Zeiger auf DMD                      */

     Hier steht das zugehrige Dateisystem.

fd_refcnt:     DS.W      1    /* 0x04: Ref.zhler frs Schlieen oder -1   */

     Der Referenzzhler. Dieser Eintrag wird nur vom Kernel verwendet, mu
     beim Aufruf von dev_close dekrementiert und durch xfs_fopen
     initialisiert werden (mit 1).
     Ein Referenzzhler von -1 signalisiert, da der FD nie freigegeben
     werden darf. Dies ist z.B. fr die Gertedateien U:\DEV\CON, U:\DEV\AUX
     usw. notwendig, die immer zur Verfgung stehen.

fd_mode:       DS.W      1    /* 0x06: Open- Modus und flags               */

     Hier steht der Modus, wie bei xfs_fopen (s.o) beschrieben. Zeigen zwei
     FDs auf dieselbe Datei, mssen die Modi kompatibel sein. Durch die
     einfache Mag!X- interne Modusdarstellung ist ein einfaches Rotieren und
     verUNDen der Bits ausreichend. Z.B:

          move.w   fd_mode(a0),d1
          btst     #BOM_NOCHECK,d1     ; kein Check durch das XFS ?
          bne.b    _opf_nxt            ; ja, ddev_open prft
          ror.b    #4,d1
          and.b    d0,d1
          bne      opd_eaccdn          ; Konflikt: return(EACCDN)

fd_dev:        DS.L      1    /* 0x08: Zeiger auf MX_DEV                   */

     Dies ist der Zeiger auf den Gertetreiber.

Die vom DOS_XFS abgeleitete Klasse (ein "DOS-FD") hat wesentlich mehr Felder
und ist in der Beschreibung der DFS- Einbindung genau aufgefhrt.

4. Der Directory-Handle-Deskriptor (DHD)
---------------------------------------

Die Directory-Handles werden fr Dopendir/Dclosedir/Drewinddir bentigt. Im
Gegensatz zu den Dateideskriptoren (FD) hlt der Kernel keine Liste der
geffneten DHs. Wenn ein Proze terminiert, wird das XFS ber die Funktion
xfs_pterm aufgerufen und mu alle fr den Proze angelegten DHs freigeben.
Den Eigner eines DH kann das XFS ber den Kernel-Zeiger <act_pd> ermitteln.
Fr den Kernel sieht ein DH folgendermaen aus, diese Eintrge mssen vom XFS
angelegt werden:

dhd_dmd:       DS.L      1    /* 0x00: Zeiger auf DMD                      */

     Hier steht das zugehrige Dateisystem.

5. Der Mediumdeskriptor (DMD)
-----------------------------

Der DMD wird vom Kernel (!) fr jedes geffnete Laufwerk angelegt und auch
ggf. wieder freigegeben. Hier legt der XFS alle Daten an, die er sich fr
das Laufwerk merken mu. Die folgenden Felder sind diejenigen, die der Kernel
bentigt (Das Ur- Objekt, von dem der XFS seinen XFS-DMD ableitet):

d_xfs:         DS.L      1    /* 0x00: Der Dateisystemtreiber              */

     Hier steht der zugehrige Dateisystemtreiber (XFS). Er wird von
     xfs_drv_open eingetragen.

d_drive:       DS.W      1    /* 0x04: Laufwerknummer 0..25                */

     Hier steht, welchem logischen Laufwerk ('A' .. 'Z') das Dateisystem
     zugeordnet ist. Das braucht nicht immer einem BIOS- Laufwerk zu
     entsprechen. Dieser Wert wird immer (!) vom Kernel eingetragen, wenn ein
     Laufwerk geffnet wird, bevor ein XFS eingetragen wird.

d_root:        DS.L      1    /* 0x06: Zeiger auf DD der Root              */

     Hier steht ein Zeiger auf den DD des Wurzelverzeichnisses.

d_biosdev:     DS.W      1    /* 0x0a: BIOS-Laufwerk oder -1               */

     Wenn es sich um eine Partition handelt, die mit BIOS Rwabs behandelt
     wird, steht hier die BIOS-Gertenummer.
     Ansonsten mu -1 eingetragen werden (z.B. bei Laufwerk U: oder einer
     Macintosh-Partition).

d_driver:      DS.L      1    /* 0x0c: def. zus. mit devcode das Medium    */
d_devcode:     DS.L      1    /* 0x10: z.B. SCSI Target & Laufwerk         */

     Bestimmen zusammen das Medium. D.h. wenn d_driver und d_devcode
     identisch sind, liegen beide Laufwerke auf demselben Medium. D.h. wenn
     das Medium ausgeworfen werden soll, mssen beide Dateisysteme gesperrt
     werden. Bei einer Harddisk-Partion ist d_biosdev das BIOS-Laufwerk,
     d_driver ist beliebig (z.B. Zeiger auf die XHDI-Struktur), d_devcode
     ist der XHDI-Code eines Mediums, d.h. SCSI-Target und Gertenummer
     (jew. ein WORD).

d_dfs:         DS.L      1    /* 0x14: DOS-spezifischer Dateisystemtreiber */

     Dieser Eintrag existiert zwingend nur fr DOS- Dateisysteme (also
     bereits fr ein abgeleitetes Objekt) und enthlt einen Zeiger auf den
     DFS- Untertreiber.

Andere XFSs oder DFSs tragen weitere Daten in den DMD ein. Man kann sich den
DMD als eine Objektklasse vorstellen. Ein fr das DOS_XFS abgeleiteter DMD
hat nur den zustzlichen Eintrag d_dfs. Der FAT-DFS trgt zustzlich Daten
wie die Clustergre und die Anzahl der Sektoren ein.

6. Die DTA
----------

Die DTA wird von den alten DOS- Funktionen Fsfirst und Fsnext verwendet,
deren ungeschickte Konzeption durch die MSDOS- Schpfer immer noch wie ein
Fluch auf uns lastet. Fr den Kernel sieht die Struktur folgendermaen aus:

dta_res1:      DS.B      20

     Wird vom Kernel nicht verwendet. Hier darf sich das XFS tummeln.

dta_drive:     DS.B      1    /* 0x14: */

     Hier steht das zugehrige logische Laufwerk ( 0 ~ 'A' usw.). Hierdurch
     kann der Kernel beim Fsnext entscheiden, welches XFS die Anforderung
     ausfhren mu.

dta_attribute: DS.B      1    /* 0x15: gefundenes Attribut                 */
dta_time:      DS.W      1    /* 0x16: gefundene Zeit                      */
dta_date:      DS.W      1    /* 0x18: gefundenes Datum                    */
dta_len:       DS.L      1    /* 0x1a: gefundene Lnge                     */
dta_name:      DS.B      14   /* 0x1e: gefundener Dateiname                */

     Das ist der dokumentierte "User-" Bereich. Er mu nach GEMDOS-
     Spezifikation behandelt werden.

7. Die Datei-Informationsstruktur (XATTR)
-----------------------------------------

Der Aufbau entspricht der MiNT- Spezifikation. Der Vollstndigkeit halber
hier noch einmal eine Kurzfassung:

xattr_mode:    DS.W      1    /* %ttttsssrwxrwxrwx                         */
                              /* Bit 12,13,14,15: Dateityp                 */
                              /*         2: BIOS special file              */
                              /*         4: Directory file                 */
                              /*         8: regular file                   */
                              /*        10: fifo                           */
                              /*        12: memory region or process       */
                              /*        14: symbolic link                  */
                              /* Bit 9,10,11: special bits (a la UNIX)     */
                              /*         1: sticky bit                     */
                              /*         2: setgid                         */
                              /*         4: setuid                         */
                              /* Bit 0..8: access modes                    */
                              /*         rwx fr user/group/world          */
xattr_index:   DS.L      1
xattr_dev:     DS.W      1
xattr_res1:    DS.W      1
xattr_nlink:   DS.W      1
xattr_uid:     DS.W      1
xattr_gid:     DS.W      1
xattr_size:    DS.L      1
xattr_blksize: DS.L      1
xattr_nblocks: DS.L      1
xattr_mtime:   DS.W      1
xattr_mdate:   DS.W      1
xattr_atime:   DS.W      1
xattr_adate:   DS.W      1
xattr_ctime:   DS.W      1
xattr_cdate:   DS.W      1
xattr_attr:    DS.W      1
xattr_res2:    DS.W      1
xattr_res3:    DS.L      2


IV Installation
===============

XFS werden normalerweise aus dem Ordner \gemsys\magic\xtension geladen und
mssen die Endung *.xfs haben. Sie werden vor dem AUTO-Ordner und nach
den Gertetreibern (\gemsys\magic\xtension\*.dev) geladen. Prinzipiell ist
aber die Installation eines XFS jederzeit mglich.

Ein XFS ist einfach ein Programm, das den Treiber installiert und sich
resident beendet.
Die Installation erfolgt durch

     kernel = Dcntl(KER_INSTXFS, NULL, &myxfs);

Man erhlt einen Zeiger auf wichtige Kernelfunktionen zurck (oder einen
Fehlercode). Die Kernelfunktionen kann man auch unabhngig von der
Installation eines XFS erfragen ber

     kernel = Dcntl(KER_GETINFO, NULL, NULL);

Die Deinstallation eines XFS ist nicht vorgesehen.


V Die Kernelfunktionen
======================

Mag!X stellt den installierten XFSs, DFSs oder Gertetreibern einige
Kernelinformationen sowie -funktionen zur Verfgung. Bei den Kernelfunktionen
gilt dieselbe Registerkonvention wie fr die XFS-Funktionen, d.h. d0-d2 und
a0-a2 knnen zerstrt werden.
Einen Zeiger auf die Struktur, die die Kernelfunktionen enthlt, bekommt man
ber

     kernel = Dcntl(KER_INSTXFS, NULL, &myxfs);
oder
     kernel = Dcntl(KER_GETINFO, NULL, NULL);

Im ersten Fall wird ein XFS installiert, im zweiten Fall bekommt man nur die
Kernelstruktur (etwa fr ein DFS oder einen Gertetreiber). Der Aufbau der
Kernelstruktur im einzelnen:

typedef struct {

 int  version;

     /* Das ist die Versionsnummer, die z.Zt. 4 ist. Bei jeder
     nderung der Kernelstruktur wird die Versionsnummer hochgesetzt, so da
     sich Programme entsprechend anpassen knnen */

 void fast_clrmem             ( a0 = void *von, a1 = void *bis );

     /* eine schnelle Speicherlschroutine, die den Speicher von <von> bis
     <bis> (ausschlielich) auf 0 setzt */

 char toupper                 ( d0 = char c );

     /* wandelt das Zeichen <c> unter Bercksichtigung der nationalen
     Sonderzeichen in Groschrift um */

 void _sprintf                (char *dest, char *source, long p[]);

     /* Eine Funktion, die ihre Argumente auf dem Stack erwartet. bergeben
     wird die Ziel-Zeichenkette <dest>, die Schablone <source> und die
     einzutragenden Werte p[]. Die Langworte werden je nach
     Formatieranweisung als "unsigned int" (%W), "signed long" (%L) oder
     Zeichenkette (%S) interpretiert. Bei %W wird das weiter unten im
     Speicher liegende Wort verwendet, die Folge %% fgt ein Prozentzeichen
     ein. */

 void *act_pd;

     /* der Zeiger auf die aktuelle Basepage, die Adresse lt sich auch
     ber den Systemheader oder die DOS- Variablen ermitteln. */

 APPL *act_appl;

     /* der Zeiger auf die aktuelle Applikation (d.h. die laufende
     Task). Der Aufbau der Struktur ist nicht dokumentiert, der Zeiger wird
     wegen des schnelleren Zugriffs anstelle der ap_id als Deskriptor
     verwendet. */

 APPL *keyb_app;

     /* die Applikation, die z.Zt. die Tastatur besitzt. Der Zeiger kann
     z.B. von Gertetreibern verwendet werden, die die tastaturbesitzende
     Applikation anders behandeln mssen. */

 int  *pe_slice;
 int  *pe_timer;

     /* Fr das premptive Multitasking. Wenn <*pe_slice> == -1 ist, ist das
     premptive Multitasking abgeschaltet, und Diskzugriffe werden nicht
     unterbrochen. */

 void (*appl_yield)       ( void );

     /* gibt Rechenzeit ans System. Wichtig fr Treiber, die nicht auf einen
     Interrupt warten knnen und verhindern mssen, da ihr "busy waiting"
     das System lahmlegt. */

 void (*appl_suspend)     ( void );

     /* arbeitet wie appl_yield(), gibt jedoch der Applikation eine
     geringere Prioritt, etwa als Hintergrundproze. */

 void (*appl_begcritic) ( void );

     /* Die aktuelle Applikation tritt in eine kritische Phase und
        darf nicht terminiert werden. */

 void (*appl_endcritic) ( void );

     /* Ende der kritischen Phase. Falls zwischenzeitlich der Befehl
        zur Terminierung eingegangen ist, wird das Programm
        terminiert */

 long (*evnt_IO)          ( d0 = long ticks_50hz, a0 = void *unsel );

     /* evnt_IO() ermglicht es, auf EIN externes Ereignis zu warten. Als
     externes Ereignis kommt entweder ein Interrupt oder eine andere
     Applikation (die etwa zum Aufwecken in eine Pipe schreibt) in Frage.

     Die Funktion wird zum Erstellen von Gertetreibern verwendet,
     Vorgehensweise (siehe DEV_LPT1 als Beispiel):

     1. Interrupts sperren
     2. Abfrage, ob das Ereignis (im Fall DEV_LPT1 lautet das Ereignis:
        "centronics busy off" eingetroffen ist.
     3. Wenn ja, Interrupts freigeben und Aktion durchfhren (im Fall
        DEV_LPT1: Zeichen drucken)
     4. Wenn nein, Interruptroutine aufsetzen (im Fall DEV_LPT1: MFP-I0,
        d.h. Centronics Busy Interrupt aktivieren) und diesem die aktuelle
        Applikation (act_appl) sowie eine Langwortadresse zugnglich machen,
        in die die Interruptroutine Rckmeldungen schreiben kann. Diese
        Adresse ist mit der Adresse einer Routine zu beschreiben, die den
        Interrupt wieder abmeldet, dahinter knnen nach eigenen
        Anforderungen z.B. noch weitere Daten folgen. Die Unselect- Routine
        bekommt spter einen Zeiger auf alle diese Daten und kann z.B. die
        optionalen Parameter auswerten.
        Der ganze Mechanismus ist notwendig, um ein korrektes
        Deinitialisieren des Interrupts in jedem Fall zu garantieren.
     5. Interrupts freigeben
     6. evnt_IO aufrufen. In d0.w die Anzahl der 50Hz- Ticks fr den Timeout
          angeben, 0 heit "kein Timeout". In a0 die Adresse des Langworts
          angeben, in dem die Adresse der Aufrumroutine steht, die den
          Interrupt wieder abmeldet (dahinter folgen optional weitere
          Parameter, falls die Unselect- Routine diese versteht). Im Fall
          des Einbindens von Gertetreibern fr Fselect() ist nur ein
          optionales Langwort mglich.

     Die Interruptroutine schreibt bei Eintreffen des Interrupts einen Status
     < 0L (Fehler) oder 1L (OK) statt der Deinitialisierungsroutine in das
     Statuslangwort (in dem vorher ihre eigene Startadresse stand).
     Anschlieend deinstalliert sich die Routine selbst bzw. stellt sicher,
     da bei folgenden Interrupts keine Aktionen ausgefhrt werden.
     Schlielich weckt die Interruptroutine die dem Interrupt zugeordnete
     Applikation auf, und zwar ber den Aufruf appl_IOcomplete() mit der
     Applikation als Parameter.

     7. evnt_IO() liefert als Rckgabewert 0L (Timeout, der Interrupt ist
        nicht eingetroffen) oder < 0 (der Interrupt hat Fehlermcode ins
        Statuslangwort geschrieben) oder 1L (der Interrupt hat eine 1L ins
        Statuslangwort geschrieben). Eine Deinstallierung des Interrupts ist
        nicht mehr notwendig, dies hat der Kernel erledigt, falls die
        Interruptroutine dies nicht selbst beim Eintreffen des Interrupts
        getan hat.

 void (*evnt_mIO)         ( d0 = long ticks_50hz, a0 = void *unsel,
                            d1 = int cnt );
 void (*evnt_emIO)        ( a0 = APPL *ap );

     /* evnt_mIO() ermglicht es, auf MEHRERE externe Ereignisse zu warten,
     z.B. wird diese Funktion von Fselect verwendet (mehrere Dateien!).
     Vorgehensweise:

      1. Fr n Ereignisse eine Langwort-Tabelle der Lnge 2*n anlegen.
      2. Fr jedes Ereignis die Aufrumroutine ("unselect- Routine")
         eintragen, (dahinter folgt ein optionaler Langwortparameter) und
         den Interrupt aufsetzen. Die Reihenfolge ist wichtig, es mu
         verhindert werden, da die unselect- Adresse den Rckgabewert des
         bereits eingetroffenen Interrupts berschreibt, ggf. Interrupts
         sperren.
      3. evnt_mIO aufrufen. Die Parameter sind wie bei evnt_IO, in d1.w wird
         aber die Anzahl der Ereignisse bergeben, a0 ist der Tabellenanfang.
      4. evnt_mIO() liefert keinen Rckgabewert. Die Tabelle mu durchsucht
         und die Interrupts deinstalliert werden (z.B. die unselect-
         Routinen aufrufen), dabei kann berprft werden, welche Interrupts
         bereits eingetroffen sind.
      5. evnt_emIO mit der aktuellen Applikation aufrufen. Dieser Aufruf
         stellt sicher, da nach Deinstallieren aller Interrupts deren jetzt
         nutzlose Nachrichten an die Applikation gelscht werden.

     Auf die Ereignisse evnt_(m)IO wartende Applikationen erscheinen im
     Programm-Manager als wartend auf "io" (Input/Output) oder "io ti"
     (Input/Output mit Timeout).

 void (*appl_IOcomplete)  ( a0 = APPL *ap );

     /* Weckt eine Applikation auf, die gerade auf evnt_(m)IO wartet */

 long (*evnt_sem)         ( d0 = int mode, a0 = void *sem,
                            d1 = long timeout );

     /* Fr mode sind folgende Unterfunktionen mglich:

      0  SEM_FREE  Semaphore freigeben (ohne Taskwechsel!)
                   a0 = Zeiger auf Semaphore
         -> 0      OK
         -> -1     Semaphore unbenutzt oder von anderer APP benutzt

      1  SEM_SET   Semaphore setzen, ggf. warten
                   a0 = Zeiger auf Semaphore
                   d1 = Timeout in 50Hz- Ticks
         -> 0      OK
         -> 1      Timeout
         -> -1     Semaphore war schon von mir gesetzt
         -> -2     Semaphore wurde inzwischen entfernt

      2  SEM_TEST  Eigner der Semaphore ermitteln (ggf. NULL)
                   a0 = Zeiger auf Semaphore
         -> >0     Eigner
         ->  0     nicht benutzt

      3  SEM_CSET  Semaphore setzen, falls nicht schon gesetzt
                   a0 = Zeiger auf Semaphore
                   d1 = Timeout in 50Hz- Ticks
         ->  0     OK
         ->  1     Semaphore von anderer APPL gesetzt
         ->  -1    Semaphore war schon von mir gesetzt

      4  SEM_GET   Semaphore ermitteln, falls Name bekannt ist.
                   d1 = Name der Semaphore
         ->  >0    Zeiger auf Semaphore
         ->  -1    Semaphore nicht gefunden

      5  SEM_CREATE Semaphore erstellen, d.h. neue einrichten
                   a0 = Zeiger auf Semaphore (32 Bytes auf gerader Adresse)
                   d1 = Name
         void

      6  SEM_DEL   Semaphore entfernen
                   a0 = Zeiger auf Semaphore
         ->   0    OK
         ->  -1    Semaphore ungltig

     SEM_SET und SEM_CSET sind die einzigen Unterfunktionen, die einen
     Taskwechsel auslsen knnen.

     Im Gegensatz zu wind_update() kann mit diesen Aufrufen das Setzen und
     Freigeben von Semaphoren nicht geschachtelt werden. Versucht man, eine
     bereits reservierte Semaphore nochmal zu reservieren, gibt es einen
     Fehlercode.

     Beim Freigeben der Semaphore wird kein Taskwechsel durchgefhrt, d.h.
     die Semaphore kann zwar ggf. jetzt einer anderen Applikation gehren,
     die den Status "ready" hat, aber sie hat noch keine Rechenzeit
     bekommen. Wenn die Situation unkritisch ist, sollte in jedem Fall
     anschlieend ein appl_yield() durchgefhrt werden.

     Die Bildschirmsemaphore hat den Namen _SCR und darf mit evnt_sem() nur
     mit der Unterfunktion SEM_TEST behandelt werden.

     SEM_CREATE setzt den Erzeuger nicht automatisch als Eigner. Dies ist
     nicht notwendig, weil kein Taskwechsel stattgefunden hat. Also kann
     bedenkenlos ein SEM_SET anschlieend durchgefhrt werden.

     SEM_DEL verlangt, da der Lscher auch der Eigner ist.
     Beim Lschen werden alle wartenden Applikationen
     freigegeben, sie erhalten, wenn sie per evnt_sem(SEM_SET, ..) warten,
     eine -2 als Rckgabewert.
     Wer System-Semaphoren (solche, deren Namen mit '_' beginnen) lscht,
     ist selbst schuld.

 void (*Pfree)            ( a0 = void *pd );

     /* gibt den Speicher fr einen Proze frei, der mit Ptermres beendet
     wurde. Dies ist notwendig, um einen Gertetreiber korrekt zu
     entfernen. */

 int  int_msize;

     /* Die Lnge eines Speicherblocks der internen (Kernel-)
     Speicherverwaltung */

 void *int_malloc         ( void );

     /* alloziert einen internen Speicherblock. Ist kein Speicher mehr frei,
     wird zunchst eine globale "garbage collection" durchgefhrt (s.o. bei
     der Beschreibung des XFS, dann bei Mierfolg das System angehalten.
     Interne Speicherblcke drfen nur in kleinen Mengen angefordert werden,
     sonst erhlt man sehr bald ein "Out of internal memory", und das System
     steht. */

 void  int_mfree         ( a0 = void *memblk );

     /* gibt einen Block wieder frei */

 void  resv_intmem       ( a0 = void *mem, d0 = long bytes );

     /* Erweitert den Kernelspeicher. Es ist keine Mglichkeit vorgesehen,
     den Speicher zurckzufordern. Da der Kernel nur zur Bootzeit ausreichend
     internen Speicher fr die FAT-Laufwerke anfordert, kann es fr ein
     XFS notwendig sein, beim Start mit dieser Funktion weiteren Kernelspeicher
     zu reservieren. */

 long diskchange         ( d0 = int drv );

     /* mu aufgerufen werden, wenn ein XFS- oder DFS- Treiber einen
     Diskwechsel erkannt hat. Der XFS- Treiber gibt seine Dateien und
     Strukturen frei, anschlieend der Kernel.
     Rckgabe: EDRIVE  Laufwerk ungltig
               E_CHNG  Laufwerk mit neuer Disk gltig
     */

 long DMD_rdevinit		( a0 = DMD *dmd );

	/* Ab Kernelversion 1.
	Initialisiert die Felder <d_driver> und <d_devcode> des DMD und
	benutzt dazu das Feld <d_biosdev>. Wird fr Diskwechselmechanismen
	bentigt.
	*/

 long proc_info		( d0 = WORD code, a0 = PD *pd );

	/* Ab Kernelversion 2.
	Ermittelt Daten fr den aktuellen Proze:
		d0 = 0:	hchste verfgbare Unterfunktionsnummer
			1:	Domain
			2:	Process-ID
	*/

 long mxalloc			( d0 = LONG amount, d1 = WORD mode, a0 = PD *pd );

	/* Ab Kernelversion 4.
	Ermglicht eine schnelle Speicherallozierung, z.B. fr ein RAMDisk-XFS,
	ohne ber den Trap gehen zu mssen.
	<pd> gibt den Proze an, der als Eigner des neuen Blocks eingetragen
	wird, daher sollte normalerweise die Basepage des XFS-Treibers bergeben
	werden.
	*/

 long mfree			( a0 = void *block );

	/* Ab Kernelversion 4.
	Gibt Speicher wieder frei.
	*/

 long mshrink			( d0 = LONG newlen, a0 = void *block );

	/* Ab Kernelversion 4.
	ndert die Gre eines Speicherblocks.
	*/
} MX_KERNEL;
