	.title	k11rtt	mt terminal service for Kermit-11/RT
	.ident	/1.0.01/

;	28-May-84  09:06:31  Brian Nelson
;
;	Copyright (C) 1984 Change Software, Inc.





	.if ndf, K11INC
	.ift
	.include	/IN:K11MAC.MAC/
	.endc

	.psect
	.sbttl	definitions for multiple terminal support

	.mcall	.mtstat	,.mtatch,.mtdtch,.mtget	,.mtin
	.mcall	.mtout	,.mtprnt,.mtrcto,.mtset
	.mcall	.mrkt	,.cmkt	,.twait	,.ttinr
	.enabl	gbl

	m.tsts	=	0		; terminal status word
	m.tst2	=	2		; terminal status word number 2
	m.tfil	=	4		; character requiring fill
	m.fcnt	=	5		; number of fillers
	m.twid	=	6		; width
	m.tstw	=	7		; terminal status byte
	m.nlun	=	4		; number of terminals for .mtstat


	.macro	$mterr			; map multiple terminal service
	movb	@#errbyt,r0		; into a global error code
	asl	r0			; simple to do
	mov	mterr(r0),r0		; thats all there is to it
	.endm	$mterr


	.save
	.psect	mtmap	,rw,d,lcl,rel,con

lunmap:	.blkw	12			; map LUNS to RT units
mtsts:	.blkw	10			; from the .mtstat call
ttsts:	.blkw	10			; for ttyini
tmowrk:	.blkw	10			; for mark time while reading
ttsave:	.blkw	4
ttctlc:	.blkw	1			; for control C things in connect mode
ttime:	.word	0,1			; a tick sleep for .twait
	.restore





	.sbttl	assign the terminal unit



m.assdev::
	save	<r1>			; we may want to use these
	.mtstat	#rtwork	,#mtsts		; get terminal driver status
	bcs	90$			; oops
	tst	mtsts+m.nlun		; any multi tty support in exec?
	beq	80$			; no, thats fatal
	call	ttpars			; parse the device unit number
	bcs	70$			; bad device name
	mov	r0	,r1		; save the unit number now
	.mtatch	#rtwork,#kbiost,r1	; try to attach the terminal now
	bcs	90$			; fatal error, exit
	clr	r0			; ok, exit with success
	br	100$			; bye

70$:	mov	#er$dev	,r0		; return bad device name error
	br	100$			; bye
80$:	mov	#er$sup	,r0		; return missing support error
	br	100$			; bye
90$:	$mterr				; map local error into global error
100$:	unsave	<r1>			; pop local registers and exit
	return


m.deadev::
	save	<r1>			; save this one, folks
	call	ttpars			; parse the device name
	bcs	70$			; oops
	mov	r0	,r1		; save the unit number now
	.mtdtch	#rtwork,r1		; do it
	clr	r0			; success
	br	100$			; bye

70$:	mov	#er$dev	,r0		; bad device name error
	br	100$			; bye
100$:	unsave	<r1>			; exit
	return				; dh

	.sbttl	initialize the terminal


;	T T Y I N I
;
;	input:	@r5	device name
;		2(r5)	LUN
;		4(r5)	modifiers
;
;	output:	r0	error code
	ttmode	=	100 ! 10000 ! 40000

m.ttyini::
	save	<r1,r2>			; we will need this one
	call	ttpars			; get the unit number
	bcs	70$			; oops, return ER$DEV error
	mov	2(r5)	,r1		; get the internal LUN to use
	asl	r1			; into a word offset
	mov	r0	,lunmap(r1)	; so we can map lun into a unit
	movb	#377	,lunmap+1(r1)	; say we have done this already
	mov	r0	,r1		; save the unit number please
	.mtatch	#rtwork,#kbiost,r1	; ensure it's attached
	mov	#ttsts	,r2		; point to the status area
	.mtget	#rtwork,r2,r1		; get the current terminal setting
	bcs	90$			; oops
	bic	#2	,m.tsts(r2)	; no automatic cr/lf's please
	bis	#ttmode	,m.tsts(r2)	; no lower case convert, no echo
	bis	#200!100000,m.tst2(r2)	; read and write pass all please
	.mtset	#rtwork,r2,r1		; set these please
	bcs	90$			; oops
	mov	#1000	,r2
