;LBSPOOLA/ASM - SPOOL setup
;
PAR_ERR	EQU	44		;Parameter Error
ETX	EQU	3
CR	EQU	13
RST28	EQU	28H
LOWBUF$	EQU	2300H		;Low memory disk I/O buff
KITSK@	EQU	31		;FLGTAB+31
;
*GET	SVCMAC:3		;SVC Macro equivalents
*LIST	OFF			;Get LDOS60/EQU
*GET	LDOS60/EQU:2		;Xref from lowcore
*LIST	ON
;
	ORG	2400H
;
;	Save stack & call Spool routine
;
SPOOL	LD	(SAVESP+1),SP	;Save SP
	CALL	SPOOL1		;Call SPOOL Code
EXIT	LD	HL,0		;Successful exit
;
;	P/u stack & clear any pending <BREAK>
;
SAVESP	LD	SP,$-$		;P/u original stack
	@@CKBRKC		;Clear any <BREAK>
	RET			;Ret to DOS
;
;	Informative Message Exit
;
CLEARD	LD	HL,CLEARD$
	DB	0DDH
RESUMD	LD	HL,RESUMD$
	DB	0DDH
PAUSED	LD	HL,PAUSED$
	DB	0DDH
SPLACT	LD	HL,SPLACT$
	DB	0DDH
SPLONM	LD	HL,SPLONM$
	DB	0DDH
SPLOFM	LD	HL,SPLOFM$
	DB	0DDH
SPLOPM	LD	HL,SPLOPM$
	DB	0DDH
PRMBGM	LD	HL,PRMBGM$
	@@LOGOT
	JR	EXIT
;
;	I/O Error Processor
;
PRMERR	LD	A,PAR_ERR	;Parameter Error
IOERR	LD	L,A		;Set HL = Error #
	LD	H,0
	OR	0C0H		;Set short, return
	LD	C,A		;Error code to C
	@@ERROR			;Dsply error
	JR	SAVESP		;Exit
;
;	Internal Error Message Handler
;
BADDCB	LD	HL,BADDCB$
	DB	0DDH
NOFIND	LD	HL,NOFIND$
	DB	0DDH
INUSE	LD	HL,INUSE$
	DB	0DDH
CANT	LD	HL,CANT$
	@@LOGOT
ERREXIT	LD	HL,-1		;Set abort code
	JR	SAVESP		;Exit
;
;	SPOOL1 - Set up system to Spool Output
;
SPOOL1
	PUSH	HL		;Save INBUF$ pointer
	@@FLAGS			;Get flag table pointer
	LD	IX,PRMSAV	;Point to parm save area
	LD	DE,SPOOL$	;If already resident,
	@@GTMOD			;  don't need to check
	JR	NZ,SPL1		;  if memory available
	LD	(SVDCB),DE	;Save DCB pointer
	LD	(SVBGN),HL	;Save module begin
	LD	HL,4		;Get parm save pointer
	ADD	HL,DE
	LD	(HIPARM),HL	;Save for use by clear
	PUSH	IX		;Also put address in DE
	POP	DE		;Shift saved parms into
	LD	BC,11		;  spool driver front end
	LDIR
	LD	E,(IX+4)	;P/u previous MPARM
	LD	D,(IX+5)
	LD	(MPARM+1),DE	;Stuff as new default
	LD	E,(IX+6)	;P/u previous DPARM
	LD	D,(IX+7)
	LD	(DPARM+1),DE	;Stuff as new default
	LD	A,(IX+10)	;P/u old bank #
	AND	07FH		;Strip hi bit
	LD	(BPARM+1),A	;  & save as default
SPL1	POP	HL		;Get INBUF$ pointer
;
;	Fetch device spec to spool
;
SPL2	LD	DE,SPLDCB	;Fetch device spec
	@@FSPEC			;  to spool
	PUSH	HL		;Save inbuf$ ptr
	JR	NZ,USEPR	;Use *PR if no entry
	LD	A,(DE)		;If a device spec not
	CP	'*'		;  found, maybe it was
	JR	Z,SPL2A		;  the spool file spec
