home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / pibasy.zip / PIBASYN1.MOD < prev    next >
Text File  |  1987-11-11  |  44KB  |  738 lines

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