	.TITLE	TAPEIO   Tape block I/O and supporting functions
;
;	Substantially modified from previous versions
;	1982-SEP-16 -- JWB -- Revision 0
;
	$RMSDEF
	$SSDEF
;
CLOSED	= 0			; File status = CLOSED
GETSW	= 1			; File status = OPEN FOR INPUT
PUTSW   = 2			; File status = OPEN FOR OUTPUT
OK	= 1			; STATUS return = 1 for OK
EOF     = 2                     ; STATUS return = 2 for END OF FILE
OPERR	= 3			; STATUS return = 3 for OPEN ERROR
IOERR	= 4			; STATUS return = 4 for I/O ERROR
;
;	REGISTER USAGE:
;	R0 - System status value
;	R1 - FAB or RAB base addresses
;	R2 - DEVICE descriptor address
;	R3 -
;	R4 - STATUS address
;	R5 - SYSTAT address
;
;	------------- READ-ONLY DATA SECTION ----------------
;
	.PSECT	TPDATR,RD,NOWRT,NOEXE,LONG
;
ONEFILE:.LONG	1
;
;	------------- READ/WRITE DATA SECTION ---------------
;
	.PSECT	TPDATW,RD,WRT,NOEXE,LONG
;
GETFAB:	$FAB	FAC=<BIO,GET>, -	; input only
		ORG=SEQ, -
		RFM=UDF
;
GETRAB:	$RAB	FAB=GETFAB, -		; link to input FAB
		RAC=SEQ 		; READ access is sequential
;
PUTFAB: $FAB	FAC=<BIO,PUT>, -	; output only
		ORG=SEQ, -
		RFM=UDF
;
PUTRAB:	$RAB	FAB=PUTFAB, -		; link to output FAB
		RAC=SEQ			; WRITE access is sequential
;
INSTAT:	.WORD	CLOSED		; 0 = not open, 1 = open for input
OUSTAT:	.WORD	CLOSED		; 0 = not open, 2 = open for output
;
IOSB:				; I/O status block for control funcs only
IOSBST:	.BLKW			; status
IOSBBC:	.BLKW			; byte count
IOSBDD:	.BLKL			; device-dependent data
DEVDESC:  .BLKQ			; local copy of DEVICE descriptor
TAPECHAN: .BLKL			; channel number for control functions
	.PAGE
;
;	----------------- CODE -----------------------------
;
	.PSECT	TAPEIO,EXE,NOWRT
;
;	SUBROUTINE TOPENR(DEVICE,MAXLBK,  STATUS,SYSTAT)
;
;	Open a tape device for reading
;
;	INPUTS: DEVICE - CHAR*(*) - Logical or physical device name
;		MAXBLK - INTEGER  - Maximum number of bytes in a block
;
;	OUTPUT: STATUS - INTEGER - 1 = ok,
;				 - 3 = error opening file
;				 - 4 = error connecting record stream
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TOPENR,^M<R2,R3,R4,R5>
	MOVL	12(AP),R4		;Address of STATUS
	MOVL    16(AP),R5		;Address of SYSTAT
	MOVL	#SS$_NORMAL,R0
	MOVL	#OK,(R4)		;Set STATUS = OK
	CMPW	INSTAT,#GETSW
	BEQL	40$			;Skip if already open
	MOVAL	GETFAB,R1
	MOVL	4(AP),R2		;Address of DEVICE descriptor
	MOVW	 (R2),FAB$B_FNS(R1)	;Filename string size
	MOVL	4(R2),FAB$L_FNA(R1)	;Filename string address
	MOVW	@8(AP),FAB$W_BLS(R1)	;Put MAXBLK in GETFAB BLS
	$OPEN	FAB=GETFAB		;Open for reading
	BLBC	R0,30$			;Error?
	$CONNECT RAB=GETRAB		;Connect for reading
	BLBC	R0,28$			;Error?
	MOVW	#GETSW,INSTAT		;Indicate open for input
	BRB	40$
28$:	MOVL	#IOERR,(R4)		;Set STATUS = CONNECT error (4)
	BRB	32$
30$:	MOVL	#OPERR,(R4)		;Set STATUS = OPEN error (3)
32$:	MOVW	#CLOSED,INSTAT		;Indicate file is not open
40$:	JSB	SET_SYSTAT		;Set SYSTAT return
	RET
