
title	'Interrupt Serial Output'

;****************************************************************
;*								*
;*	This module is the invariant part of an interrupt 	*
;*	driven serial output system.                            *
;*	Last Update: 2/14/84					*
;*								*
;****************************************************************

include flags.equ
include	system.lib
include chrcomm.equ
include serdata.equ

	dseg

public	dsr_check
public	dsr_vec

extrn	bit_mask_tbl:byte
extrn	ocdesctbl:word
extrn   icdesctbl:word
extrn   vrtl_phy:byte

	cseg

public	serial_out
public	intco
public	dsr_start

extrn	supif:near

extrn	usart_on:near
extrn	usart_off:near
extrn	usart_select:near

;;=====
intco:                                    ;; called from ssint.a86,i3int.a86
;;=====
;;      
;;	ENTRY:	bx -> Xmit Q ctl structure
;;
;;	OFLAG:	01h - process flag waiting (buf empty)
;;		02h - status ready
;;		10h - Xoff pending
;;		20H - Xon/Xoff mode
;;		80H - RTS protocol support
;;
;;      EXIT :  AX,BX used.
;;              All other registers preserved.
;;
;;		Handles the interrupt side of writing a char to the console.
;;		It runs in an interrupt context.

	push dx				;; port select register
	xor dh,dh			;; clear the high byte
	mov al, OUSART[bx]		;; get the usart number
	cmp al, NO_SELECT       	;; does it need a select ?
	  je no_sel      
	call usart_select
no_sel:
	test OFLAG[bx], XON_XOFF_MODE   ;; Is this USART supporting Xon/Xoff protocol ?
	  jz intco1
        test OFLAG[bx], XOFF_PENDING    ;; Have we received a stop request?
	  jnz icoexit                   ;; yes
intco1:
	test OFLAG[bx], RTS_PROT        ;; Is this USART supporting RTS protocol
          jz intco2
        xor dh, dh                      ;; yes,...
	  mov dl, OSTPORT[bx]		;; get the status port
	  in al, dx			;; get the status
	  mov ah, DSR_BIT[bx]		;; get the DSR bit
	  test al, ah			;; test the DSR bit of the USART
	    jnz intco2			;; bit(7) = 1 if DSR* = 0 volts
          call dsr_stop                 ;; we've gotten a request to stop
	    jmp icoexit
intco2:                                 
	mov dl, OSTPORT[bx]		;; get the status port addr
	in al,dx			;; get the USARTS status
	mov ah, XMIT_MASK[bx]		;; get the Xmit empty mask
	test al, ah			;; is the Xmit buffer empty ?
	  jz icoexit
	                                ;; yes, are there any characters to send ?
	  push cx			;; save the regs we're going to use 
	  push si
	  mov cx, OMSGCNT[bx]		
	  cmp cx,0       		;; is there a char to send ?
            je icodone	    
          mov si, OMSGOUT[bx]		;; yes, get the output index
	  mov al, OBUFFER[bx+si]	;; al = char to send
	  mov dl, OIOPORT[bx]		;; get the USARTS data port
	  out dx, al			;; send the char 
	  inc si			;; inc the output index
	  and si, ONMSGS - 1		;; mod the Queue size
	  mov OMSGOUT[bx], si		;; save the output index
	  dec cx 			;; dec the chars-to-send count
	  mov OMSGCNT[bx], cx	        ;; If there is a proccess waiting for 
                                        ;; room in this Q, do a flag set for 
                                        ;; the process when the Q is half empty.
	    cmp cx, ( ONMSGS / 2 )	;; is the Q at least half empty ?
	      ja icodone
           test OFLAG[bx], PROC_WAITING ;; yes, is there a process waiting?
	      jz icodone                ;; no,...
           push bx			;; save the remaining environment
	   push bp			;; for the flag set call
	   push di
	   push es
intco3:
           mov dl, OFLAGN[bx]	        ;; Get the flag for this Q
	   mov cl, F_FLAGSET	        ;; do the flag set
	   push bx			;; save the Q ptr in case of a retry
	   call supif
           pop bx                   
	   cmp ax, ERROR		;; was there an error ?
	    jne intco4
              cmp cx, FLAG_IGNORE       ;; yes, was the flag ignored ?
		je intco3               ;; yes, try again
