	.title NLSYMB -	Null symbiont
	.ident /01.0/
;
;			  Free software BY
;		Project Software & Development, Inc.
;
; This software is furnished for free and may be used and  copied as
; desired. This software or  any  other copies  thereof may be provided
; or otherwise made available to any other person.  No title to and
; ownership of  the  software  is  hereby transferred or allowed. 
;
; The information in this software is subject to change  without  notice
; and  should  not  be  construed  as  a commitment by PROJECT SOFTWARE
; AND DEVELOPMENT, INC.
;
; PROJECT SOFTWARE assumes no responsibility for the use or  reliability  
; of this software on any equipment whatsoever.
;
;	Project Software & Development, Inc.
;	14 Story St.
;	Cambridge, Ma. 02138
;	617-661-1444
;
;++
; FACILITY:	VAX/VMS NULL SYMBIONT
;
; ABSTRACT:	This symbiont is used to delete files.
;
;	This is a null symbiont - its sole purpose in life is to spool
;	files to the null device and then delete them.	It really doesn't
;	spool them to NL:, it just looks that way.  All files are deleted
;	unless there was a problem accessing it.
;
;
; ENVIRONMENT:	NATIVE/USER MODE NON-PRIVILEGED CODE
;
; AUTHOR:	M. Erik Husby, PSDI Inc., CREATION DATE: 3-mar-1981
;	With many thanks to Neal Lippman, MIT-JCF for the template of
;	a symbiont for the VARIAN plotter.
;
; MODIFIED BY:
;	MEH 10-apr-1981, To ignore file not found errors.
;
;--

	.page
	.sbttl Data segment declaration
.library \sys$library:lib\
;
;macros:
;
;
;program section declaration macros:
;
; arguments are:
;
;	1) NAME = psect section name
;	2) ALIGN = alignment keyword (d=LONG)
;
; generate a pure section -- code and read only data
;
	.macro pure_section	name=vsmb_pure,align=long
	.psect	name,rd,nowrt,exe,align
	.endm  pure_section
;generate an inpure section -- read/write data
	.macro impure_section	name=vsmb_impure,align=long
	.psect	name,rd,wrt,noexe,align
	.endm  impure_section
;
;macros for error signalling:
;
	.macro signal	condition,p1,p2,p3,p4,p5,p6,p7,p8
	$$$args=1
	.irp	arg,<p8,p7,p6,p5,p4,p3,p2,p1>
	.if	nb arg
	pushl	arg
	$$$args=$$$args+1
	.endc
	.endr
	pushl	#condition
	calls	#$$$args,lib$signal
	.endm	signal
;
; system wide symbolic name definitions:
;
	$shrdef		;shared message definitions
	$opcdef		;opcom definitions
	$jbcmsgdef	;job controller message definitions
	$iodef		;I/O function code definitions
	$pcbdef		;process control block definitions
	$msgdef		;message definitions
	$fabdef		;file access block definitions
	$rabdef		;record access block definitions
	$namdef		;name block definitions
	$dibdef		;device information block offsets
	$chfdef		;condition handling facility definitions
	$rmsdef		;define RMS status codes
	$accdef		;accounting values
;
; definition of message modifiers
;
	$gblini
	$defini	mod
	$equlst	mod__,,1,8,<-
		<success>-		;success
		>
	$equlst	mod__,,4,8,<-
		<abort>-		;printing aborted
		<rmserr>-		;error from RMS
		>
	$defend	mod
;
; a few constants:
;
vsmb_k_usernamesz=12			;size of username string
vsmb_c_bufsz=256			;size of cruft buffer
;
; define symbiont states:
;
	$defini	state
	$equlst	state__,,0,1,<-
		<idle>-			;symbiont idle
		<asndev>-		;assigning device
		<suspend>-		;suspended
		<active>-		;plotting file
		<done>-			;doing rundown
		<open>-			;opening file
		>
	$defend	state
;
; define offset to delete flag in flag byte of symbiont message
;
	$vield	pqr,0,<-
		<delete,,m>,-	;delete flag
		>		;ignore rest of flags
