;**************************************************************************** ;* * ;* WFDISK.ASM - * ;* * ;* Format and Diskcopy utility routines * ;* * ;**************************************************************************** include winfile.inc externFP GlobalDOSAlloc externFP GlobalDOSFree externFP GetDriveCapacity ;*--------------------------------------------------------------------------* createSeg _%SEGNAME, %SEGNAME, WORD, PUBLIC, CODE sBegin DATA Big32Sector dd ? Big32Count dw ? Big32BufPtr dd ? sEnd sBegin %SEGNAME assumes CS,%SEGNAME assumes DS,DATA ;*--------------------------------------------------------------------------* ;* * ;* LongMult() - * ;* * ;*--------------------------------------------------------------------------* ; Death to the C-Runtimes!!! cProc LongMult, ParmW x ParmW y cBegin mov ax,x mov bx,y mul bx cEnd ;*--------------------------------------------------------------------------* ;* * ;* LongDiv() - * ;* * ;*--------------------------------------------------------------------------* ; Death to the C-Runtimes!!! cProc LongDiv, ParmD dwDivident ParmW wDivisor cBegin mov ax,OFF_dwDivident mov dx,SEG_dwDivident mov bx,wDivisor div bx cEnd cProc LongShift, ParmD dwValue ParmW wCount cBegin mov ax,OFF_dwValue mov dx,SEG_dwValue mov cx,wCount LSLoop: shr dx,1 rcr ax,1 loop LSLoop cEnd ;*--------------------------------------------------------------------------* ;* * ;* SetDASD() - * ;* * ;*--------------------------------------------------------------------------* cProc SetDASD, , parmW drive parmB dasdvalue cBegin mov bx,drive shl bx,1 mov dx,_rgiInt13Drive[bx] mov ah,17h mov al,dasdvalue int 13h cEnd ;*--------------------------------------------------------------------------* ;* * ;* GetDBT() - * ;* * ;*--------------------------------------------------------------------------* cProc GetDBT, cBegin nogen ; Get Interrupt Vector 1E mov ah,35h mov al,1Eh cCall DOS3Call mov dx,es ; ES:BX contains the DISK BASE TABLE mov ax,bx ret cEnd nogen ;*--------------------------------------------------------------------------* ;* * ;* GetDOSVersion() - * ;* * ;*--------------------------------------------------------------------------* cProc GetDOSVersion, cBegin nogen mov ah,30h cCall DOS3Call xchg ah,al ret cEnd nogen ;*--------------------------------------------------------------------------* ;* ;* int FAR PASCAL DeviceParameters(WORD, PDevPB, WORD); ;* ;* drive 0 based drive number ;* pDevPB pointer to device parameter block to set/get ;* wFunction 0x40 to Set, 0x60 to Get ;* ;*--------------------------------------------------------------------------* cProc DeviceParameters, parmW drive parmW pDevPB parmW wFunction cBegin mov dx,pDevPB mov ax,440Dh ; IOCTL: Generic I/O Control for Block Devices mov bx,drive inc bx ; 1-based drive numbers mov ch,08h ; Minor Code mov cl, byte ptr wFunction ; Get/Set Device Parameters cCall DOS3Call jc GDP_Error xor ax, ax ; No error GDP_Error: ;Error code in AX cEnd ;*--------------------------------------------------------------------------* ;* * ;* DiskReset() - * ;* * ;*--------------------------------------------------------------------------* ; Flushes out the disk buffer. cProc DiskReset, cBegin nogen mov ah,0Dh cCall DOS3Call ret cEnd nogen ;*--------------------------------------------------------------------------* ;* * ;* GetDPB() - * ;* * ;*--------------------------------------------------------------------------* ; Returns the DPB for the specified drive. cProc GetDPB, , ParmW drive ParmW pDPB cBegin push ds ; Save DS on stack ; DOS Function 32h is GetDPB() - Get the Drive Parameter Block ; Input : DL = Drive (1 = A, 2 = B, ...) ; Output: AL = 0, if successful and DS:BX points to the DPB. ; AL = -1, if invalid drive. mov ah,32h ; GetDPB system call mov dx,drive inc dx ; 1-based drive numbers int 21h cbw ; Extend error into AX or ax,ax ; Problems? jnz gdpbdone ; Yup, return mov si,bx pop es ; Make ES = DS from stack; mov di,pDPB mov cx,SIZE DPB cld rep movsb ; Intensely stupid DOS 4.0 hack - ; IBM has changed the "FAT_size" field in the DPB structure from a ; byte to a word in DOS 4.0 causing us to misread any variables in ; the structure after this field. This super-sleazy hack rep moves ; the rest of the structure up one byte, effectively converting "FAT_ ; size" back into a byte. ChipA 22-Jun-1988 push ax ; Preserve AX call GetDOSVersion ; DOS 4.0 or greater? cmp ax,0400h jb gdpbdone push es ; DS=ES pop ds mov si,pDPB ; Source at DPB.dpb_dir_sector add si,17 mov di,si ; Destination up one dec di mov cx,16 rep movsb gdpbdone: pop ax cEnd ;*--------------------------------------------------------------------------* ;* * ;* SetDPB() - * ;* * ;*--------------------------------------------------------------------------* ; Fakes up a DPB from the BPB on the disk in the specified drive. cProc SetDPB, , ParmW drive ParmW pBPB ParmW pDPB cBegin ; ; What Follows is DOS function call 53h (SetDPB() - to Build a ; Drive Parameter Block given a Bios Parameter Block. ; Input: ES:BP points to the place where DPB is to be built ; DS:SI points to the given BPB ; Output: All registers except ES:BP and DS are destroyed; ; ES:BP points to the newly built DPB ; Inorder for this function to work correctly in protect mode, ; ES:BP must point to a DOS Addressable memory; To ensure that ; we allocate a GlobalDOSAlloc() and pass the ptr to it xor ax,ax push ax mov ax,SIZE DPB push ax cCall GlobalDOSAlloc ; DX=Seg address; AX=HANDLE/Selector or ax,ax jz SDPB_Err mov es,ax ; Selector address is in ES mov si,pBPB ; DS:SI = BPB mov cx,drive ; CX = drive push bp ; Save BP xor bp,bp ; ES:BP = global DPB mov byte ptr es:[bp],cl ; Set the DPB drive number mov ah,53h ;; win3.1 now has a C prolog on DOS3Call. this causes ;; BP to be trashed. since we won't be doing format on OS/2 ;; just go ahead and ;; cCall DOS3Call int 21h xor si,si ; Save the pointer to DPB pop bp ; Restore bp push ax ; Save the return code ; Make a local copy of DPB from global DPB mov di,pDPB mov ax,es ; move tmp, es push ds ; move es, ds pop es mov ds,ax ; mov ds, tmp mov cx,SIZE DPB rep movsb ; Now release the global memory allocated push ds ; Handle to be freed is passed to GlobalDOSFree ;When GLobalDOSFree() returns, the handle stored in DS is freed and ;hence invalid; So, assign a valid selector to DS before the call. push es pop ds ; DS = ES cCall GlobalDOSFree ; Intensely stupid DOS 4.0 hack - ; IBM has changed the "FAT_size" field in the DPB structure from a ; byte to a word in DOS 4.0 causing us to misread any variables in ; the structure after this field. This super-sleazy hack rep moves ; the rest of the structure up one byte, effectively converting "FAT_ ; size" back into a byte. ChipA 22-Jun-1988 call GetDOSVersion ; DOS 4.0 or greater? cmp ax,0400h jb SDExit push ds ; ES=DS pop es mov si,pDPB ; Source at DPB.dpb_dir_sector add si,17 mov di,si ; Destination up one dec di mov cx,16 rep movsb SDExit: pop ax ; Restore the return code SDPB_Err: cEnd ;*--------------------------------------------------------------------------* ;* * ;* ModifyDPB() - * ;* * ;*--------------------------------------------------------------------------* ; Used for preparing diskettes for receiving the System files. ; ; This obtains the DPB and modifies the DPB_next_free field to contain ; a value of 2, because after deleting the SYS files in the destination ; disk, the newly copied files should occupy starting from Cluster 2. cProc ModifyDPB, , ParmW drive cBegin push ds ; Save DS on stack ; DOS Function 32h is GetDPB() - Get the Drive Parameter Block ; Input : DL = Drive (1 = A, 2 = B, ...) ; Output: AL = 0, if successful and DS:BX points to the DPB. ; AL = -1, if invalid drive. mov ah,32h ; GetDPB system call mov dx,drive inc dx ; 1-based drive number int 21h cbw ; Extend error into AX or ax,ax ; Problems? jnz mdpbDone ; Yup, return push ds ; Save ds:bx (pointer to DPB) push bx ; Get Dos Version cCall GetDOSVersion pop bx ; Restore ds:bx (pointer to DPB) pop ds cmp ah,4 ; Are we dealing with quirky DOS 4? jb mdpb_DOS3 mov ds:[bx].DPB_next_free+1,2 ; Yup, handle messed up structure jmp short mdpb2 mdpb_DOS3: mov ds:[bx].DPB_next_free,2 ; DOS 3.X mdpb2: xor ax,ax ; Success returns 0 mdpbDone: pop ds ; Restore DS cEnd ;*--------------------------------------------------------------------------* ;* * ;* MyInt25() - * ;* * ;*--------------------------------------------------------------------------* ; Performs a direct sector read from the specified drive. ; Returns 0 if successful otherwise it returns the DOS INT 25h error code. ; WARNING: INT 25h does NOT preserve registers. SI & DI must be preserved! ParamBlockStruc struc LO_sector dw ? ; Lo word of starting sector HI_sector dw ? ; Hi word of starting sector SecCount dw ? ; Number of sectors to read BuffOff dw ? ; Offset of Buffer BuffSeg dw ? ; Segment of Buffer ParamBlockStruc ends cProc MyInt25, , ParmW drive ; 0-based drive number ParmD buffer ; LPSTR ParmW count ; # of sectors to read ParmW sector ; Starting sector LocalV ParamBlock, %(size ParamBlockStruc) cBegin mov ax,drive lds bx,buffer mov cx,count mov dx,sector push bp ; Save BP int 25h pop bx ; Remove flags from stack pop bp ; Restore BP jnc MyInt25_end ; If this has failed, it could be a partition > 32 Meg. So, try ; again assuming Partition size is > 32 Meg. If this also fails, ; this is really an error; mov ax,drive ; Fill the parameter block with proper values mov dx,sector mov ParamBlock.LO_sector,dx ; Starting sector ; We get only 16 bit starting sector; So, hi word is made zero mov ParamBlock.HI_sector,0 ; The number of sectors to be read mov dx,count mov ParamBlock.SecCount,dx ; The address of the buffer to read into mov dx,OFF_buffer mov ParamBlock.BuffOff,dx mov dx,SEG_buffer mov ParamBlock.BuffSeg,dx ; Keep the address of ParamBlock is DS:BX lea bx,ParamBlock push ss pop ds mov cx,-1 ; > 32Meg partition push bp ; Save BP int 25h pop bx ; Remove the flags on stack pop bp ; Restore BP MyInt25_end: jc MyInt25_err xor ax,ax ; Return 0 if successful MyInt25_err: cEnd ;*--------------------------------------------------------------------------* ;* * ;* MyInt26() - * ;* * ;*--------------------------------------------------------------------------* ; Performs a direct sector write to the specified drive. ; Returns 0 if successful otherwise it returns the DOS INT 26h error code. cProc MyInt26, , ParmW drive ParmD buffer ParmW count ParmW sector cBegin mov ax,drive lds bx,buffer mov cx,count mov dx,sector xor di, di ;; push bp ; Save BP call DoINT26 ;; int 26h ;; pop bx ; Pop of the flags on stack ;; pop bp ; Restore BP jc MyInt26_err xor ax,ax ; Return 0 if success MyInt26_err: ; Return AX != 0 and Carry set on error cEnd if 1 ;; this stuff stolen from spart ; This is the extension structure used on DOS 4.X INT 25/26 for large ; media. DS:BX -> this structure and CX = -1. ;ABS_32RW struc ; Big32Sector dd ? ; Big32Count dw ? ; Big32BufPtr dd ? ;ABS_32RW ends ; ** ; DoINT26 -- Perform an abs disk write ; ; ENTRY: ; AL = Drive Number (A=0) ; CX is sector count ; DI:DX is start sector # ; DS:BX is transfer address ; SS = DATA ; EXIT: ; Carry Set ; AX = INT 26 Error code ; Carry Clear ; OK ; USES: ; All but DS,ES,BP ; DoINT26 proc near assumes ds,nothing assumes es,nothing assumes ss,data push bp push ds push es push ax ; Save stuff push dx push di push cx push bx int 26h pop dx ; Flags jnc NotRandoBigFoot2 cmp ax,0207h ; Rando MS-DOS BIGFOOT error? jz MSDOSBF2 ; Yes, do like DOS 4.X cmp ax,0408h ; Rando COMPAQ BIGFOOT error? jnz Bad26P ; No ???????? pop bx pop cx pop di pop dx pop ax or al,80h ; Set high bit of drive for randoBigFoot jmp short Do261 Bad26P: add sp,5*2 ; pop ax dx di cx bx stc jmp short Do261OK NotRandoBigFoot2: add sp,5*2 clc jmp short Do261OK MSDOSBF2: pop bx pop cx pop di pop dx pop ax DOS4Write1: push bx mov bx, dataOffset Big32Sector pop word ptr ss:[Big32BufPtr] mov word ptr ss:[Big32BufPtr + 2],ds push ss pop ds mov [Big32Count],cx mov cx,0FFFFh mov word ptr [Big32Sector],dx mov word ptr [Big32Sector + 2],di Do261: int 26h pop dx ; Flags Do261OK: pop es pop ds pop bp ret DoINT26 endp endif ;*--------------------------------------------------------------------------* ;* * ;* IOCTL_Functions() - * ;* * ;*--------------------------------------------------------------------------* ; Uses IOCTL DOS functions to read/write/Format. cProc IOCTL_Functions, , ParmD lpParamBlock ; Parameter block ParmW Function ; 61h for Read, 41h for Write, 42h for format ParmW Drive ; 0 => A, 1 => B, ... cBegin mov ax, 440Dh mov bl, byte ptr Drive inc bl ; Make it 1 relative; mov ch, 08h mov cl, byte ptr Function lds dx, lpParamBlock cCall DOS3Call jc DOS_RWS_Error xor ax, ax ; Returns zero, if success; jmp short DOS_RWS_End DOS_RWS_Error: ; AX contains error code, if failure; mov ah, 59h ; Get the extended error code; xor bx, bx cCall DOS3Call DOS_RWS_End: cEnd ;*--------------------------------------------------------------------------* ;* * ;* MyReadWriteSector() - * ;* * ;*--------------------------------------------------------------------------* ; Uses INT 13h to read/write an absolute sector. cProc MyReadWriteSector, , ParmD lpBuffer ParmW Function ; 02 for Read and 03 for Write ParmW Drive ParmW Cylinder ParmW Head ParmW Count LocalW wRetryCount cBegin ; Retry this operation three times. mov wRetryCount,4 MRWS_TryAgain: mov ax,Count ; AL = Number of sectors mov ah,byte ptr Function ; AH = Function # mov ch,byte ptr Cylinder ; CH = Starting Cylinder mov cl,1 ; CL = Starting Sector mov bx,Drive shl bx,1 mov dx,_rgiInt13Drive[bx] ; DL = INT 13h drive designation mov dh,byte ptr Head ; DH = Head # les bx,lpBuffer ; ES:BX = Buffer int 13h jnc MRWS_End ; Problems? dec wRetryCount ; Yup, retry jz MRWS_End ; Are we out of retries? xor ah,ah ; Nope, reset the disk mov bx,Drive shl bx,1 mov dx,_rgiInt13Drive[bx] int 13h jmp short MRWS_TryAgain MRWS_End: xor al,al ; AH contains the error code, if any. cEnd ;*--------------------------------------------------------------------------* ;* * ;* FormatTrackHead() - * ;* * ;*--------------------------------------------------------------------------* ; Formats and Verifies a diskette track. Stores the track table in the ; specified buffer. cProc FormatTrackHead, , ParmW drive ParmW track ParmW head ParmW cSec ParmD lpTrack LocalD lpTrackTbl LocalW retry cBegin les di,lpTrack ; ES:DI = Sector Buffer cld mov cx,cSec ; CX = Number of Sectors ; Build the Track Address table in the Sector Buffer. mov OFF_lpTrackTbl,di ; lpTrackTbl = &Sector Buffer mov SEG_lpTrackTbl,es mov bx,0200h mov ax,track mov ah,byte ptr head TrackBuildLoop: stosw ; Store Track#, Head# inc bl xchg ax,bx stosw ; Store Sector#, Bytes/Sector code xchg ax,bx loop TrackBuildLoop ; Format the track, retrying 4 times. mov retry,4 FormatTrack: mov ax,cSec mov ah,5 ; Set up the INT 13h format call mov ch,byte ptr track mov cl,1 mov bx,drive shl bx,1 mov dx,_rgiInt13Drive[bx] mov dh,byte ptr head les bx,lpTrackTbl int 13h jc DecRetry ; Retry on error ; Verify the track. mov ax,cSec mov ah,4 ; Set up the INT 13h verify call mov ch,byte ptr track mov cl,1 mov bx,drive shl bx,1 mov dx,_rgiInt13Drive[bx] mov dh,byte ptr head les bx,lpTrackTbl int 13h jnc done ; Return if no errors DecRetry: ; Check if it is the first attempt... If so, reset the disk. cmp retry,4 jb just_retry ; Reset the disk xor ah,ah mov bx,drive shl bx,1 mov dx,_rgiInt13Drive[bx] int 13h just_retry: dec retry jnz FormatTrack ; Error code is in AH Done: xor al,al ; Error code, if any, is in AH cEnd ;*--------------------------------------------------------------------------* ;* * ;* MyGetDriveType() - * ;* * ;* This function was used to be known as GetDriveType(); But now there * ;* is an exported function in Kernel with the same name; So, we have to * ;* chang the name to its present name. * ;* --SANKAR-- 10-17-89 * ;* * ;*--------------------------------------------------------------------------* ; Returns the type of drive supported by the ROM. ; Inputs: drive 0-based drive number for int 13 ; Outputs: -1 if INT 13 returns carry ; 0 if changeline not supported ; 1 if changeline supported ; 2 if wacko returns from int 13 cProc MyGetDriveType, ParmW drive cBegin mov bx,drive shl bx,1 mov dx,_rgiInt13Drive[bx] mov ax,(15h shl 8) + 0FFh int 13h ; Stupid IBM has documented INCORRECTLY the readdasdtype call to INT 13. The ; conditions at this point are: ; ; Carry flag unknown ; ah = 00 iff no diskette present => 2 (wacko) ; ah = 01 iff no changeline available => 0 ; ah = 02 iff changeline available => 1 ; ah = 03 iff hard disk => 2 (wacko) ; ah = 15 iff not on AT => 0 cmp ah,1 jb wacko jz zero cmp ah,3 jae wacko ; Changeline present. Put drive into high density mode. GetDriveCall: mov ah,17h mov bx,drive shl bx,1 mov dx,_rgiInt13Drive[bx] mov al,3 int 13h ; Doubly stupid IBM spins the drive for this call and potentially returns the ; disk change error (mumble). If we get carry set AND ah == 6, we retry the ; operation jnc NoCarry cmp ah,06h jnz wacko jmp GetDriveCall NoCarry: mov ax,1 jmp short doneDrive wacko: mov ax,2 jmp short doneDrive zero: mov ax,0 jmp short doneDrive carry: mov ax,-1 doneDrive: cEnd ;*--------------------------------------------------------------------------* ;* * ;* ReadSerialNumber() - * ;* * ;*--------------------------------------------------------------------------* ; This reads and returns the serial number from the boot sector of the ; Diskette in the given drive. ; ; Returns: ; The serial number if the boot sector is that of DOS4.0 or above ; else returns 0L cProc ReadSerialNumber, , ParmW iDrive ParmD lpBuff cBegin ; Read the boot sector into the given drive xor bx,bx mov ax,1 cCall MyInt25, or ax,ax jnz RSN_RetZero ; Examine if it the version of boot sector is >= DOS 4.00 les di,lpBuff mov al,byte ptr es:[di].BOOT_ExSignature_DOS4 cmp al,29h ; Signature for new BOOT record je RSN_ReadIt cmp al,28h ; Signature for new BOOT record je RSN_ReadIt RSN_RetZero: xor ax,ax ; Return 0 if no serial no xor dx,dx jmp short RSN_End RSN_ReadIt: mov ax,word ptr es:[di].BOOT_SerialNo_DOS4 mov dx,word ptr es:[di].BOOT_SerialNo_DOS4+2 RSN_End: cEnd ;*--------------------------------------------------------------------------* ;* * ;* ModifyVolLabelInBootSec() - * ;* * ;*--------------------------------------------------------------------------* ; This checks whether the given floppy contains a boot record of 4.00 ; and if so, it overwrites the existing vol label with the given vol ; label and overwrites the existing serial # with the given serial # ; ; Returns: 0 if successful; ; -1 if error; cProc ModifyVolLabelInBootSec, , ParmW iDrive ParmD lpszVolLabel ParmD lSerialNo ParmD lpBuff cBegin ; Read the boot sector into the given drive xor bx,bx mov ax,1 cCall MyInt25, or ax,ax jnz MVLIBS_End ; Examine if it the version of boot sector is >= DOS 4.00 les di,lpBuff mov al,byte ptr es:[di].BOOT_ExSignature_DOS4 cmp al,29h ; Signature for new BOOT record je MVLIBS_Modify cmp al,28h ; Signature for new BOOT record je MVLIBS_Modify xor ax,ax ; Return 0 if no error jmp short MVLIBS_End MVLIBS_Modify: ; Yup! Replace the existing vol label by the given one. lea di,es:[di].BOOT_VolLabel_DOS4 lds si,lpszVolLabel mov cx,11 mov ax,ds or ax,si ; Check if the Vol Label is being removed jz MVLIBS_PadBlanks ; Yup! Remove the label. MVLIBS_Loop: lodsb or al,al jz MVLIBS_PadBlanks stosb loop MVLIBS_Loop MVLIBS_PadBlanks: ; Pad the Vol label with blanks mov al,' ' rep stosb ; Modify the serial number mov ax,OFF_lSerialNo mov dx,SEG_lSerialNo or ax,dx jz MVLIBS_Write les di,lpBuff mov word ptr es:[di].BOOT_SerialNo_DOS4,ax mov word ptr es:[di].BOOT_SerialNo_DOS4+2,dx MVLIBS_Write: ; Go ahead and write the modified boot sector xor ax,ax mov bx,1 cCall MyInt26, ; Output correct boot sector MVLIBS_End: ; Returns 0 if successful cEnd ;*--------------------------------------------------------------------------* ;* * ;* WriteBootSector() - * ;* * ;*--------------------------------------------------------------------------* ; Copies the boot sector from one drive to another. ; Inputs: SrcDrive 0-based drive of source boot sector ; DstDrive 0-based drive of destination ; pBPB pointer to BPB for destination drive ; lpBuf long pointer to buffer large enough to ; contain boot sector. ; Returns: 0 if successfull cProc WriteBootSector, , parmW SrcDrive parmW DstDrive parmW pBPB parmD lpBuf cBegin ; Read boot sector from source drive xor bx,bx mov ax,1 cCall MyInt25, or ax,ax jz bsContinue jmp bsDone bsContinue: mov si,pBPB ; if no BPB is passed, then pickup the correct one from bpbList or si,si jnz havebpb mov ah,36h mov dx,DstDrive inc dl cCall DOS3Call inc ax jz bsfail mov si,dataOffset _bpbList ; Scan BPB list for match mov bx,dataOffset _cCluster ; with associated cluster size bsloop: mov cx,word ptr [bx] jcxz bsfail cmp cx,dx je havebpb add si,SIZE BPB inc bx inc bx jmp bsloop bsfail: mov ax,-1 jmp short bsdone havebpb: ; Copy BPB appropriate for dest. drive into boot sector les di,lpBuf lea di,[di].BOOT_BPB mov cx,SIZE BPB cld rep movsb ; Check if the Boot sector read belongs to DOS 4.0 mov di,OFF_lpBuf cmp es:[di].BOOT_ExSignature_DOS4,29h je WBS_Dos4 cmp es:[di].BOOT_ExSignature_DOS4,28h je WBS_Dos4 ; No, the Boot sector version is < 4.00 ; Store a zero in BOOT_phydrv field ; (i.e. always assume A: is the boot drive ; so IBMBIO.COM will be happy) xor ax,ax mov es:[di].BOOT_phydrv,al ; 3.2 expects it here mov es:[di].BOOT_bootdrive,al ; < 3.2 expects it here jmp short WBS_Write WBS_Dos4: ; It is DOS 4.0 or above xor ax,ax lea si,es:[di].BOOT_BPB_extension ; zero the high word of number of hidden sectors mov es:[si].BPB_EX_cSecHidden_HiWord,ax ; Zero the total number of sectors, in the extended field mov word ptr es:[si].BPB_EX_cTotalSectors,ax mov word ptr es:[si].BPB_Ex_cTotalSectors+2,ax ; Make 'A' as the BOOT drive mov es:[di].BOOT_phydrv_DOS4,al ; Get a serial number for this disk push es cCall pop es mov word ptr es:[di].BOOT_SerialNo_DOS4,ax mov word ptr es:[di].BOOT_SerialNo_DOS4+2,dx ;Overwrite "FAT16" with "FAT12" in the reserved area; lea di,es:[di].BOOT_FATmarker_DOS4 lea si,_szReservedMarker mov cx,8 rep movsb WBS_Write: ; Go ahead and write the modified boot sector xor ax,ax mov bx,1 cCall MyInt26, ; Output correct boot sector bsdone: ; Returns 0 if successful cEnd ;*--------------------------------------------------------------------------* ;* * ;* OpenFAT() - * ;* * ;*--------------------------------------------------------------------------* cProc OpenFAT, parmW mode cBegin mov [_wFATSector],-1 mov ax,mode mov [_wFATMode],ax cEnd ;*--------------------------------------------------------------------------* ;* * ;* FlushFAT() - * ;* * ;*--------------------------------------------------------------------------* ; Returns 0 if successful. cProc FlushFAT, , parmW pDPB parmD lpBuf cBegin ; Make sure that OpenFAT() has been called... mov ax,[_wFATSector] inc ax jz FFDone ; ...and we are in WRITE mode. test [_wFATMode],FAT_WRITE jz FFDone mov si,[_wFATSector] ; SI = Current FAT sector mov bx,pDPB ; BX = pDPB xor dx,dx mov dl,[bx].DPB_drive mov di,dx ; DI = Drive Number ; Write out the first copy of these two sectors. mov dx,2 push bx ; Preserve BX cCall MyInt26, pop bx ; Restore BX or ax,ax ; Problems? jnz FFDone ; Yup, exit push bx ; Preserve BX ; Did we just write out the first sector? cmp si,1 jne FF2nd ; Nope, skip ; Yes, mark the media as invalid. push ds ; Save DS on Stack ; DOS function 32h is Get_DPB() - to get the Drive Parameter Block ; Input : DL = Drive (1 = A, 2 = B, ...) ; Output: AL = 0, if successful and DS:BX points to the DPB. ; AL = -1, if invalid drive. ; mov ah,32h ; Get DPB mov dx,di inc dx ; DX = 1-based drive number int 21h push ds ; ES = DS pop es pop ds ; Restore DS from Stack cbw ; Extend error into AX or ax,ax ; Problems? jnz ff2nd ; Yup, return immediately ; ***** WARNING: 4.00 HACK ***** ; es:bx now point to the DPB returned by DOS Function 32h. So, if ; it is DOS 4.X, then DPB_first_access is at one byte higher location. ; (Because, DPB_FAT_size field is one byte longer). ; Take care before assigning this field. push es ; Save es:bx on stack -GetDosVersion spoils them push bx cCall GetDOSVersion pop bx ; Restore es:bx from stack pop es cmp ah,4 jb ff_DOS3 mov es:[bx].DPB_first_access+1,-1 ; DOS 4.X jmp short ff2nd ff_DOS3: mov es:[bx].DPB_first_access,-1 ; DOS 3.X ff2nd: ; Write out the Second copy of two FAT sectors. pop bx ; Restore BX (pDPB) xor dx,dx mov dl,[bx].DPB_FAT_size add si,dx mov dl,2 cCall MyInt26,; Returns 0 if successful ffdone: cEnd ;*--------------------------------------------------------------------------* ;* * ;* SetIndexSector() - * ;* * ;*--------------------------------------------------------------------------* ; Determines the sector and offset-within-sector for a particular cluster entry. ; Inputs: DI = -> DPB block ; CX = clustor number ; ; Outputs: AX = sector number of fat sector containing fat entry ; DX = offset into fat sector of 1st bytes of fat entry for passed ; cluster number. cProc SetIndexSector, cBegin nogen xor dx,dx mov ax,cx ; Are we using 12-bit fat entries? cmp [di].DPB_max_cluster,4086 jb sis12bit ; Yes, go calculate sector/offset ; offset = (2*cluster) % pDPB->sector_size ; sector = pDPB->first_FAT + (2*cluster) / pDPB->sector_size shl ax,1 div [di].DPB_sector_size ; No, 16 bit fat entries jmp short sisdone sis12bit: ; offset = (cluster + (cluster >> 1)) % pDPB->sector_size ; sector = pDPB->first_FAT + (cluster + (cluster >> 1)) / pDPB->sector_size shr ax,1 add ax,cx div [di].DPB_sector_size sisdone: add ax,[di].DPB_first_FAT ret cEnd nogen ;*--------------------------------------------------------------------------* ;* * ;* PackFAT() - * ;* * ;*--------------------------------------------------------------------------* ; Adds a specified value into the FAT entry which corresponds to the specified ; cluster. ; Inputs: pDPB pointer to DPB ; lpBuf pointer to a 2 sector buffer ; cluster cluster which needs the entry ; value value to be stuffed into cluster entry ; ; Returns 0 if successful. cProc PackFAT, , parmW pDPB parmD lpBuf parmW cluster parmW value cBegin mov di,pDPB ; DI = pDPB mov cx,cluster ; CX = Cluster # cCall SetIndexSector ; AX = FAT Sector which contains the cluster entry ; DX = Offset within that sector for the cluster entry mov si,dx ; SI = Entry Offset ; Are we currently modifying the proper FAT Sector? cmp [_wFATSector],ax je PFNoRead ; Yup, skip ; Nope, Flush this sector and read in the right one... mov cx,ax ; CX = Desired sector push cx ; Preserve CX cCall FlushFAT, pop cx ; Restore CX or ax,ax ; Problems? jnz PFDone ; Yup, give up mov al,[di].DPB_drive ; AL = Drive# mov dx,2 ; DX = push cx ; Preserve CX cCall MyInt25, pop cx ; Restore CX or ax,ax ; Problems? jnz PFDone ; Yup, give up ; Update the Current Sector variable. mov [_wFATSector],cx PFNoRead: mov ax,value ; AX = FAT Entry Value xor dx,dx ; DX = 0 ; Does the DPB indicate more than 4086 clusters? ; i.e. Do we use 12-bit or 16-bit FAT entries? cmp [di].DPB_max_cluster,4086 jae PF2 ; Use 16-bit entries ; Use 12-bit entries. mov cl,4 mov dh,0F0h test byte ptr cluster,1 jz PF1 rol dx,cl shl ax,cl jmp short PF2 PF1: not dx and ax,dx not dx PF2: ; Store the value at the proper offset. les bx,lpBuf and es:[bx+si],dx or es:[bx+si],ax xor ax,ax ; Return success PFDone: cEnd ;*--------------------------------------------------------------------------* ;* * ;* UnpackFAT() - * ;* * ;*--------------------------------------------------------------------------* ; Inputs: pDPB drive parameter block for drive ; lpBuf pointer to a sector buffer ; cluster cluster whose FAT contents are to be returned ; ; this converts 12 bit FAT values to 16 bits values ; ; Returns: ; 0000 cluster available ; FFF0-FFF6 reserved ; FFF7 bad cluster ; FFFF-FFFF last cluster ; else next cluster in the chain cProc UnpackFAT, , parmW pDPB parmD lpBuf parmW cluster cBegin mov di,pDPB mov cx,cluster cCall SetIndexSector mov si,dx cmp [_wFATSector],ax je upfnoread push ax cCall FlushFAT, pop cx or ax,ax ;Did FlushFAT return error? jnz upfError mov al,[di].DPB_drive mov dx,2 push cx cCall MyInt25, pop cx or ax,ax ;Did MyInt25 return error? jnz upfError mov [_wFATSector],cx upfnoread: les bx,lpBuf mov ax,es:[bx+si] cmp [di].DPB_max_cluster,4096-10 ; 12 bit fat entries? ;; jae upfdone jae upfexit test byte ptr cluster,1 ;Is it an Odd or Even cluster jz upf1 mov cl,4 shr ax,cl upf1: and ax,0FFFh ; keep only 12 bits cmp ax,0FF0h ; is this a special cluster jb upfexit ; no or ax,0F000h ; extend the special clusters to 16 bits jmp short upfexit ; done, get out upfdone: ;; don't convert special end of chain and bad sectors ;; mov dx,ax ;; cmp [di].DPB_max_cluster,ax ;; jae upfexit upfError: mov ax,-1 upfexit: cEnd ;*--------------------------------------------------------------------------* ;* * ;* IsHPMachine() - * ;* * ;*--------------------------------------------------------------------------* ; Attempts to detect HP Vectra machines. cProc IsHPMachine, cBegin nogen push es mov ax,__ROMBIOS ; To work in Protect mode mov es,ax mov ax,word ptr es:[00F8h] pop es cmp ax,'PH' je IHMFoundIt xor ax,ax jmp short IHMDone IHMFoundIt: mov ax,1 IHMDone: ret cEnd nogen ifdef 0 ******************* COMMENTED OUT ***************************************** *** Look! Int13h Function 8 DOES NOT work in COMPAQ 386/16 machines ****** *** So, the following function is replaced by a GetDriveCapacity() ****** *** in WFFormat.c; Go and look at it. ****** *** This is a part of the Fix for Bug #5292 --SANKAR-- 10-17-89 ****** ;*--------------------------------------------------------------------------* ;* * ;* GetDriveCapacity() - * ;* * ;*--------------------------------------------------------------------------* ; Returns ; 0 if error ; 1 if 360KB floppy drive ; 2 if 1.2MB ; 3 if 720KB ; 4 if 1.44KB cProc GetDriveCapacity, ParmW nDriveId cBegin mov ah,08h ; Get drive parameters mov bx,nDriveId shl bx,1 mov dx,_rgiInt13Drive[bx] int 13h jc GDT_Error mov al,bl ; Drive type xor ah,ah jmp short GDT_End GDT_Error: xor ax,ax ; returns 0 if error GDT_End: cEnd ************** COMMENTED OUT **************************************** endif ;*--------------------------------------------------------------------------* ;* * ;* DreamUpSerialNumber() - * ;* * ;*--------------------------------------------------------------------------* ; Returns a unique serial number for writing into the BOOT sector of DOS 4.0 ; and above diskettes. The unique function is generated by hashing the ; system date and time. cProc DreamUpSerialNumber, , cBegin ; Get the System Date mov ah,2Ah cCall DOS3Call; cx = Year, dh=month, dl=day push cx push dx ; Save them on the stack ; Get the System Time mov ah,2Ch cCall DOS3Call; ch=hours, cl=minutes, dh=seconds, dl=1/100th secs ; Low word of serial number = dx of time + dx of date ; High word of Serial number = cx of time + cx of date pop ax add ax,dx pop dx add dx,cx cEnd ;*--------------------------------------------------------------------------* ;* * ;* GetClusterInfo() - * ;* * ;*--------------------------------------------------------------------------* ; Returns the size of a sector in dx and sectors/cluster in ax for ; the specified drive ; Inputs: drive 0=>A, 1=>B ; Returns: 0 if unsuccessful, or AX= sectors/cluster and DX = size of sector in bytes; cProc GetClusterInfo, , parmW drive cBegin mov ah,36h mov dx,drive inc dx ; make it 1 based. cCall DOS3Call inc ax ; if Error, ax = -1, else, ax = sectors/cluster jz GCSdone ; Yup, Error. Return zero. dec ax ; Get back sectors/cluster. mov dx, cx ; cx = bytes/sector GCSdone: cEnd if 0 ;*--------------------------------------------------------------------------* ;* * ;* IsHighCapacityDrive() - * ;* This returns 0 if it is a low capacity drive (360KB or 720KB) * ;* returns >0 if it is a high capacity drive(1.2MB or 1.44MB) * ;* returns -1 if error occurred in reading the capacity * ;* * ;* This function is added as a Fix for Bug #4866 --SANKAR--09-28-89-- * ;*--------------------------------------------------------------------------* ; Flushes out the disk buffer. cProc IsHighCapacityDrive, ParmW iDrive cBegin cCall GetDriveCapacity, cmp ax, 2 je IHCD_End ; Yup! It is a 1.2MB drive cmp ax, 4 je IHCD_End ; Yup! It is a 1.44MB drive or ax, ax jnz IHCD_LowCap ; AX is 1 or 3 => Low capacity drive dec ax ; Error in reading the capacity of drive; js IHCD_End IHCD_LowCap: xor ax, ax IHCD_End: cEnd endif sEnd %SEGNAME end