;
;	File spec fetched - Move to spool FCB
;
	EX	DE,HL		;DCB to HL
	LD	DE,SPLFCB	;Point to spool FCB
	PUSH	DE
	LD	BC,32
	LDIR			;Move it in
	LD	HL,PR$		;Move in default spec
	LD	DE,SPLDCB	;  for spool device
	LD	BC,4
	LDIR
	XOR	A
	POP	DE		;Point to SPLFCB
	JR	SPL2B		;Go - we have spec
USEPR	LD	HL,PR$		;Move in default spec
	LD	DE,SPLDCB
	LD	BC,4
	LDIR
;
;	Fetch file spec to use as disk spool buffer
;
SPL2A	POP	HL		;Get inbuf$ ptr
	LD	DE,(SPLDCB+1)	;Stuff device name for
	LD	(DSKSPC),DE	;  default spool file name
	LD	DE,SPLFCB	;Fetch spool filespec
	@@FSPEC
	PUSH	HL		;Save separator char
SPL2B	PUSH	AF		;  & line pointer
	LD	HL,DSKSPC	;Default to XX/SPL
	JR	Z,SPL2C
	@@FSPEC			;  if user entered none
SPL2C	LD	HL,SPLEXT	;Default ext to SPL
	@@FEXT
	POP	AF		;Rcvr line pointer
	POP	HL
	CP	':'		;Drive entered?
	JR	NZ,GETPRM
SPL3	LD	A,(DE)		;Wait for ETX or EOL
	CP	CR
	JR	Z,SPL4
	CP	3
	JR	Z,SPL4
	INC	DE
	JR	SPL3
SPL4	LD	A,':'		;Stuff colon for drive
	LD	(DE),A
	INC	DE
	LD	A,(HL)		;P/u possible drive #
	CP	CR
	JP	Z,PRMERR	;Parm error if EOL
	INC	HL
	LD	(DE),A		;Stuff drive #
	INC	DE
	LD	A,3
	LD	(DE),A		;Stuff ETX
;
;	Get parameter entries
;
GETPRM	LD	DE,PRMTBL$	;Get parms
	@@PARAM
	JP	NZ,PRMERR	;Jump on parm error
;
;	Check on OFF
;
OPARM	LD	DE,0		;P/u off parm
	INC	E		;On or off?
	JP	Z,SPLOFF	;Jump if OFF
;
;	Check on RESUME despooling
;
RPARM	LD	DE,0		;P/u Resume parm
	INC	E		;Was it used?
	JP	Z,RESUME	;Go if so
;
;	Check on PAUSE
;
PPARM	LD	DE,0		;P/u Pause parm
	INC	E		;Was it used?
	JP	Z,PAUSE		;Go if so
;
;	Check on CLEAR
;
CPARM	LD	DE,0		;P/u Clear parm
	INC	E		;Was is used?
	JP	Z,CLEAR		;Go if so
;
;	Assume request to be to install
;
	BIT	0,(IY+'C'-'A')	;Can't insert spool if
	JP	NZ,CANT		;  memory frozen
	BIT	0,(IY+'D'-'A')	;Is spooler already on?
	JP	NZ,SPLONM	;Quit if so
;
;	If module resident, ck parm sizes
;
	LD	DE,SPOOL$
	@@GTMOD
	JR	NZ,FNDDCB	;Go if no area in mem
	LD	L,(IX+4)	;Prev. MPARM
	LD	H,(IX+5)
	LD	DE,(MPARM+1)
	OR	A
	SBC	HL,DE		;Old must = new
	JP	NZ,PRMBGM	;Abort if bad
	LD	L,(IX+6)	;D parm
	LD	H,(IX+7)
	LD	DE,(DPARM+1)
	SBC	HL,DE
	JP	NZ,PRMBGM	;Abort if not same as old
	LD	A,(IX+10)	;Bank #
	AND	07FH		;Strip hi bit
	LD	HL,(BPARM+1)
	CP	L
	JP	NZ,PRMBGM	;Abort if not same as old
;
;	Find device to spool
;
FNDDCB	LD	DE,(SPLDCB+1)	;P/u device name
	@@GTDCB			;Find in device tables
	JP	NZ,IOERR	;Jump on not found