;
;	--------- Internal Subroutine SET_SYSTAT ---------
;	Assumes value is in R0, address of SYSTAT is in R5
;
SET_SYSTAT:
	CMPL	R0,#RMS$_NORMAL		;If STATUS is RMS$_NORMAL,
	BNEQU	50$
	MOVL	#SS$_NORMAL,R0		;then change it to SS$_NORMAL
50$:	MOVL	R0,(R5)			;Set SYSTAT
	RSB				;Internal RETURN
	.PAGE
;
;	SUBROUTINE TOPENW(DEVICE,MAXLBK,  STATUS,SYSTAT)
;
;	Open a tape device for writing
;
;	INPUTS: DEVICE - CHAR*(*) - Logical or physical device name
;		MAXBLK - INTEGER  - Maximum number of bytes in a block
;
;	OUTPUT: STATUS - INTEGER - 1 = ok,
;				 - 3 = error opening file
;				 - 4 = error connecting record stream
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TOPENW,^M<R2,R3,R4,R5>
	MOVL	12(AP),R4		;Address of STATUS
	MOVL    16(AP),R5		;Address of SYSTAT
	MOVL	#SS$_NORMAL,R0
	MOVL	#OK,(R4)		;Set STATUS = OK
	CMPW	OUSTAT,#PUTSW
	BEQL	40$			;Skip if already open
	MOVAL	PUTFAB,R1
	MOVL	4(AP),R2		;Address of DEVICE descriptor
	MOVW	 (R2),FAB$B_FNS(R1)	;Filename string size
	MOVL	4(R2),FAB$L_FNA(R1)	;Filename string address
	MOVW	@8(AP),FAB$W_BLS(R1)	;Put MAXBLK in PUTFAB BLS
	$OPEN	FAB=PUTFAB		;Open for writing
	BLBC	R0,30$			;Error?
	$CONNECT RAB=PUTRAB		;Connect for writing
	BLBC	R0,28$			;Error?
	MOVW	#PUTSW,OUSTAT		;Indicate open for output
	BRB	40$
28$:	MOVL	#IOERR,(R4)		;Set STATUS = connect error (4)
	BRB	32$
30$:	MOVL	#OPERR,(R4)		;Set STATUS = open error (3)
32$:	MOVW	#CLOSED,OUSTAT		;Indicate file is not open
40$:	JSB	SET_SYSTAT		;Set SYSTAT return
	RET
	.PAGE
;
;	SUBROUTINE TCLOSR(DEVICE,  STATUS,SYSTAT)
;
;	Close tape file that was opened by TOPENR
;
;	INPUT:  DEVICE - CHAR*(*) - Logical or physical device name
;
;	OUTPUT: STATUS - INTEGER - 1 = ok
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TCLOSR,^M<R4,R5>
	MOVL	 8(AP),R4		;Address of STATUS
	MOVL	12(AP),R5		;Address of SYSTAT
	MOVL	#OK,(R4)		;Set STATUS = OK
	$CLOSE	FAB=GETFAB
	MOVW	#CLOSED,INSTAT
	JSB	SET_SYSTAT
	RET
;
;	SUBROUTINE TCLOSW(DEVICE,  STATUS,SYSTAT)
;
;	Close tape file that was opened by TOPENW
;
;	INPUT:  DEVICE - CHAR*(*) - Logical or physical device name
;
;	OUTPUT: STATUS - INTEGER - 1 = ok
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TCLOSW,^M<R4,R5>
	MOVL	 8(AP),R4		;Address of STATUS
	MOVL	12(AP),R5		;Address of SYSTAT
	MOVL	#OK,(R4)		;Set STATUS = OK
	$CLOSE	FAB=PUTFAB
	MOVW	#CLOSED,OUSTAT
	JSB	SET_SYSTAT
	RET
	.PAGE
