home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / xbase / library / clipper / communic / commio / comm_io.asm next >
Assembly Source File  |  1986-12-09  |  22KB  |  612 lines

  1.                                 page,132
  2. ;-------------------------------------------------------------------------------
  3. ;                         ----  COMM_IO.ASM  ----
  4. ; To use it just MODE your COM1: to whatever speed you like, I've only tested
  5. ; it to 9600 baud it does'nt use DOS calls so its pretty fast I dont know
  6. ; how it will effect non IBM hardware, works just fine on PC'S Limited 286-8.
  7. ; It may not be fully debugged, I have'nt tested the XON or XOFF functions
  8. ; Simple communications work fine, It ignores the modem control line so to use
  9. ; it you must provide software handshaking for a terminal that does'nt have a
  10. ; buffer.
  11. ; The recieving buffer is 512 bytes so as long as you dont let it fillup you
  12. ; wont loose any characters, of coarse you could make it as larger if necessary.
  13. ;
  14. ;
  15. ; Filename: COMM_IO
  16. ; Program.: Clipper Communication for Com1:
  17. ; Authors.: Curt Klinsing,Modifed by Patrick Jonte
  18. ; Date....: April 20, 1986
  19. ;
  20. ; Function: A set of Clipper W85 callable functions to support
  21. ;           interrupt driven character I/O on the  IBM PC. Input
  22. ;           is buffered, output is polled.
  23. ;
  24. ;
  25. ;
  26. ; 1- OUTP_CHAR {call} outputs a character string up to first null encountered.
  27. ;    (Note- all clipper strings are terminated by a ascii null or hex 00)
  28. ;    Example:
  29. ;             PUTCHARS='a character string '
  30. ;             CALL OUTP_CHAR WITH PUTCHARS
  31. ;
  32. ; 2- INP_CHAR(.T.or.F.) {function} returns a character string of the characters
  33. ;    available in the input buffer (maximum of 512 characters)
  34. ;    and gives the option of deleting characters read from input buffer .T. or
  35. ;    .F. leaving it untouched which allows easy monitoring for a special
  36. ;    character(s)
  37. ;    Example:
  38. ;             RECV_STR=INP_CHAR(.T.)  & reads buffer and kills characters read
  39. ;                                       from buffer
  40. ;
  41. ; 3- INP_CNT() {function} returns numeric indicating the number of characters
  42. ;    that the input buffer is holding (Maximum of 512).
  43. ;    Example:
  44. ;             NUMCHAR=INP_CNT()
  45. ;
  46. ; 4- SET_XOFF {CALL} enables or disables xoff control .
  47. ;    Example:
  48. ;             SOFF=.T. && if you want to turn xoff feature on
  49. ;             SOFF=.F. && to turn it off
  50. ;             CALL SET_XOFF WITH SOFF
  51. ;
  52. ; 5- GET_XOFF(),RECV_XOFF(),SENT_XOFF() {FUNCTION} return logical value
  53. ;    indicating state of control flags
  54. ;    Example:
  55. ;             GFLAG=GET_XOFF()
  56. ;
  57. ; 6- INIT_COMM,UNINIT_COM,INP_FLUSH {CALL} dont pass or return parameters
  58. ;    Example:
  59. ;             CALL INIT_COMM
  60. ;             CALL INP_FLUSH
  61. ;---------------------------------------------------------------------------
  62. ;
  63.  
  64.  
  65.  
  66. name COMM_IO
  67.  
  68. public  init_comm       ;initialize the comm port,
  69. public  uninit_com      ;remove initialization,
  70. public  set_xoff        ;enable/disable XON/XOFF,
  71. public  get_xoff        ;read XON/XOFF state,
  72. public  rcvd_xoff       ;returns true if XOFF rcvd,
  73. public  sent_xoff       ;true if XOFF sent,
  74. public  inp_cnt         ;returns count of rcv chars,
  75. public  inp_char        ;get char string from buffer,
  76. public  inp_flush       ;flush input buffer,
  77. public  outp_char       ;output a character string,
  78. ;
  79. extrn   _retc:far      ; return character string
  80. extrn   _retds:far     ; return date type from date string "YYYYMMDD"
  81. extrn   _retl:far      ; return logical true or false
  82. extrn   _retni:far     ; return word as numeric
  83. extrn   _retnl:far     ; return double word as numeric
  84. extrn   _retnd:far     ; return floating point as numeric
  85. ;
  86. extrn   _parc:far      ; pass character string
  87. extrn   _parni:far     ; pass integer numeric
  88. extrn   _parnl:far     ; pass integer long numeric
  89. extrn   _parnd:far     ; pass double numeric
  90. extrn   _parl:far      ; pass logical integer
  91. extrn   _pards:far     ; pass date string "yyyymmdd"
  92. ;
  93. extrn   _parinfo:far   ; UNDEF           0
  94.                        ; CHARACTER       1
  95.                        ; NUMERIC         2
  96.                        ; LOGICAL         4
  97.                        ; DATE            8
  98.                        ; ALIAS           16
  99.                        ; MPTR            32
  100.                        ; MEMO            65
  101.                        ; WORD            128
  102. _prog  segment byte public 'code'
  103. assume  cs:_prog
  104. ;
  105. ;
  106. FALSE   EQU     0
  107. TRUE    EQU     NOT FALSE
  108. BASE    EQU     03F8H   ;BASE FOR SERIAL BOARD COMM1
  109. LCR     EQU     BASE+3  ; Line control register
  110. IER     EQU     BASE+1  ; Interrup Enable Register
  111. MCR     EQU     BASE+4  ; modem control register
  112. EnblDRdy EQU    01H     ; enable 'data-ready' interrupt bit
  113. IntCtlr  EQU    21H     ; OCW 1 FOR 8259 CONTROLLER
  114. EnblIRQ4 EQU    0EFH    ; Enable COMMUNICATIONS (IRQ4) COMM1
  115. DATAPORT EQU    BASE    ; transmit/receive data port
  116. MaskIRQ4 EQU    10H     ; BIT TO DISABLE COMM INTERRUPT (IRQ4)
  117. MDMSTA  EQU     BASE+5  ; line status register
  118. MDMMSR  EQU     BASE+6  ; modem status register
  119. MDMBAD  EQU     BASE    ; lsb baud resgister
  120. MDMBD1  EQU     BASE+1  ; msb baud rate register
  121. MDMCD   EQU     80H     ; mask for carrier dectect
  122. SETBAU  EQU     80H     ; code for Divisor Latch Access Bit
  123. MDMTBE  EQU     20H     ; 8250 tbe flag
  124. MDMBRK  EQU     40H     ; command code for 8250 break
  125. LINMOD  EQU     03H     ; line mode=8 bit, no parity
  126. MDMMOD  EQU     0BH     ; modem mode = DTR and RTS HIGH
  127. STOP2   EQU     04H     ; BIT FOR TWO STOP BITS IF BAUD<300
  128. RS8259  EQU     20H     ; OCW 3 FOR 8259
  129. RSTINT  EQU     64H     ; SPECIFIC EOI FOR COMM INTERRUPT
  130. XOFF    EQU     13H     ; XOFF character
  131. XON     EQU     11H     ; XON character
  132. ;
  133.  ;       MISCELLANEOUS EQUATES
  134. ;
  135. CR      EQU     13
  136. LF      EQU     10
  137. DosCall EQU     33      ;INTERRUPT NUMBER FOR DOS CALL
  138. CNSTAT  EQU     11      ;FUNCTION NUMBER FOR CONSOLE STATUS
  139. CNIN    EQU     1       ;FUNCTION NUMBER FOR CONSOLE INPUT
  140. BUFSIZ  EQU     512     ;Max NUMBER OF CHARS
  141. SetIntVect  EQU 25H     ;SET INTERRUPT VECTOR FUNCTION NUMBER
  142.  
  143. ;
  144. ;       DUMP BUFFER, COUNT AND POINTER.
  145. ;
  146. CIRC_BUF  DB    BUFSIZ DUP(?)   ;ALLOW 512 MAXIMUM BUFFERED CHARACTERS
  147. BUF_TOP   EQU   $ - 1           ;KEEP TRACK OF THE TOP OF THE BUFFER
  148. OUT_BUF   DB    BUFSIZ DUP(?)   ;TEMP BUFF AREA FOR CALLING PROCEDURE
  149. CIRC_TOP  DW    BUF_TOP         ;
  150. CIRC_IN   DW    OFFSET CIRC_BUF ;POINTER TO LAST CHAR. PLACED IN BUFFER
  151. CIRC_CUR  DW    OFFSET CIRC_BUF ;POINTER TO NEXT CHAR. TO BE RETRIEVED FROM
  152.                                 ; BUFFER
  153. CIRC_CT   DW    0               ;COUNT OF CHARACTERS USED IN BUFFER
  154. SNT_XOFF  DB    FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN SEND
  155. GOT_XOFF  DB    FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN RECEIVED
  156. SEE_XOFF  DB    FALSE           ;FLAG TO SEE IF WE ARE INTERESTED IN XON/XOFF
  157. CIRC_OUT  DW    0               ;NUMBER OF CHARACTERS RETURNED TO CLIPPER
  158. INTR_CUR  DW    0               ;BUFFER FOR INP_CHAR
  159. INTR_CT   DW    0               ;BUFFER FOR INP_CHAR
  160. KILLSTR   DB    0               ;FLAG PASSED TO KILL BUFFER UPON READING
  161. ;
  162. ;
  163. ;
  164. ;set_xoff(flag)         Enable (flag = 1 ) or disable
  165. ;int flag;              (flag = 0 ) XON/ XOFF protocol
  166. ;                       for the character input stream.
  167. ;If enabled, an XOFF will be sent when  the buffer
  168. ;reaches 3/4 full. NOTE: an XON will not be sent auto-
  169. ;matically. Your program must do it when it sees
  170. ;the rcvd_xoff() flag,  and ready for more chars.
  171. ;
  172. set_xoff proc far
  173.         push    bp
  174.         mov     bp,sp
  175.         PUSH    DS                  ;SAVE DATA SEGMENT
  176.         lds     si,dword ptr [bp+6] ; get calling varible addr off stack
  177.         xor     ax,ax
  178.         lodsb                       ; load al with calling variable
  179.         push    cs
  180.         pop     ds                  ; move code seg addr to data seg reg.
  181.         cmp     al,0                ; check for logic 0
  182.         jnz     to_on               ; if not 0 set it true=-1
  183.         mov     see_xoff,FALSE
  184.         jmp     done1
  185. to_on:  mov     see_xoff,TRUE
  186. done1:  pop     ds
  187.         pop     bp
  188.         ret
  189. set_xoff endp
  190. ;
  191. ;flag=  get_xoff()      Returns the current setting
  192. ;                       of the XON/ XOFF flag set
  193. ;by set_xoff(), above.
  194. ;
  195. get_xoff proc far
  196.         push    ds
  197.         push    cs
  198.         pop     ds                  ; move code seg addr to data seg reg.
  199.         xor     ax,ax               ; zero out ax
  200.         mov     al,see_xoff         ; get the flag -1=true 0=false
  201.         neg     al                  ; make it a positive
  202.         pop     ds
  203.         push    ax
  204.         call    _retl               ; return it to clipper a logical value
  205.         pop     ax                  ; adjust the stack
  206.         ret
  207. get_xoff endp
  208. ;
  209. ;flag=  sent_xoff();    Returns true if an XOFF
  210. ;                       character was sent, indicating
  211. ;                       the receive buffer is  3/4 full.
  212. ;
  213. sent_xoff proc  far
  214.         push    ds                  ; save data  seg reg
  215.         push    cs
  216.         pop     ds                  ; move code seg addr to data seg reg.
  217.         xor     ax,ax               ; zero out ax
  218.         mov     al,snt_xoff
  219.         neg     al                  ; make it positive
  220.         pop     ds
  221.         push    ax
  222.         call    _retl               ; return it to clipper
  223.         pop     ax
  224.         ret
  225. sent_xoff endp
  226. ;
  227. ;rcvd_xoff()            Returns true if an XOFF was
  228. ;                       received; will return false as
  229. ;soon as an XON is received. Does not effect data output,
  230. ;only indicates the above. (Obviously useless for binary
  231. ;data.)
  232. ;
  233. rcvd_xoff proc  far
  234.         push    ds                  ; save data  seg reg
  235.         push    cs
  236.         pop     ds                  ; move code seg addr to data seg reg.
  237.         xor     ax,ax               ; zero out ax
  238.         mov     al,got_xoff
  239.         neg     al
  240.         pop     ds
  241.         push    ax
  242.         call    _retl
  243.         pop     ax
  244.         ret
  245. rcvd_xoff endp
  246. ;
  247. ;count= inp_cnt()       Returns the number of characters
  248. ;                       available in the input buffer.
  249. ;
  250.  
  251. inp_cnt proc far
  252.          push    ds                  ; save data  seg reg
  253.          push    cs                  ;
  254.          pop     ds                  ; move code seg addr to data seg reg
  255.          mov     bx,circ_ct
  256.          pop      ds
  257.          push    bx
  258.          call    _retni              ; return to clipper a integer value
  259.          pop     bx
  260.          ret
  261. inp_cnt endp
  262. ;
  263. ;inp_flush()    Flush the input buffer.
  264. ;
  265. inp_flush proc  far
  266.         push    ds              ; save data reg
  267.         push    cs
  268.         pop     ds              ; move code seg addr to data seg reg.
  269.         mov     bx,offset circ_buf
  270.         mov     circ_in,bx
  271.         mov     circ_cur,bx     ; point the buffer pointer to the begining
  272.         xor     ax,ax
  273.         mov     circ_ct,ax      ; set the buffer cntr to zero
  274.         xor     cx,cx
  275.         mov     cl,see_xoff     ;check if interested in xon/xoff
  276.         cmp     cl,TRUE
  277.         jnz     clnup3          ;not interested, so goto return
  278.         cmp     snt_xoff,TRUE   ;have we sent an xoff?
  279.         jnz     clnup3          ;no, so return
  280.         mov     snt_xoff,FALSE
  281.         mov     cl,XON
  282.         push    ax              ; save char
  283.         call    comout          ; transmit xon char
  284.         pop     ax
  285. clnup3:
  286.         pop     ds
  287.         ret
  288. inp_flush endp
  289.  
  290. ; --------- Init -----------------------------------
  291. ; Program initialization:
  292. ;   --  Set up vector for RS232 interrupt (0CH)
  293. ;   --  Enbl IRQ4
  294. ;   --  Enbl RS232 interrupt on data ready
  295. ;
  296. ; ---------------------------------------------------
  297.  
  298. init_comm proc  far
  299.         push    bp
  300.         cli
  301. ;
  302. ;  ---- Set up  INT x'0C' for IRQ4
  303. ;
  304.         push    ds
  305.         push    cs
  306.         pop     ds              ;cs to ds
  307.         mov     dx,offset IntHdlr ;relative adddres of interrupt handler
  308.         mov     al,0cH          ;interrupt number for comm.
  309.         mov     ah,SetIntVect   ;function number for setting int vector
  310.         int     DosCall         ;set interrupt in 8086 table
  311.         pop     ds              ;restore DS
  312. ;
  313. ;  ---- Enbl IRQ4 on 8259 interrupt controller
  314. ;
  315.         cli
  316.         in      al,IntCtlr      ; get current masks
  317.         and     al,EnblIRQ4     ; Reset IRQ4 mask
  318.         out     IntCtlr,al      ; And restore to IMR
  319. ;
  320. ;  ---   Enbl 8250 data ready interrupt
  321. ;
  322.         mov     dx,LCR          ; DX ==> LCR
  323.         in      al,dx           ; Reset DLAB for IER access
  324.         and     al,7FH
  325.         out     dx,al
  326.         mov     dx,IER          ; Interrupt Enbl Register
  327.         mov     al,EnblDRdy     ; Enable 'data-ready' interrupt
  328.         out     dx,al
  329. ;
  330. ;  ---   Enbl OUT2 on 8250
  331. ;
  332.         mov     dx,MCR          ; modem control register
  333.         mov     al,0AH          ; Enable OUT2 & RTS,DTR
  334.         out     dx,al
  335.         sti
  336.         pop     bp
  337.         ret
  338. init_comm endp
  339. ;
  340. ;uninit_com()          Removes the interrupt structure
  341. ;                       installed by init_com(). Must be
  342. ;done before passing control to the DOS, else chars received
  343. ;will be stored into the next program loaded!
  344. ;
  345. uninit_com proc far
  346.         push    bp
  347. ; ---   Disable IRQ4 on 8259
  348. ;
  349.         cli
  350.         in      al,IntCtlr      ;GET OCW1 FROM 8259
  351.         or      al,MaskIRQ4     ;DISABLE COMMUNICATIONS INTERRUPT
  352.         out     IntCtlr,al
  353. ;
  354. ; ---   Disable 8250 data ready interrupt
  355. ;
  356.         mov     dx,LCR          ; DX ==> LCR
  357.         in      al,dx           ; Reset DLAB for IER access
  358.         and     al,7FH
  359.         out     dx,al
  360.         mov     dx,IER          ; Interrupt Enbl Register
  361.         mov     al,0            ; Disable all 8250 interrupts
  362.         out     dx,al
  363. ;
  364. ;  ---   Disable OUT2 on 8250
  365. ;
  366.         mov     dx,MCR          ; modem control register
  367.         mov     al,0            ; Disable OUT2
  368.         out     dx,al
  369.         sti
  370.         pop     bp
  371.         ret
  372. uninit_com endp
  373. ;
  374. ;char inp_char()        Returns a character string from the input
  375. ;                       buffer. [see header note for details]
  376. ;
  377. ;
  378. inp_char proc far
  379.         push    es                  ; save extra reg
  380.         push    ds                  ; save data  reg
  381.         cld
  382. ;
  383.         mov     ax,0
  384.         push    ax
  385.         call    _parinfo             ; make sure there is 1 parameter
  386.         pop     bx
  387.         cmp     ax,1
  388.         jnz     I30
  389. ;
  390.         mov     ax,1
  391.         push    ax
  392.         call    _parinfo             ; make sure parameter is logical type
  393.         pop     bx
  394.         cmp     ax,4
  395.         jnz     nodeflt
  396. ;
  397.         mov     ax,1                ; get parameter
  398.         push    ax                  ; put it on the stack
  399.         call    _parl               ; get the parameter from clipper
  400.         pop     es                  ; dummy pop to fixup stack
  401.         jmp     nodeflt
  402. I30:
  403.         mov     al,1
  404. nodeflt:
  405.         push    cs
  406.         pop     ds                  ; move code seg addr to data seg reg.
  407.         push    ds
  408.         pop     es                  ; load the target segment reg
  409.         mov     di,offset out_buf   ;  "    "    "    offset  reg
  410.         push    circ_ct
  411.         pop     intr_ct
  412.         push    circ_cur
  413.         pop     intr_cur
  414.         mov     killstr,al
  415.         xor     ax,ax
  416.         mov     circ_out,ax         ; zero the output count
  417. do_agan:
  418.         cmp     intr_ct,0           ; exit if the buffer is empty
  419.         jz      no_more
  420.         cmp     circ_out,length circ_buf   ; dont pass more than buffer size
  421.         jz      no_more
  422.         mov     bx,intr_cur
  423.         xor     ax,ax
  424.         mov     al,[bx]         ;get next char from circ_buf
  425.         cmp     killstr,1
  426.         jnz     ktrak
  427.         dec     circ_ct         ;decrement circ_buf COUNT
  428. ktrak:
  429.         dec     intr_ct
  430.         cmp     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  431.         jz      reset_cur       ;JUMP IF SO
  432.         inc     bx              ;ELSE, BUMP PTR
  433.         jmp short upd_cur
  434. reset_cur:
  435.         mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  436. upd_cur:
  437.         mov     intr_cur,bx             ;SAVE NEW PTR
  438.         cmp     killstr,1
  439.         jz      clnup2
  440.         xor     cx,cx
  441.         mov     cl,see_xoff     ;check if interested in xon/xoff
  442.         cmp     cl,TRUE
  443.         jnz     clnup2          ;not interested, so goto return
  444.         cmp     snt_xoff,TRUE   ;have we sent an xoff?
  445.         jnz     clnup2          ;no, so return
  446.         cmp     circ_ct,80h     ;yes, so see in buf is now emptying
  447.         jg      clnup2          ;not empty enuf to send xon, jump to ret
  448.         mov     snt_xoff,FALSE
  449.         mov     cl,XON
  450.         push    ax              ; save char
  451.         call    comout          ; transmit xon char
  452.         pop     ax
  453. clnup2:
  454.         inc     circ_out        ;inc the output counter
  455.         stosb                   ;move the recv char to the output buffer
  456.         jmp     do_agan         ;go see if we can get another character
  457. no_more:
  458.         xor     ax,ax
  459.         stosb                   ;add a null to terminate the recv string
  460. ;
  461.         cmp     killstr,1
  462.         jnz     nokill
  463.         push    intr_cur
  464.         pop     circ_cur
  465. nokill:
  466.         mov     bx,offset out_buf
  467.         mov     ax,seg out_buf
  468.         pop     ds
  469.         pop     es
  470.         push    ax
  471.         push    bx
  472.         call    _retc           ; push the segment and offset and return the
  473.         pop     bx              ; character string to clipper
  474.         pop     ax
  475.         ret
  476. ;
  477. ;
  478. inp_char endp
  479.  
  480.  
  481. ;outp_char(c)           Output the character string to the
  482. ;                       serial port. This is not buffered
  483. ;                       or interrupt driven. It will output
  484. ;                       the ascii string until a null in
  485. ;                       encountered.
  486. ;
  487. outp_char proc  far
  488.         push    bp
  489.         mov     bp,sp
  490.         push    ds
  491.         lds     si,dword ptr [bp+6] ; get the addr of varible string
  492.         cld                         ; make lodsb inc the var pointer
  493.   D20:  lodsb
  494.         cmp     al,00               ; is it the last char in string
  495.         jz      D30
  496.         mov     cl,al               ; get the transmit char to cl
  497.         push    ds
  498.         push    cs                  ; load code seg with data seg
  499.         pop     ds
  500. ;       push    ax
  501. ;       push    dx
  502. ;       xor     ax,ax
  503. ;       xor     dx,dx
  504. ;       mov     dl,cl           ; this code will echo the
  505. ;       mov     ah,2            ; characters to the screen
  506. ;       int     DosCall
  507. ;       pop     dx
  508. ;       pop     ax
  509.         sti                         ; set the interupt flag
  510.         call    comout              ; transmit a char
  511.         pop     ds
  512.         jmp     D20                 ; get the next char
  513.   D30:  pop     ds
  514.         pop     bp
  515.         ret
  516. outp_char endp
  517. ;
  518. ;Local  subroutine: output CL to the port.
  519. ;
  520. comout: mov     dx,MDMSTA
  521.         in      al,dx           ; get 8250 status
  522.         and     al,MDMTBE       ; check for transmitter ready
  523.         jz      comout          ; jump if not to wait
  524.         mov     al,cl           ; get char to al
  525.         mov     dx,DATAPORT
  526.         out     dx,al           ; output char to 8251
  527.         ret
  528. ;
  529. ;       RECEIVE INTERRUPT HANDLER (CHANGED TO PLACE CHARACTERS IN A
  530. ;        CIRCULAR circ_buf AND TO SEND AN XOFF IF THE circ_buf IS MORE THAN
  531. ;        3/4 FULL - S.G.)
  532. ;
  533. IntHdlr:
  534.         cli
  535.         push    cx
  536.         push    dx
  537.         push    bx
  538.         push    ax
  539.         push    ds
  540.         mov     ax,cs           ;get cur code segment
  541.         mov     ds,ax           ; and set it as data segment
  542.         mov     bx,circ_in      ;GET circ_buf IN PTR
  543.         mov     dx,dataport     ;GET DATA PORT NUMBER
  544.         in      al,dx           ;GET RECEIVED CHARACTER
  545. ;       push    ax
  546. ;       push    dx
  547. ;       xor     ax,ax
  548. ;       xor     dx,dx
  549. ;       mov     dl,al           ; this code will echo the
  550. ;       mov     ah,2            ; characters to the screen
  551. ;       int     DosCall
  552. ;       pop     dx
  553. ;       pop     ax
  554.         xor     cx,cx
  555.         mov     cl,see_xoff     ;check if interested in xon/xoff
  556.         cmp     cl,TRUE
  557.         jnz     ck_full         ;not interested goto ck if buf full
  558.         mov     cl,al           ;put char in cl for testing
  559.         and     cl,7fh          ;turn off any parity bits
  560.         cmp     cl,XOFF         ;see if we got an xoff
  561.         jnz     ck_xon
  562.         mov     got_Xoff,TRUE   ; code for handling xon/xoff from remote
  563.         jmp     clnup
  564. ck_xon: cmp     cl,XON
  565.         jnz     reg_ch
  566.         mov     got_Xoff,FALSE
  567.         jmp     clnup
  568. ;
  569. ;Normal character; not  XON/XOFF, or XON/XOFF disabled.
  570. ;
  571. reg_ch: test    snt_Xoff,TRUE   ;SEE IF sentXoff IS SET
  572.         jnz     ck_full         ;IF SO, DON'T SEND ANOTHER XOFF
  573.         cmp     circ_ct,(BUFSIZ * 3)/4  ;ALLOW BUF TO BECOME 3/4 FULL BEFORE
  574.                                         ; SENDING XOFF
  575.         jb      savch           ;IF IT'S OK, CONTINUE
  576.         push    ax              ;SAVE CHARACTER
  577.         mov     CL,XOFF         ;GET XOFF CHARACTER
  578.         mov     snt_Xoff,TRUE   ;RESET sentXoff
  579.         call    comout          ; AND SEND IT
  580.         pop     ax              ;RETRIEVE CHARACTER
  581.         jmp short savch         ;IF WE'RE HERE, THE circ_buf HAS BUFSIZ-80H
  582.                                 ;  CHARACTERS
  583. ck_full:
  584.         cmp     circ_ct,BUFSIZ  ;SEE IF circ_buf ALREADY FULL
  585.         jz      clnup           ; JUMP IF SO, DO NOT PLACE CHARACTER IN BFR
  586. savch:
  587.         mov     [bx],AL         ;SAVE NEW CHARACTER IN circ_buf
  588.         inc     circ_ct         ;BUMP circ_buf COUNT
  589.         cmp     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  590.         jz      reset_in        ;JUMP IF SO
  591.         inc     bx              ;ELSE, BUMP PTR
  592.         jmp short into_buf
  593. reset_in:
  594.         mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  595. into_buf:
  596.         mov     circ_in,bx              ;SAVE NEW PTR
  597. clnup:
  598.         mov     AL,RSTINT
  599.         out     RS8259,AL       ;ISSUE SPECIFIC EOI FOR 8259
  600.         pop     ds              ;GET BACK ENTERING DS
  601.         pop     ax
  602.         pop     bx
  603.         pop     dx
  604.         pop     cx
  605.         sti
  606.         iret
  607. ;
  608. _prog    ends
  609.  
  610. end
  611. 
  612.