From 80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6 Mon Sep 17 00:00:00 2001 From: Rich Turner Date: Fri, 12 Aug 1983 17:53:34 -0700 Subject: MS-DOS v2.0 Release --- v2.0/source/DISK.ASM | 1302 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1302 insertions(+) create mode 100644 v2.0/source/DISK.ASM (limited to 'v2.0/source/DISK.ASM') diff --git a/v2.0/source/DISK.ASM b/v2.0/source/DISK.ASM new file mode 100644 index 0000000..b1acd82 --- /dev/null +++ b/v2.0/source/DISK.ASM @@ -0,0 +1,1302 @@ +; +; Disk routines for MSDOS +; + +INCLUDE DOSSEG.ASM + +CODE SEGMENT BYTE PUBLIC 'CODE' + ASSUME SS:DOSGROUP,CS:DOSGROUP + +.xlist +.xcref +INCLUDE DOSSYM.ASM +INCLUDE DEVSYM.ASM +.cref +.list + +TITLE DISK - Disk utility routines +NAME Disk + + i_need COUTDSAV,BYTE + i_need COUTSAV,DWORD + i_need CINDSAV,BYTE + i_need CINSAV,DWORD + i_need CONSWAP,BYTE + i_need IDLEINT,BYTE + i_need THISFCB,DWORD + i_need DMAADD,DWORD + i_need DEVCALL,BYTE + i_need CALLSCNT,WORD + i_need CALLXAD,DWORD + i_need CONTPOS,WORD + i_need NEXTADD,WORD + i_need CONBUF,BYTE + i_need User_SS,WORD + i_need User_SP,WORD + i_need DSKStack,BYTE + i_need InDOS,BYTE + i_need NumIO,BYTE + i_need CurDrv,BYTE + i_need ThisDrv,BYTE + i_need ClusFac,BYTE + i_need SecClusPos,BYTE + i_need DirSec,WORD + i_need ClusNum,WORD + i_need NxtClusNum,WORD + i_need ReadOp,BYTE + i_need DskErr,BYTE + i_need RecCnt,WORD + i_need RecPos,4 + i_need Trans,BYTE + i_need BytPos,4 + i_need SecPos,WORD + i_need BytSecPos,WORD + i_need BytCnt1,WORD + i_need BytCnt2,WORD + i_need SecCnt,WORD + i_need ThisDPB,DWORD + i_need LastPos,WORD + i_need ValSec,WORD + i_need GrowCnt,DWORD + +SUBTTL LOAD -- MAIN READ ROUTINE AND DEVICE IN ROUTINES +PAGE +; * * * * Drivers for file input from devices * * * * + + procedure SWAPBACK,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + PUSH ES + PUSH DI + PUSH SI + PUSH BX + MOV BX,1 + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,BYTE PTR [COUTDSAV] + LDS SI,[COUTSAV] +ASSUME DS:NOTHING + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + MOV ES:[DI.fcb_DEVID],BL + PUSH SS + POP DS +ASSUME DS:DOSGROUP + XOR BX,BX + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,BYTE PTR [CINDSAV] + LDS SI,[CINSAV] +ASSUME DS:NOTHING + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + MOV ES:[DI.fcb_DEVID],BL + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV BYTE PTR [CONSWAP],0 + MOV BYTE PTR [IDLEINT],1 +SWAPRET: + POP BX + POP SI + POP DI + POP ES + return +SWAPBACK ENDP + + procedure SWAPCON,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + PUSH ES + PUSH DI + PUSH SI + PUSH BX + MOV BYTE PTR [CONSWAP],1 + MOV BYTE PTR [IDLEINT],0 + XOR BX,BX + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,ES:[DI.fcb_DEVID] + MOV BYTE PTR [CINDSAV],BL + LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS] +ASSUME DS:NOTHING + MOV WORD PTR [CINSAV],SI + MOV WORD PTR [CINSAV+2],DS + LDS SI,[THISFCB] + MOV BL,[SI.fcb_DEVID] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] + MOV ES:[DI.fcb_DEVID],BL + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV BX,1 + invoke get_sf_from_jfn + ADD DI,sf_fcb + MOV BL,ES:[DI.fcb_DEVID] + MOV BYTE PTR [COUTDSAV],BL + LDS SI,DWORD PTR ES:[DI.fcb_FIRCLUS] +ASSUME DS:NOTHING + MOV WORD PTR [COUTSAV],SI + MOV WORD PTR [COUTSAV+2],DS + LDS SI,[THISFCB] + MOV BL,[SI.fcb_DEVID] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] + MOV ES:[DI.fcb_DEVID],BL + MOV WORD PTR ES:[DI.fcb_FIRCLUS],SI + MOV WORD PTR ES:[DI.fcb_FIRCLUS+2],DS + PUSH SS + POP DS + JMP SWAPRET +SWAPCON ENDP + + procedure LOAD,NEAR +ASSUME DS:NOTHING,ES:NOTHING +; +; Inputs: +; DS:DI point to FCB +; DX:AX = Position in file to read +; CX = No. of records to read +; Outputs: +; DX:AX = Position of last record read +; CX = No. of bytes read +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + call SETUP +ASSUME DS:DOSGROUP + OR BL,BL ; Check for named device I/O + JS READDEV + call DISKREAD + return + +READDEV: +ASSUME DS:DOSGROUP,ES:NOTHING + LES DI,[DMAADD] + TEST BL,40H ; End of file? + JZ ENDRDDEVJ3 + TEST BL,ISNULL ; NUL device? + JZ TESTRAW ; NO + XOR AL,AL ; Indicate EOF +ENDRDDEVJ3: JMP ENDRDDEVJ2 + +DVRDRAW: +ASSUME DS:DOSGROUP + PUSH ES + POP DS +ASSUME DS:NOTHING +DVRDRAWR: + MOV BX,DI ; DS:BX transfer addr + XOR DX,DX ; Start at 0 + XOR AX,AX ; Media Byte, unit = 0 + invoke SETREAD + LDS SI,[THISFCB] + invoke DEVIOCALL + MOV DX,DI ; DX is preserved by INT 24 + MOV AH,86H ; Read error + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CRDROK ; No errors + invoke CHARHARD + MOV DI,DX + CMP AL,1 + JZ DVRDRAWR ; Retry +CRDROK: + MOV DI,DX + ADD DI,[CALLSCNT] ; Amount transferred + JMP SHORT ENDRDDEVJ2 + +TESTRAW: + TEST BL,020H ; Raw mode? + JNZ DVRDRAW + TEST BL,ISCIN ; Is it console device? + JZ NOTRDCON + JMP READCON +NOTRDCON: + MOV AX,ES + MOV DS,AX +ASSUME DS:NOTHING + MOV BX,DI + XOR DX,DX + MOV AX,DX + PUSH CX + MOV CX,1 + invoke SETREAD + POP CX + LDS SI,[THISFCB] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] +DVRDLP: + invoke DSKSTATCHK + invoke DEVIOCALL2 + PUSH DI + MOV AH,86H + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CRDOK + invoke CHARHARD + POP DI + MOV [CALLSCNT],1 + CMP AL,1 + JZ DVRDLP ;Retry + XOR AL,AL ;Pick some random character + JMP SHORT DVRDIGN +CRDOK: + POP DI + CMP [CALLSCNT],1 + JNZ ENDRDDEVJ2 + PUSH DS + MOV DS,WORD PTR [CALLXAD+2] + MOV AL,BYTE PTR [DI] + POP DS +DVRDIGN: + INC WORD PTR [CALLXAD] + MOV [DEVCALL.REQSTAT],0 + INC DI + CMP AL,1AH ; ^Z? + JZ ENDRDDEVJ + CMP AL,c_CR ; CR? + LOOPNZ DVRDLP +ENDRDDEVJ: + DEC DI +ENDRDDEVJ2: + JMP SHORT ENDRDDEV + +ASSUME DS:NOTHING,ES:NOTHING + +TRANBUF: + LODSB + STOSB + CMP AL,c_CR ; Check for carriage return + JNZ NORMCH + MOV BYTE PTR [SI],c_LF +NORMCH: + CMP AL,c_LF + LOOPNZ TRANBUF + JNZ ENDRDCON + XOR SI,SI ; Cause a new buffer to be read + invoke OUT ; Transmit linefeed + OR AL,1 ; Clear zero flag--not end of file +ENDRDCON: + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CALL SWAPBACK + MOV [CONTPOS],SI +ENDRDDEV: + PUSH SS + POP DS +ASSUME DS:DOSGROUP + MOV [NEXTADD],DI + JNZ SETFCBC ; Zero set if Ctrl-Z found in input + LES DI,[THISFCB] + AND ES:BYTE PTR [DI.fcb_DEVID],0FFH-40H ; Mark as no more data available +SETFCBC: + call SETFCB + return + +ASSUME DS:NOTHING,ES:NOTHING + +READCON: +ASSUME DS:DOSGROUP + CALL SWAPCON + MOV SI,[CONTPOS] + OR SI,SI + JNZ TRANBUF + CMP BYTE PTR [CONBUF],128 + JZ GETBUF + MOV WORD PTR [CONBUF],0FF80H ; Set up 128-byte buffer with no template +GETBUF: + PUSH CX + PUSH ES + PUSH DI + MOV DX,OFFSET DOSGROUP:CONBUF + invoke $STD_CON_STRING_INPUT ; Get input buffer + POP DI + POP ES + POP CX + MOV SI,2 + OFFSET DOSGROUP:CONBUF + CMP BYTE PTR [SI],1AH ; Check for Ctrl-Z in first character + JNZ TRANBUF + MOV AL,1AH + STOSB + DEC DI + MOV AL,10 + invoke OUT ; Send linefeed + XOR SI,SI + JMP SHORT ENDRDCON + +LOAD ENDP + +SUBTTL STORE -- MAIN WRITE ROUTINE AND DEVICE OUT ROUTINES +PAGE +ASSUME DS:NOTHING,ES:NOTHING + procedure STORE,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DI point to FCB +; DX:AX = Position in file of disk transfer +; CX = Record count +; Outputs: +; DX:AX = Position of last record written +; CX = No. of records written +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + call SETUP +ASSUME DS:DOSGROUP + OR BL,BL + JS WRTDEV + invoke DATE16 + MOV ES:[DI.fcb_FDATE],AX + MOV ES:[DI.fcb_FTIME],DX + call DISKWRITE + return + +WRITECON: + PUSH DS + PUSH SS + POP DS +ASSUME DS:DOSGROUP + CALL SWAPCON + POP DS +ASSUME DS:NOTHING + MOV SI,BX + PUSH CX +WRCONLP: + LODSB + CMP AL,1AH ; ^Z? + JZ CONEOF + invoke OUT + LOOP WRCONLP +CONEOF: + POP AX ; Count + SUB AX,CX ; Amount actually written + POP DS +ASSUME DS:DOSGROUP + CALL SWAPBACK + JMP SHORT ENDWRDEV + +DVWRTRAW: +ASSUME DS:NOTHING + XOR AX,AX ; Media Byte, unit = 0 + invoke SETWRITE + LDS SI,[THISFCB] + invoke DEVIOCALL + MOV DX,DI + MOV AH,87H + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CWRTROK + invoke CHARHARD + MOV BX,DX ; Recall transfer addr + CMP AL,1 + JZ DVWRTRAW ; Try again +CWRTROK: + POP DS +ASSUME DS:DOSGROUP + MOV AX,[CALLSCNT] ; Get actual number of bytes transferred +ENDWRDEV: + LES DI,[THISFCB] + XOR DX,DX + DIV ES:[DI.fcb_RECSIZ] + MOV CX,AX ; Partial record is ignored + call ADDREC + return + +ASSUME DS:DOSGROUP +WRTDEV: + OR BL,40H ; Reset EOF for input + XOR AX,AX + JCXZ ENDWRDEV ; problem of creating on a device. + PUSH DS + MOV AL,BL + LDS BX,[DMAADD] +ASSUME DS:NOTHING + MOV DI,BX + XOR DX,DX ; Set starting point + TEST AL,020H ; Raw? + JNZ DVWRTRAW + TEST AL,ISCOUT ; Console output device? + JNZ WRITECON + TEST AL,ISNULL + JNZ WRTNUL + MOV AX,DX + CMP BYTE PTR [BX],1AH ; ^Z? + JZ WRTCOOKDONE ; Yes, transfer nothing + PUSH CX + MOV CX,1 + invoke SETWRITE + POP CX + LDS SI,[THISFCB] + LDS SI,DWORD PTR [SI.fcb_FIRCLUS] +DVWRTLP: + invoke DSKSTATCHK + invoke DEVIOCALL2 + PUSH DI + MOV AH,87H + MOV DI,[DEVCALL.REQSTAT] + TEST DI,STERR + JZ CWROK + invoke CHARHARD + POP DI + MOV [CALLSCNT],1 + CMP AL,1 + JZ DVWRTLP + JMP SHORT DVWRTIGN +CWROK: + POP DI + CMP [CALLSCNT],0 + JZ WRTCOOKDONE +DVWRTIGN: + INC DX + INC WORD PTR [CALLXAD] + INC DI + PUSH DS + MOV DS,WORD PTR [CALLXAD+2] + CMP BYTE PTR [DI],1AH ; ^Z? + POP DS + JZ WRTCOOKDONE + MOV [DEVCALL.REQSTAT],0 + LOOP DVWRTLP +WRTCOOKDONE: + MOV AX,DX + POP DS + JMP ENDWRDEV + +WRTNUL: + MOV DX,CX ;Entire transfer done + JMP WRTCOOKDONE + +STORE ENDP + + procedure get_io_fcb,near +ASSUME DS:NOTHING,ES:NOTHING +; Convert JFN number in BX to FCB in DS:SI + PUSH SS + POP DS +ASSUME DS:DOSGROUP + PUSH ES + PUSH DI + invoke get_sf_from_jfn + JC RET44P + MOV SI,DI + ADD SI,sf_fcb + PUSH ES + POP DS +ASSUME DS:NOTHING +RET44P: + POP DI + POP ES + return +get_io_fcb ENDP + +SUBTTL GETTHISDRV -- FIND CURRENT DRIVE +PAGE +; Input: AL has drive identifier (1=A, 0=default) +; Output: AL has physical drive (0=A) +; Carry set if invalid drive (and AL is garbage anyway) + procedure GetThisDrv,NEAR +ASSUME DS:NOTHING,ES:NOTHING + CMP BYTE PTR [NUMIO],AL + retc + DEC AL + JNS PHYDRV + MOV AL,[CURDRV] +PHYDRV: + MOV BYTE PTR [THISDRV],AL + return +GetThisDrv ENDP + +SUBTTL DIRREAD -- READ A DIRECTORY SECTOR +PAGE + procedure DirRead,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; AX = Directory block number (relative to first block of directory) +; ES:BP = Base of drive parameters +; [DIRSEC] = First sector of first cluster of directory +; [CLUSNUM] = Next cluster +; [CLUSFAC] = Sectors/Cluster +; Function: +; Read the directory block into [CURBUF]. +; Outputs: +; [NXTCLUSNUM] = Next cluster (after the one skipped to) +; [SECCLUSPOS] Set +; ES:BP unchanged [CURBUF] Points to Buffer with dir sector +; All other registers destroyed. + + MOV CL,[CLUSFAC] + DIV CL ; AL # clusters to skip, AH position in cluster + MOV [SECCLUSPOS],AH + MOV CL,AL + XOR CH,CH + MOV DX,[DIRSEC] + ADD DL,AH + ADC DH,0 + MOV BX,[CLUSNUM] + MOV [NXTCLUSNUM],BX + JCXZ FIRSTCLUSTER +SKPCLLP: + invoke UNPACK + XCHG BX,DI + CMP BX,0FF8H + JAE HAVESKIPPED + LOOP SKPCLLP +HAVESKIPPED: + MOV [NXTCLUSNUM],BX + MOV DX,DI + MOV BL,AH + invoke FIGREC + entry FIRSTCLUSTER + XOR AL,AL ; Indicate pre-read + MOV AH,DIRPRI + invoke GETBUFFR + ret +DirRead ENDP + +SUBTTL FATSECRD -- READ A FAT SECTOR +PAGE + procedure FATSecRd,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; Same as DREAD +; DS:BX = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Calls BIOS to perform FAT read. +; Outputs: +; Same as DREAD + + MOV DI,CX + MOV CL,ES:[BP.dpb_FAT_count] + MOV AL,ES:[BP.dpb_FAT_size] + XOR AH,AH + MOV CH,AH + PUSH DX +NXTFAT: + PUSH CX + PUSH AX + MOV CX,DI + CALL DSKREAD + POP AX + POP CX + JZ RET41P + ADD DX,AX + LOOP NXTFAT + POP DX + MOV CX,DI + +; NOTE FALL THROUGH + +SUBTTL DREAD -- DO A DISK READ +PAGE + entry DREAD +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Calls BIOS to perform disk read. If BIOS reports +; errors, will call HARDERR for further action. +; DS,ES:BP preserved. All other registers destroyed. + + CALL DSKREAD + retz + MOV BYTE PTR [READOP],0 + invoke HARDERR + CMP AL,1 ; Check for retry + JZ DREAD + return ; Ignore otherwise +RET41P: POP DX + return +FATSecRd ENDP + +SUBTTL DSKREAD -- PHYSICAL DISK READ +PAGE + procedure DskRead,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer addr +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Call BIOS to perform disk read +; Outputs: +; DI = CX on entry +; CX = Number of sectors unsuccessfully transfered +; AX = Status word as returned by BIOS (error code in AL if error) +; Zero set if OK (from BIOS) +; Zero clear if error +; SI Destroyed, others preserved + + PUSH CX + MOV AH,ES:[BP.dpb_media] + MOV AL,ES:[BP.dpb_UNIT] + PUSH BX + PUSH ES + invoke SETREAD + JMP DODSKOP + +SUBTTL DWRITE -- SEE ABOUT WRITING +PAGE + entry DWRITE +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer address +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Calls BIOS to perform disk write. If BIOS reports +; errors, will call HARDERR for further action. +; BP preserved. All other registers destroyed. + + CALL DSKWRITE + retz + MOV BYTE PTR [READOP],1 + invoke HARDERR + CMP AL,1 ; Check for retry + JZ DWRITE + return + +SUBTTL DSKWRITE -- PHYSICAL DISK WRITE +PAGE + entry DSKWRITE +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:BX = Transfer addr +; CX = Number of sectors +; DX = Absolute record number +; ES:BP = Base of drive parameters +; Function: +; Call BIOS to perform disk read +; Outputs: +; DI = CX on entry +; CX = Number of sectors unsuccessfully transfered +; AX = Status word as returned by BIOS (error code in AL if error) +; Zero set if OK (from BIOS) +; Zero clear if error +; SI Destroyed, others preserved + + PUSH CX + MOV AH,ES:[BP.dpb_media] + MOV AL,ES:[BP.dpb_UNIT] + PUSH BX + PUSH ES + invoke SETWRITE +DODSKOP: + MOV CX,DS ; Save DS + POP DS ; DS:BP points to DPB + PUSH DS + LDS SI,DS:[BP.dpb_driver_addr] + invoke DEVIOCALL2 + MOV DS,CX ; Restore DS + POP ES ; Restore ES + POP BX + MOV CX,[CALLSCNT] ; Number of sectors transferred + POP DI + SUB CX,DI + NEG CX ; Number of sectors not transferred + MOV AX,[DEVCALL.REQSTAT] + TEST AX,STERR + return +DskRead ENDP + +SUBTTL SETUP -- SETUP A DISK READ OR WRITE FROM USER +PAGE +ASSUME DS:DOSGROUP,ES:NOTHING + + procedure SETUP,NEAR +ASSUME DS:NOTHING,ES:NOTHING + +; Inputs: +; DS:DI point to FCB +; DX:AX = Record position in file of disk transfer +; CX = Record count +; Outputs: +; DS = DOSGROUP +; BL = fcb_DEVID from FCB +; CX = No. of bytes to transfer (0 = 64K) +; [THISDPB] = Base of drive parameters +; [RECCNT] = Record count +; [RECPOS] = Record position in file +; ES:DI Points to FCB +; [THISFCB] = ES:DI +; [NEXTADD] = Displacement of disk transfer within segment +; [SECPOS] = Position of first sector +; [BYTPOS] = Byte position in file +; [BYTSECPOS] = Byte position in first sector +; [CLUSNUM] = First cluster +; [SECCLUSPOS] = Sector within first cluster +; [DSKERR] = 0 (no errors yet) +; [TRANS] = 0 (No transfers yet) +; [THISDRV] = Physical drive unit number + + PUSH AX + MOV AL,[DI] + DEC AL + MOV BYTE PTR [THISDRV],AL + MOV AL,[DI.fcb_DEVID] + MOV SI,[DI.fcb_RECSIZ] + OR SI,SI + JNZ HAVRECSIZ + MOV SI,128 + MOV [DI.fcb_RECSIZ],SI +HAVRECSIZ: + MOV WORD PTR [THISFCB+2],DS + PUSH SS + POP DS ; Set DS to DOSGROUP +ASSUME DS:DOSGROUP + MOV WORD PTR [THISFCB],DI + OR AL,AL ; Is it a device? + JNS NOTDEVICE + XOR AL,AL ; Fake in drive 0 so we can get BP +NOTDEVICE: + invoke GETBP + POP AX + JNC CheckRecLen + XOR CX,CX + MOV BYTE PTR [DSKERR],4 + POP BX + return + +CheckRecLen: + CMP SI,64 ; Check if highest byte of RECPOS is significant + JB SMALREC + XOR DH,DH ; Ignore MSB if record >= 64 bytes +SMALREC: + MOV [RECCNT],CX + MOV WORD PTR [RECPOS],AX + MOV WORD PTR [RECPOS+2],DX + MOV BX,WORD PTR [DMAADD] + MOV [NEXTADD],BX + MOV BYTE PTR [DSKERR],0 + MOV BYTE PTR [TRANS],0 + MOV BX,DX + MUL SI + MOV WORD PTR [BYTPOS],AX + PUSH DX + MOV AX,BX + MUL SI + POP BX + ADD AX,BX + ADC DX,0 ; Ripple carry + JNZ EOFERR + MOV WORD PTR [BYTPOS+2],AX + MOV DX,AX + MOV AX,WORD PTR [BYTPOS] + MOV BX,ES:[BP.dpb_sector_size] + CMP DX,BX ; See if divide will overflow + JNC EOFERR + DIV BX + MOV [SECPOS],AX + MOV [BYTSECPOS],DX + MOV DX,AX + AND AL,ES:[BP.dpb_cluster_mask] + MOV [SECCLUSPOS],AL + MOV AX,CX ; Record count + MOV CL,ES:[BP.dpb_cluster_shift] + SHR DX,CL + MOV [CLUSNUM],DX + MUL SI ; Multiply by bytes per record + MOV CX,AX + ADD AX,WORD PTR [DMAADD] ; See if it will fit in one segment + ADC DX,0 + JZ OK ; Must be less than 64K + MOV AX,WORD PTR [DMAADD] + NEG AX ; Amount of room left in segment + JNZ PARTSEG + DEC AX +PARTSEG: + XOR DX,DX + DIV SI ; How many records will fit? + MOV [RECCNT],AX + MUL SI ; Translate that back into bytes + MOV BYTE PTR [DSKERR],2 ; Flag that trimming took place + MOV CX,AX + JCXZ NOROOM +OK: + LES DI,[THISFCB] + MOV BL,ES:[DI.fcb_DEVID] + return + +EOFERR: + MOV BYTE PTR [DSKERR],1 + XOR CX,CX +NOROOM: + LES DI,[THISFCB] + POP BX ; Kill return address + return +SETUP ENDP + +SUBTTL BREAKDOWN -- CUT A USER READ OR WRITE INTO PIECES +PAGE + procedure BREAKDOWN,near +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; CX = Length of disk transfer in bytes +; ES:BP = Base of drive parameters +; [BYTSECPOS] = Byte position witin first sector +; Outputs: +; [BYTCNT1] = Bytes to transfer in first sector +; [SECCNT] = No. of whole sectors to transfer +; [BYTCNT2] = Bytes to transfer in last sector +; AX, BX, DX destroyed. No other registers affected. + + MOV AX,[BYTSECPOS] + MOV BX,CX + OR AX,AX + JZ SAVFIR ; Partial first sector? + SUB AX,ES:[BP.dpb_sector_size] + NEG AX ; Max number of bytes left in first sector + SUB BX,AX ; Subtract from total length + JAE SAVFIR + ADD AX,BX ; Don't use all of the rest of the sector + XOR BX,BX ; And no bytes are left +SAVFIR: + MOV [BYTCNT1],AX + MOV AX,BX + XOR DX,DX + DIV ES:[BP.dpb_sector_size] ; How many whole sectors? + MOV [SECCNT],AX + MOV [BYTCNT2],DX ; Bytes remaining for last sector + OR DX,[BYTCNT1] + retnz ; NOT (BYTCNT1 = BYTCNT2 = 0) + CMP AX,1 + retnz + MOV AX,ES:[BP.dpb_sector_size] ; Buffer EXACT one sector I/O + MOV [BYTCNT2],AX + MOV [SECCNT],DX ; DX = 0 + return +BreakDown ENDP + +SUBTTL DISKREAD -- PERFORM USER DISK READ +PAGE + procedure DISKREAD,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; Outputs of SETUP +; Function: +; Perform disk read +; Outputs: +; DX:AX = Position of last record read +; CX = No. of records read +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + MOV AX,ES:WORD PTR [DI.fcb_FILSIZ] + MOV BX,ES:WORD PTR [DI.fcb_FILSIZ+2] + SUB AX,WORD PTR [BYTPOS] + SBB BX,WORD PTR [BYTPOS+2] + JB RDERR + JNZ ENUF + OR AX,AX + JZ RDERR + CMP AX,CX + JAE ENUF + MOV CX,AX +ENUF: + LES BP,[THISDPB] + CALL BREAKDOWN + MOV CX,[CLUSNUM] + invoke FNDCLUS + OR CX,CX + JZ SHORT SKIPERR +RDERR: + JMP WRTERR +RDLASTJ:JMP RDLAST +SETFCBJ2: JMP SETFCB + +SKIPERR: + + MOV [LASTPOS],DX + MOV [CLUSNUM],BX + CMP [BYTCNT1],0 + JZ RDMID + invoke BUFRD +RDMID: + CMP [SECCNT],0 + JZ RDLASTJ + invoke NEXTSEC + JC SETFCBJ2 + MOV BYTE PTR [TRANS],1 ; A transfer is taking place +ONSEC: + MOV DL,[SECCLUSPOS] + MOV CX,[SECCNT] + MOV BX,[CLUSNUM] +RDLP: + invoke OPTIMIZE + PUSH DI + PUSH AX + PUSH BX + MOV DS,WORD PTR [DMAADD+2] +ASSUME DS:NOTHING + PUSH DX + PUSH CX + CALL DREAD + POP BX + POP DX + ADD BX,DX ; Upper bound of read + MOV AL,ES:[BP.dpb_drive] + invoke SETVISIT +NXTBUF: ; Must see if one of these sectors is buffered + MOV [DI.VISIT],1 ; Mark as visited + CMP AL,[DI.BUFDRV] + JNZ DONXTBUF ; Not for this drive + CMP [DI.BUFSECNO],DX + JC DONXTBUF ; Below first sector + CMP [DI.BUFSECNO],BX + JNC DONXTBUF ; Above last sector + CMP BYTE PTR [DI.BUFDIRTY],0 + JZ CLBUFF ; Buffer is clean, so OK +; A sector has been read in when a dirty copy of it is in a buffer +; The buffered sector must now be read into the right place + POP AX ; Recall transfer address + PUSH AX + PUSH DI ; Save search environment + PUSH DX + SUB DX,[DI.BUFSECNO] ; How far into transfer? + NEG DX + MOV SI,DI + MOV DI,AX + MOV AX,DX + MOV CX,ES:[BP.dpb_sector_size] + MUL CX + ADD DI,AX ; Put the buffer here + ADD SI,BUFINSIZ + SHR CX,1 + PUSH ES + MOV ES,WORD PTR [DMAADD+2] + REP MOVSW + JNC EVENMOV + MOVSB +EVENMOV: + POP ES + POP DX + POP DI + MOV AL,ES:[BP.dpb_drive] +CLBUFF: + invoke SCANPLACE +DONXTBUF: + invoke SKIPVISIT + JNZ NXTBUF + PUSH SS + POP DS +ASSUME DS:DOSGROUP + POP CX + POP CX + POP BX + JCXZ RDLAST + CMP BX,0FF8H + JAE SETFCB + MOV DL,0 + INC [LASTPOS] ; We'll be using next cluster + JMP RDLP + +RDLAST: + MOV AX,[BYTCNT2] + OR AX,AX + JZ SETFCB + MOV [BYTCNT1],AX + invoke NEXTSEC + JC SETFCB + MOV [BYTSECPOS],0 + invoke BUFRD + + entry SETFCB + LES SI,[THISFCB] + MOV AX,[NEXTADD] + MOV DI,AX + SUB AX,WORD PTR [DMAADD] ; Number of bytes transfered + XOR DX,DX + MOV CX,ES:[SI.fcb_RECSIZ] + DIV CX ; Number of records + CMP AX,[RECCNT] ; Check if all records transferred + JZ FULLREC + MOV BYTE PTR [DSKERR],1 + OR DX,DX + JZ FULLREC ; If remainder 0, then full record transfered + MOV BYTE PTR [DSKERR],3 ; Flag partial last record + SUB CX,DX ; Bytes left in last record + PUSH ES + MOV ES,WORD PTR [DMAADD+2] + XCHG AX,BX ; Save the record count temporarily + XOR AX,AX ; Fill with zeros + SHR CX,1 + JNC EVENFIL + STOSB +EVENFIL: + REP STOSW + XCHG AX,BX ; Restore record count to AX + POP ES + INC AX ; Add last (partial) record to total +FULLREC: + MOV CX,AX + MOV DI,SI ; ES:DI point to FCB +SETCLUS: + TEST ES:[DI].fcb_DEVID,-1 + JS ADDREC ; don't set clisters if device + MOV AX,[CLUSNUM] + AND ES:[DI.fcb_LSTCLUS],0F000h ; fcb_lstclus is packed with dir clus + OR ES:[DI.fcb_LSTCLUS],AX ; drop in the correct part of fcb_lstclus + MOV AX,[LASTPOS] + MOV ES:[DI.fcb_CLUSPOS],AX + entry AddRec + MOV AX,WORD PTR [RECPOS] + MOV DX,WORD PTR [RECPOS+2] + JCXZ RET28 ; If no records read, don't change position + DEC CX + ADD AX,CX ; Update current record position + ADC DX,0 + INC CX +RET28: return +DISKREAD ENDP + +SUBTTL DISKWRITE -- PERFORM USER DISK WRITE +PAGE + procedure DISKWRITE,NEAR +ASSUME DS:DOSGROUP,ES:NOTHING + +; Inputs: +; Outputs of SETUP +; Function: +; Perform disk write +; Outputs: +; DX:AX = Position of last record written +; CX = No. of records written +; ES:DI point to FCB +; fcb_LSTCLUS, fcb_CLUSPOS fields in FCB set + + AND BL,3FH ; Mark file as dirty + MOV ES:[DI.fcb_DEVID],BL + LES BP,[THISDPB] + CALL BREAKDOWN + MOV AX,WORD PTR [BYTPOS] + MOV DX,WORD PTR [BYTPOS+2] + JCXZ WRTEOFJ + ADD AX,CX + ADC DX,0 ; AX:DX=last byte accessed + DIV ES:[BP.dpb_sector_size] ; AX=last sector accessed + MOV BX,AX ; Save last full sector + OR DX,DX + JNZ CALCLUS + DEC AX ; AX must be zero base indexed +CALCLUS: + MOV CL,ES:[BP.dpb_cluster_shift] + SHR AX,CL ; Last cluster to be accessed + PUSH AX + PUSH DX ; Save the size of the "tail" + PUSH ES + LES DI,[THISFCB] + MOV AX,ES:WORD PTR [DI.fcb_FILSIZ] + MOV DX,ES:WORD PTR [DI.fcb_FILSIZ+2] + POP ES + DIV ES:[BP.dpb_sector_size] + MOV CX,AX ; Save last full sector of current file + OR DX,DX + JZ NORNDUP + INC AX ; Round up if any remainder +NORNDUP: + MOV [VALSEC],AX ; Number of sectors that have been written + XOR AX,AX + MOV WORD PTR [GROWCNT],AX + MOV WORD PTR [GROWCNT+2],AX + POP AX + SUB BX,CX ; Number of full sectors + JB NOGROW + JZ TESTTAIL + MOV CX,DX + XCHG AX,BX + MUL ES:[BP.dpb_sector_size] ; Bytes of full sector growth + SUB AX,CX ; Take off current "tail" + SBB DX,0 ; 32-bit extension + ADD AX,BX ; Add on new "tail" + ADC DX,0 ; ripple tim's head off + JMP SHORT SETGRW + +HAVSTART: + MOV CX,AX + invoke SKPCLP + JCXZ DOWRTJ + invoke ALLOCATE + JNC DOWRTJ +WRTERR: + XOR CX,CX + MOV BYTE PTR [DSKERR],1 + MOV AX,WORD PTR [RECPOS] + MOV DX,WORD PTR [RECPOS+2] + LES DI,[THISFCB] + return + +DOWRTJ: JMP DOWRT + +WRTEOFJ: + JMP WRTEOF + +TESTTAIL: + SUB AX,DX + JBE NOGROW + XOR DX,DX +SETGRW: + MOV WORD PTR [GROWCNT],AX + MOV WORD PTR [GROWCNT+2],DX +NOGROW: + POP AX + MOV CX,[CLUSNUM] ; First cluster accessed + invoke FNDCLUS + MOV [CLUSNUM],BX + MOV [LASTPOS],DX + SUB AX,DX ; Last cluster minus current cluster + JZ DOWRT ; If we have last clus, we must have first + JCXZ HAVSTART ; See if no more data + PUSH CX ; No. of clusters short of first + MOV CX,AX + invoke ALLOCATE + POP AX + JC WRTERR + MOV CX,AX + MOV DX,[LASTPOS] + INC DX + DEC CX + JZ NOSKIP + invoke SKPCLP +NOSKIP: + MOV [CLUSNUM],BX + MOV [LASTPOS],DX +DOWRT: + CMP [BYTCNT1],0 + JZ WRTMID + MOV BX,[CLUSNUM] + invoke BUFWRT +WRTMID: + MOV AX,[SECCNT] + OR AX,AX + JZ WRTLAST + ADD [SECPOS],AX + invoke NEXTSEC + MOV BYTE PTR [TRANS],1 ; A transfer is taking place + MOV DL,[SECCLUSPOS] + MOV BX,[CLUSNUM] + MOV CX,[SECCNT] +WRTLP: + invoke OPTIMIZE + PUSH DI + PUSH AX + PUSH DX + PUSH BX + MOV AL,ES:[BP.dpb_drive] + MOV BX,CX + ADD BX,DX ; Upper bound of write + invoke SETVISIT +ASSUME DS:NOTHING +NEXTBUFF: ; Search for buffers + MOV [DI.VISIT],1 ; Mark as visited + CMP AL,[DI.BUFDRV] + JNZ DONEXTBUFF ; Not for this drive + CMP [DI.BUFSECNO],DX + JC DONEXTBUFF ; Buffer is not in range of write + CMP [DI.BUFSECNO],BX + JNC DONEXTBUFF ; Buffer is not in range of write + MOV WORD PTR [DI.BUFDRV],00FFH ; Free the buffer, it is being over written + invoke SCANPLACE +DONEXTBUFF: + invoke SKIPVISIT + JNZ NEXTBUFF + POP BX + POP DX + MOV DS,WORD PTR [DMAADD+2] + CALL DWRITE + POP CX + POP BX + PUSH SS + POP DS +ASSUME DS:DOSGROUP + JCXZ WRTLAST + MOV DL,0 + INC [LASTPOS] ; We'll be using next cluster + JMP SHORT WRTLP + +WRTERRJ: JMP WRTERR + +WRTLAST: + MOV AX,[BYTCNT2] + OR AX,AX + JZ FINWRT + MOV [BYTCNT1],AX + invoke NEXTSEC + MOV [BYTSECPOS],0 + invoke BUFWRT +FINWRT: + LES DI,[THISFCB] + MOV AX,WORD PTR [GROWCNT] + MOV CX,WORD PTR [GROWCNT+2] + OR AX,AX + JNZ UPDATE_size + OR CX,CX + JZ SAMSIZ +Update_size: + ADD WORD PTR ES:[DI.fcb_FILSIZ],AX + ADC WORD PTR ES:[DI.fcb_FILSIZ+2],CX +SAMSIZ: + MOV CX,[RECCNT] + JMP SETCLUS + +WRTEOF: + MOV CX,AX + OR CX,DX + JZ KILLFIL + SUB AX,1 + SBB DX,0 + DIV ES:[BP.dpb_sector_size] + MOV CL,ES:[BP.dpb_cluster_shift] + SHR AX,CL + MOV CX,AX + invoke FNDCLUS + JCXZ RELFILE + invoke ALLOCATE + JC WRTERRJ +UPDATE: + LES DI,[THISFCB] + MOV AX,WORD PTR [BYTPOS] + MOV ES:WORD PTR [DI.fcb_FILSIZ],AX + MOV AX,WORD PTR [BYTPOS+2] + MOV ES:WORD PTR [DI.fcb_FILSIZ+2],AX + XOR CX,CX + JMP ADDREC + +RELFILE: + MOV DX,0FFFH + invoke RELBLKS + JMP SHORT UPDATE + +KILLFIL: + XOR BX,BX + PUSH ES + LES DI,[THISFCB] + MOV ES:[DI.fcb_CLUSPOS],BX + XCHG BX,ES:[DI.fcb_FIRCLUS] + AND ES:[DI.fcb_LSTCLUS],0F000H + POP ES + OR BX,BX + JZ UPDATE + invoke RELEASE + JMP SHORT UPDATE +DISKWRITE ENDP +do_ext + +CODE ENDS + END + \ No newline at end of file -- cgit v1.2.3