;
; define message from job controller format
;
	$defini	sim
$def sim$w_msgtyp	.blkw	1	;symbiont manager message type code
$def sim$w_rest		.blkw	1	;rest of short messages
$def sim$l_uic		.blkl	1	;UIC of requesting process
$def sim$t_usernam	.blkb	vsmb_k_usernamesz
					;username, not counted, blank filled
$def sim$q_qtime	.blkq	1	;time job was queued
$def sim$t_volnam	.blkb	16	;device ID field - counted string
$def sim$g_fileid	.blkb	6	;file ID field
$def sim$g_dirid	.blkb	6	;directory ID field
$def sim$b_flags	.blkb	1	;file print flags
$def sim$b_filcopy	.blkb	1	;number of copies to print
$def sim$w_pagcnt	.blkw	1	;max pages to print
$def sim$t_prtnam	.blkb	16	;device name for printing - counted
					;string
$def sim$t_filnam	.blkb	20	;filename to print - counted string
$def sim$t_acntname	.blkb	16	;user's account name
$def sim$k_size				;size of this structure
	$defend	sim
vsmb_mbefn = 0				;event flag for send to JBC mailbox
;
; define symbiont global data base
;
	$defini	vsd
$def	vsd_w_mbchan	.blkw 1		;mailbox input channel
$def	vsd_b_state	.blkb 1		;current state
$def	vsd_w_unit	.blkw 1		;mailbox unit
$def	vsd_q_userdesc	.blkq 1		;username descriptor
$def	vsd_t_simmsg	.blkb	sim$k_size ;simbiont message buffer
$def	vsd_w_jbcchan	.blkw 1		;JBC mailbox channel
$def	vsd_g_msgtomgr			;message to job controller
$def	vsd_t_tbuf	.blkb vsmb_c_bufsz	;temp buffer
$def	vsd_q_iosb	.blkq 1		;an I/O status block
$def	vsd_w_vchan	.blkw 1		;channel to plot to
$def	vsd_b_dcode	.blkb 1		;dispatch code for processing routine
$def	vsd_b_err_flags	.blkb 1		;error flags
	_vield	vsd,0,<-
			<abort,,m>,-	;aborting
			<geterr,,m>,-	;error getting a record
			<openerr,,m>-	;error opening file
			>
.=<.+3>&-4		;long word align
$def	vsd_g_fab	.blkb fab$c_bln	;fab for file
$def	vsd_g_rab	.blkb rab$c_bln	;rab for file
$def	vsd_g_nam	.blkb nam$c_bln	;name block to open file by file ID
$def	vsd_w_mbreadlen	.blkw 1		;length of read from mailbox
$def	vsd_k_size			;size of this data structure
	$defend	vsd

	.page
	.sbttl Condition Handler
;++
; FUNCTIONAL DESCRIPTION:
;
;	Condition Handler for the VAX/VMS Null symbiont.
;	It sends the appropriate messages to
;	the operator(s), and exits on a system error or returns to the
;	symbiont on a signalled condition.
;
; CALLING SEQUENCE:
;
;	Entered when and exception occurs, or when an error is signalled.
;	Called by CALLS/G by condition handling facility
;
; INPUT PARAMETERS:
;
;	As per condition handling standard
;
; IMPLICIT INPUTS:
;
;	None
;
; OUTPUT PARAMETERS:
;
;	None
;
; IMPLICIT OUTPUTS:
;
;	None
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	On system error, symbiont is exited
;
;--
;own storage
	impure_section
sig_name:	.blkl 1
	pure_section
facility_desc:
	.long 20$-10$
	.long 10$
10$:
	.ascii /NLSYMB/
20$:

	.page
vsmb_handler:
	.word	^m<r2,r11>			;entry mask
	movl	chf$l_sigarglst(ap),r2		;get addr of signal argument
						;list
	subw2	#2,chf$l_sig_args(r2)		;don't pass PC,PSL
	movl	chf$l_sig_name(r2),sig_name	;save signal name
	pushaq	facility_desc			;push facility name
	pushaw	putmsg_action			;push putmsg action routine
	pushl	r2				;push addr of signal arg list
	calls	#3,g^sys$putmsg			;call putmgs facility
	tstw	sig_name+2			;system exception (=0)
	bneq	10$				;branch if not
	$exit_s					;else exit
