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

  1. Program DrvFrame;  { Rahmen für einen Zeichentreiber }
  2. {$M $1000,0,0}
  3. uses Dos, Crt,     { *** CRT für Ausgabe von Fehlermeldungen! *** }
  4.      DosUtils, DrvLib;
  5.  
  6.  
  7. { ------------- Der Treiber selbst ----------------------- }
  8. Type
  9.   DrvBlock = Record  { Kopf des Parameterblocks }
  10.     DSize:      Byte;    { Größe des gesamten Blocks }
  11.     DUnit:      Byte;    { Geräte-Kennziffer (relativ) }
  12.     DFunc:      Byte;    { Funktionsnummer ($00) }
  13.     DStatus:    Word;    { Status als Ergebnis }
  14.     DResvd:     Array[0..7] of Byte;
  15.   end;
  16.  
  17. var ParmBlock: ^DrvBlock;  { Adresse des Parameterblocks,
  18.                              via "Strategie" gesetzt }
  19. Type
  20.   DrvInitBlock = Record  { Parameterblock für "Init" }
  21.     DSize:      Byte;    { Größe des gesamten Blocks }
  22.     DUnit:      Byte;    { Geräte-Kennziffer (relativ) }
  23.     DFunc:      Byte;    { Funktionsnummer ($00) }
  24.     DStatus:    Word;    { Status als Ergebnis }
  25.     DResvd:     Array[0..7] of Byte;
  26.     { --- Funktionsabhängige Felder --- }
  27.     DUnits:     Byte;    { Anzahl Laufwerke (nur für Block) }
  28.     DEndAddr:   Pointer; { Endadresse, vom Treiber gesetzt }
  29.     DCmdLine:   Pointer; { Adresse der "Kommandozeile" }
  30.     DFirstDrv:  Byte;    { Kennziffer erstes Laufwerk (nur Block) }
  31.     DMsgFlag:   Word;    { für Fehlermeldungen des Treibers }
  32.   end;
  33.   DrvInitPtr = ^DrvInitBlock;
  34.  
  35. Procedure DriverInit;  { Treiberfunktion $00 }
  36. const DriverSize = $400; { Annahme: Treiber braucht $400 Bytes Platz }
  37. var Cmd: ^Char;
  38.     p: DrvInitPtr;
  39. begin
  40.   Write('Funktion $00 (Init) - Parameter: ');
  41.   p := DrvInitPtr(ParmBlock);
  42.   Cmd := p^.DCmdLine;
  43.   while Cmd^ <> #13 do
  44.   begin
  45.     Write(Cmd^); Inc(LongInt(Cmd));
  46.   end;
  47.   Writeln;
  48.   { Annahme: DriverInit ist die erste Routine des Treibers }
  49.   p^.DEndAddr := Ptr(Seg(DriverInit), Ofs(DriverInit)+DriverSize+1);
  50.   p^.DStatus := 0;  { Error-Bit zurück }
  51. end;
  52.  
  53. Type
  54.   DrvWriteBlock = Record  { Parameterblock für "Write" }
  55.     DSize:      Byte;    { Größe des gesamten Blocks }
  56.     DUnit:      Byte;    { Geräte-Kennziffer (relativ) }
  57.     DFunc:      Byte;    { Funktionsnummer ($08) }
  58.     DStatus:    Word;    { Status als Ergebnis }
  59.     DResvd:     Array[0..7] of Byte;
  60.     { --- Funktionsabhängige Felder --- }
  61.     DMediaID:   Byte;    { Media-ID (nur Block) }
  62.     DBuffer:    Pointer; { Quelladresse im Hauptspeicher }
  63.     DBytesOrSec: Word;   { Anzahl Datenbytes/Sektoren }
  64.     DStartSec:  Word;    { erster Sektor (nur Block) }
  65.     DVolID:     Pointer; { wird vom Treiber gesetzt (nur Block) }
  66.     DStartLong: LongInt; { Startsektor mit 32 Bit (nur Block) }
  67.   end;
  68.   DrvWritePtr = ^DrvWriteBlock;
  69. Procedure DriverWrite;  { Treiberfunktion $08 }
  70. var x,Count: Word;
  71.     p: ^Char;
  72. begin
  73.   with DrvWritePtr(ParmBlock)^ do
  74.   begin
  75.     Count := DBytesOrSec;
  76.     p:= DBuffer;
  77.     for x := 1 to Count do
  78.     begin
  79.       Write(p^);        { !!! Crt.Write !!! }
  80.       Inc(LongInt(p));  { nächstes Zeichen }
  81.     end;
  82.     DBytesOrSec := Count;  { Anzahl geschriebener Bytes }
  83.     DStatus := 0;  { "Error" und "Busy"-Bit löschen }
  84.   end;
  85. end;
  86.  
  87. {$F+} Procedure DoStrategy; {$F-}  { Strategie-Routine }
  88. begin
  89.   inline($50/$53/    { push ax/bx - diese beiden Register werden }
  90.                      { von der Routine SwapValInCS gebraucht! }
  91.          $53/$06     { push bx/es - Parameterblock-Adresse }
  92.         );
  93.   if SwapValInCS(DSeg) <> 0 then;  { SWAP von DS mit Turbo-DS }
  94.   inline($8E/$D8);  { asm mov ds,ax }
  95.   inline($8F/$06/ParmBlock+2/   { pop Word Ptr[ParmBlock+2] ; ES }
  96.          $8F/$06/ParmBlock      { pop Word Ptr[ParmBlock]   ; BX }
  97.         );
  98.   if SwapValInCS(DSeg) <> 0 then ;  { TURBO-DS speichern, DS }
  99.   inline($8E/$D8);  { asm mov ds,ax }        { wieder setzen }
  100.   inline($5B/$58);  { pop bx/ax - Register zurück }
  101. end;
  102.  
  103. {$F+} Procedure DoInterrupt; {$F-} { Interrupt-Routine }
  104.     { <- keine lokalen Variablen!! }
  105. begin
  106.   inline($50/$53/$51/       { push ax/bx/cx/dx/si/di/es - ließe }
  107.          $52/$56/$57/$06    { sich eleganter mit PUSHA machen }
  108.         );
  109.   if SwapValInCS(DSeg) <> 0 then ;  { SWAP DS/Turbo-DS }
  110.   inline($8E/$D8);  { asm mov ds,ax }
  111.  
  112.   case ParmBlock^.DFunc of
  113.     0 : DriverInit;
  114.     8 : DriverWrite;
  115.    else Writeln('Unbekannte Treiberfunktion: ',ParmBlock^.DFunc);
  116.         ParmBlock^.DStatus := $8003;  { "Error"-Bit setzen, Fehlercode }
  117.   end;  { case }
  118.   ParmBlock^.DStatus := ParmBlock^.DStatus or $100;  { "Done"-Bit setzen }
  119.   if SwapValInCS(DSeg) <> 0 then ;  { DS-Register wieder tauschen }
  120.   inline($8E/$D8/           { asm mov ds,ax }
  121.          $07/$5F/$5E/$5A/   { pop es/di/si/dx/cx/bx/ax, d.h. POPA }
  122.          $59/$5B/$58
  123.         );
  124. end;
  125.  
  126. { -------------------------------------------------------- }
  127. { Reserviert einige Bytes im Codesegment und liefert
  128.   die Adresse dieses Bereichs zurück }
  129. Function ReserveCS: Pointer;
  130. var Offset: Integer;
  131.     StrPtr : ^String;
  132. begin
  133.   Offset := -1;
  134.   repeat
  135.     Inc(Offset);
  136.     StrPtr := Ptr(CSeg,Offset);
  137.   until (Pos('ReserveCS: Fehler!',StrPtr^) = 1) or (Offset > 32766);
  138.   if Offset > 32766 then
  139.   begin
  140.     Writeln('ReserveCS: Fehler!');
  141.     Halt;
  142.   end;
  143.   ReserveCS := Pointer(StrPtr);
  144. end;
  145.  
  146. { Baut den durch CHARACS spezifizierten Treiber in die Kette ein }
  147. Procedure LinkDriver(Characs: DriverPointer; InitParams: DrvInitPtr);
  148. var NULDev, NULNext: DriverPointer;
  149. begin
  150.   NULDev := GetFirstHeader;  { Gerätetreiber NUL ermitteln }
  151.   NULNext := NULDev^.DNext;  { Zeiger auf den Nachfolger }
  152.   NULDev^.DNext := Characs;  { NUL -> NULNext wird zu }
  153.   Characs^.DNext := NULNext; { NUL -> Characs -> NULNext }
  154.   { Direkter Aufruf der Strategie- und Interrupt-Routine
  155.     mit dem Initialisierungsblock }
  156.   CallStrategy(Characs, InitParams);
  157.   CallInterrupt(Characs);
  158. end;
  159.  
  160. { Baut den Treiber wieder aus der Kette aus }
  161. Procedure UnlinkDriver(Characs: DriverPointer);
  162. var NULDev: DriverPointer;
  163. begin
  164.   NULDev := GetFirstHeader;  { Gerätetreiber NUL ermitteln }
  165.   NULDev^.DNext := Characs^.DNext;  { NUL -> Characs -> Next }
  166. end;                         { wird zu NUL -> Next }
  167.  
  168. Function BuildCharDriver(Attrib: Word; DrvName: String): DriverPointer;
  169. var DrvHead: DriverPointer;
  170.     x: Integer;
  171. begin
  172.   if SwapValInCS(DSeg) <> 0 then;      { Turbo-Datensegment speichern }
  173.   DrvHead := ReserveCS;   { Platz im Datensegment }
  174.   with DrvHead^ do
  175.   begin
  176.     DAttr := $8000;    { Attribute des Treibers }
  177.     DStrat := Ofs(DoStrategy);
  178.     DIntr := Ofs(DoInterrupt);
  179.     for x := 1 to 8 do Name[x] := ' ';
  180.     for x := 1 to Length(DrvName) do Name[x] := Upcase(DrvName[x]);
  181.     DNext := Ptr($FFFF,$FFFF);
  182.   end;
  183.   BuildCharDriver := DrvHead;
  184. end;
  185.  
  186. const
  187.   DrvAttrib: Word = $8000;   { zu setzendes Attribut }
  188.   DrvName = 'DEMO';          { zu setzender Name }
  189.   CmdLine : String    { "Kommandozeile" aus CONFIG.SYS }
  190.     = 'Parameter_1 Parameter_2'#13#10;
  191. var
  192.   OurDriver: DriverPointer;
  193.   InitParams: DrvInitBlock;  { Parameter zur Initialisierung }
  194.   { - - - - - - - - - - - - }
  195.   F: Text;   { nur zur Demonstration }
  196.   IORes: Integer;
  197.  
  198. begin
  199.   OurDriver := BuildCharDriver(DrvAttrib,DrvName);
  200.   FillChar(InitParams,Sizeof(InitParams),0);
  201.   with InitParams do
  202.   begin
  203.     DSize := SizeOf(DrvInitBlock);
  204.     DFunc := $00;
  205.     DCmdLine := Addr(CmdLine[1]); { hinter dem Längenbyte }
  206.     DEndAddr := Ptr($A000,0);
  207.   end;
  208.   LinkDriver(OurDriver,@InitParams);
  209.  
  210.   { - - - - - - - - - - - - - - - - - - - - - }
  211.   Writeln('Treiber ', DrvName, ' eingebaut und initialisiert.');
  212.   Writeln('Treiberkopf: $',HexP(OurDriver),
  213.           ', Init-Routine $',HexP(Addr(DriverInit)),
  214.           ', Endadresse: $',HexP(InitParams.DEndAddr));
  215.   Writeln('Zurückgelieferter Status: $',HexW(InitParams.DStatus));
  216.  
  217.   Write('Öffnen von ', DrvName,' als Datei für Schreibaktionen: ');
  218.   Assign(F,DrvName); {$I-} Rewrite(F); {$I+}
  219.   IORes := IOResult;
  220.   if IORes <> 0 then Writeln('DOS-Fehlercode ',IORes)
  221.    else
  222.    begin
  223.      Writeln('OK!');
  224.      {$I-} Writeln(F,'Ein via Write über das ',
  225.                      'Dateisystem ausgegebener Text.');
  226.      {$I+}
  227.      IORes := IOResult;
  228.      if IORes <> 0 then Writeln('DOS-Fehlercode ',IORes)
  229.       else Close(F);
  230.    end;
  231.   { - - - - - - - - - - - - - - - - - - - - - - - }
  232.   UnlinkDriver(OurDriver);
  233.   Writeln('Treiber ',DrvName,' wieder ausgebaut.');
  234. end.
  235.  
  236.