home *** CD-ROM | disk | FTP | other *** search
- Program DrvFrame; { Rahmen für einen Zeichentreiber }
- {$M $1000,0,0}
- uses Dos, Crt, { *** CRT für Ausgabe von Fehlermeldungen! *** }
- DosUtils, DrvLib;
-
-
- { ------------- Der Treiber selbst ----------------------- }
- Type
- DrvBlock = Record { Kopf des Parameterblocks }
- DSize: Byte; { Größe des gesamten Blocks }
- DUnit: Byte; { Geräte-Kennziffer (relativ) }
- DFunc: Byte; { Funktionsnummer ($00) }
- DStatus: Word; { Status als Ergebnis }
- DResvd: Array[0..7] of Byte;
- end;
-
- var ParmBlock: ^DrvBlock; { Adresse des Parameterblocks,
- via "Strategie" gesetzt }
- Type
- DrvInitBlock = Record { Parameterblock für "Init" }
- DSize: Byte; { Größe des gesamten Blocks }
- DUnit: Byte; { Geräte-Kennziffer (relativ) }
- DFunc: Byte; { Funktionsnummer ($00) }
- DStatus: Word; { Status als Ergebnis }
- DResvd: Array[0..7] of Byte;
- { --- Funktionsabhängige Felder --- }
- DUnits: Byte; { Anzahl Laufwerke (nur für Block) }
- DEndAddr: Pointer; { Endadresse, vom Treiber gesetzt }
- DCmdLine: Pointer; { Adresse der "Kommandozeile" }
- DFirstDrv: Byte; { Kennziffer erstes Laufwerk (nur Block) }
- DMsgFlag: Word; { für Fehlermeldungen des Treibers }
- end;
- DrvInitPtr = ^DrvInitBlock;
-
- Procedure DriverInit; { Treiberfunktion $00 }
- const DriverSize = $400; { Annahme: Treiber braucht $400 Bytes Platz }
- var Cmd: ^Char;
- p: DrvInitPtr;
- begin
- Write('Funktion $00 (Init) - Parameter: ');
- p := DrvInitPtr(ParmBlock);
- Cmd := p^.DCmdLine;
- while Cmd^ <> #13 do
- begin
- Write(Cmd^); Inc(LongInt(Cmd));
- end;
- Writeln;
- { Annahme: DriverInit ist die erste Routine des Treibers }
- p^.DEndAddr := Ptr(Seg(DriverInit), Ofs(DriverInit)+DriverSize+1);
- p^.DStatus := 0; { Error-Bit zurück }
- end;
-
- Type
- DrvWriteBlock = Record { Parameterblock für "Write" }
- DSize: Byte; { Größe des gesamten Blocks }
- DUnit: Byte; { Geräte-Kennziffer (relativ) }
- DFunc: Byte; { Funktionsnummer ($08) }
- DStatus: Word; { Status als Ergebnis }
- DResvd: Array[0..7] of Byte;
- { --- Funktionsabhängige Felder --- }
- DMediaID: Byte; { Media-ID (nur Block) }
- DBuffer: Pointer; { Quelladresse im Hauptspeicher }
- DBytesOrSec: Word; { Anzahl Datenbytes/Sektoren }
- DStartSec: Word; { erster Sektor (nur Block) }
- DVolID: Pointer; { wird vom Treiber gesetzt (nur Block) }
- DStartLong: LongInt; { Startsektor mit 32 Bit (nur Block) }
- end;
- DrvWritePtr = ^DrvWriteBlock;
- Procedure DriverWrite; { Treiberfunktion $08 }
- var x,Count: Word;
- p: ^Char;
- begin
- with DrvWritePtr(ParmBlock)^ do
- begin
- Count := DBytesOrSec;
- p:= DBuffer;
- for x := 1 to Count do
- begin
- Write(p^); { !!! Crt.Write !!! }
- Inc(LongInt(p)); { nächstes Zeichen }
- end;
- DBytesOrSec := Count; { Anzahl geschriebener Bytes }
- DStatus := 0; { "Error" und "Busy"-Bit löschen }
- end;
- end;
-
- {$F+} Procedure DoStrategy; {$F-} { Strategie-Routine }
- begin
- inline($50/$53/ { push ax/bx - diese beiden Register werden }
- { von der Routine SwapValInCS gebraucht! }
- $53/$06 { push bx/es - Parameterblock-Adresse }
- );
- if SwapValInCS(DSeg) <> 0 then; { SWAP von DS mit Turbo-DS }
- inline($8E/$D8); { asm mov ds,ax }
- inline($8F/$06/ParmBlock+2/ { pop Word Ptr[ParmBlock+2] ; ES }
- $8F/$06/ParmBlock { pop Word Ptr[ParmBlock] ; BX }
- );
- if SwapValInCS(DSeg) <> 0 then ; { TURBO-DS speichern, DS }
- inline($8E/$D8); { asm mov ds,ax } { wieder setzen }
- inline($5B/$58); { pop bx/ax - Register zurück }
- end;
-
- {$F+} Procedure DoInterrupt; {$F-} { Interrupt-Routine }
- { <- keine lokalen Variablen!! }
- begin
- inline($50/$53/$51/ { push ax/bx/cx/dx/si/di/es - ließe }
- $52/$56/$57/$06 { sich eleganter mit PUSHA machen }
- );
- if SwapValInCS(DSeg) <> 0 then ; { SWAP DS/Turbo-DS }
- inline($8E/$D8); { asm mov ds,ax }
-
- case ParmBlock^.DFunc of
- 0 : DriverInit;
- 8 : DriverWrite;
- else Writeln('Unbekannte Treiberfunktion: ',ParmBlock^.DFunc);
- ParmBlock^.DStatus := $8003; { "Error"-Bit setzen, Fehlercode }
- end; { case }
- ParmBlock^.DStatus := ParmBlock^.DStatus or $100; { "Done"-Bit setzen }
- if SwapValInCS(DSeg) <> 0 then ; { DS-Register wieder tauschen }
- inline($8E/$D8/ { asm mov ds,ax }
- $07/$5F/$5E/$5A/ { pop es/di/si/dx/cx/bx/ax, d.h. POPA }
- $59/$5B/$58
- );
- end;
-
- { -------------------------------------------------------- }
- { Reserviert einige Bytes im Codesegment und liefert
- die Adresse dieses Bereichs zurück }
- Function ReserveCS: Pointer;
- var Offset: Integer;
- StrPtr : ^String;
- begin
- Offset := -1;
- repeat
- Inc(Offset);
- StrPtr := Ptr(CSeg,Offset);
- until (Pos('ReserveCS: Fehler!',StrPtr^) = 1) or (Offset > 32766);
- if Offset > 32766 then
- begin
- Writeln('ReserveCS: Fehler!');
- Halt;
- end;
- ReserveCS := Pointer(StrPtr);
- end;
-
- { Baut den durch CHARACS spezifizierten Treiber in die Kette ein }
- Procedure LinkDriver(Characs: DriverPointer; InitParams: DrvInitPtr);
- var NULDev, NULNext: DriverPointer;
- begin
- NULDev := GetFirstHeader; { Gerätetreiber NUL ermitteln }
- NULNext := NULDev^.DNext; { Zeiger auf den Nachfolger }
- NULDev^.DNext := Characs; { NUL -> NULNext wird zu }
- Characs^.DNext := NULNext; { NUL -> Characs -> NULNext }
- { Direkter Aufruf der Strategie- und Interrupt-Routine
- mit dem Initialisierungsblock }
- CallStrategy(Characs, InitParams);
- CallInterrupt(Characs);
- end;
-
- { Baut den Treiber wieder aus der Kette aus }
- Procedure UnlinkDriver(Characs: DriverPointer);
- var NULDev: DriverPointer;
- begin
- NULDev := GetFirstHeader; { Gerätetreiber NUL ermitteln }
- NULDev^.DNext := Characs^.DNext; { NUL -> Characs -> Next }
- end; { wird zu NUL -> Next }
-
- Function BuildCharDriver(Attrib: Word; DrvName: String): DriverPointer;
- var DrvHead: DriverPointer;
- x: Integer;
- begin
- if SwapValInCS(DSeg) <> 0 then; { Turbo-Datensegment speichern }
- DrvHead := ReserveCS; { Platz im Datensegment }
- with DrvHead^ do
- begin
- DAttr := $8000; { Attribute des Treibers }
- DStrat := Ofs(DoStrategy);
- DIntr := Ofs(DoInterrupt);
- for x := 1 to 8 do Name[x] := ' ';
- for x := 1 to Length(DrvName) do Name[x] := Upcase(DrvName[x]);
- DNext := Ptr($FFFF,$FFFF);
- end;
- BuildCharDriver := DrvHead;
- end;
-
- const
- DrvAttrib: Word = $8000; { zu setzendes Attribut }
- DrvName = 'DEMO'; { zu setzender Name }
- CmdLine : String { "Kommandozeile" aus CONFIG.SYS }
- = 'Parameter_1 Parameter_2'#13#10;
- var
- OurDriver: DriverPointer;
- InitParams: DrvInitBlock; { Parameter zur Initialisierung }
- { - - - - - - - - - - - - }
- F: Text; { nur zur Demonstration }
- IORes: Integer;
-
- begin
- OurDriver := BuildCharDriver(DrvAttrib,DrvName);
- FillChar(InitParams,Sizeof(InitParams),0);
- with InitParams do
- begin
- DSize := SizeOf(DrvInitBlock);
- DFunc := $00;
- DCmdLine := Addr(CmdLine[1]); { hinter dem Längenbyte }
- DEndAddr := Ptr($A000,0);
- end;
- LinkDriver(OurDriver,@InitParams);
-
- { - - - - - - - - - - - - - - - - - - - - - }
- Writeln('Treiber ', DrvName, ' eingebaut und initialisiert.');
- Writeln('Treiberkopf: $',HexP(OurDriver),
- ', Init-Routine $',HexP(Addr(DriverInit)),
- ', Endadresse: $',HexP(InitParams.DEndAddr));
- Writeln('Zurückgelieferter Status: $',HexW(InitParams.DStatus));
-
- Write('Öffnen von ', DrvName,' als Datei für Schreibaktionen: ');
- Assign(F,DrvName); {$I-} Rewrite(F); {$I+}
- IORes := IOResult;
- if IORes <> 0 then Writeln('DOS-Fehlercode ',IORes)
- else
- begin
- Writeln('OK!');
- {$I-} Writeln(F,'Ein via Write über das ',
- 'Dateisystem ausgegebener Text.');
- {$I+}
- IORes := IOResult;
- if IORes <> 0 then Writeln('DOS-Fehlercode ',IORes)
- else Close(F);
- end;
- { - - - - - - - - - - - - - - - - - - - - - - - }
- UnlinkDriver(OurDriver);
- Writeln('Treiber ',DrvName,' wieder ausgebaut.');
- end.
-
-