File:  [Synchronet] / sbbs / steve / rciolx.asm
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:37:52 2018 UTC (8 years, 3 months ago) by root
Branches: digitaldynamics, MAIN
CVS tags: v1_06a, HEAD
1.06a MS-DOS

	.xlist
	include	mdef
	.ilist
;************************************************************************
;*									*
;*         rciol: direct 8250 communications interface for C		*
;*									*
;*    prototypes: int   rioini(int,int);     initialize com,irq		*
;*		  int   setbaud(int);        set baud rate		*
;*	*n/a	  int   rioctl(int);         remote i/o control		*
;*		  void  dtr(char);           set/reset dtr		*
;*		  int   outcom(int);         send character		*
;*		  int   incom(void);         receive character		*
;*	*n/a	  int   rioifc(int);         local i/o redirection	*
;*									*
;************************************************************************

; this source file is lacking _rioctl and _rioifc

biosda	segment at 40h		;bios data area
biosda	ends

	setmod	%mm

; 8259 interrupt controller register equates

icr1	equ	20h		;interrupt command register (master)
imr1	equ	21h		;interrupt mask register (master)
ivb1	equ	8		;vector base 0-7: cannot be read, assumed
icr2	equ	0a0h		;interrupt command register (slave)
imr2	equ	0a1h		;interrupt mask register (slave)
ivb2	equ	70h		;vector base 8-f: cannot be read, assumed

; 8250 uart register equates

iir	equ	2		;interrupt identification register
ier	equ	1		;interrupt enable register
ierd	equ	0bh		;enable: rxd, thre, msr

msr	equ	6		;modem status register
mcr	equ	4		;modem control register
mcrd	equ	0bh		;irq enable, rts on, dtr on

lsr	equ	5		;line status register
lcr	equ	3		;line control register
lcrd	equ	3		;N,8,1 mode

; buffer pointer structure

dstruc	bufp,0
	dss	2,bcnt		;character count
	dss	2,bput		;next character to buffer
	dss	2,bget		;next character from buffer
	dss	1,ovfl		;overflow flag
	dss	1
	dss	2,bofst		;buffer offset
	dss	2,bsize		;buffer size
dstruc	bufp
	.xlist
	.eopg
	.data
	public	_plst

	align 2

brdd	dd	115200		;baud rate dividend

iv16h	dd	0		;saved interrupt vector for int 16h
iv29h	dd	0		;saved interrupt vector for int 29h
ivsio	dd	0		;saved serial i/o vector

buart	dw	0		;uart base address
lsrad	dw	0		;line status register port address
irqn	db	0		;interrupt request line
ircr	db	0		;saved interrupt controller mask
siovn	db	0		;serial i/o vector number

ic29h	equ	1		;int 29h is being intercepted
ic29d	equ	3		;int 29h is being diverted
ic16h	equ	10h		;int 16h is being intercepted
intcp	db	0		;intercepted interrupt code

opera	db	0		;operational (port defined, baud set)

mode	db	0		;function enable (incl pause/abort cycles)
state	db	0		;operational state (must follow mode)
hold	equ	2		;stop transmission
abort	equ	4		;aborting
ctsck	equ	10h		;check clear to send signal (mode only, fixed)

txintp	db	0		;transmit interrupt pending
status	db	0		;communications status
rxlost	equ	1		;received characters lost

	align	2
txbmx	equ	1024		;receive buffer maximum size
rxbmx	equ	1024		;transmit buffer maximum size

_plst	label	word

dv	rxbp	bufp,0		;receive buffer pointers
dv	txbp	bufp,0		;transmit buffer pointers

dv	rxb	rxbmx,0a8h	;receive buffer
dv	txb	txbmx,0a8h	;transmit buffer

tst	db	0
	.xlist
	.eopg
	.code
	public	_rioini,_outcom,_incom,_dtr,_setbaud

riods:	dw	-1		;remote i/o routine data segment value

; initialize communications

; clear buffers, data, program uart, enable interrupts

_rioini	proc
	push	bp
	mov	bp,sp
	push	si
	push	di

	mov	ax,pb[bp]	;com port or uart address
	or	ax,ax
	mov	ax,buart
	jnz	@f		;initialize
	or	ax,ax
	jz	cierr		;error, not initialized
	jmp	finis		;terminate

