	.title	Serial Line unit handler

	;	DECUS C Calling Format
	;
	;	jsr	r5,csv$		;save r2,r3, and r4
	;				;r5 is parameter base
	;				;c$pmtr(r5) is first argument
	;				;c$pmtr+2(r5) is second argument
	;				;...
	;				;return args in r0
	;	...
	;	user code
	;	...
	;
	;	jmp	cret$		;restore r2-r5 and return
	;	rts	pc		;does the same (cret$ follows csv$)
	;	
	;	csv$ and cret$ need be used only if arguments are used
	;

	.include	"os.mac"

	.mcall	.close

	arg1	=	2

.if ne ts$sys			;tsx-plus specific
	CLIUNT	= 13		;Channel # for CL unit input
	CLOUNT	= 12		;Channel # for CL unit output
	CLCTRL	= 11		;Channel # for CL unit control

	CLRXNF	= 201		;SPFUN code to clear XOFF / send XON
	CLRBYT	= 203		;SPFUN code to read CL with byte count
	CLSOPT	= 250		;SPFUN code to set CL options
	CLCOPT	= 251		;SPFUN code to clear CL options
	CLABRT	= 257		;SPFUN code to abort this jobs pending i/o
	CLIPND	= 261		;SPFUN code to get # chars pending CL input
	CLWBYT	= 263		;SPFUN code to write CL with byte count
	CLRST	= 265		;SPFUN code to reset CL unit

	.sbttl	CL Unit Initialization

	.psect	c$code

sl.init::
	mov	#-1,-(sp)		;error return

	mov	arg1+2(sp),r0		;get unit number
	cmp	r0,#7
	bhi	1$

	mov	#^rCL0,clspec		;restore spec
	add	r0,clspec		;compute unit

	jsr	pc,sl.abort		;abort any current i/o

	mov	#lkaloc,r0		;allocate CL unit
	emt	375
	bcs	1$			;allocation error - exit

	mov	#lkctla,r0		;.lookup
	emt	375
	bcs	1$			;device error - exit

	mov	#lkinpa,r0		;.lookup
	emt	375
	bcs	1$			;device error - exit

	mov	#lkoupa,r0		;.lookup
	emt	375
	bcs	1$			;device error - exit

	mov	#clrset,r0		;.spfun
	emt	375
	bcs	1$			;initialization error - exit

	mov	#clset,r0		;.spfun
	emt	375
	bcs	1$			;initialization error - exit

	mov	#clclr,r0		;.spfun
	emt	375
	bcs	1$			;initialization error - exit

	clr	oupact			;clear output

	jsr	pc,$mrkto		;startup CL input timeout

	clr	(sp)

1$:	mov	(sp)+,r0
	rts	pc


	.psect	c$data

lkaloc:	.byte	0,156			;allocate CL unit
	.word	clspec

lkctla:	.byte	CLCTRL,1		;lookup
	.word	clspec
	.word	0

lkinpa:	.byte	CLIUNT,1		;lookup
	.word	clspec
	.word	0

lkoupa:	.byte	CLOUNT,1		;lookup
	.word	clspec
	.word	0

clspec:	.rad50	/CL0/			;cl unit specification
	.word	0,0,0

clrset:	.byte	CLCTRL,32		;.spfun for CLRST
	.word	0
	.word	0
	.word	0
	.byte	377,CLRST
	.word	0

	; CL unit flags, (1) set, (0) noset
	;000001 FORM		Send form feed characters
	;000002 TAB		Send tab characters
	;000004 LC		Send lower case letters
	;000010 LFOUT		Send line feed characters
	;000020 LFIN		Accept line feed characters
	;000040 FORM0		Send form feed on block 0 write
	;000100 BINOUT		Send binary output characters
	;000200 BININ		Accept binary input characters
	;000400 CR		Send carriage return characters
	;001000 CTRL		Send control characters
	;002000 DTR		Raise Data Terminal Ready (DTR)
	;004000 EIGHTBIT	Accept and send 8 bit characters

clset:	.byte	CLCTRL,32		;.spfun for CLSOPT
	.word	0
	.word	1$
	.word	0
	.byte	377,CLSOPT
	.word	0