;
;	SUBROUTINE TPREAD(BUFSIZ,  BUFFER,LENGTH,STATUS,SYSTAT)
;
;	Read a tape block into BUFFER
;
;	INPUT:	BUFSIZ - INTEGER - Size of BUFFER, bytes
;
;	OUTPUTS:BUFFER - INTEGER(BUFSIZ/4) - Input buffer
;		       - or BYTE(BUFSIZ)
;		LENGTH - INTEGER - Block length read, in bytes
;		STATUS - INTEGER - 1 = ok,
;                                - 2 = end of file 
;				 - 3 = error - file not open for input
;				 - 4 = error - read failure - see systat
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TPREAD,^M<R4,R5>
	MOVL	16(AP),R4		;Address of STATUS
	MOVL	20(AP),R5		;Address of SYSTAT
	MOVL	#OK,(R4)		;Set STATUS to OK
	CMPW	INSTAT,#GETSW		;Open for input?
	BEQL	10$			;Proceed if OK
	MOVL	#OPERR,(R4)		;Set STATUS = open error
	CLRL	R0			;Return warning in R0
	JSB	SET_SYSTAT		;Set SYSTAT value
	RET
10$:		;;;	$RAB_STORE RAB=GETRAB,UBF=BUFFER,USZ=BUFSIZ
	MOVAL	GETRAB,R1
	MOVW	@4(AP),RAB$W_USZ(R1)	;USZ=BUFSIZ (value)
        MOVL	 8(AP),RAB$L_UBF(R1)	;UBF=BUFFER (address)
;
	$READ	RAB=GETRAB
;
	MOVAL	GETRAB,R1		;Reset in case clobbered
	MOVW	RAB$W_RSZ(R1),@12(AP)	;Set LENGTH
	BLBS	R0,20$			;GET ok?
        MOVL	#EOF,(R4)               ;Set STATUS = EOF
        CMPL	R0,#RMS$_EOF            ;End of file?
        BEQL	20$                     ;Yes
	MOVL	#IOERR,(R4)		;Set STATUS = ERROR
20$:	JSB	SET_SYSTAT		;Set SYSTAT = R0
	RET
	.PAGE
;
;	SUBROUTINE TPWRIT(BUFSIZ,BUFFER,LENGTH,  STATUS,SYSTAT)
;
;	Write a tape block from BUFFER
;
;	INPUT:	BUFSIZ - INTEGER - Size of BUFFER, bytes (not used)
;		BUFFER - INTEGER(BUFSIZ/4) - Output buffer
;		       - or BYTE(BUFSIZ)
;		LENGTH - INTEGER - Block length to write, in bytes
;
;	OUTPUT:	STATUS - INTEGER - 1 = ok,
;                                - 2 = end of file / end of medium
;				 - 3 = error - file not open for output
;				 - 4 = error - write failure - see SYSTAT
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TPWRIT,^M<R4,R5>
	MOVL	16(AP),R4		;Address of STATUS
	MOVL	20(AP),R5		;Address of SYSTAT
	MOVL	#OK,(R4)		;Set STATUS to OK
	CMPW	OUSTAT,#PUTSW		;Open for output?
	BEQL	10$			;Proceed if OK
	MOVL	#OPERR,(R4)		;Set STATUS = OPEN error
	CLRL	R0			;Return warning in R0
	JSB	SET_SYSTAT		;Set SYSTAT value
	RET
10$:		;;;	$RAB_STORE RAB=PUTRAB,RBF=BUFFER,RSZ=LENGTH
	MOVAL	PUTRAB,R1
	MOVW	@12(AP),RAB$W_RSZ(R1)	;RSZ=LENGTH (value)
        MOVL	  8(AP),RAB$L_RBF(R1)	;RBF=BUFFER (address)
;
	$WRITE	RAB=PUTRAB
;
	BLBS	R0,20$			;WRITE ok?
        MOVL	#EOF,(R4)               ;Set STATUS = EOF
        CMPL	R0,#RMS$_EOF            ;End of file?
        BEQL	20$                     ;Yes
	MOVL	#IOERR,(R4)		;Set STATUS = ERROR
20$:	JSB	SET_SYSTAT		;Set SYSTAT = R0
	RET
	.PAGE
;
;	SUBROUTINE TPSKPF(DEVICE,  STATUS,SYSTAT)
;
;	Skip forward to next end of file
;
;	INPUT:	DEVICE - CHAR*(*) - Device name descriptor
;	OUTPUT:	STATUS - INTEGER  - 1 = ok,
;				    3 = channel assignment error
;				    4 = I/O error
;		SYSTAT - INTEGER  - System status code
;
	.ENTRY	TPSKPF,^M<R2,R3,R4,R5>
	MOVL	4(AP),R2		;Address of DEVICE descriptor
	MOVL	8(AP),R4		;Address of STATUS
	MOVL	12(AP),R5		;Address of SYSTAT
	MOVL	(R2),DEVDESC		;Make copy so macro will work
	MOVL	4(R2),DEVDESC+4
	MOVL	#OK,(R4)
	$ASSIGN_S DEVNAM=DEVDESC,CHAN=TAPECHAN
	BLBS	R0,10$			;Continue if OK
	MOVL	#OPERR,(R4)		;Set STATUS = open error
	JSB	SET_SYSTAT
	RET	