10$:	calls	binrea	,<2(r5),#-1>	; eat anything that's pending please
	dec	r2			; don't loop forever please
	beq	20$			; exit the loop
	tst	r0			; did we get anything at all ?
	beq	10$			; yes, eat some more input
20$:	clr	r0			; all done
	br	100$			; bye

70$:	mov	#er$dev	,r0		; device name parse failed
	br	100$			; bye

90$:	$mterr				; map local error into a global one
100$:	unsave	<r2,r1>			; pop and exit
	return




	.sbttl	save/restore terminal settings


m.ttysav::
	save	<r1>			; we will use this one
	call	ttpars			; parse the unit number please
	bcs	80$			; oops
	mov	r0	,r1		; copy the parsed unit number
	.mtget	#rtwork,#ttparm,r1	; get the current settings
	bcs	90$			; error
	clr	r0			; success
	br	100$			; bye

80$:	mov	#er$dev	,r0		; bad device name
	br	100$			; bye
90$:	$mterr				; error, map into global and exit
100$:	unsave	<r1>			; pop this and exit
	return



m.ttyrst::
	save	<r1,r2>			; we will use this one
	clr	r2			; was already attached
	call	ttpars			; parse the unit number please
	bcs	80$			; oops
	mov	r0	,r1		; copy the parsed unit number
	.mtset	#rtwork,#ttparm,r1	; get the current settings
	bcc	20$			; it worked
	cmpb	@#errbyt,#1		; not attached?
	bne	90$			; no
	.mtatch	#rtwork,#0,r1		; yes, attach it
	bcs	90$			; oops
	mov	sp	,r2		; flag we just attached it
	.mtset	#rtwork,#ttparm,r1	; get the current settings
	bcs	90$			; error
20$:	clr	r0			; success
	br	100$			; bye

80$:	mov	#er$dev	,r0		; bad device name
	br	100$			; bye
90$:	$mterr				; error, map into global and exit
100$:	tst	r2			; need to detach it again
	beq	110$			; no
	.mtdtch	#rtwork,r1		; yes, do it please
110$:	unsave	<r2,r1>			; pop this and exit
	return




	.sbttl	binrea	read binary


;	B I N R E A
;
;	input:	@r5	LUN
;		2(r5)	timeout
;	output:	r0	error code
;		r1	character just read


m.xbinre::
m.binrea::
	save	<r2,r3,r4>		; we may want to use these here
	clr	-(sp)			; allocate a single character buffer
	mov	sp	,r4		; and a pointer to it also
	clr	-(sp)			; allocate a mark time tim buffer
	clr	-(sp)			; simple
	mov	sp	,r2		; and point to it
	mov	@r5	,r3		; get the LUN
	asl	r3			; and map it into the unit number
	movb	lunmap(r3),r3		; simple
;-	.mtget	#rtwork,#ttsts,r3	; get current terminal setting
;-	bcs	90$			; oops
;-	bis	#ttmode	,ttsts+m.tsts	; set so we don't wait for anything
;-	.mtset	#rtwork,#ttsts,r3	; set this please
;-	bcs	90$			; can't set it for some reason
	cmp	2(r5)	,#-1		; read without any wait ?
	bne	40$			; no

	.mtin	#rtwork,r4,r3,#1	; read a single character now
	bcs	80$			; it worked
	clr	r1			; get the character into r1 now
	bisb	@r4	,r1		; and exit with success
	clr	r0			; bye
	br	100$			; exit at last


40$:	mov	2(r5)	,r1		; get the timeout in seconds
	mul	#60.	,r1		; into ticks now
50$:	.mtin	#rtwork,r4,r3,#1	; do it please
	bcc	60$			; it worked, get the ch into r1
	dec	r1			; been here too long ?
	beq	80$			; yes, exit with error
	tst	clkflg			; /37/ is there a clock on system?
	bne	55$			; /37/ yes
	cpuwait	#1			; /37/ no, try loop for one tick
	br	56$			; /37/ very cpu speed dependent.
55$:	.twait	#rtwork,#ttime		; sleep a moment please
56$:	br	50$			; and try again please

