;HDWD2/ASM - WD installation system - 06/10/84
	SUBTTL	'<Driver Initialization Routines>'
;
;*=*=*
;Entry point after initial tests
;Set IY=>correct DCT type
;*=*=*
USER	LD	IY,DCTAB
;*=*=*%
;       Request physical drive slot first
;*=*=*
	JR	PRMPT4
GETDRV	CALL	ABTJCL
PRMPT4	LD	HL,DRIVE$	;Request physical drive#
	CALL	GETARG		;Display & get argument
	SUB	'1'		;Convert to binary (0-3)
	JR	C,GETDRV	;Re-request if bad range
	CP	3+1		;Check max value
	JR	NC,GETDRV	;Re-request if bad range
;*=*=*
;       Stuff the drive select address into DCT
;*=*=*
;       Merge the drive address
	OR	(IY+DRVSEL)	;  into the standard
	LD	(IY+DRVSEL),A	;  DCT parameters
;*=*=*
; see if drive type has been established
;*=*=*
	CALL	FNDOLD
	JR	NZ,PRMPT1	;1st installation of drive
	LD	A,(IX+5)	;IX=>existing DCT
	LD	(IY+5),A	;Propagate to this one
	AND	00000111B
	CALL	LDMAX		;Set max heads
	LD	A,(IX+6)	;Cyl count
	LD	(IY+6),A	;Set it
	SRL	A		;Dir cyl in center
	LD	(IY+9),A
	BIT	5,(IX+4)	;Double?
	JP	Z,STMP
	SET	5,(IY+4)	;Set to match
	JP	STMP		;Now map heads in-use
;*=*=*
;       Request drive type information
;*=*=*
GTMAXHD	CALL	ABTJCL		;Unless re-prompt
PRMPT1	LD	HL,HDS$
	CALL	GETARG		;Prmpt/get 1 char
	SUB	'1'
	JR	C,GTMAXHD	;Must be at least 1
	CP	8		;Not over 8
	JR	NC,GTMAXHD
	LD	(IY+5),A	;Store total entry
	CALL	LDMAX		;Store away
;*=*=*
; request total tracks on drive
;*=*=*
	JR	PRMPT2
GTTRKS	CALL	ABTJCL
PRMPT2	LD	HL,TRK$		;Prompt
	LD	B,3
	CALL	GETARGX		;Get b chars
	CALL	DECHEX		;Make decimal in BC
	PUSH	BC		;Save the trk count
	LD	HL,09		;Bump up for rounding
	ADD	HL,BC
	LD	C,8		;Divide by 8 now
	@@DIV16			; do it
	LD	A,L
	LD	HL,PCPTRK+1	;Point to out instr.
	LD	(HL),A		;Put value there
	POP	BC		;Recover the entry
	LD	HL,MINTRK-1
	OR	A
	SBC	HL,BC
	JR	NC,GTTRKS	;If too small
	LD	HL,MAXTRK
	OR	A
	SBC	HL,BC
	JR	C,GTTRKS
	LD	HL,203		;Max w/o double trking
	OR	A
	SBC	HL,BC
	JR	NC,SETTRK
	SET	5,(IY+4)	;Set double bit
	SRL	B		;Divide by 2
	RR	C
SETTRK	LD	A,C
	DEC	A		;Offset fm 0
	LD	(IY+6),A	;Store high Trk #
	SRL	C		;Div by 2
	LD	(IY+9),C	;Dir cyl in center
;
	LD	A,(RESNUM)	;Driver resident?
	OR	A
	JR	NZ,STMP		;Skip step rate if loaded
;*=*=*
;Request drive step rate
;*=*=*
	JR	PRMPT3
GTSTP	CALL	ABTJCL
PRMPT3	LD	HL,STP$
	LD	B,3
	CALL	GETARGX
	CALL	PARSENM		;Conv to step rate bits
	JR	NZ,GTSTP	;If bad entry
	LD	C,A
	CP	00000110	; 3.0 mS?
	JR	NC,FASTOK	;If 3 or less leave 1st cmd
	LD	A,(STP1)	;Chg if >3.0
	AND	11110000B	;Leave command
	OR	C		;Merge step rate bits
	LD	(STP1),A
