home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / das_buch / remote / pardata.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-08-10  |  30.8 KB  |  1,213 lines

  1. (* ====================================================== *)
  2. (*                     PARDATA.PAS                        *)
  3. (*         (c) 1993 Ralf Hensmann & DMV-Verlag            *)
  4. (* ====================================================== *)
  5. {$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R-,S+,T-,V+,X+,Y+}
  6. {$M 16384,0,655360}
  7.  
  8. UNIT ParData;
  9.  
  10. INTERFACE
  11.  
  12. {$DEFINE LapLink}
  13. {$DEFINE Debug}
  14.  
  15. USES Dos;
  16.  
  17.   FUNCTION GetLPTAdress(LPTNr : BYTE) : WORD;
  18.   (* Emittelt laut BIOS die Adresse der parallelen        *)
  19.   (* Schnittstelle. Achtung: Die Ermittlung funkioniert   *)
  20.   (* nicht immer, wenn das Kabel bereits beim Booten      *)
  21.   (* die Rechner verbindet. (LPT1=1, LPT2 = 2, ...        *)
  22.  
  23.   PROCEDURE UnitInit(LPTAdress : WORD);
  24.   (* Initialisiert die parallele Schnittstelle            *)
  25.  
  26.   (* Die Sende- und Empfangsroutinen sind aus Geschwindig-*)
  27.   (* keitsgründen in drei Einzelroutinen aufgespalten.    *)
  28.   (* Mit den Startroutinen (StartSend und StartReceive)   *)
  29.   (* wird die Synchronisation hergestellt. Die eigent-    *)
  30.   (* liche Übertragung geschieht mit SendBlock bzw.       *)
  31.   (* ReceiveBlock, die neben der Pufferadresse die Größe  *)
  32.   (* des Blocks enthalten. Ist der Empfängerblock zu      *)
  33.   (* klein, wird das Programm abgebrochen. StopSend und   *)
  34.   (* StopReceive geben den Kanal nach der Übertragung     *)
  35.   (* wieder frei. Sie können (und sollten) mehrere Block- *)
  36.   (* transfers zwischen den Synchronisationsprozeduren    *)
  37.   (* durchführen.                                         *)
  38.   (* Um den TimeOut so allgemein wie möglich zu halten,   *)
  39.   (* überprüfen alle Routinen die Variable LeaveProc^.    *)
  40.   (* Enthält sie den Wert $FF, brechen die Routinen ab.   *)
  41.   (* LeaveProc^ wird automatisch zu Beginn der Routinen   *)
  42.   (* auf den  Wert 0 gesetzt.                             *)
  43.  
  44. TYPE
  45.   WaitResult   = (UserBreak, ReadyToTransfer);
  46.   TransMode    = (Transfer4, Transfer8);
  47.  
  48. VAR
  49.   pLeave       : ^BYTE;      { Zeiger auf untersuchte Byte }
  50.   LastResult   : WaitResult; { Letztes Resultat            }
  51.   TransferMode : TransMode;
  52.   (* Gibt die Art der Übertragung (4-Bit oder 8-Bit an).  *)
  53.   (* Liefert erst ein Ergebnis, wenn StartReceive und     *)
  54.   (* StartSend durchgeführt wurden.                       *)
  55.   LastMode     : BYTE;
  56.   (* letztes Mal gesendet oder empfangen ...              *)
  57.  
  58.   PROCEDURE StartSend;
  59.    (* Synchronisation mit Empfänger herstellen            *)
  60.   PROCEDURE SendBlock(VAR Buf; Size : WORD);
  61.   PROCEDURE SendBlock4(VAR Buf; Size : WORD);
  62.    (* Die eigentliche Kernroutine des Sendens (auch in    *)
  63.    (* der 4-Bit-Version).                                 *)
  64.  
  65.   PROCEDURE StartReceive;
  66.    (* Synchronisation mit Sender herstellen               *)
  67.   PROCEDURE ReceiveBlock(VAR Buf; Size : WORD);
  68.   PROCEDURE ReceiveBlock4(VAR Buf; Size : WORD);
  69.    (* Die eigentliche Kernroutine des Empfangens (auch in *)
  70.    (* der 4-Bit-Version).                                 *)
  71.  
  72.   FUNCTION ParaResult : WaitResult;
  73.    (* Ermittelt das Resultat der Datenübertragung.        *)
  74.    (* Bei auftretendem Fehler werden alle Prozeduren      *)
  75.    (* solange ignoriert, bis ParaResult abgefragt ist.    *)
  76.  
  77.   PROCEDURE SetTimerWatchdog;
  78.   PROCEDURE ClrTimerWatchdog;
  79.    (* Die Prozeduren SetTimerWatchDog und ClrTimerWatchDog*)
  80.    (* bedienen den standardmäßig eingebauten Watchdog,    *)
  81.    (* der durch den Timer-Interrupt ausgelöst wird und    *)
  82.    (* und die Variable LeaveProc jeweils um eins erhöht.  *)
  83.    (* Der Watchdog kann beliebig ein- und ausgeschaltet   *)
  84.    (* werden. Achtung: Da der Watchdog sich in Int8 ein-  *)
  85.    (* hängt, darf zwischen Ein- und Ausschalten dieser    *)
  86.    (* Interrupt nicht verändert werden.                   *)
  87.  
  88.   PROCEDURE SetKbdWatchdog;
  89.   PROCEDURE ClrKbdWatchdog;
  90.    (* dito für Tastatur                                   *)
  91.  
  92. IMPLEMENTATION
  93.  
  94. VAR
  95.   Daten, Status, Steuer : WORD;
  96.   OldInt08Ptr,
  97.   OldInt09Ptr, OldExit  : POINTER;
  98.   OldInt08              : PROCEDURE ABSOLUTE OldInt08ptr;
  99.   OldInt09              : PROCEDURE ABSOLUTE OldInt09Ptr;
  100.  
  101.   PROCEDURE ColdError(st : STRING);
  102.    (* interne Fehlermeldungen bei falscher Programmierung *)
  103.   BEGIN
  104.     WriteLn(st);
  105.     RunError;
  106.   END;
  107.  
  108.   FUNCTION GetLPTAdress(LPTNr : BYTE) : WORD;
  109.     (* Ermittlung der LPTAdresse des Ports                *)
  110.   BEGIN
  111.     GetLPTAdress := MemW[Seg0040:$08+2*(LPTNr-1)];
  112.   END;
  113.  
  114.   PROCEDURE UnitInit(LPTAdress : WORD);
  115.     (* Initialisierung der Schnittstelle                  *)
  116.   BEGIN
  117.     (* Adresse aus dem ROM-BIOS-Speicherbereich holen     *)
  118.     Daten  := LPTAdress;
  119.     Status := Daten+1;
  120.     Steuer := Daten+2;
  121.     (* Ports auf Lesen vorbereiten *)
  122.     Port[Steuer] := $4;
  123.     Port[Status] := $0;
  124.     Port[Daten ] := $0;
  125.     (* Noch kein Timeout erreicht  *)
  126.     LastResult   := ReadyToTransfer;
  127.   END;
  128.  
  129. (* ====================================================== *)
  130. (*            Routinen für LapLink (TM) Kabel             *)
  131. (* ====================================================== *)
  132.  
  133. {$IFDEF LapLink}
  134.  
  135.   PROCEDURE SendToReceive;
  136.     (* Sorgt für einen definierten Übergang von Senden zu *)
  137.     (* Empfangen ...                                      *)
  138.   BEGIN
  139.     IF LastResult <> ReadyToTransfer THEN Exit;
  140.     Port[Daten] := 0;
  141.     WHILE (Port[Status] >= $80) AND (pLeave^ <> 255) DO;
  142.       Port[Daten] := $F;
  143.     IF pLeave^= 255 THEN LastResult := ReadyToTransfer;
  144.   END;
  145.  
  146.   PROCEDURE ReceiveToSend;
  147.     (* dito für Übergang von Empfangen zu Senden ...      *)
  148.   BEGIN
  149.     IF LastResult <> ReadyToTransfer THEN Exit;
  150.     WHILE (Port[Status] < $80) AND (pLeave^ <> 255) DO
  151.       (* nothing *);
  152.     Port[Daten] := $10;
  153.     WHILE (Port[Status] < $F8) AND (pLeave^ <> 255) DO
  154.       (* nothing *);
  155.     IF pLeave^ = 255 THEN LastResult := ReadyToTransfer;
  156.   END;
  157.  
  158. (* ====================================================== *)
  159. (*   Transfer - Routinen                                  *)
  160.  
  161. CONST
  162.   CALLB = $F; ECHO = $4; ECHO2 = $9;
  163.  
  164.   PROCEDURE StartSend; ASSEMBLER;
  165.   (* Synchronisiert mit dem Sender und setzt Strobe-Signal*)
  166.   ASM
  167.     LES  DI,pLeave      { es:di := pLeave }
  168.     SUB  AL,AL
  169.     MOV  ES:[DI],AL
  170.     MOV  BL,0FFH
  171.   @Restart:
  172.     MOV  DX,Steuer
  173.                  { Port[steuer] := 0; Port[daten] := $10; }
  174.     MOV  AL,ECHO2
  175.     OUT  DX,AL
  176.     DEC  DX
  177.     DEC  DX
  178.     MOV  AL,CALLB
  179.     OUT  DX,AL
  180.     INC  DX
  181.   @Loop1:
  182.     CMP  BL,ES:[DI]     { repeat }
  183.     JZ   @Break         { if pLeave^= 255 then break }
  184.     IN   AL,DX
  185.     AND  AL,$F8
  186.     CMP  AL,$80 XOR (ECHO SHL 3)
  187.     JNE  @Loop1
  188.     INC  DX
  189.     MOV  AL,4           { Port[steuer] := 4; }
  190.     OUT  DX,AL
  191.     NOP
  192.     IN   AL,DX
  193.     NOP
  194.     OUT  DX,AL
  195.     MOV  BH,AL
  196.     DEC  DX
  197.     DEC  DX
  198.     MOV  AL,$10 OR CALLB
  199.     OUT  DX,AL
  200.     INC  DX
  201.     MOV  CX,$400
  202.   @Loop2:
  203.     CMP  BL,ES:[DI]     { repeat }
  204.     JZ   @Break         { if pLeave^= 255 then break }
  205.     IN   AL,DX
  206.     AND  AL,$F8
  207.     CMP  AL,$80 XOR (ECHO2 SHL 3)
  208.     JE   @Allright
  209.     LOOP @Loop2
  210.     JMP  @Restart
  211.   @Allright:
  212.     MOV  AL,BH
  213.     AND  AL,$F
  214.     CMP  AL,4
  215.     JNE  @Trans8
  216.     MOV  TransferMode,0
  217.     JMP  @Weiter
  218.   @Trans8:
  219.     MOV  TransferMode,1
  220.   @Weiter:
  221.     MOV  AL,ReadyToTransfer
  222.     JMP  @ProgEnd
  223.   @Break:
  224.     MOV  AL,UserBreak
  225.   @ProgEnd:
  226.     MOV  LastResult,AL
  227.     MOV  LastMode,1
  228.   END;
  229.  
  230.   PROCEDURE StartReceive; ASSEMBLER;
  231.   (* Synchronisiert mit dem Empfänger und löscht          *)
  232.   (* Strobe-Signal                                        *)
  233.   ASM
  234.     LES  DI,pLeave
  235.     SUB  AL,AL
  236.     MOV  ES:[DI],AL
  237.     MOV  BL,0FFH
  238.   @Restart:
  239.     MOV  DX,Daten     { Port[daten] := 0 }
  240.     SUB  AL,AL
  241.     OUT  DX,AL
  242.     INC  DX
  243.     INC  DX
  244.     MOV  AL,4
  245.     OUT  DX,AL        { Port[steuer] := 4 }
  246.     DEC  DX
  247.   @Loop1:
  248.     CMP  BL,ES:[DI]   { repeat }
  249.     JZ   @Break       { if pLeave^= 255 then break }
  250.     IN   AL,DX
  251.     AND  AL,$F8
  252.     CMP  AL,$80 OR (CALLB SHL 3)
  253.     JNZ  @Loop1
  254.     INC  DX
  255.     IN   AL,DX
  256.     NOP
  257.     NOP
  258.     OUT  DX,AL
  259.     DEC  DX
  260.     DEC  DX
  261.     MOV  AL,ECHO
  262.     OUT  DX,AL
  263.     INC  DX
  264.     MOV  CX,$400
  265.   @Loop2:
  266.     CMP  BL,ES:[DI]   { repeat }
  267.     JZ   @Break       { if pLeave^= 255 then break }
  268.     IN   AL,DX
  269.     AND  AL,$F8
  270.     CMP  AL,(CALLB SHL 3)
  271.     JE   @Allright
  272.     LOOP @Loop2
  273.     JMP  @Restart
  274.   @Allright:
  275.     MOV  AL,ECHO2
  276.     Dec  DX
  277.     OUT  DX,AL
  278.     INC  DX
  279.     INC  DX
  280.     MOV  AL,4
  281.     OUT  DX,AL
  282.     NOP
  283.     NOP
  284.     IN   AL,DX
  285.     AND  AL,$F
  286.     CMP  AL,4
  287.     JNE  @Trans8
  288.     MOV  TransferMode,0
  289.     JMP  @Weiter
  290.   @Trans8:
  291.     MOV  TransferMode,1
  292.   @Weiter:
  293.     MOV  AL,ReadyToTransfer
  294.     JMP  @ProgEnd
  295.   @Break:
  296.     MOV  AL,UserBreak
  297.   @ProgEnd:
  298.     MOV  LastResult,AL
  299.     MOV  LastMode,0
  300.   END;
  301.  
  302. CONST
  303.   ACK1 = $A;
  304.   ACK2 = $5;
  305.  
  306.   PROCEDURE SendBlock(VAR Buf; Size : WORD); ASSEMBLER;
  307.     (* Die eigentliche Kernroutine des Sendens. *)
  308.   ASM
  309.     CMP  LastMode,0
  310.     JNZ  @First
  311.     CALL ReceiveToSend
  312.   @First:
  313.     PUSH DS
  314.     MOV  AL,LastResult
  315.     CMP  AL,ReadyToTransfer
  316.     JNE  @ProgEnd
  317.     LES  DI,pLeave        { Registerspeicherung  }
  318.     SUB  AL,AL
  319.     MOV  ES:[DI],AL       { pLeave^:= 0;         }
  320.     MOV  CX,0FF04H
  321.     CLD
  322.   @Restart:
  323.     MOV  AX,Seg @Data
  324.     MOV  DS,AX
  325.     MOV  BX,Size          { cx := (size+1) div 2  }
  326.                           {  Anzahl der Worte     }
  327.     INC  BX
  328.     SHR  BX,1
  329.     MOV  DX,Steuer        { Adr. Schnittstelle   }
  330.     LDS  SI,Buf           { Adresse des Puffers  }
  331.   @LOOP:
  332.     LODSB
  333.     ROR  AL,CL
  334.     OUT  DX,AL            { Steuerleitungen (high) raus }
  335.     DEC  DX
  336.     DEC  DX
  337.     CLC
  338.     RCR  AL,CL
  339.     OUT  DX,AL            { Datenleitungen (low) raus }
  340.     INC  DX
  341.   @ACK1:
  342.     CMP  CH,ES:[DI]
  343.     JZ   @UserBreak
  344.     IN   AL,DX
  345.     AND  AL,$F8
  346.     CMP  AL,$80 OR (ACK1 SHL 3)
  347.     JNE  @ACK1
  348.     INC  DX
  349.     LODSB
  350.     ROR  AL,CL
  351.     OUT  DX,AL            { Steuerleitungen (high) raus }
  352.     DEC  DX
  353.     DEC  DX
  354.     STC
  355.     RCR  AL,CL
  356.     OUT  DX,AL            { Datenleitungen (low) raus }
  357.     INC  DX
  358.   @ACK2:
  359.     CMP  CH,ES:[DI]
  360.     JZ   @UserBreak
  361.     IN   AL,DX
  362.     AND  AL,$F8
  363.     CMP  AL,$80 OR (ACK2 SHL 3)
  364.     JNE  @ACK2
  365.     INC  DX
  366.     SUB  BX,1
  367.     JNZ  @LOOP
  368.   @ProcEnd:
  369.     MOV  AL,ReadyToTransfer { Transfer fertig...      }
  370.     JMP  @ProgEnd
  371.   @UserBreak:
  372.     MOV  AL,UserBreak
  373.   @ProgEnd:
  374.     POP  DS
  375.     MOV  LastResult,AL
  376.     MOV  LastMode,1
  377.   END;
  378.  
  379.   PROCEDURE ReceiveBlock(VAR Buf; Size : WORD); ASSEMBLER;
  380.     (* Die eigentliche Kernroutine des Empfangens. *)
  381.   ASM
  382.     CMP  LastMode,1
  383.     JNZ  @First
  384.     CALL SendToReceive
  385.   @First:
  386.     PUSH DS
  387.     MOV  AL,LastResult
  388.     CMP  AL,ReadyToTransfer
  389.     JNE  @ProgEnd
  390.     LDS  SI,pLeave        { Registerspeicherung  }
  391.     SUB  AL,AL
  392.     MOV  [SI],AL          { pLeave^:= 0;         }
  393.     MOV  CX,0FF04H
  394.     CLD
  395.     MOV  DX,Steuer
  396.     MOV  AL,4
  397.     OUT  DX,AL
  398.   @Restart:
  399.     MOV  AX,Seg @Data
  400.     MOV  DS,AX
  401.     MOV  BX,Size
  402.     INC  BX
  403.     SHR  BX,1
  404.     MOV  DX,Status
  405.     LES  DI,Buf
  406.     LDS  SI,pLeave
  407.   @LOOP:
  408.   @Wait1:
  409.     CMP  CH,[SI]
  410.     JZ   @UserBreak
  411.     IN   AL,DX            { status }
  412.     SHL  AL,1
  413.     JNC  @Wait1
  414.     NOP
  415.     NOP
  416.     IN   AL,DX
  417.     SHL  AL,1
  418.     MOV  AH,AL
  419.     INC  DX
  420.     IN   AL,DX            { steuer }
  421.     ROL  AX,CL
  422.     STOSB
  423.     DEC  DX
  424.     DEC  DX
  425.     MOV  AL,ACK1          { Port[daten] := ACK1; }
  426.     OUT  DX,AL
  427.     INC  DX
  428.   @Wait2:
  429.     CMP  CH,[SI]
  430.     JZ   @UserBreak
  431.     IN   AL,DX            { status }
  432.     SHL  AL,1
  433.     JC   @Wait2
  434.     NOP
  435.     NOP
  436.     IN   AL,DX
  437.     SHL  AL,1
  438.     MOV  AH,AL
  439.     Inc  DX
  440.     IN   AL,DX            { steuer }
  441.     ROL  AX,CL
  442.     STOSB
  443.     DEC  DX
  444.     DEC  DX
  445.     MOV  AL,ACK2          { Port[daten] := ACK1;        }
  446.     OUT  DX,AL
  447.     INC  DX
  448.     SUB  BX,1
  449.     JNZ  @LOOP
  450.     MOV  AL,ReadyToTransfer
  451.     JMP  @ProgEnd
  452.   @UserBreak:
  453.     MOV  AL,UserBreak
  454.   @ProgEnd:
  455.     POP  DS
  456.     MOV  LastResult,AL
  457.     MOV  LastMode,0
  458.   END;
  459.  
  460.   PROCEDURE SendBlock4(VAR Buf; Size : WORD); ASSEMBLER;
  461.     (* Die eigentliche Kernroutine des Sendens. *)
  462.   ASM
  463.     CMP  LastMode,0
  464.     JNZ  @First
  465.     CALL ReceiveToSend
  466.   @First:
  467.     PUSH DS
  468.     MOV  AL,LastResult
  469.     CMP  AL,ReadyToTransfer
  470.     JNE  @ProgEnd
  471.     LES  DI,pLeave        { Registerspeicherung  }
  472.     SUB  AL,AL
  473.     MOV  ES:[DI],AL       { pLeave^:= 0;         }
  474.     MOV  CX,0FF04H
  475.     CLD
  476.   @Restart:
  477.     MOV  AX,Seg @Data
  478.     MOV  DS,AX
  479.     MOV  BX,Size
  480.     MOV  DX,Daten         { Adr. Schnittstelle   }
  481.     LDS  SI,Buf           { Adresse des Puffers  }
  482.   @LOOP:
  483.     LODSB
  484.     SUB  AH,AH
  485.     ROR  AX,CL
  486.     OUT  DX,AL            { Datenleitungen (high) raus }
  487.     INC  DX
  488.   @ACK1:
  489.     CMP  CH,ES:[DI]
  490.     JZ   @UserBreak
  491.     IN   AL,DX
  492.     AND  AL,$F8
  493.     CMP  AL,$80 OR (ACK1 SHL 3)
  494.     JNE  @ACK1
  495.     Dec  DX
  496.     MOV  AL,1
  497.     ROL  AX,CL
  498.     OUT  DX,AL            { Datenleitungen (low) raus }
  499.     INC  DX
  500.   @ACK2:
  501.     CMP  CH,ES:[DI]
  502.     JZ   @UserBreak
  503.     IN   AL,DX
  504.     AND  AL,$F8
  505.     CMP  AL,$80 OR (ACK2 SHL 3)
  506.     JNE  @ACK2
  507.     DEC  DX
  508.     SUB  BX,1
  509.     JNZ  @LOOP
  510.   @ProcEnd:
  511.     MOV  AL,ReadyToTransfer { Transfer fertig...  }
  512.     JMP  @ProgEnd
  513.   @UserBreak:
  514.     MOV  AL,UserBreak
  515.   @ProgEnd:
  516.     POP  DS
  517.     MOV  LastResult,AL
  518.     MOV  LastMode,1
  519.   END;
  520.  
  521.   PROCEDURE ReceiveBlock4(VAR Buf; Size : WORD); ASSEMBLER;
  522.     (* Die eigentliche Kernroutine des Empfangens. *)
  523.   ASM
  524.     CMP  LastMode,1
  525.     JNZ  @First
  526.     CALL SendToReceive
  527.   @First:
  528.     PUSH DS
  529.     MOV  AL,LastResult
  530.     CMP  AL,ReadyToTransfer
  531.     JNE  @ProgEnd
  532.     LDS  SI,pLeave        { Registerspeicherung  }
  533.     SUB  AL,AL
  534.     MOV  [SI],AL          { pLeave^:= 0;         }
  535.     MOV  CX,0FF04H
  536.     CLD
  537.     MOV  DX,Steuer
  538.     MOV  AL,4
  539.     OUT  DX,AL
  540.   @Restart:
  541.     MOV  AX,Seg @Data
  542.     MOV  DS,AX
  543.     MOV  BX,Size
  544.     MOV  DX,Status
  545.     LES  DI,Buf
  546.     LDS  SI,pLeave
  547.   @LOOP:
  548.   @Wait1:
  549.     CMP  CH,[SI]
  550.     JZ   @UserBreak
  551.     IN   AL,DX            { status }
  552.     SHL  AL,1
  553.     JNC  @Wait1
  554.     NOP
  555.     NOP
  556.     IN   AL,DX
  557.     SHL  AL,1
  558.     SHL  AX,CL            { in ah zwischenspeichern }
  559.     Dec  DX
  560.     MOV  AL,ACK1          { Port[daten] := ACK1;    }
  561.     OUT  DX,AL
  562.     Inc  DX
  563.   @Wait2:
  564.     CMP  CH,[SI]
  565.     JZ   @UserBreak
  566.     IN   AL,DX            { status }
  567.     SHL  AL,1
  568.     JC   @Wait2
  569.     NOP
  570.     NOP
  571.     IN   AL,DX
  572.     SHL  AL,1
  573.     ROR  AX,CL            { zusammenfügen }
  574.     STOSB
  575.     Dec  DX
  576.     MOV  AL,ACK2          { Port[daten] := ACK1;    }
  577.     OUT  DX,AL
  578.     Inc  DX
  579.     SUB  BX,1
  580.     JNZ  @LOOP
  581.     MOV  AL,ReadyToTransfer
  582.     JMP  @ProgEnd
  583.   @UserBreak:
  584.     MOV  AL,UserBreak
  585.   @ProgEnd:
  586.     POP  DS
  587.     MOV  LastResult,AL
  588.     MOV  LastMode,0
  589.   END;
  590.  
  591. (* ====================================================== *)
  592. (*  Routinen für eigenes Kabel                            *)
  593.  
  594. {$ELSE}   { IFNDEF LAPLINK }
  595.  
  596. CONST
  597.   DoStrobe = 5; { Konstanten sind hardwareabhängig }
  598.   NoStrobe = 4;
  599.  
  600.   PROCEDURE SendToReceive;
  601.     (* Sorgt für einen definierten Übergang von Senden zu *)
  602.     (* Empfangen ...                                      *)
  603.   BEGIN
  604.     IF LastResult <> ReadyToTransfer THEN Exit;
  605.     IF TransferMode = Transfer4 THEN BEGIN
  606.       Port[Daten] := 0;
  607.       WHILE ((Port[Status] AND $8) = 0) AND
  608.              (pLeave^ <> 255) DO (* nothing *);
  609.       Port[Daten] := $70;
  610.     END ELSE BEGIN
  611.       Port[Daten] := 0;
  612.       Port[Steuer] := NoStrobe;
  613.       WHILE NOT Odd(Port[Steuer]) AND (pLeave^ <> 255) DO;
  614.         (* nothing *)
  615.       Port[Daten] := $70;
  616.     END;
  617.     IF pLeave^= 255 THEN LastResult := ReadyToTransfer;
  618.   END;
  619.  
  620.   PROCEDURE ReceiveToSend;
  621.     (* dito für Übergang von Empfangen zu Senden ...      *)
  622.   BEGIN
  623.     IF LastResult <> ReadyToTransfer THEN Exit;
  624.     IF TransferMode = Transfer4 THEN BEGIN
  625.       WHILE ((Port[Status] AND $8) <> 0) AND
  626.              (pLeave^ <> 255) DO (* nothing *);
  627.       Port[Daten] := 8;
  628.       WHILE (Port[Status] < $F0) AND (pLeave^ <> 255) DO
  629.         (* nothing *);
  630.     END ELSE BEGIN
  631.       WHILE Odd(Port[Steuer]) AND (pLeave^ <> 255) DO
  632.         (* nothing *);
  633.       Port[Steuer] := DoStrobe;
  634.       WHILE (Port[Status] < $F0) AND (pLeave^ <> 255) DO
  635.         (* nothing *);
  636.     END;
  637.   END;
  638.  
  639. (* ====================================================== *)
  640. (*  Transfer - Routinen                                   *)
  641.  
  642.   FUNCTION GetByte : BYTE; ASSEMBLER;
  643.     (* empfängt einzelnes Byte                            *)
  644.   ASM
  645.     MOV   DX,Status
  646.     IN    AL,DX
  647.     MOV   AH,AL
  648.     AND   AH,$F8
  649.     INC   DX
  650.     IN    AL,DX
  651.     SHR   AL,1
  652.     AND   AL,$7
  653.     OR    AL,AH
  654.     XOR   AL,$85
  655.   END;
  656.  
  657. CONST
  658.   NULL     = 0;
  659.   ECHO     = $A8;
  660.   ECHOANS4 = $57;
  661.   ECHOANS8 = $50;
  662.   ECHOOK   = $AF;
  663.         { Konstanten sind algorithmusabhängig }
  664.  
  665.   PROCEDURE MakeTransfer; ASSEMBLER;
  666.     (* ermittelt aus dem Echobyte die Art des Transfers   *)
  667.   ASM
  668.     CMP   AL,ECHOANS8
  669.     JNZ   @Mode4
  670.     MOV   TransferMode,Transfer8
  671.     JMP   @ProgEnd
  672.   @Mode4:
  673.     MOV   TransferMode,Transfer4
  674.   @ProgEnd:
  675.   END;
  676.  
  677.   PROCEDURE StartSend; ASSEMBLER;
  678.     (* Synchronisiert mit dem Sender und setzt            *)
  679.     (* Strobe-Signal                                      *)
  680.   ASM
  681.     LES  DI,pLeave      { es:di := pLeave }
  682.     SUB  AL,AL
  683.     MOV  ES:[DI],AL
  684.     MOV  BL,0FFH
  685.   @Restart:
  686.     MOV  DX,Daten       { Port[daten] := echo }
  687.     MOV  AL,ECHO
  688.     OUT  DX,AL
  689.   @Loop1:
  690.     CALL GetByte        { if GetByte = ECHOANSWER goto ok1 }
  691.     CMP  AL,ECHOANS4
  692.     JZ   @Ok1
  693.     CMP  AL,ECHOANS8
  694.     JZ   @Ok1
  695.     CMP  ES:[DI],BL     { if pLeave = 255 then             }
  696.                         {   StartSend := UserBreak; exit;  }
  697.     JNZ  @Loop1
  698.     MOV  AL,UserBreak
  699.     JMP  @ProgEnd
  700.   @Ok1:
  701.     CALL MakeTransfer
  702.     MOV  CX,0400H
  703.     MOV  DX,Daten       { Port[daten] := echo }
  704.     OUT  DX,AL
  705.   @Loop2:
  706.     CALL GetByte        { if GetByte = ECHOOK goto ok2 }
  707.     CMP  AL,ECHOOK
  708.     JZ   @Ok2
  709.     CMP  ES:[DI],BL     { if pLeave = 255 then }
  710.                         {   StartSend := UserBreak; exit; }
  711.     JZ   @Break
  712.     LOOP @Loop2
  713.     JMP  @Restart
  714.   @Break:
  715.     MOV  AL,UserBreak
  716.     JMP  @ProgEnd
  717.   @Ok2:
  718.     MOV  AL,ReadyToTransfer
  719.     MOV  DX,Steuer
  720.     MOV  AL,DoStrobe
  721.     OUT  DX,AL
  722.   @ProgEnd:
  723.     MOV  LastResult,AL
  724.     MOV  LastMode,1
  725.   END;
  726.  
  727.   PROCEDURE StartReceive; ASSEMBLER;
  728.     (* Synchronisiert mit dem Empfänger und löscht        *)
  729.     (* Strobe-Signal                                      *)
  730.   ASM
  731.     LES  DI,pLeave
  732.     SUB  AL,AL
  733.     MOV  ES:[DI],AL
  734.     MOV  BL,0FFH
  735.   @Restart:
  736.     MOV  DX,Daten     { Port[daten] := 0; }
  737.     MOV  AL,NULL
  738.     OUT  DX,AL
  739.   @Loop1:
  740.     CALL GetByte      { repeat h := GetByte; }
  741.     MOV  AH,AL        { h1 := h; }
  742.     AND  AL,0F8H      { h := h and $F8 }
  743.     CMP  AL,ECHO      { until (h = ECHO) or }
  744.     JZ   @Ok1
  745.     CMP  ES:[DI],BL   { (pLeave^ = 255); }
  746.     JNZ  @Loop1
  747.     MOV  AL,UserBreak { if pLeave^=255 return UserBreak }
  748.     JMP  @ProgEnd
  749.   @Ok1:
  750.     MOV  DX,Daten
  751.                 { Port[daten] := ECHOANS8 xor h xor h1; }
  752.     XOR  AL,ECHOANS8
  753.     XOR  AL,AH
  754.     OUT  DX,AL
  755.     MOV  CX,0300H     { i := $300; }
  756.   @Loop2:
  757.     CALL GetByte      { repeat h := GetByte }
  758.     CMP  AL,ECHOANS8  { until (h =ECHOANS8) or }
  759.     JZ   @Ok2
  760.     CMP  AL,ECHOANS4  { (h = ECHOANS4) or }
  761.     JZ   @Ok2
  762.     CMP  ES:[DI],BL   { (pLeave^ = 255); }
  763.     JZ   @Break
  764.     LOOP @Loop2
  765.     JMP  @Restart     { if (--i = 0) then goto restart }
  766.   @Break:
  767.     MOV  AL,UserBreak
  768.     JMP  @ProgEnd
  769.   @Ok2:
  770.     CALL MakeTransfer
  771.     MOV  DX,Daten
  772.     MOV  AL,ECHOOK
  773.     OUT  DX,AL
  774.     MOV  AL,ReadyToTransfer
  775.   @ProgEnd:
  776.     MOV  LastResult,AL
  777.     MOV  LastMode,0
  778.   END;
  779.  
  780. CONST
  781.   ACK1     = $C8;
  782.   ACK2     = $30;
  783.   ACKError = 7;
  784.   { Konstanten sind algorithmusabhängig  }
  785.  
  786.   PROCEDURE SendBlock(VAR Buf; Size : WORD); ASSEMBLER;
  787.     (* Die eigentliche Kernroutine des Sendens. *)
  788.   ASM
  789.     CMP  LastMode,0
  790.     JNZ  @First
  791.     CALL ReceiveToSend
  792.   @First:
  793.     PUSH DS
  794.     MOV  AL,LastResult
  795.     CMP  AL,ReadyToTransfer
  796.     JNE  @ProgEnd
  797.     LES  DI,pLeave        { Registerspeicherung  }
  798.     SUB  AL,AL
  799.     MOV  ES:[DI],AL       { pLeave^:= 0;         }
  800.     MOV  BL,0FFH
  801.     CLD
  802.   @Restart:
  803.     POP  DS
  804.     PUSH DS
  805.     MOV  CX,Size          { Anzahl der Worte     }
  806.     Inc  CX
  807.     SHR  CX,1
  808.     MOV  DX,Daten         { Adr. Schnittstelle   }
  809.     LDS  SI,Buf           { Adresse des Puffers  }
  810.   @LOOP:
  811.     LODSW
  812.     OUT  DX,AL            { low-Byte raus        }
  813.     NOP
  814.     NOP
  815.     ADD  DX,2
  816.     MOV  AL,NoStrobe
  817.     OUT  DX,AL            { Strobe löschen          }
  818.     Dec  DX
  819.   @ACK1:                  { repeat                  }
  820.     CMP  BL,ES:[DI]       {   if [es:di]^=$FF then  }
  821.                           {    TimeOut ?            }
  822.     JZ   @UserBreak       {     goto UserBreak      }
  823.                           {   Abbruch der Prozedur  }
  824.     IN   AL,DX            {
  825.           until (Port[status] and $F8) = (ACK1 xor $80) }
  826.     AND  AL,$F8
  827.     CMP  AL,ACK1 XOR $80
  828.     JNE  @ACK1
  829.     Dec  DX
  830.     MOV  AL,AH
  831.     OUT  DX,AL            { High-Byte raus       }
  832.     NOP
  833.     NOP
  834.     ADD  DX,2
  835.     MOV  AL,DoStrobe
  836.     OUT  DX,AL            {  Strobe setzen     }
  837.     Dec  DX
  838.   @ACK2:                  { repeat                    }
  839.     CMP  BL,ES:[DI]       {   if [es:di]^=$FF then    }
  840.                           {   // TimeOut ?            }
  841.     JZ   @UserBreak       {     goto UserBreak        }
  842.                           {  // Abbruch der Prozedur  }
  843.     IN   AL,DX
  844.       { until (Port[status] and $F8) = (ACK2 xor $80) }
  845.     AND  AL,$F8
  846.     CMP  AL,ACK2 XOR $80
  847.     JNE  @ACK2
  848.     Dec  DX
  849.     LOOP @LOOP
  850.   @ProcEnd:
  851.     MOV  AL,ReadyToTransfer { Transfer fertig...      }
  852.     JMP  @ProgEnd
  853.   @UserBreak:
  854.     MOV  AL,UserBreak
  855.   @ProgEnd:
  856.     POP  DS
  857.     MOV  LastResult,AL
  858.     MOV  LastMode,1
  859.   END;
  860.  
  861.   PROCEDURE ReceiveBlock(VAR Buf; Size : WORD); ASSEMBLER;
  862.     (* Die eigentliche Kernroutine des Empfangens. *)
  863.   ASM
  864.     CMP  LastMode,1
  865.     JNZ  @First
  866.     CALL SendToReceive
  867.   @First:
  868.     PUSH DS
  869.     MOV  AL,LastResult
  870.     CMP  AL,ReadyToTransfer
  871.     JNE  @ProgEnd
  872.     LDS  SI,pLeave        { Registerspeicherung  }
  873.     SUB  AL,AL
  874.     MOV  [SI],AL          { pLeave^:= 0;         }
  875.     MOV  BL,0FFH
  876.     CLD
  877.   @Restart:
  878.     POP  DS
  879.     PUSH DS
  880.     MOV  CX,Size          { Anzahl der Worte     }
  881.     Inc  CX
  882.     SHR  CX,1
  883.     MOV  DX,Steuer        { Strobe-Empfang       }
  884.     LES  DI,Buf           { Adresse des Puffers  }
  885.     LDS  SI,pLeave        { Registerspeicherung  }
  886.   @LOOP:
  887.   @Wait1:                 { repeat                         }
  888.     CMP  BL,[SI]
  889.     JZ   @UserBreak
  890.     IN   AL,DX
  891.     SHR  AL,1
  892.     JC   @Wait1           { until not odd(Port[steuer]);   }
  893.     AND  AL,7
  894.     MOV  AH,AL
  895.     Dec  DX
  896.     IN   AL,DX
  897.            { [es:di]^ := ((Port[status] and $F8) or        }
  898.     AND  AL,$F8
  899.            {              ((Port[steuer] shr 1) and $7))   }
  900.     OR   AL,AH
  901.     XOR  AL,$85     { xor $85;                             }
  902.     STOSB           { inc(di);                             }
  903.     Dec  DX
  904.     MOV  AL,ACK1          { Port[daten] := ACK1;           }
  905.     OUT  DX,AL
  906.     NOP
  907.     NOP
  908.     ADD  DX,2
  909.   @Wait2:                 { repeat                         }
  910.     CMP  BL,[SI]
  911.     JZ   @UserBreak
  912.     IN   AL,DX
  913.     SHR  AL,1
  914.     JNC  @Wait2           { until odd(Port[steuer]);       }
  915.     AND  AL,7
  916.     MOV  AH,AL
  917.     Dec  DX
  918.     IN   AL,DX
  919.            { [es:di]^ := ((Port[status] and $F8) or        }
  920.     AND  AL,$F8
  921.            {              ((Port[steuer] shr 1) and $7))   }
  922.     OR   AL,AH
  923.     XOR  AL,$85           {             xor $85;           }
  924.     STOSB                 { inc(di);                       }
  925.     Dec  DX
  926.     MOV  AL,ACK2          { Port[daten] := ACK1;           }
  927.     OUT  DX,AL
  928.     NOP
  929.     NOP
  930.     ADD  DX,2
  931.     LOOP @LOOP
  932.     SUB  DX,2
  933.     MOV  AL,ReadyToTransfer
  934.     JMP  @ProgEnd
  935.   @UserBreak:
  936.     MOV  AL,UserBreak
  937.   @ProgEnd:
  938.     POP  DS
  939.     MOV  LastResult,AL
  940.     MOV  LastMode,0
  941.   END;
  942.  
  943.   PROCEDURE SendBlock4(VAR Buf; Size : WORD); ASSEMBLER;
  944.     (* Die eigentliche Kernroutine des Sendens. *)
  945.   ASM
  946.     CMP  LastMode,0
  947.     JNZ  @First
  948.     CALL ReceiveToSend
  949.   @First:
  950.     PUSH DS
  951.     MOV  AL,LastResult
  952.     CMP  AL,ReadyToTransfer
  953.     JNE  @ProgEnd
  954.     LES  DI,pLeave        { Registerspeicherung  }
  955.     SUB  AL,AL
  956.     MOV  ES:[DI],AL       { pLeave^:= 0;         }
  957.     MOV  CX,0FF04H
  958.     CLD
  959.   @Restart:
  960.     POP  DS
  961.     PUSH DS
  962.     MOV  BX,Size          { Anzahl der Bytes     }
  963.     MOV  DX,Daten         { Adr. Schnittstelle   }
  964.     LDS  SI,Buf           { Adresse des Puffers  }
  965.   @LOOP:
  966.     LODSB
  967.     SHL  AX,CL
  968.            { lower 4 Bit zuerst senden (upper in ah) ...   }
  969.     OUT  DX,AL            { (ohne Strobe) }
  970.     Inc  DX
  971.   @ACK1:                  { repeat                         }
  972.     CMP  CH,ES:[DI]       {   if [es:di]^=$FF then         }
  973.                           {     // TimeOut ?               }
  974.     JZ   @UserBreak       {     goto UserBreak             }
  975.                           {     // Abbruch der Prozedur    }
  976.     IN   AL,DX
  977.            { until (Port[status] and $F8) = (ACK1 xor $80) }
  978.     AND  AL,$F8
  979.     CMP  AL,ACK1 XOR $80
  980.     JNE  @ACK1
  981.     Dec  DX
  982.     STC
  983.     RCL  AH,CL
  984.     MOV  AL,AH            { obere 4 Bit mit Strobe-Signal  }
  985.     OUT  DX,AL            { High-Byte raus                 }
  986.     Inc  DX
  987.   @ACK2:                  { repeat                         }
  988.     CMP  CH,ES:[DI]       {   if [es:di]^=$FF then         }
  989.                           {     // TimeOut ?               }
  990.     JZ   @UserBreak       {     goto UserBreak             }
  991.                           {     // Abbruch der Prozedur    }
  992.     IN   AL,DX
  993.            { until (Port[status] and $F8) = (ACK2 xor $80) }
  994.     AND  AL,$F8
  995.     CMP  AL,ACK2 XOR $80
  996.     JNE  @ACK2
  997.     Dec  DX
  998.     SUB  BX,1
  999.     JNZ  @LOOP
  1000.   @ProcEnd:
  1001.     MOV  AL,ReadyToTransfer
  1002.     JMP  @ProgEnd
  1003.   @UserBreak:
  1004.     MOV  AL,UserBreak
  1005.   @ProgEnd:
  1006.     POP  DS
  1007.     MOV  LastResult,AL
  1008.     MOV  LastMode,1
  1009.   END;
  1010.  
  1011.   PROCEDURE ReceiveBlock4(VAR Buf; Size : WORD); ASSEMBLER;
  1012.     (* Die eigentliche Kernroutine des Empfangens. *)
  1013.   ASM
  1014.     CMP  LastMode,1
  1015.     JNZ  @First
  1016.     CALL SendToReceive
  1017.   @First:
  1018.     PUSH DS
  1019.     MOV  AL,LastResult
  1020.     CMP  AL,ReadyToTransfer
  1021.     JNE  @ProgEnd
  1022.     LDS  SI,pLeave     { Registerspeicherung  }
  1023.     SUB  AL,AL
  1024.     MOV  [SI],AL       { pLeave^:= 0;         }
  1025.     MOV  CX,0FF04H     { für Bitmaske und Schiebeoperation }
  1026.     CLD
  1027.   @Restart:
  1028.     POP  DS
  1029.     PUSH DS
  1030.     MOV  BX,Size          { Anzahl der Worte     }
  1031.     MOV  DX,Status        { Strobe-Empfang       }
  1032.     LES  DI,Buf           { Adresse des Puffers  }
  1033.     LDS  SI,pLeave        { Registerspeicherung  }
  1034.   @LOOP:
  1035.   @Wait1:                 { repeat                         }
  1036.     CMP  CH,[SI]
  1037.     JZ   @UserBreak
  1038.     IN   AL,DX
  1039.     AND  AL,8
  1040.     JNZ  @Wait1           { until kein Strobe-Signal       }
  1041.     NOP    { Schonfrist zur Beruhigung des Leitungspegels  }
  1042.     NOP
  1043.     NOP
  1044.     IN   AL,DX            { und die Daten ins AH-Register  }
  1045.     SUB  AH,AH
  1046.     SHL  AX,CL
  1047.     Dec  DX
  1048.     MOV  AL,ACK1          { Port[daten] := ACK1;           }
  1049.     OUT  DX,AL
  1050.     NOP
  1051.     NOP
  1052.     Inc  DX
  1053.   @Wait2:                 { repeat                         }
  1054.     CMP  CH,[SI]
  1055.     JZ   @UserBreak
  1056.     IN   AL,DX
  1057.     AND  AL,8
  1058.     JZ   @Wait2           { until Strobe                   }
  1059.     NOP
  1060.     NOP
  1061.     NOP
  1062.     IN   AL,DX
  1063.     AND  AL,0F0H
  1064.     OR   AL,AH            { ... auch 'ne Wiedervereinigung }
  1065.     XOR  AL,88H
  1066.     STOSB                 { inc(di);                       }
  1067.     Dec  DX
  1068.     MOV  AL,ACK2          { Port[daten] := ACK1;           }
  1069.     OUT  DX,AL
  1070.     NOP
  1071.     NOP
  1072.     Inc  DX
  1073.     SUB  BX,1
  1074.     JNZ  @LOOP
  1075.     Dec  DX
  1076.     MOV  AL,ReadyToTransfer
  1077.     JMP  @ProgEnd
  1078.   @UserBreak:
  1079.     MOV  AL,UserBreak
  1080.   @ProgEnd:
  1081.     POP  DS
  1082.     MOV  LastResult,AL
  1083.     MOV  LastMode,0
  1084.   END;
  1085.  
  1086. {$ENDIF}  { eigenes Kabel }
  1087.  
  1088. (* ====================================================== *)
  1089.  
  1090.   FUNCTION ParaResult : WaitResult;
  1091.   BEGIN
  1092.     ParaResult := LastResult;
  1093.     LastResult := ReadyToTransfer;
  1094.   END;
  1095.  
  1096. (* = Watchdog-Routinen ================================== *)
  1097.  
  1098.   PROCEDURE TimerWatchdog; ASSEMBLER;
  1099.   ASM
  1100.     PUSH DS          { Register sichern }
  1101.     PUSH SI
  1102.     PUSH AX
  1103.     MOV  AX,Seg @Data
  1104.     MOV  DS,AX
  1105.     LDS  SI,pLeave   { al := pLeave^ }
  1106.     MOV  AL,[SI]
  1107.     Inc  AL          { if al <> 255 then LeaveProc^:= al+1 }
  1108.     OR   AL,AL
  1109.     JZ   @Weiter
  1110.     MOV  [SI],AL
  1111.   @Weiter:
  1112.     PUSHF            { OldInt08; }
  1113.     CALL OldInt08
  1114.     POP  AX          { Register restaurieren }
  1115.     POP  SI
  1116.     POP  DS
  1117.     IRET
  1118.   END;
  1119.  
  1120.   PROCEDURE SetTimerWatchdog;
  1121.   BEGIN
  1122.   {$IFDEF Debug}
  1123.     IF (OldInt08ptr <> NIL) THEN
  1124.       ColdError('Watchdog bereits initialisiert');
  1125.   {$ENDIF}
  1126.     GetIntVec($08, OldInt08ptr);
  1127.     SetIntVec($08, @TimerWatchdog);
  1128.   END;
  1129.  
  1130.   PROCEDURE ClrTimerWatchdog;
  1131.   VAR
  1132.     Test08ptr : POINTER;
  1133.   BEGIN
  1134.   {$IFDEF Debug}
  1135.     IF (OldInt08ptr = NIL) THEN
  1136.       ColdError('Watchdog nicht initialisiert');
  1137.     GetIntVec($08, Test08ptr);
  1138.     IF Test08ptr <> @TimerWatchdog THEN
  1139.       ColdError('Zwischenzeitliche Installation eines '+
  1140.                 'anderen Hooks');
  1141.   {$ENDIF}
  1142.     SetIntVec($08, OldInt08ptr);
  1143.     OldInt08ptr := NIL;
  1144.   END;
  1145.  
  1146.   PROCEDURE KbdWatchdog; ASSEMBLER;
  1147.   ASM
  1148.     PUSH DS            { Register sichern }
  1149.     PUSH SI
  1150.     PUSH AX
  1151.     MOV  AX,Seg @Data
  1152.     MOV  DS,AX
  1153.     LDS  SI,pLeave
  1154.     MOV  AL,0FFH
  1155.     MOV  [SI],AL
  1156.     @Weiter:
  1157.     PUSHF              { OldInt09; }
  1158.     CALL OldInt09
  1159.     POP  AX            { Register restaurieren }
  1160.     POP  SI
  1161.     POP  DS
  1162.     IRET
  1163.   END;
  1164.  
  1165.   PROCEDURE SetKbdWatchdog;
  1166.   BEGIN
  1167.   {$IFDEF Debug}
  1168.     IF (OldInt09Ptr <> NIL) THEN
  1169.       ColdError('Watchdog bereits initialisiert');
  1170.   {$ENDIF}
  1171.     GetIntVec($09,OldInt09Ptr);
  1172.     SetIntVec($09,@KbdWatchdog);
  1173.   END;
  1174.  
  1175.   PROCEDURE ClrKbdWatchdog;
  1176.   VAR Test09ptr : POINTER;
  1177.   BEGIN
  1178.   {$IFDEF Debug}
  1179.     IF (OldInt09Ptr = NIL) THEN
  1180.       ColdError('Watchdog nicht initialisiert');
  1181.     GetIntVec($09,Test09ptr);
  1182.     IF Test09ptr <> @KbdWatchdog THEN
  1183.       ColdError('Zwischenzeitliche Installation eines '+
  1184.                 'anderen Hooks');
  1185.   {$ENDIF}
  1186.     SetIntVec($09, OldInt09Ptr);
  1187.     OldInt09Ptr := NIL;
  1188.   END;
  1189.  
  1190.   PROCEDURE UnitExit; FAR;
  1191.   BEGIN
  1192.     IF OldInt08ptr <> NIL THEN
  1193.       SetIntVec($08,OldInt08ptr);
  1194.     IF OldInt09Ptr <> NIL THEN
  1195.       SetIntVec($09,OldInt09Ptr);
  1196.     ExitProc := OldExit;
  1197.   END;
  1198.  
  1199. VAR
  1200.   LeaveByte : BYTE;
  1201.  
  1202. BEGIN
  1203.   OldInt08ptr := NIL;
  1204.   OldInt09Ptr := NIL;
  1205.   pLeave      := @LeaveByte;
  1206.   OldExit     := ExitProc;
  1207.   ExitProc    := @UnitExit;
  1208.   LastResult  := ReadyToTransfer;
  1209.   TransferMode:= Transfer4;
  1210. END.
  1211. (* ====================================================== *)
  1212. (*                 Ende von PARDATA.PAS                   *)
  1213.