; Routine:	FRESET -- fast drive reset and login
; Author:	Bridger Mitchell (Plu*Perfect Systems)
; CPU:		Z80-compatible
; Date:		January 2, 1988
; Version:	1.0
; 
; This routine (fast-)resets and logs in the CP/M drive in register
; (A).  When possible, it uses BDOS function 37 (logoff drives). 
; In most cases FRESET is significantly faster than using function 13
; (reset all drives) to do a general reset.
; 
; FRESET functions correctly with Digital Research's CP/M 2.2 BDOS,
; which contains a bug that does not allow the logged-in drive to
; be reset with function 37.
; 
; Some CP/M BDOS emulators (such as ZRDOS, PZDOS, ...) have changed
; the operation of the general-reset function 13, in order to speed
; up warm-boots and disk-resets on systems with hard-drives. In this
; case, a non-removable drive (hard disk, ram disk), after it
; has been initially logged in, remains logged in after a general
; reset.
; 
; On such systems it is **essential** that any program that uses
; BIOS disk functions to write to a non-removable drive also cause
; the disk's allocation map to be rebuilt before any BDOS disk
; functions are used.  DU (DU3) and UNERASE are probably the most
; common examples of such programs; they modify the disk directory.
; For these systems, the drive must first be logged off with
; function 37 and then logged in.  Calling FRESET within such
; programs will ensure that the disk's allocation map is recomputed.
; 
; The FRESET algorithm:
;
;   if requested_drive is logged in
; 	if a second drive is logged in
; 	    log into the second drive
; 	logoff requested drive (fn.37)
; 	    if no second drive was logged in
; 		do general reset (fn. 13)	
;   log into requested drive
; 
; Note:  Unnumbered version dated 12/27/87 did not provide for
; logging out the drive in one special case, namely when only that
; one drive is currently logged in.  Thanks to Howard Goldstein
; for spotting the problem.
;
xbdos	equ	5

;	Fast-reset drive (A)
;	A = 0 ... 15  for  A: ... P:
;	
CSEG
freset:
	ld	(reqdrv),a	; save requested drive
	push	af
	ld	c,24		; get vector of logged-in drives
	call	xbdos
	pop	af		; (recover requested drive)
	push	hl		; save logged-in vector
	call	fshftr		; shift requested drive's bit to bit 0
	bit	0,l		; is requested drive logged in?
	pop	hl		;  (recover (unshifted) logged vector)
	jr	z,flogit	; ..z - no, just log it in
	ld	e,0		;  initialize drive index/count
	jr	frese2
;
frese1:	ld	a,1		; shift vector right 1 bit
	call	fshftr
frese2:	bit	0,l		; if drive is not logged in
	jr	z,frese3	; ..check next drive
	ld	a,(reqdrv)	; or if it is the requested drive
	cp	e		; 
	jr	z,frese3	; ..check next drive
;
; found a second logged-in drive, so switch to it
;
	call	fslctit		; select e'th drive
	call	flogout		; log out requested drive
	jr	flogit		; then log into it and exit.
;
frese3:	inc	e		; increment drive count
	ld	a,e		
	cp	16
	jr	c,frese1	; .. and continue for 16 drives 
;
; no second drive found,
;
	call	flogout		; log out requested drive
	ld	c,13		; do general reset, then (re)log requested
	call	xbdos		; 
;
; log into requested drive
;
flogit:	ld	a,(reqdrv)
	ld	e,a
;
fslctit:ld	c,14		; select bdos drive
jxbdos:	jp	xbdos	
;
; log out the requested drive
;
flogout:ld	a,(reqdrv)	; set up bit to log out drive
	ld	hl,1
	call	fshftl
	ex	de,hl
	ld	c,37		; log out drive in DE vector
	jr	jxbdos
;
;
; shift hl right (a) bits
;
fshftr:
	inc	a
shftr1:	dec	a
	ret	z
	srl	h
	rr	l	
	jr	shftr1
;
;
; shift hl left (a) bits
;
fshftl:
	inc	a
shftl1:	dec	a
	ret	z
	add	hl,hl
	jr	shftl1	

;--------------------
DSEG
reqdrv:	ds	1

	end
	z,frese3	; ..check next drive
;
; found a second logged-in drive, so switch to it
;
	call	fslctit		; select e'