10$:
	ret
;
; putmsg action routine
;
putmsg_action:
	.word	^m<r2,r3,r6>			;entry mask
	movl	4(ap),r2			;get addr of message
						;descriptor
	movzbl	#120,r6				;assume max message length
	cmpw	(r2),r6				;compare with actual len
	bgeq	5$				;branch if greater -- truncate
	movzwl	(r2),r6				;else use actual length
5$:
	subl2	r6,sp				;make room on stack for
	movc3	r6,@4(r2),(sp)			;move string onto stack
	pushl	#0				;no reply ID
	movzwl	#opc$_rq_rqst!-			;request type
			<<opc$m_nm_centrl>@8>-	   ;send to central
			,-(sp)
	pushl	sp				;create descriptor
	addl3	r6,#8,-(sp)			;...
	movl	sp,r0				;get descriptor addr
	$sndopr_s	(r0)			;send message to opers
	clrl	r0				;inhibit sending to sys$output
						;and sys$error
	ret

	.page
	.sbttl	Initialization Routine
;++
; FUNCTIONAL DESCRIPTION:
;
;	Once only init routine
;
; CALLING SEQUENCE:
;
;	Entered as main symbiont entry point
;
; INPUT PARAMETERS:
;
;	None
;
; IMPLICIT INPUTS:
;
;	None
;
; OUTPUT PARAMETERS:
;
;	r11 = address of symbiont data base
;
; IMPLICIT OUTPUTS:
;
;	Init done message send to Job Controller
;	Channel assigned to Job Controller's mbox
;	Mailbox created to recieve messages
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	None
;
;--
;own data
jbcmailbox:	;name of job controller's mailbox
	.long 20$-10$
	.long 10$
10$:	.ascii /_/
	.long sys$c_jobctlmb
	.ascii /:/
20$:
vsmb_start::
	.word 0				;entry mask
	moval	vsmb_handler,(fp)	;set condition handler in stack frame
	$setast_s	#0		;disable AST delivery during init
	moval	vsd_g_data,r11		;set address of data base
	movb	#state__idle,vsd_b_state(r11) ;set state initially to idle
;
; assign channel to job controller's mailbox
;
	$assign_s	jbcmailbox,-	;device to assign to
			vsd_w_jbcchan(r11)	;addr for channel
	blbs	r0,20$			;successful?
	signal	jbc$_mbasgn,#0,r0	;signal the error
10$:
	$exit_s				;exit
;
; create symbiont's mailbox
;
20$:
	$crembx_s	-		;create the mbox
		promsk=#0,-		;protection
		maxmsg=#sim$k_size,-	;max size of message
		bufquo=#2*sim$k_size,-	;two messages, max
		chan=vsd_w_mbchan(r11)	;addr for channel
	blbs	r0,30$			;success?
	signal	jbc$_symbcre,#0,r0	;signal the error
	brb	10$			;and exit
30$:
;
; init some values in the data segment
;
	clrb	vsd_b_err_flags(r11)	;clear all flags
	moval	vsd_g_fab(r11),r6	;get fab addr
	moval	vsd_g_rab(r11),r7	;get rab addr
	moval	vsd_g_nam(r11),r8	;get nam block addr
	movb	#fab$c_bid,fab$b_bid(r6);create fab
	movb	#fab$c_bln,fab$b_bln(r6);...
	movb	#rab$c_bid,rab$b_bid(r7);create rab
	movb	#rab$c_bln,rab$b_bln(r7);...
	movb	#nam$c_bid,nam$b_bid(r8);create nam block
	movb	#nam$c_bln,nam$b_bln(r8);...
	movl	r8,fab$l_nam(r6)	;set nam block addr in fab
	movl	r6,rab$l_fab(r7)	;set fab addr in rab
	movl	#fab$m_nam,fab$l_fop(r6);set nam block open in fab
	movw	#sim$k_size,vsd_w_mbreadlen(r11) ;set initial mbox read length