FASTOK	LD	A,(STP2)
	AND	11110000B	;P/u command
	OR	C		;Merge step
	LD	(STP2),A
;
STMP	CALL	SETMAP		; map out heads in use
;*=*=*
;Request heads for partition
;*=*=*
	JR	PRMPT5
REQHD	CALL	ABTJCL
PRMPT5	LD	HL,HEADMP$	;Show in-use
	CALL	@DSPLY
	LD	HL,HEADS$	;Get number for partition
	CALL	GETARG
	SUB	'1'		;Adjust to binary
	JR	C,REQHD		;Must be > 0
	CP	(IY+0)		;Free heads left
	JR	NC,REQHD	;User exceed max?
	INC	A		;Make real
	LD	C,A
	LD	(NUMHDS),A	;Store number for later
	DEC	A		;Offset fm 0
	RRCA			;Shift to 5-7
	RRCA
	RRCA
	LD	B,A		;Save # of heads
	LD	A,(IY+7)	;P/u # of heads in tab
	AND	1FH		;Strip what's there
	OR	B		;Merge # of heads
	LD	(IY+7),A	;Update DCT$+7 init
;*=*=*
;       Calculate proper Sectors Per Granule (SPG)
;       and Grans per cylinder
;*=*=*
	LD	A,C		;Number of heads
	ADD	A,A		;Double # for GPC
	LD	D,15		;Sec/gran (-1)
	LD	E,8+1		;Use 16 sec/gran w/4 heads
	BIT	5,(IY+4)	;Unless dbl bit is set
	JR	Z,UPTO4
	LD	E,4+1		;Then 2 is max
UPTO4	CP	E		;More than max heads (x2)?
	JR	C,G1		;16 sec grans OK if less
	LD	D,31		;Else 32 sec/gran
	LD	A,C		;And GPC will be = # heads
;D=sec/gran A=#heads*2 if 2 grans/trk or # if 1 gran/trk
G1	DEC	A		;GPC offset fm 0
	RRCA
	RRCA
	RRCA			;Roll to bits 5-7
	OR	D		;Merge sec/gran
	LD	(IY+8),A	; put in DCT
;
	LD	A,(MAXHDS)	;Total available
	SUB	C		;ALL requested?
	JR	Z,PUTRHD	;0 =start head
;*=*=*
;       If not all heads requested, get starting head
;*=*=*
	JR	PRMPT6
REQSHD	CALL	ABTJCL		;Quit if JCL
PRMPT6	LD	HL,STRTHD$
	CALL	GETARG
	SUB	'1'		;In range?
	JR	C,REQSHD
	LD	C,A		;Save start head
	PUSH	BC
	CALL	FREE		;Are these heads in use
	POP	BC
	JR	NZ,REQSHD	;Get again if bad
;*=*=*
;
	LD	A,C		;P/u starting head
PUTRHD	OR	(IY+4)		;Merge user's start
	LD	(IY+4),A	;Update init DCT$+4
;*=*=*
	CALL	INSTALL
	JP	@EXIT
;*=*=*
;Convert ASCII step rate entry to WD bit field
;*=*=*
PARSENM	LD	D,0		;Clear for ans
CHAR	LD	A,(HL)		;Read one
	INC	HL		;=>next
	CP	'.'		;Decimal
	JR	Z,POINT		;Go if found
	CP	CR
	JR	Z,ISCR		;End of line
	SUB	'0'		;Make BCD 0-7
	RET	C		;Out of range
	CP	7+1		;7.5 is high number except 10
	JR	NC,RNGERR
	LD	E,A		;Save BCD
	LD	A,D		;Take D*10
	ADD	A,A		;X2
	ADD	A,A		;X4
	ADD	A,D		;X5
	ADD	A,A		;X10
	ADD	A,E		;+this one to catch 10.0
	JR	CHAR		;Get next char
;
POINT	LD	A,(HL)
ISCR	SLA	D		;Number x2
	CP	'5'
	JR	NZ,NT5
	INC	D
	JR	IS0
NT5	CP	'0'
	JR	Z,IS0
	CP	CR
	RET	NZ
