	.title	k11prt	pro/rt XC/XL interface
	.ident	/1.0.01/

;	13-Oct-84  11:02:39  Brian Nelson
;
;	6-May-85             Basically had to add in checks for xl and tsx
;                            and then roll in some of the code from k11tsx
;                            in order to properly use the cl lines under
;                            TSX.  (Ned W. Rhodes)
;
;	Copyright (C) 1984 Change Software, Inc.




;	NOTICE: !!!!!!
;
;	 To operate  properly with Kermits at high speed and with Kermits
;	not supporting xon/xoff flow control, the PRO/RT11 device handler
;	for XC: MUST be modified to increase the internal buffer size and
;	to  repress XON/XOFF  transmission within a packet.  This is very
;	easy to do.  In the file XL.MAC  from your PRO/RT kit, change the
;	line
;	from:		BUFSIZ	= 64.
;	to:		BUFSIZ	= 220.
;
;	and the line
;	from:		STPSIZ	= BUFSIZ/4
;	to:		STPSIZ	= BUFSIZ/2
;
;	 To recreate  XCX.SYS, first copy XC.MAC, XM.MAC, XL.MAC, XM.ANS
;	and SYSGEN.COM to DK: and then type  IND SYSGEN.  Tell it to use
;	the saved answer file  XM.ANS.  When SYSGEN exits,  it will have
;	created, among other files, a file called XM.CND which is needed
;	for the driver assembly.
;
;	Then:
;
;	assign dk: src:
;	copy xcx.sys xcx.old
; 	ren/nopro xcx.sys xcx.sys
;	unlo xc:
;	rem xc:
;	macro/obj:xcx (xm,xm.cnd,xc)
;	link/exe:xcx.sys xcx
;	ins xc:


	.include	/IN:K11MAC.MAC/
	.psect

	.mcall	.abtio	,.readw	,.writw	,.spfun	,.ttinr	,.ttyin	,.ttyou
	.mcall	.mrkt	,.cmkt	,.twait	,.writc
	.mcall	.lookup	,.dstat	,.fetch	,.close
	.mcall	.print	,.gval
	.enabl	gbl

	.psect	XCRW	,rw,d,lcl,rel,con
xcwork:	.blkw	12			; for asynch calls to the XC driver
second:	.word	0,60.			; wait a full second
tenth:	.word	0,6			; wait 1/10 second
break:	.word	0,17.			; for sending breaks, .283 seconds
wait:	.word	0,1			; wait one tick (1/60 second)
devnam:	.word	0,0,0,0,0,0,0,0,0,0,0,0	; save the device name
ttctlc:	.blkw	1			; for control C things in connect mode
xoffed:	.word	0			; flag that we xoffed the other kermit
xcpoint:.word	xcrdbf			; current pointer into XCRDBF
xcsize:	.word	0			; size of last XC read (not used)
xcdone:	.word	0			; read is complete
xcwdon:	.word	0			; writc is complete
xcwrbf:	.blkb	200			; for a write buffer ?
xcrdbf:	.blkb	102			; for a local read buffer, always asciz
xcrdsi	=	100			; size of XCRDBF

m.tsxs:	.byte	35,'S			; Single Character
	.BYTE	35,'W			; Tape mode on
	.BYTE	35,'U			; No wait
	.BYTE	35,'Y			; High efficiency
	.BYTE	35,'R
	.BYTE	0
	.even
m.tsxr:	.byte	35,'T			; Single character off
	.byte	35,'X			; Tape mode off
	.byte	35,'Z			; Line feed echo
	.byte	0
	.even
hieff:	.byte	0,120			; Turn hi eff off
xlset:	.word	1427			; Options to set
xlset2:	.word	40			; Options to reset

	.psect	$CODE

	ERRBYT	=	52
	JSW	=	44