;
; get mailbox channel info
;
	movw	vsd_w_mbchan(r11),r0	;get channel number
	subl2	#dib$k_length,sp	;make buffer on stack
	movl	sp,r2			;r2 is buffer pointer
	pushl	r2			;push addr on stack
	movzwl	#dib$k_length,-(sp)	;and put length on
	movl	sp,r1			;get descriptor address
	$getchn_s	chan=r0,-	;channel
			scdbuf=(r1)	;buffer
	movw	dib$w_unit(r2),vsd_w_unit(r11) ;save unit number
;
; set unsolicited AST to jbc mailbox
;
	bsbw	vsmb_setmbast
	movw	vsd_w_unit(r11),r0	;get unit number of our mailbox
	bsbw	vsmb_init_done		;send init done message
	$setast_s	#1		;enable ASTs
	brw	vsmb_main		;enter main loop

	.page
	.sbttl Subroutines -- Uic routines
;++
; FUNCTIONAL DESCRIPTION:
;
;	These routines are used to set/restore the symbiont's UIC
;
; CALLING SEQUENCE:
;
;	BSB/JSB
;		Registers:
;				r0,r1 -- scratch
;
; INPUT PARAMETERS:
;
;	r11 = address of data segment
;
; IMPLICIT INPUTS:
;
;	Requestor's UIC in the symbiont start print message buffer
;
; OUTPUT PARAMETERS:
;
;	None
;
; IMPLICIT OUTPUTS:
;
;	None
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	The symbiont's UIC is set/reset
;
;--
.enabl lsb
vsmb_setuic:
	movl	sim$l_uic+vsd_t_simmsg(r11),r5	;get uic of requestor
	brb	10$
vsmb_restoreuic:
	movl	#<<1@16>+4>,r5			;get our uic [1,4]
10$:	$cmkrnl_s	routin=20$		;set the uic
	rsb
20$:				;kernel mode routine to set uic
	.word 0				;save no regs
	movl	@#sch$gl_curpcb,r1	;get PCB addr
	movl	r5,pcb$l_uic(r1)	;set the uic
	movl	#1,r0			;must return success
	ret
.dsabl lsb

	.page
	.sbttl Subroutines -- Send messages to Job Controller
;++
; FUNCTIONAL DESCRIPTION:
;
;	This routines sends the init done message to the Job Controller
;
; CALLING SEQUENCE:
;
;	BSB/JSB
;
;		Registers:
;			r0,r1 -- scratch
;
; INPUT PARAMETERS:
;
;	r0 = unit number of symbiont's mailbox
;	r11 = address of data base
;
; IMPLICIT INPUTS:
;
;	None
;
; OUTPUT PARAMETERS:
;
;	None
;
; IMPLICIT OUTPUTS:
;
;	Init done message sent
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	None
;
;--
vsmb_init_done:
	movw	r0,vsd_g_msgtomgr+2(r11)  ;set mb unit in buffer
	movw	#msg$_smbini,vsd_g_msgtomgr(r11) ;set init_done message type
	$qiow_s	-			;send the message
		efn=#vsmb_mbefn,-	;event flag
		chan=vsd_w_jbcchan(r11),-;channel
		func=#io$_writevblk!io$m_now,- ;write with no wait
		iosb=vsd_q_iosb(r11),-	;iosb
		p1=vsd_g_msgtomgr(r11),-	;message
		p2=#4			;length
	blbc	r0,20$			;error?
	movzwl	vsd_q_iosb(r11),r0	;get I/O status
	blbs	r0,30$			;br if okay
20$:	signal	jbc$_mbwrite,#0,r0	;signal the error
30$:
	rsb

	.page