;D=number fm 0 to 20 (2*entry)
;20 = 10 = 0000
;Otherwise range fm 1 to 15 = bit setting for WD step
;Test range
IS0	LD	A,D
	CP	20
	JR	NZ,RNG
	XOR	A
	RET			;Set 0 if 10 was entered
RNG	CP	15+1
	JR	NC,RNGERR	;Bad entry if >15
	CP	A		;Set Z
	RET
RNGERR	OR	0FFH		;Set NZ
	RET
;*=*=*
;Stuff max heads on drive A=numb offset fm 0
;*=*=*
LDMAX	RRCA			;Roll to bits 7-5
	RRCA
	RRCA
	LD	C,A
	LD	A,(IY+7)	;Merge
	AND	00011111B
	OR	C
	LD	(IY+7),A	;Store max heads
	RET
;*=*=*
;Driver dependent strings
HELLO$	DB	LF
	DB	'TRSHD6b - WD 1000/1010 - Winchester Disk Driver',LF
	DB	'Version'
*GET	CLIENT:3
HDS$	DB	'Enter total number of heads'
	DB	' on drive <1-8> ',3
TRK$	DB	'Enter physical tracks per surface: ',3
STP$	DB	'Enter step rate for drive: ',3
DRIVE$	DB	'Enter drive select address <'
	DB	'1-4> ',3
;
;******************************************
;Common subroutines for hard disk drivers
;*******************************************
;*=*=*
;       Routine to set a bit in head map
;*=*=*
SETBIT	RLCA			;Shift to "b" field
	RLCA
	RLCA
	OR	0C3H		;Establish as SET b,E
	LD	(SBIT1+1),A	;Alter the OP code
SBIT1	SET	0,E		;Map the head bit
	RET
;*=*=*
;       Routine to test if bit is set in head map
;*=*=*
BITBIT	RLCA
	RLCA
	RLCA
	OR	43H		;Construct BIT b,E
	LD	(BBIT1+1),A
BBIT1	BIT	0,E
	RET
;*=*=*
; get total heads and cyl count if an existing driver is
; found for this drive select address
FNDOLD	LD	A,(RESNUM)	;Get number of DCTs
	OR	A		;Using this driver
	JR	Z,NTHERE	;If none, prompt
	LD	B,A		;Number to B
	LD	HL,DCTPTR	;=>list of addresses
OLDLP	LD	E,(HL)		;P/u DCT address
	INC	HL
	LD	D,(HL)		;DE=>DCT
	INC	HL		;=>next pointer
	PUSH	DE
	POP	IX		;IX=>DCT
	LD	A,(IX)		;Don't use any drive
	CP	0C9H		;  that's disabled
	JR	Z,SKPTHS
	LD	A,(IX+DRVSEL)	;Check if this matches
	AND	3		;  the drive #
	LD	C,A		;P/u drive requested
	LD	A,(IY+DRVSEL)
	AND	3		;Check if same
	CP	C		;Match up yet?
	RET	Z		;IX=>DCT for same disk
SKPTHS	DJNZ	OLDLP		;Check the rest
NTHERE	OR	0FFH		;Force NZ
	RET
;*=*=*
;SETMAP
;IY=>New DCT containing Drive address in bits 0-2 of IY+3
;IY+7 = max heads possible in bits 5-7
;Sets up Heads in use message
;Sets IY+1&2 to existing driver address if found
;Sets used bits in (BITMAP)
;Sets (MAXHDS) = total heads
;Sets IY+0 = free heads
;*=*=*
;       P/u # of heads on the drive & init checks
;*=*=*
SETMAP	LD	A,(IY+7)	;P/u Maximum heads
	RLCA			;Shift into 0-2
	RLCA
	RLCA
	AND	7		;Mask off Max sector #
	INC	A		;Adjust for zero offset
	LD	(MAXHDS),A	;Save for later
	LD	B,A
;*=*=*
;       Adjust heads in use message
;*=*=*
	LD	HL,INUSE$
	LD	A,8
	SUB	B		;Calc index into msg
	JR	Z,GOT8HDS
	LD	B,A
	PUSH	HL		;Save start of message
BLP	INC	HL		;Bump msg pointer 2
	INC	HL		;  bytes per head loss
	DJNZ	BLP
	POP	DE		;Recover start of msg
	LD	BC,HEADS$-INUSE$
	LDIR			;Reposition message
