home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES2.ZIP / UUCICO / comm.asm < prev    next >
Encoding:
Assembly Source File  |  1993-11-20  |  53.2 KB  |  1,694 lines

  1.     TITLE    COMM
  2.     PAGE    83,132
  3. ;    $Id: comm.asm 1.10 1993/11/20 14:51:47 ahd Exp $
  4. ;
  5. ;    $Log: comm.asm $
  6. ;; Revision 1.10  1993/11/20  14:51:47  ahd
  7. ;; Up UUPC/extended buffer size to 16K from 8K
  8. ;;
  9. ;; Revision 1.9  1993/10/12  00:04:16  ahd
  10. ;; rhg changes for 8250 and RTS flow control
  11. ;;
  12. ;; Revision 1.7  1993/05/31  01:39:23  ahd
  13. ;; Add return to spin loop (fix by Bill Plummer)
  14. ;; Drop FIFO size to 8
  15. ;;
  16. ;; Revision 1.4  1993/05/30  00:20:02  ahd
  17. ;; Insert minor delay to allow slow modems to catch up
  18. ;;
  19. ;; Revision 1.2  1992/12/18  12:08:25  ahd
  20. ;; Add Plummer's fix for bad TASM assemble of com_errors
  21. ;;
  22. ;
  23. ;  9-Oct-93 Gumpertz    Further improved RTI and made it exit via LSI2 when
  24. ;            it still has the LSR available for counting errors.
  25. ;            Added/removed some JMP $+2 instructions to get some
  26. ;            I/O delay for slow 8259 and UART (8250) chips in
  27. ;            some old machines; I think one JMP is plenty for an
  28. ;            80286; the 386 and 486 are unlikely to be found in
  29. ;            machines that use old chips like the 8250.  Moby Sigh.
  30. ;            I suppose I will need some volunteers to test it.
  31. ;            Simplified CHROUT and then expanded it inline and
  32. ;            deleted the subroutine.  Simplified SENDII.
  33. ;  8-Oct-93 Gumpertz    Added _rts_off and _rts_on to support hardware
  34. ;            handshaking with modems.
  35. ;            Changed RXI to read one character without testing LSR.
  36. ;  7-Oct-93 Gumpertz    Made a number of changes to improve execution speed:
  37. ;            Changed START_TDATA, END_TDATA, START_RDATA, END_RDATA
  38. ;            to DWORDS.  Deleted TBuff and RBuff; (START_TDATA+2):0
  39. ;            and (START_RDATA+2):0 are now used instead.
  40. ;            Rearranged SPTAB for word alignment.
  41. ;            Changed SEND_OK to not be 0/1 but 0/10H/20H/30H
  42. ;            Deleted BP saving, setting, and restoring in routines
  43. ;            that don't use BP.
  44. ;            Added checks for R_SIZE or S_SIZE not powers of 2.
  45. ;            Changed receive_com and sen_com to NOT use CLI
  46. ;            unless really needed.
  47. ;            Expanded TX_CHR inline and deleted the subroutine.
  48. ;            Changed transmit FIFO back to 16 bytes and added
  49. ;            IER_SHADOW to save reading the IER.
  50. ;            Added a few even pseudo-ops togain a bit of speed.
  51. ; 28-Jun-93 Gumpertz    Added COM3IRQ5 option (and a few minor cleanups)
  52. ; 14-Jun-93 plummer    Add RET to spinloop routine
  53. ; 14-Jun-93 plummer    Set FIFO thresholds to 8 rather than 16 bytes
  54. ; 18-May-93 plummer    Define IO$DELAY and use in UART type determination
  55. ; 16-May-93 plummer    Debug code to printout UART type
  56. ; 22-Apr-93 plummer    Make case consistent in "TBuff" so it links properly
  57. ;  2-Dec-92 plummer    Fix com_errors() again.  Change got lost.
  58. ; Fix com_errors() to avoid problems with tasm.  Plummer, 11/16/92
  59. ; 8259 EOI issued after interrupts serviced.  Plummer, 3/25/92
  60. ; Fix botch in Set_Baud.  Plummer, 3/20/92
  61. ; Put in Gordon Lee's cure from dropped interrupts.  Plummer, 3/19/92
  62. ; TEMPORARY ioctl_com().  Plummer, 3/9/92.
  63. ; Clear OUT2 bit in UART.  Some machines use it so enable IRQ. Plummer, 3/9/92
  64. ; Release send buffer if we can't assign a recv buffer.  Plummer, 3/9/92
  65. ; Move EQU's outside of SP_TAB struc definition.  ahd, 3/8/92.
  66. ; ahd changes: short jmp's out of range in INST, OPEN ???  (ahd, 3/?/92)
  67. ; open_com() leaves DTR unchanged so Drew's autobaud works.  Plummer, 3/2/92
  68. ; Missing DX load in close_com() -- FIFO mode not cleared.  Plummer, 3/2/92
  69. ; C calling convention does not require saving AX, BX, CX, DX. Plummer 2/23/92
  70. ; Flush consideration of the PC Jr.  Wm. W. Plummer, 2/15/92
  71. ; Cleanup PUSHF/POPF and CLI/STI usage.  Wm. W. Plummer, 2/15/92
  72. ; Make SENDII have Giles Todd's change.  Wm. W. Plummer, 2/15/92
  73. ; Changes to Giles Todd's code to support dynamic buffers.  Plummer, 2/3/92
  74. ; 26 Jan 92 Giles Todd    Prime THR for UARTs which do not give a Tx empty
  75. ;            interrupt when Tx interrupts are enabled.
  76. ; S_SIZE & R_SIZE may be set with -D to MASM.  Wm. W. Plummer, 1/19/92
  77. ; Assign buffers dynamically.  Wm. W. Plummer, 1/19/92
  78. ; Unfix byte length -- I screwed up.  Wm. W. Plummer, 1/15/92
  79. ; Fix byte length with specific PARITY select.    Wm. W. Plummer, 1/13/92
  80. ; Buffers up to 4096 per AHD.  Wm. W. Plummer, 1/1/92
  81. ; Always use FIFO length of 16 on send side.  Wm. W. Plummer, 12/30/91.
  82. ; Init DSR and CTS previous state from current status.    Wm. Plummer, 12/30/91.
  83. ; UUPC conditional to disable v.24.  Wm. W. Plummer, 12/30/91.
  84. ; Buffer sizes up to 2048 per ahd.  Wm. W. Plummer, 12/15/91.
  85. ; dtr_on() switches to D connection if CTS&DSR don't come up.  WWP, 12/15/91.
  86. ; New dtr_on() logic.  Wm. W. Plummer, 12/11/91
  87. ; Fix bad reg. per report from user.  Wm. W. Plummer, 12/11/91
  88. ; Semicolon before control-L's for MASM 5.00 per ahd. Wm. W. Plummer, 12/8/91
  89. ; Use AHD's handling of COM ports.  Wm. W. Plummer, 11/29/91
  90. ; Buffer sizes reduced and required to be 2**N.  Wm. W. Plummer, 11/11/91
  91. ; Accomodate V.24 requirements on DTR flaps.  Wm. W. Plummer 10/15/91
  92. ; Revised DTR_ON_COM to solve user problem.  Wm. W. Plummer, 10/3/91
  93. ; Make time delays independent of CPU speed.  Wm. W. Plummer, 9/16/91
  94. ; Use interrupts to trace CD, DSR, Wm. W. Plummer, 9/16/91
  95. ; Remove modem control from TXI. Wm. W. Plummer, 9/13/91
  96. ; Completely redo the XOFF/XON logic.  Too many races before. Wm. W. Plummer
  97. ; Revise interrupt dispatch for speed & function.  William W. Plummer, 9/12/91
  98. ; Merge in ahd's changes to flush control Q,S when received as flow control
  99. ; SEND buffer allows one byte for a SENDII call.  Avoids flow control
  100. ;  lockups. - William W. Plummer, 8/30/91
  101. ; Support for NS16550A chip with SILO - William W. Plummer, 8/30/91
  102. ; Add modem_status() routine - William W. Plummer, 7/2/91
  103. ; Put wrong code under AHD conditional - William W. Plummer, 7/2/91
  104. ; Change TITLE, repair bad instr after INST3 - William W. Plummer, 7/1/91
  105. ; Modified to use COM1 thru COM4 - William W. Plummer, 2/21/91
  106. ; Eliminate (incomplete) support for DOS1 - William W. Plummer, 11/13/90
  107.  
  108. ; Changes may be copied and modified with no notice.  Copyrights and copylefts
  109. ; are consider silly and do not apply.    --  William W. Plummer
  110.  
  111. ; modified to use MSC calling sequence.  jrr 3/86
  112. ;****************************************************************************
  113. ; Communications Package for the IBM PC, XT, AT and strict compatibles.
  114. ; May be copied and used freely -- This is a public domain program
  115. ; Developed by Richard Gillmann, John Romkey, Jerry Saltzer,
  116. ; Craig Milo Rogers, Dave Mitton and Larry Afrin.
  117. ;
  118. ; We'd sure like to see any improvements you might make.
  119. ; Please send all comments and queries about this package
  120. ; to GILLMANN@USC-ISIB.ARPA
  121. ;
  122. ; o Supports both serial ports simultaneously
  123. ; o All speeds to 19200 baud
  124. ; o Compatible with PC, XT, AT
  125. ; o Built in XON/XOFF flow control option
  126. ; o C language calling conventions
  127. ; o Logs all comm errors
  128. ; o Direct connect or modem protocol
  129.     PAGE;
  130. ;
  131. ; Buffer sizes -- *** MUST be powers of 2 ****
  132.  
  133. IFDEF UUPC
  134.     R_SIZE    EQU    8192    ; 7 1K data packets + header
  135.     S_SIZE    EQU    8192    ; 7 1K data packets + header
  136. ENDIF
  137.  
  138. ; If not set above, maybe on assembler command line.  But if not, ...
  139. IFNDEF R_SIZE
  140.     R_SIZE    EQU    512    ; Recv buffer size
  141. ENDIF
  142. IFNDEF S_SIZE
  143.     S_SIZE    EQU    512    ; Send buffer size
  144. ENDIF
  145.  
  146. IF (R_SIZE AND -R_SIZE) NE R_SIZE
  147.     .ERR    R_SIZE must be a power of 2
  148. ENDIF
  149.  
  150. IF (S_SIZE AND -S_SIZE) NE S_SIZE
  151.     .ERR    S_SIZE must be a power of 2
  152. ENDIF
  153.  
  154. ; INTERRUPTS
  155. VECIRQ3 EQU    08H+3        ; IRQ3 VECTOR FROM 8259
  156. VECIRQ4 EQU    08H+4        ; IRQ4 VECTOR FROM 8259
  157. VECIRQ5 EQU    08H+5        ; IRQ5 VECTOR FROM 8259
  158.  
  159. IRQ3    EQU    2*2*2        ; 8259A OCW1 MASK, M3=1, A0=0
  160. IRQ4    EQU    2*2*2*2     ; 8259A OCW1 MASK, M4=1, A0=0
  161. IRQ5    EQU    2*2*2*2*2    ; 8259A OCW1 MASK, M4=1, A0=0
  162.  
  163. NIRQ3    EQU    NOT IRQ3 AND 0FFH ; COMPLEMENT OF ABOVE
  164. NIRQ4    EQU    NOT IRQ4 AND 0FFH ; COMPLEMENT OF ABOVE
  165. NIRQ5    EQU    NOT IRQ5 AND 0FFH ; COMPLEMENT OF ABOVE
  166.  
  167. EOI3    EQU    3 OR 01100000B    ; 8259A OCW2 SPECIFIC IRQ3 EOI, A0=0
  168. EOI4    EQU    4 OR 01100000B    ; 8259A OCW2 SPECIFIC IRQ4 EOI, A0=0
  169. EOI5    EQU    5 OR 01100000B    ; 8259A OCW2 SPECIFIC IRQ5 EOI, A0=0
  170.  
  171. ; 8259 PORTS
  172. INTA00    EQU    20H        ; 8259A PORT, A0 = 0
  173. INTA01    EQU    21H        ; 8259A PORT, A0 = 1
  174.  
  175. ; FLOW CONTROL CHARACTERS
  176. CONTROL_Q EQU    11H        ; XON
  177. CONTROL_S EQU    13H        ; XOFF
  178. ; MISC.
  179. DOS    EQU    21H        ; DOS FUNCTION CALLS
  180.  
  181. ;
  182. ; ROM BIOS Data Area
  183. ;
  184. RBDA    SEGMENT AT 40H
  185. RS232_BASE DW    4 DUP(?)    ; ADDRESSES OF RS232 ADAPTERS
  186. RBDA    ENDS
  187.  
  188. PAGE;
  189. ;
  190. ; TABLE FOR EACH SERIAL PORT
  191. ;
  192. SP_TAB        STRUC
  193. PORT        DB    ?    ; 1 OR 2 OR 3 OR 4
  194. INSTALLED    DB    ?    ; IS PORT INSTALLED ON THIS PC? (1=YES,0=NO)
  195. ; PARAMETERS FOR THIS INTERRUPT LEVEL
  196. IRQVEC        DB    ?    ; INTERRUPT NUMBER
  197. IRQ        DB    ?    ; 8259A OCW1 MASK
  198. NIRQ        DB    ?    ; COMPLEMENT OF ABOVE
  199. EOI        DB    ?    ; 8259A OCW2 SPECIFIC END OF INTERRUPT
  200. ; INTERRUPT HANDLERS FOR THIS LEVEL
  201. INT_HNDLR    DW    ?    ; OFFSET TO INTERRUPT HANDLER
  202. OLD_COM     DD    ?    ; OLD HANDLER'S OFFSET AND SEGMENT
  203. ; ATTRIBUTES
  204. BAUD_RATE    DW    ?    ; 19200 MAX (maybe 38400 or 57600 with 16550?)
  205. CONNECTION    DB    ?    ; M(ODEM), D(IRECT)
  206. PARITY        DB    ?    ; N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  207. STOP_BITS    DB    ?    ; 1, 2
  208. XON_XOFF    DB    ?    ; E(NABLED), D(ISABLED)
  209. UART_SILO_LEN    DB    ?    ; Size of a transmit silo chunk (1 for 8250)
  210. ; FLOW CONTROL STATE
  211. HOST_OFF    DB    ?    ; HOST XOFF'ED (1=YES,0=NO)
  212. PC_OFF        DB    ?    ; PC XOFF'ED (1=YES,0=NO)
  213. URGENT_SEND    DB    ?    ; We MUST send one byte (XON/XOFF)
  214. SEND_OK     DB    ?    ; DSR and CTS bits, masked from MSR
  215. IER_SHADOW    DB    ?    ; shadow copy of what we last wrote to IER
  216. ; ERROR COUNTS
  217. ERROR_BLOCK    DW    8 DUP(?); EIGHT ERROR COUNTERS
  218.  
  219. ; UART PORTS - DATREG thru MSR must be in order shown.
  220. DATREG        DW    ?    ; DATA REGISTER
  221. IER        DW    ?    ; INTERRUPT ENABLE REGISTER
  222. IIR        DW    ?    ; INTERRUPT IDENTIFICATION REGISTER (RO)
  223. LCR        DW    ?    ; LINE CONTROL REGISTER
  224. MCR        DW    ?    ; MODEM CONTROL REGISTER
  225. LSR        DW    ?    ; LINE STATUS REGISTER
  226. MSR        DW    ?    ; MODEM STATUS REGISTER
  227. ;
  228. ; BUFFER POINTERS
  229. START_TDATA    DD    ?    ; POINTER TO FIRST CHARACTER IN X-MIT BUFFER
  230. END_TDATA    DD    ?    ; POINTER TO FIRST FREE SPACE IN X-MIT BUFFER
  231. START_RDATA    DD    ?    ; POINTER TO FIRST CHARACTER IN REC. BUFFER
  232. END_RDATA    DD    ?    ; POINTER TO FIRST FREE SPACE IN REC. BUFFER
  233. ; BUFFER COUNTS
  234. SIZE_TDATA    DW    ?    ; NUMBER OF CHARACTERS IN X-MIT BUFFER
  235. SIZE_RDATA    DW    ?    ; NUMBER OF CHARACTERS IN REC. BUFFER
  236. ; BUFFERS
  237. SP_TAB        ENDS
  238.  
  239. ; SP_TAB EQUATES
  240. ; WE HAVE TO USE THESE BECAUSE OF PROBLEMS WITH STRUC
  241. EOVFLOW     EQU    ERROR_BLOCK    ; BUFFER OVERFLOWS
  242. EOVRUN        EQU    ERROR_BLOCK+2    ; RECEIVE OVERRUNS
  243. EBREAK        EQU    ERROR_BLOCK+4    ; BREAK CHARS
  244. EFRAME        EQU    ERROR_BLOCK+6    ; FRAMING ERRORS
  245. EPARITY     EQU    ERROR_BLOCK+8    ; PARITY ERRORS
  246. EXMIT        EQU    ERROR_BLOCK+10    ; TRANSMISSION ERRORS
  247. EDSR        EQU    ERROR_BLOCK+12    ; DATA SET READY ERRORS
  248. ECTS        EQU    ERROR_BLOCK+14    ; CLEAR TO SEND ERRORS
  249. DLL        EQU    DATREG        ; LOW DIVISOR LATCH
  250. DLH        EQU    IER        ; HIGH DIVISOR LATCH
  251.  
  252. ;
  253. ; Equates having to do with the FIFO
  254. ;
  255. FCR        EQU    IIR    ; FIFO Control Register (WO)
  256.  ; Bits in FCR for NS16550A UART.  Note that writes to FCR are ignored
  257.  ; by other chips.
  258.  FIFO_ENABLE    EQU    001H    ; Enable FIFO mode
  259.  FIFO_CLR_RCV    EQU    002H    ; Clear receive FIFO
  260.  FIFO_CLR_XMT    EQU    004H    ; Clear transmit FIFO
  261.  FIFO_STR_DMA    EQU    008H    ; Start DMA Mode
  262.  ; 10H and 20H bits are register bank select on some UARTs (not handled)
  263.  FIFO_SZ_1    EQU    000H    ; RCV Warning level is 1 byte in the FIFO
  264.  FIFO_SZ_4    EQU    040H    ; RCV Warning level is 4 bytes in the FIFO
  265.  FIFO_SZ_8    EQU    080H    ; RCV Warning level is 8 bytes in the FIFO
  266.  FIFO_SZ_14    EQU    0C0H    ; RCV Warning level is 14 bytes in the FIFO
  267.  ;
  268.  ; Commands used in code to operate FIFO.  Made up as combinations of above
  269.  ;
  270.  FIFO_CLEAR    EQU    0    ; Turn off FIFO
  271.  FIFO_SETUP    EQU    FIFO_SZ_8 OR FIFO_ENABLE
  272.  FIFO_INIT    EQU    FIFO_SETUP OR FIFO_CLR_RCV OR FIFO_CLR_XMT
  273.  ;
  274.  ; Miscellaneous FIFO-related stuff
  275.  ;
  276. FIFO_ENABLED    EQU    0C0H    ; 16550 makes these equal FIFO_ENABLE
  277. FIFO_LEN    EQU    16    ; Length of the transmit FIFO in a 16550A
  278.     PAGE;
  279. ;    put the data in the DGROUP segment
  280. ;    far calls enter with DS pointing to DGROUP
  281. ;
  282. DGROUP    GROUP _DATA
  283. _DATA    SEGMENT PUBLIC 'DATA'
  284. ;
  285. ; DATA AREAS FOR EACH PORT
  286. AREA1    SP_TAB    <1,0,VECIRQ4,IRQ4,NIRQ4,EOI4,OFFSET COM_TEXT:INT_HNDLR1> ; COM1
  287. AREA2    SP_TAB    <2,0,VECIRQ3,IRQ3,NIRQ3,EOI3,OFFSET COM_TEXT:INT_HNDLR2> ; COM2
  288.  IFDEF COM3IRQ5 ; special KLUDGE: assemble for COM3 with IRQ5 instead of IRQ4
  289. AREA3    SP_TAB    <3,0,VECIRQ5,IRQ5,NIRQ5,EOI5,OFFSET COM_TEXT:INT_HNDLR3> ; COM3
  290.  ELSE        ; normal: assemble for COM3 with IRQ4
  291. AREA3    SP_TAB    <3,0,VECIRQ4,IRQ4,NIRQ4,EOI4,OFFSET COM_TEXT:INT_HNDLR3> ; COM3
  292.  ENDIF
  293. AREA4    SP_TAB    <4,0,VECIRQ3,IRQ3,NIRQ3,EOI3,OFFSET COM_TEXT:INT_HNDLR4> ; COM4
  294. CURRENT_AREA    DW OFFSET DGROUP:AREA1    ; CURRENTLY SELECTED AREA
  295.  
  296. DIV50        DW 2304         ; ACTUAL DIVISOR FOR 50 BAUD IN USE
  297.  
  298. IFDEF DEBUG
  299.  ST8250     DB "8250 or 16450$"
  300.  ST16550    DB "16550AN$"
  301.  STUART     DB " UART detected", 0DH, 0AH, '$'
  302. ENDIF
  303.  
  304. _DATA    ENDS
  305.  
  306.  
  307.  
  308.  
  309. COM_TEXT SEGMENT PARA PUBLIC 'CODE'
  310.      ASSUME CS:COM_TEXT,DS:DGROUP,ES:NOTHING
  311.  
  312.      PUBLIC AREA1, AREA2, AREA3, AREA4
  313.      PUBLIC _select_port
  314.      PUBLIC _save_com
  315.      PUBLIC _install_com
  316.      PUBLIC _restore_com
  317.      PUBLIC _open_com
  318.      PUBLIC _ioctl_com
  319.      PUBLIC _close_com
  320.      PUBLIC _dtr_on
  321.      PUBLIC _dtr_off
  322.      PUBLIC _rts_off
  323.      PUBLIC _rts_on
  324.      PUBLIC _r_count
  325.      PUBLIC _s_count
  326.      PUBLIC _receive_com
  327.      PUBLIC _send_com
  328.      PUBLIC _sendi_com
  329. IFNDEF UUPC
  330.      PUBLIC _send_local
  331. ENDIF
  332.      PUBLIC _break_com
  333.      PUBLIC _com_errors
  334.      PUBLIC _modem_status
  335. IFDEF DEBUG
  336.      PUBLIC INST2, INST4
  337.      PUBLIC OPEN1, OPEN2, OPENX
  338.      PUBLIC DTRON1, DTRON6, DTRONF, DTRDIR, DTRONS, DTRONX
  339.      PUBLIC RECV1, RECV3, RECV4, RECVX
  340.      PUBLIC SEND1, SEND2, SEND3, SENDX
  341.      PUBLIC WaitN, WaitN1, WaitN2
  342.      PUBLIC SENDII, SENDII1, SENDII2, SENDII4
  343.      PUBLIC SPINLOOP
  344.      PUBLIC BREAKX
  345.      PUBLIC INT_HNDLR1, INT_HNDLR2, INT_HNDLR3, INT_HNDLR4
  346.      PUBLIC INT_COMMON, REPOLL, INT_END
  347.      PUBLIC LSI, LSI2
  348.      PUBLIC MSI
  349.      PUBLIC TXI, TXI1, TXI3, TXI4, TXI9
  350.      PUBLIC RXI, RXI0, RXINXT, RXIFUL, RXI1, RXI2, RXI3
  351. ENDIF
  352.     PAGE;
  353. ; Notes, thoughts and explainations by Bill Plummer.  These are intended to
  354. ; help those of you who would like to make modifications.
  355.  
  356. ; Here's the order of calls in UUPC.  The routines in COMM.ASM are called
  357. ; from ulib.c.
  358.  
  359. ; First (when a line in system has been read?), ulib&openline calls
  360. ;     select_port()        ; Sets up CURRENT_AREA
  361. ; then,  save_com()        ; Save INT vector
  362. ; then,  install_com()        ; Init area, hook INT
  363. ; then,  open_com(&cmd, 'D', 'N', STOP*T, 'D')  ; Init UART, clr bufs
  364. ; then,  dtr_on().
  365.  
  366. ; At that point the line is up and running.  UUPC calls ulib&sread()
  367. ; which calls,    receive_com();
  368.  
  369. ; And UUPC calls ulib&swrite()
  370. ; which calls,    send_com();
  371.  
  372. ; To cause an error that the receiver will see, UUPC calls ulib&ssendbrk();
  373. ; which calls,    break_com();
  374.  
  375. ; When all done with the line, UUPC calls ulib&closeline()
  376. ; which calls,    dtr_off();
  377. ; then,  close_com();
  378. ; then,  restore_com();     ; Unhook INT
  379. ; and,     stat_errors();
  380.  
  381.  
  382. ; Note: On the PC COM1 and COM3 share IRQ4, while COM2 and COM4 share IRQ3.
  383. ; BUT, only one device on a given IRQ line can be active at a time.  So it is
  384. ; sufficient for UUPC to hook whatever IRQ INT its modem is on as long as it
  385. ; unhooks it when it is done with that COM port.  COMM cannot be an installed
  386. ; device driver since it must go away when UUPC is done so that other devices
  387. ; on the same INTs will come back to life.  Also, it is OK to have a static
  388. ; CURRENT_AREA containing the current area that UUPC is using.
  389.  
  390. ; Note about using the NS16550A UART chip's FIFOs.  These are operated as
  391. ; silos.  In other words when an interrupt happens because the receive(send)
  392. ; FIFO is nearly full(empty), as many bytes as possible are transferred and
  393. ; the interrupt dismissed.  Thus, the interrupt load is lowered.
  394.  
  395.  
  396. ; Concerning the way the comm line is brought up.
  397. ; There are two basic cases, the Direct ('D') connection and the Modem ('M')
  398. ; connection.  For either UUPC calls dtr_on_com() to bring up the line.  This
  399. ; causes Data Terminal Ready (DTR) and Request To Send (RTS) to be set.  Note
  400. ; this is OK for a simple 3-wire link but may be REQUIRED for a COM port
  401. ; connected to an external modem.
  402.  
  403. ; The difference between a D connection and an M connection is
  404. ; whether or not the PC can expect any signals back from the modem.  If
  405. ; there is a simple 3-wire link, Data Set Ready will be floating.
  406. ; (Actually, some wise people jumper Data Terminal Read back to Data
  407. ; Set Ready so the PC sees its own DTR appear as DSR.)    UUPC should be
  408. ; able to handle the simplest cable as a design feature.  So both D and
  409. ; M connections send out DTR and RTS, but only the M connection expects
  410. ; a modem to respond.
  411.  
  412. ; Then, if it is full modem connection (M), we wait for a few
  413. ; seconds hoping that both Data Set Ready (DSR) and Clear To Send (CTS)
  414. ; will come up.  If they don't, the associated counters are incremented
  415. ; for subsequent printing in the error log.  Note that no error is
  416. ; reported from COMM to UUPC at this point, although this would be a
  417. ; good idea.  COMMFIFO.ASM forces the connection to be a D type and lets
  418. ; UUPC storm ahead with its output trying to
  419. ; establish a link, but the output is never sent due to one of the
  420. ; control signals being false.    UUPC could check the modem status using
  421. ; a call which has been installed just for this purpose.
  422.  
  423. ; Note, if you are going to connect your PC running UUPC to,
  424. ; say, a mainframe and you need hardware flow control (i.e., RTS-CTS
  425. ; handshaking), use a Modem connection.  Using a simple 3-wire cable
  426. ; forbids hardware flow control and UUPC must be instructed to use a
  427. ; Direct connection.  Refer to comments in the SYSTEMS file on how to
  428. ; make this selection.
  429.  
  430. ; References used in designing the revisions to COMM.ASM:
  431. ;    1.    The UNIX fas.c Driver code.
  432. ;    2.    SLIP8250.ASM from the Clarkson driver set.
  433. ;    3.    NS16550A data sheet and AN-491 from National Semiconductor.
  434. ;    4.    Bell System Data Communications, Technical Reference for
  435. ;        Data Set 103A, Interface Specification, February, 1967
  436. ;    5.    Network mail regarding V.24
  437. ;    6.    Joe Doupnik
  438.     PAGE;
  439. ;
  440. ; void far select_port(int)
  441. ;    Arg is 1..4 and specifies which COM port is referenced by
  442. ;    all other calls in this package.
  443. ;
  444. _select_port PROC FAR
  445.     push bp
  446.     mov bp,sp
  447.     MOV    AX,[BP+6]        ; get argument
  448.     CMP    AX,1            ; Port 1?
  449.      JE    SP1            ; Yes
  450.     CMP    AX,2            ; Port 2?
  451.      MOV    BX,OFFSET DGROUP:AREA2    ; SELECT COM2 DATA AREA
  452.      JE    SPX            ; Yes
  453.     CMP    AX,3            ; Port 3?
  454.      MOV    BX,OFFSET DGROUP:AREA3    ; SELECT COM3 DATA AREA
  455.      JE    SPX            ; Yes
  456.     CMP    AX,4            ; Port 4?
  457.      MOV    BX,OFFSET DGROUP:AREA4    ; SELECT COM4 DATA AREA
  458.      JE    SPX            ; Yes
  459.     INT 20H             ; N.O.T.A. ????? Halt for debugging!
  460.     ; Assume port 1 if continued
  461. SP1:    MOV    BX,OFFSET DGROUP:AREA1    ; SELECT COM1 DATA AREA
  462. SPX:    MOV    CURRENT_AREA,BX     ; SET SELECTION IN MEMORY
  463.     mov sp,bp
  464.     pop bp
  465.     RET
  466. _select_port ENDP
  467.     PAGE;
  468. ;
  469. ; void far save_com(void)
  470. ;    Save the interrupt vector of the selected COM port.
  471. ;    N.B. save_com() and restore_com() call MUST be properly nested
  472. ;
  473. _save_com PROC FAR
  474.     PUSH SI
  475.     PUSH    ES            ; SAVE EXTRA SEGMENT
  476.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  477.  
  478. ; Save old interrupt vector
  479.     MOV    AH,35H            ; FETCH INTERRUPT VECTOR CONTENTS
  480.     MOV    AL,IRQVEC[SI]        ; INTERRUPT NUMBER
  481.     INT    DOS            ; DOS 2 FUNCTION
  482.     MOV    WORD PTR OLD_COM[SI],BX ; SAVE ES:BX
  483.     MOV    WORD PTR OLD_COM[SI+2],ES ; FOR LATER RESTORATION
  484.     POP    ES            ; RESTORE ES
  485.     POP SI
  486.     RET                ; DONE
  487. _save_com ENDP
  488.     PAGE;
  489. ;
  490. ; int far install_com(void)
  491. ;
  492. ;    Install the selected COM port.
  493. ;    Returns:    0: Failure
  494. ;            1: Success
  495. ;
  496. ; SET UART PORTS FROM RS-232 BASE IN ROM BIOS DATA AREA
  497. ; INITIALIZE PORT CONSTANTS AND ERROR COUNTS
  498. ;
  499. ; Assign blocks of memory for transmit and receive buffers
  500. ;
  501. _install_com PROC FAR
  502.     PUSH SI
  503.     PUSH ES
  504.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  505.     CMP    INSTALLED[SI],1     ; Is port installed on this machine?
  506.      JNE    INST1            ; NO, CONTINUE
  507.      JMP    INST9            ; ELSE JUMP IF ALREADY INSTALLED
  508.  
  509. ; Assign memory for transmit and receive buffers
  510.  
  511. INST1:
  512.     MOV BX,S_SIZE/16        ; Send buffer size in paragraphs
  513.     MOV AX,4800H            ; Allocate memory
  514.     INT DOS
  515.      JC INSTFAIL            ; Give fail return
  516.     MOV WORD PTR START_TDATA[SI],0
  517.     MOV WORD PTR START_TDATA[SI+2],AX
  518.     MOV WORD PTR END_TDATA[SI],0
  519.     MOV WORD PTR END_TDATA[SI+2],AX
  520.  
  521.     MOV BX,R_SIZE/16        ; Receive buffer size in paragraphs
  522.     MOV AX,4800H            ; Allocate memory
  523.     INT DOS
  524.      JC INSTFREET            ; jump on FAILURE
  525.     MOV WORD PTR START_RDATA[SI],0
  526.     MOV WORD PTR START_RDATA[SI+2],AX
  527.     MOV WORD PTR END_RDATA[SI],0
  528.     MOV WORD PTR END_RDATA[SI+2],AX
  529.  
  530. IFDEF DEBUG
  531.     PUSH DI
  532.     CLD                ; Go up in memory
  533.     XOR AX,AX            ; A zero to store
  534.     MOV ES,START_TDATA[SI]        ; Transmit buffer location
  535.     MOV DI,AX
  536.     MOV CX,S_SIZE/2         ; Size of buffer
  537.     REP STOSW            ; Clear entire buffer
  538.     MOV ES,START_RDATA[SI]        ; Receive buffer location
  539.     MOV DI,AX
  540.     MOV CX,R_SIZE/2         ; Size of buffer
  541.     REP STOSW            ; Clear entire buffer
  542.     POP DI
  543. ENDIF
  544.     PAGE;
  545.  
  546.     MOV    BX,RBDA         ; ROM BIOS DATA AREA
  547.     MOV    ES,BX            ; TO ES
  548.     ASSUME    ES:RBDA
  549.  
  550. ; Map port number (COMx) into IO Address using the RS232_Base[x] table in
  551. ; the BIOS data area.  If any of the ports is missing there should be a
  552. ; zero in the table for this COM port.    BIOS startup routines pack the table
  553. ; so that if you have a COM4 but no COM3, 2E8 will be found in 40:4 and 0
  554. ; will be in 40:6.
  555.  
  556. ; N.B. The exact IO address in 40:x is irrelevant and may well be something
  557. ; other than the "standard" values if specially designed hardware is used.
  558. ; To minimize flack, we will use the standard value if the slot in the table
  559. ; is 0.  The bad side effect of this is that (in the standard losing case of
  560. ; a COM4 but no COM3) both COM3 and COM4 will reference the hardware at 2E8.
  561.  
  562.     CMP    PORT[SI],1        ; PORT 1?
  563.      JE    INST3F8         ; Yes
  564.     CMP    PORT[SI],2        ; PORT 2?
  565.      JE    INST2F8         ; Yes
  566.     CMP    PORT[SI],3        ; PORT 3?
  567.      JE    INST3E8         ; Yes
  568.     CMP    PORT[SI],4        ; PORT 4?
  569.      JE    INST2E8         ; Yes
  570.     INT    20H            ; NOTA. (Caller is screwed up badly)
  571.  
  572. ; We interrupt this program to bring you code that we want to be within
  573. ; short-jump range of the code that conditionally jumps to it:
  574.  
  575. INSTFREEBOTH:    ; Unhand the receive and send buffers assigned above
  576.     MOV ES,WORD PTR START_RDATA[SI+2] ; Receive buffer paragraph
  577.     assume ES:nothing
  578.     MOV AX,4900H            ; Release memory
  579.     INT DOS
  580.     ; Ignore error
  581. INSTFREET:    ; Unhand the send buffer assigned above
  582.     MOV ES,WORD PTR START_TDATA[SI+2] ; Transmit buffer paragraph
  583.     MOV AX,4900H            ; Release memory
  584.     INT DOS
  585.     ; Ignore error
  586.     ; Fall into INSTFAIL
  587.  
  588. ; PORT NOT INSTALLED
  589. INSTFAIL:
  590.     XOR AX,AX
  591.     JMP INSTX
  592.  
  593.     ASSUME    ES:RBDA
  594. ; And now back to your regularly scheduled program:
  595.  
  596. INST3F8:MOV AX,3F8H            ; Standard COM1 location
  597.     CMP    RS232_BASE+0,0000H    ; We have information?
  598.      JE    INST2            ; No --> Use default
  599.     MOV    AX,RS232_BASE+0     ; Yes --> Use provided info
  600.     JMP    SHORT INST2        ; CONTINUE
  601.  
  602. INST2F8:MOV AX,2F8H            ; Standard COM2 location
  603.     CMP    RS232_BASE+2,0000H    ; We have information?
  604.      JE    INST2            ; No --> Use default
  605.     MOV    AX,RS232_BASE+2     ; Yes --> Use provided info
  606.     JMP    SHORT INST2        ; CONTINUE
  607.  
  608. INST3E8:MOV AX,3E8H            ; Standard COM3 location
  609.     CMP    RS232_BASE+4,0000H    ; We have information?
  610.      JE    INST2            ; No --> Use default
  611.     MOV    AX,RS232_BASE+4     ; Yes --> Use provided info
  612.     JMP    SHORT INST2        ; CONTINUE
  613.  
  614. INST2E8:MOV AX,2E8H            ; Standard COM4 location
  615.     CMP    RS232_BASE+6,0000H    ; We have information?
  616.      JE    INST2            ; No --> Use default
  617.     MOV    AX,RS232_BASE+6     ; Yes --> Use provided info
  618.     ; Fall into INST2
  619.  
  620.  
  621. ; Now we have an IO address for the COMx that we want to use.  If it is
  622. ; anywhere in RS232_Base, we know that it has been check and is OK to use.
  623. ; So, even if my 2E8 (COM4) appears in 40:6 (normally for COM3), I can use
  624. ; it.
  625.  
  626. INST2:    CMP    AX,RS232_BASE        ; INSTALLED?
  627.      JE    INST2A            ; JUMP IF SO
  628.     CMP    AX,RS232_BASE+2     ; INSTALLED?
  629.      JE    INST2A            ; JUMP IF SO
  630.     CMP    AX,RS232_BASE+4     ; INSTALLED?
  631.      JE    INST2A            ; JUMP IF SO
  632.     CMP    AX,RS232_BASE+6     ; INSTALLED?
  633.      JNE    INSTFREEBOTH        ; JUMP IF NOT
  634.     ; Fall into INST2A
  635.  
  636. INST2A: MOV    BX,DATREG        ; OFFSET OF TABLE OF PORTS
  637.     MOV    CX,7            ; LOOP SIX TIMES
  638. INST3:    MOV    WORD PTR [SI][BX],AX    ; SET PORT ADDRESS
  639.     INC    AX            ; NEXT PORT
  640.     ADD    BX,2            ; NEXT WORD ADDRESS
  641.      LOOP    INST3            ; RS232 BASE LOOP
  642.  
  643. ; CLEAR ERROR COUNTS
  644.     MOV    WORD PTR EOVFLOW[SI],0    ; BUFFER OVERFLOWS
  645.     MOV    WORD PTR EOVRUN[SI],0    ; RECEIVE OVERRUNS
  646.     MOV    WORD PTR EBREAK[SI],0    ; BREAK CHARS
  647.     MOV    WORD PTR EFRAME[SI],0    ; FRAMING ERRORS
  648.     MOV    WORD PTR EPARITY[SI],0    ; PARITY ERRORS
  649.     MOV    WORD PTR EXMIT[SI],0    ; TRANSMISSION ERRORS
  650.     MOV    WORD PTR EDSR[SI],0    ; DATA SET READY ERRORS
  651.     MOV    WORD PTR ECTS[SI],0    ; CLEAR TO SEND ERRORS
  652.  
  653.     PUSHF                ; Save caller's interrupt state
  654.     CLI                ; Stray interrupts cause havoc
  655.  
  656.     MOV DX,FCR[SI]            ; Get FIFO Control Register
  657.     MOV AL,FIFO_INIT
  658.     OUT DX,AL            ; Try to initialize the FIFO
  659.     CALL SPINLOOP            ; Permit I/O bus to settle
  660.     MOV DX,IIR[SI]            ; Get interrupt ID register
  661.     IN AL,DX            ; See how the UART responded
  662.     AND AL,FIFO_ENABLED        ; Keep only these bits
  663.     MOV CL,1            ; Assume size 1 for 8250/16450 case
  664.     CMP AL,FIFO_ENABLED        ; See if 16550A
  665.      JNE INST4            ; Jump if not
  666.     MOV CL,FIFO_LEN
  667. INST4:    MOV UART_SILO_LEN[SI],CL    ; Save chunk size for XMIT side
  668.  IF FCR NE IIR                ; FCR should be same as IIR
  669.     MOV DX,FCR[SI]
  670.  ENDIF
  671.     MOV AL,FIFO_CLEAR        ; disable the FIFOs until open_com
  672.     OUT DX,AL
  673.  
  674.     POPF                ; Restore caller's interrupt state
  675.  
  676.     MOV    AH,25H            ; SET INTERRUPT VECTOR CONTENTS
  677.     MOV    AL,IRQVEC[SI]        ; INTERRUPT NUMBER
  678.     MOV    DX,INT_HNDLR[SI]    ; OUR INTERRUPT HANDLER [WWP]
  679.     PUSH    DS            ; SAVE DATA SEGMENT
  680.     PUSH    CS            ; COPY CS
  681.     POP    DS            ; TO DS
  682.     INT    DOS            ; DOS FUNCTION
  683.     POP    DS            ; RECOVER DATA SEGMENT
  684.  
  685. ; PORT INSTALLED
  686. INST9:    MOV AX,1
  687.     ;Fall into INSTX
  688.  
  689. ; Common exit
  690. INSTX:    MOV INSTALLED[SI],AL        ; Indicate whether installed or not
  691. IFDEF DEBUG
  692.     MOV DX,OFFSET ST8250
  693.     CMP UART_SILO_LEN[SI],1
  694.      JE INSTXX
  695.     MOV DX,OFFSET ST16550
  696. INSTXX: MOV AH,9
  697.     INT DOS             ; Announce UART type
  698.     MOV DX,OFFSET STUART
  699.     INT DOS
  700. ENDIF
  701.     POP ES
  702.     assume ES:nothing
  703.     POP SI
  704.     RET
  705. _install_com ENDP
  706.     PAGE;
  707. ;
  708. ; void far restore_com(void)
  709. ;    Restore original interrupt vector and release storage
  710. ;
  711. _restore_com PROC FAR
  712.     PUSHF
  713.     PUSH SI
  714.     PUSH ES
  715.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  716.     CLI
  717.     MOV    INSTALLED[SI],0     ; PORT IS NO LONGER INSTALLED
  718.     PUSH    DS            ; SAVE DS
  719.     LDS    DX,OLD_COM[SI]        ; OLD INTERRUPT HANDLER IN DS:BX
  720.     MOV    AH,25H            ; SET INTERRUPT VECTOR FUNCTION
  721.     MOV    AL,IRQVEC[SI]        ; INTERRUPT NUMBER
  722.     INT    DOS            ; DOS FUNCTION
  723.     POP    DS            ; Recover our data segment
  724.  
  725.     MOV ES,WORD PTR START_TDATA[SI+2] ; Transmit buffer paragraph
  726.     MOV AX,4900H            ; Release memory
  727.     INT DOS
  728.      ; Ignore error
  729.     MOV ES,WORD PTR START_RDATA[SI+2] ; Receive buffer paragraph
  730.     MOV AX,4900H
  731.     INT DOS
  732.      ; Ignore error
  733.     POP ES
  734.     POP SI
  735.     POPF
  736.     RET
  737. _restore_com ENDP
  738.     PAGE;
  739. ;
  740. ; void far open_com(int Baud, char Conn, char Parity, char Stops, char Flow);
  741. ;
  742. ; CLEAR BUFFERS
  743. ; RE-INITIALIZE THE UART
  744. ; ENABLE INTERRUPTS ON THE 8259 INTERRUPT CONTROL CHIP
  745. ;
  746. ; [bp+6] = BAUD RATE
  747. ; [bp+8] = CONNECTION: M(ODEM), D(IRECT)
  748. ; [bp+10] = PARITY:    N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  749. ; [bp+12] = STOP BITS:    1, 2
  750. ; [bp+14] = XON/XOFF:    E(NABLED), D(ISABLED)
  751. ;
  752. _open_com PROC FAR
  753.     push bp
  754.     mov bp,sp
  755.     PUSH SI
  756.     PUSHF
  757.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  758.     CLI                ; INTERRUPTS OFF
  759.     TEST INSTALLED[SI],1        ; Port installed?
  760.      JNZ OPEN1            ; Yes --> Proceed
  761.       JMP OPENX            ; No  --> Get out
  762.  
  763. OPEN1:    mov ax,[bp+6]
  764.     MOV    BAUD_RATE[SI],AX    ; SET
  765.     mov bh,[bp+8]
  766.     MOV    CONNECTION[SI],BH    ; ARGS
  767.     mov bl,[bp+10]
  768.     MOV    PARITY[SI],BL        ; IN
  769.     mov ch,[bp+12]
  770.     MOV    STOP_BITS[SI],CH    ; MEMORY
  771.     mov cl,[bp+14]
  772.     MOV    XON_XOFF[SI],CL
  773.  
  774. ; RESET FLOW CONTROL
  775.     MOV    HOST_OFF[SI],0        ; HOST FLOWING
  776.     MOV    PC_OFF[SI],0        ; PC FLOWING
  777.     MOV URGENT_SEND[SI],0        ; No (high priority) flow ctl
  778.     MOV SEND_OK[SI],0        ; DTR&CTS are not on yet
  779.  
  780. ; RESET BUFFER COUNTS AND POINTERS
  781.     MOV    WORD PTR START_TDATA[SI],0
  782.     MOV    WORD PTR END_TDATA[SI],0
  783.     MOV    WORD PTR START_RDATA[SI],0
  784.     MOV    WORD PTR END_RDATA[SI],0
  785.     MOV    SIZE_TDATA[SI],0
  786.     MOV    SIZE_RDATA[SI],0
  787.  
  788. ;
  789. ; RESET THE UART
  790.     MOV DX,MCR[SI]            ; Modem Control Register
  791.     IN AL,DX            ; Get current settings
  792.     JMP SHORT $+2
  793. ; In next line, comment doesn't match the constant.  Should it be 01H?  -RHG
  794.     AND AL,0FEH            ; Clr RTS, OUT1, OUT2 & LOOPBACK, but
  795.     OUT DX,AL            ; Not DTR (No hangup during autobaud)
  796.     MOV DX,MSR[SI]            ; Modem Status Register
  797.     JMP SHORT $+2
  798.     IN AL,DX            ; Get current DSR and CTS states.
  799.     JMP SHORT $+2
  800.     AND AL,30H            ; Init PREVIOUS STATE FLOPS to current
  801.     OUT DX,AL            ;  state and clear Loopback, etc.
  802.     MOV SEND_OK[SI],AL        ; If 30H, allow TXI to send out data
  803.     JMP SHORT $+2
  804.     IN AL,DX            ; Re-read to get delta bits & clr int
  805.     JMP SHORT $+2
  806. OPEN2:    MOV DX,FCR[SI]            ; I/O Address of FIFO control register
  807.     MOV AL,FIFO_CLEAR        ; Disable FIFOs
  808.     OUT DX,AL            ; Non-16550A chips will ignore this
  809.     MOV    DX,LSR[SI]        ; RESET LINE STATUS CONDITION
  810.     JMP SHORT $+2
  811.     IN    AL,DX
  812.     MOV    DX,DATREG[SI]        ; RESET RECEIVE DATA CONDITION
  813.     JMP SHORT $+2
  814.     IN    AL,DX
  815.     MOV    DX,MSR[SI]        ; RESET MODEM DELTAS AND CONDITIONS
  816.     JMP SHORT $+2
  817.     IN    AL,DX
  818.  
  819.     CALL Set_Baud            ; Set the baud rate from arg
  820.     PAGE;
  821. ; SET PARITY AND NUMBER OF STOP BITS
  822.     MOV    AL,03H            ; Default: NO PARITY + 8 bits data
  823.  
  824.     CMP    PARITY[SI],'O'          ; ODD PARITY REQUESTED?
  825.      JNE    P1            ; JUMP IF NOT
  826.     MOV    AL,0AH            ; SELECT ODD PARITY + 7 bits data
  827.     JMP    SHORT P4        ; CONTINUE
  828. ;
  829. P1:    CMP    PARITY[SI],'E'          ; EVEN PARITY REQUESTED?
  830.      JNE    P2            ; JUMP IF NOT
  831.     MOV    AL,1AH            ; SELECT EVEN PARITY + 7 bits data
  832.     JMP    SHORT P4        ; CONTINUE
  833. ;
  834. P2:    CMP    PARITY[SI],'M'          ; MARK PARITY REQUESTED?
  835.      JNE    P3            ; JUMP IF NOT
  836.     MOV    AL,2AH            ; SELECT MARK PARITY + 7 bits data
  837.     JMP SHORT P4
  838.  
  839. P3:    CMP PARITY[SI],'S'              ; SPACE parity requested?
  840.      JNE P4             ; No.  Must be 'N' (NONE)
  841.     MOV AL,3AH            ; Select SPACE PARITY + 7 bits data
  842.  
  843. P4:    TEST    STOP_BITS[SI],2     ; 2 STOP BITS REQUESTED?
  844.      JZ    STOP1            ; NO
  845.     OR    AL,4            ; YES
  846. STOP1:    MOV    DX,LCR[SI]        ; LINE CONTROL REGISTER
  847.     OUT    DX,AL            ; SET UART PARITY MODE AND DLAB=0
  848.  
  849. ; Initialize the FIFOs
  850.  
  851.     CMP UART_SILO_LEN[SI],1     ; Is it a 16550A?
  852.      JE P5                ; jump if 8250, 16450, or 16550(no A)
  853.     MOV    DX,FCR[SI]        ; I/O Address of FIFO control register
  854.     MOV    AL,FIFO_INIT        ; Clear FIFOs, set size, enable FIFOs
  855.     OUT    DX,AL
  856.     JMP SHORT $+2
  857.  
  858. ; ENABLE INTERRUPTS ON 8259 AND UART
  859. P5:    IN    AL,INTA01        ; SET ENABLE BIT ON 8259
  860.     AND    AL,NIRQ[SI]
  861.     JMP SHORT $+2
  862.     OUT    INTA01,AL
  863.     MOV DX,IER[SI]            ; Interrupt enable register
  864.     MOV AL,0DH            ; Line & Modem status, recv [GT]
  865.     OUT DX,AL            ; Enable those interrupts
  866.     MOV IER_SHADOW[SI],AL
  867.  
  868. OPENX:    POPF                ; Restore interrupt state
  869.     POP SI
  870.     mov sp,bp
  871.     pop bp
  872.     RET                ; DONE
  873. _open_com ENDP
  874.     PAGE;
  875. ;
  876. ; void far ioctl_com(int Flags, int Arg1, ...)
  877. ;    Flags have bits saying what to do or change (IGNORED TODAY)
  878. ;    Arg1, ...  are the new values
  879. ;
  880. _ioctl_com PROC FAR
  881.     PUSH BP
  882.     MOV BP,SP
  883.     PUSH SI
  884.     MOV SI,CURRENT_AREA        ; Pointer to COMi private area
  885.     TEST INSTALLED[SI],1
  886.      JE IOCTLX            ; No good.  Just return.
  887.     PUSHF                ; Save interrupt context
  888.     CLI                ; Prevent surprises
  889.     ; MOV AX,[BP+6]         ; Flags
  890.     ; Check bits here...
  891.     MOV AX,[BP+8]            ; Line speed
  892.     MOV BAUD_RATE[SI],AX        ; Save in parameter block
  893.     CALL Set_Baud            ; Set the baud rate in UART
  894.     POPF                ; Restore interrupt state
  895. IOCTLX: POP SI
  896.     MOV SP,BP
  897.     POP BP
  898.     RET
  899. _ioctl_com    ENDP
  900.     PAGE;
  901. ; ioctl-called routines (internal) ...
  902.  
  903. ; SI:    COMi private block
  904. ;    CALL Set_Baud
  905. ; Returns: (nothing)
  906. ; Clobber: AX, BX, DX
  907.  
  908. Set_Baud PROC NEAR
  909.     MOV AX,50
  910.     MUL DIV50            ; Could be different on a PCJr!
  911.     DIV BAUD_RATE[SI]        ; Get right number for the UART
  912.     MOV BX,AX            ; Save it
  913.     MOV DX,LCR[SI]            ; Line Control Register
  914.     IN AL,DX            ; Get current size, stops, parity,...
  915.     MOV AH,AL
  916.     OR AL,80H            ; DLAB bit
  917.     JMP SHORT $+2
  918.     OUT DX,AL            ; Talk to the baud rate regs now
  919.     MOV DX,WORD PTR DLL[SI]     ; Least significant byte
  920.     MOV AL,BL            ; New value
  921.     JMP SHORT $+2
  922.     OUT DX,AL            ; To UART
  923.     MOV DX,WORD PTR DLH[SI]     ; Most significant byte
  924.     MOV AL,BH            ; New value
  925.     JMP SHORT $+2
  926.     OUT DX,AL
  927.     MOV DX,LCR[SI]            ; Line Control Register
  928.     MOV AL,AH
  929.     JMP SHORT $+2
  930.     OUT DX,AL            ; Turn off DLAB, keep saved settings
  931.     RET
  932. Set_Baud ENDP
  933.     PAGE;
  934. ;
  935. ; void far close_com(void)
  936. ;    Turn off interrupts from the COM port
  937. ;
  938. _close_com PROC FAR
  939.     PUSH SI
  940.     PUSHF
  941.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  942.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  943.      JZ    CCX            ; ABORT IF NOT
  944.  
  945. ; TURN OFF UART and clear FIFOs in NS16550A
  946.     CLI
  947.     MOV DX,IER[SI]
  948.     XOR AL,AL
  949.     OUT DX,AL            ; No interrupts right now, please
  950.     MOV IER_SHADOW[SI],AL
  951.     MOV DX,FCR[SI]            ; FIFO Control Register
  952.     MOV AL,FIFO_CLEAR        ; Disable FIFOs
  953.     JMP SHORT $+2
  954.     OUT DX,AL
  955.     MOV DX,MCR[SI]            ; Modem control register
  956.     XOR AL,AL            ; OUT2 is IRQ enable on some machines,
  957.     JMP SHORT $+2
  958.     OUT DX,AL            ; So, clear RTS, OUT1, OUT2, LOOPBACK
  959.  
  960. ; TURN OFF 8259
  961.     MOV    DX,INTA01
  962.     JMP SHORT $+2
  963.     IN    AL,DX
  964.     OR    AL,IRQ[SI]
  965.     JMP SHORT $+2
  966.     OUT    DX,AL
  967.  
  968. CCX:    POPF                ; Restore interrupt state
  969.     POP SI
  970.     RET
  971. _close_com ENDP
  972.     PAGE;
  973. ;
  974. ; void far dtr_off(void)
  975. ;    Tells modem we are done.  Remote end should hang up also.
  976. ;
  977. _dtr_off PROC FAR
  978.     PUSH SI
  979.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  980.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  981.      JZ    DFX            ; ABORT IF NOT
  982.  
  983.     MOV DX,MCR[SI]            ; Modem Control Register
  984. IFNDEF UUPC
  985.     IN AL,DX            ; Get current state
  986.     SHR AL,1            ; Save old DTR bit in Carry flag
  987.     JMP SHORT $+2
  988. ENDIF
  989.     MOV AL,08H            ; DTR off, RTS off, OUT2 on
  990.     OUT DX,AL
  991. IFNDEF UUPC
  992.      JNC DFX            ; if DTR wasn't on then don't wait.
  993.     MOV AX,50            ; 50/100 of second
  994.     CALL WaitN            ; V.24 says it must be low >1/2 sec
  995. ENDIF
  996. DFX:    POP SI
  997.     RET
  998. _dtr_off    ENDP
  999.     PAGE;
  1000. ;
  1001. ; void far dtr_on(void)     Tell modem we can take traffic
  1002. ;
  1003. _dtr_on PROC FAR
  1004.     PUSH SI
  1005.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1006.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1007.      JZ DTRONF            ; Suppress output if not
  1008.  
  1009. ; Tell modem we are ready and want to send with line idle
  1010.  
  1011.     MOV DX,MCR[SI]            ; Modem Control Register
  1012.     MOV AL,00001011B        ; OUT 2, RTS, DTR
  1013.     OUT DX,AL
  1014.     CMP CONNECTION[SI],'D'          ; Direct connection (no DSR,CTS)?
  1015.      JE DTRDIR            ; if so, then don't wait
  1016.  
  1017. ; Wait for awhile to give the modem time to respond
  1018.  
  1019.     MOV AH,2CH            ; Get time (H:M:S:H to CH:CL:DH:DL)
  1020.     INT 21H
  1021.     MOV BX,DX            ; Save seconds&hundreths
  1022.     ADD BH,06            ; Allow a few seconds
  1023.     CMP BH,60            ; Wrap around check
  1024.      JL DTRON1            ; No wrap
  1025.     SUB BH,60
  1026. DTRON1: CMP SEND_OK[SI],30H        ; Did the modem come up?
  1027.      JE DTRONS            ; Yes.    Both DSR and CTS are true.
  1028.     INT 21H             ; Get the time again
  1029.     CMP DX,BX            ; Current time is passed the deadline?
  1030.      JB DTRON1            ; No, keep checking 'til time runs out
  1031.  
  1032.     ; Modem failed to come up.  Bump counts that tell why.
  1033.     MOV    DX,MSR[SI]        ; MODEM STATUS REGISTER
  1034.     IN    AL,DX            ; GET MODEM STATUS
  1035.     TEST    AL,20H            ; DATA SET READY?
  1036.      JNZ DTRON6            ; Yup.
  1037.     INC    WORD PTR EDSR[SI]    ; BUMP ERROR COUNT
  1038. DTRON6: TEST    AL,10H            ; Clear To Send?
  1039.      JNZ DTRONF            ; That's OK.
  1040.     INC    WORD PTR ECTS[SI]    ; BUMP ERROR COUNT - WE TIMED OUT
  1041.     ; Fall into DTRONF
  1042.     PAGE;
  1043. ; Failure return
  1044.  
  1045. DTRONF: MOV CONNECTION[SI],'D'          ; Switch to DIR connection (MSTATINT)
  1046.     ; Fall into DTRDIR
  1047.  
  1048. DTRDIR: MOV SEND_OK[SI],30H        ; Make believe DSR & CTS are up!!!
  1049.     ; Fall into DTRONS
  1050.  
  1051. ; Successful return
  1052.  
  1053. DTRONS: ; SEND_OK is on.  Setting it again could confuse interrupt level
  1054.     ; Fall into DTRONX
  1055.  
  1056. DTRONX:
  1057. IFNDEF UUPC
  1058.     MOV AX,200H            ; 2 Seconds
  1059.     CALL WaitN            ; V.24 says 2 sec hi before data
  1060. ENDIF
  1061.     POP SI
  1062.     RET
  1063. _dtr_on ENDP
  1064.     PAGE;
  1065. ;
  1066. ; void far rts_off(void)
  1067. ;    Turns off RTS for RTS-style throttling of modem->PC data
  1068. ;
  1069. _rts_off PROC FAR
  1070.     PUSH SI
  1071.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1072.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1073.      JZ    RFX            ; ABORT IF NOT
  1074.     MOV DX,MCR[SI]            ; Modem Control Register
  1075.     MOV AL,00001001B        ; OUT 2, DTR
  1076.     OUT DX,AL
  1077. RFX:    POP SI
  1078.     RET
  1079. _rts_off    ENDP
  1080.     PAGE;
  1081. ;
  1082. ; void far rts_off(void)
  1083. ;    Turns on RTS for RTS-style throttling of modem->PC data
  1084. ;
  1085. _rts_on PROC FAR
  1086.     PUSH SI
  1087.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1088.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1089.      JZ    RNX            ; ABORT IF NOT
  1090.     MOV DX,MCR[SI]            ; Modem Control Register
  1091.     MOV AL,00001011B        ; OUT 2, RTS, DTR
  1092.     OUT DX,AL
  1093. RNX:    POP SI
  1094.     RET
  1095. _rts_on ENDP
  1096.     PAGE;
  1097. ;
  1098. ; Wait for specified time using the 18.2 ticks/second clock
  1099. ;
  1100. ; Call:     AX has seconds,hundreths
  1101. ;        CALL WaitN
  1102. ; Return:    At least the requested time has passed
  1103. ;
  1104.  
  1105. WaitN    PROC NEAR
  1106.     PUSH AX
  1107.     PUSH BX
  1108.     PUSH CX
  1109.     PUSH DX
  1110.     PUSH AX             ; Save a copy of the arg
  1111.     MOV AH,2CH            ; Get time (H:M:S:H to CH:CL:DH:DL)
  1112.     INT DOS
  1113.     POP BX                ; Recover S:H arg
  1114.     ADD BX,DX            ; Determine deadline
  1115.     CMP BL,100            ; Wrap around?
  1116.      JL WaitN1            ; No
  1117.     SUB BL,100            ; Yes.    Subtract 100 hundreths
  1118.     INC BH                ; And add a second
  1119. WaitN1: CMP BH,60            ; Wrap around check
  1120.      JL WaitN2            ; No wrap
  1121.     SUB BH,60            ; Forget about Days and Hours
  1122. WaitN2: INT DOS             ; Get the time again
  1123.     CMP DX,BX            ; Is current time after the deadline?
  1124.      JB WaitN2            ; No, keep checking 'til time runs out
  1125.     POP DX
  1126.     POP CX
  1127.     POP BX
  1128.     POP CX
  1129.     RET
  1130. WaitN    ENDP
  1131.     PAGE;
  1132. ;
  1133. ; unsigned long r_count(void)
  1134. ;    Value is really two uints:  Buffer size in high half, count in low.
  1135. ;    Count returned is <= number of chars waiting to be read.
  1136. ;        (More may come in after you asked.)
  1137. ;
  1138. _r_count PROC FAR
  1139.     PUSH SI
  1140.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1141.     XOR    AX,AX            ; Say nothing available if not inst'd
  1142.     MOV DX,R_SIZE            ; Size of entire receive buffer
  1143.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1144.      JZ    RCX            ; ABORT IF NOT
  1145.     MOV    AX,SIZE_RDATA[SI]    ; GET NUMBER OF BYTES USED
  1146. RCX:    POP SI
  1147.     RET
  1148. _r_count ENDP
  1149.     PAGE;
  1150. ;
  1151. ; char far receive_com(void)
  1152. ;    Returns AX: -1 if port not installed or no characters available
  1153. ;        or AX: the next character with parity stipped if not in P mode
  1154. ;
  1155. _receive_com PROC FAR
  1156.     PUSH SI
  1157.     PUSH ES
  1158.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1159.     mov    ax,-1            ; -1 if bad call
  1160.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1161.      JZ    RECVX            ; ABORT IF NOT
  1162.     CMP    SIZE_RDATA[SI],0    ; ANY CHARACTERS?
  1163.      JE    RECVX            ; Return -1 in AX
  1164.  
  1165.     mov ah,0            ; good call
  1166.     LES    BX,START_RDATA[SI]    ; GET POINTER TO OLDEST CHAR
  1167.     MOV    AL,ES:[BX]        ; Get character from buffer
  1168.     INC    BX            ; BUMP START_RDATA
  1169.     AND    BX,R_SIZE-1        ; Ring the pointer
  1170.     MOV    WORD PTR START_RDATA[SI],BX ; SAVE THE NEW START_RDATA VALUE
  1171.     DEC    SIZE_RDATA[SI]        ; ONE LESS CHARACTER
  1172.     CMP    PARITY[SI],'N'          ; ARE WE RUNNING WITH NO PARITY? LBA
  1173.      JE    RECV1            ; IF SO, DON'T STRIP HIGH BIT    LBA
  1174.     AND    AL,7FH            ; STRIP PARITY BIT
  1175. RECV1:    CMP    XON_XOFF[SI],'E'        ; XON/XOFF FLOW CONTROL ENABLED?
  1176.      JNE    RECVX            ; DO NOTHING IF DISABLED
  1177.     CMP    HOST_OFF[SI],1        ; HOST TURNED OFF?
  1178.      JNE    RECVX            ; JUMP IF NOT
  1179.     CMP    SIZE_RDATA[SI],R_SIZE/16; RECEIVE BUFFER NEARLY EMPTY?
  1180.      JAE    RECVX            ; DONE IF NOT
  1181.     MOV    HOST_OFF[SI],0        ; TURN ON HOST IF SO
  1182.  
  1183.     PUSH    AX            ; SAVE RECEIVED CHAR
  1184.     MOV    AL,CONTROL_Q        ; TELL HIM TO TALK
  1185.     PUSHF                ; Save interrupt context
  1186. RECV3:    CLI                ; TURN OFF INTERRUPTS
  1187.     CMP URGENT_SEND[SI],1        ; Previous send still in progress?
  1188.      JNE RECV4            ; No.  There is space now.
  1189.     STI                ; Yes.    Wait for interrupt to take it.
  1190.     JMP SHORT $+2            ; Waste some time with interrupts on
  1191.     JMP SHORT RECV3         ; Loop 'til it's gone
  1192.  
  1193. RECV4:    CALL    SENDII            ; SEND IMMEDIATELY INTERNAL
  1194.     POPF                ; Restore interrupt state
  1195.     POP    AX            ; RESTORE RECEIVED CHAR
  1196.  
  1197. RECVX:    POP ES
  1198.     POP SI
  1199.     RET
  1200. _receive_com ENDP
  1201.     PAGE;
  1202. ;
  1203. ; unsigned long s_count(void)
  1204. ;    Value is really two uints: Buffer size in high half (returned in DX).
  1205. ;                Free space count in low (returned in AX).
  1206. ;    Count returned is <= number of chars which can be sent without blocking.
  1207. ;        (More may become available after you asked.)
  1208. ;
  1209. ; N.B. The free space might be negative (-1) if the buffer was full and then
  1210. ; the program called SENDI or RXI required sending a control-S to squelch
  1211. ; the remote sender.  Return 0 in this case.
  1212. ;
  1213. _s_count PROC FAR
  1214.     PUSH SI
  1215.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1216.     XOR    AX,AX            ; NO SPACE LEFT IF NOT INSTALLED
  1217.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1218.      JZ    SCX            ; ABORT IF NOT
  1219.     MOV AX,S_SIZE-1         ; Size, keeping one aside for SENDII
  1220.     SUB AX,SIZE_TDATA[SI]        ; Minus number in use right now
  1221.     CWD                ; Avoid returning a negative number
  1222.     NOT DX
  1223.     AND AX,DX            ; return 0 if it was negative
  1224. SCX:    MOV DX,S_SIZE-1         ; Leave 1 byte for a SENDII call
  1225.     POP SI
  1226.     RET
  1227. _s_count ENDP
  1228.     PAGE;
  1229. ;
  1230. ; void far send_com(char)
  1231. ;    Send a character to the selected port
  1232. ;
  1233. _send_com PROC FAR
  1234.     push bp
  1235.     mov bp,sp
  1236.     PUSH SI
  1237.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1238.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1239.      JZ    SENDX            ; ABORT IF NOT
  1240.  
  1241. SEND1:    CMP    SIZE_TDATA[SI],S_SIZE-1 ; BUFFER FULL? (Leave room for SENDII)
  1242.      JAE SEND1            ; Wait for interrupts to empty buffer
  1243.     MOV AL,[BP+6]            ; Character to send
  1244.     PUSH ES
  1245.     LES BX,END_TDATA[SI]        ; ES:BX points to free space
  1246.     MOV ES:[BX],AL            ; Move character to buffer
  1247.     INC    BX            ; INCREMENT END_TDATA
  1248.     AND BX,S_SIZE-1         ; Ring the pointer
  1249.     MOV WORD PTR END_TDATA[SI],BX    ; SAVE NEW END_TDATA
  1250.     INC    SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  1251.     TEST PC_OFF[SI],1        ; Were we stopped by a ^S from host?
  1252.      JNZ SEND2            ; Yes.    Don't enable interrupts yet.
  1253.     CMP SEND_OK[SI],30H        ; See if Data Set Ready & CTS are on
  1254.      JNE SEND2            ; No. Still can't enable TX ints
  1255.     PUSHF                ; Save interrupt state
  1256.     CLI
  1257.     TEST IER_SHADOW[SI],02H     ; Tx interrupts enabled?
  1258.      JNZ SEND3            ; Jump if so: transmit already running
  1259.     MOV DX,IER[SI]            ; Interrupt Enable Register
  1260.     MOV AL,0FH            ; Rx, Tx, Line & Modem enable bits
  1261.     OUT DX,AL            ; Enable those interrupts
  1262.     MOV IER_SHADOW[SI],AL
  1263. SEND3:    POPF                ; Restore interrupt state
  1264. SEND2:    POP ES
  1265. SENDX:    POP SI
  1266.     mov sp,bp
  1267.     pop bp
  1268.     RET
  1269. _send_com ENDP
  1270.     PAGE;
  1271. ;
  1272. ; void far sendi_com(char)
  1273. ;    Send a character immediately by placing it at the head of the queue
  1274. ;
  1275. _sendi_com PROC FAR
  1276.     push bp
  1277.     mov bp,sp
  1278.     PUSH SI
  1279.     mov al,[bp+6]
  1280.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1281.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1282.      JZ SENDIX            ; Return if not
  1283.     PUSHF                ; Save interrupt state
  1284. SENDI3: CLI                ; TURN OFF INTERRUPTS
  1285.     CMP URGENT_SEND[SI],1        ; Previous send still in progress?
  1286.      JNE SENDI4            ; No.  There is space now.
  1287.     STI                ; Yes.    Wait for interrupt to take it.
  1288.     JMP SHORT $+2            ; Waste some time with interrupts on
  1289.     JMP SHORT SENDI3        ; Loop 'til it's gone
  1290.  
  1291. SENDI4: CALL    SENDII            ; CALL INTERNAL SEND IMMEDIATE
  1292.     POPF                ; Restore interrupt state
  1293. SENDIX: POP SI
  1294.     mov sp,bp
  1295.     pop bp
  1296.     RET
  1297. _sendi_com ENDP
  1298.     PAGE;
  1299. ; SENDII(AL, SI)  [internal routine]
  1300. ;    Put char at head of output queue so it will go out next
  1301. ;    Called from process level and (receive) interrupt level
  1302. ;    DEPENDS ON CALLER TO KEEP INTERRUPTS CLEARED AND SET SI
  1303. ;    Clobbers AL
  1304. ;
  1305. SENDII    PROC NEAR
  1306.     TEST    IER_SHADOW[SI],02H    ; Tx interrupts enabled?
  1307.      JNZ    SENDII1         ; Jump if so: transmit already running
  1308.     CMP    SEND_OK[SI],30H     ; See if Data Set Ready & CTS are on
  1309.      JNE    SENDII1         ; No. Still can't enable TX ints
  1310. ; Was idle: transmit the character without buffering; enable TX interrupt
  1311.     PUSH    DX
  1312.     MOV    DX,DATREG[SI]        ; I/O address of data register
  1313.     OUT    DX,AL            ; Output the character
  1314.     MOV    DX,IER[SI]        ; Interrupt Enable Register
  1315.     MOV    AL,0FH            ; Rx, Tx, Line & Modem enable bits
  1316.     OUT    DX,AL            ; Enable those interrupts
  1317.     MOV    IER_SHADOW[SI],AL
  1318.     POP    DX
  1319.     RET
  1320.  
  1321. ; Unable to send the character now: buffer it.
  1322. SENDII1:PUSH BX
  1323.     PUSH ES
  1324.     LES BX,START_TDATA[SI]        ; ES:BX point to 1st chr in buffer
  1325.     CMP    SIZE_TDATA[SI],S_SIZE    ; BUFFER FULL?
  1326.      JB    SENDII2         ; JUMP IF NOT
  1327.     INC    WORD PTR EOVFLOW[SI]    ; BUMP ERROR COUNT (Can this happen?)
  1328.     JMP SHORT SENDII4        ; and overwrite old first char
  1329.  
  1330. SENDII2:DEC BX                ; Back it up
  1331.     AND BX,S_SIZE-1         ; Ring it
  1332.     MOV WORD PTR START_TDATA[SI],BX ; Save new value
  1333.     INC    SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  1334.     ; No check for PC_OFF here.  Flow control ALWAYS gets sent!
  1335. SENDII4:MOV ES:[BX],AL            ; Move character to buffer
  1336.     MOV URGENT_SEND[SI],1        ; Flag high priority message
  1337.     POP ES
  1338.     POP BX
  1339.     RET
  1340. SENDII    ENDP
  1341.     PAGE;
  1342. ;*---------------------------------------------------------------------*
  1343. ;*    s p i n l o o p                            *
  1344. ;*                                       *
  1345. ;*    Waste time to allow slow UART chips to catch up            *
  1346. ;*---------------------------------------------------------------------*
  1347.  
  1348. SPINLOOP PROC NEAR
  1349.     PUSH CX
  1350.     MOV CX,100
  1351. WASTERS:
  1352.     CALL CRET        ; Better time waster than a 1-byte NOP
  1353.     LOOP WASTERS
  1354.     POP  CX
  1355. CRET:    RET
  1356. SPINLOOP ENDP
  1357.     PAGE;
  1358.  
  1359. IFNDEF UUPC
  1360. ;
  1361. ; void far send_local(char);
  1362. ;    Simulate a loopback by placing characters sent in recv buffer
  1363. ;
  1364. _send_local PROC FAR
  1365.     push bp
  1366.     mov bp,sp
  1367.     PUSH SI
  1368.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1369.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1370.      JZ    SLX            ; ABORT IF NOT
  1371.  
  1372.     PUSHF                ; Save interrupt state
  1373.     CLI                ; INTERRUPTS OFF
  1374.  
  1375.     CMP    SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  1376.      JB SL3             ; SKIP IF ROOM
  1377.     INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW COUNT
  1378.     JMP SHORT SL9            ; PUNT
  1379.  
  1380. SL3:    PUSH ES
  1381.     LES BX,END_RDATA[SI]        ; ES:BX POINTS TO FREE SPACE
  1382.     MOV AL,[BP+6]            ; Get the byte to send
  1383.     MOV ES:[BX],AL            ; Put into buffer
  1384.     INC    BX            ; INCREMENT END_RDATA POINTER
  1385.     AND BX,R_SIZE-1         ; Ring the pointer
  1386.     MOV WORD PTR END_RDATA[SI],BX    ; SAVE VALUE
  1387.     INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  1388.     POP ES
  1389.  
  1390. SL9:    POPF                ; Restore interrupt state
  1391. SLX:    POP SI
  1392.     mov sp,bp
  1393.     pop bp
  1394.     RET                ; DONE
  1395. _send_local    ENDP
  1396. ENDIF
  1397.     PAGE;
  1398. ;
  1399. ; void far break_com(void)    Send a BREAK out to alert the remote end
  1400. ;
  1401. _break_com PROC FAR
  1402.     PUSH SI
  1403.  
  1404.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  1405.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  1406.      JZ    BREAKX            ; ABORT IF NOT
  1407.  
  1408.     MOV    DX,LCR[SI]        ; LINE CONTROL REGISTER
  1409.     IN    AL,DX            ; GET CURRENT SETTING
  1410.     OR    AL,40H            ; TURN ON BREAK BIT
  1411.     JMP SHORT $+2
  1412.     OUT    DX,AL            ; SET IT ON THE UART
  1413.     MOV AX,25            ; 25/100 of a second
  1414.     CALL WaitN
  1415.     MOV    DX,LCR[SI]        ; LINE CONTROL REGISTER
  1416.     IN    AL,DX            ; GET CURRENT SETTING
  1417.     AND    AL,NOT 40H        ; TURN OFF BREAK BIT
  1418.     JMP SHORT $+2
  1419.     OUT    DX,AL            ; RESTORE LINE CONTROL REGISTER
  1420. BREAKX: POP SI
  1421.     RET
  1422. _break_com ENDP
  1423.     PAGE;
  1424. ;
  1425. ; ERROR_STRUCT far *com_errors(void)
  1426. ;    Returns a pointer to the table of error counters
  1427. ;
  1428. _com_errors PROC FAR
  1429.     PUSH SI
  1430.     MOV SI,CURRENT_AREA        ; Point to block for selected port
  1431.     LEA AX,ERROR_BLOCK[SI]        ; Offset to error counters
  1432.     MOV DX,DS            ; Value is in DX:AX
  1433.     POP SI
  1434.     RET
  1435. _com_errors ENDP
  1436.  
  1437.  
  1438.  
  1439.  
  1440.  
  1441.  
  1442. ;
  1443. ; char far modem_status(void)
  1444. ;    Returns the modem status register in AL
  1445. ;
  1446. ; Bits are:    0x80:    Carrier Detect
  1447. ;        0x40:    Ring Indicator
  1448. ;        0x20:    Data Set Ready
  1449. ;        0x10:    Clear To Send
  1450. ;        0x08:    Delta Carrier Detect    (CD changed)
  1451. ;        0x04:    Trailing edge of RI    (RI went OFF)
  1452. ;        0x02:    Delta DSR        (DSR changed)
  1453. ;        0x01:    Delta CTS        (CTS changed)
  1454.  
  1455. _modem_status PROC FAR
  1456.     PUSH SI
  1457.     MOV SI,CURRENT_AREA        ; Point to block for selected port
  1458.     MOV DX,MSR[SI]            ; IO Addr of Modem Status Register
  1459.     IN AL,DX            ; Get the live value
  1460.     XOR AH,AH            ; Flush unwanted bits
  1461.     POP SI
  1462.     RET
  1463. _modem_status ENDP
  1464.     PAGE;
  1465. ;
  1466. ; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
  1467. ;
  1468.     assume    DS:nothing
  1469.     even
  1470. INT_HNDLR1 PROC FAR
  1471.     PUSH SI
  1472.     MOV    SI,OFFSET DGROUP:AREA1    ; DATA AREA FOR COM1:
  1473.     JMP    SHORT INT_COMMON    ; CONTINUE
  1474. ;
  1475. ; INT_HNDLR2 - HANDLES INTERRUPTS GENERATED BY COM2:
  1476. ;
  1477.     even
  1478. INT_HNDLR2 PROC FAR
  1479.     PUSH SI
  1480.     MOV    SI,OFFSET DGROUP:AREA2    ; DATA AREA FOR COM2:
  1481.     JMP    SHORT INT_COMMON    ; CONTINUE
  1482. ;
  1483. ; INT_HNDLR3 - HANDLES INTERRUPTS GENERATED BY COM3:
  1484. ;
  1485.     even
  1486. INT_HNDLR3 PROC FAR
  1487.     PUSH SI
  1488.     MOV    SI,OFFSET DGROUP:AREA3    ; DATA AREA FOR COM3:
  1489.     JMP    SHORT INT_COMMON    ; CONTINUE
  1490. ;
  1491. ; INT_HNDLR4 - HANDLES INTERRUPTS GENERATED BY COM4:
  1492. ;
  1493.     even
  1494. INT_HNDLR4 PROC FAR
  1495.     PUSH SI
  1496.     MOV    SI,OFFSET DGROUP:AREA4    ; DATA AREA FOR COM4:
  1497.     ; Fall into INT_COMMON
  1498.     PAGE;
  1499. ;
  1500. ; BODY OF INTERRUPT HANDLER
  1501. ;
  1502. INT_COMMON: ; SI has been pushed and loaded
  1503.     PUSH AX
  1504.     PUSH DX
  1505.     PUSH DS
  1506.     PUSH BX
  1507.     PUSH CX
  1508.     PUSH ES
  1509.  
  1510.     MOV AX,DGROUP            ; offsets are relative to DGROUP [WWP]
  1511.     MOV    DS,AX
  1512.     assume    DS:DGROUP
  1513.  
  1514. ; FIND OUT WHERE INTERRUPT CAME FROM AND JUMP TO ROUTINE TO HANDLE IT
  1515. REPOLL: MOV DX,IIR[SI]            ; Interrupt Identification Register
  1516.     IN AL,DX
  1517.     MOV BL,AL            ; Put where we can index by it
  1518.     SHR AL,1            ; Check the "no interrupt present" bit
  1519.      JC INT_END            ; ON means we are done
  1520.     AND BX,000EH            ; Ignore FIFO_ENABLED bits, etc.
  1521.  
  1522.     JMP WORD PTR CS:INT_DISPATCH[BX]; Go to appropriate routine
  1523.  
  1524.     even
  1525. INT_DISPATCH:
  1526.     DW MSI                ; 0: Modem status interrupt
  1527.     DW TXI                ; 2: Transmitter interrupt
  1528.     DW RXI                ; 4: Receiver interrupt
  1529.     DW LSI                ; 6: Line status interrupt
  1530.     DW INT_END            ; 8: (Future use by UART makers)
  1531.     DW INT_END            ; A: (Future use by UART makers)
  1532.     DW RXI                ; C: FIFO Timeout
  1533.     DW INT_END            ; E: (Future use by UART makers)
  1534.  
  1535. INT_END: ; Now tell 8259 we handled that IRQ
  1536.  
  1537.     MOV DX,IER[SI]            ; Gordon Lee's cure for dropped ints
  1538.     XOR AL,AL
  1539.     OUT DX,AL            ; Disable UART interrupts
  1540.     MOV AL,EOI[SI]            ; End of Interrupt. With input gone,
  1541.     POP ES                ; do the POPs now for some I/O delay
  1542.     POP CX
  1543.     OUT INTA00,AL            ; Give EOI to 8259 Interrupt ctlr
  1544.     MOV AL,IER_SHADOW[SI]        ; Get saved interrupt enable bits
  1545.     POP BX                ; do the POPs now for some I/O delay
  1546.     POP DS
  1547.     assume    DS:nothing
  1548.     OUT DX,AL            ; Restore them, maybe causing a
  1549.                     ; transition into the 8259!!!
  1550.     POP DX
  1551.     POP AX
  1552.     POP SI
  1553.     IRET
  1554.     PAGE;
  1555. ;
  1556. ; Line status interrupt
  1557. ;
  1558.     even
  1559.     assume    DS:DGROUP
  1560. LSI:    MOV    DX,LSR[SI]        ; Line status register
  1561.     IN    AL,DX            ; Read line status & bump error counts
  1562.     SHR    AL,1
  1563. LSI2:    ; RXI also comes here with the LSR (shifted right 1) already in AL
  1564.     SHR    AL,1            ; OVERRUN ERROR?
  1565.     ADC    WORD PTR EOVRUN[SI],0    ; BUMP ERROR COUNT
  1566.     SHR    AL,1            ; PARITY ERROR?
  1567.     ADC    WORD PTR EPARITY[SI],0    ; BUMP ERROR COUNT
  1568.     SHR    AL,1            ; FRAMING ERROR?
  1569.     ADC    WORD PTR EFRAME[SI],0    ; BUMP ERROR COUNT
  1570.     SHR    AL,1            ; BREAK RECEIVED?
  1571.     ADC    WORD PTR EBREAK[SI],0    ; BUMP ERROR COUNT
  1572.     JMP    REPOLL            ; SEE IF ANY MORE INTERRUPTS
  1573.  
  1574. ;
  1575. ; Modem status interrupt
  1576. ;
  1577.     even
  1578.     assume    DS:DGROUP
  1579. MSI:    MOV DX,MSR[SI]            ; Modem Status Register
  1580.     IN AL,DX            ; Read status & clear interrupt
  1581.     AND AL,30H            ; Expose CTS and Data Set Ready
  1582.     CMP CONNECTION[SI],'D'          ; Direct connection - ignore int
  1583.      JNE MSI0            ; if not direct them DSR,CTS valid
  1584.     MOV AL,30H            ; Make believe DSR & CTS are up!!!
  1585. MSI0:    MOV SEND_OK[SI],AL        ; Put where TXI and send_com can see
  1586.     MOV DX,IER[SI]            ; Let a TX int happen for thoro chks
  1587.     MOV AL,0FH            ; Line & modem sts, recv, send.
  1588.     OUT DX,AL
  1589.     MOV IER_SHADOW[SI],AL
  1590.     JMP REPOLL            ; Check for other interrupts
  1591.     PAGE;
  1592. ;
  1593. ; Receive interrupt
  1594. ;
  1595.     even
  1596.     assume    DS:DGROUP
  1597. RXI:    LES    BX,END_RDATA[SI]    ; ES:BX points to free space
  1598. RXI0:    MOV    DX,DATREG[SI]        ; UART DATA REGISTER
  1599.     IN    AL,DX            ; Get data, clear status
  1600.     CMP    XON_XOFF[SI],'E'        ; XON/XOFF FLOW CONTROL ENABLED?
  1601.      JE    RXI1            ; Yes.    Check for XON/XOFF
  1602.     CMP    SIZE_RDATA[SI],R_SIZE    ; Any room in buffer?
  1603.      JAE    RXIFUL            ; No room left
  1604.     MOV    ES:[BX],AL        ; Put character in buffer
  1605.     INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  1606.     INC    BX            ; Bump pointer past location just used
  1607.     AND    BX,R_SIZE-1        ; Ring the pointer
  1608. RXINXT: MOV    DX,LSR[SI]        ; Line Status Register
  1609.     IN    AL,DX            ; Read it
  1610.     SHR    AL,1            ; Check the RECV DATA READY bit
  1611.      JC    RXI0            ; More data; go get it
  1612.     MOV    WORD PTR END_RDATA[SI],BX ; Store updated pointer
  1613.     JMP    SHORT LSI2        ; No more data; count errors if any
  1614.  
  1615. RXIFUL: INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW ERROR COUNT
  1616.     MOV    WORD PTR END_RDATA[SI],BX ; Store updated pointer
  1617.     JMP    REPOLL
  1618.  
  1619. ; Check each character for possible flow control (XON/XOFF)
  1620. RXI1:    MOV    AH,AL            ; Save character in AH
  1621.     AND    AL,7FH            ; STRIP PARITY
  1622.     CMP    AL,CONTROL_S        ; STOP COMMAND RECEIVED?
  1623.      JNE    RXI2            ; Jump if not. Might be ^Q though.
  1624.     MOV    PC_OFF[SI],1        ; Stop output
  1625.     JMP    SHORT RXINXT        ; Don't store the character
  1626.  
  1627. RXI2:    CMP    AL,CONTROL_Q        ; GO COMMAND RECEIVED?
  1628.      JNE    RXI3            ; No.  Not a flow control character
  1629.     MOV    PC_OFF[SI],0        ; Enable output
  1630.     JMP    SHORT RXINXT        ; Don't store the character
  1631.  
  1632. RXI3:    CMP    SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  1633.      JAE    RXIFUL            ; No room left
  1634.     MOV    ES:[BX],AH        ; Put saved character in buffer
  1635.     INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  1636.     INC    BX            ; Bump pointer past location just used
  1637.     AND    BX,R_SIZE-1        ; Ring the pointer
  1638. ; See if we must tell remote host to stop outputting.
  1639.     CMP    HOST_OFF[SI],1        ; Already told remote to shut up?
  1640.      JE    RXINXT            ; Yes.    Don't flood him with ^Ss
  1641.     CMP    SIZE_RDATA[SI],R_SIZE/2 ; RECEIVE BUFFER NEARLY FULL?
  1642.      JBE    RXINXT            ; No.  No need to stifle remote end
  1643.     ; Would like to wait here for URGENT_SEND to go off if it is on.
  1644.     ; But we need to take a TX interrupt for that to happen.
  1645.     MOV    AL,CONTROL_S        ; TURN OFF HOST IF SO
  1646.     CALL    SENDII            ; SEND IMMEDIATELY INTERNAL
  1647.     MOV    HOST_OFF[SI],1        ; HOST IS NOW OFF
  1648.     JMP    RXINXT
  1649.     PAGE;
  1650. ;
  1651. ; Transmit interrupt
  1652. ;
  1653.     even
  1654.     assume    DS:DGROUP
  1655. TXI:    CMP    SEND_OK[SI],30H     ; Hardware (CTS & DSR on) OK?
  1656.      JNE    TXI9            ; No.  Must wait 'til cable right!
  1657.     MOV    CX,1            ; Transfer count for flow ctl
  1658.     CMP    URGENT_SEND[SI],CL    ; Flow control character to send?
  1659.      JE    TXI3            ; Yes.    Always send flow control.
  1660.     CMP    PC_OFF[SI],CL        ; Flow control (XON/XOFF) OK?
  1661.      JE    TXI9            ; Stifled & not urgent. Forget it.
  1662.  
  1663. TXI1:    MOV    CL,UART_SILO_LEN[SI]    ; MAX size chunk (1 for 8250/16450)
  1664.     ; Too bad there is no "Transmitter FIFO Full" indication!
  1665.     CMP    SIZE_TDATA[SI],CX    ; SEE IF ANY MORE DATA TO SEND
  1666.      JAE    TXI3            ; jump if UART is the limit
  1667.     MOV    CX,SIZE_TDATA[SI]    ; Buffer contents limited.  Use that.
  1668.      JCXZ    TXI9            ; No data, disable TX ints
  1669. TXI3:    LES    BX,START_TDATA[SI]    ; ES:BX points to next char to send
  1670.     MOV    DX,DATREG[SI]        ; I/O address of data register
  1671. TXI4:    MOV    AL,ES:[BX]        ; Get character from buffer
  1672.     OUT    DX,AL            ; Output the character
  1673.     INC    BX            ; Bump the head pointer
  1674.     AND    BX,S_SIZE-1        ; Ring it
  1675.     DEC    SIZE_TDATA[SI]        ; One fewer in buffer now
  1676.      LOOP    TXI4            ; Keep going 'til silo is full
  1677.     MOV    WORD PTR START_TDATA[SI],BX ; Store pointer back
  1678.     MOV    URGENT_SEND[SI],0    ; Tell process level we sent flow ctl
  1679.     JMP    REPOLL
  1680.  
  1681. ; IF NO DATA TO SEND, or can't send, RESET TX INTERRUPT AND RETURN
  1682. TXI9:    MOV    DX,IER[SI]
  1683.     MOV    AL,0DH            ; Line & modem sts, recv, no send.
  1684.     OUT    DX,AL
  1685.     MOV    IER_SHADOW[SI],AL
  1686.     JMP    REPOLL
  1687.  
  1688. INT_HNDLR4 ENDP
  1689. INT_HNDLR3 ENDP
  1690. INT_HNDLR2 ENDP
  1691. INT_HNDLR1 ENDP
  1692. COM_TEXT   ENDS
  1693.        END
  1694.