;++
; FUNCTIONAL DESCRIPTION:
;
;	This routine is called to send a file_done message to the
;	Job Controller
;
; CALLING SEQUENCE:
;
;	BSB/JSB
;
;		Registers:
;			r0-r5	are destroyed
;
; INPUT PARAMETERS:
;
;	r3 = reason for termination
;	r11 = address of data segment
;
; IMPLICIT INPUTS:
;
;	None
;
; OUTPUT PARAMETERS:
;
;	None
;
; IMPLICIT OUTPUTS:
;
;	None
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	Mailbox read length is reset to init message length
;
;--
vsmb_file_done:
	movw	#msg$_smbdon,vsd_g_msgtomgr(r11) ;set message done code
	movw	r3,vsd_g_msgtomgr+2(r11)	;set reason code
	movc5	#0,0,#0,#14,vsd_g_msgtomgr+4(r11) ;zero fill rest
	$qiow_s	-				;send the message
		efn=#vsmb_mbefn,-		;event flag number
		chan=vsd_w_jbcchan(r11),-	;channel
		func=#io$_writevblk!io$m_now,-	;write with no wait
		iosb=vsd_q_iosb(r11),-		;iosb
		p1=vsd_g_msgtomgr(r11),-	;buffer
		p2=#16				;len
	blbc	r0,20$				;error?
	movzwl	vsd_q_iosb(r11),r0		;get iosb
	blbs	r0,30$				;okay?
20$:	signal	jbc$_mbwrite,#0,r0		;signal the error
30$:
	movw	#sim$k_size,vsd_w_mbreadlen(r11) ;reset mb read length to max
	rsb

	.page
	.sbttl	Subroutine -- Set mailbox AST
;++
; FUNCTIONAL DESCRIPTION:
;
;	This routine sets an unsolicited AST on the Job Controller's
;	mailbox
;
; CALLING SEQUENCE:
;
;	BSB/JSB
;
;		Registers:
;			r0 destroyed
; INPUT PARAMETERS:
;
;	None
;
; IMPLICIT INPUTS:
;
;	r11 = address of data segment
;
; OUTPUT PARAMETERS:
;
;	None
;
; IMPLICIT OUTPUTS:
;
;	None
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	None
;
;--
vsmb_setmbast:
	$qiow_s	-			;set unsolicited AST
		efn=#vsmb_mbefn,-	;event flag
		chan=vsd_w_mbchan(r11),-;channel
		func=#io$_setmode,-	;set mode function
		iosb=vsd_q_iosb(r11),-	;iosb
		p1=vsmb_mbast		;AST routine
	blbc	r0,10$			;error?
	movzwl	vsd_q_iosb(r11),r0	;get iosb
	blbs	r0,20$			;okay?
10$:	signal	jbc$_mbsetast,#0,r0	;signal the error
20$:	rsb

	.page
	.sbttl Symbiont	Mainline
;++
; FUNCTIONAL DESCRIPTION:
;
;	This is the symbiont mainline. It is entered directly from
;	the init routine, and loops around, processing files.
;
; CALLING SEQUENCE:
;
;	BR
;
; INPUT PARAMETERS:
;
;	None
;
; IMPLICIT INPUTS:
;
;	r11 = address of data segment
;	At wake, the file is open, and the dispatch code is in the data
;	segment; a channel has been assigned to the requested device.
;
; OUTPUT PARAMETERS:
;
;	None
;
; IMPLICIT OUTPUTS:
;
;	None
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	The file is deleted.
;
;--
;
; this is the data segment
;
	impure_section
vsd_g_data::
	.blkb	vsd_k_size
	pure_section
vsmb_main:
	$hiber_s			;wait for something todo
	movb	#state__active,vsd_b_state(r11)	 ;set us active
	bbc	#vsd_v_openerr,vsd_b_err_flags(r11),35$
					;br if opened successfully
	cmpl	#rms$_fnf,-		; Was error file not found?
		vsd_g_fab+fab$l_sts(r11) ; Ignore if so.
	beql	35$			; ...
	moval	vsd_t_simmsg+sim$t_filnam+1(r11),-(sp) ;push file name addr
	movzbl	vsd_t_simmsg+sim$t_filnam(r11),-(sp) ;push length of file name
	movl	sp,r3			;save descriptor address
	pushl	vsd_g_fab+fab$l_stv(r11) ;push RMS status value
	pushl	vsd_g_fab+fab$l_sts(r11) ;push RMS status code
	pushl	r3			;push filename descriptor
	pushl	#1			;one FAO arg
	pushl	#<4@16>!shr$_openin!4	;condition code
	calls	#5,lib$signal		;signal the error
	addl2	#8,sp			;pop the descriptor off the stack