;*=*=*
GOT8HDS	LD	DE,0		;Init count & bitmap
	LD	A,(RESNUM)	;How many active
	OR	A
	JR	Z,NORES
	LD	B,A
	LD	HL,DCTPTR	;=>saved addresses
HCLP	PUSH	BC		;Save loop counter
	LD	C,(HL)
	INC	HL
	LD	B,(HL)		;P/u DCT address
	INC	HL
	PUSH	HL		;Save ptr to next entry
	PUSH	BC
	POP	IX		;Xfer to IX
	LD	A,(IX+1)	;Move address of driver
	LD	(IY+1),A	;To new DCT
	LD	A,(IX+2)
	LD	(IY+2),A
	CALL	CNTHDS		;Add 'em up
	POP	HL
	POP	BC
	DJNZ	HCLP
	LD	A,E
	LD	(BITMAP),A
;*=*=*
;  check for heads in use past entered total
;*=*=*
	LD	A,(MAXHDS)	;Entered #
	DEC	A
TSTHGH	CP	7		;Max of 8
	JR	Z,NORES		;All OK
	INC	A		;Check each past total
	LD	C,A
	CALL	BITBIT		;For in-use
	JP	NZ,BADTOT	;Abort if any
	LD	A,C
	JR	TSTHGH		;Check up to 8
;
NORES	LD	A,(MAXHDS)	;P/u maximum
	LD	L,A		;Save
	SUB	D		;Calculate the quantity
	JP	Z,NOHEAD	;Go if none remaining
;Find largest group of contiguous heads
	LD	BC,0		;Init count
	XOR	A		;Start w/0
CNTH1	LD	H,A		;Save hd posn
	CALL	BITBIT		;Head available?
	JR	Z,CNTH3		;Yes, count it
	LD	C,0		;Reset for hd in use
CNTH2	LD	A,H		;Head posn
	INC	A		;Bits are offset fm 0
	CP	L		;So matching w/maxhds
	JR	NZ,CNTH1	;Means we are done
	LD	A,B		;Get max count
	JR	GOTMX
CNTH3	INC	C		;Count free head
	LD	A,C
	CP	B		;Move highest contiguous
	JR	C,CNTH2		;Count into B
	LD	B,C		;If B was less
	JR	CNTH2
;Max of 4 heads if double tracking...
GOTMX	CP	4+1
	JR	C,SETMX		;OK if 4 or less
	BIT	5,(IY+4)	;Is double bit set?
	JR	Z,SETMX		;8 OK if not
	LD	A,4		;Else set max 4 for partition
SETMX	LD	(IY+0),A	;Save user limit
	ADD	A,'0'		;Adjust to ASCII
	LD	(HEADS1$),A	;Update the message
;*=*=*
;       Adjust heads in use message
;*=*=*
	LD	HL,INUSE$
	LD	A,'1'		;Init to head '1'
	LD	B,8
MODHD	RRC	E		;If bit set, stuff msg
	JR	NC,$+3
	LD	(HL),A		;Show head in use
	INC	HL
	INC	HL		;Bump to next pos
	INC	A		;Bump ASCII head #
	DJNZ	MODHD
	RET
;
CNTHDS	LD	A,(IX)		;Don't use any drive
	CP	0C9H		;  that's disabled
	RET	Z
	LD	A,(IX+DRVSEL)	;Check if this matches
	AND	3		;  the drive #
	LD	C,A		;P/u drive requested
	LD	A,(IY+DRVSEL)
	AND	3		;Check if same
	CP	C		;Match up yet?
	RET	NZ		;Skip if different unit
;
;       IF      ARM!ARMM
;       LD      A,(IX+5)        ;P/u the controller
;       CP      (IY+5-3)        ;  address & check
;       RET     NZ              ;  for a match
;       ENDIF
;
	LD	A,(IX+7)	;Accumulate the number
	RLCA			;  of heads already
	RLCA			;  in use
	RLCA
	AND	7
	INC	A		;Adjust for zero offset
	LD	B,A		;Set new head set loop
	ADD	A,D
	LD	D,A		;Set new total heads