1$:	.word	001437			;set these flags

clclr:	.byte	CLCTRL,32		;.spfun for CLCOPT
	.word	0
	.word	1$
	.word	0
	.byte	377,CLCOPT
	.word	0

1$:	.word	006340			;clear these flags


	.sbttl	CL Unit Abort I/O

	.psect	c$code

sl.abort::
	mov	#clabt,r0		;abort i/o
	emt	375

	mov	#$cmkta,r0		;abort .mrkt request
	emt	375

	.close	#CLCTRL			;close the channel
	.close	#CLIUNT			;close the channel
	.close	#CLOUNT			;close the channel

	rts	pc


	.psect	c$data

clabt:	.byte	CLCTRL,32		;.spfun for CLABRT
	.word	0
	.word	0
	.word	0
	.byte	377,CLABRT
	.word	0


	.page
	.sbttl	CL Input a String

	;	bytes = sl_gets(buffer, maxbytes);

	.psect	c$code

sl.gets::
	jsr	r5,csv$
	clr	-(sp)			;null character count

	clr	slbyts
	mov	#slgcnt,r0		;any pending characters ?
	emt	375

	mov	slbyts,r2		;if no characters - finished
	beq	2$

	mov	c$pmtr(r5),slbufr	;buffer address
	mov	c$pmtr+2(r5),r1		;buffer length
	beq	2$			;bad argument (=0)

	cmp	r1,r2			;select smallest of
	blos	1$			;slbyts or maxbytes
	mov	r2,r1
1$:	mov	r1,slbyts		;characters to read
	mov	r1,(sp)			;characters returned

	mov	#slgstr,r0		;place characters in buffer
	emt	375

	clr	ticks			;character received

2$:	mov	(sp)+,r0		;return a NULL / CHARACTER COUNT
	rts	pc


slgcnt:	.byte	CLIUNT,32		;.spfun for CLIPND
	.word	0
	.word	slbyts
	.word	0
	.byte	377,CLIPND
	.word	0

slgstr:	.byte	CLIUNT,32		;.spfun for CLRBYT
	.word	1
slbufr:	.word	0
slbyts:	.word	0
	.byte	377,CLRBYT
	.word	0

	.page
	.sbttl	CL Input Timeout

	.psect	c$code

$mrkto:	add	$mrktm,ticks		;update ticks
	cmp	#60.*60.,ticks		;line timeout ?
	bhi	1$			;no - skip
	clr	ticks			;yes - clear ticks
	mov	#clrhnd,r0		;yes - clear XOFF / send XON
	emt	375
1$:	mov	#$mrkta,r0		;set up next time interrupt
	emt	375			;.mrkt request
	rts	pc

	.psect	c$data

ticks:	.word	0			;clock ticks

clrhnd:	.byte	CLCTRL,32		;.spfun for CLRXNF
	.word	0
	.word	0
	.word	0
	.byte	377,CLRXNF
	.word	0

$mrkta:	.byte	0,22			;.mrkt emt
	.word	1$			;time to wait address
	.word	$mrkto			;entry point
	.word	3			;id = 3

1$:	.word	0
$mrktm:	.word	60			;1 second

$cmkta:	.byte	0,23			;.cmkt
	.word	3			;id = 3
	.word	0

	.page
	.sbttl	CL Output

	.psect	c$code

sl.putc::
	tst	oupact			;active ?
	bne	1$			;yes - exit

	mov	#1,oupact		;active
	movb	arg1(sp),chroup		;place character
	mov	#clpchr,r0		;send character
	emt	375

	mov	arg1(sp),r0		;character
	rts	pc

1$:	mov	#-1,r0			;EOF
	rts	pc

cloupc:	clr	oupact			;finished
	rts	pc


	.psect	c$data

oupact:	.word	0			;active flag

clpchr:	.byte	CLOUNT,32		;.spfun for CLWBYT
	.word	1
	.word	chroup
clocnt:	.word	1
	.byte	377,CLWBYT
	.word	cloupc

chroup:	.word	0			;output character
.endc