10$:	$QIOW_S   CHAN=TAPECHAN,FUNC=#IO$_SKIPFILE,IOSB=IOSB,P1=1
	CMPL	R0,#SS$_NORMAL		;Check status from QIOW
	BNEQ	20$
	MOVZWL	IOSBST,R0		;Check status in IOSB
20$:	JSB	SET_SYSTAT		;Return SYSTAT value
	BLBS	R0,30$			;Any error?
	MOVL	#IOERR,(R4)		;Set STATUS = IOERR
30$:	$DASSGN_S CHAN=TAPECHAN
	RET
	.PAGE
;
;	SUBROUTINE TPREWD(DEVICE,  STATUS,SYSTAT)
;
;	Rewind a tape device
;
;	INPUT:	DEVICE - CHAR*(*) - Device descriptor
;
;	OUTPUT:	STATUS - INTEGER - 1 = ok,
;				   3 = channel assignment error,
;				   4 = I/O error
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TPREWD,^M<R2,R3,R4,R5>
	MOVL	4(AP),R2		;Address of DEVICE descriptor
	MOVL	8(AP),R4		;Address of STATUS
	MOVL	12(AP),R5		;Address of SYSTAT
	MOVL	(R2),DEVDESC		;Make copy so macro will work
	MOVL	4(R2),DEVDESC+4
	MOVL	#OK,(R4)
	$ASSIGN_S DEVNAM=DEVDESC,CHAN=TAPECHAN
	BLBS	R0,10$			;Continue if OK
	MOVL	#OPERR,(R4)		;Set STATUS = open error
	JSB	SET_SYSTAT
	RET	
10$:	$QIOW_S  CHAN=TAPECHAN,IOSB=IOSB,-
		FUNC=#IO$_REWIND
	CMPL	R0,#SS$_NORMAL		;Check status from QIOW
	BNEQ	20$
	MOVZWL	IOSBST,R0		;Check status in IOSB
20$:	JSB	SET_SYSTAT		;Return SYSTAT value
	BLBS	R0,30$			;Any error?
	MOVL	#IOERR,(R4)		;Set STATUS = IOERR
30$:	$DASSGN_S CHAN=TAPECHAN
	RET
	.PAGE
;
;	SUBROUTINE TPREWO(DEVICE,  STATUS,SYSTAT)
;
;	Rewind a tape device, and put it offline
;
;	INPUT:	DEVICE - CHAR*(*) - Device descriptor
;
;	OUTPUT:	STATUS - INTEGER - 1 = ok,
;				   3 = channel assignment error,
;				   4 = I/O error
;		SYSTAT - INTEGER - System status code
;
	.ENTRY	TPREWO,^M<R2,R3,R4,R5>
	MOVL	4(AP),R2		;Address of DEVICE descriptor
	MOVL	8(AP),R4		;Address of STATUS
	MOVL	12(AP),R5		;Address of SYSTAT
	MOVL	(R2),DEVDESC		;Make copy so macro will work
	MOVL	4(R2),DEVDESC+4
	MOVL	#OK,(R4)
	$ASSIGN_S DEVNAM=DEVDESC,CHAN=TAPECHAN
	BLBS	R0,10$			;Continue if OK
	MOVL	#OPERR,(R4)		;Set STATUS = open error
	JSB	SET_SYSTAT
	RET	
10$:	$QIOW_S  CHAN=TAPECHAN,IOSB=IOSB,-
		FUNC=#<IO$_REWINDOFF!IO$M_NOWAIT>
	CMPL	R0,#SS$_NORMAL		;Check status from QIOW
	BNEQ	20$
	MOVZWL	IOSBST,R0		;Check status in IOSB
20$:	JSB	SET_SYSTAT		;Return SYSTAT value
	BLBS	R0,30$			;Any error?
	MOVL	#IOERR,(R4)		;Set STATUS = IOERR
30$:	$DASSGN_S CHAN=TAPECHAN
	RET
;
	.END