35$:
;
; perform rundown on file:
;
90$:
	$setast_s	#0		;disable AST delivery
	tstw	vsd_g_fab+fab$w_ifi(r11) ;has open been done?
	beql	120$			;br if not
	bicl	#fab$m_dlt,vsd_g_fab+fab$l_fop(r11) ;clear delete bit
	bbs	#vsd_v_abort,vsd_b_err_flags(r11),115$ ;br if aborting
	bisl	#fab$m_dlt,vsd_g_fab+fab$l_fop(r11) ;set delete bit
115$:
	bsbw	vsmb_setuic		;set UIC to requestor's
	$close	vsd_g_fab(r11)		;close the file
	clrw	vsd_g_rab+rab$w_isi(r11) ;quick disconnect
	bsbw	vsmb_restoreuic		;set uic back to [1,4]
;
; set ending status
;
120$:
	movzbl	#mod__rmserr,r3		;assume input error
	bitb	#vsd_m_openerr!-	;check open error,
		 vsd_m_geterr,-		;get error
		 vsd_b_err_flags(r11)	;was either set?
	bneq	130$			;br if no
	movzbl	#mod__abort,r3		;set abort
	bbs	#vsd_v_abort,vsd_b_err_flags(r11),130$
					;br if aborting
	movzbl	#mod__success,r3	;okay, successful
;
; final cleanup
;
130$:
	clrb	vsd_b_err_flags(r11)	;reset all flags
	$dassgn_s vsd_w_vchan(r11)	; deasign the null device.
	movb	#state__idle,vsd_b_state(r11) ;set state to idle
	bsbw	vsmb_file_done		;send file done message
	$setast_s	#1		;enable ASTs
	brw	vsmb_main		;and loop back for another go

	.page
	.sbttl	Subroutine -- assign channel to	dev
;++
; FUNCTIONAL DESCRIPTION:
;
;	This routine assigns a channel to the device specified in the
;	start print message
;
; CALLING SEQUENCE:
;
;	BSB/JSB
;
;		Registers:
;			r7 - buffer pointer
;			r8 - device name string length
;			r9 - pointer to device name string
;		***NOTE: r7-r9 are restored on exit
; INPUT PARAMETERS:
;
;	None
;
; IMPLICIT INPUTS:
;
;	r11 = addr of data segment
;	Device name string in symbiont start print message
;
; OUTPUT PARAMETERS:
;
;	None
;
; IMPLICIT OUTPUTS:
;
;	None
;
; COMPLETION CODES:
;
;	The return code from the assign system service is returned in R0
;
; SIDE EFFECTS:
;
;	A channel is assigned to the device
;
;--
vsmb_assigndev:
	pushr	#^m<r7,r8,r9>		;save registers
	subl2	#20,sp			;make buffer on stack
	movl	sp,r7			;make r7 buffer pointer
	pushl	r7			;put addr on stack for descriptor
	movzbl	vsd_t_simmsg+sim$t_prtnam(r11),r8 ;get device name length
	movab	vsd_t_simmsg+sim$t_prtnam+1(r11),r9 ;device name addr
	movb	#^a/_/,(r7)+		;put on leading underscore
10$:	movb	(r9)+,(r7)+		;move a character into buffer
	sobgtr	r8,10$			;done?
	movb	#^a/:/,(r7)+		;end with a colon
	subl3	(sp),r7,-(sp)		;compute length of string onto
					;stack for descriptor
	movl	sp,r7			;get descriptor addr
	movab	vsd_w_vchan(r11),r8	;get channel addr
	$assign_s (r7),(r8)		;assign the channel
	addl2	#28,sp			;clear buffer+descriptor from stack
	popr	#^m<r7,r8,r9>		;pop registers
	rsb

	.page
	.sbttl AST level routines