;	.spfun	codes for the XC/XL driver

	CLRDRV	=	201		; undo xon, reset the driver
	BRKDRV	=	202		; wc=0, end break else break
	SRDDRV	=	203		; special read, wc is max # of bytes
					; to read, always returns at least one
					; byte, up to max if data is there.
	STSDRV	=	204		; driver status, high byte is driver
					; version, low byte is:
					; bit 0 = 1 if sent xoff to host
					; bit 1 = 1 if rec xoff from host
					; bit 2 = 1 if CTS is ok
	OFFDRV	=	205		; disable interupts at program exit

	DTRDRV	=	206		; rt 5.2, set/clear DTR. If WC <> 0
					; then turn it on else turn it off.
	
	CLSET	=	250		; Set cl options for TSX-Plus
	CLRSET	=	251		; Reset cl option for TSX-Plus

	XC.CONTROL = 	14		; channel for controlling the driver


	nobinary=	1		; if XC driver strips bit 7, set this

	.iif ndf, nobinary, nobinary = 1
	.iif ndf, XON	  , XON = 'Q&37
	.iif ndf, XOFF	  , XOFF= 'S&37


	.sbttl	assign and init the XC/XL port



x.ttysav::
x.ttyrst::
x.deadev::
x.assdev::
	tst	tsxcl			; Under tsx and using cl line?
	beq	100$			; Nope
	mov	#hieff,r0		; Get emt parameter block
	emt	375			; Turn off hi efficiency
	.print	#m.tsxr			; Reset some terminal parameters
100$:	clr	r0			; Success
	return				; not needed for PRO/RT




;	T T Y I N I
;
;	input:	@r5	device name
;		2(r5)	LUN
;		4(r5)	modifiers
;
;	output:	r0	error code


x.ttyini::
	save	<r1,r2>			; always save temps please
	mov	@r5	,r1		; get the device name address
	mov	2(r5)	,r0		; copy the device name please
	asl	r0			; lun times two please
	movb	(r1)	,devnam(r0)	; save it please
	movb	1(r1)	,devnam+1(r0)	; both ascii characters please
	clr	r0			; assume success
	tstb	@r1			; perhaps the console ?
	beq	100$			; yes, don't do anything
	cmpb	@r1	,#'T&137	; TT: ?
	beq	100$			; do nothing then
	cmpb	(r1)+	,#'X&137	; must be either XC or XL
	bne	90$			; neither, just exit then

	clr	xoffed			; reset 'sent an XOFF' flag
	mov	#xcrdbf	,xcpoint	; a pointer into the XC: buffer
	mov	#xcrdbf	,r2		; xc device, zero the buffer
	mov	#xcrdsi+2,r0		; the size of the buffer
5$:	clrb	(r2)+			; clear it out
	sob	r0	,5$		; next please

	mov	#XCNAME	,r2		; assume XC0:
	cmpb	@r1	,#'L&137	; but is it XL0: ?
	bne	10$			; no
	mov	#XLNAME	,r2		; yes
10$:	calls	fetch	,<@r2>		; get the device loaded ?
	tst	r0			; did it work ?
	bne	95$			; no
20$:	clr	xcdone			; nothing pending to read from XC:
	.lookup	#rtwork,2(r5),r2	; try to open the port up please
	bcs	60$			; oops
	.lookup	#rtwork,#XC.CONTROL,r2	; also open a control channel
	bcs	60$			; should never happen, of course
	.spfun	#rtwork,#XC.CONTROL,#CLRDRV,#0,#0,#0
	bcs	70$			; oops
	tst	#nobinary		; can we do binary i/o to XC: ?
	beq	30$			; yes
	cmpb	parity	,#par$no	; currently PARITY NONE ?
	bne	30$			; no
	movb	#par$sp	,parity		; set space parity to fake it
30$:	tst	tsxcl			; tsx and cl?
	beq	35$			; nope
	call	tsxopt			; do some special things for tsx
35$:	clr	r0			; all is well today
	br	100$			; exit with sucess



60$:	mov	#xcierr	,r0		; open error on X?0: device
	br	90$			; map it to a global error
70$:	mov	#xcspfun,r0		; .SPFUN error for X?0:
	br	90$			; map it to a global error

90$:	clr	r1			; now map to the global error code
	movb	@#ERRBYT,r1		; get RT11's error code
	asl	r1			; times 2 for word indexing
	add	r0	,r1		; point to the global error code
	mov	@r1	,r0		; and get it
95$:	mov	2(r5)	,r1		; clear the saved device name
	asl	r1			; times two please
	clr	devnam(r1)		; simple
100$:	unsave	<r2,r1>			; pop scratch registers and exit
	return				; bye

