3.3 ** Input-/Output Sub-Systems
There is no single i/o system in QDOS.
Each device, and even memory can be considered a device, in this sense, maintains it's own, typically very efficient, set of procedures of memory management, which will be operated in a (fairly) common manner.
3.3.1 * Strukture
Besides the lowest level, the "slave blocks" management in memory, any data transfer will be managed on behalf of "channels" as a property of the device(s) concerned, transparently to programs - and to the user, in about the same manner. Several operations, the "QDOS traps", are defined w.r.t. what they are expected to accomplish, and from within the device definitions, w.r.t. what they should deliver to the caller.Each channel will, after being "opened", assigned an unique identifer to, the "channel id", which is the only addressing reference ever necessary to invoke any operations on such channels. The traps might expect several additional data, in a unique way, as decribed by what may be called the "QDOS conventions".
Thus any input and output is fully re-directable and, at most, device independent.
Further, because QDOS is a multitasking system, any i/o-operation can be assigned a "timeout" figure to, until elapsing of which the channel concerned cannot be accessed by any other "job".
-1 waiting until completion not "atomic", system still multi tasking 0 immediately returning required when in "supervisor" mode +ve 16bit nunber timout in units of 20ms returns D0:=-1 after timing out Timing can only be superseded by an error in the channel, or if the channel was closed (de-allocated) by some other job or, by (forced) removal of it's owner job.
The key code to the required operation will be passed with D0, timeout with D3, the channel id with A0, an auxiliary buffer address with A1, its size with D2. More data may be passed as required with D1 and A2. This is all what is necessary for any i/o and screen related operations.
Device dependent actions wil be managed by the device "handler" concerned, which also is described by a set of conventions which apply to any such thing in the system.
Devices can be re-defined, entirely, or selectively their i/o, channels allocation or, channels de-allocation procedures. One well known exaple being the "Pointer Interface", an extension to the screen handler which facilitates some fundamental windowing operations.
3.3.2 ** Device Handler, Device Driver - Device management
3.3.2.1 * Aufbau
Die Verwaltung durch den Handler steht der sinnfälligen Verwendung der Daten in einem program gegenüber. Auf der anderen Seite besorgt er die Verbindung mit dem Geschehen außerhalb des eigentlichen Rechnerbereiches. "Außerhalb" ist hierbei in weitestem Sinne jede irgendwie zugängliche Einrichtung, nur nicht die selbst gerade aktiven Teile. Insbesondere sind das die Standard-Einheiten des QL:Die Geräteverwaltung verbindet also zwei Ebenen (Schichten - layer). Die Zugangsebene, "access layer", auf Seiten der Software und für die Hardware die körperlich vorhandene, physische Ebene, "physical layer".
- Sichtgerät
- RAM
- I.P.C. "Intelligent Peripheral Controller" mit Tastatur und Tongenerator
- Serielle Schnittstellen - teils auch vom IPC betreut
- Netzwerk
- Microdrive(s)
- Uhr
Der Device Handler verwaltet die Hardware, indem er ihr Daten in der benötigten Form zuführt oder sie ihr in entsprechender Weise entnimmt. Zugleich ist darin auch der Transport von oder zur Softwareseite organisiert. Dank dieser Aufteilung kann einerseits die Software weitestgehend standardisierten Protokollen folgen, die Hardware andererseits davon völlig unabhängig ihren meist hoch spezialisierten Anforderungen gemäß gesteuert werden.
Der große Gewinn liegt in eben dieser Trennung.
Es ist weitgehend gleichgültig, wohin die Daten gehen oder woher sie geholt werden. Die programierung wird vereinfacht und ermöglicht besonders vielseitige Anwendungen. Zum anderen ist bei der Hardwarebetreuung keinerlei Rücksicht auf die programe erforderlich. Sie kann völlig auf die jeweiligen Anforderungen ausgerichtet werden.
In sich geschlossene Datenaufzeichnungen heißen Files. Das entspricht einem Begriff der Buchhaltung, wo sie Notizen eines gewissen Zeitraumes zu einem bestimmten Thema sind. Die Verwendung wird auch hier damit recht gut dargestellt. Der Handlichkeit halber werden größere Sammlungen an Files auf einem Datenträger zusammengefaßt. Zugleich ist mit der Datenmemoryung dann immer auch die Aufzeichnung eines Inhaltsverzeichnisses (directory) erforderlich. Von einer gewissen Anzahl Files an werden schließlich noch weitere Unterverzeichnisse sinnvoll, die "subdirectories".
Dementsprechend unterscheidet man im Betriebssystem des QL Geräte mit und ohne Directory.Es gibt einfache Devices und Directory Devices. Diese werden in zwei verketteten Listen notiert. Die "device handler" in der Liste von SV.DRLIST auf $44(sb) verwalten Geräte ohne Directory, die Geräte mit Directory werden von einem "directory device handler" aus der Liste SV.DDLIST auf $48(sb) betreut. Alle Funktionen der einfachen Device Handler sind auch den Directory Device Handlern zueigen. Letztere dagegegen haben mit der Betreuung der Directories noch umfangreiche zusätzliche Aufgaben zu erledigen.
3.3.2.2 * Physical Layer
Ausführlich kann hier darauf nicht näher eingegangen werden, denn die Hardware wird nur wenig von den Gegebenheiten des Computers bestimmt. Der Aufbau der Physical Layer kann erst erfolgen, wenn diese genau bekannt ist.Hierzu werden später noch einige Hilfsmittel beschrieben, die im Betriebssystem bereitstehen.
Besonders die Interruptverwaltung des QL ist bei der Hardware-Bedienung von großem Nutzen. Zugleich kann damit auch eine besondere Kathegorie programe betreut werden. Darum finden sich die näheren Angaben in einem gesonderten Kapitel und bei den verschiedenen programarten des QL.
Unter dem Begriff des "slaving" schließlich ist von hier aus dem Access Layer ein Hilfsdienst zu leisten, der seine Aufgabenstellung im Grenzbereich der beiden Layer findet. Zwischen memoryung und Verarbeitung werden die Daten in einem buffermemory aufgefangen. Damit können sie kompakt und zu einem Zeitpunkt weitergeleitet werden, zu dem der Transport das System möglichst wenig belastet.
Beim Schließen eines Kanals ist dafür zu sorgen, daß nicht noch irgendwo gebufferte Daten verlorengehen. Das regelt eine Scheduler-Task, die die buffer bereinigt und nach der ordungsmäßigen Abwicklung dies der Physical Layer in Form einer Flag mitteilt. Dann wird der nun freie memoryblock endgültig aufgegeben und die Überwachung beendet.
Für das Öffnen von Kanälen ist eine Kontrolle vorzusehen. Vor allem bei dem Versuch, auf einen bereits offenen Kanal zuzugreifen, müssen zwei Zustände erkannt werden: Falls ein regulär noch arbeitender Kanal eröffnet werden soll, ist der Aufruf mit dem Fehlercode ERR.IU abzuweisen. Befindet sich der Kanal im gerade beschriebenen Endstadium seiner Auflösung, wird wieder eine Scheduler-Task aktiv werden, um erst nach Freigabe der Sicherungsblöcke das Öffnen zu veranlassen.
3.3.2.3 * Acces Layer
Seitens der "access layer" ordnen wir drei Zugriffsarten:Im allgemeinen sind einige Angaben nötig, die die Art der Datenübertragung zur Physical Layer definieren. Für den Weg aus der Access Layer in die programe entsprechend.
- Öffnen eines Kanals mit Einrichtung eines zugehörigen Datenblocks, dem "channel definition block", wo die besonderen Daten eines jeden Kanals liegen, und die von seinem Handler verwaltet werden.
- Schließen eines Kanals, Auflösen der memoryblöcke.
- Datentransport zur und von der Hardwareseite.
Das ist der "statische Arbeitsbereich" der Device Handler. Er enthält organisatorische Angaben. Etwa die Anzahl der offenen Kanäle und deren Adressen oder den Pointer auf eine verkettete Liste davon, wenn ihre Anzahl unbegrenzt sein soll. Der aktuelle Zustand der betreuten Hardware ist dort zu verzeichnen, oder auch gewisse Grundeinstellungen, wie z.B. die Spurenanzahl einer Floppy Disc. Darum wird ein Device Handler bei der eigenen Installation stets auch einen kleinen Bereich im RAM reklamieren. Dort werden Daten eingetragen, die das Verfahren bestimmen. Für jeden einzelnen der im System bereits vordefinierten Handler wird so ein "device handler definition block" in der Umgebung der Systemvariablen gleich nach dem Einschalten des QL angelegt. Er kann ansonsten aber auch an irgendeiner anderen Stelle eingerichtet werden. Es gibt Beschränkungen hierbei nur bezüglich der Sicherheit gegen Überschreiben oder versehentliches Auflösen der Bereiche.
Solche memoryblöcke können mit den Vectoren MM.ALCHP ($C0) im Common Heap eingerichtet, mit MM.RECHP ($C2) wieder freigegeben werden. Beide dürfen nur im Supervisor Mode aufgerufen werden. Besitzer ist der Device Handler, er wiederum ist Teil des Betriebssystems.
Dagegen dürfen die Physical Layer eigene Codeteile nur einfügen oder entfernen, wenn das aus einem Scheduler-Aufruf heraus geschieht. Besonders bei der Freigabe sind unbedingt zuvor die zugehörigen Listen zu korrigieren, falls zugleich damit auch der Handler selbst aufgegeben wird.
Unabhängig voneinander und zur selben Zeit können nun mehrere Kanäle auf ein Gerät offen und tätig sein. Darum muß ein Device Handler unbedingt reentrant aufgebaut sein. Aus diesem Grunde werden den Kanälen beim Öffnen eigene Tabellen zugeordnet, die zugleich auch helfen, das ganze Verfahren übersichtlich zu halten. Dorthin werden die Daten gebracht, die die Besonderheiten einzelner Kanäle aufzeichnen. Das sind z.B. stets die vom System zugeteilte laufende Nummer und die Adresse des Handlers. Dann auch Angaben, wie die gültige Zeichenposition für das nächste PRINT-Kommando, die Farben eines windows, die Position in einem Datenfile, etc.
Die memorybereiche dieser Tabellen werden vom Handler mit Schließen der Kanäle freigemacht.
Ein einfacher Device Handler mit unterstützenden Befehlen, die als Basic-Erweiterungen aufgebaut sind, ist mit dem Namen STAK in den Beispielprogramen angegeben.
Für das Einfügen der Device Handler in das Betriebssystem und ihren Aufbau selbst gibt es die Manager-Traps (1):
MT.LXINT 26 $1A externe Interruptbearbeitung eintragen MT.RXINT 27 $1B diese aus der Liste herausnehmen MT.LPOLL 28 $1C Abfrage-Interrupt (polled) eintragen MT.RPOLL 29 $1D diesen aus der Liste herausnehmen MT.LSCHD 30 $1E Scheduler-program-Aufruf eintragen MT.RSCHD 31 $1F diesen aus der Liste herausnehmen MT.LIOD 32 $20 einfachen Device Handler eintragen MT.RIOD 33 $21 diesen aus der Liste herausnehmen MT.LDD 34 $22 Directory Device Handler eintragen MT.RDD 35 $23 diesen aus der Liste herausnehmen
Mit der Thing erweiterung noch
MT.LTHG 38 $26 Thing in die Liste SV.THGL eintragen MT.RTHG 39 $27 unbenutztes Thing aus der Liste nehmen Weiter die Vectoren:
Für den Aufbau von Handler, Tabellen und Kanälen
MM.ALCHP $00C0 memory im Heap reservieren MM.RECHP $00C2 diesen wieder freigeben IO.NAME $0122 einen Devicenamen analysieren
Für die Handhabung der Daten
IO.QSET $00DC eine Queue einrichten IO.QTEST $00DE Status einer Queue prüfen O.QIN $00E0 ein Byte dorthin bringen O.QOUT $00E2 ein Byte abholen IO.QEOF $00E4 EOF markieren
Für die allgemeine Handhabung der Queues besonders
IO.SERQ $00E8 direkte Queue-Behandlung IO.SERIO $00EA erweiterte Queue-Behandlung 3.3.2.3.1 - Aufbau
Das Verfahren ist wie folgt:Mit Aufruf des Handlers durch eine Trap der Kanalzuweisung (2) oder der I/O-Behandlung (3), die auch in einem Vectoraufruf verborgen sein kann - UT.CON zum Beispiel - befindet sich der Processor im Supervisor Mode. Der Handler ist dementsprechend zu programieren.
Das Qdos stellt in einigen Registern folgende Angaben zur Verfügung:
D0 auf .b freimaskierter Code vom Aufruf der Trap #3
Innerhalb des Handlers sind nur D2 und D3 immer beliebig verwendbar, bei den i/o-Traps kommt D3 beim ersten Versuch mit 0, ansonsten mit -1 an.
D1 liefert ggf. zusätzlichen Übergabedaten
D2 dto., wird vor der Rückkehr restauriert
D3 enthält in einer Schedulerschleife die Anzahl versäumter
50Hz-Interrupts seit dem letzten Aufruf
A0 Adresse des Kanaldefinitionsblocks oder des Namen
A1 Datenübergabe, zumeist Adresse eines bufferbereiches
A2 wie D2
A3 Basisadresse CH.LNEXT-$18 der Handlerdefinition
A6 Basisadresse der Systemvariablen
A7 Supervisor Stackpointer, bis zu 64 Bytes nutzbar
D0 gibt mit unten näher beschriebenen Besonderheiten einen Fehlercode zurück.
ERR.NC (-1):
D1 und A1 sind so einzustellen, die sie sich ohne Datenverlust für einen erneuten Versuch eignen.
Das bedeutet z.B. beim Holen eines String, daß der hereingereichte Wert D1 vor Addition der empfangen Anzahl Zeichen nur dann gelöscht wird. wenn nicht unmittelbar davor dieselbe Trap mit ERR.NC (-1) abgebrochen wurde. Ohne weitere Abfrage läßt sich das ganz einfach durch eine AND-Operation D3 mit D1 erledigen.
programe sind bereitzustellen für
1. CH.AIO Datentransport Trap #3
Die verschiedensten Bedingungen können hier geprüft und eingestellt werden. Es werden die vielfältigen Aufgaben der I/O-Traps bearbeitet. Einzelheiten entnehme man den betreffenden Beschreibungen. Insbesondere werden hier mit Unterstützung durch das IOSS die gelesenen Bytes an das aufrufende program weitergeleitet und daraus übergebene Bytes in den Kanal geschrieben.2. CH.AOPEN Öffnen von Kanälen Trap #2
Darin sind alle Kanaltabellen, buffer und Datenpfade einzurichten. Die zugehörigen Aufzeichnungen über Ort und Größe sowie Art der Ausstattung werden in die entsprechend erweiterten Kanaltabellen eingetragen.3. CH.ACLOS Schließen von Kanälen Trap #2
Erst wird kontrolliert, ob der betreffende Kanal überhaupt vorhanden ist; dann, ob er nicht noch einem vorrangigen Gebrauch unterliegt. Ist dies nicht der Fall, werden die zugehörigen Eintragungen der Qdos-Tabellen markiert und die memoryblöcke des Kanals aufgegeben.Hier die Liste der besonderen Aufrufe, die man im Handler zweckmäßig zu Beginn des Codebereichs einträgt. Der Ort ist nicht vorgeschrieben. Die Tabelle kann völlig getrennt vom zugehörigen Code auch in einem sicheren Bereich des Ram stehen {MINERVA}.
Zunächst optional, also nur erforderlich, wenn wirklich benutzt:
CH.LXINT -24 00 Link auf nächsten Externen Interrupt CH.AXINT -20 04 hier gültiger Aufruf CH.LPOLL -16 08 Link auf nächsten Poll-Int. CH.APOLL -12 12 hier gültiger Aufruf CH.LSCHD -08 16 Link auf nächstes Scheduler-program CH.ASCHD -04 20 hier gültiger Aufruf
Weiter die Pointer, die mit Null besetzt werden müssen, wenn das Betriebssystem keine entsprechende Bearbeitung zulassen soll:
CH.LNEXT 00 24 Pointer auf nächsten Device Handler CH.AIO 04 28 Ptr auf die I/O-Bearbeitung CH.AOPEN 08 32 dto., zum Öffnen eines Kanals CH.ACLOS 12 36 dto., zum Schließen eines Kanals
Die Offsetangaben sind in {1,2} unterschiedlich gezählt. Davon unabhängig ist immer CH.LXINT die Basis, die mit A3 im Trap-Aufruf ankommt, vom System ermittelt aus CH.LNEXT-$18.CH.L... sind Namen, die auf Posten deuten, die das Betriebssystem verwaltet. Deren Orte sind als Adressen den Traps beim Einfügen in die zugehörige Liste mitzugeben.
CH.A... sind die Eintragungen der im Handler aufgerufenen Adressen.Beim Einfügen einer neuen Handlerdefinition ist dessen Link-Adresse die Position CH.LNEXT, welche dem System mit MT.LIOD oder MT.LDD in A0 zu übergeben. ist
3.3.2.3.2 - Fehlermeldungen
Die Rückkehr aus einem Trap-Aufruf erfolgt grundsätzlich stets mit einem Fehlercode in D0. Als Fehler gilt jede Zahl ungleich Null.
Vom System auswertbar ist nur die negative Standardcodierung. Positive Zahlen sollten mit Vorsicht und nur in genau dokumentierten Sonderfällen zurückgegeben werden. Deren Auswertung kann in Unkenntnis dieser Möglichkeit leicht zu Mißverständnissen führen, etwa weil dann durch das Basic-OPEN kein Fehler gemeldet wird (z.B. SER-Device im UQLX 5/98).Das System oder direkt ein Aufruf veranlaßt mittels UT.ERRØ die Ausgabe eines Textes auf den Bildschirm. Neben den vom Basic her bekannten Meldungen mit den Zahlen bis -22, MGG bis -27, sind Möglichkeiten der freien Definition vorgesehen.
Zunächst einmal lassen sich für die genannten Codes neue Texte in Form einer Tabelle definieren. Das Verfahren dazu ist ausführlich im Abschnitt 3.8.2 beschrieben.
Ursprünglich vielleicht vorgesehen, jedoch nicht erkennbar umgesetzt, wurde die in {1,2} beschriebene Form freier Systemmeldungen, welche hier nur zitiert ist, um den aus ihrer Verwendung resultierenden Fehlern vorzubeugen:
Eine positive Zahl soll das System als Offset zu $8000 bewerten und an der resultierenden Adresse einen String für die Ausgabe als Fehlermeldung erwarten.
Überprüfung mit MGG und GC ergab, daß zumindest dort diese Auswertung NICHT stattfindet, solche Texte in Gegenteil sogar zu üblen Fehlern führen können.Folgende außerdem noch angegebene Konvention ist zuverlässig anwendbar:
Fehlernummern mit ungesetztem Bit 30 bewertet das System direkt als Adresse eines als Meldung auszugebenden String.Die Sequenz
lea textadresse(pc),a1 move.l a1,d0 bset #31,d0
kann an beliebiger Stelle im memory stehen, und liefert die richtige Codierung. Der Text muß mit führendem Längenwort auf gerader Adresse beginnen.
3.3.2.3.3 - programierung
Zu 1. CH.AIO Trap #3Dort wird die eigentliche Arbeit erledigt. Der Anforderung aus D0 ist nun in entsprechender Weise nachzukommen. Zunächst vielleicht:
D0=9 führt etwa mit JMP(A2) in den SD.EXTOP-Aufruf,Was übrigbleibt, könnte etwa dem Vector IO.SERIO übergeben werden, wo I/O-Trap-Aufrufe (3 / 0, 1, 2, 3, 5, 7, 70, 71, 72, 73) behandelt werden. In diesem Falle müssen wir eine Tabelle bereitstellen, die dem Aufruf des Vectors als Subroutine unmittelbar folgt. Das erspart die Übergabe der Adresse, da sie mit dem Stackpointer schon bekannt ist.
D0=66 setzt eine Position entsprechend FS.POSAB.
D0=67 FS.POSRE, Position relativ zum aktuellen Wert.move.w 234,a2 Vector IO.SERIODafür müssen noch die zugehörigen programteile für den Test auf Vorhandensein sowie Abholen und Senden einzelner Bytes bereitgestellt werden.
jsr (a2) > io_test
* absolute(!) adressen *
dc.l kanal.prüfen
dc.l byte.holen
dc.l byte.senden
rts
Die Übergabe der Basis des Kanal-Definitionsblocks im Register A0 ist besonders hier von großem Nutzen. Mit Hilfe der in die Trap hineingereichten Register lassen sich im allgemeinen alle nötigen Informationen ermitteln und die betreffenden Aufgaben leicht durchführen.D3 hat beim ersten Aufruf den Wert Null. Wenn die geforderte Operation nicht erfolgreich beendet werden konnte und solange eine womöglich angegebene Wartezeit noch nicht abgelaufen ist, kommt danach jedesmal -1 herein.
Nach der Arbeit gibt man ggf. A1 (Ort) und D1 (Länge) von Strings und zugehörigen buffern weitergezählt zurück.
Dies ist Voraussetzung dafür, daß z.B. bei langsamen Peripheriegeräten alle Daten successive in den buffer geholt werden können. Denn um das Multitasking nicht durch ständiges Abschalten bei längerwährenden i/o-Operationen ad absurdum zu führen, stellt das Betriebssystem die Wartezeit durch Simulation einer programschleife auf dem betr. Trap-Code dar. Haben dann A1 und D1 nicht die korrekten Werte, wird es zu Fehlern kommen.Konnte die Operation nicht abgeschlossen werden, stehen die beim Abbruch aktuellen Angaben in diesen Registern. So kann bei Bedarf ein erneuter Aufruf die Aktion beenden. Durch Rückgabe von D0=-1 kann auch im Handler selbst dafür gesorgt werden, daß die Trap solange wiederholt wird, bis entweder die Wartezeit abgelaufen ist, oder die Operation erfolgreich war, ohne daß das in einer Anwendung gesondert programiert werden muß. Das Qdos selbst stellt in seinen übergeordneten programteilen der Systemverwaltung den PC dann bei Bedarf auf den Trap-Code zurück.
Wenn irgendwo eine Zwischenmemoryung organisiert wurde, ist nötigenfalls gesondert dafür zu sorgen, daß die Operation auch im Phsical Layer richtig abgeschlossen wird. Vorgesehen ist die Trap FS.MDINF (3/69) für die Angabe, ob der Datentransport beendet wurde, oder die Traps FS.CHECK (3/64, insbes. zur Überprüfung bei MDV-Aktionen) und FS.FLUSH (3/65), welche mit dem TK2 noch zusätzliche Operationen zum sicheren Abschluß auch offener Files auslöst.
Die Definition selbst muß für Fehlersituationen die passende Bearbeitung bereitstellen und unbedingt auch den Regeln folgend die entsprechende Fehlernummer zurückgeben. Bei fehlerfreiem Ablauf geht Null in D0 zurück, in den restlichen ungültigen Fällen der Fehlercode ERR.BP (-15).
Zu 2. CH.AOPEN Trap #2
CH.AOPEN hält die Adresse des Teilprogrames zum Öffnen von Kanälen.
Namen von zu öffnenden Kanälen haben einer genau einzuhaltenden Konvention zu folgen, ebenso die Definition des Erlaubten im Device Handler. Ihr Aufbau zusammen mit den Möglichkeiten zur Parameterangabe ist allerdings längst nicht so schwer durchschaubar gestaltet, wie es zuerst den Anschein haben mag und in der Literatur gelegentlich dargestellt wird. Ganz im Gegenteil sind sie trotz ihrer Vielseitigkeit eher plausibel zusammengesetzt.
Mit dem Aufruf stehen ergänzend zu eingangs Erwähntem in
D3 ein Schlüsselcode für die Art, wie der Kanal zu öffen ist.Folgende Aufgaben müssen erfolgreich bendet worden sein, bevor ein Kanal vom Qdos anerkannt wird:
A0 der Pointer auf den Namen
A3 die Basis des Device Handlers.
D0 - D7, A1 - A6 sind frei verwendbar.Der übergebene Name wurde fehlerlos decodiert.Vom IOSS her sind alle Kanäle in beiden Richtungen gangbar. Unerwünschte Operationen müssen ggf. in der Handlerdefinition selbst abgefangen und mit einem Fehlercode quittiert werden.
Es ist memory für Kanal-Definitionsblock und ggf. weitere buffer reserviert worden.
Außer den vom System belegten ersten sechs Langworten wurde der Definitionsblock gültig besetzt.
Die Adresse des Blocks wurde in A0 zurückgegeben.Eine sehr wirksame Hilfsfunktionen stellt der Qdos-Vector IO.NAME bereit:
Neue Kanäle werden durch Angabe einer namentlichen Bezeichnung definiert. Der Vector IO.NAME hilft bei "einfachen" Devices, diese zu decodieren; bei Directory-Devices erledigt dies das IOSS für den Gerätenamen, und nur der Filename selbst, samt "Pfad", ist im Handler zu bearbeiten.
Eingangs ist soviel Platz an Zwischenmemory zu reservieren, wie maximal für die Übergabeparameter erforderlich werden kann. Dessen Basis wird in A3 notiert. Da es nicht allzuviele Daten sind, die so gememoryt werden, bietet sich als leicht zu verwaltender Datenbuffer der Stack an.
Der Vectoraufruf analysiert nun den Namen gemäß dessen Definition im Handler. Die entsprechend ausgewerteten Parameter legt er in Reihenfolge der Definitionsliste im buffermemory ab. A3 dient als Ptr dorthinein, die Zahlen haben Wort-Länge. Je nach Ablauf dieser Analyse erfolgt die Rückkehr an eine von drei Adressen in Wort-Abstand nach dem Vectoraufruf:
Nach dem Block dieser drei Wortadressen steht unmittelbar die Namensdefinition nach folgendem Muster:
- Die erste Position gilt, wenn der Name falsch war,
- die zweite bei irgendeinem fehlerhaften Parameter,
- die dritte, wenn alles in Ordnung ist. Hieraus kann sofort mit RTS abgebrochen werden, oder es folgt ein kurz adressierter Sprung in die weitere Bearbeitung.
count.w+nameAm Anfang der Devicename in der üblichen Form mit zwei Längenbytes und den Zeichen auf gerader Adresse:
anzahl.w definierter parameter
parameterDC.B 0,2,'SCR',0Dann ist die Anzahl möglicher Parameter angegeben:DC.W 4In einer von drei Formen folgen nun die Parameter:1. Leerzeichen, (Trenn-)Zeichen, Vorgabezahl
DC.W ' _',448wie das etwa für das SCR-Device gelten kann.
DC.W ' X',180
DC.W ' A',32
DC.W ' X',16 ...2. eine negative Zahl, eine Vorgabezahl
DC.W -1,1283. ein Zähler, ebensoviele CodezeichenDC.W 3Alle Parameter beginnen auf gerader Adresse. Buchstaben müssen groß geschrieben werden. Zahlen sind vorzeichenbehaftete 16-Bit-Zahlen. Einschränkungen gibt es sonst nicht.
DC.B 'POI',0Der Vectoraufruf liefert nun den übergebenen Wert oder den der Vorgabe. Bei Codezeichen kommt deren Position in ihrer besonderen Liste zurück. Ist keines angegeben, wird das mit Null signalisiert. Bei dieser Einteilung können Parameter auch teilweise fortgelassen werden, egal, an welcher Stelle sie stehen. Bis hier kann der Code dann etwa so aussehen:
- chopen subq.l #8,sp Zwischenmemory
- move.l sp,a3 angeben
- move.w 290,a2 IO.NAME, A0 zeigt
- jsr (a2) auf den Namen
- rts bei falschem Namen
- rts bei Parameterfehler
- bra.s aufmachen alles richtig
- namtab dc.w 4,'STAK' der Name
- dc.w 4 vier Parameter
- dc.w -1,1 etwa laufende Nummer, Vorgabe 1
- dc.w ' _',32766 ein Datenbuffer Vorgabewert 32766
- dc.w 3 drei Codezeichen
- dc.b 'FIS',0 Typ float, integer, string
- dc.w 1 ein Codezeichen
- dc.b 'P',0 für permanenten buffer
Die Fehlerbehandlung darf nur die vorgesehene Fehlercodierung zurückgeben, weil sonst die Routinen des Systems in die Irre geführt werden und Fehler produzieren, die nicht mehr abgefangen werden können. Das gilt verschärft, wenn die TK2-Devicevorgabe aktiv ist, da diese die Vorgabenamen auf Basis der Fehlercodes verwaltet.Wie zu sehen war, können dabei verschiedene Kathegorien auftreten. Über diese Angaben muß irgendwo Buch geführt werden.
Vom Handler selbst sind auf jeden Fall memorybereiche für die Kanal-Definitionsblöcke einzurichten.
Mittels des Vectors MM.ALCHP wird Platz für mindestens 24 Bytes einer Tabelle fixiert. Diesen Bereich belegt und verwaltet das IOSS. Eine Begrenzung ist nicht vorgesehen, sodaß für weitere Angaben die Reservierung entsprechend vergrößert werden kann. Alle Informationen, die das Erscheinungsbild eines Kanals bestimmen, haben hier ihren Platz.
Standardmäßig belegt das IOSS:
CH.LEN 00Länge des Definitionsblockes CH.DRIVR 04Adresse des Handlers CH.OWNER 08ID des Besitzer-Jobs CH.RFLAG $0Cbei Bereichsfreigabe zu markierende Adresse eines Byte CH.TAG $10Laufend Nummer des Kanals CH.STAT $12A1 gilt mit -1 absolut, mit $80 rel A6, 0 wenn die Bearbeitung erledigt ist, sonst negativ bei Wartezustand CH.ACTN $13Verrichtung des wartenden Jobs (Trap#3 Op-Code) CH.JOBWT $14ID des Jobs, der auf I/O-Bedienung wartet
Hier können nun frei definierte Daten folgen.Zu 3. CH.ACLOS Trap #2
Vor dem Schließen eines Kanals ist zu prüfen, ob er noch irgendwo in Gebrauch ist. In solchem Fall geht der Fehlercode -9 für ERR.IU zurück. Sonst muß man ggf. noch darauf achten, daß alle Operationen auf Seiten des Physical Layer auch wirklich schon durchgeführt sind.
Mit Schließen des Kanals werden auch die ihm zugeeigneten memorybereiche freigegeben. Dabei könnten Daten verloren gehen. Diese Kontrolle kann aber z.B. auch der besonderen Anforderung, etwa durch FS.FLUSH (3/65), überlassen bleiben. Besonders dieser Aufruf erledigt alles Nötige selbst. Mit TK2 werden die Daten im Directoryfile des zugehörigen Datenträgers zusätzlich aktualisiert, sodaß es dann sogar durch Bedienungsfehler kaum noch Schäden geben kann.
Nun sind alle Tabellen im zugehörigen Device Handler zu bereinigen, damit nicht irgendein Irrläufer den inzwischen ungültigen Datenbereich benutzen kann.
Außer D0 und A7 sind alle Register frei verwendbar.
Der Vector MM.RECHP auf $0C2 (192) löst den reservierten memorybereich wieder auf. Dessen Basisadresse ist in A0 zu übergeben. Das Register kommt dafür durch diesen Aufruf der Trap #2 schon richtig besetzt an.
Als letzte Aktion kann die Freigabe erfolgen. Z.B. in Gestalt dieses Zweizeilers
- move.w 194,a2
- jmp (a2)
Eine Fehlermeldung aus dem Vector gibt es nicht. Da auch die CLOSE-Trap keine zurückzugeben braucht, ist hier das Ende erreicht. Wie schon beim Öffnen nimmt auch hier Qdos die Anpassung der Systemtabellen vor, ohne daß das extra programiert werden müßte.