;++
; FUNCTIONAL DESCRIPTION:
;
;	These routines are called at AST level when something is put
;	in the mailbox. They process the message and adjust the appropriate
;	parts of the data segment.
;
; CALLING SEQUENCE:
;
;	CALLS/G from AST dispatcher
;
; INPUT PARAMETERS:
;
;	None
;
; IMPLICIT INPUTS:
;
;	None
;
; OUTPUT PARAMETERS:
;
;	See each routine for a description of return codes, if any.
;
; IMPLICIT OUTPUTS:
;
;	None
;
; COMPLETION CODES:
;
;	None
;
; SIDE EFFECTS:
;
;	The file is opened/connected on init print. Various actions
;	are taken by the subroutines.
;
;--
vsmb_mbast:
	.word	^m<r2,r3,r9,r10,r11>	;entry mask
	moval	vsd_g_data,r11		;get addr of data segment
	movzbl	vsd_b_state(r11),r10	;get current state
read_mb_again:
	cmpb	#state__asndev,r10	;assigning device?
	bneq	10$			;br if no
	bsbw	asndev			;try again
10$:	bsbw	read_mb_now		;read the mbox
	blbs	r0,chk_mbrd		;check read if successful
	bsbw	vsmb_setmbast		;reque the AST
	movb	r10,vsd_b_state(r11)	;reset state in data segment
	ret
;
; This routine is used to case to the appropriate handler
; for each message type. We really want this to look like a subroutine call,
; so a return addr is pushed for the rsb instruction.
;
chk_mbrd:
	pushab	read_mb_again		;push return addr
	case	vsd_t_simmsg+sim$w_msgtyp(r11),- ;dispatch code
			<<init>,-	;start print
			 <abort>,-	;abort printing
			 <suspend>,-	;suspend printing
			 <resume>,-	;resume printing
			 <exit>,-	;exit symbiont
			>,limit=#msg$_iniopr ;start at first message
	signal	jbc$_invmsg		;signal invalid message
	brb	read_mb_again		;try again
.enabl lsb
5$:	.long	<-1*50000000>,-1	;five minutes, delta time
;
; this routine processes an init print message
;
init:
	cmpb	#state__idle,r10	;are we idle?
	beql	1$			;okay if so
	brw	unexpect		;else unexpected
1$:	movzbl	#state__asndev,r10	;set assigning device state
asndev:	movw	#4,vsd_w_mbreadlen(r11)	;set read length to minimum
12$:	bsbw	vsmb_assigndev		;try to assign device
	blbs	r0,17$			;br if okay
	bsbw	read_mb_now		;read again
	blbc	r0,2$			;br if failed
	brw	chkmb1			;else check the read
2$:	$setimr_s	#10,5$		;wait for five minutes
	$waitfr_s	#10		;...
	brw	12$			;try again
17$:
	movzbl	#state__open,r10	;set opening file state
	movc3	#16+6+6,vsd_t_simmsg+sim$t_volnam(r11),-
		vsd_g_nam+nam$t_dvi(r11) ;set device, file, and dir
					;fields in nam block
	bsbw	vsmb_setuic		;set uic to requestor's
	$open	fab=vsd_g_fab(r11)	;open the file
	blbs	r0,20$			;br if okay
9$:	bsbw	vsmb_restoreuic		;reset uic to [1,4]
	bisb	#vsd_m_openerr,vsd_b_err_flags(r11) ;set open error bit
10$:	movzbl	#state__done,r10	;set done state
	brw	40$			;and exit
20$:
	$connect	rab=vsd_g_rab(r11) ;connect to file
	blbc	r0,9$			;take care of connect error
	bsbw	vsmb_restoreuic		;set UIC to [1,4]
	movab	vsd_g_rab(r11),r2	;get rab addr
	movab	vsd_t_tbuf(r11),r3	;get buffer addr
	movl	r3,rab$l_ubf(r2)	;set buffer addr in rab
	movw	#256,rab$w_usz(r2)	;set buffer size in rab
