back : next  content =
 

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".

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:
  1. Ö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.
  2. Schließen eines Kanals, Auflösen der memoryblöcke.
  3. Datentransport zur und von der Hardwareseite.
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.

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:

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.

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 #3

Dort 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,
D0=66 setzt eine Position entsprechend FS.POSAB.
D0=67 FS.POSRE, Position relativ zum aktuellen Wert.
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.
move.w 234,a2    Vector IO.SERIO
jsr (a2)         > io_test
* absolute(!) adressen *
dc.l kanal.prüfen
dc.l byte.holen
dc.l byte.senden
rts
Dafür müssen noch die zugehörigen programteile für den Test auf Vorhandensein sowie Abholen und Senden einzelner Bytes bereitgestellt werden.
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.
A0 der Pointer auf den Namen
A3 die Basis des Device Handlers.
D0 - D7, A1 - A6 sind frei verwendbar.
Folgende Aufgaben müssen erfolgreich bendet worden sein, bevor ein Kanal vom Qdos anerkannt wird:
Der übergebene Name wurde fehlerlos decodiert.
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.
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.

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:
count.w+name
anzahl.w definierter parameter
parameter
Am Anfang der Devicename in der üblichen Form mit zwei Längenbytes und den Zeichen auf gerader Adresse:
DC.B 0,2,'SCR',0
Dann ist die Anzahl möglicher Parameter angegeben:
DC.W 4
In einer von drei Formen folgen nun die Parameter:

1. Leerzeichen, (Trenn-)Zeichen, Vorgabezahl

DC.W ' _',448
DC.W ' X',180
DC.W ' A',32
DC.W ' X',16 ...
wie das etwa für das SCR-Device gelten kann.

2. eine negative Zahl, eine Vorgabezahl

DC.W -1,128
3. ein Zähler, ebensoviele Codezeichen
DC.W 3
DC.B 'POI',0
Alle Parameter beginnen auf gerader Adresse. Buchstaben müssen groß geschrieben werden. Zahlen sind vorzeichenbehaftete 16-Bit-Zahlen. Einschränkungen gibt es sonst nicht.

Der 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

 
Erst jetzt ist die memoryverwendung wieder frei.
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
 00 
Länge des Definitionsblockes
CH.DRIVR
 04 
Adresse des Handlers
CH.OWNER
 08 
ID des Besitzer-Jobs 
CH.RFLAG
$0C 
bei Bereichsfreigabe zu markierende Adresse eines Byte
CH.TAG
$10 
Laufend Nummer des Kanals
CH.STAT
$12 
A1 gilt mit -1 absolut, mit $80 rel A6, 0 wenn die Bearbeitung erledigt ist, sonst negativ bei Wartezustand
CH.ACTN
$13 
Verrichtung des wartenden Jobs (Trap#3 Op-Code)
CH.JOBWT
$14 
ID 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.
 
 


top : back : next  content 

= (count)