@@:	or	ax,ax
	jz	cinit		;continue, not yet initialized
cierr:	mov	ax,-1
	jmp	ciex		;return error

cinit:	mov	ax,ds
	mov	cs:riods,ax		;save data segment

	call	ibfls			;clear input buffer
	mov	bofst[si],os rxb	;set receive buffer address
	call	obfls			;clear output buffer
	mov	bofst[si],os txb	;set transmit buffer address

	xor	ax,ax
	mov	mode,ax		;clear mode and state
	mov	txintp,al	;clear int pending

	mov	ax,seg biosda
	mov	es,ax
	mov	bx,pb[bp]	;com port or uart address
	mov	dx,bx
	dec	bx
	cmp	bx,4
	jnc	scport		;com port address specified

	and	bx,3		;com 0-3 for 1-4
	add	bx,bx		;offset (x 2)
	mov	dx,es:[bx]
	or	dx,dx
	jnz	scport		;port exists
	jmp	ciabt		;no such com port

scport:	mov	buart,dx	;uart base address
	add	dx,lsr
	mov	lsrad,dx	;line status register

;	mov	al,pb[bp+4]	;hardware flow control
;	and	al,1
;	jz	girq
;	or	mode,ctsck	;check cts

girq:	mov	al,pb[bp+2]	;irq line
	and	al,7
	jnz	irqv		;valid
	and	al,1
	add	al,3		;assume 4 for 1, 3 for 2
irqv:	mov	irqn,al
	mov	cl,al
	mov	al,1
	shl	al,cl		;mask for current irq line
;	mov	irqm,al
	mov	ah,al
	push	ax		;save irq mask
	in	al,imr1
	mov	ircr,al		;save prior enable mask
	or	al,ah
	out	imr1,al		;inhibit interrupts
	mov	al,cl		;irq number
	add	al,ivb1		;add vector base
	mov	siovn,al	;save sio vector
	call	gvect		;get prior vector in dx:bx
	mov	ivsio,bx
	mov	ivsio+2,dx	;save prior vector
	push	cs
	pop	dx
	mov	bx,os sioisr
	call	svect		;set service routine vector in dx:bx

	mov	dx,buart
	in	ax,dx		;clear%
	add	dx,mcr
	mov	al,mcrd
	out	dx,al		;modem control register
	dec	dx
	mov	al,lcrd
	out	dx,al		;line control register
	dec	dx
	dec	dx
	mov	al,ierd
	out	dx,al		;interrupt enable register

	pop	ax		;irq mask
	in	al,imr1
	not	ah
	and	al,ah
	out	imr1,al		;enable interrupts

;	mov	mw cs:mv2,1234h
;	xor	ax,ax
;	mov	si,os inims
;	call	msout

	xor	ax,ax		;return 0
	jmp	ciex		;exit

; terminate serial i/o operation

finis:	mov	dx,buart
	add	dx,mcr
	xor	al,al
	out	dx,al		;dtr off, release irq line

	mov	al,siovn	;serial i/o vector
	mov	bx,ivsio	;prior offset
	mov	dx,ivsio+2	;prior segment
	call	svect		;replace original vector

	mov	al,ircr
	out	imr1,al		;replace prior interrupt controller mask
	xor	bx,bx
	jmp	cterm		;return 0

ciabt:	mov	bx,-1
cterm:	xor	ax,ax
	mov	buart,ax	;not initialized
	mov	opera,al	;not operational
	mov	ax,bx		;return code
ciex:	pop	di
	pop	si
	pop	bp
	ret

_rioini	endp


; get interrupt vector al in dx:bx

gvect:	push	es
	mov	ah,35h
	int	21h		;returns vector in es:bx
	push	es
	pop	dx		;segment
	pop	es
	ret

; set interrupt vector al in dx:bx

svect:	push	ds
	push	dx
	mov	ds,dx		;segment
	mov	dx,bx		;offset
	mov	ah,25h
	int	21h		;takes vector in ds:dx
	pop	dx
	pop	ds
	ret


; flush buffers

ibfls:	mov	si,os rxbp	;address input buffer pointers
	mov	bx,rxbmx	;set maximum size
	jmp	s xbfls
obfls:	mov	si,os txbp	;address output buffer pointers
	mov	bx,txbmx	;set maximum size

; si -> bufp structure, bx = maximum size