tsxopt:	.gval	#rtwork,#-4		; get tsx leadin
	movb	r0,m.tsxr		; set in place
	movb	r0,m.tsxr+2		; set in place
	movb	r0,m.tsxr+4		; set in place
	movb	r0,m.tsxs		; set in place
	movb	r0,m.tsxs+2		; set in place
	movb	r0,m.tsxs+4		; set in place
	movb	r0,m.tsxs+6		; set in place
	movb	r0,m.tsxs+8.		; set in place
	.print	#m.tsxs			; set the options
	.spfun	#rtwork,#xc.control,#clset,#xlset,#1,#0
					; set some cl options
	.spfun	#rtwork,#xc.control,#clrset,#xlset2,#1,#0
					; reset some cl options
	bis	#40000!10000!100,@#JSW	; lower case, no wait, and special
	return				; back to caller

x.ttyfin::
	save	<r1>			; save temps please
	clr	wasxc			; was not xc/xl and pure RT
	mov	2(r5)	,r1		; get the internal lun
	asl	r1			; map it
	cmpb	devname(r1),#'X		; see if the device was X?:
	bne	10$			; no, then do nothing
	call	clrxc			; reset the driver
	tst	tsxcl			; tsx and cl?
	bne	5$			; yes
	mov	sp	,wasxc		; flag for .exit that this was XC/XL
5$:	.spfun	#rtwork,#XC.CONTROL,#OFFDRV,#0,#0,#1 ;disable interupts at exit
	.abtio	2(r5)			; try to stop all i/o please
	.close	2(r5)			; yes, was XC/XL, thus close it
	.close	#XC.CONTROL		; and close the controller port
	clr	xcwdone			; nothing as far as writes either
	clr	xcdone			; nothing pending to read from XC:
	mov	#xcrdbf	,xcpoint	; reset the pointer to the buffer
	clrb	@xcpoint		; stuff a null in please
10$:	clr	devnam(r1)		; no device active now
	clr	r0			; no error are possible
	unsave	<r1>			; pop temp and exit
	return				; bye


	.save
	.psect	XCDATA	,rw,d,lcl,rel,con
XCNAME:	.rad50	/XC /
	.rad50	/   /
	.rad50	/   /
	.rad50	/   /
XLNAME:	.rad50	/XL /
	.rad50	/   /
	.rad50	/   /
	.rad50	/   /
	.restore



	.mcall	.scca

x.contrp::
	clr	ttctlc
	.scca	#rtwork	,#ttctlc
	return

x.conrst::
	.scca	#rtwork	,#0
	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
;
;	To avoid rewriting the terminal emulation code, the case
;	where we get passed a timeout of -1 is used to do a  qio
;	to the XC port and then subsequent calls simply check to
;	see if it completed. If so, get whats in the buffer.  If
;	it's not done, exit and check  next time.  This  is only
;	done from the connect code,  so perhaps later I will get
;	around to rewriting it.
;
;	For the normal Kermit timed packet read, we post the qio
;	and loop waiting for it to complete. If it does not com-
;	plete  within the specified time, we cancel  the i/o and
;	reset the driver.
;	For proper operation, the XC driver must be modified  as
;	described at the beginning of the file.


x.xbinre::
x.binrea::
	save	<r2,r3,r4>		; we may want to use these here
	mov	@r5	,r2		; get the lun to use
	asl	r2			; if TT: then do it different
	cmpb	devnam(r2),#'X&137	; XC: ?
	beq	10$			; yes (or at least assume so)
	call	ttread			; yes, get from the console tt
	br	100$			; bye

10$:	cmp	xcpoint	,#xcrdbf+xcrdsi	; insure no buffer overflows
	bhis	20$			; gone too far, XC driver is %$#@!
	tstb	@xcpoint		; anything left in the readbuffer?
	bne	30$			; no
20$:	mov	#xcrdbf	,xcpoint	; reset the pointer to the buffer
	clrb	@xcpoint		; stuff a null in please
	call	xxread			; load the buffer with as much as can
	tst	r0			; did this read succeed ?
	bne	100$			; no
30$:	clr	r1			; avoid sxt even if the fubar XC
	bisb	@xcpoint,r1		; driver always drops bit 7 (future?)
	inc	xcpoint			; point to the next one in the buffer
	clr	r0			; insure success and exit

100$:	unsave	<r4,r3,r2>
	return


xxread:	mov	2(r5)	,r3		; timeout in seconds here
	bne	10$			;
	inc	r3			; convert nothing to one second