.if ne rt$sys			;rt-11 specific

	.sbttl	MultiTerminal Unit Initialization

	.psect	c$code

sl.init::
	mov	#-1,-(sp)		;error return

	mov	arg1+2(sp),r0		;get unit number
	cmp	r0,#7
	bhi	1$

	movb	r0,mtatch+4		;set unit numbers
	movb	r0,mtget+4
	movb	r0,mtset+4
	movb	r0,mtrcto+4
	movb	r0,mtdtch+4
	movb	r0,mtin+4
	movb	r0,mtout+4
	movb	r0,mtxon+4
	movb	r0,mtxoff+4

	mov	#mtatch,r0		;.mtatch
	emt	375
	bcs	1$

	mov	#mtget,r0		;.mtget
	emt	375
	bcs	1$

	bis	#150305,m.tsts		;100000 (15) use backspace for rubout
	bic	#020072,m.tsts		;040000 (14) lower to upper disabled
					;020000 (13) terminal is remote
					;010000 (12) character mode input
					;007400 (11-8) terminal line speed
					;000200 (7) enable ^S - ^Q processing
					;000100 (6) inhibit TT wait
					;000010 (3) process ^X, ^F and ^B
					;000004 (2) Terminal has form feed
					;000002 (1) output RET/LF on too wide
					;000001 (0) terminal has tab

	bis	#100200,m.tst2		;100000 (15) write all
					;077400 (14-8) reserved
					;000200 (7) read all
					;000140 (6-5) reserved
					;000020 (4) DZ, odd parity
					;000010 (3) DZ, enable parity
					;000004 (2) DZ, 2 stop bits
					;000003 (1-0) DZ, 5(00), 6(01),
					;	char bits 7(10), 8(11)

;		m.tstw ---		;100000 (15) Acting console
					;040000 (14) double ^C struck
					;020000 (13) read all
					;010000 (12) DZ11
					;004000 (11) terminal has hung
					;002000 (10) terminal is shared

	mov	#mtset,r0		;.mtset
	emt	375
	bcs	1$

	mov	#mtrcto,r0		;.mtrcto
	emt	375
	bcs	1$

	jsr	pc,$mrkti		;.mtin

	clr	(sp)

1$:	mov	(sp)+,r0
	rts	pc


	.psect	c$data

mtatch:	.byte	5,37			;attach a terminal unit
	.word	m.asts			;address of asynchronous status word
	.word	0			;unit

mtget:	.byte	1,37			;get status of terminal unit
	.word	m.tsts
	.word	0			;unit

mtset:	.byte	0,37			;set status of terminal unit
	.word	m.tsts
	.word	0			;unit

mtrcto:	.byte	4,37			;get status of terminal unit
	.word	0
	.word	0			;unit

m.asts:	.word	040000			;asynchronous terminal status
					;If the asynchronous terminal
					;status is not included during
					;system generation then this
					;bit always stays SET
m.tsts:	.word	0			;terminal configuration word 1
m.tst2:	.word	0			;terminal configuration word 2
m.tfil:	.byte	0			;character requiring fillers
m.fcnt:	.byte	0			;number of fillers
m.twid:	.byte	0			;carriage width
m.tstw:	.byte	0			;terminal status byte


	.sbttl	MultiTerminal Unit Abort I/O

	.psect	c$code

sl.abort::
	mov	#mtdtch,r0		;abort i/o
	emt	375

	mov	#$cmkta,r0		;abort .mrkt request
	emt	375

	rts	pc


	.psect	c$data

mtdtch:	.byte	6,37			;.mtdtch
	.word	0
	.word	0			;unit


	.page
	.sbttl	MultiTerminal Input a String

	;	bytes = sl_gets(buffer, maxbytes);

	.psect	c$code

sl.gets::
	jsr	r5,csv$
	clr	r0			;null character count

	mov	c$pmtr(r5),r3		;buffer address
	mov	c$pmtr+2(r5),r2		;character count
	beq	3$

	mov	outptr,r1
1$:	cmp	r1,inptr		;characters available ?
	beq	2$

	movb	getbuf(r1),(r3)+	;take character
	incb	r1			;MOD 256.
	mov	r1,outptr		;save index
	sob	r2,1$