intco4:
            pop es			;; restore the environment
	    pop di			;; that was saved for the flag set
	    pop bp
	    pop bx
            and OFLAG[bx], not  PROC_WAITING ;; clear the proc waiting flag
icodone:
	pop si				;; restore the context 
	pop cx			       	
	cmp OMSGCNT[bx], 0              ;; More char's to send ?
	  jne icoexit                   ;; yes, just return
	mov al, OUSART[bx]		;; no,  get the usart number
	call usart_off                  ;; turn off usart's transmit system
icoexit:
	pop dx

	ret


eject

;===========
serial_out:
;===========
;
;	ENTRY:	cl = character to send out
;		bx -> Queue control struct
;
;	EXIT:	the character is :
;               1] either sent to the USART, 
;               2] or put in the output buffer,	
;               3] or, the process is flagwaited until there is room
;		in the output buffer .

	pushf				 
	push bx
	cli				
	push cx				;; save the character
	mov cx, OMSGCNT[bx]		;; cx = number of chars in the Q
	cmp cx, ONMSGS			;; is there room in the Q ?
	  jb con1
	or OFLAG[bx], PROC_WAITING	;; no, set a local process-waiting flag
	pop cx 			        
	pop bx
	popf				;; turn interrupts back on
	push cx			        ;; save the character
	push bx			        ;; save the Q ctl structure

	mov dl,OFLAGN[bx]		;; do the global flagwait
	mov cl,F_FLAGWAIT
	  call supif
	cmp ax, ERROR			;; was there an error ?
	  jne con0
	                                ;; It might have been a flag overrun.
        mov cl, P_DISPATCH              ;; Dispatch the process, and try again.
          call supif

con0:
        pop bx			        ;; BX -> Q ctl structure
        pop cx			        ;; restore the char
	  jmps serial_out

con1:                                   ;; There's  room in the Xmit Q.
	cmp OESC_CNT[bx], 0		;; Check the esc count
	  jz not_esc
	push bx
        cmp OESC_CNT[bx], 1             ;; Are we at the end of the sequence?
	  je check_switch		;; Yes, see if PIN is waiting.

check_xy:
	cmp OESC_CNT[bx], 3		;; See if this is a 4-char sequence.
	  jne dec_esc			;; We're at first or third char.
        pop bx ! pop ax 
	push ax ! push bx 		;; AX -> char , BX -> Output Q ctl
        cmp ax, 'Y'			;; ESC Y is only 4-char sequence.
	  je dec_esc

check_switch:
        pop bx ! pop ax 
	mov OESC_CNT[bx], 0		;; Clear escape count.
         call con2			;; Send the last char in the sequence
        xor ah,ah			;; before doing the flag set, if any.
        mov al, CUR_VCON[bx]
        mov bx,ax
        mov bl, vrtl_phy[bx]		;; get the physical console #
        xor bh,bh
        shl bx, 1
        mov bx, icdesctbl[bx]		;; get the Input Q control structure
        test Q_STATE[bx],SWITCH_PEND    ;; Is PIN waiting for an escape
          jz exit 			;; sequence to end ?

flag_set:
        push bx ! push cx ! push si
        xor dh, dh
        mov dl, P_CON[bx]
        add dl, SWITCH_BIAS		;; Flag # = virtual console + bias
        mov cl, f_flagset		;; Wake up the PIN waiting to do
         call supif			;; a screen switch.
        pop si ! pop cx ! pop bx
        and Q_STATE[bx], not SWITCH_PEND
	  jmps exit
not_esc:
	pop ax
	call con2
	 jmps exit
dec_esc:
        pop bx  ! pop ax
	dec OESC_CNT[bx]
	call con2

exit:
	pop bx
	popf
	 ret