40$:
	$wake_s				;wake up
	rsb
.dsabl lsb
;
; Local subroutines to read the mailbox
;
;
; Read with no wait:
;
read_mb_now:
	movzwl	#io$_readvblk!io$m_now,r0 ;set I/O function code
;read the mb
read_mb:
	movaq	-(sp),r1		;make iosb on stack
	$qiow_s	-			;do the read
		chan=vsd_w_mbchan(r11),-;channel
		func=r0,-		;function
		iosb=(r1),-		;iosb
		p1=vsd_t_simmsg(r11),-	;buffer
		p2=vsd_w_mbreadlen(r11)	;size to read
	movq	(sp)+,r0		;get iosb
	rsb
;
; This routine processes the abort file message.
; The abort bit is set, and outstanding I/O canceled.
;
abort:
	cmpb	#state__done,r10	;are we done?
	beql	30$			;then ignore it
	cmpb	#state__idle,r10	;were we idle?
	bneq	10$			;br if not
	brw	unexpect		;else unexpected
10$:
	bisb	#vsd_m_abort,vsd_b_err_flags(r11) ;set abort bit
	$cancel_s	vsd_w_vchan(r11)	;cancel I/O on channel
	cmpb	#state__suspend,r10	;were we suspended?
	bneq	20$			;br if not
	movzbl	r9,r10			;restore previous state
20$:
	cmpb	#state__asndev,r10	;are we assigning device?
	bneq	30$			;br if no
	movzbl	#state__idle,r10	;else make us idle
30$:
	rsb
;
; This routine is the symbiont exit point
;
exit:
	cmpb	#state__idle,r10	;are we idle
	beql	10$			;br if so
	brw	unexpect		;else unexpected
10$:
	$dassgn_s vsd_w_jbcchan(r11)	;deassign channel to JBC's mbox
	blbc	r0,20$			;br on error
	$dassgn_s vsd_w_mbchan(r11)	;deassign my mb
	blbs	r0,30$			;br if okay
20$:	signal	jbc$_mbdeas,#0,r0	;signal the error
30$:
	$delmbx_s	vsd_w_unit(r11)	;kill my mb (just in case)
	$exit_s
;
; signal unexpected message
;
unexpect:
	signal	jbc$_unesymmsg		;signal
	brw	read_mb_again		;read again
;
; Handle suspend message
;
.enabl lsb
suspend:
	cmpb	#state__done,r10	;done?
	beql	20$			;ignore it
	cmpb	#state__idle,r10	;were we idle?
	bneq	10$			;okay if not
	brw	unexpect		;else unexpected
10$:
	movzbl	r10,r9			;save old state
	movzbl	#state__suspend,r10	;set suspend state
	movzwl	#io$_readvblk,r0	;set function code
	bsbw	read_mb			;wait for something in mbox
chkmb1:	movab	chk_mbrd,(sp)		;set new ret addr
20$:	rsb
.dsabl lsb
;
; This routine performs a resume print
;
resume:
	cmpb	#state__done,r10	;are we done?
	beql	30$			;then ignore it
	cmpb	#state__suspend,r10	;are we suspended
	beql	1$			;okay if so
	brw	unexpect		;else unexpected
1$:	movzbl	r9,r10			;restore old state
	movw	vsd_t_simmsg+sim$w_rest(r11),r0	;get rest of message
	beql	30$			;no flags, just resume
	cmpw	#^x8000,r0		;top of file requested?
	bneq	30$			;br if no
	$rewind	vsd_g_rab(r11)		;rewind the file
	blbs	r0,30$			;br if okay
	signal	shr$_rmserror!<4@16>,#0,r0 ;signal the error
	bisb	#vsd_m_geterr,vsd_b_err_flags(r11) ;set error bit
30$:	rsb

;
; end of symbiont
;
	.end	vsmb_start
