;****************************************************************************** ;* * ;* DISK FUNCTIONS * ;* * ;****************************************************************************** ; ; Return version number ; cmnd12: ld a,22h ; Set version number jr cmd25a ; and exit ; ; Reset disk system ; cmnd13: if resdsk and not resflag ; detect change between single and double sided disks if this function is ; supported.--b.h. ld a,(flags) ; Check full system reset flag bit 5,a jr z,cmnd13a ; If not set, we can't do setdisk call setdsk endif cmnd13a:ld hl,0 ; Load zero ld (login),hl ; All drives loged out if runlog ld (dskro),hl ; All drives read/write endif ld hl,ramlow+80h ; Set up DMA address ld (dma),hl ; And save it call stdma ; Do P2bios call xor a ; Set default drive = 'a' ld (defdrv),a ; Save it call seldk ; Select drive 'a' ld a,(subflg) ; Get submit flag jr cmd25a ; Exit ; ; Search for file ; cmnd17: call seldrv ; Select drive from FCB ld a,(ix+0) ; Get drive number from FCB sub '?' ; Test if '?' jr z,cmd17b ; If so all entries match ld a,(ix+14) ; Get system byte cp '?' ; Test if '?' jr z,cmd17a ; Yes, jump ld (ix+14),0 ; Load system byte with zero cmd17a: ld a,15 ; Test first 15 items in FCB cmd17b: call search ; Do search cmd17c: ld hl,(dirbuf) ; Copy directory buffer ld de,(dma) ; To DMA address ld bc,128 ; Directory=128 bytes ldir ret ; Exit ; ; Search for next occurence file ; cmnd18: ld ix,(dcopy) ; Get last FCB used by search call seldrv ; Selext drive from FCB call searcn ; Search next file match jr cmd17c ; And copy directory to DMA address ; ; Delete file ; cmnd19: call seldrv ; Select drive from FCB call delete ; Delete file cmd19a: ld a,(searex) ; Get exit byte 00=file found,0ffh not jr cmd25a ; And exit ; ; Rename file ; cmnd23: call seldrv ; Select drive from FCB call renam ; Rename file jr cmd19a ; And exit ; ; Return permanent medium vector ; if hifuncs permdsk: ld hl,(pmedia) jr cmd24a endif ; ; Return login vector ; cmnd24: ld hl,(login) ; Get login vector cmd24a: ld (pexit),hl ; Save it ret ; And exit ; ; Return current drive ; cmnd25: ld a,(defdrv) ; Get current drive cmd25a: jp exit ; And exit ; ; Return alv vector ; cmnd27: ld hl,(alv) ; Get allocation vector jr cmd24a ; And exit ; ; Return disk r/o vector ; cmnd29: ld hl,(dskro) ; Get disk r/o vector jr cmd24a ; And exit ; ; Change status ; cmnd30: call seldrv ; Select drive from FCB call cstat ; Change status jr cmd19a ; And exit ; ; Return drive table ; cmnd31: ld hl,(ixp) ; Get drive table jr cmd24a ; And exit if hifuncs ; ; Return DMA address ; getdma: ld hl,(dma) jr cmd24a ; ; Return a ZRDOS compatible version number ; zrdos: ld hl,zrvers jr cmd24a endif ; ; Set/get user code ; cmnd32: inc a ; Test if 0ffh ld a,(user) ; Get old user code jr z,cmd25a ; If 0ffh then exit ld a,e ; Get new user code and 01fh ; Mask it ld (user),a ; Save it ret ; And exit ; ; Compute file size command ; cmnd35: call seldrv ; Select drive from FCB call filsz ; Compute file size jr cmd19a ; And exit ; ; Set random record count ; cmnd36: ld hl,32 ; Set pointer to next record call calrrc ; Calculate random record count ldrrc: ld (ix+33),d ; And save random record count ld (ix+34),c ld (ix+35),b ret ; And exit ; ; Reset multiple login drive ; cmnd37: cpl ; Complement it ld e,a ld a,d ; Get mask MSB cpl ; Complement it ld d,a ld hl,(login) ; Get login vector ld a,e ; Mask login vector and l ; LSB ld l,a ld a,d ; Mask login vector and h ; MSB ld h,a ld (login),hl ; Save login vector if runlog ; If resetting unlogged-in disks ex de,hl ; Use login vector as mask endif ; Otherwise reset only those in mask ld hl,(dskro) ; Get drive r/o vector ld a,e ; Mask drive r/o vector and l ; LSB ld l,a ld a,d ; Mask drive r/o vector and h ; LSB ld h,a ld (dskro),hl ; Save drive r/o vector ; dbl: ; Code removed by L.H. Resdsk causes problems on a fast boot system and ; clrdsk trashes the login vector which the above routine so carefully sets. ; ; exx ; if resdsk ; call setdsk ; endif ; call initdr ; exx ret ; ;******************************** ;* error routines * ;* * ;******************************** ; ; ; Select error ; selerr: ld de,msel ; Load select error message ld b,2 jr derror ; And diplay error ; ; File read only error ; filro: ld de,mfilro ; Load file r/o message ld a,0ffh ; Set file r/o message flag ld b,4 jr error ; And display error ; ; Read error message--b.h. ; rderr: ld de,mrderr ld b,1 jr derror ; ; Write error message--b.h. wrterr: ld de,mwrter ld b,5 jr derror ; ; Drive read only error ; rdonly: ld de,mro ; Load drive r/o message derror: xor a ; Set no file r/o message ; ; ; Display error message ; ; P2dos error on d: error message ; function = nn [file = filename.typ] ; error: ld c,a ; Save file r/o message flag push bc push de ; Save error message pointer ld a,(defdrv) ; Get current drive ld e,a ; Save drive in E in case of trap add a,'A' ; Make ascii ld (mdrive),a ; Save it if hifuncs ld a,(trapflag) ; If wb trap, then no messages or a ld a,b ; Get ZRDOS error number in A jp nz,error5 endif call crout ; Diplay cr/lf ld de,mberr ; Load message "P2dos error on d:" call mess ; Display message pop de ; Get error message pointer call mess ; Display message call crout ; Display cr/lf ld de,mbfunc ; Load message "function =" call mess ; Display message ld a,(funct) ; Get function number push af ; Save it ld bc,100 ; Display number / 100 call num ld c,10 ; Display number / 10 call num ld bc,101h ; Always display number / 1 call num pop af ; Get function number pop bc ; Get file r/o flag cp 15 ; Test if FCB used in command jr c,error3 cp 24 jr c,error1 cp 30 jr z,error1 cp 33 jr c,error3 cp 37 jr c,error1 cp 40 jr nz,error3 error1: push ix ; Yes then display "file =" sub 19 ; Test delete file function jr nz,error2 ; Not then jump or c ; Test file r/o flag jr z,error2 ; No file r/o then jump call caldir ; Get FCB from directory buffer ex (sp),hl ; Save it error2: ld de,mfile ; Get message " file =" call mess ; Display message pop hl ; Get pointer FCB ld b,8 ; Display fisrt 8 characters call filenm ld a,'.' ; Load '.' push hl ; Save FCB pointer call wrcon ; Echo it pop hl ; Restore FCB pointer ld b,3 ; Display last 3 characters call filenm error3: call gconst ; Test if character present or a jr z,error4 ; No then jump call getch ; Get character jr error3 ; And test again error4: call getch ; Get character ; P2dos had a bug which did not allow the user to ignore a read/write error ; by hitting a key other than control-c. This is the fix.--b.h. ; ; Modified by l.h. to escape errors ONLY if the error ignore key is entered. ; This key is defined in the header file. ; pop hl ; Restore directory entry if erresc gt 0 push af ; Save it ld a,(retflg) ; Get retflg or a jr z,error5 pop af cp erresc ret z endif trap equ $+1 ; Warm boot trap address error5: jp ramlow ; And do warm boot error5a:xor a jr error5 ; ; Display number ; num: ld d,0ffh ; Load number -1 num1: inc d ; Increment number sub c ; Divide by c jr nc,num1 ; Not finished then loop add a,c ; Restore last value push af ; Save it ld a,d ; Test if "0" or b ; And if leading zero jr z,num2 ; Yes, then exit ld b,d ; Set no leading zero ld a,d ; Get number add a,'0' ; Make ascii push bc ; Save registers call wrcon ; Echo number pop bc ; Restore registers num2: pop af ; Restore number ret ; And exit ; ; Display filname.typ ; filenm: inc hl ; Increment pointer FCB ld a,(hl) ; Get character from FCB and 07fh ; Mask it push hl ; Save registers push bc call wrcon ; Echo character pop bc ; Restore registers pop hl djnz filenm ; Repeat b times ret ; And exit ; ; Error messages ; made more meaningful-b.h. ; ; Bad sector message replaced by read/write error messages ;mbadsc: db 'Bad sector$' ; msel: db 'Drive ?$' ; mfilro: db 'File ' ; mro: db 'R/O$' ; mberr: db 'Error, Disk ' mdrive: db 0 db drvsep db ' $' ; mbfunc: db 'Fnc: $' ; mfile: db '; File: $' ; mrderr: db 'Read Err$' ; mwrter: db 'Write Err$' ; ; Select disk from FCB ; seldrv: ld a,0ffh ; Set disk select done flag ld (fldrv),a ld a,(defdrv) ; Get current drive ld (drive),a ; Save it in memory ld e,a ; Save it in register e ld a,(ix+0) ; Get drive from FCB ld (fcb0),a ; Save it cp '?' ; Test if '?' jr z,cmnd14 ; Yes, then select drive from register e and 01fh ; Mask drive ld a,e ; Test if zero jr z,seldr0 ; Select drive from register e ld a,(ix+0) ; Get drive from FCB dec a ; Decrement drive seldr0: call seldk ; Select drive ld a,(ix+0) ; Get drive from FCB and 0e0h ; Remove drive bits ld b,a ; Save register ld a,(user) ; Get user number or b ; Insert user number in FCB ld (ix+0),a ret ; And exit ; ; Select disk ; cmnd14: ld a,e ; Get drive in A ; ; Select disk ; seldk: and 0fh ; Mask drive number ld b,a ; Save counter ld de,(login) ; Get login vector or a ; Test drive 'a' jr z,seldk1 ; Yes then jump seldk0: rr d ; Shift login vector rr e ; Until bit 0 register e djnz seldk0 ; Is current drive seldk1: ld hl,defdrv ; Get pointer last drive bit 0,e ; Test if drive logged in jr z,seldk2 ; No, login drive cp (hl) ; Test same drive ret z ; Yes then exit seldk2: ld (hl),a ; Save new current drive push de ; Save drive logged in flag ld c,a ; Copy drive number call seldsk ; Do P2bios select ld a,h ; Test if error or l jr z,seldk3 ; Yes, illegal drive number ld e,(hl) ; Get LSB translation vector inc hl ; Increment pointer ld d,(hl) ; Get MSB translation vector inc hl ; Increment pointer ld (trans),de ; Save translation vector ld (temp0),hl ; Save address temp0 ld de,06 ; Increment to next address add hl,de ld de,dirbuf ; Load dirbuf pointer ld bc,8 ; Copy 8 bytes ldir ld hl,(ixp) ; Get drive parameter address ld c,15 ; Copy 15 bytes ldir pop de ; Get drive logged in flag bit 0,e ; Test it ret nz ; Drive logged in so return ld hl,(login) ; Get login vector call sdrvb ; Set drive bit in login vector ld (login),hl ; Save login vector if hifuncs ld hl,(ncheck) ; Get number of records to check ld a,h ; If zero, then permanent medium or l jr nz,initflpy ; So don't set permedia table ld hl,(pmedia) ; Get permanent medium vector call sdrvb ; Set drive bit ld (pmedia),hl ; Save perm. medium vector sbc hl,de ; Check if drive just made perm jr nz,initdr ; If bit added, then init ld hl,(temp0) ld a,(hl) ; Get number of files inc hl ; If it's zero, then init the dir or (hl) jr z,initdr ld a,(flags) ; Check if auto-init bit 5,a ; Bit 5, pmedia auto-init ret z ; If not set, then don't init drive. endif jr initdr ; And setup drive tables seldk3: ld hl,(stsel) ; Load error message address jp (hl) ; And display error ; ; Init drive ; clear alv bit buffer after drive reset ; initflpy: ; If using resdsk, arrive here only if resdsk and resflag ; for logging in floppy drives. rflgmac ; Code for macro in header file endif initdr: ld de,(maxlen) ; Get length alv buffer-1 (bits) ld a,3 ; Divide by 8 initd0: srl d ; To get bytes rr e dec a jr nz,initd0 inc de ; Increment, so all bits are cleared ld hl,(alv) ; Get pointer alv buffer push hl initd1: ld (hl),0 ; Clear 8 bits inc hl ; Increment pointer dec de ; Decrement counter ld a,d ; Test if counter zero or e jr nz,initd1 ; Not then jump pop hl ; Get alv pointer ld de,(ndir0) ; Get first two bytes alv buffer ld (hl),e ; Save LSB inc hl ; Increment pointer ld (hl),d ; Save MSB ld hl,(temp0) ; Clear number of files xor a ; On this drive ld (hl),a ; Clear LSB inc hl ; Increment pointer ld (hl),a ; Clear MSB ld (subflg),a ; Clear submit flag (reset disk command) call setfct ; Set file count initd2: ld a,0ffh ; Update directory checksum call rddir ; Read FCB's from directory call tstfct ; Test last FCB ret z ; Yes then exit call caldir ; Calculate entry point FCB ld a,(hl) ; Get first byte FCB cp 0e5h ; Test empty directory entry jr z,initd2 ; Yes then get next FCB cp 021h ; Test time stamp jr z,initd2 ; Yes then get next FCB ; The next 3 lines must be removed if reset disk is to flag a $$*.* file on ; any user area rather than just the current user area. (Release E) ; ; ld a,(user) ; Get user number ; cp (hl) ; Test if user is same ; jr nz,initd3 ; No then jump inc hl ; Point to file name ld a,(hl) ; Get first char filename cp '$' ; Test if '$' jr nz,initd3 ; Not then jump inc hl ; Check for a second '$' sub (hl) ; to compensate for public '$' files jr nz,initd3 ; Not there? then jump dec a ; Load a with 0ffh ld (subflg),a ; Save it in subflg initd3: ld c,1 ; Set bit in alv buffer call fillbb ; Set bits from FCB in alv buffer call setlf ; Update last file count jr initd2 ; And get next FCB ; ; Set drive bit in hl ; sdrvb: ex de,hl ; Copy hl=>de ld hl,1 ; Get mask drive "a" ld a,(defdrv) ; Get current drive or a ; Test if drive "a" jr z,sdrvb1 ; Yes then done sdrvb0: add hl,hl ; Get next mask dec a ; Decrement drive counter jr nz,sdrvb0 ; And test if done sdrvb1: ld a,d ; hl=hl or de or h ld h,a ld a,e or l ld l,a ret ; Exit ; ; Calculate sector/track directory ; stdir: ld hl,(filcnt) ; Get FCB counter directory srl h ; Divide by 4 rr l ; (4 FCB's / sector) srl h rr l ld (recdir),hl ; Save value (used by checksum) ex de,hl ; Copy it to de ld hl,0 ; Clear hl ; ; Calculate sector/track ; entry: hl,de=sector number (128 byte sector) ; result set track =hl,de / maxsec ; set sector =hl,de mod maxsec ; calst: ld bc,(maxsec) ; Get sectors/track ld a,17 ; Set up loop counter calst0: or a ; Test hl>=bc sbc hl,bc ccf jr c,calst1 ; Yes then jump add hl,bc ; No then retore hl or a ; And clear carry calst1: rl e ; Shift result in de rl d dec a ; Test last bit done jr z,calst2 ; Yes then exit rl l ; Shift next bit in hl rl h jr calst0 ; Continue calst2: push hl ; Save sector number ld hl,(nftrk) ; Get first track add hl,de ; Add track number ld b,h ; Copy it to bc ld c,l call settrk ; P2bios call set track pop bc ; Restore sector number ld de,(trans) ; Get translation table address call sectrn ; P2bios call sector translation ld b,h ; Copy result to bc ld c,l jp setsec ; P2bios call set sector ; ; Get disk map block number from FCB ; exit hl=address FCB ; de=dm ; bc=offset in dm ; getdm: ld c,(ix+32) ; Get next record ld a,(nblock) ; Get number of blocks ld b,a ; Save it getdm0: srl c ; Shift next record djnz getdm0 ; Number of blocks times getdm1: cpl ; Complement number of blocks add a,9 ; Add 9 ld b,a ; B=8-number of blocks ld a,(nextnd) ; Get extent mask and (ix+12) ; Mask with extent rrca ; Rotate one right getdm2: rlca ; Rotate one left djnz getdm2 ; 8-number of blocks times getdm3: add a,c ; Add the two values to get entry FCB getdm4: push ix ; Get FCB address pop hl ld c,16 ; Add offset 16 to point to dm add hl,bc ld c,a ; Add entry FCB add hl,bc ld a,(maxlen+1) ; Test 8 bits/16 bits FCB entry or a jr nz,getdm5 ; 16 bits => jump ld e,(hl) ; Get 8 bit value ld d,0 ; Make MSB zero ret ; And exit getdm5: add hl,bc ; Add twice (16 bit values) ld e,(hl) ; Get LSB inc hl ; Increment pointer ld d,(hl) ; Get MSB dec hl ; Decrement pointer ret ; And exit ; ; Calculate sector number ; entry: de=block number from FCB ; calsec: ld hl,0 ; Clear MSB sector number ld a,(nblock) ; Get loop counter ld b,a ; Save it in b calsc0: sla e ; Shift l,d,e rl d rl l djnz calsc0 ; B times calsc1: ld a,(nmask) ; Get sector mask and (ix+32) ; And whit next record or e ; Set up LSB sector number ld e,a ret ; And exit ; ; Calculate dirbuf entry point ; caldir: ld hl,(dirbuf) ; Get start address dirbuf ld a,(secpnt) ; Get sector pointer add a,l ; Add l=l+a ld l,a ret nc ; No carry exit inc h ; Increment h ret ; And exit ; ; Init file count ; setfct: ld hl,-1 ; Set up file count ld (filcnt),hl ; Save it ret ; And exit ; ; Test file count ; tstfct: ld hl,(filcnt) ; Test file count=0ffffh ld a,h ; Get MSB and l ; And LSB inc a ; Test if result=0ffh ret ; And exit ; ; Set last file ; setlf: call tstlf ; Test last file ret c ; No then exit inc de ; Increment last file ld (hl),d ; Save it in temp0 dec hl ld (hl),e ret ; And exit ; ; Test last file ; tstlf: ld hl,(temp0) ; Get pointer to last file ld de,(filcnt) ; Get file counter ld a,e ; Subtract de-(hl) sub (hl) inc hl ld a,d sbc a,(hl) ret ; Exit ; ; Get next FCB from drive ; entry a=0 check checksum, a=0ffh update checksum ; rddir: ld c,a ; Save checksum flag ld hl,(filcnt) ; Get file counter inc hl ; Increment it ld (filcnt),hl ; And save it ld de,(nfiles) ; Get maximum number of files or a ; Clear carry sbc hl,de ; Test if last file add hl,de jr z,rddir0 ; No jump jr nc,setfct ; Yes set file count to 0ffffh rddir0: ld a,l ; Get file count LSB rrca ; *32 rrca rrca and 060h ; Mask it ld (secpnt),a ; Save it for later use ret nz ; Return if not fisrt FCB sector push bc ; Save checksum flag call stdir ; Calculate sector/track directory call readdr ; Read sector directory pop bc ; Restore checksum flag call chkdir ret nc push bc call initdr ; Relog drive pop bc jr rddir ; ; Update/check checksum directory ; entry c=0 check checksum, c=0ffh update checksum ; chkdir: ld hl,(ncheck) ; Get number of checked records ld de,(recdir) ; Get current record or a ; Clear carry sbc hl,de ; Test current record ret z ; Exit if zero ccf ret nc ; Exit if greater then ncheck ld hl,(dirbuf) ; Get dirbuf ld b,128 ; Set up counter xor a ; Clear checksum chkdr0: add a,(hl) ; Add checksum inc hl ; Increment pointer djnz chkdr0 ; 128 times ld hl,(csv) ; Get pointer checksum directory add hl,de ; Add current record inc c ; Test checksum flag jr z,chkdr1 ; 0ffh=> update checksum cp (hl) ; Test checksum ret z ; Exit if ok ; automatic disk logging--instead of setting read/only flag when disk is ; changed, carry is returned set to calling routine if checksum error ; jp setwpd scf ; From Mod. 3 Suprbdos jp setfn ; Set number of files chkdr1: ld (hl),a ; Update checksum ret ; And exit ; ; Read sector from drive ; ; ; Readr and writer modified to give separate error messages--b.h. readr: call read ; P2bios call read sector ld hl,(srderr) jr write0 ; ; Write sector on drive ; writer: call write ; P2bios call write sector ld hl,(swrter) write0: or a ; Test exit code ret z ; Exit if ok ld a,1 ; Allow a return to program if r/o ld (retflg),a jp (hl) ; P2dos error on d: bad sector ; ; Read directory from drive ; readdr: call dmadir ; Set up DMA directory call readr ; Read record jr stdma ; Set up DMA user ; ; Write directory on drive ; writdr: ld c,0ffh ; Update checksum directory call chkdir call dmadir ; Set up DMA directory ld c,1 ; Write directory flag call writer ; Write record jr stdma ; Set up DMA user