xbfls:	mov	cx,os bofst/2	;pointer list length
	pushf
	cli
	push	si
	xor	ax,ax
	rep	stosw		;clear pointers
	pop	si
	mov	bsize[si],bx
	popf
	ret


; get character from buffer, ds:si -> pointers, saves cx, dx

bgetc:	mov	ax,bcnt[si]
	or	ax,ax
	jz	bgnc		;buffer empty

	pushf
	cli
	mov	bx,bofst[si]	;buffer offset from segment
	mov	di,bget[si]	;character offset from buffer
	mov	al,mb [bx+di]	;get character
	inc	di		;advance pointer
	cmp	di,bsize[si]
	jc	bggp		;pointer not past end of buffer
	xor	di,di		;reset to start
bggp:	mov	bget[si],di
	dec	bcnt[si]	;character count
	popf			;re-enable interrupts if disabled
	or	al,al		;character in al, clear carry
	ret

bgnc:	stc
	ret


; put character to buffer, ds:si -> pointers, al = char, saves ax, cx, dx

bputc:	mov	bx,bcnt[si]
bputco:	cmp	bx,bsize[si]
	jnc	bgnc		;buffer full

	pushf
	cli
	mov	bx,bofst[si]	;buffer offset from segment
	mov	di,bput[si]	;character offset from buffer
	mov	mb [bx+di],al	;put character
	inc	di		;advance pointer
	cmp	di,bsize[si]
	jc	bpgp		;pointer not past end of buffer
	xor	di,di		;reset to start
bpgp:	mov	bput[si],di
	inc	bcnt[si]	;character count
	popf			;re-enable interrupts if disabled
	clc			;character in al, clear carry
	ret


; sio input character

_incom	proc
	push	si
	push	di

	mov	si,os rxbp	;address receive buffer pointers
	call	bgetc		;get character from receive buffer
	mov	ah,state
	jnc	icgc		;received character in al
	or	ah,1		;no character available
	xor	al,al

icgc:	pop	di
	pop	si
	ret
_incom	endp


; sio output character

_outcom	proc
	xor	al,al
	mov	ah,state
	test	ah,abort
	jnz	ocabt		;aborting

	push	bp
	mov	bp,sp
	push	si
	push	di

	mov	al,pb[bp]
	mov	si,os txbp	;address transmit buffer pointers

ocrep:	mov	bx,bcnt[si]
	or	bx,bx
	jnz	ocbuf		;buffer not empty

	test	ah,hold
	jnz	ocbuf		;paused

	mov	dx,lsrad	;address line status register
	mov	cl,al
	in	al,dx
	and	al,20h		;transmit hold register empty
	mov	al,cl
	jz	ocbuf		;interrupt pending

	mov	dx,buart	;uart base (r/w data port)
	out	dx,al		;transmit character
	jmp	s ocex		;exit

ocbuf:	call	bputco		;put character to transmit buffer
	jnc	ocex		;done

	;check timer, exit if 2 min.

	jmp	ocrep		;retry

ocex:	pop	di
	pop	si
	pop	bp
ocabt:	ret			;state in ah
_outcom	endp


; sio interrupt service routine

sioisr	proc
	cli
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	ds

	mov	ax,cs:riods
	mov	ds,ax		;i/o data segment

isrep:	mov	dx,lsrad	;line status register
	in	ax,dx		;lsr in al, msr in ah
	mov	mw cs:mv2,ax	;%
	mov	cx,ax		;save line status
	sub	dx,lsr		;address r/w data port
	test	al,1		;received data available
	jz	txchk		;no character received

	test	al,0ch		;overrun/parity/framing error
	in	al,dx		;read data
	jnz	txchk		;receive error, discard data

	mov	bx,mode		;mode in bl, state in bh
	test	bh,abort
	jnz	intex		;aborting
	test	bl,abort
	jz	rcpau		;not checking for abort
	cmp	al,3		;^C
	jnz	rcpau		;not abort character

	call	ibfls		;flush input buffer
	call	obfls		;flush output buffer
	mov	state,abort	;aborting
	jmp	intex

rxccs:	mov	state,hold	;set pause flag
	jmp	s txchk
rxccq:	and	state,not hold	;clear pause flag
	jmp	s txchk

