home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 December / simtel1292_SIMTEL_1292_Walnut_Creek.iso / msdos / pibterm / pibt41s2.arc / PIBASYN1.MOD < prev    next >
Text File  |  1988-02-19  |  48KB  |  786 lines

  1. (*----------------------------------------------------------------------*)
  2. (*                BIOS_RS232_Init --- Initialize UART                   *)
  3. (*----------------------------------------------------------------------*)
  4.  
  5. PROCEDURE BIOS_RS232_Init( ComPort : INTEGER; ComParm : WORD );
  6.  
  7. (*----------------------------------------------------------------------*)
  8. (*                                                                      *)
  9. (*     Procedure:  BIOS_RS232_Init                                      *)
  10. (*                                                                      *)
  11. (*     Purpose:    Issues interrupt $14 to initialize the UART          *)
  12. (*                                                                      *)
  13. (*     Calling Sequence:                                                *)
  14. (*                                                                      *)
  15. (*        BIOS_RS232_Init( ComPort, ComParm : INTEGER );                *)
  16. (*                                                                      *)
  17. (*           ComPort  --- Communications Port Number (0 thru 3)         *)
  18. (*           ComParm  --- Communications Parameter Word                 *)
  19. (*                                                                      *)
  20. (*      Calls:   INTR   (to perform BIOS interrupt $14)                 *)
  21. (*                                                                      *)
  22. (*----------------------------------------------------------------------*)
  23.  
  24. VAR
  25.    Regs: Registers;
  26.  
  27. BEGIN   (* BIOS_RS232_Init *)
  28.                                    (* Initialize port    *)
  29.    WITH Regs DO
  30.       BEGIN
  31.          Ax := ComParm AND $00FF;  (* AH=0; AL=ComParm   *)
  32.          Dx := ComPort;            (* Port number to use *)
  33.          INTR($14, Regs);
  34.       END;
  35.  
  36. END    (* BIOS_RS232_Init *);
  37.  
  38. (*----------------------------------------------------------------------*)
  39. (*               Async_Isr --- Interrupt Service Routine                *)
  40. (*----------------------------------------------------------------------*)
  41.  
  42. PROCEDURE Async_Isr( Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : WORD );
  43.    Interrupt;
  44.  
  45. (*----------------------------------------------------------------------*)
  46. (*                                                                      *)
  47. (*     Procedure:  Async_Isr                                            *)
  48. (*                                                                      *)
  49. (*     Purpose:    Invoked when serial port interrupt occurs.           *)
  50. (*                                                                      *)
  51. (*     Calling Sequence:                                                *)
  52. (*                                                                      *)
  53. (*        Async_Isr;                                                    *)
  54. (*                                                                      *)
  55. (*           --- Called asynchronously only!!!!!!                       *)
  56. (*                                                                      *)
  57. (*----------------------------------------------------------------------*)
  58.  
  59. BEGIN   (* Async_Isr *)
  60.  
  61. INLINE(
  62.   $FB/                                 {         STI                                ;Allow interrupts}
  63.                                        {;}
  64.                                        {;  Begin major polling loop over pending interrupts.}
  65.                                        {;}
  66.                                        {;  The polling loop is needed because the 8259 cannot handle another 8250}
  67.                                        {;  interrupt while we service this interrupt.  We keep polling here as long}
  68.                                        {;  as an interrupt is received.}
  69.                                        {;}
  70.   $8B/$16/>ASYNC_UART_IIR/             {Poll:    MOV     DX,[>Async_Uart_IIR]       ;Get Interrupt ident register}
  71.   $EC/                                 {         IN      AL,DX                      ;Pick up interrupt type}
  72.                                        {;}
  73.   $A8/$01/                             {         TEST    AL,1                       ;See if any interrupt signalled.}
  74.   $74/$03/                             {         JZ      Polla                      ;Yes --- continue}
  75.   $E9/$B9/$01/                         {         JMP     NEAR Back                  ;No  ---  return to invoker}
  76.                                        {;}
  77.                                        {;  Determine type of interrupt.}
  78.                                        {;  Possibilities:}
  79.                                        {;}
  80.                                        {;     0 = Modem status changed}
  81.                                        {;     2 = Transmit hold register empty (write char)}
  82.                                        {;     4 = Character received from port}
  83.                                        {;     6 = Line status changed}
  84.                                        {;}
  85.   $24/$06/                             {Polla:   AND     AL,6                       ;Strip unwanted bits from interrupt type}
  86.   $3C/$04/                             {         CMP     AL,4                       ;Check if interrupt >= 4}
  87.   $74/$03/                             {         JE      Pollb                      ;}
  88.   $E9/$DB/$00/                         {         JMP     NEAR Int2}
  89.                                        {;}
  90.                                        {;  Write interrupts must be turned on if a higher-priority interrupt}
  91.                                        {;  has been received, else the characters may not be sent (and a lockup}
  92.                                        {;  may occur).}
  93.                                        {;}
  94.   $50/                                 {Pollb:   PUSH    AX                         ;Save interrupt type}
  95.   $E8/$9F/$01/                         {         CALL    EnabWI                     ;Enable write interrupts}
  96.   $58/                                 {         POP     AX                         ;Restore interrupt type}
  97.                                        {;}
  98.                                        {;  --- Received a character ----}
  99.                                        {;}
  100.   $3C/$04/                             {Int4:    CMP     AL,4                       ;Check for received char interrupt}
  101.   $74/$03/                             {         JE      Int4a                      ;Yes -- process it.}
  102.   $E9/$CF/$00/                         {         JMP     NEAR Int2                  ;No -- skip.}
  103.                                        {;}
  104.                                        {;  Read the character from the serial port.}
  105.                                        {;}
  106.   $8B/$16/>ASYNC_BASE/                 {Int4a:   MOV     DX,[>Async_Base]           ;Read character from port}
  107.   $EC/                                 {         IN      AL,DX}
  108.                                        {;}
  109.                                        {;  Check if XON/XOFF honored.  If so, check if incoming character is}
  110.                                        {;  an XON or an XOFF.}
  111.                                        {;}
  112.   $F6/$06/>ASYNC_DO_XONXOFF/$01/       {         TEST    BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF}
  113.   $74/$25/                             {         JZ      Int4d                      ;No -- skip XON/XOFF checks}
  114.                                        {;}
  115.   $3C/<XON/                            {         CMP     AL,<XON                    ;See if XON found}
  116.   $74/$11/                             {         JE      Int4b                      ;Skip if XON found}
  117.   $3C/<XOFF/                           {         CMP     AL,<XOFF                   ;See if XOFF found}
  118.   $75/$1D/                             {         JNE     Int4d                      ;Skip if XOFF not found}
  119.                                        {;}
  120.                                        {;  XOFF received -- set flag indicating sending of chars isn't possible}
  121.                                        {;}
  122.   $C6/$06/>ASYNC_XOFF_RECEIVED/$01/    {         MOV     BYTE [<Async_XOFF_Received],1    ;Turn on received XOFF flag}
  123.   $C6/$06/>ASYNC_XOFF_REC_DISPLAY/$01/ {         MOV     BYTE [<Async_XOFF_Rec_Display],1 ;Turn on display flag}
  124.   $E9/$BE/$FF/                         {         JMP     NEAR Poll}
  125.                                        {;}
  126.                                        {;  XON received -- allow more characters to be sent.}
  127.                                        {;}
  128.   $C6/$06/>ASYNC_XOFF_RECEIVED/$00/    {Int4b:   MOV     BYTE [<Async_XOFF_Received],0   ;Turn off received XOFF flag}
  129.   $C6/$06/>ASYNC_XON_REC_DISPLAY/$01/  {         MOV     BYTE [<Async_XON_Rec_Display],1 ;Turn on display flag}
  130.                                        {;}
  131.   $E8/$69/$01/                         {         CALL    EnabWI                     ;Enable write interrupts}
  132.   $E9/$9B/$00/                         {         JMP     NEAR Int4z}
  133.                                        {;}
  134.                                        {;  Not XON/XOFF -- handle other character.}
  135.                                        {;}
  136.   $F6/$06/>ASYNC_LINE_STATUS/$02/      {Int4d:   TEST    BYTE [>Async_Line_Status],2 ;Check for buffer overrun}
  137.   $74/$03/                             {         JZ      Int4e                       ;Yes --- don't store anything}
  138.   $E9/$91/$00/                         {         JMP     Int4z}
  139.                                        {;}
  140.   $8B/$1E/>ASYNC_BUFFER_HEAD/          {Int4e:   MOV     BX,[>Async_Buffer_Head]    ;Current position in input buffer}
  141.   $C4/$3E/>ASYNC_BUFFER_PTR/           {         LES     DI,[>Async_Buffer_Ptr]     ;Pick up buffer address}
  142.   $01/$DF/                             {         ADD     DI,BX                      ;Update position}
  143.   $26/$88/$05/                         {     ES: MOV     [DI],AL                    ;Store received character in buffer}
  144.   $FF/$06/>ASYNC_BUFFER_USED/          {         INC     WORD [>Async_Buffer_Used]  ;Increment count of chars in buffer}
  145.                                        {;}
  146.   $A1/>ASYNC_BUFFER_USED/              {         MOV     AX,[>Async_Buffer_Used]    ;Pick up buffer usage count}
  147.   $3B/$06/>ASYNC_MAXBUFFERUSED/        {         CMP     AX,[>Async_MaxBufferUsed]  ;See if greater usage than ever before}
  148.   $7E/$03/                             {         JLE     Int4f                      ;Skip if not}
  149.   $A3/>ASYNC_MAXBUFFERUSED/            {         MOV     [>Async_MaxBufferUsed],AX  ;This is greatest use thus far}
  150.                                        {;}
  151.   $43/                                 {Int4f:   INC     BX                         ;Increment buffer pointer}
  152.   $3B/$1E/>ASYNC_BUFFER_SIZE/          {         CMP     BX,[>Async_Buffer_Size]    ;Check if past end of buffer}
  153.   $7E/$02/                             {         JLE     Int4h}
  154.   $31/$DB/                             {         XOR     BX,BX                      ;If so, wrap around to front}
  155.                                        {;}
  156.   $39/$1E/>ASYNC_BUFFER_TAIL/          {Int4h:   CMP     WORD [>Async_Buffer_Tail],BX ;Check for overflow}
  157.   $74/$60/                             {         JE      Int4s                        ;Jump if head ran into tail}
  158.                                        {;}
  159.   $89/$1E/>ASYNC_BUFFER_HEAD/          {         MOV     [>Async_Buffer_Head],BX    ;Update head pointer}
  160.                                        {;}
  161.                                        {;  Check for receive buffer nearly full here.}
  162.                                        {;}
  163.                                        {;  If XON/XOFF available, and buffer getting full, set up to send}
  164.                                        {;  XOFF to remote system.}
  165.                                        {;}
  166.                                        {;  This happens in two possible stages:}
  167.                                        {;}
  168.                                        {;     (1)  An XOFF is sent right when the buffer becomes 'Async_Buffer_High'}
  169.                                        {;          characters full.}
  170.                                        {;}
  171.                                        {;     (2)  A second XOFF is sent right when the buffer becomes}
  172.                                        {;          'Async_Buffer_High_2' characters full;  this case is likely the}
  173.                                        {;          result of the remote not having seen our XOFF because it was}
  174.                                        {;          lost in transmission.}
  175.                                        {;}
  176.                                        {;  If CTS/RTS handshaking, then drop RTS here if buffer nearly full.}
  177.                                        {;  Note that this has to be done even if the XOFF is being sent as well.}
  178.                                        {;}
  179.                                        {;}
  180.                                        {;  Check receive buffer size against first high-water mark.}
  181.                                        {;}
  182.   $3B/$06/>ASYNC_BUFFER_HIGH/          {         CMP     AX,[>Async_Buffer_High]    ;AX still has Async_Buffer_Used}
  183.   $7C/$5B/                             {         JL      Int4z                      ;Not very full, so keep going.}
  184.                                        {;}
  185.                                        {;  Remember if we've already (supposedly) disabled sender.}
  186.                                        {;}
  187.   $8A/$16/>ASYNC_SENDER_ON/            {         MOV     DL,[<Async_Sender_On]      ;Get sender enabled flag.}
  188.                                        {;}
  189.                                        {;  Drop through means receive buffer getting full.}
  190.                                        {;  Check for XON/XOFF.}
  191.                                        {;}
  192.   $F6/$06/>ASYNC_OV_XONXOFF/$01/       {         TEST    BYTE [<Async_OV_XonXoff],1 ;See if we honor XON/XOFF}
  193.                                        {;                                           ; for buffer overflow}
  194.   $74/$1A/                             {         JZ      Int4k                      ;No -- skip XON/XOFF checks}
  195.                                        {;}
  196.                                        {;  Check if we've already sent XOFF.}
  197.                                        {;}
  198.   $F6/$06/>ASYNC_XOFF_SENT/$01/        {         TEST    BYTE [<Async_XOFF_Sent],1  ;Remember if we sent XOFF or not}
  199.   $74/$06/                             {         JZ      Int4j                      ;No -- go send it now.}
  200.                                        {;}
  201.                                        {;  Check against second high-water mark.}
  202.                                        {;  If we are right at it, send an XOFF regardless of whether we've}
  203.                                        {;  already sent one or not.  (Perhaps the first got lost.)}
  204.                                        {;}
  205.   $3B/$06/>ASYNC_BUFFER_HIGH_2/        {         CMP     AX,[>Async_Buffer_High_2]}
  206.   $75/$0D/                             {         JNE     Int4k                      ;Not at 2nd mark -- skip}
  207.                                        {;}
  208.   $C6/$06/>ASYNC_SEND_XOFF/$01/        {Int4j:   MOV     BYTE [<Async_Send_XOFF],1  ;Indicate we need to send XOFF}
  209.   $E8/$06/$01/                         {         CALL    EnabWI                     ;Ensure write interrupts enabled}
  210.   $C6/$06/>ASYNC_SENDER_ON/$00/        {         MOV     BYTE [<Async_Sender_On],0  ;Disable sender}
  211.                                        {;}
  212.                                        {;  Check here if we're doing hardware handshakes.}
  213.                                        {;  Drop RTS if CTS/RTS handshaking.}
  214.                                        {;  Drop DTR if DSR/DTR handshaking.}
  215.                                        {;}
  216.   $F6/$C2/$01/                         {Int4k:   TEST    DL,1                       ;See if sender already disabled}
  217.   $74/$31/                             {         JZ      Int4z                      ;Yes -- skip hardware handshakes.}
  218.                                        {;}
  219.   $30/$E4/                             {         XOR     AH,AH                      ;No hardware handshakes}
  220.                                        {;}
  221.   $F6/$06/>ASYNC_DO_CTS/$01/           {         TEST    BYTE [<Async_Do_CTS],1     ;See if RTS/CTS checking}
  222.   $74/$02/                             {         JZ      Int4l                      ;No -- skip it}
  223.                                        {;}
  224.   $B4/<ASYNC_RTS/                      {         MOV     AH,<Async_RTS              ;Turn on RTS bit}
  225.                                        {;}
  226.   $F6/$06/>ASYNC_DO_DSR/$01/           {Int4l:   TEST    BYTE [<Async_Do_DSR],1     ;See if DSR/DTR checking}
  227.   $74/$03/                             {         JZ      Int4m                      ;No -- skip it}
  228.                                        {;}
  229.   $80/$CC/<ASYNC_DTR/                  {         OR      AH,<Async_DTR              ;Turn on DTR bit}
  230.                                        {;}
  231.   $80/$FC/$00/                         {Int4m:   CMP     AH,0                       ;Any hardware signal?}
  232.   $74/$17/                             {         JZ      Int4z                      ;No -- skip}
  233.                                        {;}
  234.   $8B/$16/>ASYNC_UART_MCR/             {         MOV     DX,[>Async_Uart_MCR]       ;Get modem control register}
  235.   $EC/                                 {         IN      AL,DX}
  236.   $F6/$D4/                             {         NOT     AH                         ;Complement hardware flags}
  237.   $20/$E0/                             {         AND     AL,AH                      ;Nuke RTS/DTR}
  238.   $EE/                                 {         OUT     DX,AL}
  239.                                        {;}
  240.   $C6/$06/>ASYNC_SENDER_ON/$00/        {         MOV     BYTE [<Async_Sender_On],0  ;Indicate sender disabled}
  241.   $E9/$05/$00/                         {         JMP     Int4z}
  242.                                        {;}
  243.                                        {;  If we come here, then the input buffer has overflowed.}
  244.                                        {;  Characters will be thrown away until the buffer empties at least one slot.}
  245.                                        {;}
  246.   $80/$0E/>ASYNC_LINE_STATUS/$02/      {Int4s:   OR      BYTE PTR [>Async_Line_Status],2 ;Flag overrun}
  247.                                        {;}
  248.   $E9/$10/$FF/                         {Int4z:   JMP     NEAR Poll}
  249.                                        {;}
  250.                                        {;  --- Write a character ---}
  251.                                        {;}
  252.   $3C/$02/                             {Int2:    CMP     AL,2                       ;Check for THRE interrupt}
  253.   $74/$03/                             {         JE      Int2a                      ;Yes -- process it.}
  254.   $E9/$97/$00/                         {         JMP     NEAR Int6                  ;No -- skip.}
  255.                                        {;}
  256.                                        {;  Check first if we need to send an XOFF to remote system.}
  257.                                        {;}
  258.   $F6/$06/>ASYNC_SEND_XOFF/$01/        {Int2a:   TEST    BYTE [<Async_Send_Xoff],1  ;See if we are sending XOFF}
  259.   $74/$34/                             {         JZ      Int2d                      ;No -- skip it}
  260.                                        {;}
  261.                                        {;  Yes, we are to send XOFF to remote.}
  262.                                        {;}
  263.                                        {;  First, check DSR and CTS as requested.}
  264.                                        {;  If those status lines aren't ready, turn off write interrupts and}
  265.                                        {;  try later, after a line status change.}
  266.                                        {;}
  267.   $F6/$06/>ASYNC_DO_DSR/$01/           {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  268.   $74/$09/                             {         JZ      Int2b                      ;No -- skip it}
  269.                                        {;}
  270.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  271.   $EC/                                 {         IN      AL,DX}
  272.   $A8/<ASYNC_DSR/                      {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  273.   $74/$2E/                             {         JZ      Int2e                      ;If not DSR, turn off write interrupts}
  274.                                        {;}
  275.   $F6/$06/>ASYNC_DO_CTS/$01/           {Int2b:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  276.   $74/$09/                             {         JZ      Int2c                      ;No -- skip it}
  277.                                        {;}
  278.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  279.   $EC/                                 {         IN      AL,DX}
  280.   $A8/<ASYNC_CTS/                      {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  281.   $74/$1E/                             {         JZ      Int2e                      ;If not CTS, turn off write ints}
  282.                                        {;}
  283.                                        {;  All status lines look OK.}
  284.                                        {;  Send the XOFF.}
  285.                                        {;}
  286.   $B0/<XOFF/                           {Int2c:   MOV     AL,<XOFF                   ;Get XOFF Character}
  287.   $8B/$16/>ASYNC_BASE/                 {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  288.   $EE/                                 {         OUT     DX,AL                      ;Output the XOFF}
  289.   $C6/$06/>ASYNC_SEND_XOFF/$00/        {         MOV     BYTE [<Async_Send_XOFF],0  ;Turn off send XOFF flag}
  290.   $C6/$06/>ASYNC_XOFF_SENT/$01/        {         MOV     BYTE [<Async_XOFF_Sent],1  ;Turn on sent XOFF flag}
  291.   $E9/$CE/$FE/                         {         JMP     NEAR Poll                  ;Return}
  292.                                        {;}
  293.                                        {;  Not sending XOFF -- see if any character in buffer to be sent.}
  294.                                        {;}
  295.   $8B/$1E/>ASYNC_OBUFFER_TAIL/         {Int2d:   MOV     BX,[>Async_OBuffer_Tail]   ;Pick up output buffer pointers}
  296.   $3B/$1E/>ASYNC_OBUFFER_HEAD/         {         CMP     BX,[>Async_OBuffer_Head]}
  297.   $75/$0B/                             {         JNE     Int2m                      ;Skip if not equal --> something to send}
  298.                                        {;}
  299.                                        {;  If nothing to send, turn off write interrupts to avoid unnecessary}
  300.                                        {;  time spent handling useless THRE interrupts.}
  301.                                        {;}
  302.   $8B/$16/>ASYNC_UART_IER/             {Int2e:   MOV     DX,[>Async_Uart_IER]       ;If nothing -- or can't -- send ...}
  303.   $EC/                                 {         IN      AL,DX                      ;}
  304.   $24/$FD/                             {         AND     AL,$FD                     ;}
  305.   $EE/                                 {         OUT     DX,AL                      ;... disable write interrupts}
  306.   $E9/$B9/$FE/                         {         JMP     NEAR Poll                  ;}
  307.                                        {;}
  308.                                        {;  If something to send, ensure that remote system didn't send us XOFF.}
  309.                                        {;  If it did, we can't send anything, so turn off write interrupts and}
  310.                                        {;  wait for later (after an XON has been received).}
  311.                                        {;}
  312.   $F6/$06/>ASYNC_XOFF_RECEIVED/$01/    {Int2m:   TEST    BYTE [<Async_XOFF_Received],1 ;See if we received XOFF}
  313.   $75/$EE/                             {         JNZ     Int2e                      ;Yes -- can't send anything now}
  314.                                        {;}
  315.                                        {;  If we can send character, check DSR and CTS as requested.}
  316.                                        {;  If those status lines aren't ready, turn off write interrupts and}
  317.                                        {;  try later, after a line status change.}
  318.                                        {;}
  319.   $8B/$16/>ASYNC_UART_MSR/             {         MOV     DX,[>Async_Uart_MSR]       ;Otherwise get modem status}
  320.   $EC/                                 {         IN      AL,DX}
  321.   $A2/>ASYNC_MODEM_STATUS/             {         MOV     [>Async_Modem_Status],AL   ;and save modem status for later}
  322.                                        {;}
  323.   $F6/$06/>ASYNC_DO_DSR/$01/           {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  324.   $74/$04/                             {         JZ      Int2n                      ;No -- skip it}
  325.                                        {;}
  326.   $A8/<ASYNC_DSR/                      {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  327.   $74/$DB/                             {         JZ      Int2e                      ;If not DSR, turn off write ints}
  328.                                        {;}
  329.   $F6/$06/>ASYNC_DO_CTS/$01/           {Int2n:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  330.   $74/$04/                             {         JZ      Int2o                      ;No -- skip it}
  331.                                        {;}
  332.   $A8/<ASYNC_CTS/                      {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  333.   $74/$D0/                             {         JZ      Int2e                      ;If not CTS, turn off write ints}
  334.                                        {;}
  335.                                        {;  Everything looks OK for sending, so send the character.}
  336.                                        {;}
  337.   $C4/$3E/>ASYNC_OBUFFER_PTR/          {Int2o:   LES     DI,[>Async_OBuffer_Ptr]    ;Get output buffer pointer}
  338.   $01/$DF/                             {         ADD     DI,BX                      ;Position to character to output}
  339.   $26/$8A/$05/                         {     ES: MOV     AL,[DI]                    ;Get character to output}
  340.   $8B/$16/>ASYNC_BASE/                 {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  341.   $EE/                                 {         OUT     DX,AL                      ;Output the character}
  342.                                        {;}
  343.   $FF/$0E/>ASYNC_OBUFFER_USED/         {         DEC     WORD [>Async_OBuffer_Used] ;Decrement count of chars in buffer}
  344.   $43/                                 {         INC     BX                         ;Increment tail pointer}
  345.   $3B/$1E/>ASYNC_OBUFFER_SIZE/         {         CMP     BX,[>Async_OBuffer_Size]   ;See if past end of buffer}
  346.   $7E/$02/                             {         JLE     Int2z}
  347.   $31/$DB/                             {         XOR     BX,BX                      ;If so, wrap to front}
  348.                                        {;}
  349.   $89/$1E/>ASYNC_OBUFFER_TAIL/         {Int2z:   MOV     [>Async_OBuffer_Tail],BX   ;Store updated buffer tail}
  350.   $E9/$72/$FE/                         {         JMP     NEAR Poll}
  351.                                        {;}
  352.                                        {;  --- Line status change ---}
  353.                                        {;}
  354.   $3C/$06/                             {Int6:    CMP     AL,6                       ;Check for line status interrupt}
  355.   $75/$11/                             {         JNE     Int0                       ;No -- skip.}
  356.                                        {;}
  357.   $8B/$16/>ASYNC_UART_LSR/             {         MOV     DX,[>Async_Uart_LSR]       ;Yes -- pick up line status register}
  358.   $EC/                                 {         IN      AL,DX                      ;and its contents}
  359.   $24/$1E/                             {         AND     AL,$1E                     ;Strip unwanted bits}
  360.   $A2/>ASYNC_LINE_STATUS/              {         MOV     [>Async_Line_Status],AL    ;Store for future reference}
  361.   $08/$06/>ASYNC_LINE_ERROR_FLAGS/     {         OR      [>Async_Line_Error_Flags],AL ;Add to any past transgressions}
  362.   $E9/$5D/$FE/                         {         JMP     NEAR Poll}
  363.                                        {;}
  364.                                        {;  --- Modem status change ---}
  365.                                        {;}
  366.   $3C/$00/                             {Int0:    CMP     AL,0                       ;Check for modem status change}
  367.   $74/$03/                             {         JE      Int0a                      ;Yes -- handle it}
  368.   $E9/$56/$FE/                         {         JMP     NEAR Poll                  ;Else get next interrupt}
  369.                                        {;}
  370.   $8B/$16/>ASYNC_UART_MSR/             {Int0a:   MOV     DX,[>Async_Uart_MSR]       ;Pick up modem status reg. address}
  371.   $EC/                                 {         IN      AL,DX                      ;and its contents}
  372.   $A2/>ASYNC_MODEM_STATUS/             {         MOV     [>Async_Modem_Status],AL   ;Store for future reference}
  373.   $E8/$03/$00/                         {         CALL    EnabWI                     ;Turn on write interrupts, in case}
  374.                                        {;                                           ;status change resulted from CTS/DSR}
  375.                                        {;                                           ;changing state.}
  376.   $E9/$48/$FE/                         {         JMP     NEAR Poll}
  377.                                        {;}
  378.                                        {;  Internal subroutine to enable write interrupts.}
  379.                                        {;}
  380.                                        {EnabWI: ;PROC    NEAR}
  381.   $8B/$16/>ASYNC_UART_IER/             {         MOV     DX,[>Async_Uart_IER]       ;Get interrupt enable register}
  382.   $EC/                                 {         IN      AL,DX                      ;Check contents of IER}
  383.   $A8/$02/                             {         TEST    AL,2                       ;See if write interrupt enabled}
  384.   $75/$03/                             {         JNZ     EnabRet                    ;Skip if so}
  385.   $0C/$02/                             {         OR      AL,2                       ;Else enable write interrupts ...}
  386.   $EE/                                 {         OUT     DX,AL                      ;... by rewriting IER contents}
  387.   $C3/                                 {EnabRet: RET                                ;Return to caller}
  388.                                        {;}
  389.                                        {;  Send non-specific EOI to 8259 controller.}
  390.                                        {;}
  391.   $B0/$20/                             {Back:    MOV     AL,$20                     ;EOI = $20}
  392.   $E6/$20);                            {         OUT     $20,AL}
  393.  
  394. END;
  395.  
  396. (*----------------------------------------------------------------------*)
  397. (*               Async_Close --- Close down communications interrupts   *)
  398. (*----------------------------------------------------------------------*)
  399.  
  400. PROCEDURE Async_Close( Drop_DTR: BOOLEAN );
  401.  
  402. (*----------------------------------------------------------------------*)
  403. (*                                                                      *)
  404. (*     Procedure:  Async_Close                                          *)
  405. (*                                                                      *)
  406. (*     Purpose:    Resets interrupt system when UART interrupts         *)
  407. (*                 are no longer needed.                                *)
  408. (*                                                                      *)
  409. (*     Calling Sequence:                                                *)
  410. (*                                                                      *)
  411. (*        Async_Close( Drop_DTR : BOOLEAN );                            *)
  412. (*                                                                      *)
  413. (*           Drop_DTR --- TRUE to drop DTR when closing down port       *)
  414. (*                                                                      *)
  415. (*     Calls:  None                                                     *)
  416. (*                                                                      *)
  417. (*----------------------------------------------------------------------*)
  418.  
  419. VAR
  420.    I : INTEGER;
  421.    M : INTEGER;
  422.  
  423. BEGIN  (* Async_Close *)
  424.  
  425.    IF Async_Open_Flag THEN
  426.       BEGIN
  427.  
  428.                      (* disable the IRQ on the 8259 *)
  429.  
  430.          INLINE($FA);                 (* disable interrupts *)
  431.  
  432.          I := Port[I8088_IMR];        (* get the interrupt mask register *)
  433.          M := 1 SHL Async_Irq;        (* set mask to turn off interrupt  *)
  434.          Port[I8088_IMR] := I OR M;
  435.  
  436.                      (* disable the 8250 interrupts *)
  437.  
  438.          Port[UART_IER + Async_Base] := 0;
  439.  
  440.                      (* Disable OUT2, RTS, OUT1 on the 8250, but *)
  441.                      (* possibly leave DTR enabled.              *)
  442.  
  443.          IF Drop_Dtr THEN
  444.             Port[UART_MCR + Async_Base] := 0
  445.          ELSE
  446.             Port[UART_MCR + Async_Base] := 1;
  447.  
  448.          INLINE($FB);                 (* enable interrupts *)
  449.  
  450.                      (* re-initialize our data areas so we know *)
  451.                      (* the port is closed                      *)
  452.  
  453.          Async_Open_Flag := FALSE;
  454.          Async_XOFF_Sent := FALSE;
  455.          Async_Sender_On := FALSE;
  456.  
  457.                      (* Restore the previous interrupt pointers *)
  458.  
  459.          SetIntVec( Async_Int , Async_Save_Iaddr );
  460.  
  461.       END;
  462.  
  463. END    (* Async_Close *);
  464.  
  465. (*----------------------------------------------------------------------*)
  466. (*    Async_Clear_Errors --- Reset pending errors in async port         *)
  467. (*----------------------------------------------------------------------*)
  468.  
  469. PROCEDURE Async_Clear_Errors;
  470.  
  471. (*----------------------------------------------------------------------*)
  472. (*                                                                      *)
  473. (*     Procedure:   Async_Clear_Errors                                  *)
  474. (*                                                                      *)
  475. (*     Purpose:     Resets pending errors in async port                 *)
  476. (*                                                                      *)
  477. (*     Calling sequence:                                                *)
  478. (*                                                                      *)
  479. (*        Async_Clear_Errors;                                           *)
  480. (*                                                                      *)
  481. (*     Calls:  None                                                     *)
  482. (*                                                                      *)
  483. (*----------------------------------------------------------------------*)
  484.  
  485. VAR
  486.    I:  INTEGER;
  487.    M:  INTEGER;
  488.  
  489. BEGIN (* Async_Clear_Errors *)
  490.  
  491.                    (* Read the RBR and reset any pending error conditions. *)
  492.                    (* First turn off the Divisor Access Latch Bit to allow *)
  493.                    (* access to RBR, etc.                                  *)
  494.  
  495.    INLINE($FA);  (* disable interrupts *)
  496.  
  497.    Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] AND $7F;
  498.  
  499.                    (* Read the Line Status Register to reset any errors *)
  500.                    (* it indicates                                      *)
  501.  
  502.    I := Port[UART_LSR + Async_Base];
  503.  
  504.                    (* Read the Receiver Buffer Register in case it *)
  505.                    (* contains a character                         *)
  506.  
  507.    I := Port[UART_RBR + Async_Base];
  508.  
  509.                    (* enable the irq on the 8259 controller *)
  510.  
  511.    I := Port[I8088_IMR];  (* get the interrupt mask register *)
  512.    M := (1 SHL Async_Irq) XOR $00FF;
  513.  
  514.    Port[I8088_IMR] := I AND M;
  515.  
  516.                    (* enable OUT2 on 8250 *)
  517.  
  518.    I := Port[UART_MCR + Async_Base];
  519.    Port[UART_MCR + Async_Base] := I OR $0B;
  520.  
  521.                    (* enable the data ready interrupt on the 8250 *)
  522.  
  523.    Port[UART_IER + Async_Base] := $0F;
  524.  
  525.                    (* Re-enable 8259 *)
  526.  
  527.    Port[$20] := $20;
  528.  
  529.    INLINE($FB); (* enable interrupts *)
  530.  
  531. END   (* Async_Clear_Errors *);
  532.  
  533. (*----------------------------------------------------------------------*)
  534. (*    Async_Reset_Port --- Set/reset communications port parameters     *)
  535. (*----------------------------------------------------------------------*)
  536.  
  537. PROCEDURE Async_Reset_Port( ComPort       : INTEGER;
  538.                             BaudRate      : WORD;
  539.                             Parity        : CHAR;
  540.                             WordSize      : INTEGER;
  541.                             StopBits      : INTEGER );
  542.  
  543. (*----------------------------------------------------------------------*)
  544. (*                                                                      *)
  545. (*     Procedure:   Async_Reset_Port                                    *)
  546. (*                                                                      *)
  547. (*     Purpose:     Resets communications port                          *)
  548. (*                                                                      *)
  549. (*     Calling Sequence:                                                *)
  550. (*                                                                      *)
  551. (*        Async_Reset_Port(   ComPort       : INTEGER;                  *)
  552. (*                            BaudRate      : WORD;                     *)
  553. (*                            Parity        : CHAR;                     *)
  554. (*                            WordSize      : INTEGER;                  *)
  555. (*                            StopBits      : INTEGER);                 *)
  556. (*                                                                      *)
  557. (*           ComPort  --- which port (1, 2, 3, 4)                       *)
  558. (*           BaudRate --- Baud rate (110 to 57600)                      *)
  559. (*           Parity   --- "E" for even, "O" for odd, "N" for none,      *)
  560. (*                        "M" for mark, "S" for space.
  561. (*           WordSize --- Bits per character  (5 through 8)             *)
  562. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  563. (*                                                                      *)
  564. (*     Calls:                                                           *)
  565. (*                                                                      *)
  566. (*        Async_Clear_Errors --- Clear async line errors                *)
  567. (*                                                                      *)
  568. (*----------------------------------------------------------------------*)
  569.  
  570. CONST   (* Baud Rate Constants *)
  571.  
  572.    Async_Num_Bauds = 11;
  573.  
  574.    Async_Baud_Table : ARRAY [1..Async_Num_Bauds] OF RECORD
  575.                                                        Baud, Bits : WORD;
  576.                                                     END
  577.  
  578.                     = ( ( Baud:  110;  Bits: $00 ),
  579.                         ( Baud:  150;  Bits: $20 ),
  580.                         ( Baud:  300;  Bits: $40 ),
  581.                         ( Baud:  600;  Bits: $60 ),
  582.                         ( Baud:  1200; Bits: $80 ),
  583.                         ( Baud:  2400; Bits: $A0 ),
  584.                         ( Baud:  4800; Bits: $C0 ),
  585.                         ( Baud:  9600; Bits: $E0 ),
  586.                         ( Baud: 19200; Bits: $E0 ),
  587.                         ( Baud: 38400; Bits: $E0 ),
  588.                         ( Baud: 57600; Bits: $E0 ) );
  589.  
  590. VAR
  591.    I       : INTEGER;
  592.    M       : INTEGER;
  593.    ComParm : INTEGER;
  594.  
  595. BEGIN (* Async_Reset_Port *)
  596.  
  597.             (*---------------------------------------------------*)
  598.             (*    Build the ComParm for RS232_Init               *)
  599.             (*    See Technical Reference Manual for description *)
  600.             (*---------------------------------------------------*)
  601.  
  602.                                    (* Set up the bits for the baud rate *)
  603.  
  604.    IF ( BaudRate > Async_Baud_Table[Async_Num_Bauds].Baud ) THEN
  605.       BaudRate := Async_Baud_Table[Async_Num_Bauds].Baud
  606.  
  607.    ELSE IF ( BaudRate < Async_Baud_Table[1].Baud ) THEN
  608.       BaudRate := Async_Baud_Table[1].Baud;
  609.  
  610.                                    (* Remember baud rate for purges *)
  611.    Async_Baud_Rate := BaudRate;
  612.  
  613.    I := 0;
  614.  
  615.    REPEAT
  616.       I := I + 1
  617.    UNTIL ( ( I >= Async_Num_Bauds ) OR
  618.            ( BaudRate = Async_Baud_Table[I].Baud ) );
  619.  
  620.    ComParm := Async_Baud_Table[I].Bits;
  621.  
  622.                                    (* Choose Parity.  Temporarily   *)
  623.                                    (* consider mark, space as none. *)
  624.    Parity := UpCase( Parity );
  625.  
  626.    CASE Parity OF
  627.       'E' : ComParm := ComParm OR $0018;
  628.       'O' : ComParm := ComParm OR $0008;
  629.       ELSE ;
  630.    END (* CASE *);
  631.                                    (* Choose number of data bits *)
  632.  
  633.    WordSize := WordSize - 5;
  634.  
  635.    IF ( WordSize < 0 ) OR ( WordSize > 3 ) THEN
  636.       WordSize := 3;
  637.  
  638.    ComParm := ComParm OR WordSize;
  639.  
  640.                                    (* Choose stop bits *)
  641.  
  642.    IF StopBits = 2 THEN
  643.       ComParm := ComParm OR $0004;  (* default is 1 stop bit *)
  644.  
  645.                                    (* Use the BIOS COM port init routine *)
  646.  
  647.    BIOS_RS232_Init( ComPort - 1 , ComParm );
  648.  
  649.                                    (* If > 9600 baud, we have to screw *)
  650.                                    (* around a bit                     *)
  651.  
  652.    IF ( BaudRate >= 19200 ) THEN
  653.       BEGIN
  654.  
  655.          I                             := PORT[ UART_LCR + Async_Base ];
  656.          PORT[ UART_LCR + Async_Base ] := I OR $80;
  657.  
  658.          PORT[ UART_THR + Async_Base ] := 115200 DIV BaudRate;
  659.          PORT[ UART_IER + Async_Base ] := 0;
  660.  
  661.          I                             := PORT[ UART_LCR + Async_Base ];
  662.          PORT[ UART_LCR + Async_Base ] := I AND $7F;
  663.  
  664.       END;
  665.                                    (* Now fix up mark, space parity *)
  666.  
  667.    IF ( ( Parity = 'M' ) OR ( Parity = 'S' ) ) THEN
  668.       BEGIN
  669.  
  670.          I := PORT[ UART_LCR + Async_Base ];
  671.          PORT[ UART_LCR + Async_Base ] := $80;
  672.  
  673.          ComParm := WordSize OR ( ( StopBits - 1 ) SHL 2 );
  674.  
  675.          CASE Parity OF
  676.             'M' : ComParm := ComParm OR $0028;
  677.             'S' : ComParm := ComParm OR $0038;
  678.             ELSE ;
  679.          END (* CASE *);
  680.  
  681.          PORT[ UART_LCR + Async_Base ] := ComParm;
  682.  
  683.       END;
  684.                                    (* Sender is enabled *)
  685.    Async_Sender_On := TRUE;
  686.                                    (* Clear any pending errors on *)
  687.                                    (* async line                  *)
  688.    Async_Clear_Errors;
  689.  
  690. END   (* Async_Reset_Port *);
  691.  
  692. (*----------------------------------------------------------------------*)
  693. (*               Async_Open --- Open communications port                *)
  694. (*----------------------------------------------------------------------*)
  695.  
  696. FUNCTION Async_Open( ComPort       : INTEGER;
  697.                      BaudRate      : WORD;
  698.                      Parity        : CHAR;
  699.                      WordSize      : INTEGER;
  700.                      StopBits      : INTEGER  ) : BOOLEAN;
  701.  
  702. (*----------------------------------------------------------------------*)
  703. (*                                                                      *)
  704. (*     Function:   Async_Open                                           *)
  705. (*                                                                      *)
  706. (*     Purpose:    Opens communications port                            *)
  707. (*                                                                      *)
  708. (*     Calling Sequence:                                                *)
  709. (*                                                                      *)
  710. (*        Flag := Async_Open( ComPort       : INTEGER;                  *)
  711. (*                            BaudRate      : WORD;                     *)
  712. (*                            Parity        : CHAR;                     *)
  713. (*                            WordSize      : INTEGER;                  *)
  714. (*                            StopBits      : INTEGER) : BOOLEAN;       *)
  715. (*                                                                      *)
  716. (*           ComPort  --- which port (1 though 4)                       *)
  717. (*           BaudRate --- Baud rate (110 to 57600)                      *)
  718. (*           Parity   --- "E" for even, "O" for odd, "N" for none,      *)
  719. (*                        "S" for space, "M" for mark.                  *)
  720. (*           WordSize --- Bits per character  (5 through 8)             *)
  721. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  722. (*                                                                      *)
  723. (*           Flag returned TRUE if port initialized successfully;       *)
  724. (*           Flag returned FALSE if any errors.                         *)
  725. (*                                                                      *)
  726. (*     Calls:                                                           *)
  727. (*                                                                      *)
  728. (*        Async_Reset_Port --- initialize RS232 port                    *)
  729. (*        Async_Close      --- close open RS232 port                    *)
  730. (*        SetIntVec        --- set address of RS232 interrupt routine   *)
  731. (*        GetIntVec        --- get address of RS232 interrupt routine   *)
  732. (*                                                                      *)
  733. (*----------------------------------------------------------------------*)
  734.  
  735. BEGIN  (* Async_Open *)
  736.                              (* If port open, close it down first.  *)
  737.    IF Async_Open_Flag THEN
  738.       Async_Close( FALSE );
  739.                              (* Choose communications port *)
  740.  
  741.    IF ( ComPort < 1 ) THEN
  742.       ComPort := 1
  743.    ELSE IF ( ComPort > MaxComPorts ) THEN
  744.       ComPort := MaxComPorts;
  745.  
  746.    Async_Port  := ComPort;
  747.    Async_Base  := Com_Base [ ComPort ];
  748.    Async_Irq   := Com_Irq  [ ComPort ];
  749.    Async_Int   := Com_Int  [ ComPort ];
  750.  
  751.                                    (* Set register pointers for ISR routine *)
  752.  
  753.    Async_Uart_IER  := Async_Base + UART_IER;
  754.    Async_Uart_IIR  := Async_Base + UART_IIR;
  755.    Async_Uart_MSR  := Async_Base + UART_MSR;
  756.    Async_Uart_LSR  := Async_Base + UART_LSR;
  757.    Async_Uart_MCR  := Async_Base + UART_MCR;
  758.  
  759.                                    (* Check if given port installed *)
  760.  
  761.    IF ( Port[UART_IIR + Async_Base] AND $00F8 ) <> 0 THEN
  762.       Async_Open := FALSE          (* Serial port not installed *)
  763.    ELSE
  764.       BEGIN   (* Open the port *)
  765.  
  766.                                    (* Get current interrupt address *)
  767.  
  768.          GetIntVec( Async_Int , Async_Save_Iaddr );
  769.  
  770.                                    (* Set interrupt routine address *)
  771.  
  772.          SetIntVec( Async_Int , @Async_Isr );
  773.  
  774.                                    (* Set up UART                   *)
  775.  
  776.          Async_Reset_Port( ComPort, BaudRate, Parity, WordSize, StopBits );
  777.  
  778.                                    (* Remember that port is open *)
  779.          Async_Open      := TRUE;
  780.          Async_Open_Flag := TRUE;
  781.  
  782.     END;
  783.  
  784. END   (* Async_Open *);
  785.  
  786.