	.enabl	lc
	.title	unx
	.nlist	bex
;
;
;	this program, when installed as ...unx, is used to
;	unload the LBL communication drivers which have the
;	perpetual timer to perform the self-cleansing
;	action required for their use.
;
;	usage:
;
;	unx xx:
;
;	where xx: is the device mnemonic.  A syntax error occurs if the
;	colon(:) is not found.
;
;	after retrieving the device mnemonic from the command line,
;	a lun is assigned to the device.  A qiow is made to the driver
;	with the function code IO.STP.  If the qiow is successful (the
;	requesting terminal must be priveleged), the timer will have been
;	stopped.  This task then spawns the following three MCR commands
;
;	device xx:
;	unload xx:
;	device xx:
;
	.mcall	gmcr$,dir$,alun$s,glun$s,spwn$s,stse$s,exit$s,qiow$s
;
;	local constants
;
ttylun=1	; lun for terminal io
devlun=2	; lun for device
qioefn=1	; event flag for qios
spnefn=2	; event flag for spawn
blank=40	; ASCII code for blank
cr=15		; ASCII code for carriage return
lf=12		; ASCII code for line feed
esc=33		; ASCII code for escape
;
;	local macros
;
	.macro	concat	a,b,c
	mov	#'c,r0
	mov	#'a,r1
	call	scopy
	mov	#'b,r1
	call	scopy
	.endm	concat
;
;
;	local impure storage
;
;
xx:	.blkb	2		; location for device mnemonic
gmcrpb:	gmcr$			; DPB for GMCR$
iosb:	.blkb	4		; io status block for qiow
numbuf:	.blkb	10.		; buffer for formatted numbers
tbuf:	.blkb	80.		; temporary buffer for formatted error msgs
outbuf:	.byte	cr,lf		; formatting buffer for error processor
obuf:	.blkb	132.		; remainder of buffer
devstr:	.ascii	"device "		; device command to spawn
devxx:	.blkb	2
	.ascii	":"
devlen=.-devstr
	.even
unlstr:	.ascii	"unload "		; unload command to spawn
unlxx:	.blkb	2
	.ascii	":"
unllen=.-unlstr
	.even
;
;
;	local pure storage
;
;
usemsg: .asciz	"Usage:  unx xx:"
lunmsg:	.asciz	"unx - error assigning lun to device; $dsw = "
qiomsg:	.asciz	"unx - error stopping timer; iosb(1) = "
spnmsg:	.asciz	"unx - error spawning process; $dsw = "
	.even
;
;	task name for spawn invocation
;
mcr:	.rad50	"MCR..."
;
;
;	start of unx code
;
;	first assign lun to TI: and get MCR command line
;
start:
	alun$s	#ttylun,#"TI,#0		; assign lun to TI:
	dir$	#gmcrpb			; get MCR command line
	mov	@#$dsw,r0		; place number of chars in r0
	ble	useerr			; if <= 0, error
	clrb	gmcrpb+g.mcrb(r0)	; terminate with 0 byte
	mov	#gmcrpb+g.mcrb,r0	; starting buffer address
10$:
	movb	(r0)+,r1		; get next character
	beq	useerr			; if == 0, syntax error
	cmpb	r1,#' 			; see if blank
	bne	10$			; if != BLANK, try next character
	movb	(r0)+,xx		; copy first character
	beq	useerr			; if == 0, syntax error
	movb	(r0)+,xx+1		; copy second character
	beq	useerr			; copy second character
	cmpb	(r0)+,#':		; check for colon(:)
	bne	useerr			; if !=, syntax error
	tstb	(r0)			; must be 0 byte
	beq	synok			; if == 0, OK go on
useerr:
	mov	#usemsg,r0		; error to report
	jmp	errmsg			; report it and exit
synok:
	alun$s	#devlun,xx,#0		; assign lun to device
	mov	$dsw,r1			; get status word
	bgt	devok			; if > 0, ok
	call	numfmt			; format error number
	concat	lunmsg,numbuf,tbuf	; generate error string
	mov	#tbuf,r0		; message to report
	jmp	errmsg			; display it
devok:
	qiow$s	#io.stp,#devlun,#qioefn,,#iosb	; stop timer
	mov	$dsw,r1			; get directive status
	ble	qioerr			; if <= 0, error
	movb	iosb,r1			; get io status
	bgt	qiook			; if > 0, continue
	bis	#177400,r1		; sign extend byte
qioerr:
	call	numfmt			; format error number
	concat	qiomsg,numbuf,tbuf	; generate full error message
	mov	#tbuf,r0		; message to report
	jmp	errmsg			; report it and die
qiook:
	movb	xx,devxx		; copy device mnemonic to spawn string
	movb	xx+1,devxx+1		;
	movb	xx,unlxx		; copy device mnemonic to spawn string
	movb	xx+1,unlxx+1		;
	spwn$s	#mcr,,,,,#spnefn,,,#devstr,#devlen,#0	; spawn device xx:
	mov	$dsw,r1			; get status
	ble	spnerr			; if <= 0, error
	stse$s	#spnefn			; wait for it to complete
	spwn$s	#mcr,,,,,#spnefn,,,#unlstr,#unllen,#0	; spawn unload xx:
	mov	$dsw,r1			; get status
	ble	spnerr			; if <= 0, error
	stse$s	#spnefn			; wait for it to complete
	spwn$s	#mcr,,,,,#spnefn,,,#devstr,#devlen,#0	; spawn device xx:
	mov	$dsw,r1			; get status
	ble	spnerr			; if <= 0, error
	stse$s	#spnefn			; wait for it to complete
	br	done
spnerr:
	call	numfmt			; format error number
	concat	spnmsg,numbuf,tbuf	; generate full error message
	mov	#tbuf,r0		; message to report
	jmp	errmsg			; report it and die
done:
	exit$s
;
;
;	routine to format error code into buffer numbuf
;
;	inputs:	r1	number to format
;
;	outputs:	number formatted in number with 0-byte teminator
;		r0-r3	are modified
;
numfmt:
	mov	#numbuf,r0		; buffer for error number
	clr	r2			; no leading zeroes
	call	$cbdsg			; convert to signed decimal
	clrb	(r0)			; terminate with zero byte
	return
;
;
;	routine to calculate the length of the zero byte terminated
;	string pointed to by r1. length returned in r0, r1 is left
;	unmodified
;
;
	.enabl	lsb
length:
	clr	r0			; initialize count
	mov	r1,-(sp)		; save r1
1$:
	tstb	(r1)+			; see if 0 byte
	beq	2$			; yes, done
	inc	r0
	br	1$
2$:
	mov	(sp)+,r1		; restore r1
	return
;
;
;	routine to copy 0-byte terminated string pointed to by r1
;	to string pointed to by r0.  r1 is left pointing to character
;	after z byte, and r0 points to next available location
;
scopy:
	movb	(r1)+,(r0)+		; copy byte
	bne	scopy			; try again
	tstb	-(r0)			; backup one byte
	return
;
;
;	routine to display error message on terminal.  address of
;	zero byte terminated message is passed in r0
;
;
errmsg:
	mov	r0,r1			; going to scopy into buffer
	mov	#obuf,r0		; destination
	call	scopy			; copy string
	mov	#outbuf,r1		; calculate length
	call	length			; length in r0
	qiow$s	#io.wlb,#ttylun,#qioefn,,,,<r1,r0>
	br	done			; exit
	.end	start