;*=*=*
;       Merge bit map into E reg
;*=*=*
	LD	A,(IX+4)	;P/u starting head
	AND	0FH		;Remove other junk
SETHDS	PUSH	AF		;Save head number
	CALL	SETBIT		;Turn on reg E bit
	POP	AF		;  corresponding to #
	INC	A		;Bump head number
	DJNZ	SETHDS		;Loop for all heads used
	RET
;*=*=*
;       Test if user entry conflicts with head map
;       A=starting head #
;*=*=*
FREE	LD	C,A		;Starting # (-1)
	LD	A,(NUMHDS)	;P/u number of heads
	ADD	A,C		;Add to start posn
	LD	B,A		;Save ending hd #
	LD	A,(MAXHDS)	;P/u max heads
	CP	B		;Will last head be OK?
	JR	C,BDHD		;Go if bad entry
	LD	A,C		;Retrieve number-1
	LD	E,0		;P/u in-use head map
BITMAP	EQU	$-1
	LD	B,0		;P/u # of heads user req
NUMHDS	EQU	$-1
TSTHDS	LD	C,A		;Save for test
	CALL	BITBIT		;Head bit in use?
	LD	A,C
	JR	NZ,ISUSED	;Go if already used
	INC	A		;Bump head pointer
	DJNZ	TSTHDS		;Loop for # of heads
	XOR	A
	RET			;Z=no conflict
ISUSED	LD	HL,HDBAD$	;Show conflict
	CALL	@DSPLY
BDHD	OR	0FFH
	RET			;W/NZ for error
;
;*=*=*
;INSTALL - move driver if necessary 
; put JP into (IY)
;  move DCT=>IY into address fm (DCTADD)
;*=*=*
INSTALL	LD	(IY),0C3H	;Stuff JP
	LD	A,(RESNUM)
	OR	A		;Is a copy loaded?
	JR	NZ,ISRES	;Then don't re-load
;*=*=*
	IFDEF	LINK		;If driver has LINK defined...
	CALL	INIT		;Init drv before moving driver
;       Move @ICNFG vector into driver next
;*=*=*
	LD	IX,$-$
FLAGTB	EQU	$-2		;Saved address of table
	LD	A,(IX+28)	;Get opcode
	LD	(LINK),A
	LD	L,(IX+29)	;Get address
	LD	H,(IX+30)
	LD	(LINK+1),HL
	PUSH	IX		;Save table address
	ENDIF
;
;*=*=*
;       Relocate internal references in driver
;*=*=*
	LD	IX,RELTAB	;Point to relocation tbl
SVEND	LD	HL,$-$		;Find distance to move
	LD	(DISK+2),HL	;Set last byte used
	LD	DE,DISKEND-1
	OR	A		;Clear carry flag
	SBC	HL,DE
	LD	B,H		;Move to BC
	LD	C,L
	LD	A,TABLEN	;Get table length
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
;*=*=*
	IFDEF	LINK
;       Set up @ICNFG
;*=*=*
	POP	IX		;Get FLAGTBL
	LD	HL,INIT		;Get entry pt
	ADD	HL,BC		;Relocate it
	LD	(IX+29),L	;Init address
	LD	(IX+30),H
	LD	(IX+28),0C3H	;Stuff JP instruction
	ENDIF
;
	LD	HL,(HCPTR)	;Did it move to high$
	LD	A,H
	OR	L
	PUSH	AF		;NZ if high
;*=*=*
;       Move driver
;*=*=*
	LD	HL,(LCPTR)	;Low core pointer
	LD	E,(HL)		;P/u start address
	INC	L
	LD	D,(HL)
	PUSH	DE		;Save start
	LD	HL,DISK
	LD	BC,DISKEND-DISK	;Calc driver length
	LDIR
	LD	HL,(LCPTR)
	LD	(HL),E		;Put new free address
	INC	L
	LD	(HL),D
	POP	DE		;Entry pt
	LD	(IY+1),E	;Driver LSB
	LD	(IY+2),D	;Driver MSB
	LD	HL,HMEM$
	POP	AF		;Going high?
	JR	Z,ISRES		;Fits in low mem
	@@LOGOT			;Else tell user
