home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turbo Toolbox
/
Turbo_Toolbox.iso
/
dtx9203
/
driver
/
drvframe.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-04-05
|
8KB
|
236 lines
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.