10$:	cmp	r3	,#-1		; no wait ?
	beq	15$			; yes
	mul	#60.	,r3		; no, convert time to ticks then
	br	20$			; and check on the i/o status
15$:	mov	#1	,r3		; no wait (really, one tick)

20$:	tst	xcdone			; no timout, last read ever finish?
	bmi	30$			; no, keep waiting then
	mov	#-1	,xcdone		; read without waiting for it
	.spfun	#xcwork,@r5,#SRDDRV,#xcrdbf,#xcrdsi,#1,#200$

30$:	tst	xcdone			; return that fast (?)
	bgt	40$			; yes
	.twait	#rtwork,#wait		; no, sleep for 1/60 second
	sob	r3	,30$		; and see if we should keep waiting
	tst	xcdone			; got it from the XC buffer now?
	bmi	50$			; no, return no data and exit

40$:	clr	r1			; all done, get character and exit
	bisb	xcrdbf	,r1		; and set the error code to zero
	clr	xcdone			; que a new read next time called
	clr	r0			; in r0
	br	100$			; bye

50$:	cmp	2(r5)	,#-1		; no xon's if we are looping no tmo
	beq	60$			;
	call	clrxc			; insure interupts are ok, also XON
60$:	mov	#ER$NIN	,r0		; no data has come it yet
	br	100$			; exit

100$:	return


200$:	mov	#1	,xcdone		; flag a read completion and exit
	return				; so we will break the .twait loop




	.sbttl	raw i/o from the console TT


ttread:	bis	#40000!10000!100,@#JSW	; lower case, no wait
	cmp	2(r5)	,#-1		; read without any wait ?
	bne	10$			; no
	.ttinr				; one char from the console tt:
	bcs	80$			; it worked
	mov	r0	,r1		; and exit with success
	clr	r0			; bye
	br	100$			; exit at last

10$:	mov	2(r5)	,r1		; get the timeout in seconds
	mul	#60.	,r1		; into ticks now
20$:	.ttinr				; try a character from TT:
	bcc	30$			; it worked, get the ch into r1
	dec	r1			; been here too long ?
	beq	80$			; yes, exit with error
	.twait	#rtwork,#wait		; sleep a moment please
	br	20$			; and try again please

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

80$:	mov	#er$nin	,r0		; no data today
	clr	r1			; same here, return a null
100$:
	tst	tsxcl			; tsx and cl
	bne	101$			; yes
	bic	#40000!10000!100,@#JSW	; reset some tt options
101$:	return




	.sbttl	binary write



;	B I N W R I
;
;	binwri( %loc buffer, %val buffer_size, %val lun )
;
;	output:	r0	error code



x.binwri::
	save	<r1,r2,r3,r4>
	clr	r0			; presume no errors
	tst	2(r5)			; any i/o to do at all?
	beq	100$			; no
	mov	4(r5)	,r4		; check for TT: please
	asl	r4			; by indexing to DEVNAM:
	cmpb	devnam(r4),#'T&137	; TT: ?
	bne	20$			; no
	mov	@r5	,r4		; simple
	mov	2(r5)	,r2		; number of characters to write
15$:	.ttyout	(r4)+			; dump via .ttyou to avoid .print's
	sob	r2	,15$		; problems with 8bit characters please
	clr	r0			; and exit
	br	100$			; bye

20$:	mov	#-1	,xcwdone	; wait a while for completion
	mov	(r5)	,r3		; copy the data to a local buffer
	mov	#xcwrbf	,r2		; buffer = xcwritebuffer
	mov	2(r5)	,r4		; get the bytecount
	mov	r4	,r1		; save the byte count for later
25$:	movb	(r3)+	,(r2)+		; for (i=bytecount;i>0;i--)
	sob	r4	,25$		;   *buffer++ = *source++
	mov	r1	,r4		; restore  the byte count
	dec	r4			; if bytecount <> 1
	beq	40$			;  then
	cmpb	-(r3)	,#CR		;    if lastcharacter == CR
	bne	30$			;     then
	movb	#LF	,(r2)+		;       *bufffer++ = NULL
	inc	r1			;       bytecount++
30$:	clr	xoffed			;    xoffed = false ;
	tst	rtflow			;    if (needflowcontrol)
	beq	35$			;     then
	movb	#XOFF	,(r2)+		;      *buffer++ = XOFF
	inc	r1			;      bytecount++
	mov	sp	,xoffed		;      xoffed = true