;
ISRES	PUSH	IY
	POP	HL		;Prepare to move DCT
	LD	DE,(DCTADD)	;To requested position
	PUSH	DE
	LD	BC,10
	LDIR
	POP	IY		; IY=>real DCT
;*=*=*
; log in correct dir cyl if possible
;*=*=*
	LD	DE,0		;Read BOOT
	LD	HL,SECBUF
	CALL	READS		;Get if formatted
	JR	NZ,NOFMT
	LD	A,(SECBUF+2)	;Get possible dir cyl
	CP	(IY+6)
	JR	NC,NOFMT
	LD	D,A		;Dir cyl
	CALL	READS
	JR	NZ,NOFMT
	LD	A,'/'
	LD	HL,SECBUF+0DAH	;Date field
	CP	(HL)
	JR	NZ,NOFMT
	LD	HL,SECBUF+0DDH	;Second slash
	CP	(HL)
	JR	NZ,NOFMT
	LD	(IY+9),D	;Stuff correct DIR cyl..
	RET
READS	LD	B,9		;READ command
	CALL	DOIO
	RET	Z		;Normal status
	CP	6		; or DIR cyl OK
	RET
DOIO	JP	(IY)		;Do it
NOFMT	LD	HL,NOFMT$
	@@LOGOT
	RET
;
;*=*=*
;       Routine to convert ascii =>HL to number in BC
DECHEX	@@DECHEX		;Make decimal in BC
	RET
;*=*=*
;       Routine to parse user input parameter
;*=*=*
GETARG	LD	B,1
GETARGX	CALL	@DSPLY		;Display message
KEYIN	LD	HL,KEYBUF$
	LD	C,0
	@@KEYIN			;Fetch user response
	JP	C,ABTJOB
	LD	A,(HL)		;Load value
	RET
;*=*=*
;
BEGIN
	@@CKBRKC		;Check for break
	JR	Z,BEGINA	; go if not
	LD	HL,-1		;Else abort
	RET
;
BEGINA	LD	(SPSAV),SP	;Save callers stack
	LD	(DCTADD),DE	;Save passed DCT ptr
	PUSH	DE		;Save DCT address
	LD	HL,HELLO$
	CALL	@DSPLY		;Welcome the user
	@@FLAGS
	IFDEF	LINK
	LD	(FLAGTB),IY	;Save for install
	ENDIF
	LD	DE,'S'-'A'	;Find SFLAG$
	ADD	IY,DE
	LD	(SFLAG),IY	;Save address
;*=*=*
;       Check if requested drive slot is available
;*=*=*
	POP	DE
	LD	A,(DE)		;P/u vector OP
	CP	0C9H		;RET = disabled
	JP	NZ,CANTDO	;No good if not RET
;*=*=*
;Look for existing driver
;*=*=*
	LD	C,0		;Find start of DCT$
	@@GTDCT
	LD	IX,DCTPTR	;Save matching DCTs
	LD	B,8		;# of DCTs
TSTDCT	LD	L,(IY+1)
	LD	H,(IY+2)	;Point to driver vector
	PUSH	BC
	INC	HL		;  in DCT & see if res
	INC	HL		;Point to name length
	INC	HL
	INC	HL
	LD	DE,DISK+4	;Point to this namlen
	LD	A,(DE)		;P/u length & match
	CP	(HL)		;  with resident driver
	JR	NZ,NOTRES	;Go if dif lengths
	INC	HL		;Advance to name field
	INC	DE
	LD	B,A		;Set compare length
TSTNAM	LD	A,(DE)		;Match this driver to
	CP	(HL)		;  resident vector
	JR	NZ,NOTRES
	INC	DE		;Bump to next char
	INC	HL
	DJNZ	TSTNAM		;Loop for name length
;Count and save DCT posns w/same driver
	LD	A,(RESNUM)	;Get count so far
	INC	A
	LD	(RESNUM),A
	PUSH	IY
	POP	HL		;DCT address
	LD	(IX),L
	INC	IX
	LD	(IX),H
	INC	IX
;
NOTRES	LD	BC,10
	ADD	IY,BC		;Move to next DCT posn
	POP	BC		;Recover count
	DJNZ	TSTDCT		;Do all 8
;
	LD	A,(RESNUM)	;P/u count
	OR	A		;Any here?
	JP	NZ,USER		;Get input if resident