60$:	clr	r1			; it worked, get the character and exit
	bisb	@r4	,r1		; simple
	clr	r0			; success
	br	100$

80$:	mov	#er$nin	,r0		; no data today
	br	100$			; bye

90$:	$mterr				; map the error code into a global one

100$:	add	#6	,sp		; pop local buffers
	unsave	<r4,r3,r2>		; pop registers and exit
	return


200$:	mov	#1	,r1		; flag a timeout
	return





	.sbttl	binary write



;	B I N W R I
;
;	binwri( %loc buffer, %val buffer_size, %val lun )
;
;	output:	r0	error code
;
;	Assumption:	TTYINI has been called to map the Kermit LUN
;			into the RT11 unit number for the terminal.




m.binwri::
	save	<r1,r2,r3,r4,r5>	; save registers we may need
	sub	#20	,sp		; a save area for tt settings
	clr	r0			; preset no errors as of yet
	mov	@r5	,r1		; get the string address
	mov	2(r5)	,r2		; get the string length
	beq	100$			; nothing to do
	mov	#ttsts	,r3		; for getting tt settings
	mov	4(r5)	,r4		; the internal LUN
	bne	10$			; map LUN 0 to console
	print	r1,r2			; simple
	clr	r0			; no errors
	br	100$			; exit

10$:	mov	sp	,r5		; point to the stack work area
	asl	r4			; times two	
	tstb	lunmap+1(r4)		; have we mapped the lun into unit?
	beq	80$			; no, fatal error
	movb	lunmap(r4),r4		; map into the rt11 unit number
	.mtget	#rtwork,r3,r4		; get current settings, set to wait
	bcs	90$			; oops, exit with the error code in r0
	mov	(r3)+	,(r5)+		; copy the four words now
	mov	(r3)+	,(r5)+		; copy the four words now
	mov	(r3)+	,(r5)+		; copy the four words now
	mov	(r3)+	,(r5)+		; copy the four words now
	bit	#100	,ttsts+m.tsts	; is the wait bit set already ?
	beq	20$			; no, don't bother to clear it
	bic	#100	,ttsts+m.tsts	; set so we will wait for buffer space
	.mtset	#rtwork,#ttsts,r4	; simple to set
20$:	.mtout	#rtwork,r1,r4,r2	; do the output now
	bcs	90$			; oops, it failed for whatever reason
	mov	-(r5)	,-(r3)		; restore the terminal settings
	mov	-(r5)	,-(r3)		; restore the terminal settings
	mov	-(r5)	,-(r3)		; restore the terminal settings
	mov	-(r5)	,-(r3)		; restore the terminal settings
	.mtset	#rtwork,r3,r4		; simple
	clr	r0			; say it worked and exit
	br	100$			; bye

80$:	mov	#er$map	,r0		; rt11 unit not mapped to internal LUN
	br	100$			; bye
90$:	$mterr				; map mt error into global error code

100$:	add	#20	,sp		; pop local work buffer
	unsave	<r5,r4,r3,r2,r1>	; pop the saved registers
	return				; and exit




	.sbttl	parse terminal unit


;	T T P A R S
;
;	input:	@r5	address of RT11 Multiple terminal service unit string
;	output:	r0	unit in binary


m.ttpars::
	mov	r1	,-(sp)		; save scratch register please
	mov	@r5	,r0		; get the address of the string
	call	200$			; check for legit character
	bcs	110$			; oops
	movb	(r0)+	,r1		; get the first byte please
	sub	#'0	,r1		; convert to binary
	call	200$			; check for legit character
	bcs	110$			; oops
	movb	@r0	,r0		; get the next digit
	beq	100$			; nothing there then we are done
	mul	#12	,r1		; something there, shift over by 10
	sub	#'0	,r0		; and convert low digit to binary
	add	r0	,r1		; add into the accumulator
100$:	mov	r1	,r0		; and return the result
	clc				; return success
110$:	mov	(sp)+	,r1
	return


200$:	tstb	@r0			; null ?
	beq	210$			; yes, it's ok
	cmpb	@r0	,#'0		; must only be digits today
	blo	220$			; oops
	cmpb	@r0	,#'9		; 0..9
	bhi	220$			; bad device name