CKRTE	BIT	4,(HL)		;Routed device?
	JR	Z,CKLNK		;Bypass if not
CKRTE1	INC	L		;Pt to vector
	LD	A,(HL)		;P/u vector DCB address
	INC	L		;  & test it
	LD	H,(HL)
	LD	L,A
	JR	CKRTE
CKLNK	BIT	5,(HL)		;If linked, get DCB
	JR	NZ,CKRTE1
	BIT	6,(HL)		;If filtered, trace to
	JR	Z,SETDVR	;  its DCB in header
	LD	D,H		;Save to ck inactive
	LD	E,L
	INC	L
	LD	A,(HL)		;Get vector to module
	INC	L
	LD	H,(HL)
	LD	L,A
	LD	BC,4		;HL now points to the
	ADD	HL,BC		;  entry point. Get its
	LD	C,(HL)		;  DCB address by peeking
	INC	C		;  past the name field
	ADD	HL,BC
	LD	A,(HL)		;Get low-order
	INC	HL
	LD	H,(HL)		;Get hi-order
	LD	L,A
	PUSH	HL		;If DCB is itself, then
	SBC	HL,DE		;  it's some error
	POP	HL		;  else continue to
	JR	NZ,CKRTE	;  search the chain
	JP	BADDCB
;
;	Found the device
;
SETDVR	BIT	1,(HL)		;Device handle @PUT?
	JP	Z,BADDCB	;Can't do if not
	LD	(MODDVR),HL	;Stuff DCB table address
;
;	Check BANK spec for availability
;
BPARM	LD	BC,0		;Pick up the bank #
	LD	A,C		;If bank=0, no need
	OR	B		;  to test for
	JR	Z,LOCDCB	;  availability
	CP	8		;This version supports
	JP	NC,PRMERR	;  banks 0-7
	SET	7,A		;Set for transfer
	LD	(BANKX1),A	;Stuff for module A
	LD	(BANKX2),A
	LD	(BANKX3),A
	LD	(SPLBNK),A
	LD	B,2		;Test if bank 1-x
	@@BANK			;  is available
	JP	NZ,INUSE	;Quit if not available
;
;	Locate a spare DCB for the spool module
;
LOCDCB	LD	DE,0
	@@GTDCB
	LD	A,33		;Init "No device space...
	JP	NZ,IOERR	;Go if no spare DCBs
	LD	(S0DCB),HL	;Save pointer
	LD	(S0DCB1),HL
	PUSH	HL		;Save DCB field pointer
	LD	DE,'/S'		;Let's find a link name
NAMLP	INC	D		;Bump "2nd" character
	@@GTDCB			;If we find this name
	JR	Z,NAMLP		;  look for another
	POP	HL		;Get DCB pointer
	SET	3,(HL)		;NIL in case of error
	LD	BC,6
	ADD	HL,BC		;Point to name field
	LD	(HL),E		;  & stuff in the
	INC	L		;  selected spool name
	LD	(HL),D
;
;	Create a disk file for spooling
;
	LD	DE,(DPARM+1)	;P/u disk size
	LD	(IX+6),E	;Save DPARM for next time
	LD	(IX+7),D	;  SPOOL is entered
	LD	A,D
	OR	E
	JR	Z,PUHIGH	;No file if DISK=0
	LD	DE,SPLFCB	;Init the spool file
	LD	HL,BUFFER
	SET	0,(IY+'S'-'A')	;Init file open bit
	@@INIT
	JP	NZ,IOERR	;Jump on init error
DPARM	LD	BC,4		;D parm (default=4K)
	LD	A,B		;Parm error if > 4095K
	AND	0F0H
PRMERRA	JP	NZ,PRMERR	;Go if too big a file
	SLA	C		;Multiply K by 4
	RL	B		;  to calculate sectors
	SLA	C
	RL	B
	LD	(IPLDSK1+1),BC	;Stuff disk K
	DEC	BC		;Adjust for 0 offset
	@@POSN			;Position to end
	@@WRITE			;Write a junk sector
	JP	NZ,IOERR	;Jump on write error
	@@REW			;Restore file to 0
	@@WEOF			;End of file mark
	LD	BC,(SPLFCB+6)	;P/u DEC & drive
	@@DIRRD			;Read its dir record
	JP	NZ,IOERR	;Quit on read error
	INC	HL		;Point to DIR+1
	SET	7,(HL)		;Turn on CREATE bit
	@@DIRWR			;Write dir back
	JP	NZ,IOERR	;Jump on error
	LD	HL,LOWBUF$	;Revise I/O buffer
	LD	(SPLFCB+3),HL	;  in file's FCB