;*=*=*
;If not already loaded, find space 
;*=*=*
	LD	DE,'IK'
	@@GTDCB			;Locate pointer
	JP	NZ,IOERR
	DEC	L
	LD	D,(HL)		;P/u pointer to
	DEC	L		;  start of free
	LD	E,(HL)		;  low core
	LD	(LCPTR),HL	;Save ptr for later
	LD	HL,DISKEND-DISK-1
	ADD	HL,DE		;Start + driver length
	LD	(SVEND+1),HL
	LD	BC,1300H	;Max addr + 1
	XOR	A
	SBC	HL,BC		;If space in low mem
	JP	C,USER		;Go get input for drive
;*=*=*
;       try high memory
;*=*=*
	@@FLAGS			;IY=>info
	BIT	0,(IY+'C'-'A')	;Memory frozen?
	JR	NZ,NOROOM	;Can't
	LD	HL,0
	LD	B,L
	@@HIGH$
	LD	(SVEND+1),HL	;Save top end
	LD	BC,DISKEND-DISK
	OR	A
	SBC	HL,BC		;Minus length
	LD	B,0
	PUSH	HL
	@@HIGH$			;Is new high$
	POP	HL
	INC	HL		;+1 is start
	LD	(HCPTR),HL	;Save it
	LD	HL,HCPTR
	LD	(LCPTR),HL	;And point to it
	JP	USER
;*=*=*
;       Error exits
;*=*=*
NOROOM	LD	HL,NOROOM$
	DB	0DDH
CANTDO	LD	HL,CANTDO$
	DB	0DDH
ABTJOB	LD	HL,ABTJOB$
	DB	0DDH
NOHEAD	LD	HL,NOHEAD$
	DB	0DDH
BADTOT	LD	HL,BADTOT$
ABORTL	@@LOGOT
@ABORT	@@CKBRKC
	@@ABORT			;Use abort
QUIT	LD	SP,$-$
SPSAV	EQU	$-2
	@@CKBRKC
	RET
IOERR	LD	L,A
	LD	H,0
	OR	0C0H
	LD	C,A
	@@ERROR
	JR	@ABORT
@EXIT	LD	HL,0
	JR	QUIT
@DSPLY	@@DSPLY
	RET	Z
	JR	IOERR
; abort instead or re-prompt if JCL running
ABTJCL	PUSH	AF
	PUSH	HL
	LD	A,($-$)
SFLAG	EQU	$-2
	BIT	5,A		;JCL active?
	LD	HL,JCLAB$	;=>msg
	JR	NZ,ABORTL	;Log out
	POP	HL		;Else restore regs
	POP	AF
	RET
;*=*=*
;       Messages & Data tables
;*=*=*
HCPTR	DW	0		;Pointer if going to HIGH$
NOFMT$	DB	LF,'Note: Drive appears to be unformatted.',CR
HMEM$	DB	LF,'Note:driver installed in high memory.',CR
JCLAB$	DB	LF,'Incorrect entry from JCL.',CR
HEADMP$	DB	'Heads already in use <'
INUSE$	DB	'.-.-.-.-.-.-.-.>',CR
HEADS$	DB	'Enter number of heads for partition <1-'
HEADS1$	DB	'X> ',3
STRTHD$	DB	'Enter starting head: ',3
HDBAD$	DB	'Heads requested conflict with '
	DB	'heads in-use.',CR
NOHEAD$	DB	'No heads available on that drive.',CR
BADTOT$	DB	'Drive has heads in use higher'
	DB	' than entered total.',CR
ABTJOB$	DB	'Manual abort - Job terminated.',CR
NOROOM$	DB	'No memory space available.',CR
CANTDO$	DB	'Requested drive slot already in use.',CR
	DW	0		;Slack
MAXHDS	DB	0		;Total heads on drive
RESNUM	DB	0		;Count of DCT's using this driver
DCTPTR	DW	0,0,0,0,0,0,0	;Addresses
LCPTR	DW	0		;Save area for low mem ptr address
DCTADD	DW	0		;Address for this DCT
SECBUF	DS	256		;Use to log drive
KEYBUF$	EQU	$
;*=*=*
	END	BEGIN
