home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / modem / com_pkg2.arc / COM_PKG2.ASM
Assembly Source File  |  1985-10-06  |  30KB  |  964 lines

  1.     TITLE   COM_PKG2 -- Last updated 10/6/85
  2.         PAGE    55,131
  3. ;
  4. ; Communications Package for the IBM PC, XT, AT and PCjr
  5. ; and strict compatibles.
  6. ; May be copied and used freely -- This is a public domain program
  7. ; Developed by Richard Gillmann, John Romkey, Jerry Saltzer,
  8. ; Craig Milo Rogers, Dave Mitton and Larry Afrin.
  9. ;
  10. ; We'd sure like to see any improvements you might make.
  11. ; Please send all comments and queries about this package
  12. ; to GILLMANN@USC-ISIB.ARPA
  13. ;
  14. ; o Supports both serial ports simultaneously
  15. ; o All speeds to 19200 baud
  16. ; o Compatible with PC, XT, AT and PCjr.
  17. ; o Built in XON/XOFF flow control option
  18. ; o Assembly language calling conventions
  19. ; o Logs all comm errors
  20. ; o Direct connect or modem protocol
  21. ;
  22. ; MAXIMUM BUFFER SIZES
  23. R_SIZE    EQU     500        ; SIZE OF RECEIVE BUFFERS
  24. S_SIZE    EQU     100        ; SIZE OF TRANSMIT BUFFERS
  25. ; INTERRUPT NUMBERS
  26. INT_COM1 EQU    0CH        ; COM1: FROM 8259
  27. INT_COM2 EQU    0BH        ; COM2: FROM 8259
  28. ; 8259 PORTS
  29. INTA00  EQU     20H             ; 8259A PORT, A0 = 0
  30. INTA01  EQU     21H             ; 8259A PORT, A0 = 1
  31. ; COM1: LEVEL 4
  32. IRQ4    EQU    2*2*2*2            ; 8259A OCW1 MASK, M4=1, A0=0
  33. NIRQ4    EQU    NOT IRQ4 AND 0FFH    ; COMPLEMENT OF ABOVE
  34. EOI4    EQU    4 OR 01100000B        ; 8259A OCW2 SPECIFIC IRQ4 EOI, A0=0
  35. ; COM2: LEVEL 3
  36. IRQ3    EQU    2*2*2            ; 8259A OCW1 MASK, M3=1, A0=0
  37. NIRQ3    EQU    NOT IRQ3 AND 0FFH    ; COMPLEMENT OF ABOVE
  38. EOI3    EQU    3 OR 01100000B        ; 8259A OCW2 SPECIFIC IRQ3 EOI, A0=0
  39. ; FLOW CONTROL CHARACTERS
  40. CONTROL_Q EQU    11H        ; XON
  41. CONTROL_S EQU    13H        ; XOFF
  42. ; MISC.
  43. DOS    EQU    21H        ; DOS FUNCTION CALLS
  44.     PAGE
  45. ;
  46. ; ROM BIOS Data Area
  47. ;
  48. RBDA    SEGMENT    AT 40H
  49. RS232_BASE DW    4 DUP(?)    ; ADDRESSES OF RS232 ADAPTERS
  50. RBDA    ENDS
  51. ;
  52. ; ROM PC-Type IDENT
  53. ;
  54. ROM    SEGMENT    AT 0F000H
  55.     ORG    0FFFEH
  56. ROMID    DB    ?        ; 0FFH=PC OR EARLY XT, 0FEH=XT, 0FDH=JR
  57. ROM    ENDS
  58.         PAGE
  59. ;
  60. ; TABLE FOR EACH SERIAL PORT
  61. ;
  62. SP_TAB        STRUC
  63. PORT        DB    ?    ; 1 OR 2
  64. ; PARAMETERS FOR THIS INTERRUPT LEVEL
  65. INT_COM        DB    ?    ; INTERRUPT NUMBER
  66. IRQ        DB    ?    ; 8259A OCW1 MASK
  67. NIRQ        DB    ?    ; COMPLEMENT OF ABOVE
  68. EOI        DB    ?    ; 8259A OCW2 SPECIFIC END OF INTERRUPT
  69. ; INTERRUPT HANDLERS FOR THIS LEVEL
  70. INT_HNDLR    DW    ?    ; OFFSET TO INTERRUPT HANDLER
  71. OLD_COM_OFF    DW    ?    ; OLD HANDLER'S OFFSET
  72. OLD_COM_SEG    DW    ?    ; OLD HANDLER'S SEGMENT
  73. ; ATTRIBUTES
  74. INSTALLED    DB    ?    ; IS PORT INSTALLED ON THIS PC? (1=YES,0=NO)
  75. BAUD_RATE    DW    ?    ; 19200 MAX
  76. CONNECTION    DB    ?    ; M(ODEM), D(IRECT)
  77. PARITY        DB    ?    ; N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  78. STOP_BITS    DB    ?    ; 1, 2
  79. XON_XOFF    DB    ?    ; E(NABLED), D(ISABLED)
  80. ; FLOW CONTROL STATE
  81. HOST_OFF    DB    ?    ; HOST XOFF'ED (1=YES,0=NO)
  82. PC_OFF        DB    ?    ; PC XOFF'ED (1=YES,0=NO)
  83. ; ERROR COUNTS
  84. ERROR_BLOCK    DW    8 DUP(?)    ; EIGHT ERROR COUNTERS
  85. ; 8250 PORTS
  86. DATREG        DW    ?    ; DATA REGISTER
  87. IER        DW    ?    ; INTERRUPT ENABLE REGISTER
  88. IIR        DW      ?    ; INTERRUPT IDENTIFICATION REGISTER
  89. LCR        DW      ?    ; LINE CONTROL REGISTER
  90. MCR        DW      ?    ; MODEM CONTROL REGISTER
  91. LSR        DW      ?    ; LINE STATUS REGISTER
  92. MSR        DW      ?    ; MODEM STATUS REGISTER
  93. ; BUFFER POINTERS
  94. START_TDATA     DW      ?       ; INDEX TO FIRST CHARACTER IN X-MIT BUFFER
  95. END_TDATA       DW      ?       ; INDEX TO FIRST FREE SPACE IN X-MIT BUFFER
  96. START_RDATA     DW      ?       ; INDEX TO FIRST CHARACTER IN REC. BUFFER
  97. END_RDATA       DW      ?       ; INDEX TO FIRST FREE SPACE IN REC. BUFFER
  98. ; BUFFER COUNTS
  99. SIZE_TDATA      DW      ?       ; NUMBER OF CHARACTERS IN X-MIT BUFFER
  100. SIZE_RDATA      DW      ?       ; NUMBER OF CHARACTERS IN REC. BUFFER
  101. ; BUFFERS
  102. TDATA           DB      S_SIZE DUP(?)    ; SEND BUFFER
  103. RDATA           DB      R_SIZE DUP(?)    ; RECEIVE BUFFER
  104. SP_TAB        ENDS
  105. ; SP_TAB EQUATES
  106. ; WE HAVE TO USE THESE BECAUSE OF PROBLEMS WITH STRUC
  107. EOVFLOW        EQU    ERROR_BLOCK    ; BUFFER OVERFLOWS
  108. EOVRUN        EQU    ERROR_BLOCK+2    ; RECEIVE OVERRUNS
  109. EBREAK        EQU    ERROR_BLOCK+4    ; BREAK CHARS
  110. EFRAME        EQU    ERROR_BLOCK+6    ; FRAMING ERRORS
  111. EPARITY        EQU    ERROR_BLOCK+8    ; PARITY ERRORS
  112. EXMIT        EQU    ERROR_BLOCK+10    ; TRANSMISSION ERRORS
  113. EDSR        EQU    ERROR_BLOCK+12    ; DATA SET READY ERRORS
  114. ECTS        EQU    ERROR_BLOCK+14    ; CLEAR TO SEND ERRORS
  115. DLL        EQU    DATREG        ; LOW DIVISOR LATCH
  116. DLH        EQU    IER        ; HIGH DIVISOR LATCH
  117.     PAGE
  118. DATA    SEGMENT PUBLIC 'DATA'
  119. DIV50PC        EQU    2304        ; DIVISOR FOR 50 BAUD (PC,XT)
  120. DIV50JR        EQU    2237        ; DIVISOR FOR 50 BAUD (JR)
  121. DIV50        DW    2304        ; ACTUAL DIVISOR FOR 50 BAUD IN USE
  122. CURRENT_AREA    DW    AREA1        ; CURRENTLY SELECTED AREA
  123. ; DATA AREAS FOR EACH PORT
  124. AREA1    SP_TAB    <1,INT_COM1,IRQ4,NIRQ4,EOI4>    ; COM1 DATA AREA
  125. AREA2    SP_TAB    <2,INT_COM2,IRQ3,NIRQ3,EOI3>    ; COM2 DATA AREA
  126. DATA    ENDS
  127.         PAGE
  128. CODE    SEGMENT PARA PUBLIC 'CODE'
  129.         ASSUME  CS:CODE,DS:DATA,ES:NOTHING
  130.  
  131.     PUBLIC    SELECT_PORT    ; SELECT COMMUNICATIONS PORT
  132.     PUBLIC    SAVE_COM    ; SAVE OLD INTERRUPT VECTOR
  133.         PUBLIC  INSTALL_COM     ; INSTALL OUR INTERRUPT VECTOR
  134.         PUBLIC  RESTORE_COM     ; RESTORE OLD INTERRUPT VECTOR
  135.         PUBLIC  OPEN_COM        ; INITIALIZE PORT
  136.         PUBLIC  CLOSE_COM       ; TURN OFF INTERRUPTS FROM COM PORT
  137.         PUBLIC  DTR_OFF         ; TURN OFF DTR
  138.         PUBLIC  DTR_ON          ; TURN ON DTR
  139.         PUBLIC  R_COUNT         ; RETURN NUMBER OF CHARACTERS IN INPUT BUFFER
  140.         PUBLIC  RECEIVE        ; READ NEXT CHARACTER IN INPUT BUFFER
  141.         PUBLIC  S_COUNT         ; RETURN NO. OF FREE BYTES IN OUTPUT BUFFER
  142.         PUBLIC  SEND            ; WRITE A CHARACTER TO OUTPUT BUFFER
  143.     PUBLIC    SENDI        ; WRITE A CHAR TO FRONT OF OUTPUT BUFFER
  144.         PUBLIC  S_LOCAL         ; WRITE A CHARACTER TO THE INPUT BUFFER
  145.         PUBLIC  BREAK           ; SEND A BREAK
  146.     PUBLIC    COM_ERRORS    ; RETURN POINTER TO ERROR COUNTS
  147.     PAGE
  148. ;
  149. ; SELECT WHICH PORT IS TO BE "ACTIVE"
  150. ; AL = PORT NUMBER (1 OR 2)
  151. ;
  152. SELECT_PORT PROC NEAR
  153.     PUSHF            ; SAVE FLAGS
  154.     PUSH    AX        ; SAVE AX
  155.     TEST    AL,1        ; FIRST PORT?
  156.     JZ    SP1        ; IF NOT, IT MUST BE SECOND PORT
  157.     MOV    AX,OFFSET AREA1    ; SELECT COM1 DATA AREA
  158.     JMP    SHORT SPX    ; CONTINUE
  159. SP1:    MOV    AX,OFFSET AREA2    ; SELECT COM2 DATA AREA
  160. SPX:    MOV    CURRENT_AREA,AX    ; SET SELECTION IN MEMORY
  161.     POP    AX        ; RESTORE AX
  162.     POPF            ; RESTORE FLAGS
  163.     RET            ; DONE
  164. SELECT_PORT ENDP
  165.     PAGE
  166. ;
  167. ; SAVE ORIGINAL COM VECTOR
  168. ;
  169. SAVE_COM PROC    NEAR
  170.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  171.     PUSH    ES        ; SAVE EXTRA SEGMENT
  172.     MOV    AREA1.INT_HNDLR,OFFSET INT_HNDLR1
  173.     MOV    AREA2.INT_HNDLR,OFFSET INT_HNDLR2
  174.     MOV    AH,30H        ; GET DOS VERSION NUMBER
  175.     INT    DOS        ; DOS FUNCTION
  176.     CMP    AL,2        ; AT LEAST DOS 2?
  177.     JB    SVC1        ; JUMP IF DOS 1
  178. ; SAVE OLD VECTOR WITH DOS 2 CALLS
  179.     MOV    AH,35H        ; FETCH INTERRUPT VECTOR CONTENTS
  180.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  181.     INT    DOS        ; DOS 2 FUNCTION
  182.     MOV    OLD_COM_OFF[SI],BX    ; SAVE
  183.     MOV    BX,ES            ; ES:BX
  184.     MOV    OLD_COM_SEG[SI],BX    ; FOR LATER RESTORATION
  185.     JMP    SHORT SVCX    ; DONE
  186. ; SAVE OLD VECTOR WITH DOS 1 CALLS
  187. SVC1:    MOV    AX,0        ; ZERO SEGMENT
  188.     MOV    ES,AX        ; ES POINTS TO INTERRUPT VECTORS
  189.     MOV    BL,INT_COM[SI]    ; OUR INTERRUPT NUMBER
  190.     MOV    BH,0        ; BL -> BX
  191.     SHL    BX,1        ; TIMES FOUR
  192.     SHL    BX,1        ; IS OFFSET OF VECTOR IN MEMORY
  193.     MOV    AX,WORD PTR ES:[BX]    ; SAVE
  194.     MOV    OLD_COM_OFF[SI],AX    ; THE
  195.     ADD    BX,2            ; OLD
  196.     MOV    AX,WORD PTR ES:[BX]    ; INTERRUPT
  197.     MOV    OLD_COM_SEG[SI],AX    ; VECTOR
  198. SVCX:    POP    ES        ; RESTORE ES
  199.     RET            ; DONE
  200. SAVE_COM ENDP
  201.     PAGE
  202. ;
  203. ; INSTALL_COM:  INSTALL THE ACTIVE PORT
  204. ;
  205. ; SET 8250 PORTS FROM RS-232 BASE IN ROM BIOS DATA AREA
  206. ; INITIALIZE PORT CONSTANTS AND ERROR COUNTS
  207. ; INSTALL INTERRUPT VECTOR
  208. ;
  209. ; RETURNS WITH CARRY CLEARED UPON SUCCESS
  210. ; RETURNS WITH CARRY SET IF PORT IS UNAVAILABLE ON THIS PC
  211. ;
  212. INSTALL_COM PROC NEAR
  213.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  214.     PUSH    ES        ; SAVE EXTRA SEGMENT
  215.     CMP    INSTALLED[SI],1    ; ALREADY INSTALLED?
  216.     JNE    INSTOK        ; NO, CONTINUE
  217.     JMP    INSTX        ; ELSE JUMP IF ALREADY INSTALLED
  218. ; CLEAR ERROR COUNTS
  219. INSTOK:    MOV    WORD PTR EOVFLOW[SI],0    ; BUFFER OVERFLOWS
  220.     MOV    WORD PTR EOVRUN[SI],0    ; RECEIVE OVERRUNS
  221.     MOV    WORD PTR EBREAK[SI],0    ; BREAK CHARS
  222.     MOV    WORD PTR EFRAME[SI],0    ; FRAMING ERRORS
  223.     MOV    WORD PTR EPARITY[SI],0    ; PARITY ERRORS
  224.     MOV    WORD PTR EXMIT[SI],0    ; TRANSMISSION ERRORS
  225.     MOV    WORD PTR EDSR[SI],0    ; DATA SET READY ERRORS
  226.     MOV    WORD PTR ECTS[SI],0    ; CLEAR TO SEND ERRORS
  227. ; SENSE PC TYPE AND SET DIVISOR ACCORDINGLY
  228.     MOV    BX,ROM        ; HIGH ROM SEGMENT
  229.     MOV    ES,BX        ; TO ES
  230.     ASSUME    ES:ROM
  231.     MOV    DIV50,DIV50PC    ; ASSUME PC OR XT
  232.     CMP    ROMID,0FDH    ; IS IT A PCjr?
  233.     JNE    INST0        ; JUMP IF NOT
  234.     MOV    DIV50,DIV50JR    ; ELSE SET JR DIVISOR
  235. ; SET 8250 PORT ADDRESSES
  236. INST0:    MOV    BX,RBDA        ; ROM BIOS DATA AREA
  237.     MOV    ES,BX        ; TO ES
  238.     ASSUME    ES:RBDA
  239.     TEST    PORT[SI],1    ; PORT 1?
  240.     JZ    INST1        ; JUMP IF NOT
  241.     MOV    AX,3F8H        ; COM1 BASE PORT ADDRESS
  242.     JMP    SHORT INST2    ; CONTINUE
  243. INST1:    MOV    AX,2F8H        ; COM2 BASE PORT ADDRESS
  244. INST2:    CMP    AX,RS232_BASE    ; INSTALLED?
  245.     JE    INST2A        ; JUMP IF SO
  246.     CMP    AX,RS232_BASE+2    ; INSTALLED?
  247.     JNE    INST666        ; JUMP IF NOT
  248. INST2A:    MOV    BX,DATREG    ; OFFSET OF TABLE OF PORTS
  249.     MOV    CX,7        ; LOOP SIX TIMES
  250. INST3:    MOV    WORD PTR [SI][BX],AX ; SET PORT ADDRESS
  251.     INC    AX        ; NEXT PORT
  252.     ADD    BX,2        ; NEXT WORD ADDRESS
  253.     LOOP    INST3        ; RS232 BASE LOOP
  254. ; RESET VECTOR TO POINT TO OUR HANDLER
  255.     MOV    AREA1.INT_HNDLR,OFFSET INT_HNDLR1
  256.     MOV    AREA2.INT_HNDLR,OFFSET INT_HNDLR2
  257.     MOV    AH,25H        ; SET INTERRUPT VECTOR CONTENTS
  258.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  259.     MOV    DX,OFFSET INT_HNDLR[SI] ; OUR INTERRUPT HANDLER
  260.     PUSH    DS              ; SAVE DATA SEGMENT
  261.     PUSH    CS        ; COPY CS
  262.     POP    DS        ; TO DS
  263.     INT    DOS        ; DOS FUNCTION
  264.     POP     DS              ; RECOVER DATA SEGMENT
  265. ; PORT INSTALLED
  266. INSTX:    MOV    INSTALLED[SI],1    ; PORT INSTALLED
  267.     POP    ES        ; RESTORE ES
  268.     CLC            ; SUCCESS - CLEAR CARRY BIT
  269.         RET            ; DONE
  270. ; PORT NOT INSTALLED
  271. INST666:MOV    INSTALLED[SI],0    ; PORT NOT INSTALLED ON THIS PC
  272.     POP    ES        ; RESTORE ES
  273.     STC            ; SET CARRY BIT FOR ERROR FLAG
  274.     RET            ; DONE
  275. INSTALL_COM ENDP
  276.     PAGE
  277. ;
  278. ; RESTORE ORIGINAL INTERRUPT VECTOR
  279. ;
  280. RESTORE_COM PROC NEAR
  281.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  282.     MOV    INSTALLED[SI],0    ; PORT IS NO LONGER INSTALLED
  283.     MOV    AH,25H        ; SET INTERRUPT VECTOR FUNCTION
  284.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  285.     MOV    DX,OLD_COM_OFF[SI] ; OLD OFFSET TO DX
  286.     MOV    BX,OLD_COM_SEG[SI] ; OLD SEG
  287.     PUSH    DS        ; SAVE DS
  288.     MOV    DS,BX        ; TO DS
  289.     INT    DOS        ; DOS FUNCTION
  290.     POP    DS        ; RECOVER DS
  291.         RET            ; DONE
  292. RESTORE_COM ENDP
  293.         PAGE
  294. ;
  295. ; OPEN_COM ON CURRENT PORT
  296. ; AX = BAUD RATE
  297. ; BH = CONNECTION: M(ODEM), D(IRECT)
  298. ; BL = PARITY:     N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  299. ; CH = STOP BITS:  1, 2
  300. ; CL = XON/XOFF:   E(NABLED), D(ISABLED)
  301. ;
  302. ; CLEAR BUFFERS
  303. ; RE-INITIALIZE THE INTEL 8250 UART
  304. ; ENABLE INTERRUPTS ON THE INTEL 8259 INTERRUPT CONTROL CHIP
  305. ;
  306. OPEN_COM PROC   NEAR
  307.     MOV    SI,CURRENT_AREA        ; SI POINTS TO DATA AREA
  308.  
  309.     CLI                ; INTERRUPTS OFF
  310.     MOV    BAUD_RATE[SI],AX    ; SET
  311.     MOV    CONNECTION[SI],BH    ;     ARGS
  312.     MOV    PARITY[SI],BL        ;          IN
  313.     MOV    STOP_BITS[SI],CH    ;             MEMORY
  314.     MOV    XON_XOFF[SI],CL    
  315.  
  316. ; RESET FLOW CONTROL
  317.     MOV    HOST_OFF[SI],0        ; HOST FLOWING
  318.     MOV    PC_OFF[SI],0        ; PC FLOWING
  319.  
  320. ; RESET BUFFER COUNTS AND POINTERS
  321.     MOV    START_TDATA[SI],0
  322.     MOV    END_TDATA[SI],0
  323.     MOV    START_RDATA[SI],0
  324.     MOV    END_RDATA[SI],0
  325.     MOV    SIZE_TDATA[SI],0
  326.     MOV    SIZE_RDATA[SI],0
  327.  
  328.     TEST    INSTALLED[SI],1        ; PORT INSTALLED?
  329.     JNZ    OC1            ; SKIP IF SO
  330.     JMP    OCX            ; ELSE ABORT
  331. OC1:
  332. ; RESET THE 8250
  333.         MOV     AL,0
  334.         MOV     DX,MCR[SI]
  335.         OUT     DX,AL
  336.     JMP    $+2        ; I/O DELAY FOR JR
  337.  
  338.         MOV     DX,LSR[SI]    ; RESET LINE STATUS CONDITION
  339.         IN      AL,DX
  340.     JMP    $+2        ; I/O DELAY FOR JR
  341.         MOV     DX,DATREG[SI]    ; RESET RECSIVE DATA CONDITION
  342.         IN      AL,DX
  343.     JMP    $+2        ; I/O DELAY FOR JR
  344.         MOV     DX,MSR[SI]    ; RESET MODEM DELTAS AND CONDITIONS
  345.         IN      AL,DX
  346.  
  347. ; CONVERT PASSED BAUD RATE TO 8250 DIVISOR
  348.     MOV    AX,50        ; 50 BAUD
  349.     MUL    DIV50        ; TIMES ITS DIVISOR
  350.     DIV    BAUD_RATE[SI]    ; OTHER SPEEDS ARE PROPORTIONAL
  351.     MOV    BX,AX        ; RESULT TO BX
  352.  
  353. ; SET 8250 DIVISOR
  354.         MOV     DX,LCR[SI]    ; LINE CONTROL REGISTER
  355.         MOV     AL,80H          ; HI BIT ON
  356.         OUT     DX,AL           ; SET DLAB = 1
  357.     JMP    $+2        ; I/O DELAY FOR JR
  358.         MOV     DX,WORD PTR DLL[SI]    ; LEAST SIGNIFICANT BYTE
  359.         MOV     AL,BL        ; LSB FROM TABLE
  360.         OUT     DX,AL           ; SET LSB ON 8250
  361.     JMP    $+2        ; I/O DELAY FOR JR
  362.         MOV     DX,WORD PTR DLH[SI]    ; MOST SIGNIFICANT BYTE
  363.         MOV     AL,BH        ; MSB FROM TABLE
  364.         OUT     DX,AL           ; SET MSB ON 8250
  365.     JMP    $+2        ; I/O DELAY FOR JR
  366.  
  367. ; SET PARITY AND NUMBER OF STOP BITS
  368.     MOV    AL,03H        ; NONE OR SPACE PARITY IS THE DEFAULT
  369.     CMP    PARITY[SI],'O'    ; ODD PARITY REQUESTED?
  370.     JNE    P1        ; JUMP IF NOT
  371.     MOV    AL,0AH        ; SELECT ODD PARITY
  372.     JMP    SHORT P3    ; CONTINUE
  373. P1:    CMP    PARITY[SI],'E'    ; EVEN PARITY REQUESTED?
  374.     JNE    P2        ; JUMP IF NOT
  375.     MOV    AL,1AH        ; SELECT EVEN PARITY
  376.     JMP    SHORT P3    ; CONTINUE
  377. P2:    CMP    PARITY[SI],'M'    ; MARK PARITY REQUESTED?
  378.     JNE    P3        ; JUMP IF NOT
  379.     MOV    AL,2AH        ; SELECT MARK PARITY
  380. P3:    TEST    STOP_BITS[SI],2    ; 2 STOP BITS REQUESTED?
  381.     JZ    STOP1        ; NO
  382.     OR    AL,4        ; YES
  383. STOP1:    MOV     DX,LCR[SI]    ; LINE CONTROL REGISTER
  384.         OUT     DX,AL           ; SET 8250 PARITY MODE AND DLAB=0
  385.  
  386. ; ENABLE INTERRUPTS ON 8259 AND 8250
  387.         IN      AL,INTA01    ; SET ENABLE BIT ON 8259
  388.         AND     AL,NIRQ[SI]
  389.         OUT     INTA01,AL
  390.         MOV     DX,IER[SI]    ; ENABLE INTERRUPTS ON 8250
  391.         MOV     AL,5        ; RECEIVE & LINE ERROR
  392.         OUT     DX,AL
  393.     JMP    $+2        ; I/O DELAY FOR JR
  394.         MOV     DX,MCR[SI]    ; SET DTR AND ENABLE INT DRIVER
  395.         MOV     AL,0BH
  396.         OUT     DX,AL
  397.  
  398. OCX:    STI            ; INTERRUPTS ON
  399.     RET            ; DONE
  400. OPEN_COM ENDP
  401.     PAGE
  402. ;
  403. ; CLOSE_COM - TURNS OFF INTERRUPTS FROM THE COMMUNICATIONS PORT
  404. ;
  405. CLOSE_COM PROC  NEAR
  406.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  407.     TEST    INSTALLED[SI],1    ; PORT INSTALLED?
  408.     JZ    CCX        ; ABORT IF NOT
  409.  
  410. ; TURN OFF 8250
  411.         MOV     DX,IER[SI]
  412.         MOV     AL,0
  413.         OUT     DX,AL
  414.  
  415. ; TURN OFF 8259
  416.         MOV     DX,INTA01
  417.         IN      AL,DX
  418.         OR      AL,IRQ[SI]
  419.     JMP    $+2        ; DELAY FOR AT
  420.         OUT     DX,AL
  421.  
  422. CCX:    RET
  423. CLOSE_COM ENDP
  424.         PAGE
  425. ;
  426. ; DTR_OFF - TURNS OFF DTR TO TELL MODEMS THAT THE TERMINAL HAS GONE AWAY
  427. ;           AND TO HANG UP THE PHONE
  428. ;
  429. DTR_OFF PROC    NEAR
  430.     PUSHF            ; SAVE FLAGS
  431.     PUSH    AX        ; SAVE REGS
  432.     PUSH    DX
  433.     PUSH    SI
  434.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  435.     TEST    INSTALLED[SI],1    ; PORT INSTALLED?
  436.     JZ    DFX        ; ABORT IF NOT
  437.  
  438.         MOV     DX,MCR[SI]
  439.         MOV     AL,08H        ; DTR OFF, RTS OFF, OUT2 ON
  440.         OUT     DX,AL
  441. DFX:    POP    SI        ; RECOVER REGS
  442.     POP    DX
  443.     POP    AX
  444.     POPF            ; RECOVER FLAGS
  445.     RET
  446. DTR_OFF ENDP
  447. ;
  448. ; DTR_ON - TURNS DTR ON
  449. ;
  450. DTR_ON  PROC    NEAR
  451.     PUSHF            ; SAVE FLAGS
  452.     PUSH    AX        ; SAVE REGS
  453.     PUSH    DX
  454.     PUSH    SI
  455.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  456.     TEST    INSTALLED[SI],1    ; PORT INSTALLED?
  457.     JZ    DNX        ; ABORT IF NOT
  458.  
  459.         MOV     DX,MCR[SI]
  460.         MOV     AL,0BH
  461.         OUT     DX,AL
  462. DNX:    POP    SI        ; RECOVER REGS
  463.     POP    DX
  464.     POP    AX
  465.     POPF            ; RECOVER FLAGS
  466.     RET            ; DONE
  467. DTR_ON  ENDP
  468.         PAGE
  469. ;
  470. ; R_COUNT - RETURNS NUMBER OF BYTES IN THE RECEIVE BUFFER IN AX
  471. ;           RETURNS TOTAL SIZE IN BX
  472. ;
  473. R_COUNT PROC    NEAR
  474.     PUSHF            ; SAVE FLAGS
  475.     PUSH    SI        ; SAVE SI
  476.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  477.     MOV    AX,0        ; NOTHING RECEIVED IF NOT INSTALLED
  478.     MOV    BX,R_SIZE    ; GET TOTAL SIZE
  479.  
  480.     TEST    INSTALLED[SI],1    ; PORT INSTALLED?
  481.     JZ    RCX        ; ABORT IF NOT
  482.  
  483.         MOV     AX,SIZE_RDATA[SI] ; GET NUMBER OF BYTES USED
  484. RCX:    POP    SI        ; RESTORE SI
  485.     POPF            ; RESTORE FLAGS
  486.     RET
  487. R_COUNT ENDP
  488.     PAGE
  489. ;
  490. ; RECEIVE - RETURNS THE NEXT CHARACTER FROM THE RECEIVE BUFFER IN AL
  491. ;            AND REMOVES IT FROM THE BUFFER
  492. ;            THE PARITY BIT IS STRIPPED OFF
  493. ;
  494. RECEIVE    PROC    NEAR
  495.     PUSHF                ; SAVE FLAGS
  496.     PUSH    BX            ; SAVE REGS
  497.     PUSH    SI
  498.     MOV    SI,CURRENT_AREA        ; SI POINTS TO DATA AREA
  499.     MOV    AL,0            ; RETURN NUL IF BAD CALL
  500.     TEST    INSTALLED[SI],1        ; PORT INSTALLED?
  501.     JZ    RCVX            ; ABORT IF NOT
  502.     CMP    SIZE_RDATA[SI],0    ; ANY CHARACTERS?
  503.     JE    RCVX            ; ABORT IF NOT
  504.  
  505. ; GOOD CALL
  506.         MOV     BX,START_RDATA[SI]    ; GET POINTER TO OLDEST CHAR
  507.         MOV     AL,RDATA[SI][BX]    ; GET CHAR FROM BUFFER
  508. ; MOD BY LBA, 10/6/85 FOR PROPER SUPPORT OF NO PARITY COMMUNICATIONS
  509.     CMP    PARITY[SI],'N'        ; ARE WE RUNNING WITH NO PARITY?
  510.     JE    L11            ; IF SO, DON'T STRIP HIGH BIT
  511. ; END OF MOD
  512.     AND    AL,7FH            ; STRIP PARITY BIT
  513. L11:    INC     BX                  ; BUMP START_RDATA
  514.         CMP     BX,R_SIZE        ; SEE IF PAST END
  515.         JB      L12                 ; IF NOT THEN SKIP
  516.         MOV    BX,0            ; ADJUST TO BEGINNING
  517. L12:    MOV     START_RDATA[SI],BX    ; SAVE THE NEW START_RDATA VALUE
  518.         DEC     SIZE_RDATA[SI]        ; ONE LESS CHARACTER
  519.     CMP    XON_XOFF[SI],'E'    ; FLOW CONTROL ENABLED?
  520.     JNE    RCVX            ; DO NOTHING IF DISABLED
  521.     CMP    HOST_OFF[SI],1        ; HOST TURNED OFF?
  522.     JNE    RCVX            ; JUMP IF NOT
  523.     CMP    SIZE_RDATA[SI],R_SIZE/20 ; RECEIVE BUFFER NEARLY EMPTY?
  524.     JGE    RCVX            ; DONE IF NOT
  525.     MOV    HOST_OFF[SI],0        ; TURN ON HOST IF SO
  526.     PUSH    AX            ; SAVE RECEIVED CHAR
  527.     MOV    AL,CONTROL_Q        ; TELL HIM TO TALK
  528.     CLI                ; TURN OFF INTERRUPTS
  529.     CALL    SENDII            ; SEND IMMEDIATELY INTERNAL
  530.     STI                ; INTERRUPTS BACK ON
  531.     POP    AX            ; RESTORE RECEIVED CHAR
  532. RCVX:    POP    SI            ; RECOVER REGS
  533.     POP    BX
  534.     POPF                ; RECOVER FLAGS
  535.     RET                ; DONE
  536. RECEIVE    ENDP
  537.         PAGE
  538. ;
  539. ; S_COUNT - RETURNS IN AX THE AMOUNT OF FREE SPACE
  540. ;              REMAINING IN THE TRANSMIT BUFFER
  541. ;           RETURNS IN BX THE TOTAL SIZE OF THE TRANSMIT BUFFER
  542. ;
  543. S_COUNT PROC    NEAR
  544.     PUSHF            ; SAVE FLAGS
  545.     PUSH    SI        ; SAVE SI
  546.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  547.     MOV    AX,0        ; NO SPACE LEFT IF NOT INSTALLED
  548.     MOV    BX,S_SIZE    ; SIZE IN BX
  549.  
  550.     TEST    INSTALLED[SI],1    ; PORT INSTALLED?
  551.     JZ    SCX        ; ABORT IF NOT
  552.  
  553.         MOV     AX,S_SIZE    ; GET THE SIZE OF THE X-MIT BUFFER
  554.         SUB     AX,SIZE_TDATA[SI] ; SUBTRACT THE NUMBER OF BYTES USED
  555. SCX:    POP    SI        ; RECOVER SI
  556.     POPF            ; RESTORE FLAGS
  557.     RET
  558. S_COUNT ENDP
  559.         PAGE
  560. ;
  561. ; SEND - SEND A CHARACTER
  562. ; AL = CHAR TO WRITE
  563. ;
  564. SEND    PROC    NEAR
  565.     PUSHF                ; SAVE FLAGS
  566.     PUSH    AX            ; SAVE REGS
  567.     PUSH    BX
  568.     PUSH    DX
  569.     PUSH    SI
  570.     MOV    SI,CURRENT_AREA        ; SI POINTS TO DATA AREA
  571.     TEST    INSTALLED[SI],1        ; PORT INSTALLED?
  572.     JZ    L44            ; ABORT IF NOT
  573.  
  574.     CMP    SIZE_TDATA[SI],S_SIZE    ; BUFFER FULL?
  575.     JL    L4A            ; JUMP IF NOT
  576.     INC    WORD PTR EOVFLOW[SI]    ; BUMP ERROR COUNT
  577.     JMP    SHORT L44        ; PUNT
  578. L4A:    MOV     BX,END_TDATA[SI]    ; BX POINTS TO FREE SPACE
  579.         MOV     TDATA[SI][BX],AL    ; MOVE CHAR TO BUFFER
  580.         INC     BX                  ; INCREMENT END_TDATA
  581.         CMP     BX,S_SIZE        ; SEE IF PAST END
  582.         JL      L4                  ; IF NOT THEN SKIP
  583.     MOV    BX,0            ; ADJUST TO BEGINNING
  584. L4:     MOV     END_TDATA[SI],BX    ; SAVE NEW END_TDATA
  585.         INC     SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  586.     MOV     DX,IER[SI]        ; INTERRUPT ENABLE REGISTER
  587.         IN      AL,DX            ; GET IT
  588.     TEST    AL,2            ; SEE IF TX INTERRUPTS ARE ENABLED
  589.         JNZ     L44            ; JUMP IF SO
  590.         MOV     AL,7            ; IF NOT THEN RCV, TX, LINE ERROR
  591.         OUT     DX,AL            ; ARE ENABLED
  592. L44:    POP    SI            ; RESTORE REGS
  593.     POP    DX
  594.     POP    BX
  595.     POP    AX
  596.     POPF                ; RESTORE FLAGS
  597.     RET                ; DONE
  598. SEND    ENDP
  599.         PAGE
  600. ;
  601. ; SENDI - SEND A CHARACTER IMMEDIATELY
  602. ; AL = CHAR TO WRITE
  603. ;
  604. SENDI    PROC    NEAR
  605.     PUSHF                ; SAVE FLAGS
  606.     PUSH    AX            ; SAVE REGS
  607.     PUSH    BX
  608.     PUSH    DX
  609.     PUSH    SI
  610.     MOV    SI,CURRENT_AREA        ; SI POINTS TO DATA AREA
  611.     TEST    INSTALLED[SI],1        ; PORT INSTALLED?
  612.     JZ    LQ44            ; ABORT IF NOT
  613.  
  614.     CLI                ; MASK INTERRUPTS
  615.     CALL    SENDII            ; CALL INTERNAL SEND IMMEDIATE
  616.     STI                ; INTERRRUPTS BACK ON
  617.  
  618. LQ44:    POP    SI            ; RESTORE REGS
  619.     POP    DX
  620.     POP    BX
  621.     POP    AX
  622.     POPF                ; RESTORE FLAGS
  623.     RET                ; DONE
  624. SENDI    ENDP
  625.         PAGE
  626. ;
  627. ; INTERNAL ROUTINE
  628. ; DEPENDS ON CALLER TO KEEP INTERRUPTS CLEARED AND SET SI
  629. ; SENDI - SEND A CHARACTER IMMEDIATELY (PUT AT BEGINNING OF QUEUE)
  630. ; AL = CHAR TO WRITE
  631. ;
  632. SENDII    PROC    NEAR
  633.     PUSH    DX            ; SAVE DX
  634.     CMP    SIZE_TDATA[SI],S_SIZE    ; BUFFER FULL?
  635.     JB    LI4A            ; JUMP IF NOT
  636.     INC    WORD PTR EOVFLOW[SI]    ; BUMP ERROR COUNT
  637.     MOV    BX,START_TDATA[SI]    ; BX POINTS TO FIRST CHAR IN BUFFER
  638.     MOV     TDATA[SI][BX],AL     ; CLOBBER FIRST CHAR IN BUFFER
  639.     JMP    SHORT LI4B        ; CONTINUE
  640. LI4A:    MOV    BX,START_TDATA[SI]    ; BX POINTS TO FIRST CHAR IN BUFFER
  641.     DEC    BX            ; BACKUP THE PTR
  642.     CMP    BX,-1            ; BEFORE BEGINNING?
  643.     JNE    LI4            ; JUMP IF NOT
  644.     MOV    BX,S_SIZE-1        ; POINT TO END IF SO
  645. LI4:    MOV     TDATA[SI][BX],AL     ; MOVE CHAR TO BUFFER
  646.     MOV     START_TDATA[SI],BX    ; SAVE NEW START_TDATA
  647.     INC     SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  648. LI4B:    MOV     DX,IER[SI]        ; INTERRUPT ENABLE REGISTER
  649.         IN      AL,DX            ; GET IT
  650.     TEST    AL,2            ; SEE IF TX INTERRUPTS ARE ENABLED
  651.         JNZ     LI44            ; JUMP IF SO
  652.         MOV     AL,7            ; IF NOT THEN RCV, TX, LINE ERROR
  653.         OUT     DX,AL            ; ARE ENABLED
  654. LI44:    POP    DX            ; RECOVER DX
  655.     RET                ; DONE
  656. SENDII    ENDP
  657.     PAGE
  658. ;
  659. ; S_LOCAL
  660. ; AL = CHAR
  661. ;
  662. ; WRITES A CHARACTER TO THE INPUT BUFFER
  663. ;
  664. S_LOCAL PROC    NEAR
  665.     PUSHF                ; SAVE FLAGS
  666.     PUSH    AX            ; SAVE REGS
  667.     PUSH    BX
  668.     PUSH    SI
  669.     MOV    SI,CURRENT_AREA        ; SI POINTS TO DATA AREA
  670.     TEST    INSTALLED[SI],1        ; PORT INSTALLED?
  671.     JZ    SLX            ; ABORT IF NOT
  672.  
  673.         CLI                ; INTERRUPTS OFF
  674.         CMP     SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  675.     JB    L13A            ; SKIP IF ROOM
  676.     INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW COUNT
  677.     JMP    SHORT L14        ; PUNT
  678. L13A:    MOV     BX,END_RDATA[SI]    ; BX POINTS TO FREE SPACE
  679.         MOV     RDATA[SI][BX],AL    ; SEND DATA TO BUFFER
  680.         INC     BX                     ; INCREMENT END_RDATA POINTER
  681.         CMP     BX,R_SIZE        ; SEE IF GONE PAST END
  682.         JL      L13                 ; IF NOT THEN SKIP
  683.         MOV    BX,0            ; ELSE ADJUST TO BEGINNING
  684. L13:    MOV     END_RDATA[SI],BX     ; SAVE VALUE
  685.         INC     SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  686. L14:    STI                ; INTERRUPTS BACK ON
  687.  
  688. SLX:    POP    SI            ; RECOVER REGS
  689.     POP    BX
  690.     POP    AX
  691.     POPF                ; RECOVER FLAGS
  692.     RET                ; DONE
  693. S_LOCAL ENDP
  694.         PAGE
  695. ;
  696. ; BREAK - CAUSES A BREAK TO BE SENT OUT ON THE LINE
  697. ;
  698. BREAK   PROC    NEAR
  699.     PUSHF            ; SAVE FLAGS
  700.     PUSH    AX        ; SAVE REGS
  701.     PUSH    CX
  702.     PUSH    DX
  703.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  704.     TEST    INSTALLED[SI],1    ; PORT INSTALLED?
  705.     JZ    BRX        ; ABORT IF NOT
  706.  
  707.     MOV    DX,LCR[SI]    ; LINE CONTROL REGISTER
  708.     IN    AL,DX        ; GET CURRENT SETTING
  709.     JMP    $+2        ; I/O DELAY FOR JR
  710.     OR    AL,40H        ; TURN ON BREAK BIT
  711.     OUT    DX,AL        ; SET IT ON THE 8250
  712.     MOV    CX,0C000H    ; WAIT APPROX. 1/4 SEC.
  713. BREAK1:    LOOP    BREAK1        ; BUSY WAIT
  714.     AND    AL,0BFH        ; TURN OFF BREAK BIT
  715.     OUT    DX,AL        ; RESTORE LINE CONTROL REGISTER
  716. BRX:    POP    DX        ; RECOVER REGS
  717.     POP    CX
  718.     POP    AX
  719.     POPF            ; RECOVER FLAGS
  720.     RET            ; DONE
  721. BREAK   ENDP
  722.     PAGE
  723. ;
  724. ; COM_ERRORS - RETURN POINTER IN SI TO ERROR COUNTS
  725. ;
  726. COM_ERRORS PROC    NEAR
  727.     MOV    SI,CURRENT_AREA    ; SI POINTS TO DATA AREA
  728.     ADD    SI,ERROR_BLOCK    ; SI POINTS TO ERROR BLOCK
  729.     RET            ; DONE
  730. COM_ERRORS ENDP
  731.         PAGE
  732. ;
  733. ; INTERNAL ROUTINE
  734. ; BUMP ERROR COUNTS FROM LINE STATUS IN AL
  735. ;
  736. E_BUMP    PROC    NEAR
  737.     TEST    AL,2        ; OVERRUN ERROR?
  738.     JZ    LSI1        ; JUMP IF NOT
  739.     INC    WORD PTR EOVRUN[SI]    ; ELSE BUMP ERROR COUNT
  740. LSI1:    TEST    AL,4        ; PARITY ERROR?
  741.     JZ    LSI2        ; JUMP IF NOT
  742.     INC    WORD PTR EPARITY[SI]    ; ELSE BUMP ERROR COUNT
  743. LSI2:    TEST    AL,8        ; FRAMING ERROR?
  744.     JZ    LSI3        ; JUMP IF NOT
  745.     INC    WORD PTR EFRAME[SI]    ; ELSE BUMP ERROR COUNT
  746. LSI3:    TEST    AL,16        ; BREAK RECEIVED?
  747.     JZ    LSI4        ; JUMP IF NOT
  748.     INC    WORD PTR EBREAK[SI]    ; ELSE BUMP ERROR COUNT
  749. LSI4:    RET            ; DONE
  750. E_BUMP    ENDP
  751.     PAGE
  752. ;
  753. ; INTERNAL ROUTINE
  754. ; MODEM SEND PROTOCOL
  755. ;
  756. M_PROTOCOL PROC    NEAR
  757.         CMP     CONNECTION[SI],'M' ; MODEM CONNECTION?
  758.         JNE     S3        ; IF NOT, SKIP DSR & CTS PROTOCOL
  759.  
  760. ; TELL MODEM WE'RE READY TO SEND
  761.         MOV     DX,MCR[SI]    ; MODEM CONTROL REGISTER
  762.         MOV     AL,00001011B    ; OUT 2, RTS, DTR
  763.         OUT     DX,AL           ; TERMINAL READY, REQUEST TO SEND
  764.     JMP    $+2        ; I/O DELAY FOR JR
  765.  
  766. ; WAIT UNTIL MODEM SAYS DATA SET READY
  767.     MOV     CX,1000        ; TIMEOUT COUNT
  768.         MOV     DX,MSR[SI]    ; MODEM STATUS REGISTER
  769. S1:     IN      AL,DX           ; GET MODEM STATUS
  770.         TEST    AL,20H          ; DATA SET READY?
  771.         JNZ     S1X        ; YES, TEST CLEAR TO SEND
  772.         LOOP    S1              ; NO, BUSY WAIT
  773.         INC    WORD PTR EDSR[SI]    ; BUMP ERROR COUNT
  774.     JMP    SHORT S3    ; WE TIMED OUT
  775. S1X:
  776. ; WAIT UNTIL MODEM SAYS IT'S CLEAR TO SEND
  777.     MOV    CX,1000        ; TIMEOUT COUNT
  778. S2:    IN      AL,DX           ; GET MODEM STATUS
  779.         TEST    AL,10H          ; CLEAR TO SEND?
  780.         JNZ     S2X        ; YES
  781.         LOOP    S2        ; NO, KEEP TRYING
  782.         INC    WORD PTR ECTS[SI]    ; BUMP ERROR COUNT - WE TIMED OUT
  783. S2X:
  784. ; TEST FOR TRANSMITTER READY
  785. S3:    MOV     DX,LSR[SI]    ; LINE STATUS REGISTER
  786.     IN      AL,DX           ; GET LINE STATUS
  787.         TEST    AL,20H          ; TRANSMITTER READY?
  788.         JNZ     S4        ; SKIP IF SO
  789.     INC    WORD PTR EXMIT[SI]    ; ELSE BUMP ERROR COUNT
  790. S4:    RET            ; DONE
  791. M_PROTOCOL ENDP
  792.     PAGE
  793. ;
  794. ; INTERNAL ROUTINES FOR FLOW CONTROL
  795. ;
  796. ; FLOW_IN - RESPOND TO FLOW CONTROL COMMANDS FROM HOST
  797. ; FLOW_OUT - ISSUE FLOW CONTROL COMMANDS TO HOST
  798. ;
  799. FLOW_IN    PROC    NEAR
  800.     PUSH    AX        ; SAVE CHAR
  801.     CMP    XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
  802.     JNE    FI_2        ; DO NOTHING IF DISABLED
  803.     AND    AL,7FH        ; STRIP PARITY
  804.     CMP    AL,CONTROL_S    ; STOP COMMAND RECEIVED?
  805.     JNE    FI_1        ; JUMP IF NOT
  806.     MOV    PC_OFF[SI],1    ; WE MUST SHUT UP
  807.     JMP    SHORT FI_2    ; CONTINUE
  808. FI_1:    CMP    AL,CONTROL_Q    ; GO COMMAND RECEIVED?
  809.     JNE    FI_2        ; NO, MUST BE NORMAL CHAR
  810.     MOV    PC_OFF[SI],0    ; WE START TALKING AGAIN
  811. FI_2:    POP    AX        ; RESTORE CHAR
  812.     RET            ; DONE
  813. FLOW_IN    ENDP
  814. ;
  815. FLOW_OUT PROC    NEAR
  816.     CMP    XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
  817.     JNE    FO_X        ; DO NOTHING IF DISABLED
  818.     CMP    HOST_OFF[SI],1    ; HOST TURNED OFF?
  819.     JE    FO_X        ; JUMP IF SO
  820.     CMP    SIZE_RDATA[SI],R_SIZE/2    ; RECEIVE BUFFER NEARLY FULL?
  821.     JLE    FO_X        ; DONE IF NOT
  822.     MOV    AL,CONTROL_S    ; TURN OFF HOST IF SO
  823.     CALL    SENDII        ; SEND IMMEDIATELY INTERNAL
  824.     MOV    HOST_OFF[SI],1    ; HOST IS NOW OFF
  825. FO_X:    RET            ; DONE
  826. FLOW_OUT ENDP
  827.         PAGE
  828. ;
  829. ; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
  830. ;
  831. INT_HNDLR1 PROC  FAR
  832.     PUSH    SI        ; SAVE SI
  833.     MOV    SI,OFFSET AREA1    ; DATA AREA FOR COM1:
  834.     JMP    SHORT INT_COMMON ; CONTINUE
  835. ;
  836. ; INT_HNDLR2 - HANDLES INTERRUPTS GENERATED BY COM2:
  837. ;
  838. INT_HNDLR2 PROC  FAR
  839.     PUSH    SI        ; SAVE SI
  840.     MOV    SI,OFFSET AREA2    ; DATA AREA FOR COM2:
  841. ;
  842. ; BODY OF INTERRUPT HANDLER
  843. ;
  844. INT_COMMON:
  845.     PUSH    AX        ; SAVE REGS
  846.     PUSH    BX
  847.     PUSH    CX
  848.     PUSH    DX
  849.     PUSH    BP
  850.     PUSH    DI
  851.     PUSH    DS
  852.     PUSH    ES
  853.  
  854.     MOV    AX,DATA        ; OUR DATA SEG
  855.     MOV    DS,AX        ; TO DS
  856.  
  857. ; CLEAR THE INTERRUPT CONTROLLER FLAG
  858.     MOV    DX,INTA00    ; 8259 CONTROL PORT
  859.     MOV    AL,EOI[SI]    ; SPECIFIC END OF INTERRUPT
  860.     OUT    DX,AL        ; CLEAR FLAG
  861.  
  862. ; FIND OUT WHERE INTERRUPT CAME FROM AND JUMP TO ROUTINE TO HANDLE IT
  863. REPOLL:
  864.         MOV     DX,IIR[SI]    ; READ INTERRUPT STATUS REGISTER
  865.         IN      AL,DX
  866.         CMP     AL,4
  867.         JE    RX_INT        ; IF FROM THE RECEIVER
  868.     CMP     AL,2
  869.         JE      TX_INT          ; IF FROM THE TRANSMITTER
  870.         CMP     AL,6
  871.         JE    LSTAT_INT       ; INTERRUPT BECAUSE OF LINE STATUS
  872.         CMP     AL,0
  873.         JE    MSTAT_INT       ; INTERRUPT BECAUSE OF MODEM STATUS
  874.         JMP     FAR PTR INT_END    ; DONE, EXIT (DON'T FIX FAR PTR STUFF)
  875.  
  876. LSTAT_INT:
  877.         MOV     DX,LSR[SI]    ; READ AND IGNORE LINE STATUS
  878.         IN      AL,DX        ;
  879.     CALL    E_BUMP        ; JUST BUMP ERROR COUNTS
  880.     JMP     REPOLL          ; SEE IF ANY MORE INTERRUPTS
  881.  
  882. MSTAT_INT:
  883.         MOV     DX,MSR[SI]    ; READ AND IGNORE MODEM STATUS
  884.         IN      AL,DX        ;
  885.         JMP     REPOLL          ; SEE IF ANY MORE INTERRUPTS
  886.  
  887. TX_INT:
  888.     CMP    PC_OFF[SI],1    ; HAVE WE BEEN TOLD TO SHUT UP?
  889.     JNE    GOODTX1        ; JUMP IF NOT
  890.     CMP    HOST_OFF[SI],1    ; HAS HOST ALSO SHUT UP?
  891.     JNE    SEND_NO_MORE    ; JUMP IF NOT
  892.  
  893. ; CLEAR XON/XOFF DEADLOCK
  894.     MOV    PC_OFF[SI],0    ; WE SPEAK
  895.     MOV    HOST_OFF[SI],0    ; THEY REPLY
  896.     MOV    AL,CONTROL_Q    ; BUT ONLY WHEN
  897.     CALL    SENDII        ; WE LET THEM
  898.  
  899. GOODTX1:
  900.     CMP     SIZE_TDATA[SI],0 ; SEE IF ANY MORE DATA TO SEND
  901.     JG    HAVE_DATA       ; IF POSITIVE THEN THERE IS DATA TO SEND
  902.  
  903. ; IF NO DATA TO SEND THEN RESET TX INTERRUPT AND RETURN
  904. SEND_NO_MORE:
  905.         MOV     DX,IER[SI]        ;
  906.         MOV     AL,5            ; JUST RCV AND LINE ERROR
  907.         OUT     DX,AL            ; ARE SET
  908.         JMP     REPOLL            ;
  909.  
  910. HAVE_DATA:
  911.     CALL    M_PROTOCOL        ; DO MODEM PROTOCOL IF NECESSARY
  912.  
  913.         MOV     BX,START_TDATA[SI]    ; BX POINTS TO NEXT CHAR. TO BE SENT
  914.         MOV     AL,TDATA[SI][BX]    ; GET DATA FROM BUFFER
  915.         MOV     DX,DATREG[SI]        ; DX EQUALS PORT TO SEND DATA TO
  916.         OUT     DX,AL               ; SEND DATA
  917.         INC     BX                  ; INCREMENT START_TDATA
  918.         CMP     BX,S_SIZE        ; SEE IF GONE PAST END
  919.         JB      NTADJ               ; IF NOT THEN SKIP
  920.     MOV    BX,0            ; RESET TO BEGINNING
  921. NTADJ:  MOV     START_TDATA[SI],BX    ; SAVE START_TDATA
  922.         DEC     SIZE_TDATA[SI]        ; ONE LESS CHARACTER IN X-MIT BUFFER
  923.         JMP     REPOLL
  924.  
  925. RX_INT:
  926.         MOV     DX,DATREG[SI]        ; 8250 DATA REGISTER
  927.         IN      AL,DX            ; GET DATA
  928.     CALL    FLOW_IN            ; RESPOND TO F.C. COMMANDS FROM HOST
  929.         CMP     SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  930.         JL    GOOD_RX1        ; CONTINUE IF SO
  931.     INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW ERROR COUNT
  932.     JMP    REPOLL            ; PUNT
  933. GOOD_RX1:
  934.         MOV     BX,END_RDATA[SI]    ; BX POINTS TO FREE SPACE
  935.         MOV     RDATA[SI][BX],AL    ; MOVE DATA TO BUFFER
  936.         INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  937.         INC     BX                  ; INCREMENT END_RDATA POINTER
  938.         CMP     BX,R_SIZE        ; SEE IF GONE PAST END
  939.     JB    NRADJ               ; IF NOT THEN SKIP
  940.         MOV     BX,0            ; ELSE ADJUST TO BEGINNING
  941. NRADJ:  MOV     END_RDATA[SI],BX    ; SAVE VALUE
  942.     CALL    FLOW_OUT        ; ISSUE FLOW CONTROL COMMANDS TO HOST
  943.     JMP    REPOLL            ; 
  944.  
  945. INT_END:
  946.     POP    ES        ; RESTORE REGS
  947.     POP    DS
  948.     POP    DI
  949.     POP    BP
  950.         POP     DX
  951.         POP     CX
  952.         POP     BX
  953.         POP     AX
  954.  
  955.     POP    SI        ; RESTORE SI, TOO
  956.         IRET
  957. INT_HNDLR2 ENDP
  958. INT_HNDLR1 ENDP
  959. DATA    SEGMENT
  960.     DB    'R.A.G. 85'
  961. DATA    ENDS
  962. CODE    ENDS
  963.         END
  964.