2$:	mov	c$pmtr+2(r5),r0		;compute number of
	sub	r2,r0			;characters returned
	beq	3$
	clr	ticks			;characters received

3$:	rts	pc			;return a NULL / CHARACTER COUNT


	.page
	.sbttl	Asynchronous MultiTerminal Character Processing

	.psect	c$code

$mrkte:	jsr	pc,mtchar		;check for characters

	mov	inptr,r1		;compute characters in buffer
	sub	outptr,r1
	bic	#^C377,r1		;MOD 256.
	bne	2$

	cmp	#60.*60.,ticks		;line timeout ?
	blos	1$			;XON at timeout

	tst	xoffed			;XON at empty buffer
	beq	2$
1$:	mov	#mtxon,r0
	emt	375
	bcs	2$
	clr	xoffed
	clr	ticks

2$:	cmp	r1,#192.
	blt	$mrkti

	tst	xoffed			;XOFF at almost full buffer
	bne	3$
	mov	#mtxoff,r0
	emt	375
	bcs	3$
	inc	xoffed

3$:	jsr	pc,resume		;incoming characters

$mrkti:	mov	#$mrkta,r0		;set up next time interrupt
	emt	375			;.mrkt request
	rts	pc

mtchar:	add	$mrktm,ticks		;clock ticks

	jsr	pc,1$
	beq	5$

	clr	ticks			;clear timeout ticks

1$:	clr	-(sp)			;no characters

	bit	#40000,m.asts		;characters available ?
	beq	4$			;no - exit

	mov	#255.,r1		;limit
	mov	inptr,r0		;compute characters in buffer
	sub	outptr,r0
	bic	#^C377,r0		;MOD 256.
	sub	r0,r1			;space available
	beq	4$

	mov	#256.,r0		;space to end of buffer
	sub	inptr,r0

	cmp	r1,r0			;use smaller
	ble	2$
	mov	r0,r1

2$:	mov	#mtin,r0		;.mtin
	movb	r1,5(r0)		;character count
	mov	#getbuf,r1		;buffer address
	add	inptr,r1
	mov	r1,2(r0)
	emt	375
	bcc	3$
	tstb	@#52			;assume error is data not available
	bne	4$			;real error

3$:	mov	r0,(sp)			;compute number of
	sub	r1,(sp)			;characters returned
	beq	4$

	mov	(sp),r0
	add	inptr,r0		;update index
	movb	r0,inptr		;MOD 256.

4$:	mov	(sp)+,r0		;return a NULL / CHARACTER COUNT

5$:	rts	pc


	.psect	c$data

$cmkta:	.byte	0,23			;.cmkt
	.word	3			;id = 3
	.word	0

$mrkta:	.byte	0,22			;.mrkt emt
	.word	1$			;time to wait address
	.word	$mrkte			;entry point
	.word	3			;id = 3

1$:	.word	0
$mrktm:	.word	3			;1/20 th of a second

mtin:	.byte	2,37			;.mtin
	.word	0
	.byte	0,0

mtxon:	.byte	3,37			;.mtout	xon
	.word	1$
	.byte	0,1

1$:	.word	21			;XON

mtxoff:	.byte	3,37			;.mtout	xoff
	.word	1$
	.byte	0,1

1$:	.word	23			;XOFF

xoffed:	.word	0			;xoffed flag

ticks:	.word	0			;elapsed ticks

outptr:	.word	0			;output index
inptr:	.word	0			;input  index

getbuf:	.blkb	256.			;buffer area

	.page
	.sbttl	MultiTerminal Output

	.psect	c$code

sl.putc::
	mov	#-1,r1			;EOF

	movb	arg1(sp),chroup		;place character
	mov	#mtout,r0		;send character
	emt	375
	bcs	1$
	mov	chroup,r1

1$:	mov	r1,r0			;character / EOF
	rts	pc


	.psect	c$data

mtout:	.byte	3,37			;.mtout
	.word	chroup
	.byte	0,1

chroup:	.word	0			;character
.endc

	.end