35$:

40$:	clrb	@r2			; *buffer++ = NULL ;
	inc	r1			; bytecount++ 
	asr	r1			; bytecount = bytecount/2
	.writc	#xcwork,4(r5),#xcwrbf,r1,#200$,#1
	mov	#10.*60.,r3		; wait at most 10 seconds (?)

50$:	tst	xcwdone			; ast completion as of yet ?
	bne	60$			; yes
	.twait	#rtwork,#wait		; still not complete, wait a tick
	sob	r3	,50$		; and check again
	call	clrxc			; clear the driver out, send XON
	clr	r0
	br	100$			; exit

60$:	tst	r4			; was that a single character i/o?
	beq	70$			; yes
	tst	xoffed			; in case a virgin xcdriver, wait.
	beq	70$			; no, skip the wait and xon then.
	.twait	#rtwork,#tenth		; no, sleep for a moment please
	.twait	#rtwork,#tenth		; at 9600, we need this one also
	call	300$			; xon the other side please
70$:	clr	r0			; success
	clr	xcwdone			; reset the i/o in progress flag

100$:	unsave	<r4,r3,r2,r1>		; pop registers and exit
	return				; bye


200$:	mov	#1	,xcwdone	; flag ast level completion
	return				; and exit


300$:	tst	xoffed			; did we xoff the other side?
	beq	310$			; no
	.writc	#xcwork,4(r5),#320$,#1,#0,#1 ; synch i/o this time please
310$:	clr	xoffed			; say no xoff's anymore please
	return

320$:	.byte	XON,0


clrxc:	.spfun	#rtwork,#XC.CONTROL,#CLRDRV,#0,#0,#1 ; clear the driver
	return


	.sbttl	cantyp	try to dump all typeahead


x.cantyp::
	save	<r1,r2>			; save temps
	mov	#200	,r2		; loop for no more than 128 characters
	mov	#xcrdbf	,xcpoint	; reset the pointer to the buffer
	clrb	@xcpoint		; stuff a null in please
10$:	calls	binrea	,<2(r5),#-1>	; try to get something
	tst	r0			; did it work ?
	bne	20$			; no, exit
	sob	r2	,10$		; yes, eat somemore characters
20$:	.abtio	2(r5)			; try to reinit the driver and exit
	call	clrxc			; this also please
100$:	unsave	<r2,r1>			; pop temp and exit
	clr	r0
	return				; bye


x.ttxon::
	call	clrxc			; get the driver to clear xoff status
	return


x.senbrk::
	.spfun	#rtwork,#XC.CONTROL,#BRKDRV,#0,#1,#1
	.twait	#rtwork,#break
	.spfun	#rtwork,#XC.CONTROL,#BRKDRV,#0,#0,#1
	clr	r0
	return



	.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


x.ttpars::
	clr	r0			; always unit zero for PRO/RT
	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

x.gttnam::
	mov	@r5	,r0		; for PRO/RT, always return TT:
	movb	#'T&137	,@r0
	movb	(r0)+	,consave
	movb	#'T&137	,@r0
	movb	(r0)+	,consave+1
	movb	#':	,@r0
	movb	(r0)+	,consave+2
	clrb	@r0
	clrb	consave+3
	clr	r0
	return


	global	<consave>


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

x.setspd::
	mov	#377	,r0
	return


x.chkabo::
	bis	#40000!10000!100,@#JSW	; enable special input modes
	.ttinr				; check for ^z or ^x
	bcc	100$			; no
	clr	r0			; nothing, return a null
100$:	bic	#40000!10000!100,@#JSW	; restore special modes please
	return				; return( failure )


x.ttspee::
x.ttset::
x.ttrfin::
x.ttrini::
	clr	r0
	return

x.ttydtr::
x.ttyhan::
	mov	#er$iop	,r0
	return


	.mcall	.ttyin
	jsw	=	44

x.kbread::
	mov	r2	,-(sp)
	mov	r3	,-(sp)
	bis	#40000	,@#jsw		; enable lower case tt: input
	tst	tsxcl			; tsx and cl?
	beq	5$			; nope
	bic	#10000!100,@#jsw	; ditch single ch input and wait
	br	7$			; jump ahead

5$:	bic	#10000	,@#jsw		; ditch single ch input please

7$:	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



	.end