con2:	                                ;; put the character in the Xmit 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],al		;; put it in the Q
	inc cx				;; inc Q char count
	mov OMSGCNT[bx],cx		
	                                ;; if 1st char in Q, start USART Xmit
	dec cx				;; cx = chars in Q -1 
	  jnz con4
	test OFLAG[bx], XON_XOFF_MODE   ;; Is it supporting Xon/Xoff protocol ?
	  jz con3
	test OFLAG[bx], XOFF_PENDING    ;; Is there an Xoff pending ?
	    jnz con4                    
	                                ;; The character is in the buffer and 
con3:                                   ;; the usart int system is turned off.
	call usart_on                   ;; Start the Usart's Xmitter.
con4:
	ret

eject


;===========
dsr_stop:
;===========
;	This routine is called when the USART is set to acknowledge the DSR pin
;       and the DSR line is high (i.e.,stop sending data).
;
;	ENTRY:	bx ->	Output Q control structure for the USART
;	EXIT:	The dsr_vec has a bit set for this usart. 
;               The usart transmitter interrupt system is shut down.
;		The dsr_check flag is posted for the tick routine.

	                                ; To post this usart in the dsr_vec
	mov al, O_BIT_MASK[bx]		; get the bit corresponding to this USART 
        or dsr_vec, al                  ; OR  it into the DSR vector
	mov al, OUSART[bx]		; get the usart number
	call usart_off			; and stop the transmitter
	mov dsr_check, TRUE             ; signal the tick routine to check the
                                        ; state of the DSR pin for this usart
	ret

;=========
dsr_start:
;=========
;	Called by the tick routine when the dsr_check flag = true.
;	It looks at the dsr vector to figure out which usart has had its 
;       transmitter turned off (due to the DSR pin). It then reads the usart's
;	status and tests the state of the DSR bit in the status word (bit(7)).
;	When this bit is on ,the port we're sending to	wants more data. We 
;       start the transmitter and remove its bit from the dsr_vector. If the
;       dsr vector has all its bits cleared, we clear the dsr check flag.

	push ax                         ;; save the environment
	push bx
	push cx
	push dx

dsr_test_lp:	
	mov al, 0			
	call usart_select		;; select the usart
	mov ah, dsr_vec			;; bit vector of the off Xmitters
dsr_lp_0:
	mov bx, offset bit_mask_tbl	;; byte mask for each Xmit interrupt
	mov cx, 8			;; length of bit mask table
dsr_lp:
	test ah, [bx]
	  jz dsr_lp_2
	 mov al, [bx]                   ;; found the usart, AND off the bit in
	 not al                         ;; dsr_vec
	 and ah, al
                                        ;; CX = USART	  
	  mov bx, offset ocdesctbl	;; get base of Xmit Q table
	  shl cx, 1			;; times 2 ( word table )
	  add bx, cx			;; index into the table
	  mov bx, [bx]			;; bx -> Xmit Q ctl Structure
	  mov al, OUSART[bx]		;; select the USART
	  call usart_select
	  xor dh, dh
	  mov dl, OSTPORT[bx]		;; get USART's status port
	  in al, dx			;; read the status
	  test al, DSR_BIT[bx]          ;; check DSR pin - should we turn on 
            jz dsr_lp_1                 ;; the transmitter ?
          call usart_on		        ;; yes, turn on the Usart 
          mov al, O_BIT_MASK[bx]	;; get the bit
          not al			;; make it an AND mask
          and dsr_vec, al	    	;; remove from bit vector
dsr_lp_1:
	jmps dsr_lp_0			;; in case another usart has it's
					;; xmitter turned off
dsr_lp_2:
	inc bx				;; point to the next mask
	loop dsr_lp			;; check all the USARTS

	cmp dsr_vec, 0                  ;; if dsr_vec is empty, clear dsr_check
          jne dsr_st1                   ;; flag
        mov dsr_check, FALSE
dsr_st1:
	pop dx				;; restore the environment
	pop cx
	pop bx 
	pop ax
	
	ret



	dseg


dsr_check	db	0	; This flag = true when a USART has had its
				; transmitter shut down due to the state of 
				; the dsr pin.

dsr_vec		db	0	; This is a bit vector of the usarts that
				; have had their transmitter(s) shut down by
				; a reqest from the port they're sending data
				; to.


	end