210$:	clc				; device name ok so far
	return				; bye
220$:	sec				; bad, set and exit
	return


	.sbttl	GTTNAM	get MT unit of current console (set tt:consol=nn)

;	G T T N A M
;
;	input:	@r5	address of console name to be written
;	output:	@r5	current console name
;		consave	same thing

	.mcall	.mtstat

;	data returned by .mtstat
;
;	offset	0	offset from RMON base to first TCB
;		2	offset from RMON base to the current console TCB
;		4	numer of luns generated into the exec
;		6	size of the TCB in bytes
;
;	Since the TCB does NOT contain a copy of the LUN in it, we have
;	to start with TCB number 0 and add in the TCB size until we get
;	the value of the offset to the current console's TCB.  Counting
;	this will give us the LUN for that TCB.

m.gttnam::
	save	<r1,r2,r3>		; save registers please
	.mtstat	#rtwork,#mtsts		; get info on mt service
	clr	r3			; current lun number, starts with zero
	tst	mtsts+4			; see if mt service is present?
	beq	30$			; no, ignore it for now
	mov	mtsts+0	,r1		; offset to tcb for console interface
	mov	mtsts+4	,r2		; number of tcb's generated in exec
10$:	cmp	r1	,mtsts+2	; find our tcb yet?
	beq	20$			; yes, exit
	inc	r3			; no, then lun := succ(lun)
	add	mtsts+6	,r1		; add the tcb size in and compage offset
	dec	r2			; if more tcbs to do, then try again
	bne	10$			; next please
20$:
30$:	asl	r3			; get word indexing please to map the
	add	#200$	,r3		; value into a ascii string.
	mov	@r5	,r1		; where to put it please
	movb	(r3)+	,@r1		; copy a byte
	cmpb	@r1	,#40		; but if it's a blank, then skip it
	beq	40$			; a space
	inc	r1			; not a space, bump the dest pointer
40$:	movb	(r3)+	,(r1)+		; copy the next character now
	clrb	@r1			; always make it .asciz
	mov	@r5	,r1		; copy to consave:
	mov	#consave,r2		;
50$:	movb	(r1)+	,(r2)+		; simple to copy .asciz string
	bne	50$			; next please
100$:	clr	r0
	unsave	<r3,r2,r1>
	return


;	This is a rather dumb way to convert to ascii, but there are only
;	a few values,  and it is easier to test via downloading to my PDT
;	with Kermit since the PDT150 lacks DIV.

200$:	.asciz	/ 0 1 2 3 4 5 6 7 8 9/
	.asciz	/101112131415161718/
	.even

	global	<consave>



m.ttyfin::
	call	ttpars			; finish up mt service
	mov	r0	,r1		; parse the device name
	.mtdtch	#rtwork,r1		; and detach the device now
	clr	r0			; return 'success'
	return				; and exit



	.sbttl	speed read and change

m.setspd::
	save	<r1,r2,r3>		; save temps that we will use
	clr	r0			; find the speed map now
10$:	tst	spdlst(r0)		; reach the end of the table?
	beq	80$			; yes, return unknown speed
	cmp	2(r5)	,spdlst(r0)	; table entry match the passed speed
	beq	20$			; yes
	add	#2	,r0		; no, try the next one please
	br	10$			; next please
20$:	mov	spdmap(r0),r3		; and get the speed setting bits
	call	ttpars			; parse the mt unit number
	bcs	70$			; oops
	mov	r0	,r1		; save the unit number
	.mtatch	#rtwork,#kbiost,r1	; insure unit is attached
	mov	#ttsts	,r2		; point to the status area
	.mtget	#rtwork,r2,r1		; get the current terminal setting
	bcs	90$			; oops
	bic	#7400	,m.tsts(r2)	; clear out old speed bits
	bis	r3	,m.tsts(r2)	; stuff the dz11 speed bits in
	.mtset	#rtwork,r2,r1		; set these please
	bcs	90$			; oops
	clr	r0			; all done
	br	100$			; bye

70$:	mov	#er$dev	,r0		; device name parse failed
	br	100$			; bye

80$:	mov	#er$spe	,r0		; unknown speed ?
	br	100$

