BDEVIO.A86
资源名称:drdossrc.zip [点击查看]
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:42k
源码类别:
操作系统开发
开发平台:
Asm
- title 'BDEVIF - Block DEVice Input/Output support'
- ; File : $BDEVIO.A86$
- ;
- ; Description :
- ;
- ; Original Author : DIGITAL RESEARCH
- ;
- ; Last Edited By : $CALDERA$
- ;
- ;-----------------------------------------------------------------------;
- ; Copyright Work of Caldera, Inc. All Rights Reserved.
- ;
- ; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
- ; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
- ; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
- ; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
- ; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
- ; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
- ; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
- ; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
- ; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
- ; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
- ; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
- ; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
- ; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
- ; CIVIL LIABILITY.
- ;-----------------------------------------------------------------------;
- ;
- ; *** Current Edit History ***
- ; *** End of Current Edit History ***
- ;
- ; $Log$
- ; BDEVIO.A86 1.27 94/11/30 16:25:22
- ; added delayed retry for read/write to locked region
- ; added support for using multiple FAT copies on reads if one fails;
- ; BDEVIO.A86 1.26 94/02/22 17:11:25
- ; Fix where corrupt dir entry results in read beyond end-of-chain (Filelink bug)
- ; BDEVIO.A86 1.25 93/12/15 03:07:11
- ; New ddioif entry point so Int 25/26 bypasses address normalisation
- ; BDEVIO.A86 1.24 93/12/08 03:15:14
- ; Force rebuild_ldt_root if root in JOIN's subdirectory
- ; BDEVIO.A86 1.23 93/11/19 18:29:29
- ; Fix for SERVER print queue viewing problem
- ; BDEVIO.A86 1.22 93/09/21 12:43:37
- ; On fdos read/write do EOF checks before SHARE LOCK checks
- ; BDEVIO.A86 1.21 93/09/14 20:02:50
- ; Trust LFLG_PHYSICAL
- ; BDEVIO.A86 1.20 93/09/02 22:22:56
- ; Use 32 bit sectors to read fat for build bpb if appropriate (SYQUEST bug)
- ; BDEVIO.A86 1.19 93/08/27 18:46:49
- ; int 26 discards hash codes
- ; BDEVIO.A86 1.18 93/07/20 22:42:25
- ; Even fewer checks on int 25/26
- ; BDEVIO.A86 1.12 93/06/23 02:57:07
- ; Add auto-commit to fdowrw
- ; BDEVIO.A86 1.11 93/05/14 13:47:41
- ; Shorten media change code slightly
- ; BDEVIO.A86 1.9 93/03/16 22:30:21 IJACK
- ; UNDELETE support changes
- ; ENDLOG
- eject ! include i:mserror.equ ; F_DOS erros
- eject ! include i:fdos.equ
- eject ! include i:driver.equ
- eject ! include i:doshndl.def
- eject ! include bdos.equ
- eject ! include rh.equ
- ;*****************************************************
- ;*
- ;* bdos data area
- ;*
- ;*****************************************************
- PCMODE_DATA dseg word
- extrn current_ddsc:dword
- extrn current_dhndl:dword
- extrn current_dsk:byte ; default drive
- extrn current_ldt:dword ; currently selected LDT
- extrn dma_offset:word ; DTA offset
- extrn dma_segment:word ; DTA segment
- extrn ddsc_ptr:dword
- extrn err_drv:byte
- extrn error_dev:dword ; failing device for Int 24's
- extrn fdos_stub:dword
- extrn ioexerr:byte
- extrn last_drv:byte
- extrn ldt_ptr:dword
- extrn lock_bios:dword
- extrn phys_drv:byte
- extrn rwmode:byte
- extrn share_stub:dword
- extrn unlock_bios:dword
- extrn verify_flag:byte
- extrn net_retry:word
- BDOS_DATA dseg word
- extrn bcb_root:dword
- extrn deblock_seg:word
- extrn fdos_hds_drv:byte
- extrn fdos_hds_blk:word
- extrn fdos_hds_root:word
- extrn fdos_ret:word
- public adrive
- public clsize
- public dosfat
- public cur_dma
- public cur_dma_seg
- public datadd
- public diradd
- public dirinroot
- public dirperclu
- public fatadd
- public hdsaddr
- public lastcl
- public logical_drv
- public mult_sec
- public nfatrecs
- public nfats
- public pblock
- public physical_drv
- public psecsiz
- public req_hdr
- public secperclu
- eject
- ; The following specify the drive selected for the current operation
- hdsaddr dw 0 ; current HDS address (0 means at root)
- logical_drv db 0 ; logical drive number
- physical_drv db 0 ; physical disk number
- ; The following describe the currently active drive - not this may differ from
- ; the currently selected drive above due to eg. flushing dirty buffers
- ; Local copy of DDSC_ variables - ORDER CRITICAL - must match DDSC_
- local_ddsc rb 0
- psecsiz dw 0 ; byte size of sector
- clmsk db 0
- clshf db 0
- fatadd dw 0 ; sector offset of 1st FAT sector
- byte_nfats db 0 ; number of FAT's
- dirinroot dw 0 ; # dir entries in root
- datadd dw 0 ; sector offset of data sector
- lastcl dw 0 ; # last cluster (after adjustment)
- if DOS5
- dw 0 ; # sectors per FAT
- else
- db 0 ; # sectors per FAT (nb. may be inaccurate on large drives)
- endif
- diradd dw 0 ; sector offset of 1st root DIR sector
- LOCAL_DDSC_LEN equ offset $ - offset local_ddsc
- ; some extra parameters calculated from local_ddsc for convenience
- nfats dw 0 ; # FAT's (WORD is handier)
- nfatrecs dw 0 ; # sectors per FAT (accurate version)
- clsize dw 0 ; cluster size in bytes
- secperclu dw 0 ; # sectors per cluster
- dirperclu dw 0 ; # dir enrties in subdir
- dosfat dw 0 ; FAT length indicator (FAT12 or FAT16)
- ; The following specify the next block read/write operation on the active drive
- adrive db 0ffh ; currently active disk
- pblock dw 0, 0 ; absolute block address
- mult_sec dw 1 ; multi sector count passed to xios
- cur_dma dw 0
- cur_dma_seg dw 0
- fdrwreq dw 0 ; requested count (roundup)
- public fdrwflg
- fdrwflg db 0 ; bdosrw flags
- fdrwcnt dw 0 ; requested byte count for read/write
- fdrwptr rd 0 ; disk transfer address for read/write
- fdrwoff dw 0 ; offset for R/W DTA
- fdrwseg dw 0 ; segment for R/W DTA
- fdrwsec rd 1 ; physical block for fdosrw
- fdrwsecoff dw 0 ; offset within sector
- fdrwdircnt dw 0 ; # sectors in direct xfer
- byteoff dw 0 ; fdosrw local variable
- dw 0 ; byte offset with file
- blk dw 0 ; current cluster of filepos
- blkidx dw 0 ; current cluster index within file
- blkoffset dw 0 ; offset within cluster
- ; static request header for DOS device driver I/O
- Public req_hdr
- req_hdr rb 0
- req_len db 22
- req_unit rb 1
- req_cmd rb 1
- req_status rw 1
- req_rwmode db 0 ; action hint for device drivers
- rb 7
- req_media rb 1
- rb 16
- req1_return equ byte ptr req_media+1
- req1_volid equ word ptr req_media+2
- req2_buffer equ word ptr req_media+1
- req2_bpb equ word ptr req_media+5
- req3_buffer equ word ptr req_media+1
- req3_count equ word ptr req_media+5
- req3_sector equ word ptr req_media+7
- req3_volid equ word ptr req_media+9
- req4_buffer equ word ptr req_media+1
- req4_count equ word ptr req_media+5
- req4_sector equ word ptr req_media+7
- req4_volid equ dword ptr req_media+9
- req4_bigsector equ dword ptr req_media+13
- eject
- BDOS_CODE cseg
- extrn alloc_chain:near
- extrn bpb2ddsc:near ; converts BPB to DDSC
- extrn buffers_check:near ; look for buffers
- extrn delfat:near
- extrn discard_all:near ; discard all buffers
- extrn discard_dir:near ; discard directory buffers
- extrn discard_dirty:near ; discard all dirty buffers
- extrn discard_files:near ; discard open files
- extrn fdos_error:near
- extrn fdos_restart:near
- extrn file_update:near
- extrn fixfat:near
- extrn getnblk:near ; get block value from FAT
- extrn get_ldt:near
- extrn get_ldt_raw:near
- extrn hdsblk:near ; get current HDS block
- extrn hshdscrd:near
- extrn locate_buffer:near
- extrn rebuild_ldt_root:near
- extrn timestamp_dhndl:near
- extrn update_dat:near
- extrn update_fat:near
- extrn share_delay:near
- public block_device_driver
- public clus2sec
- public device_driver
- public read_block
- public select_adrive
- public select_logical_drv
- public select_physical_drv
- public write_block
- eject
- eject
- Public get_ddsc
- get_ddsc:
- ;--------
- ; On Entry:
- ; AL = physical drive
- ; On Exit:
- ; CY set if bad drive, else
- ; ES:BX -> DDSC_
- ; (All other registers preserved)
- ;
- cmp al,ss:phys_drv
- jae get_ddsc30
- les bx,ss:ddsc_ptr
- get_ddsc10:
- cmp bx,0FFFFh ; end of the line
- je get_ddsc30
- cmp al,es:DDSC_UNIT[bx] ; does the unit match ?
- je get_ddsc20 ; no, try the next
- les bx,es:DDSC_LINK[bx]
- jmps get_ddsc10
- get_ddsc20:
- ; clc
- ret
- get_ddsc30:
- stc
- ret
- eject
- ; Read/Write from/to disk file
- ; entry: CURRENT_DNHDL -> file handle
- ; BDRWFLG = 1 => read
- ; 0 => write
- ; ES:DI = buffer (32 bit: off/seg)
- ; CX = requested byte count (16 bit)
- ; exit: FDOS_RET = number of bytes read/written
- ; CURRENT_DHNDL incremented by FDOS_RET
- public fdosrw ; read/write to/from disk file
- fdosrw:
- ;------
- call fdrw_prepare ; set up address, where we are in file
- jc fdrw_error ; stop if we have a problem
- call fdrw_size ; extend file if necessary
- jc fdrw_error ; bail out if we can't
- cmp fdrwcnt,0 ; are we truncating?
- jne fdrw_loop ; read/write if non-zero count
- test fdrwflg,1 ; writing zero bytes?
- jnz fdrw_error ; (reading has no meaning)
- call fdw_trunc ; writing truncates the file
- jmps fdrw_nobigger
- fdrw_error:
- ret
- fdrw_loop: ; loop here for long reads/writes
- call fdrw_seek ; seek to position for xfer
- jc fdrw_exit ; should get error's now...
- jnz fdrw_buffered ; deblocking required if not aligned
- mov cx,fdrwcnt ; CX = requested transfer size
- cmp cx,psecsiz ; at least one sector transferred?
- jb fdrw_buffered ; if less, need deblocked transfer
- mov fdrwreq,cx ; requested count for direct r/w
- call direct_rw ; transfer straight to/from TPA
- jmps fdrw_more
- fdrw_buffered: ; perform deblocked read/write
- call deblock_rw ; transfer via BDOS buffer
- fdrw_more:
- add fdrwoff,ax ; adjust buffer address
- add fdos_ret,ax ; adjust return code
- add byteoff,ax ; adjust file offset
- adc byteoff+2,0
- sub fdrwcnt,ax ; adjust remaining count
- ja fdrw_loop ; still more to do
- fdrw_exit:
- les bx,current_dhndl
- mov ax,fdos_ret ; get total xfered and update position
- add es:DHNDL_POSLO[bx],ax
- adc es:DHNDL_POSHI[bx],0
- test fdrwflg,1
- jnz fdrw_return ; skip if reading
- mov ax,byteoff ; has the file grown ?
- mov dx,byteoff+WORD
- sub ax,es:DHNDL_SIZELO[bx]
- sbb dx,es:DHNDL_SIZEHI[bx]
- jb fdrw_nobigger ; yes, update the file size
- add es:DHNDL_SIZELO[bx],ax
- adc es:DHNDL_SIZEHI[bx],dx
- fdrw_nobigger:
- call timestamp_dhndl ; record the current time
- test es:DHNDL_MODE[bx],DHM_COMMIT
- jz fdrw_return ; is auto-commit in place ?
- call file_update ; yes, commit the file
- fdrw_return:
- ret
- fdw_trunc:
- ;---------
- ; On Entry:
- ; BLKIDX = block number within file
- ; BLKOFFSET = block offset
- ; On Exit:
- ; DHNDL_SIZE adjusted, any excess clusters freed
- ;
- les bx,current_dhndl
- mov cx,blkoffset ; get offset within current block
- mov ax,blkidx ; get logical block number
- jcxz fdw_t10 ; skip if no data in last block
- inc ax ; else add in another cluster
- fdw_t10: ; AX = # of clusters required in file
- test ax,ax
- jnz fdw_t20
- xchg ax,es:DHNDL_BLK1[bx] ; forget about chain
- jmps fdw_t50
- fdw_t20:
- xchg ax,cx ; CX = # of blocks to keep
- mov ax,es:DHNDL_BLK1[bx] ; get first block in file
- fdw_t30: ; scan all block we want to keep
- push cx
- push ax
- call getnblk ; get next block
- pop bx
- pop cx
- cmp ax,lastcl ; stop on premature end of chain
- ja fdw_t60
- loop fdw_t30
- push ax ; yep, remember what
- mov ax,dosfat
- xchg ax,bx ; truncate chain at cluster AX
- call fixfat ; as thats all we need
- pop ax
- fdw_t50:
- call delfat ; release the chain
- fdw_t60:
- les bx,current_dhndl
- mov ax,byteoff ; now truncate the file
- mov es:DHNDL_SIZELO[bx],ax
- mov ax,byteoff+2
- mov es:DHNDL_SIZEHI[bx],ax
- xor ax,ax ; cause reads/writes to scan
- mov es:DHNDL_BLK[bx],ax ; block chain from start
- mov es:DHNDL_IDX[bx],ax
- mov fdos_ret,ax ; no logical errors
- ret
- fdrw_prepare:
- ;------------
- ; Normalise the xfer address and count
- ; Calculate current position in the file
- ;
- ; On Entry:
- ; ES:DI -> buffer
- ; CX = bytes to xfer
- ; On Exit:
- ; FDRWSEG:FDRWOFF -> normalised buffer
- ; FDRWCNT = bytes to xfer
- ; FDOS_RET = bytes xfer'd (0)
- ; PREREAD = TRUE
- ; BYTEOFF = current offset in file
- ; BLKIDX = cluster containing current file position
- ; BLKOFFSET = offset within cluster
- ; CY set if current position theoretically impossible
- ;
- xor ax,ax ; AX = 0
- mov fdos_ret,ax ; initialize byte return count
- mov fdrwcnt,cx ; save byte count for read/write
- mov ax,000Fh
- and ax,di ; get offset within paragraph
- mov fdrwoff,ax ; save normalized offset for read/write
- add ax,cx ; do we overflow 64k ?
- jnc fdrw_p10 ; yes, then forget about what would
- sub fdrwcnt,ax ; overflow this segment
- fdrw_p10:
- mov cl,4
- shr di,cl ; DI = paragraph offset
- mov ax,es
- add ax,di ; AX = effective segment
- jnc fdrw_p20 ; if above 1 MByte base it at FFFF
- inc ax ; AX = para's above FFFF
- shl ax,cl ; make it bytes
- add fdrwoff,ax ; add to offset
- mov ax,0ffffh ; use our magic segment
- fdrw_p20:
- mov fdrwseg,ax ; save normalized segment for read/write
- les bx,current_dhndl
- mov ax,es:DHNDL_POSLO[bx]
- mov byteoff,ax ; copy position to local variables
- mov ax,es:DHNDL_POSHI[bx]
- mov byteoff+WORD,ax
- mov cx,clsize
- mov ax,lastcl
- mul cx ; DX:AX = maximum size of disk
- sub ax,byteoff
- sbb dx,byteoff+WORD ; beyond this we can't go
- jc fdrw_p30
- mov ax,byteoff ; DX:AX = current file size
- mov dx,byteoff+WORD
- div clsize
- mov blkidx,ax ; save it for later
- mov blkoffset,dx ; DX = offset within cluster
- clc ; theoretically possible
- fdrw_p30:
- ret
- fdrw_size:
- ;---------
- ; On reads check xfer starts within file, and clip size to reflect EOF.
- ; On writes try to extend to cluster chain so it is big enough to contain
- ; the data we wish to write.
- ;
- ; On Entry:
- ; BYTEOFF = current position in file
- ; FDRWCNT = extra bytes requested
- ; On Exit:
- ; FDRWCNT adjusted if read past EOF
- ; CY set if problem extending file
- ;
- les bx,current_dhndl
- mov ax,es:DHNDL_SIZELO[bx] ; are we past the end of file
- mov dx,es:DHNDL_SIZEHI[bx] ; if so we may wish to extend on write
- sub ax,byteoff ; AX,DX = current offset
- sbb dx,byteoff+WORD ; are we already beyond EOF ?
- jb fdrw_s40
- sub ax,fdrwcnt ; will we be going beyond EOF ?
- sbb dx,0
- jnb fdrw_s10 ; no, whole xfer is OK
- test fdrwflg,1 ; check if we're reading
- jz fdrw_s50 ; if we are just adjust the
- add fdrwcnt,ax ; amount we can xfer
- fdrw_s10:
- ; We call share concerning the XFER to check if any of the proposed
- ; file region is locked.
- ; les bx,current_dhndl ; check for locked regions
- mov cx,net_retry
- fdrw_s15:
- push cx
- mov cx,fdrwcnt ; in the file
- callf share_stub+S_FDOSRW
- pop cx
- jnc fdrw_s20 ; CY set on error
- dec cx
- jz fdrw_s30
- call share_delay
- jmps fdrw_s15
- fdrw_s20:
- ret
- fdrw_s30:
- jmp fdos_error ; CY clear, AX = error code
- fdrw_s40:
- ; We are going beyond EOF - if it is a read we fail it, if a write
- ; try to extend the file
- test fdrwflg,1 ; check if we're reading
- stc ; assume failure
- jnz fdrw_s20 ; reads fail now, writes extend file
- fdrw_s50:
- call fdrw_s10 ; make sure SHARE doesn't object
- ; jmp fdwrite_extend ; if not try to extend the file
- fdwrite_extend:
- ;--------------
- ; Try to extend to file to the required size before we write to it
- ; On Entry:
- ; ES:BX -> DHNDL_
- ; BYTEOFF = current position in file
- ; FDRWCNT = extra requested
- ; On Exit:
- ; CY clear if cluster chain now big enough for desired file size
- ;
- mov ax,byteoff ; AX,DX = current offset
- mov dx,byteoff+2
- add ax,fdrwcnt ; AX,DX = offset after r/w if success
- adc dx,0 ; add offset from lower 16 bits
- div clsize ; AX whole blocks required
- test dx,dx ; any remainder ?
- jz fdw_e05 ; yes, we have a partial block
- inc ax ; round up blocks required
- fdw_e05:
- xchg ax,cx ; CX blocks are required
- mov ax,es:DHNDL_BLK1[bx] ; assume we need to follow from start
- test ax,ax
- jz fdw_e30 ; if no starting block do the lot
- dec cx ; else count # extra blocks required
- mov dx,es:DHNDL_BLK[bx] ; do we have a current block ?
- test dx,dx ; if not we have to start
- jz fdw_e10 ; with the first block
- mov ax,dx ; new starting block as this must
- sub cx,es:DHNDL_IDX[bx] ; be less than extended size
- fdw_e10:
- jcxz fdw_e20 ; bail out of we have enough
- fdw_e15:
- push ax ; save current block
- push cx ; save # required
- call getnblk ; AX = next block in chain
- pop cx ; restore # required
- pop bx ; recover previous block
- cmp ax,lastcl ; end of chain yet ?
- ja fdw_e40
- loop fdw_e15 ; try another one
- fdw_e20:
- clc ; chain is already long enough
- ret
- fdw_e30:
- ; We have no initial block, so allocate them all
- ; xor ax,ax ; no preconceptions over where we
- call alloc_chain ; allocate chain of CX clusters
- jc fdw_e35
- les bx,current_dhndl
- mov es:DHNDL_BLK1[bx],ax ; remember initial block
- clc
- fdw_e35:
- ret
- fdw_e40:
- ; We have a partial chain, ending at cluster BX
- push bx ; save current end of chain
- xchg ax,bx ; start allocating from cluster AX a
- call alloc_chain ; a chain of CX clusters
- pop bx
- jc fdw_e45
- xchg ax,bx ; AX = previous cluster, link cluster
- call fixfat ; BX to end of the chain
- clc
- fdw_e45:
- ret
- fdrw_seek:
- ;---------
- ; On Entry:
- ; BYTEOFF = offset within file
- ; On Exit:
- ; BLK = cluster containing current filepos
- ; BLKOFFSET = offset within cluster
- ; BLKIDX = cluster index within file
- ; PBLOCK = sector containing current filepos
- ; POFFSET = offset within sector (reflected in ZF)
- ;
- mov ax,byteoff ; where are we now ?
- mov dx,byteoff+WORD
- div clsize
- mov blkidx,ax ; save cluster
- mov blkoffset,dx ; and offset within it
- les bx,current_dhndl
- cmp ax,es:DHNDL_IDX[bx] ; do we know this block ?
- jb fdrw_seek10 ; we can't go backwards, use 1st block
- mov cx,es:DHNDL_BLK[bx] ; get last index block
- jcxz fdrw_seek10 ; use 1st block if it isn't valid
- sub ax,es:DHNDL_IDX[bx] ; skip this many
- jmps fdrw_seek20
- fdrw_seek10:
- mov cx,es:DHNDL_BLK1[bx] ; start with 1st block
- fdrw_seek20:
- xchg ax,cx ; AX = starting cluster
- jcxz fdrw_seek40 ; CX = clusters to skip
- fdrw_seek30:
- push cx
- call getnblk ; get next block
- pop cx
- cmp ax,lastcl ; stop on premature end of chain
- ja fdrw_seek_error ; (file size must be wrong..)
- loop fdrw_seek30
- fdrw_seek40:
- les bx,current_dhndl
- mov dx,blkidx
- mov es:DHNDL_IDX[bx],dx ; remember this position for next time
- mov es:DHNDL_BLK[bx],ax
- mov blk,ax ; save the block for coniguous checks
- mov bx,blkoffset
- call clus2sec ; convert to sector/offset
- mov word ptr fdrwsec,ax ; remember this block
- mov word ptr fdrwsec+WORD,dx
- mov fdrwsecoff,bx ; and offset within it
- test bx,bx ; set ZF
- ; clc ; no problems
- ret
- fdrw_seek_error:
- stc ; we hit unexpected end of chain
- ret ; (shouldn't happen)
- ; Read/write partial sector via deblocking code
- ; On Entry:
- ; FDRWSEC = sector address on disk
- ; FDRWSECOFF = offset within sector
- ; FDRWCNT = byte count for read/write
- ; On Exit:
- ; AX = # of bytes transferred
- deblock_rw:
- ;----------
- mov cx,0FF00h+BF_ISDAT ; CH = preread, buffer is data
- mov dx,word ptr fdrwsec ; set sector to xfer from
- mov ah,byte ptr fdrwsec+WORD
- call locate_buffer ; ES:SI -> buffer
- mov bx,fdrwsecoff ; BX = offset within sector
- mov ax,psecsiz
- mov dx,ax ; DX = physical sector size
- sub ax,bx ; AX = bytes left in sector
- cmp ax,fdrwcnt ; more than we want to transfer?
- jb deblkrw10 ; yes, only do up to end of sector
- mov ax,fdrwcnt ; else do up to end of request
- deblkrw10:
- mov cx,ax ; AX, CX = byte count
- ; (AX for return, CX for MOVSW)
- push ds
- test fdrwflg,1 ; check if reading or writing
- jz dblkrw30 ; skip if writing
- push es
- les di,fdrwptr ; destination is user memory
- pop ds ; source segment is data buffer
- lea si,BCB_DATA[si+bx] ; DS:SI -> data
- jmps dblkrw40 ; copy the data
- dblkrw30: ; we're writing
- or es:BCB_FLAGS[si],BF_DIRTY; mark buffer as dirty
- lea di,BCB_DATA[si+bx] ; ES:DI -> data
- lds si,fdrwptr ; source is user memory
- dblkrw40:
- shr cx,1 ; make it a word count
- rep movsw ; move the words
- jnc dblkrw50 ; skip if even # of bytes
- movsb ; else move last byte
- dblkrw50:
- pop ds ; restore registers
- ret
- ; entry: BYTEOFF = 32-bit offset into file
- ; BLKOFFSET = byte offset within cluster
- ; PRVBLK = block in which transfer starts
- ; FDRWREQ = requested transfer length
- ;---------
- direct_rw:
- ;---------
- sub dx,dx ; assume no extra blocks required
- mov ax,fdrwreq ; total byte count
- mov cx,clsize ; get number of bytes
- sub cx,blkoffset ; CX = bytes remaining in this block
- sub ax,cx ; if wholly containined within block
- jbe direct_rw10 ; then leave it alone
- div clsize ; else get # of extra clusters
- xchg ax,dx ; DX = clusters, AX = remainder
- or ax,ax ; round up if any remainder
- jz direct_rw10 ; skip if even number
- inc dx ; else one more cluster
- direct_rw10: ; DX = # of contiguous clusters req'd
- call check_cont ; check how many contiguous blocks
- mov ax,clsize ; space = cnt * dpbptr->clsize;
- mul cx ; AX:DX = # of bytes transferrable
- sub ax,blkoffset ; BX = skipped bytes in 1st cluster
- sbb dx,0
- ; AX:DX = max # of bytes transferrable
- ; from current position
- test dx,dx
- jnz direct_rw20 ; if > 64 K, use up request
- cmp ax,fdrwreq ; if less than we requested
- jb direct_rw30 ; then lets do it
- direct_rw20:
- xor dx,dx
- mov ax,fdrwreq ; else use requested count
- direct_rw30:
- div psecsiz ; AX = # complete sectors
- mov fdrwdircnt,ax ; save direct sector count
- mov mult_sec,ax ; set multi sector count
- mul psecsiz ; AX = bytes to xfer
- push ax ; save for later
- mov ax,fdrwoff ; FDRWPTR = disk transfer address
- mov cur_dma,ax
- mov ax,fdrwseg
- mov cur_dma_seg,ax
- mov ax,word ptr fdrwsec ; set sector to xfer from
- mov word ptr pblock,ax
- mov ax,word ptr fdrwsec+WORD
- mov word ptr pblock+WORD,ax
- mov rwmode,0000$0110b ;data read/write
- mov cl,fdrwflg
- and cl,1 ; CL = read/write flag
- jz direct_rw40
- xor cx,cx ; indicate no retries
- call read_block ; read in the data
- jmps direct_rw50
- direct_rw40:
- call write_block ; write out the data
- direct_rw50:
- call SynchroniseBuffers ; synchronize BCBs with direct transfer
- pop ax ; recover bytes xfered
- push ds ! pop es ; restore ES = SYSDAT
- ret
- check_cont: ; check for adjacent blocks or space
- ;----------
- ; entry: DX = # of extra contiguous blocks req'd
- ; exit: CX = # of contiguous blocks available
- ; We first check all adjacent allocated clusters.
- ; If we'd like more and we find the end of file
- ; and we are writing and the adjacent blocks aren't
- ; allocated, then we count them as well and link
- ; them into the file.
- mov ax,blk ; current block number
- xor cx,cx ; contiguous blocks found = 0
- test dx,dx ; any extra required ?
- jz check_cont20
- check_cont10: ; get link of current block
- push ax ; save current block
- push cx ; save extra blocks so far
- push dx ; save extra blocks we'd like
- call getnblk ; get the link
- pop dx
- pop cx
- pop bx
- inc bx ; BX = current block + 1
- cmp ax,bx ; check if next block is contiguous
- jne check_cont20 ; and try for another
- inc cx ; extra contiguous cluster
- dec dx ; one less block to check
- jnz check_cont10 ; try again if we still want more
- check_cont20: ; we can do CX extra clusters
- inc cx ; include 1st cluster too..
- ret
- ;------------------
- SynchroniseBuffers: ; synchronize BCBs after multi sector transfer
- ;------------------
- ; On Entry:
- ; FDRWSEG:FDRWOFF = transfer address for IO_READ/IO_WRITE
- ; FDRWDIRCNT = physical sector count for direct transfer
- ; FDRWSEC = sector address for transfer
- ; FDWRFLG = even for write, odd for read
- ; On Exit:
- ; direct transfer buffer or BCB updated if BCB overlap
- ;
- ; If any data buffer is found, that falls into the region affected
- ; by the direct sector transfer, the following action is performed:
- ; If the operation was a read and the sector buffer is clean,
- ; no action is required. If it was dirty, the buffer contents is
- ; copied to the corresponding location in the DTA buffer.
- ; If the operation was a write, the sector buffer is discarded.
- ;
- ;
- mov dx,word ptr fdrwsec
- mov ah,byte ptr fdrwsec+WORD
- mov al,adrive ; get our drive number
- lds bx,bcb_root ; DS:BX -> 1st buffer
- SynchroniseBuffers10:
- test ds:BCB_FLAGS[bx],BF_ISDAT; is this a data buffer?
- jz SynchroniseBuffers30 ; skip if directory or FAT
- cmp al,ds:BCB_DRV[bx] ; does the drive match?
- jne SynchroniseBuffers30 ; skip if different
- mov si,ds:BCB_REC[bx] ; compute bcb->rec - prec
- sub si,dx ; result in SI,CL (lsb..msb)
- mov cl,ds:BCB_REC2[bx]
- sbb cl,ah ; get bits 16-23 of result
- jne SynchroniseBuffers30 ; skip if bcb->rec < prec
- cmp si,ss:fdrwdircnt ; else check against transfer length
- jae SynchroniseBuffers30 ; skip if beyond transfer length
- test ss:fdrwflg,1 ; test direction: read or write
- jz SynchroniseBuffers20 ; skip if disk write
- test ds:BCB_FLAGS[bx],BF_DIRTY; if buffer dirty, did read old data
- jz SynchroniseBuffers30 ; else data read was valid
- push ax ! push dx ; save record address
- mov ax,ss:psecsiz ; # of bytes in sector buffer
- mov cx,ax
- shr cx,1 ; CX = words per sector
- mul si ; AX = byte offset from start buffer
- add ax,ss:fdrwoff ; AX = offset
- xchg ax,di ; DI = offset
- mov es,ss:fdrwseg ; ES:DI -> data to be replaced
- lea si,BCB_DATA[bx]
- rep movsw ; move CX words (one physical sector)
- pop dx ! pop ax ; restore record address
- jmps SynchroniseBuffers30
- SynchroniseBuffers20: ; multi sector write
- mov ds:BCB_DRV[bx],0FFh ; discard this sector
- SynchroniseBuffers30:
- if DOS5
- mov bx,ds:BCB_NEXT[bx]
- cmp bx,ss:word ptr bcb_root
- else
- lds bx,ds:BCB_NEXT[bx] ; get next buffer address
- cmp bx,0ffffh
- endif
- jne SynchroniseBuffers10 ; if so stop
- push ss ! pop ds ; restore DS
- ret
- eject
- Public blockif, ddioif
- ;======= ================================
- blockif: ; disk read/write bios interface
- ;======= ================================
- ; entry: AL = BIOS Request function number
- ; ADRIVE = block device to xfer to/from
- ; RWMODE = read/write mode
- ; CUR_DMA_SEG:CUR_DMA -> xfer address
- ; PBLOCK = starting block of xfer
- ; MULT_CNT = # blocks to xfer
- ; exit: AX = BX = output
- mov req_cmd,al
- mov al,rwmode ; copy rwmode to where the device
- mov req_rwmode,al ; driver can get the hint
- mov ax,cur_dma ; get DMA offset
- push ax ; (save it)
- and ax,000Fh ; get offset within paragraph
- mov req4_buffer,ax ; set transfer offset
- pop ax ; (restore offset)
- mov cl,4
- shr ax,cl ; convert to paragraphs
- add ax,cur_dma_seg ; add in the segment
- mov req4_buffer+2,ax ; set transfer segment
- mov ax,mult_sec ; get requested sector count
- mov req4_count,ax ; set requested sector count
- ;------
- ddioif:
- ;------
- push es
- mov al,adrive ; get selected drive
- call get_ddsc ; ES:BX -> DDSC
- mov ax,word ptr pblock
- mov dx,word ptr pblock+WORD ; DX:AX = starting block
- push es
- les si,es:DDSC_DEVHEAD[bx] ; ES:SI -> device driver
- if DOS5
- ; DOS 4 support
- mov word ptr req4_bigsector,ax
- mov word ptr req4_bigsector+2,dx
- mov req_len,RH4_LEN ; set length of request header
- test es:DH_ATTRIB[si],DA_BIGDRV ; large sector number support?
- jz blockif10 ; no, normal request header
- mov ax,-1 ; indicate we use 32-bit sector number
- blockif10:
- mov req4_sector,ax ; set requested sector address
- else
- mov word ptr req4_bigsector,ax
- mov word ptr req4_bigsector+2,dx
- mov req4_sector,ax ; set requested sector address
- mov req4_sector+2,dx ; (support large DOS drives)
- mov req_len,RH4_LEN ; assume 22 bytes in request header
- test es:DH_ATTRIB[si],DA_BIGDRV ; large sector number support?
- jz blockif10 ; no, normal request header
- mov req_len,RH4_LEN+2 ; else indicate long request
- blockif10:
- endif
- pop es
- call block_device_driver ; make call to device driver
- js blockif20
- xor ax,ax ; no error
- blockif20:
- mov mult_sec,1 ; reset sector count
- mov bx,ax ; AX, BX = return code
- pop es
- ret
- block_device_driver:
- ;------------------
- ; entry: ES:BX -> DDSC, req_hdr partly filled in
- ; exit: AX = status after function
- ; SF = 1 if error occurred
- ; note: BX preserved
- mov al,es:DDSC_MEDIA[bx]
- mov req_media,al ; set current media byte
- mov al,es:DDSC_RUNIT[bx] ; get relative unit #
- mov req_unit,al ; set the unit
- push ds
- push es
- push bx
- push ds
- lds si,es:DDSC_DEVHEAD[bx]
- pop es
- mov bx,offset req_hdr ; ES:BX -> request packet
- call device_driver ; do operation
- pop bx
- pop es
- pop ds
- ret
- ; On Entry:
- ; DS:SI Device Header
- ; ES:BX Current Request Header
- ;
- ; On Exit:
- ; AX Request Header Status
- ;
- device_driver:
- ;------------
- xor ax,ax
- mov es:RH_STATUS[bx],ax ; Initialise return status
- push es
- push bx
- push bp
- callf ss:lock_bios ; lock access to BIOS
- push cs
- call device_driver10 ; fake a callf
- callf ss:unlock_bios ; unlock access to BIOS
- pop bp
- pop bx
- pop es
- sti
- cld ; Restore Flags
- mov ax,es:RH_STATUS[bx] ; Return the Status to the caller
- test ax,ax ; set SF=1 if error
- ret
- device_driver10:
- push ds
- push ds:DH_INTERRUPT[si] ; interrupt routine address on stack
- push ds
- push ds:DH_STRATEGY[si] ; strategy routine address on stack
- retf ; retf to strategy, interrupt, us
- eject
- ; Select drive and check for door open ints
- ; Build fdos_hds to refer to the drive
- ; Exit: DL = drive to be selected (0-15)
- select_logical_drv:
- ;------------------
- ; On Entry:
- ; AL = logical drive to select (with change media checks)
- ; On Exit:
- ; ES:BX -> LDT_
- ;
- cmp al,last_drv ; is it a legal drive ?
- jae select_drv_bad ; no, reject it now
- mov logical_drv,al ; save logical drive
- call get_ldt ; ES:BX -> LDT_ for drive
- jc select_physical_drv ; no LDT_ during init, must be physical
- mov word ptr current_ldt,bx
- mov word ptr current_ldt+WORD,es
- mov al,es:byte ptr LDT_FLAGS+1[bx] ; is the drive valid ?
- test al,(LFLG_NETWRKD+LFLG_JOINED)/100h
- jnz select_drv_bad ; reject networked/joined drives
- test al,LFLG_PHYSICAL/100h
- jz select_drv_bad ; reject non-physical drives
- mov al,es:LDT_NAME[bx] ; get the drive from the ascii name
- and al,1fh ; as the drive may require rebuilding
- dec ax ; make it zero based
- push es ! push bx
- call select_physical_drv ; select the physical root
- pop bx ! pop es
- cmp es:LDT_ROOTLEN[bx],2 ; if logical and physical roots
- jbe select_logical_drv30 ; are the same we are OK now
- if JOIN
- mov al,es:LDT_DRV[bx] ; should we be on a different
- cmp al,fdos_hds_drv ; physical drive ?
- jne select_logical_drv10 ; if so then we'd better rebuild
- endif
- cmp es:LDT_BLK[bx],0FFFFh ; did we have a media change ?
- jne select_logical_drv20 ; then we'd better rebuild
- select_logical_drv10:
- call rebuild_ldt_root ; the LDT_ root block
- select_logical_drv20:
- mov ax,es:LDT_ROOT[bx] ; get virtual root from LDT
- mov fdos_hds_root,ax ; move there
- mov fdos_hds_blk,ax
- if JOIN
- mov al,es:LDT_DRV[bx] ; same with drive
- mov fdos_hds_drv,al
- endif
- select_logical_drv30:
- ret
- select_physical_drv:
- ;-------------------
- ; On Entry:
- ; AL = physical drive to select (with change media checks)
- ; On Exit:
- ; None
- ;
- xor dx,dx
- mov fdos_hds_blk,dx ; put it in the root by default
- mov fdos_hds_root,dx
- mov fdos_hds_drv,al ; set physical drive in working HDS
- cmp al,phys_drv ; should we have a DDSC_ for this drive
- jae select_drv_bad ; no, we can't select it then
- mov physical_drv,al ; save physical drive number
- call select_adrive ; no, better select it
- jc select_drv_critical_error
- ret
- select_drv_bad:
- ;--------------
- ; An attempt has been made to select a bad drive,
- ; return a logical error "invalid drive"
- mov ax,ED_DRIVE ; ED_DRIVE "invalid drive"
- jmp fdos_error
- select_drv_critical_error:
- ;-------------------------
- ; The drive is logically correct, so all error at this point must
- ; be physical ones - so we want a critical error
- jmp generate_critical_error
- eject
- select_adrive:
- ;-------------
- ; This entry is called to physically select a drive (eg. when flushing buffers)
- ; It does not alter the current physical_drv setting, which must be re-selected
- ; afterwards by the caller.
- ;
- ; On Entry:
- ; AL = disk to select (range validated)
- ; On Exit:
- ; CY set if a problem selecting the drive
- mov adrive,al
- mov err_drv,al ; save error drive
- call get_ddsc ; ES:BX -> DDSC_ for drive
- mov al,1 ; AL = "Unknown Unit"
- jc select_drv_err ; error if no DDSC_
- mov ax,es:word ptr DDSC_DEVHEAD[bx]
- mov word ptr error_dev+0,ax
- mov ax,es:word ptr DDSC_DEVHEAD+2[bx]
- mov word ptr error_dev+2,ax
- push es ; remember driver address for error's
- push bx ; preserve DDSC_
- call check_media ; see if media has changed
- pop bx ; restore DDSC_
- pop es
- jc select_drv_err
- ; select the disk drive and fill the drive specific variables
- ; entry: ES:BX -> DDSC_ of disk to select
- ; AX <> 0 if drive requires BPB rebuilt
- ; exit: CY flag set on error
- test ax,ax ; device driver, new select?
- jz select_ddsc ; use current DDSC if old select
- call build_ddsc_from_bpb ; else get BPB and build new DDSC
- jc select_drv_err ; carry flag reset
- call select_ddsc ; use to DDSC for select
- if DELWATCH
- mov ah,DELW_NEWDISK ; we have a new disk so I guess
- mov al,physical_drv ; I'd better tell delwatch
- les bx,current_ddsc ; about the new disk so it
- callf fdos_stub ; knows to update itself
- endif
- clc ;select disk function ok
- ret
- select_drv_err:
- ; On Entry:
- ; AL = extended error code
- ; CY set
- ;
- mov ioexerr,al ; save error code
- ret
- select_ddsc:
- ;-----------
- ; On Entry:
- ; ES:BX -> DDSC_ of drive to be selected
- mov word ptr current_ddsc,bx
- mov word ptr current_ddsc+WORD,es
- push ds ! push es
- pop ds ! pop es ; swap ES and DS
- lea si,DDSC_SECSIZE[bx] ; DS:SI -> DDSC_ original
- mov di,offset local_ddsc ; ES:DI -> DDSC_ copy
- mov cx,LOCAL_DDSC_LEN
- rep movsb ; make a local copy of interesting bits
- push es ! pop ds ; DS=ES=local data segment
- mov ax,psecsiz ; now initialise some other vaiiables
- mov cl,clshf
- shl ax,cl ; AX = bytes per cluster
- mov clsize,ax
- xor ax,ax
- mov al,clmsk
- inc ax ; AX = sectors per cluster
- mov secperclu,ax
- mov al,byte_nfats ; AX = number of FATs
- mov nfats,ax ; (it's handier as a word
- mov ax,diradd ; number of FAT records can be
- sub ax,fatadd ; bigger than 255
- xor dx,dx
- div nfats
- mov nfatrecs,ax
- mov cx,FCBLEN
- mov ax,clsize ; convert from cluster size
- xor dx,dx ; to number of dir entries
- div cx ; per cluster - handy for
- mov dirperclu,ax ; subdirectories
- mov ax,FAT12
- cmp lastcl,MAX12 ; is it a 12 bit FAT ?
- jbe select_ddsc10
- mov ax,FAT16 ; no, it's 16 bit
- select_ddsc10:
- mov dosfat,ax ; remember which for later
- clc ; drive all selected
- ret
- eject
- build_ddsc_from_bpb: ; call device driver to build BPB, convert to DDSC_
- ;-------------------
- ; On Entry:
- ; ES:BX -> DDSC_ to rebuild
- ; On Exit:
- ; ES:BX preserved
- ; CY set on error
- ; AL = error code
- push es
- push bx ; save DDSC_ address
- xor di,di
- mov ax,deblock_seg
- mov es,ax ; ES:DI -> deblock seg
- test ax,ax ; if we are deblocking spare buffer
- jnz build_bpb10 ; might be in high memory
- dec ax ; AX = FFFF
- mov dx,ax ; compute impossible record #
- mov cx,BF_ISDIR ; locate directory sector w/o preread
- call locate_buffer ; this will find the cheapest buffer
- mov es:BCB_DRV[si],0FFh ; don't really want this...
- lea di,BCB_DATA[si] ; ES:DI -> disk buffer
- build_bpb10:
- mov req4_buffer,di ; xfer to ES:DI
- mov req4_buffer+2,es
- pop bx ; restore DDSC_ address
- pop es
- push ds
- lds si,es:DDSC_DEVHEAD[bx] ; DS:SI -> device header
- mov ax,ds:DH_ATTRIB[si] ; non-FAT ID driver ("non-IBM") bit
- pop ds ; in device header attributes
- test ax,DA_NONIBM
- jnz bldbpb30 ; skip if media byte in FAT not used
- mov req_rwmode,0 ; read of system area
- mov req_len,RH4_LEN ; set length field
- mov req_cmd,CMD_INPUT ; read first FAT sector off disk
- if DOS5
- test ax,DA_BIGDRV ; large sector numbers ?
- endif
- mov ax,1
- mov req4_count,ax ; read 1st FAT sector
- cwd ; DS:AX = sector 1
- mov word ptr req4_bigsector,ax
- mov word ptr req4_bigsector+2,dx
- if DOS5
- jz bldbpb20
- dec ax ! dec ax ; AX = 0FFFFh
- bldbpb20:
- endif
- mov req4_sector,ax ; set requested sector address
- mov req4_sector+2,dx ; (support large DOS drives)
- call block_device_driver ; try to read FAT sector, AX = status
- js bldbpb_err ; skip if errors (AX negative)
- bldbpb30:
- mov req_len,RH2_LEN ; length of req
- mov req_cmd,CMD_BUILD_BPB ; "build bpb"
- call block_device_driver ; call the device driver
- js bldbpb_err ; skip if errors (AX negative)
- push ds
- push es
- push bx
- mov di,bx ; ES:DI -> DDSC_ to initialise
- lds si,dword ptr req2_bpb ; DS:SI -> BPB to convert
- call bpb2ddsc ; rebuild the DDSC_
- pop bx
- pop es
- pop ds
- clc ; success - we have a new DDSC_
- ret
- bldbpb_err:
- stc ; we had a problem
- ret
- eject
- ;-----------
- check_media: ; check media if DPH media flag set
- ;-----------
- ; On Entry:
- ; ES:BX -> DDSC_ of physical drive to check
- ; On Exit:
- ; CY set on error, AX = error code
- ; else
- ; AX <> 0 if disk requires BPB rebuild
- ; If definite/possible change then LDT's marked as invalid
- ; If possible then buffers/hashing discarded provided they are clean
- ; If definite then all buffers/hashing for drive discarded even if dirty
- ;
- mov req_len,RH1_LEN ; set length field
- mov req_cmd,CMD_MEDIA_CHECK ; media check routine
- call block_device_driver ; call the device driver
- jns chkmed10
- stc ; we have a problem, generate
- ret ; an error
- chkmed10:
- mov al,req_media+1 ; else get returned value
- xor ah,ah ; watch out for 1st access too..
- xchg ah,es:DDSC_FIRST[bx] ; treat never accessed as changed
- cmp al,1 ; 1 = no change
- jne chkmed20
- dec ax ; AL=0, build bpb only if DDSC_FIRST
- ; clc ; it all went OK
- ret
- chkmed20:
- mov dl,adrive ; media may have/has changed
- call mark_ldt_unsure ; so force LDT's to unsure
- ; AL = 00 if maybe changed, FF for definitely changed
- test al,al
- jz chkmed_maybe ; media may have changed
- chkmed_changed: ; disk has changed for sure
- call discard_files ; discard open files
- jmps chkmed30 ; discard buffers, build bpb required
- chkmed_maybe: ; disk has possibly changed
- call discard_dir ; we can always discard dir as they
- mov ah,BF_DIRTY ; won't be dirty
- mov al,adrive
- call buffers_check ; any dirty buffers on adrive?
- jnz chkmed40 ; yes, can't discard FAT
- chkmed30:
- call discard_all ; discard buffers for drive
- chkmed40:
- or ax,0FFFFh ; better rebuild bpb
- ; clc
- ret
- Public mark_ldt_unsure
- mark_ldt_unsure:
- ;---------------
- ; On Entry:
- ; DL = physical drive
- ; On Exit:
- ; All corresponding LDT's marked as unsure
- ; All reg preserved
- ;
- push es
- push ax
- push bx
- xor ax,ax ; start with drive A:
- mlu10:
- call get_ldt_raw ; ES:BX -> LDT_
- jc mlu30 ; CY = no more LDT's
- test es:LDT_FLAGS[bx],LFLG_NETWRKD+LFLG_JOINED
- jnz mlu20 ; if networked leave it alone
- cmp dl,es:LDT_DRV[bx] ; does the physical drive match ?
- jne mlu20
- mov es:LDT_BLK[bx],0FFFFh ; indicate we shouldn't trust BLK
- mlu20:
- inc ax ; onto next LDT
- jmps mlu10
- mlu30:
- pop bx
- pop ax
- pop es
- ret
- ;-----------
- write_block:
- ;-----------
- ; entry: RWMODE = write type
- ; bit 0:
- ; 1 - write, not read
- ; bits 2-1 (affected disk area)
- ; 0 0 - system area
- ; 0 1 - FAT area
- ; 1 0 - root or sub directory
- ; 1 1 - data area
- or rwmode,1 ; mark it as a write
- xor cx,cx ; indicate no second attempt
- mov al,CMD_OUTPUT ; assume normal write
- cmp verify_flag,0 ; is verify on ?
- je rdwr_block
- mov al,CMD_OUTPUT_VERIFY ; assume use write w/ verify
- jmps rdwr_block
- ;----------
- read_block:
- ;----------
- ; entry: RWMODE = read type
- ; bit 0:
- ; 0 - read, not write
- ; bits 2-1 (affected disk area)
- ; 0 0 - system area
- ; 0 1 - FAT area
- ; 1 0 - root or sub directory
- ; 1 1 - data area
- ; CX <> 0 if FAT retry possible (critical error should then
- ; be avoided)
- ; exit: SF = 0 if success
- ; SF = 1 if failure (CX was non-zero on call)
- and rwmode,not 1 ;mark it as a read
- mov al,CMD_INPUT
- rdwr_block:
- push cx
- call blockif ;current drive, track,....
- pop cx
- jns rdwrb5
- jcxz rdwrb10 ; test if any disk error detected
- rdwrb5:
- ret ; skip if yes
- rdwrb10:
- mov ioexerr,al ; save extended error
- test al,al ; is it write protect error ?
- jnz rdwrb20 ; we have dirty buffers we can't write
- call discard_dirty ; out, so throw 'em away
- rdwrb20:
- mov al,adrive ; if error on different drive
- cmp al,physical_drv ; treat error as media change
- je generate_critical_error ; if same drive, report error
- call discard_all ; discard all buffers on drive
- call discard_files ; and flush files
- jmp fdos_restart ; try to restart the instruction
- generate_critical_error:
- ;-----------------------
- ; On Entry:
- ; err_drv, rwmode, ioexerr set up
- ; On Exit:
- ; None - we don't come back
- ;
- mov al,ioexerr ; AL = BIOS error return byte
- cbw ; make it a word
- cmp ax,15 ; only handle sensible errors
- jb gen_crit_err10 ; anything else becomes
- mov ax,12 ; general failure
- gen_crit_err10:
- neg ax ; convert to our negative errors
- add ax,ED_PROTECT ; and start with write protect
- jmp fdos_error ; now return with error
- eject
- clus2sec: ; convert from cluster/offset to sector/offset
- ;--------
- ; On Entry:
- ; AX = cluster
- ; BX = byte offset in cluster
- ; On Exit:
- ; DX:AX = sector
- ; BX = byte offset in sector
- ;
- xchg ax,cx ; remember cluster in CX
- xor dx,dx
- xchg ax,bx ; DX:AX = byte offset
- div psecsiz ; AX = sector offset, DX = byte offset
- mov bx,dx ; BX = byte offset in sector
- xchg ax,cx ; AX = cluster, CX = sector offset
- dec ax
- dec ax ; forget about 2 reserved clusters
- mul secperclu ; DX:AX = offset of cluster
- add ax,datadd
- adc dx,0 ; DX:AX = offset of start of dir
- add ax,cx ; DX:AX - add in sector offset
- adc dx,0
- ret
- end