title 'Serial Input module' ;***************************************** ; * ; SERIAL INPUT MODULE * ; Last change : 2/13/84 * ; * ;***************************************** include system.lib include chrcomm.equ include serdata.equ cseg public serial_in public store_char extrn supif:near ;; headentr.a86 extrn ocdesctbl:word ;; serdata.a86 extrn usart_on:near extrn xmit_on:near ;; servar.a86 extrn xmit_off:near ;; servar.a86 extrn set_bit:near ;; servar.a86 extrn clear_bit:near ;; servar.a86 serial_in: ;----- ; ENTRY: bx = addr of the input Q control block ; ; EXIT: al = data from the usart's Q ; ah = the usarts status byte pushf ! cli cin2: ;; if char is available, get it test Q_STATE[bx], CHAR_AVAIL ;; else flagwait until it's available jnz cin1 or Q_STATE[bx], IPROC_WAITING ;; set a loacal proc waiting flag push bx ;; save the address of Q control struc mov dl, SYS_FLAG[bx] ;; do the flag wait mov cl, F_FLAGWAIT call supif cmp ax, 0ffffh ! jne cin3 ;; was there an error ? mov cl, P_DISPATCH ;; dispatch the process, let it try call supif ;; again later cin3: pop bx ;; get back the Q control structure jmps cin2 ;; just in case the flagset shouldn't ;; have happened. cin1: push bx ;; save the Q control structure call conin_fc ;; call the console read routine pop bx ;; restore the Q control addr mov al, LAST_CHAR[bx] ;; al = char from Q mov ah, LAST_STAT[bx] ;; ah = status from Q popf ;; turn the interrupts back on ret conin_fc: ;;-------- ;; This routine reads a character from the console input Q ;; ;; ENTRY: bx -> the Q control structure ;; ;; EXIT: LAST_CHAR[bx] = the character that was read in ;; LAST_STAT[bx] = the usart's status that corresponded to the ;; char in LAST_CHAR[bx] push si ;; we need an index register mov si, PROC_OUT[bx] ;; get the Q's output index mov al, D_BUFF[bx+si] ;; get the character mov LAST_CHAR[bx], al mov al, S_BUFF[bx+si] ;; get the status byte mov LAST_STAT[bx], al inc si ;; inc the processes output index and si, (INMSGS -1) ;; mod the size of the Q mov PROC_OUT[bx], si ;; restore the index register pop si ;; restore the extra index register dec UN_PC[bx] ;; dec un-processed char count cmp UN_PC[bx], 0 ;; was this the last char in the Q ? jne cinf2 ;; no ... cinf1: and Q_STATE[bx], not CHAR_AVAIL cinf2: ;; if sender was stopped check the receive buffer ;; for being half empty. When the receive buffer is half test Q_STATE[bx], SENDER_STOPPED ;; empty restart the sender jz cinf3 cmp UN_PC[bx], ( INMSGS / 2 ) ja cinf3 call start_sender ;; the Q is half empty cinf3: ret store_char: ;;---------- ;; ;; This routine stores the status and data bytes from a usart in their Q's. ;; It also handles the interrupt level Xon Xoff protocol. ;; If an error is detected in the status byte returned from the USART ;; a reset error command is sent to the usart. ;; ;; ENTRY: bx -> receive Q control structure ;; al = the data read from the USART ;; ah = the status read from the USART ;; ;; EXIT: the status and data are put in the status and data Q's. ;; test Q_STATE[bx], BIT8_MASK ;; are we masking off the 8th bit jz try_xon and al, 7FH try_xon: test Q_STATE[bx], XX_MODE ;; is this Q in Xon Xoff mode ? jz store_now cmp al, XON ! jne try_xoff ;; is the char an Xon call xmit_on ;; char was an Xon, start transmitter ret try_xoff: cmp al, XOFF ! jne store_now call xmit_off ;; char was an Xoff, stop transmitter ret store_now: push si ;; use SI as an index register mov si, INT_IN[bx] mov D_BUFF[bx+si], al ;; store the data mov S_BUFF[bx+si], ah ;; store the status inc si and si, (INMSGS - 1) mov INT_IN[bx], si pop si or Q_STATE[bx], CHAR_AVAIL ;; set char avail flag test ah, PARITY_ERR or OVERRUN_ERR or FRAME_ERR;; check for usart errs jz no_err ;; if err, send error reset to usart inc ERR_CNT[bx] ;; inc the error reset counter mov ah, ERROR_RESET ;; set up the error reset bit call set_bit ;; now set it in the usarts command register and CMD_REG[bx], not ERROR_RESET ;; this is one time command ;; we have to reset the command ;; register image, so we don't ;; keep doing an error reset no_err: inc UN_PC[bx] cmp UN_PC[bx], UPPER_LIM ;; is # chars in buff >= limit ? jb check_proc_waiting ;; no call stop_sender ;; yes, stop transmitter check_proc_waiting: test Q_STATE[bx], IPROC_WAITING ;; only do flagset if proc is waiting jz no_proc_waiting ;; for a character and Q_STATE[bx], not IPROC_WAITING ;; clear the process waiting flag push ax ! push bx ! push cx ;; this is an interrupt context push dx ! push bp ! push si ;; save the environment push di ! push es ! push ds sc2: mov dl, SYS_FLAG[bx] ;; get the flag number mov cl, F_FLAGSET ;; set the system function push bx ;; save the Q ptr in case of a retry call supif pop bx ;; restore the Q ptr cmp ax, 0ffffh ;; check for an error jne sc3 cmp cx, 2aH ;; was it a flag ignore ? jne sc3 ;; if it was not an ignore just exit jmps sc2 ;; else, try again sc3: pop ds ! pop es ! pop di ;; restore environment pop si ! pop bp ! pop dx pop cx ! pop bx ! pop ax no_proc_waiting: ret start_sender: ;;------------ ;; ;; This routine tries to restart the sender. ;; ;; ENTRY: bx = addr Q control structure ;; ;; EXIT: none ;; ;; NOTE: I have assumed + 12 volts on the DSR or RTS lines means ;; send data. Conversely - 12 volts means stop ;; sending data. ;; The DTR* pin (#24) on the 2651 is wired ;; to the DSR pin on the DB-25 connector ( pin 6 ), ;; through an inverting driver. This requires setting ;; the DTR bit in the command register to start the sender. ;; ;; For the RTS protocol, the RTS* pin (23) on the 2651 ;; is wired to the Ready for Send pin on the DB-25 ;; connector ( pin 5 ) through an inverting driver. This ;; requires setting the RTS bit in the command register ;; to start the sender. test Q_STATE[bx], DTR_MODE ;; check dtr protocol jz try_rts1 mov ah, DTR ;; force DTR* (dtr not) pin low call set_bit and Q_STATE[bx], not SENDER_STOPPED try_rts1: test Q_STATE[bx], RTS_MODE ;; check for RTS protocol, jz try_xx1 mov ah, RTS ;; force the RTS* (rts not) pin low call set_bit and Q_STATE[bx], not SENDER_STOPPED try_xx1: test Q_STATE[bx], XX_MODE ;; check for Xon/Xoff protocol jz no_prot call send_xon and Q_STATE[bx], not SENDER_STOPPED no_prot: ret stop_sender: ;;----------- ;; This routine tries to stop the transmitter. ;; ;; ENTRY: bx = addr( Q control ) ;; ;; EXIT: none ;; test Q_STATE[bx], DTR_MODE jz try_rts mov ah, DTR ;; force DTR* (dtr not) pin high call clear_bit or Q_STATE[bx], SENDER_STOPPED try_rts: test Q_STATE[bx], RTS_MODE ;; check for RTS protocol, jz try_xx mov ah, RTS ;; force the RTS* (rts not) pin high call clear_bit or Q_STATE[bx], SENDER_STOPPED try_xx: test Q_STATE[bx], XX_MODE ;; check for Xon/Xoff protocol jz no_protocol call send_xoff or Q_STATE[bx], SENDER_STOPPED no_protocol: cmp UN_PC[bx], INMSGS ;; If at lim of buffer, adjust char jb ss_2 ss_0: dec UN_PC[bx] cmp INT_IN[bx], 0 je ss_1 dec INT_IN[bx] jmps ss_2 ss_1: mov INT_IN[bx], (INMSGS - 1) ;; force index to end of buffer ss_2: ret send_xon: ;;-------- ;; This routine sends an Xon to the sender ;; ;; ENTRY: bx = addr of Q control sturcture ;; ;; EXIT: An Xon ( ctl q ) is sent to the sender ;; test XINT_MASK[bx], SS_U ;; is this the system support board? je sxn mov ah, XON ;; it's interfacer 3 board call send_char sxn: ret send_xoff: ;;--------- ;; This routine sends an Xoff to the sender. ;; ;; ENTRY: bx = addr of Q control sturcture ;; ;; EXIT: An Xoff ( ctl s ) is sent to the sender ;; test XINT_MASK[bx], SS_U ;; is this the system support board? je sxf mov ah, XOFF ;; it's the interfacer 3 board call send_char sxf: ret send_char: ;;--------- ;; This routine sends a single character to the USART in the Q ctl struct. ;; ;; ENTRY: bx = addr Q control structure ;; ah = char to send ;; ;; EXIT: none push bx ;; save the input Q control addr mov bl, U_NUMB[bx] ;; get the usart's i3 number xor bh, bh ;; clear the upper byte inc bx ;; index above the SS usart shl bx, 1 ;; indexing into a word table mov bx, ocdesctbl[bx] ;; bx -> Output Q control push cx push si mov cx, OMSGCNT[bx] ;; get the number of chars in Q mov si, omsgout[bx] ;; get the output index add si, cx ;; add to it the number of chars and si,onmsgs-1 ;; in the buffer, mod( buff size ) mov obuffer[bx+si],ah ;; put the char in the Q inc cx ;; inc the chars in Q count mov omsgcnt[bx],cx ;; update dec cx ;; if 1st char in Q, start Xmit int's jnz sc1 ;; cx = chars in Q - 1 call usart_on ;; start the Xmitter sc1: pop si pop cx pop bx ;; restore the input Q control addr ret end