;
;	Get current HIGH$
;
PUHIGH	LD	HL,0		;Set HLB to zero to
	LD	B,L		;  fetch HIGH$
	@@HIGH$
	LD	(GBUF1+1),HL	;Save for later
	LD	(OLDHI+1),HL
;
;	If bank RAM, recalculate MPARM
;
	LD	A,(BPARM+1)	;Alternate banks requested?
	OR	A
	JR	Z,MPARM		;Go if not
;
;	Recalculate MEM parameter to use the
;	Maximum space in bank RAM. Formula is
;	[((32768 - 512 for module) - ((DPARM+1)*16)]
;	Divided by 260. The 260 is derived from
;	256-byte page plus 4-bytes for pointers.
;	Then revise to K from pages.
;
	LD	HL,(DPARM+1)
	INC	HL		;Bump by 1
	ADD	HL,HL		;Times 16
	ADD	HL,HL
	ADD	HL,HL
	ADD	HL,HL
	LD	C,L		;Xfer to BC for subtract
	LD	B,H
	LD	HL,32768-512	;RAM space - module space
	XOR	A		;The remainder is for
	SBC	HL,BC		;  MEM pages and ptrs
	SRL	H		;A divide by 260 is
	RR	L		;  accomplished by
	LD	C,260/2		;  div 2 and div 130
	@@DIV16
	LD	C,L
	LD	B,H
	SRL	C		;Calculate
	SRL	C		;  K = pages / 4
	JR	CALCPTR
;
;	Calculate memory buffer space requested
;
MPARM	LD	BC,1		;MEM parm - default 1K
	LD	A,B		;Test entry - must be
	OR	A		;< 33K
	JR	NZ,PRMERRA	;Hi-order must = 0
	CP	C		;MEM = 0 ?
	JP	Z,PRMERR	;Yes - Parameter Error
	LD	A,H		;Get hi-order HIGH$
	SUB	81H		;Can't go below 8000H
	RRA			;Divide by 2
	SRL	A		;  & again to calc K
	SUB	C		;Reduce by K of req
	JP	C,PRMERR	;Error if goes < 8000H
CALCPTR	LD	(IX+4),C	;Stuff MEM parm into
	LD	(IX+5),B	;  save area
;
;	Add memory buffer space to disk space
;
	LD	HL,(DPARM+1)	;P/u disk K
	ADD	HL,BC		;Calculate pointer
	ADD	HL,HL		;  buffer space required
	ADD	HL,HL		;  (D+M)*16 + 4 extra
	INC	HL		;  used to detect the end
	ADD	HL,HL
	ADD	HL,HL
;
;	Retrieve high memory space for buffers
;
	PUSH	HL
	LD	L,(IX+0)	;P/u saved HIGH$ entry
	LD	H,(IX+1)
	LD	A,L		;If <> 0, then SPOOL
	OR	H		;  is resident
	JR	NZ,GBUF2
GBUF1	LD	HL,$-$		;P/u current high
	LD	(IX+0),L	;Save the value
	LD	(IX+1),H
GBUF2	LD	(SVEND+1),HL	;Stuff highest byte used
;
;	If bank RAM used, reset to X'FFFF'
;
	INC	HL		;Pt to lower 256
	LD	L,0		;  byte block boundary
	LD	A,(BPARM+1)	;Bank specified?
	OR	A
	JR	Z,$+3		;Jump if not
	LD	H,L		;Set to FFFF+1 = 0
	LD	C,A		;Reside bank for
	LD	B,0		;  module B
	@@BANK
	JP	NZ,IOERR	;Quit on bank error
	LD	A,(IX+4)	;P/u MEM parm
	RLCA			;MEM * 4 = # of
	RLCA			;  256-byte blocks
	LD	B,A		;Go back that number
	NEG			;  of blocks needed
	ADD	A,H		;HL now reserves buffer
	LD	H,A		;  blocks for MEM
	LD	(PUTNXT$),HL	;Stuff pointers to begin
	LD	(GETNXT$),HL	;  of memory blocks
	LD	C,H
	POP	DE		;Get (D+M)*16+4
	XOR	A		;Backup the # of D+M
	SBC	HL,DE		;  sectors
;
;	Initialize the memory pointers
;
	PUSH	HL		;Save pointer
IPLMEM	LD	(HL),0		;Init the 4-byte fields
	INC	HL		;  for each of the disk &
	LD	(HL),0		;  memory block pointers
	INC	HL
	LD	(HL),C		;Stuff memory hi-order
	INC	HL
	LD	(HL),0
	INC	HL
	INC	C		;Bump memory hi-order
	DJNZ	IPLMEM
;
;	Initialize the disk pointers
;
IPLDSK1	LD	DE,0		;P/u # of disk sectors
	LD	A,D
	OR	E
	JR	Z,IPLDSK3	;Bypass if none
	LD	BC,0		;Set up a disk pointer
IPLDSK2	LD	(HL),0		;  for each disk block
	INC	HL
	LD	(HL),0
	INC	HL
	LD	(HL),C		;Stuff block number
	INC	HL
	LD	(HL),B
	SET	7,(HL)		;Set bit 7 to indicate
	INC	HL		;  this pntr is for disk
	INC	BC		;Inc block number
	DEC	DE
	LD	A,D		;Test if finished
	OR	E
	JR	NZ,IPLDSK2	;Loop if not
IPLDSK3	LD	(HL),0		;One more used to
	INC	HL		;  indicate the end
	LD	(HL),0		;  of the pointer fields
	INC	HL
	LD	(HL),0FFH
	INC	HL
	LD	(HL),0FFH
	POP	HL		;Rcvr start of pointers
	PUSH	HL
	LD	(MAPPTR$),HL	;  & stuff for later use
	LD	(PUTBLK$),HL
	LD	(GETBLK$),HL
	LD	A,H		;Stuff 1st MEM block ptr
	LD	(HL),L		;  with table addr
	INC	HL
	LD	(HL),A
;
;	Modify driver for spooling device vector address
;
	LD	A,(IY+KITSK@)	;Transfer device hook
	LD	L,(IY+KITSK@+1)
	LD	H,(IY+KITSK@+2)
	LD	(GETBLK0),A
	LD	(GETBLK0+1),HL
	PUSH	IY		;Set up address
	POP	DE		;  in despooler
	LD	HL,'P'-'A'	;PFLAG use to
	ADD	HL,DE		;  determine if spooler
	LD	(DFLAG),HL	;  is Paused
	LD	(DFLAG1),HL
	POP	BC		;Start of MEM block tbl
	DEC	BC		;Get last byte to use
	PUSH	BC
	LD	DE,DVRBEND	;Point to module B
	LD	HL,RELTABB	;Point to table
	CALL	RELO		;Relocate absolute refs
;
;	If bank 0, then wipe out module A
;
	LD	A,(BPARM+1)	;Alternate bank used?
	OR	A
	JR	NZ,MOVMODB	;Skip next if so
	LD	HL,FIX1		;Shift in JPs for the
	LD	DE,PUTCHAR	;  bank transfer
	LD	BC,5		;  linkage
	LDIR
	LD	DE,FIX2UP
	LD	C,5
	LDIR
	LD	DE,GETBLK
	LD	C,5
	LDIR
MOVMODB	POP	DE		;Get last byte to use
	LD	HL,DVRBEND	;Last byte of module
	LD	BC,DVRBEND-DVRBBGN+1
	LDDR
	PUSH	DE		;New last byte
;
;	Switch to bank 0 always
;
	LD	BC,0		;Set function 0, bank 0
	@@BANK
	JP	NZ,IOERR	;Quit on bank error
	POP	BC
;
;	If module B is in bank x, switch HIGH for A
;
	LD	A,(BPARM+1)	;P/u alternate bank resp.
	OR	A
	JR	Z,STORHI	;Go if none used
	LD	C,A		;Reserve the bank
	LD	B,3		;Set function # 3
	@@BANK
	JP	NZ,IOERR	;Quit on bank error
	LD	BC,(SVEND+1)	;P/u bank-A HIGH$
STORHI	PUSH	BC
;
;	Relocate absolute addresses in module A
;
	LD	DE,DVRAEND	;Point to last used in A
	LD	HL,RELTABA	;Point to relo table
	CALL	RELO		;Relocate absolute refs
	POP	DE		;Get last byte to use
	LD	HL,DVRAEND	;Last byte of module
	LD	BC,DVRAEND-DVRABGN+1
	LDDR
	LD	HL,PRMSAV+2-DVRABGN+1
	ADD	HL,DE		;Data area in himem
	LD	(HL),E
	INC	HL
	LD	(HL),D		;Save high$ there
;
;	Stuff new HIGH$
;
OLDHI	LD	HL,$-$		;P/u old HIGH$
	SBC	HL,DE		;Check if old HIGH$ is
	JR	C,NOSET		;  already lower
	EX	DE,HL		;New HIGH$ to HL
	@@HIGH$			;Stuff new HIGH$
	EX	DE,HL
NOSET	INC	DE		;Point to module start
	LD	HL,(S0DCB)	;P/u module DCB pointer
	LD	(HL),46H	;  & set to filter
	INC	HL		;Pt to DCB vector pos
	LD	(HL),E		;Put entry point of
	INC	HL		;  module into DCB
	LD	(HL),D
	LD	DE,DSPLTCB	;Calculate entry point
RX05	EQU	$-2
	LD	C,9		;This will be task 9
	@@ADTSK
	LD	HL,GETBLK	;Now update device hook
RX06	EQU	$-2
;
;	Interface to KITSK - No need to DI/EI
;	As KITSK not used by interrupts
;
	LD	(IY+KITSK@+2),H	;Move in device 
	LD	(IY+KITSK@+1),L	;  vector and a
	LD	A,0C3H		;  JP opcode
	LD	(IY+KITSK@),A
	SET	0,(IY+'D'-'A')	;Turn on device flag bit
	SET	7,(IY+'P'-'A')	;Show not paused
;
;	Filter the specified device driver
;
	LD	HL,(MODDVR)	;Ptr to device DCB
	LD	DE,(S0DCB)	;Ptr to spooler DCB
	LD	B,3
	DI			;Interrupts off during swap
SWAP	LD	C,(HL)		;Swap first 3 bytes
	LD	A,(DE)
	LD	(HL),A		;  of the DCBs
	LD	A,C
	LD	(DE),A
	INC	L		;Bump DCB pointers
	INC	E
	DJNZ	SWAP		;Loop 3 times
	EI
	JP	SPLACT		;Set complete
;
;	Routine to PAUSE despooling
;
PAUSE	BIT	0,(IY+'D'-'A')	;Spool resident?
	JP	Z,SPLOFM	;Quit if not
	BIT	7,(IY+'P'-'A')	;Ck first if active
	RES	7,(IY+'P'-'A')	;  then turn off
	JP	Z,SPLOPM	;Quit if already paused
	JP	PAUSED
;
;	Routine to RESUME despooling
;
RESUME	BIT	0,(IY+'D'-'A')	;Ck first if resident
	JP	Z,SPLOFM	;Quit if not
	BIT	7,(IY+'P'-'A')	;See if despooling now
	SET	7,(IY+'P'-'A')
	JP	NZ,SPLONM	;Can't resume if so
	JP	RESUMD
;
;	Routine to turn off the spooler
;
SPLOFF	BIT	0,(IY+'D'-'A')	;Test if off already
	JP	Z,SPLOFM	;Go if off now
	LD	DE,SPOOL$	;Find out where spooler
	@@GTMOD
	JP	NZ,NOFIND	;Quit if not there
	RES	0,(IY+'D'-'A')	;  else turn off
	RES	7,(IY+'P'-'A')	;Show paused also
	LD	BC,GETBLK0-DVRABGN
	ADD	HL,BC		;Point to KITSK@ swap
	LD	A,(HL)
	LD	(IY+KITSK@),A	;Restuff KIHOOK
	INC	HL
	LD	A,(HL)
	LD	(IY+KITSK@+1),L
	INC	HL
	LD	A,(HL)
	LD	(IY+KITSK@+2),A
	LD	C,9		;Remove task 9 from
	@@RMTSK			;  the task processor
;
;	Attempt to reclaim memory space
;
	LD	HL,0		;Get current HIGH$
	LD	B,L
	@@HIGH$
	LD	E,(IX+2)	;Get HIGH$ after spool
	LD	D,(IX+3)	;  was installed
	XOR	A
	SBC	HL,DE		;Is it the same now?
	LD	E,(IX+0)	;Get HIGH before res
	LD	(IX+0),A	;  & clear data
	LD	D,(IX+1)
	LD	(IX+1),A
	LD	HL,NOMEM$	;Init "Can't reclaim...
	JR	NZ,LOGMEM	;Go if HIGH$ different
	EX	DE,HL		;  else release memory
	@@HIGH$			;  by resetting HIGH$
	LD	HL,GOTMEM$	;"Memory released
LOGMEM	@@LOGOT
;
;	De-use any RAM bank
;
	LD	A,(IX+10)	;P/u bank used
	AND	7		;Strip 3-7
	JR	Z,RESDCB	;Jump if only bank 0
	LD	C,A		;Save bank in C
	OR	'0'		;Convert to ASCII for dsply
	LD	(FREBNK$+5),A	;Stuff in message
	LD	B,1		;Function to reset BUR$
	@@BANK			;Free the bank
	LD	HL,FREBNK$	;Init"Bank released
	@@LOGOT
;
;	RESET the device
;
RESDCB	LD	HL,$-$
SVDCB	EQU	$-2		;Point to SPOOL DCB ptr
	LD	E,(HL)		;  & get the DCB ptr
	INC	HL		;  into reg DE
	LD	D,(HL)
;
;	Check if DCB is inactive [user RESET *PR]
;
	PUSH	DE		;Save DCB pointer
	INC	E
	LD	A,(DE)		;Get DCB vector contents
	LD	C,A		;  into reg BC
	INC	E
	LD	A,(DE)
	LD	B,A
	POP	DE		;Recover DCB pointer
	LD	HL,$-$		;P/u start of module
SVBGN	EQU	$-2
	XOR	A		;If vector points to
	SBC	HL,BC		;  start of module,
	RET	Z		;  we are finished
	LD	L,(IX+8)	;P/u DCB being spooled
	LD	H,(IX+9)
	EX	DE,HL		;SPOOL to HL,
	LD	B,3		;  device to DE
	DI
SWAP1	LD	A,(HL)		;Undo the SPOOLer
	LD	(HL),0		;  by swapping back the
	LD	(DE),A		;  original vector and
	INC	L		;  zeroing the spool DCB
	INC	E
	DJNZ	SWAP1
	INC	L		;Point to name field
	INC	L		;  & wipe it out
	INC	L
	LD	(HL),0
	INC	L
	LD	(HL),0
	EI
	RET			;Done - return
;
;	Routine to CLEAR the SPOOL buffer
;
CLEAR	BIT	0,(IY+'D'-'A')	;Spool active?
	JP	Z,SPLOFM	;Go if not active
	LD	IX,$-$		;Parms in himem
HIPARM	EQU	$-2
	LD	L,(IX+11)	;P/u SPLFCB pointer
	LD	H,(IX+12)
	LD	C,(IX+10)	;P/u RAM bank used
	RES	7,C		;Set on xfer to bank
	LD	B,0		;Function to load bank
	DI			;Interrupts off now
	@@BANK
	PUSH	BC		;Save old bank
	PUSH	HL		;Xfer FCB pointer
	POP	IX		;  to IX
	LD	L,(IX+24H)	;Get LINK map pointer
	LD	H,(IX+25H)
	PUSH	HL
CLEAR1	LD	(HL),0		;Reset every link
	INC	HL
	LD	(HL),0
	INC	HL		;Bypass page pointer
	INC	HL
	LD	A,(HL)		;Ck for TABEND
	INC	HL
	INC	A		;End if it was X'FF'
	JR	NZ,CLEAR1
	POP	HL		;Point to LINK start
	LD	(IX+26H),L	;Reset PUTBLK$
	LD	(IX+27H),H
	LD	(IX+28H),L	;Reset GETBLK$
	LD	(IX+29H),H
	LD	A,H		;Show 1st LINK position
	LD	(HL),L		;  is the "last" one by
	INC	HL		;  loading it to point
	LD	(HL),A		;  to itself
	INC	HL		;P/u the page pointer
	LD	B,(HL)
	LD	(IX+21H),B	;Stuff PUTNXT$
	LD	(IX+20H),0
	LD	(IX+23H),B	;Stuff GETNXT$
	LD	(IX+22H),0
	POP	BC		;Reload previous bank
	@@BANK
	EI
	JP	CLEARD
;
;	Relocate internal references in driver
;	HL = relocation table
;	DE = pointer to last byte of module
;	BC = pointer to last RAM byte to use
;
RELO	PUSH	IX		;Save index reg
	PUSH	HL		;Xfer rel tab pointer
	POP	IX
SVEND	LD	HL,$-$		;P/u last byte used
	LD	(DVRABGN+2),HL	;  & stuff into module
	LD	H,B		;Xfer last byte to
	LD	L,C		;  use to HL
	XOR	A		;Clear carry flag
	SBC	HL,DE
	LD	B,H		;Move to BC
	LD	C,L
	LD	A,(IX)		;Get table length
	INC	IX
RLOOP	LD	L,(IX)		;Get address to change
	LD	H,(IX+1)
	LD	E,(HL)		;P/U address
	INC	HL
	LD	D,(HL)
	EX	DE,HL		;Offset it
	ADD	HL,BC
	EX	DE,HL
	LD	(HL),D		;And put back
	DEC	HL
	LD	(HL),E
	INC	IX
	INC	IX
	DEC	A
	JR	NZ,RLOOP	;Loop till done
	POP	IX
	RET
;
NOFIND$	DB	'Can''t locate SPOOL in memory',CR
CLEARD$	DB	'SPOOL buffer cleared',CR
PAUSED$	DB	'Despooling now paused',CR
RESUMD$	DB	'Despooling now resumed',CR
SPLOFM$	DB	'Spooler is not active',CR
SPLONM$	DB	'Spooler is already active',CR
SPLOPM$	DB	'Spooler already active but paused',CR
PRMBGM$	DB	'Cannot reinstall with altered parameters',CR
SPLACT$	DB	'Spooler is now operational',CR
NOMEM$	DB	'Can''t reclaim memory space',CR
GOTMEM$	DB	'Memory space reclaimed',CR
FREBNK$	DB	'Bank x released',CR
INUSE$	DB	'Requested bank in use',CR
CANT$	DB	'No memory space available',CR
BADDCB$	DB	'Device driver incompatible',CR
SPLDCB	DS	32
DSKSPC	DB	'XX/'
SPLEXT	DB	'SPL',3
PR$	DB	'*PR',ETX
;
PRMTBL$	DB	'R'!80H		;6.x table format
VAL	EQU	80H
SW	EQU	40H
STR	EQU	20H
SGL	EQU	10H
	DB	VAL!SGL!3,'MEM',0
	DW	MPARM+1
	DB	VAL!SGL!4,'DISK',0
	DW	DPARM+1
	DB	SW!3,'OFF',0
	DW	OPARM+1
	DB	SW!1,'N',0
	DW	OPARM+1
	DB	VAL!SGL!4,'BANK',0
	DW	BPARM+1
	DB	SW!SGL!5,'PAUSE',0
	DW	PPARM+1
	DB	SW!SGL!6,'RESUME',0
	DW	RPARM+1
	DB	SW!SGL!5,'CLEAR',0
	DW	CPARM+1
	NOP
;
	ORG	$<-8+1<8
BUFFER	DS	256
	PAGE	OFF
;
*GET	LBSPOOLB:3
;
	END	SPOOL