rcpau:	test	bl,hold
	jz	rxpch		;not checking pause
	cmp	al,13h		;^s
	jz	rxccs		;pause
	cmp	al,10h		;^q
	jz	rxccq		;resume

rxpch:	mov	si,os rxbp	;address receive buffer
	call	bputc		;put character in buffer
	jnc	txchk		;done
	or	status,rxlost	;set receive characters lost flag

txchk:	test	cl,20h		;transmit hold register empty
	jz	intex		;not ready to transmit

	mov	si,os txbp	;address transmit buffer
	call	bgetc
	jc	intex		;buffer empty

	mov	bx,mode		;mode in bl, state in bh
	not	ch
	and	ch,bl		;mode and not msr
	test	ch,ctsck	;cts checking and cts off
	jnz	intex		;hardware flow off, interrupt will resume

	test	bh,hold
	jnz	intex		;paused

	out	dx,al		;transmit character

intex:	mov	dx,buart
	add	dx,iir
	in	al,dx		;reset int?
	in	al,dx
;	and	al,1
;	jnz	isrex		;more?
;	jmp	isrep

	inc	mw cs:mv1
	mov	ax,rxbp.bcnt
	mov	mw cs:mv3,ax
	mov	ax,txbp.bcnt
	mov	mw cs:mv4,ax
	mov	ax,800
	mov	si,os intmsg
	call	msout

isrex:	pop	ds
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	mov	al,20h
	out	icr1,al		;non-specific eoi
	pop	ax
	iret

intmsg:	db	'Interrupt �5, msr/lsr �4, rxbc �4, txbc �4    ',0

sioisr	endp


; set baud rate

_setbaud proc
	mov	dx,buart	;base port address
	or	dx,dx
	jnz	sbinit		;initialized
	xor	ax,ax
	dec	ax		;-1
	ret			;return error

sbinit:	push	bp
	mov	bp,sp
	push	si
	mov	cx,dx	;%
	mov	si,os brdd	;address baud rate dividend
	mov	dx,2[si]
	mov	ax,[si]		;dividend in dx:ax
	div	mw pb[bp]	;divide by parameter 1
	mov	dx,cx	;%
	push	ax		;actual rate divisor for uart
	mov	si,dx
	add	dx,lcr		;address line control register
	in	al,dx
	or	al,80h
	out	dx,al		;address baud rate divisor
	xchg	si,dx
	pop	ax
	out	dx,ax		;write baud rate divisor
	xchg	si,dx
	in	al,dx
	and	al,7fh
	out	dx,al		;address rx/tx registers, ier
	xchg	si,dx
	in	ax,dx		;clear%

	xor	ax,ax		;no error
	pop	si
	pop	bp
	ret
_setbaud endp
	.xlist
	.eopg
; drop dtr

; n=0 (off), n=1 (on), or n>1 (off, wait n seconds for dcd off)

_dtr	proc

	push	bp
	mov	bp,sp
	mov	ax,seg biosda
	mov	es,ax

	mov	dx,buart	;uart base port
	or	dx,dx
	jz	dtrer		;not initialized

	add	dx,4		;address mcr
	in	al,dx
	and	al,0feh		;clear dtr bit
	mov	ah,pb[bp]	;parameter
	and	ah,0fh
	cmp	ah,2		;0 off, 1 on
	jnc	wtdcd		;off, wait for dcd
	or	al,ah
	out	dx,al		;set as specified
	xor	al,al
	jmp	s dtrck

wtdcd:	out	dx,al		;dtr off
	inc	dx
	inc	dx		;address msr

twn:	mov	cx,18		;55ms/s
tws:	mov	bl,es:[6ch]	;55ms counter
twt:	in	al,dx
	and	al,80h		;dcd
	jz	dtrck		;done
	cmp	bl,es:[6ch]	;55ms counter
	jz	twt		;wait 55ms
	loop	tws		;wait 990ms
	dec	ah
	jnz	twn		;wait 2-x seconds
dtrer:	mov	al,-1		;timeout

dtrck:	mov	ah,al
	cmp	mb pb[bp],1
	jz	dtrex		;dtr was set

	push	ax		;dtr was reset, clear state and buffers
	call	ibfls
	call	obfls
	xor	al,al
	mov	state,al
	mov	status,al
	pop	ax

dtrex:	pop	bp
	ret
_dtr	endp

	include	mviow
	end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.