90$:	$mterr				; map local error into a global one
100$:	unsave	<r3,r2,r1>		; pop and exit
	return


m.ttspee::
	save	<r1,r2,r3>		; save these please
	call	ttpars			; parse the mt unit number
	bcs	70$			; oops
	mov	r0	,r1		; save the unit number
	.mtatch	#rtwork,#kbiost,r1	; insure unit is attached
	mov	#ttsts	,r2		; point to the status area
	.mtget	#rtwork,r2,r1		; get the current terminal setting
	bcs	90$			; oops
	mov	m.tsts(r2),r3		; get the speed mask out now
	bic	#^C7400	,r3		; drop all bits but the speed
	clr	r0			; now look for the correct speed map
10$:	tst	spdmap(r0)		; reach the end of the list ?
	bmi	80$			; yes, return a speed of zero
	cmp	r3	,spdmap(r0)	; setting match up now ?
	beq	20$			; yes
	add	#2	,r0		; no, try again please
	br	10$			; next
20$:	mov	spdlst(r0),r0		; a match, return the speed setting
	br	100$			; bye

70$:	mov	#er$dev	,r0		; device name parse failed
	br	100$			; bye

80$:	clr	r0			; failure
	br	100$			; return a speed of zero then

90$:	$mterr				; map local error into a global one
100$:	unsave	<r3,r2,r1>		; pop and exit
	return


	.save
	.psect	$pdata

spdlst:	.word	50.	,75.	,110.	,134.	,150.	,300.	,600.
	.word	1200.	,1800.	,2000.	,2400.	,3600.	,4800.	,7200.
	.word	9600.	,0	,0

spdmap:	.word	0	,400	,1000	,1400	,2000	,2400	,3000
	.word	3400	,4000	,4400	,5000	,5400	,6000	,6400
	.word	7000	,7400	,-1

	.restore



	.sbttl	terminal i/o things we don't need, can't do or haven't done yet

m.ttxon::
m.cantyp::
m.ttset::
m.ttydtr::
m.ttrfin::
m.ttrini::
	clr	r0
	return

m.ttyhan::
	mov	#er$iop	,r0
	return


	.mcall	.ttyin
	jsw	=	44

m.kbread::
	mov	r2	,-(sp)
	mov	r3	,-(sp)
	bis	#40000	,@#jsw		; enable lower case tt: input
	bic	#10000	,@#jsw		; ditch single ch input please
	mov	@r5	,r1		; a buffer to put the chars
	mov	#80.	,r3		; size of the buffer here
;10$:	.scca	#area	,#kmonbf	; so we can catch control Z
10$:	.ttyin				; read a character please
	tstb	r0
	beq	15$			; a null
	cmpb	r0	,#'Z&37		; control Z ?
	beq	20$			; yes
	cmpb	r0	,#'C&37		; control C ?
	beq	20$			; yep
	cmpb	r0	,#15		; carriage return ?
	beq	30$			; yep
	movb	r0	,(r1)+		; return what we just got
	cmpb	r0	,#14		; form feed ?
	beq	40$			; yep
15$:	sob	r3	,10$		; next please
20$:	mov	#er$eof	,r0		; say read error and exit
	br	100$			; bye
30$:	movb	#cr	,(r1)+		; return all terminators please
	movb	#lf	,(r1)+		; simple
	.ttyin				; eat the line feed now
40$:	clrb	@r1
	sub	@r5	,r1		; the length
	clr	r0
100$:	mov	(sp)+	,r3
	mov	(sp)+	,r2
	return




m.finrt::				; /37/
	clr	r0			; /37/
	return				; /37/

m.senbrk::
	calls	ttspee	,<@r5>		; get the remotes terminal speed
	mov	r0	,r2		; save the old speed
	calls	setspd	,<@r5,#50.,2(r5)>;try to set it down to 50 baud
	tst	r0			; did it work ?
	bne	100$			; no, forget it
	calls	binwri	,<#200$,#2,2(r5)>;yes, send a null over
	calls	setspd	,<@r5,r2,2(r5)>	; restore the terminal's speed
100$:	clr	r0
	return

200$:	.byte	0,0

	.end
