home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / communic / yasync.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1987-12-21  |  39.8 KB  |  1,081 lines

  1. {$R-,S-,I-,D+,T+,F-,V+,B-,N-,L+ }
  2. Unit YAsync; { Version 1.4 }
  3. {
  4.   "Yet another" set of Async routines.  This unit supports concurrent
  5.   use of one to four 8250 Asynchronous communications ports with transmit and
  6.   receive buffer interrupt support and flexible handshaking options at the
  7.   interrupt level.  Upon program termination, all open ports are closed
  8.   and interrupt vectors returned to their former values.
  9.  
  10.   Copyright 1987 by Edwin Floyd [76067,747]
  11.                     4210 Pickering Dr.
  12.                     Columbus, GA 31907
  13.                     (404) 563 - 9915
  14.  
  15.   All rights reserved; non-commercial use Ok.
  16.  
  17.   Update History
  18.  
  19.   1.0 10-12-87 E. Floyd, Initial implementation and testing complete
  20.   1.1 11-22-87 E. Floyd, Added handshaking options, changed name to YAsync
  21.   1.2 11-29-87 E. Floyd, Separated handshaking options, changed irpt handler
  22.   1.3 12-19-87 E. Floyd, Removed polling support, changed buffer spec.
  23.   1.4 12-21-87 E. Floyd, Documented for upload to C'Serv, added buflen funcs
  24. }
  25. Interface
  26.  
  27. Uses Dos, Crt;
  28.  
  29. Const
  30.   YasyncVersion = 14; { Current version * 10 }
  31.   MaxPorts = 4;       { Maximum number of ports supported }
  32.   DefaultBufferSize = 2048; { Default size of receive & transmit buffers }
  33.   BaudRateDividend : LongInt = 115200; { Used to compute baud rate divisor }
  34.   TimeoutMilliseconds : LongInt = 1000; { Retry Send until timeout ms }
  35.   BreakMiliseconds : Word = 300; { Duration of break signal }
  36.  
  37.   { These constants define the bits for the Line Status Register }
  38.   LSRRcvReady = $01;  { Received data ready }
  39.   LSROverrun  = $02;  { OverRun error }
  40.   LSRParity   = $04;  { Parity error }
  41.   LSRFrame    = $08;  { Framing error }
  42.   LSRBreak    = $10;  { Break detected }
  43.   LSRXhReady  = $20;  { Transmit hold register empty }
  44.   LSRXsReady  = $40;  { Transmit shift register empty }
  45.   LSRTimeout  = $80;  { Time out (software implemented) }
  46.  
  47.   { These constants define the bits for the Modem Status Register }
  48.   MSRctsDelta = $01;  { Clear To Send changed }
  49.   MSRdsrDelta = $02;  { DataSet Ready changed }
  50.   MSRriDelta  = $04;  { Ring Indicate changed }
  51.   MSRcdDelta  = $08;  { Carrier Detect changed }
  52.   MSRcts      = $10;  { Clear To Send }
  53.   MSRdsr      = $20;  { DataSet Ready }
  54.   MSRri       = $40;  { Ring Indicate }
  55.   MSRcd       = $80;  { Carrier Detect }
  56.  
  57. Type
  58.   AsyncBuffer = Array[0..32767] Of Byte;
  59.   {
  60.     Note, AsyncBuffer is for the buffer pointer declarations below.  The actual
  61.     buffer size is specified in Async_Control.
  62.   }
  63.   Async_Control = Record
  64.   {
  65.     This record contains control information used to manage the activity of
  66.     a port.  Certain fields may be altered before calling OpenPort.  These
  67.     are marked with an "*" in the comments.  For instance...
  68.  
  69.       With AsyncPort[2] Do Begin
  70.         ReceiveSize := 10000;
  71.         TransmitSize := 8000;
  72.         WaitForXon := True;
  73.         XoHand := True;
  74.         XoTransparent := False;
  75.       End;
  76.       OpenPort(2, 9600, 7, 1, 'E');
  77.  
  78.     ...sets buffer sizes and Xon/Xoff handshaking for COM2 and opens COM2 at
  79.     9600 bps, 7 bits, 1 stop bit, even parity.  Fields not marked with "*"
  80.     in comments are used internally by YAsync; do not alter these fields.
  81.     Do not alter any fields while a port is open.
  82.   }
  83.     PortOpen : Boolean;       { True if port is currently open }
  84.     VectorIndex : Byte;       { Index to interrupt vector save area }
  85.  
  86.     IrqNumber : Byte;         { *IRQ number }
  87.     IntNumber : Byte;         { *Interrupt number }
  88.     BasePort : Word;          { *Base I/O port for UART }
  89.     {
  90.       The IRQ, Interrupt and base port numbers are set to default values during
  91.       initialization.  The defaults (see implementation Const's for details)
  92.       should be appropriate for most systems, but they may be reset if
  93.       necessary before calling OpenPort.
  94.     }
  95.     LineStatus : Byte;        { Line status register for ErrorRoutine,
  96.                                   Decode with LSRxxx constants above }
  97.     ModemStatus : Byte;       { Modem status register for ModemRoutine,
  98.                                   Decode with MSRxxx constants above }
  99.     UserData : Word;          { This field is unused by YAsync routines }
  100.  
  101.     WaitForXon : Boolean;     { *Inhibit transmit between Xoff and Xon }
  102.     WaitForCts : Boolean;     { *Inhibit transmit if not Cts }
  103.     WaitForDsr : Boolean;     { *Inhibit transmit if not Dsr }
  104.     WaitForCd  : Boolean;     { *Inhibit transmit if not Cd }
  105.     XoHand : Boolean;         { *Handshake receive buffer with Xon/Xoff }
  106.     RtsHand : Boolean;        { *Handshake receive buffer with Rts }
  107.     DtrHand : Boolean;        { *Handshake receive buffer with Cts }
  108.     XoTransparent : Boolean;  { *Pass Xon/Xoff through to data stream }
  109.     {
  110.       If XoTransparent is False, Xon and Xoff characters are not placed in
  111.       the receive buffer (they will still have their handshaking effect if
  112.       WaitForXon is True).  The defaults are:
  113.         WaitForXon = False
  114.         WaitForCts = False
  115.         WaitForDsr = False
  116.         WaitForCd = False
  117.         XoHand = False
  118.         RtsHand = True
  119.         DtrHand = False
  120.         XoTransparent = True
  121.     }
  122.     TransmitEnabled : Boolean;{ If False, transmit is inhibited }
  123.     SenderEnabled : Boolean;  { Handshake signal was sent to sender }
  124.     AwaitingXon : Boolean;    { True if waiting for Xon }
  125.     AwaitingCts : Boolean;    { True if waiting for Cts }
  126.     AwaitingDsr : Boolean;    { True if waiting for Dsr }
  127.     AwaitingCd  : Boolean;    { True if waiting for Cd }
  128.     AwaitingCh  : Boolean;    { True if waiting for character to transmit }
  129.     StreamInsert : Byte;      { Character to be forced into output stream }
  130.  
  131.     ErrorRoutine : Pointer;   { *Pointer to routine for line status interrupt }
  132.     ModemRoutine : Pointer;   { *Pointer to routine for modem status intrpt }
  133.     {
  134.       These routines must be declared as Far-calls ($F+) at the global level
  135.       with a one-Word value parameter, the port number.  Do NOT declare
  136.       them as "Interrupt" type procedures.  These routines, though not
  137.       "Interrupt" type routines, are called from the interrupt service routine,
  138.       therefore they should follow the same rules as an ISR - no DOS services,
  139.       reentrant, etc.  ErrorRoutine should examine LineStatus to determine the
  140.       cause of the error; ModemRoutine should examine ModemStatus.
  141.     }
  142.     ReceiveBuffer : ^AsyncBuffer;  { *Receive buffer }
  143.     ReceiveSize : Word;            { *0..32767 }
  144.     ReceiveHead : Word;
  145.     ReceiveTail : Word;
  146.     TransmitBuffer : ^AsyncBuffer; { *Transmit buffer }
  147.     TransmitSize : Word;           { *0..32767 }
  148.     TransmitHead : Word;
  149.     TransmitTail : Word;
  150.     ReleaseReceive : Boolean; { YAsync obtained receive buffer, must release }
  151.     ReleaseTransmit : Boolean;{ Ditto, transmit buffer }
  152.     {
  153.       Buffers are allocated from the heap if the corresponding pointer is Nil
  154.       when OpenPort is called.  You may allocate a buffer yourself and place
  155.       its address in ReceiveBuffer or TransmitBuffer, and its size in
  156.       ReceiveSize or TransmitSize.  Alternatively, you may change the size of
  157.       the automatically allocated buffer by changing ReceiveSize or
  158.       TransmitSize before calling OpenPort.
  159.     }
  160.   End;
  161.  
  162.   SetOfChar = Set of Char; { Used by LineReadPort below }
  163.  
  164. Var
  165.   AsyncPort: Array[1..MaxPorts] Of Async_Control;
  166.   PortOpenError : Byte;  { Error code from open routine..
  167.                            0 Normal, open successful
  168.                            1 Port number out of range (1..4)
  169.                            2 Baud rate out of range (50..115200)
  170.                            3 Word length out of range (5..8)
  171.                            4 Stop bits out of range (1..2)
  172.                            5 Invalid parity (N,E,O,1,0)
  173.                            6 Buffer size invalid (2..32767)
  174.                            7 Insufficient heap space for buffers
  175.                            8 UART not responding
  176.                            9 Program bug - should never happen
  177.                          }
  178.  
  179. Function OpenPort(ComPort : Word;     { Com port number, 1..4 }
  180.                   BaudRate : LongInt; { BPS, 50..115200 }
  181.                   WordLength : Word;  { 5..8 bits }
  182.                   StopBits : Word;    { 1..2 stop bits }
  183.                   Parity : Char      { N,E,O,1,0 }
  184.                   ) : Boolean;        { Return True if open successful }
  185. { Prepare port for communications.  Baud rate may be any number from
  186.   50..115200; the actual steady-state baud rate that can be maintained without
  187.   overruns depends on the cpu speed in response to interrupts.  A 4.77 Mhz,
  188.   8088 XT can handle up to about 10000.  If WordLength is 5 and StopBits is 2,
  189.   the actual stop bits used will be 1.5.  If OpenPort fails, it returns False
  190.   and places an error code in PortOpenError above. }
  191.  
  192. Procedure ClosePort(ComPort : Word);
  193. { Close async port, reset interrupts and release buffers.  If buffered output
  194.   is in progress, ClosePort will wait for its completion.  ClosePort turns
  195.   off the DTR and RTS modem control signals. }
  196.  
  197. Procedure ClearTransmitBuffer(ComPort : Word);
  198. { Discard all unsent characters in the transmit buffer. }
  199.  
  200. Procedure ClearReceiveBuffer(ComPort : Word);
  201. { Discard all unread characters in the receive buffer. }
  202.  
  203. Function ReceiveBufferUsed(ComPort : Word) : Word;
  204. { Returns the number of receive buffer bytes in use }
  205.  
  206. Function TransmitBufferUsed(ComPort : Word) : Word;
  207. { Returns the number of transmit buffer bytes in use }
  208.  
  209. Function SendPort(ComPort : Word; Ch : Char ) : Boolean;
  210. { Send a character (or place it in transmit buffer).  Return True if
  211.   successful.  This rouine will wait up to TimeoutMilliseconds for buffer
  212.   space to become available. }
  213.  
  214. Function BlockSendPort(ComPort : Word; Var Block; BlkLen : Word) : Word;
  215. { Move a block of characters to the buffer and return the number of characters
  216.   inserted in buffer.  This function does not wait for buffer space to become
  217.   available - it always returns immediately. }
  218.  
  219. Function BlockSendPortWait(ComPort : Word; Var Block; BlkLen : Word) : Word;
  220. { Send a block of characters; return the number of characters sent.  This
  221.   function will wait TimeoutMilliseconds between characters sent if not enough
  222.   buffer space is available.  As soon as the remainder of the message will
  223.   fit in the buffer, this routine returns (maybe immediately if the entire
  224.   message fits). Otherwise, if TimeoutMilliseconds elapses without a single
  225.   character being transmitted (may happen if handshaking is asserted), this
  226.   routine signals a timeout error and returns the number of bytes
  227.   successfully loaded into the buffer. }
  228.  
  229. Function PortReady(ComPort : Word) : Boolean;
  230. { Returns True if a character is waiting in the receive buffer or RBR. }
  231.  
  232. Function ReadPort(ComPort : Word; Var Ch) : Boolean;
  233. { Returns received character from buffer, returns False if none ready. }
  234.  
  235. Function BlockReadPort(ComPort : Word; Var Block; BlkLen : Word) : Word;
  236. { Read a block of characters from the port and return number of characters
  237.   read.  This function does not wait for characters to appear in the buffer;
  238.   it transfers any characters which might be present, up to BlkLen, and returns
  239.   the number of characters transferred.}
  240.  
  241. Function BlockReadPortDelim(ComPort : Word; Var Block; BlkLen : Word;
  242.   Delim : SetOfChar) : Word;
  243. { Read a block of characters from the port and return number of characters
  244.   read.  This function reads characters from the port until either: 1. BlkLen
  245.   characters have been read; 2. A character appearing in Delim has been read
  246.   (The Delim character appears in the buffer and is included in the count); or
  247.   3. TimeoutMilliseconds has elapsed since the last character received
  248.   (LSRTimeout bit set in LineStatus and ErrorRoutine called if present). }
  249.  
  250. Procedure SendBreak(ComPort : Word);
  251. { Send break signal for BreakMiliseconds.  If buffered output is in progress,
  252.   SendBreak will wait for its completion before sending the break signal. }
  253.  
  254. Procedure SetDTR(ComPort : Word; Dtr : Boolean);
  255. { Set DTR on/off - WARNING: When DtrHand is True, DTR is turned off
  256.   by the interrupt handler when the receive buffer exceeds 75% full, and
  257.   turned back on by ReadPort when the receive buffer falls below 50% full.
  258.   Use of this procedure may interfere with automatic DTR handshaking. }
  259.  
  260. Procedure SetRTS(ComPort : Word; Rts : Boolean);
  261. { Set RTS on/off - WARNING: This signal is also controlled by the state of the
  262.   receive buffer when RtsHand is True.  Use of this procedure may interfere
  263.   with automatic RTS handshaking.}
  264.  
  265. Procedure SetLoop(ComPort : Word; Loop : Boolean);
  266. { Set LoopBack on/off - WARNING: Setting LoopBack on disables interrupts
  267.   from the 8250 UART! (It apparently disconnects OUT2 from the PC bus.) }
  268.  
  269. Implementation
  270.  
  271. Const
  272.   { These are the offsets from BasePort of the 8250 control registers }
  273.   DLL = 0; { Divisor Latch Least-significant-byte (LCR bit $80 on) }
  274.   DLM = 1; { Divisor Latch Most-significant-byte (LCR bit $80 on) }
  275.   RBR = 0; { Receiver Buffer Register (read) }
  276.   THR = 0; { Transmitter Holding Register (write) }
  277.   IER = 1; { Interrupt Enable Register }
  278.   IIR = 2; { Interrupt Identification Register (read only) }
  279.   LCR = 3; { Line Control Register }
  280.   MCR = 4; { Modem Control Register }
  281.   LSR = 5; { Line Status Register }
  282.   MSR = 6; { Modem Status Register }
  283.  
  284.   { These constants define the bits for the Modem Control Register }
  285.   MCRloop     = $10; { Loopback mode }
  286.   MCRout2     = $08; { Out2, must be on for interrupts }
  287.   MCRout1     = $04; { Out1 ? }
  288.   MCRrts      = $02; { Request to send }
  289.   MCRdtr      = $01; { Data terminal ready }
  290.  
  291.   { These are the default base ports, IRQs and interrupts }
  292.   BasePorts : Array[1..MaxPorts] Of Word = ($03F8,$02F8,$03E8,$02E8);
  293.   IRQs : Array[1..MaxPorts] Of Byte = (4,3,4,3);
  294.   Interrupts : Array[1..MaxPorts] Of Byte = (12,11,12,11);
  295.  
  296.   XOn  = 17; {^Q, DC1, XOn }
  297.   XOff = 19; {^S, DC3, XOff }
  298.  
  299. Type
  300.   VectorType = Record
  301.     UseCount : Byte;  { Number of ports using this interrupt vector }
  302.     IntrptNo : Byte;  { Interrupt number for this vector }
  303.     Vector : Pointer; { Old value of vector }
  304.     NextPort : Word;  { Next port to process }
  305.     PortList : Array[0..MaxPorts] Of Word; { Open ports using this vector }
  306.   End;
  307.  
  308. Var
  309.   FormerExitProc : Pointer; { Save area for ExitProc pointer }
  310.   VectorSave : Array[1..MaxPorts] Of VectorType;
  311.  
  312. Procedure CallFar(ComPort : Word; proc : Pointer);
  313. { Call proc, reentrant far call, works even when @proc is in a record.
  314.   Far proc may only be declared globally. }
  315. InLine($5B/          { pop bx   ; save @proc in cx:bx }
  316.        $59/          { pop cx }
  317.        $0E/          { push cs  ; set up return address }
  318.        $E8/$00/$00/  { call $ }
  319.        $58/          { pop ax }
  320.        $05/$08/$00/  { add ax,8 }
  321.        $50/          { push ax }
  322.        $51/          { push cx  ; restore @proc to stack }
  323.        $53/          { push bx }
  324.        $CB);         { retf     ; go to proc }
  325.  
  326. Procedure DisableInterrupts;
  327. { Disable 80x86/8 interrupts }
  328. Inline($FA);
  329.  
  330. Procedure EnableInterrupts;
  331. { Enable 80x86/8 interrupts }
  332. Inline($FB);
  333.  
  334. Function ReceiveBufferUsed(ComPort : Word) : Word;
  335. { Return number of receive buffer bytes used }
  336. Begin { ReceiveBufferUsed }
  337.   With AsyncPort[ComPort] Do Begin
  338.     DisableInterrupts;
  339.     If ReceiveHead < ReceiveTail Then
  340.       ReceiveBufferUsed := (ReceiveSize-ReceiveTail)+ReceiveHead
  341.     Else ReceiveBufferUsed := ReceiveHead-ReceiveTail;
  342.     EnableInterrupts;
  343.   End;
  344. End;  { ReceiveBufferUsed }
  345.  
  346. Function TransmitBufferUsed(ComPort : Word) : Word;
  347. { Return number of transmit buffer bytes used }
  348. Begin { TransmitBufferUsed }
  349.   With AsyncPort[ComPort] Do Begin
  350.     DisableInterrupts;
  351.     If TransmitHead < TransmitTail Then
  352.       TransmitBufferUsed := (TransmitSize-TransmitTail)+TransmitHead
  353.     Else TransmitBufferUsed := TransmitHead-TransmitTail;
  354.     EnableInterrupts;
  355.   End;
  356. End;  { TransmitBufferUsed }
  357.  
  358. Procedure SetDTR(ComPort : Word; Dtr : Boolean);
  359. { Set DTR on/off }
  360. Begin { SetDTR }
  361.   With AsyncPort[ComPort] Do Begin
  362.     If Dtr Then
  363.       Port[BasePort+MCR] := Port[BasePort+MCR] Or MCRdtr
  364.     Else
  365.       Port[BasePort+MCR] := Port[BasePort+MCR] And Not MCRdtr;
  366.   End;
  367. End;  { SetDTR }
  368.  
  369. Procedure SetRTS(ComPort : Word; Rts : Boolean);
  370. { Set RTS on/off }
  371. Begin { SetRTS }
  372.   With AsyncPort[ComPort] Do Begin
  373.     If Rts Then
  374.       Port[BasePort+MCR] := Port[BasePort+MCR] Or MCRrts
  375.     Else
  376.       Port[BasePort+MCR] := Port[BasePort+MCR] And Not MCRrts;
  377.   End;
  378. End;  { SetRTS }
  379.  
  380. Procedure EnableTransmit(ComPort : Word);
  381. { Enable buffered transmit, restart interrupt if necessary }
  382. Begin { EnableTransmit }
  383.   With AsyncPort[ComPort] Do Begin
  384.     TransmitEnabled := True;
  385.     DisableInterrupts;
  386.     If (TransmitHead <> TransmitTail) And AwaitingCh Then Begin
  387.       Port[BasePort+THR] := TransmitBuffer^[TransmitTail];
  388.       TransmitTail := Succ(TransmitTail);
  389.       If TransmitTail = TransmitSize Then TransmitTail := 0;
  390.     End;
  391.     EnableInterrupts;
  392.   End;
  393. End;  { EnableTransmit }
  394.  
  395. Procedure EnableSender(ComPort : Word);
  396. { Enable sender via handshaking signal }
  397. Begin { EnableSender }
  398.   With AsyncPort[ComPort] Do Begin
  399.     If Not SenderEnabled Then Begin
  400.       If XoHand Then Begin
  401.         DisableInterrupts;
  402.         If AwaitingCh Then Port[BasePort+THR] := XOn
  403.         Else StreamInsert := XOn;
  404.         EnableInterrupts;
  405.       End;
  406.       If DtrHand Then SetDtr(ComPort, True);
  407.       If RtsHand Then SetRts(ComPort, True);
  408.       SenderEnabled := True;
  409.     End;
  410.   End;
  411. End;  { EnableSender }
  412.  
  413. Procedure DisableSender(ComPort : Word);
  414. { Disable sender via handshaking signal }
  415. Begin { DisableSender }
  416.   With AsyncPort[ComPort] Do Begin
  417.     If SenderEnabled Then Begin
  418.       If XoHand Then Begin
  419.         DisableInterrupts;
  420.         If AwaitingCh Then Port[BasePort+THR] := XOff
  421.         Else StreamInsert := XOff;
  422.         EnableInterrupts;
  423.       End;
  424.       If DtrHand Then SetDtr(ComPort, False);
  425.       If RtsHand Then SetRts(ComPort, False);
  426.       SenderEnabled := False;
  427.     End;
  428.   End;
  429. End;  { DisableSender }
  430.  
  431. Procedure ClearTransmitBuffer(ComPort : Word);
  432. { Discard all unsent characters in the transmit buffer. }
  433. Begin { ClearTransmitBuffer }
  434.   With AsyncPort[ComPort] Do Begin
  435.     DisableInterrupts;
  436.     TransmitHead := 0;
  437.     TransmitTail := 0;
  438.     EnableInterrupts;
  439.   End;
  440. End;  { ClearTransmitBuffer }
  441.  
  442. Procedure ClearReceiveBuffer(ComPort : Word);
  443. { Discard all unsent characters in the receive buffer. }
  444. Begin { ClearReceiveBuffer }
  445.   With AsyncPort[ComPort] Do Begin
  446.     DisableInterrupts;
  447.     ReceiveHead := 0;
  448.     ReceiveTail := 0;
  449.     EnableInterrupts;
  450.     EnableSender(ComPort);
  451.   End;
  452. End;  { ClearReceiveBuffer }
  453.  
  454. Procedure AsyncISR(VectorNo : Word);
  455. { General Interrupt Handler (called by specific interrupt procs below) }
  456. Var
  457.   i, Next, ComPort : Word;
  458.   work : Byte;
  459.   done : Boolean;
  460. Begin { AsyncISR }
  461.   EnableInterrupts;
  462.   With VectorSave[VectorNo] Do Begin
  463.     Inc(NextPort);
  464.     If NextPort > UseCount then NextPort := 1;
  465.     i := NextPort;
  466.     Repeat
  467.       ComPort := PortList[i];
  468.       With AsyncPort[ComPort] Do Begin
  469.         done := False;
  470.         Repeat
  471.           Case Port[BasePort+IIR] Of
  472.             $06 : Begin { Received character error or break }
  473.               LineStatus := Port[BasePort+LSR];
  474.               If (LineStatus And LSRBreak) <> 0 Then Begin
  475.                 LineStatus := LineStatus And Not LSRFrame;
  476.                 work := Port[BasePort+RBR];
  477.               End;
  478.               If ErrorRoutine <> Nil Then CallFar(ComPort, ErrorRoutine);
  479.             End;
  480.             $04 : Begin { Received data ready }
  481.               work := Port[BasePort+RBR];
  482.               If XoTransparent Or ((work <> XOff) And (work <> XOn)) Then Begin
  483.                 next := Succ(ReceiveHead);
  484.                 If next = ReceiveSize Then next := 0;
  485.                 If next = ReceiveTail Then Begin
  486.                   LineStatus := LSROverrun;
  487.                   If ErrorRoutine <> Nil Then CallFar(ComPort, ErrorRoutine);
  488.                 End Else Begin
  489.                   ReceiveBuffer^[ReceiveHead] := work;
  490.                   ReceiveHead := next;
  491.                 End;
  492.                 If (XoHand Or RtsHand Or DtrHand) And SenderEnabled Then Begin
  493.                   If ReceiveHead < ReceiveTail Then
  494.                     next := (ReceiveSize-ReceiveTail)+ReceiveHead
  495.                   Else next := ReceiveHead-ReceiveTail;
  496.                   If next > (ReceiveSize - (ReceiveSize Shr 2)) Then
  497.                     DisableSender(ComPort);
  498.                 End;
  499.               End;
  500.               If WaitForXon Then Begin
  501.                 Case work Of
  502.                   XOff : Begin
  503.                     TransmitEnabled := False;
  504.                     AwaitingXon := True;
  505.                   End;
  506.                   XOn : Begin
  507.                     AwaitingXon := False;
  508.                     If Not (AwaitingCts Or AwaitingDsr Or AwaitingCd) Then
  509.                       EnableTransmit(ComPort);
  510.                   End;
  511.                 End;
  512.               End;
  513.             End;
  514.             $02 : Begin { Transmit holding register empty }
  515.               If StreamInsert > 0 Then Begin
  516.                 Port[BasePort+THR] := StreamInsert;
  517.                 StreamInsert := 0;
  518.               End Else If (TransmitHead <> TransmitTail) And TransmitEnabled
  519.               Then Begin
  520.                 Port[BasePort+THR] := TransmitBuffer^[TransmitTail];
  521.                 Inc(TransmitTail);
  522.                 If TransmitTail = TransmitSize Then TransmitTail := 0;
  523.               End Else AwaitingCh := True;
  524.             End;
  525.             $00 : Begin { Modem status change }
  526.               ModemStatus := Port[BasePort+MSR];
  527.               AwaitingCts := WaitForCts And ((ModemStatus And MSRcts) = 0);
  528.               AwaitingDsr := WaitForDsr And ((ModemStatus And MSRdsr) = 0);
  529.               AwaitingCd := WaitForCd And ((ModemStatus And MSRcd) = 0);
  530.               If (AwaitingCts Or AwaitingDsr Or AwaitingCd Or AwaitingXon)
  531.                 Then TransmitEnabled := False
  532.                 Else If Not TransmitEnabled Then EnableTransmit(ComPort);
  533.               If ModemRoutine <> Nil Then CallFar(ComPort, ModemRoutine);
  534.             End;
  535.             Else done := True;
  536.           End;
  537.         Until done;
  538.       End;
  539.       Inc(i);
  540.       If i > UseCount Then i := 1;
  541.     Until i = NextPort;
  542.   End;
  543.   DisableInterrupts;
  544.   Port[$20] := $20; { Non-specific EOI to 8259 }
  545. End;  { AsyncISR }
  546.  
  547. { One of these should exist for each element of VectorSave above. }
  548. { These are are the actual interrupt routines referenced in OpenPort below }
  549. Procedure AsyncISR1; Interrupt; Begin AsyncISR(1); End;
  550. Procedure AsyncISR2; Interrupt; Begin AsyncISR(2); End;
  551. Procedure AsyncISR3; Interrupt; Begin AsyncISR(3); End;
  552. Procedure AsyncISR4; Interrupt; Begin AsyncISR(4); End;
  553.  
  554. Procedure ClosePort(ComPort : Word);
  555. { Release async port }
  556. Var
  557.   Timer : LongInt;
  558.   i, LastTail : Word;
  559. Begin { ClosePort }
  560.   With AsyncPort[ComPort] Do Begin
  561.     If PortOpen Then Begin
  562.       { Allow transmit buffer to empty }
  563.       Timer := TimeoutMilliseconds;
  564.       LastTail := TransmitTail;
  565.       While (TransmitHead <> TransmitTail) And (Timer > 0) Do Begin
  566.         Dec(Timer);
  567.         Delay(1);
  568.         If LastTail <> TransmitTail Then Begin
  569.           LastTail := TransmitTail;
  570.           Timer := TimeoutMilliseconds;
  571.         End;
  572.       End;
  573.       If Timer = 0 Then Begin
  574.         LineStatus := LSRTimeout;
  575.         If ErrorRoutine <> Nil Then CallFar(ComPort, ErrorRoutine);
  576.       End;
  577.  
  578.       Port[BasePort+IER] := 0; { Disable 8250 interrupts }
  579.       Port[BasePort+MCR] := 0; { All modem signals off }
  580.       With VectorSave[VectorIndex] Do Begin
  581.         i := 0;
  582.         Repeat Inc(i) Until (i >= UseCount) Or (PortList[i] = ComPort);
  583.         PortList[i] := PortList[UseCount];
  584.         Dec(UseCount);
  585.         If UseCount = 0 Then Begin { No more ports using this irq }
  586.           Port[$21] := Port[$21] Or (1 Shl IrqNumber);
  587.           SetIntVec(IntrptNo, Vector);
  588.         End;
  589.       End;
  590.       { Free buffers }
  591.       If ReleaseReceive Then Begin
  592.         FreeMem(ReceiveBuffer, ReceiveSize);
  593.         ReceiveBuffer := Nil;
  594.       End;
  595.       If ReleaseTransmit Then Begin
  596.         FreeMem(TransmitBuffer, TransmitSize);
  597.         TransmitBuffer := Nil;
  598.       End;
  599.       PortOpen := False;
  600.     End;
  601.   End;
  602. End;  { ClosePort }
  603.  
  604. Function OpenPort(ComPort : Word;     { Com port number, 1..4 }
  605.                   BaudRate : LongInt; { BPS, 50..115200 }
  606.                   WordLength : Word;  { 5..8 bits }
  607.                   StopBits : Word;    { 1..2 stop bits }
  608.                   Parity : Char       { N,E,O,1,0 }
  609.                   ) : Boolean;        { Return True if open successful }
  610. { Prepare port for communications }
  611. Var
  612.   BaudDivisor : Word;
  613.   Work, FreeSave : Byte;
  614. Begin { OpenPort }
  615.   If (ComPort < 1) Or (ComPort > MaxPorts) Then PortOpenError := 1
  616.   Else With AsyncPort[ComPort] Do Begin
  617.     If PortOpen Then ClosePort(ComPort) Else Begin { Precautionary... }
  618.       Port[BasePort+IER] := 0; { disable 8250 interrupts }
  619.       Port[BasePort+MCR] := 0; { all modem control signals off }
  620.     End;
  621.     PortOpenError := 0;
  622.     Parity := UpCase(Parity);
  623.  
  624.     If (BaudRate < 50) Or (BaudRate > 115200) Then PortOpenError := 2
  625.     Else If (WordLength < 5) Or (WordLength > 8) Then PortOpenError := 3
  626.     Else If (StopBits < 1) Or (StopBits > 2) Then PortOpenError := 4
  627.     Else If Not (Parity In ['N','E','O','1','0']) Then PortOpenError := 5
  628.     Else If (ReceiveSize < 2 ) Or (ReceiveSize > 32767)
  629.          Or (TransmitSize < 2) Or (TransmitSize > 32767)
  630.     Then PortOpenError := 6 Else Begin
  631.       ReleaseReceive := False;
  632.       ReleaseTransmit := False;
  633.       If ReceiveBuffer = Nil Then Begin
  634.         If MaxAvail < ReceiveSize Then PortOpenError := 7 Else Begin
  635.           GetMem(ReceiveBuffer, ReceiveSize);
  636.           ReleaseReceive := True;
  637.         End;
  638.       End;
  639.       If TransmitBuffer = Nil Then Begin
  640.         If MaxAvail < TransmitSize Then PortOpenError := 7 Else
  641.           ReleaseTransmit := True;
  642.       End;
  643.       If ReleaseReceive Then Begin
  644.         FreeMem(ReceiveBuffer, ReceiveSize);
  645.         ReceiveBuffer := Nil;
  646.       End;
  647.     End;
  648.  
  649.     If (PortOpenError = 0) And ((Port[BasePort+IIR] And $F8) <> 0) Then
  650.       PortOpenError := 8;
  651.  
  652.     If PortOpenError = 0 Then Begin
  653.       { Get buffers }
  654.       If ReceiveBuffer = Nil Then GetMem(ReceiveBuffer, ReceiveSize);
  655.       ReceiveHead := 0;
  656.       ReceiveTail := 0;
  657.       If TransmitBuffer = Nil Then GetMem(TransmitBuffer, TransmitSize);
  658.       TransmitHead := 0;
  659.       TransmitTail := 0;
  660.  
  661.       { Set baud rate }
  662.       BaudDivisor := BaudRateDividend Div BaudRate;
  663.       Port[BasePort+LCR] := $80;
  664.       Port[BasePort+DLM] := Hi(BaudDivisor);
  665.       Port[BasePort+DLL] := Lo(BaudDivisor);
  666.  
  667.       { Set Word Length, Stop Bits, Parity }
  668.       Work := WordLength - 5;
  669.       If StopBits = 2 Then Work := Work Or $04;
  670.       Case Parity Of
  671.         'N' : ;
  672.         'O' : Work := Work Or $08;
  673.         'E' : Work := Work Or $18;
  674.         '1' : Work := Work Or $28;
  675.         '0' : Work := Work Or $38;
  676.       End;
  677.       Port[BasePort+LCR] := Work;
  678.  
  679.       { Read registers to reset pending conditions }
  680.       LineStatus := Port[BasePort+LSR];
  681.       ModemStatus := Port[BasePort+MSR];
  682.       Work := Port[BasePort+RBR];
  683.  
  684.       AwaitingXon := False;
  685.       AwaitingCh := True;
  686.       SenderEnabled := True;
  687.  
  688.       { Set interrupts }
  689.       FreeSave := 0;
  690.       VectorIndex := 1;
  691.       While (VectorIndex <= MaxPorts)
  692.       And
  693.       (
  694.         (VectorSave[VectorIndex].UseCount = 0)
  695.         Or
  696.         (VectorSave[VectorIndex].IntrptNo <> IntNumber)
  697.       ) Do Begin
  698.         If (FreeSave = 0) And (VectorSave[VectorIndex].UseCount = 0) Then
  699.           FreeSave := VectorIndex;
  700.         Inc(VectorIndex);
  701.       End;
  702.       If VectorIndex <= MaxPorts Then With VectorSave[VectorIndex] Do Begin
  703.         DisableInterrupts;
  704.         Inc(UseCount);
  705.         PortList[UseCount] := ComPort;
  706.       End
  707.       Else If FreeSave = 0 Then PortOpenError := 9 { This should never happen }
  708.       Else With VectorSave[FreeSave] Do Begin { Save old vector }
  709.         VectorIndex := FreeSave;
  710.         UseCount := 1;
  711.         PortList[1] := ComPort;
  712.         IntrptNo := IntNumber;
  713.         GetIntVec(IntrptNo, Vector);
  714.         Case VectorIndex Of
  715.           1 : SetIntVec(IntrptNo, @AsyncISR1);
  716.           2 : SetIntVec(IntrptNo, @AsyncISR2);
  717.           3 : SetIntVec(IntrptNo, @AsyncISR3);
  718.           4 : SetIntVec(IntrptNo, @AsyncISR4);
  719.           Else PortOpenError := 9; { This shouldn't happen }
  720.         End;
  721.         Port[$21] := Port[$21] And Not (1 Shl IrqNumber);
  722.       End;
  723.       PortOpen := True;
  724.       Port[BasePort+MCR] := MCRout2+MCRrts+MCRdtr;
  725.       Port[BasePort+IER] := $0F; { Enable 8250 interrupts }
  726.       EnableInterrupts;
  727.       AwaitingCts := WaitForCts And ((ModemStatus And MSRcts) = 0);
  728.       AwaitingDsr := WaitForDsr And ((ModemStatus And MSRdsr) = 0);
  729.       AwaitingCd := WaitForCd And ((ModemStatus And MSRcd) = 0);
  730.       TransmitEnabled := Not (AwaitingCts Or AwaitingDsr Or AwaitingCd);
  731.     End;
  732.     OpenPort := PortOpen And (PortOpenError = 0);
  733.   End;
  734. End;  { OpenPort }
  735.  
  736. Function SendPort(ComPort : Word; Ch : Char ) : Boolean;
  737. { Send a character (or place in transmit buffer).  Return true if successful }
  738. Var
  739.   Timer : LongInt;
  740.   next : Word;
  741. Begin { SendPort }
  742.   With AsyncPort[ComPort] Do Begin
  743.     SendPort := False;
  744.     Timer := TimeoutMilliseconds;
  745.     next := Succ(TransmitHead);
  746.     If next = TransmitSize Then next := 0;
  747.     While (next = TransmitTail) And (Timer > 0) Do Begin
  748.       Delay(1);
  749.       Dec(Timer);
  750.     End;
  751.     If Timer > 0 Then Begin
  752.       DisableInterrupts;
  753.       If TransmitEnabled And AwaitingCh Then Begin
  754.         Port[BasePort+THR] := Ord(Ch);
  755.         AwaitingCh := False;
  756.       End Else Begin
  757.         TransmitBuffer^[TransmitHead] := Ord(Ch);
  758.         TransmitHead := next;
  759.       End;
  760.       EnableInterrupts;
  761.       SendPort := True;
  762.     End Else Begin
  763.       LineStatus := LSRTimeout;
  764.       If ErrorRoutine <> Nil Then CallFar(ComPort, ErrorRoutine);
  765.     End;
  766.   End;
  767. End;  { SendPort }
  768.  
  769. Function BlockSendPort(ComPort : Word; Var Block; BlkLen : Word) : Word;
  770. { Move a block of characters to the buffer; returns number of characters
  771.   inserted in buffer.  This function does not wait for buffer space to become
  772.   available - it always returns immediately. }
  773. Var
  774.   next, first, second, len : Word;
  775.   blk : AsyncBuffer Absolute Block;
  776. Begin { BlockSendPort }
  777.   With AsyncPort[ComPort] Do Begin
  778.     BlockSendPort := 0;
  779.     If BlkLen > 0 Then Begin
  780.       DisableInterrupts;
  781.       If TransmitTail > TransmitHead Then Begin
  782.         first := TransmitTail - TransmitHead - 1;
  783.         second := 0;
  784.       End Else Begin
  785.         first := TransmitSize - TransmitHead;
  786.         second := TransmitTail;
  787.         If TransmitTail = 0 Then Dec(first) Else Dec(second);
  788.       End;
  789.       EnableInterrupts;
  790.       len := BlkLen;
  791.       next := TransmitHead;
  792.       If first > 0 Then Begin
  793.         If first > len Then first := len;
  794.         Move(Blk, TransmitBuffer^[TransmitHead], first);
  795.         len := len - first;
  796.         next := TransmitHead + first;
  797.         If next >= TransmitSize Then next := 0;
  798.       End;
  799.       If (len > 0) And (second > 0) Then Begin
  800.         If second > len Then second := len;
  801.         Move(Blk[first], TransmitBuffer^, second);
  802.         len := len - second;
  803.         next := second;
  804.       End;
  805.       TransmitHead := next;
  806.       BlockSendPort := BlkLen - len;
  807.       If TransmitEnabled Then Begin { JumpStart the interrupt }
  808.         DisableInterrupts;
  809.         If AwaitingCh And (TransmitHead <> TransmitTail) Then Begin
  810.           Port[BasePort+THR] := TransmitBuffer^[TransmitTail];
  811.           TransmitTail := Succ(TransmitTail);
  812.           If TransmitTail = TransmitSize Then TransmitTail := 0;
  813.           AwaitingCh := False;
  814.         End;
  815.         EnableInterrupts;
  816.       End;
  817.     End;
  818.   End;
  819. End;  { BlockSendPort }
  820.  
  821. Function BlockSendPortWait(ComPort : Word; Var Block; BlkLen : Word) : Word;
  822. { Send a block of characters; return the number of characters sent.  This
  823.   function will wait TimeoutMilliseconds between characters sent if not enough
  824.   buffer space is available. }
  825. Var
  826.   Blk : AsyncBuffer Absolute Block;
  827.   i, j : Word;
  828.   Timer : LongInt;
  829. Begin { BlockSendPortWait }
  830.   With AsyncPort[ComPort] Do Begin
  831.     BlockSendPortWait := 0;
  832.     Timer := TimeoutMilliseconds;
  833.     i := 0;
  834.     While (BlkLen > 0) And (Timer > 0) Do Begin
  835.       j := BlockSendPort(ComPort, Blk[i], BlkLen);
  836.       If j > 0 Then Begin
  837.         i := i + j;
  838.         BlkLen := BlkLen - j;
  839.         Timer := TimeoutMilliseconds;
  840.       End Else Begin
  841.         Dec(Timer);
  842.         Delay(1);
  843.       End;
  844.     End;
  845.     If Timer = 0 Then Begin
  846.       LineStatus := LSRTimeout;
  847.       If ErrorRoutine <> Nil Then CallFar(ComPort, ErrorRoutine);
  848.     End;
  849.   End;
  850. End;  { BlockSendPortWait }
  851.  
  852. Function PortReady(ComPort : Word) : Boolean;
  853. { Returns True if character waiting in receive buffer or RBR }
  854. Begin { PortReady }
  855.   With AsyncPort[ComPort] Do Begin
  856.     PortReady := ReceiveHead <> ReceiveTail;
  857.   End;
  858. End;  { PortReady }
  859.  
  860. Function ReadPort(ComPort : Word; Var Ch) : Boolean;
  861. { Returns received character from buffer }
  862. Var
  863.   bufused : Word;
  864.   Rch : Byte Absolute Ch;
  865. Begin { ReadPort }
  866.   With AsyncPort[ComPort] Do Begin
  867.     If ReceiveHead = ReceiveTail Then ReadPort := False Else Begin
  868.       Rch := ReceiveBuffer^[ReceiveTail];
  869.       DisableInterrupts;
  870.       Inc(ReceiveTail);
  871.       If ReceiveTail = ReceiveSize Then ReceiveTail := 0;
  872.       EnableInterrupts;
  873.       ReadPort := True;
  874.     End;
  875.     If Not SenderEnabled And (XoHand Or RtsHand Or DtrHand) Then Begin
  876.       DisableInterrupts;
  877.       If ReceiveHead < ReceiveTail Then
  878.         bufused := (ReceiveSize-ReceiveTail)+ReceiveHead
  879.       Else bufused := ReceiveHead-ReceiveTail;
  880.       EnableInterrupts;
  881.       If bufused < (ReceiveSize Shr 1) Then EnableSender(ComPort);
  882.     End;
  883.   End;
  884. End;  { ReadPort }
  885.  
  886. Function BlockReadPort(ComPort : Word; Var Block; BlkLen : Word) : Word;
  887. { Read a block of characters from the port and return number of characters
  888.   read.  This function does not wait for characters to appear in the buffer;
  889.   it transfers any characters which might be present, up to BlkLen, and returns
  890.   the number transferred.}
  891. Var
  892.   Blk : AsyncBuffer Absolute Block;
  893.   first, second, len, bufused, i : Word;
  894. Begin { BlockReadPort }
  895.   With AsyncPort[ComPort] Do Begin
  896.     DisableInterrupts;
  897.     If ReceiveHead < ReceiveTail Then Begin
  898.       first := ReceiveSize - ReceiveTail;
  899.       second := ReceiveHead;
  900.     End Else Begin
  901.       first := ReceiveHead - ReceiveTail;
  902.       second := 0;
  903.     End;
  904.     EnableInterrupts;
  905.     i := 0;
  906.     len := first;
  907.     If len > BlkLen Then len := BlkLen;
  908.     If len > 0 Then Begin
  909.       Move(ReceiveBuffer^[ReceiveTail], Blk, len);
  910.       BlkLen := BlkLen - len;
  911.       i := i + len;
  912.       DisableInterrupts;
  913.       ReceiveTail := ReceiveTail + len;
  914.       If ReceiveTail = ReceiveSize Then ReceiveTail := 0;
  915.       EnableInterrupts;
  916.     End;
  917.     If BlkLen > 0 Then Begin
  918.       len := second;
  919.       If len > BlkLen Then len := BlkLen;
  920.       If len > 0 Then Begin
  921.         Move(ReceiveBuffer^, Blk[i], len);
  922.         i := i + len;
  923.         DisableInterrupts;
  924.         ReceiveTail := ReceiveTail + len;
  925.         EnableInterrupts;
  926.       End;
  927.     End;
  928.     BlockReadPort := i;
  929.     If Not SenderEnabled And (XoHand Or RtsHand Or DtrHand) Then Begin
  930.       DisableInterrupts;
  931.       If ReceiveHead < ReceiveTail Then
  932.         bufused := (ReceiveSize-ReceiveTail)+ReceiveHead
  933.       Else bufused := ReceiveHead-ReceiveTail;
  934.       EnableInterrupts;
  935.       If bufused < (ReceiveSize Shr 1) Then EnableSender(ComPort);
  936.     End;
  937.   End;
  938. End;  { BlockReadPort }
  939.  
  940. Function BlockReadPortDelim(ComPort : Word; Var Block; BlkLen : Word;
  941.   Delim : SetOfChar) : Word;
  942. { Read a block of characters from the port and return number of characters
  943.   read.  This function reads characters from the port until either: 1. BlkLen
  944.   characters have been read; 2. A character appearing in Delim has been read
  945.   (The Delim character appears in the buffer and is included in the count); or
  946.   3. TimeoutMilliseconds has elapsed since the last character received
  947.   (LSRTimeout bit set in LineStatus and ErrorRoutine called if present). }
  948. Var
  949.   Blk : AsyncBuffer Absolute Block;
  950.   Timer : LongInt;
  951.   i : Word;
  952.   ch : Byte;
  953. Begin { BlockReadPortDelim }
  954.   With AsyncPort[ComPort] Do Begin
  955.     i := 0;
  956.     Timer := TimeoutMilliseconds;
  957.     If BlkLen > 0 Then Repeat
  958.       If ReadPort(ComPort, ch) Then Begin
  959.         Blk[i] := Ch;
  960.         Inc(i);
  961.         Timer := TimeoutMilliseconds;
  962.       End Else Begin
  963.         Dec(Timer);
  964.         Delay(1);
  965.       End;
  966.     Until (i >= BlkLen) Or (Timer = 0) Or (Chr(ch) In Delim);
  967.     If Timer = 0 Then Begin
  968.       LineStatus := LSRTimeout;
  969.       If ErrorRoutine <> Nil Then CallFar(ComPort, ErrorRoutine);
  970.     End;
  971.   End;
  972. End;  { BlockReadPortDelim }
  973.  
  974. Procedure SetLoop(ComPort : Word; Loop : Boolean);
  975. { Set LoopBack on/off }
  976. Begin { SetLoop }
  977.   With AsyncPort[ComPort] Do Begin
  978.     If Loop Then
  979.       Port[BasePort+MCR] := Port[BasePort+MCR] Or MCRloop
  980.     Else
  981.       Port[BasePort+MCR] := Port[BasePort+MCR] And Not MCRloop;
  982.   End;
  983. End;  { SetLoop }
  984.  
  985. Procedure SendBreak(ComPort : Word);
  986. { Send break signal }
  987. Var
  988.   Timer : LongInt;
  989.   LastTail : Word;
  990. Begin { SendBreak }
  991.   With AsyncPort[ComPort] Do Begin
  992.     If TransmitSize > 0 Then Begin { Allow transmit buffer to empty }
  993.       Timer := TimeoutMilliseconds;
  994.       LastTail := TransmitTail;
  995.       While (TransmitHead <> TransmitTail) And (Timer > 0) Do Begin
  996.         Dec(Timer);
  997.         Delay(1);
  998.         If LastTail <> TransmitTail Then Begin
  999.           LastTail := TransmitTail;
  1000.           Timer := TimeoutMilliseconds;
  1001.         End;
  1002.       End;
  1003.       If Timer = 0 Then Begin
  1004.         LineStatus := LSRTimeout;
  1005.         If ErrorRoutine <> Nil Then CallFar(ComPort, ErrorRoutine);
  1006.       End;
  1007.     End;
  1008.     Port[BasePort+LCR] := Port[BasePort+LCR] Or $40; { Turn on break }
  1009.     Delay(BreakMiliseconds);
  1010.     Port[BasePort+LCR] := Port[BasePort+LCR] And $BF; { Turn off break }
  1011.   End;
  1012. End;  { SendBreak }
  1013.  
  1014. {$F+} Procedure AsyncExit; {$F-}
  1015. { Exit procedure, close ports }
  1016. Var
  1017.   i : Word;
  1018. Begin { AsyncExit }
  1019.   For i := 1 To MaxPorts Do ClosePort(i);
  1020.   ExitProc := FormerExitProc;
  1021. End;  { AsyncExit }
  1022.  
  1023. Procedure InitializeAsync;
  1024. { Initialize data areas and install exit proc }
  1025. Var
  1026.   i : Word;
  1027. Begin { InitializeAsync }
  1028.   For i := 1 To MaxPorts Do Begin
  1029.     With AsyncPort[i] Do Begin
  1030.       PortOpen := False;
  1031.       IrqNumber := IRQs[i];
  1032.       IntNumber := Interrupts[i];
  1033.       VectorIndex := 0;
  1034.       BasePort := BasePorts[i];
  1035.       LineStatus := 0;
  1036.       ModemStatus := 0;
  1037.       UserData := 0;
  1038.       WaitForXon := False;
  1039.       WaitForCts := False;
  1040.       WaitForDsr := False;
  1041.       WaitForCd := False;
  1042.       RtsHand := True;
  1043.       DtrHand := False;
  1044.       XoHand := False;
  1045.       XoTransparent := True;
  1046.       TransmitEnabled := True;
  1047.       AwaitingXon := False;
  1048.       AwaitingCts := False;
  1049.       AwaitingDsr := False;
  1050.       AwaitingCd := False;
  1051.       AwaitingCh := True;
  1052.       SenderEnabled := True;
  1053.       StreamInsert := 0;
  1054.       ErrorRoutine := Nil;
  1055.       ModemRoutine := Nil;
  1056.       ReceiveBuffer := Nil;
  1057.       ReceiveSize := DefaultBufferSize;
  1058.       ReceiveHead := 0;
  1059.       ReceiveTail := 0;
  1060.       TransmitBuffer := Nil;
  1061.       TransmitSize := DefaultBufferSize;
  1062.       TransmitHead := 0;
  1063.       TransmitTail := 0;
  1064.       ReleaseReceive := True;
  1065.       ReleaseTransmit := True;
  1066.     End;
  1067.     With VectorSave[i] Do Begin
  1068.       UseCount := 0;
  1069.       IntrptNo := 0;
  1070.       Vector := Nil;
  1071.       NextPort := 1;
  1072.     End;
  1073.   End;
  1074.   PortOpenError := 0;
  1075.   FormerExitProc := ExitProc;
  1076.   ExitProc := @AsyncExit;
  1077. End;  { InitializeAsync }
  1078.  
  1079. Begin { Initialization }
  1080.   InitializeAsync;
  1081. End.  { Unit }