Category : Files from Magazines
Archive   : WDOCT92.ZIP
Filename : 3N10052A

 
Output of file : 3N10052A contained in archive : WDOCT92.ZIP
;======================================================================
; FDFORMAT.ASM
; Copyright (c) 1992 Schaefer Software, Robert L. Hummel
;----------------------------------------------------------------------
; FormatDiskette() is a function that attempts to format a floppy disk
; drive to the requested (capacity) using BIOS calls. It returns an
; integer value that indicates whether the format was successful. If
; not, the return value identifies the type of error as defined in the
; equate section below.
;
; Notes:
; 1. This routine operates on PHYSICAL diskette drives, not logical
; drives.
; 2. This routine makes no attempt to identify or check the drive,
; drive type, or media. You must call it with the correct drive
; number, type, and ensure the correct media is in use to ensure a
; successful format.
; 3. Only the standard DOS capacities are supported. Altering these to
; produce custom formats, however, is quite simple.
; 4. Bad sectors are detected and marked as such in the FAT using the
; sector bad = track bad DOS convention.
; 5. Compatible with Microsoft medium model.
;----------------------------------------------------------------------
; Usage:
; Result=FormatDiskette(DrvNum,DrvType,Media,SEG Buf)
; where
; DrvNum = (16-bit integer) physical drive number
; 0 = 1st physical diskette
; 1 = 2nd physical diskette
; 2 = 3rd physical diskette
; etc.
;
; DrvType = (16-bit integer) type of drive (maximum capacity)
; 1 = 360k 5.25"
; 2 = 1.2M 5.25"
; 3 = 720k 3.5"
; 4 = 1.4M 3.5"
;
; Media = (16-bit integer) type of media being formatted
; 360, for 360K 5.25"
; 1200, for 1.2M 5.25"
; 720, for 720K 3.5"
; 1440, for 1.44M 3.5"
;
; SEG Buf = Far pointer to scratch buffer
; (minimum size in bytes shown for each format)
; ( 9*4)+(2*512)=1060, for 360K 5.25"
; (15*4)+(7*512)=3644, for 1.2M 5.25"
; ( 9*4)+(3*512)=1572, for 720K 3.5"
; (18*4)+(9*512)=4680, for 1.44M 3.5"
;
; Result = (16-bit integer)
; 0, diskette formatted successfully
; > 0, see error table
;----------------------------------------------------------------------
PUBLIC FormatDiskette ;BASIC, PASCAL (FAR)
PUBLIC _FormatDiskette ;C (FAR)
PUBLIC FormatDiskette$FAR ;ASM (FAR)

;======================================================================
; Equates
;----------------------------------------------------------------------
; These error returns are defined by the BIOS.
;----------------------------------------------------------------------
ERR$INV_DISK_PARM EQU 1 ;Invalid disk parameter
ERR$ADR_MARK_NOT_FND EQU 2 ;Address mark not found
ERR$WR_PROT_ERR EQU 3 ;Write protect error
ERR$REQ_SEC_NOT_FND EQU 4 ;Requested sector not found
ERR$DISK_CHG_LN_ACTV EQU 6 ;Disk change line active
ERR$DMA_OVRRUN EQU 8 ;DMA overrun
ERR$DMA_BNDRY EQU 9 ;DMA boundary error
ERR$MED_TYP_NOT_FND EQU 0CH ;Media type not found
ERR$CRC_RD_ERR EQU 10H ;CRC read error
ERR$CTRLR_FAIL EQU 20H ;Controller failure
ERR$SEEK_FAIL EQU 40H ;Seek failure
ERR$DRV_NOT_RDY EQU 80H ;You'll get this if door open

;----------------------------------------------------------------------
; I define these additional errors.
;----------------------------------------------------------------------
ERR$INV_CAP EQU 7 ;Wrong capacity for drive
ERR$TRK_0_BAD EQU 0AH ;Bad disk/cap=1.4 w/720k disk
; or write protected disk
ERR$BAD_SECT EQU 0BH ;Bad sectors found and marked

;----------------------------------------------------------------------
; Drive types.
;----------------------------------------------------------------------
DRIVE_360 EQU 1
DRIVE_1200 EQU 2
DRIVE_720 EQU 3
DRIVE_1440 EQU 4

;----------------------------------------------------------------------
; Program equates. Change if required.
;----------------------------------------------------------------------
RETRY0 EQU 5 ;Retries for track 0
RETRY EQU 3 ;Retries for other tracks

;======================================================================
; A convenient alias for low memory.
;----------------------------------------------------------------------
LOMEM SEGMENT AT 0000H

ORG (1EH * 4H) ;Int 1Eh points to disk base
DISK_BASE DD ?

LOMEM ENDS

;======================================================================
; DGROUP addressing compatible with medium memory model. DS=SS=DGROUP
;----------------------------------------------------------------------
DGROUP GROUP DSEG,USEG
DSEG SEGMENT WORD PUBLIC 'DATA'

;----------------------------------------------------------------------
; Each entry defines all the information for a particular disk format.
; Feel free to insert your own company name as the OEM System ID.
;----------------------------------------------------------------------
; Media info/boot record for 360K 5.25" floppy.
;----------------------------------------------------------------------
MEDIA_360 DB 50H ; 0, Format gap length
DB 40 ; 1, Number of tracks
DB 7 ; 2, Root dir sectors

DB 0EBH,2EH,90H ; 3, JMP 30H, NOP
DB "SCHAEFER" ; 6, System ID
DW 512 ;200H ;14, Bytes per sector
DB 2 ;16, Sectors per cluster
DW 1 ;17, # reserved sectors
DB 2 ;19, # copies of FAT
DW 112 ;70H ;20, # root directory entries
DW 2*9*40 ;2D0H ;22, Total # of sectors
DB 0FDH ;24, Format ID
DW 2 ;25, Sectors per FAT
DW 9 ;27, Sectors per track
DW 2 ;29, Number of heads
DD 0 ;31, Special reserved sectors
;----------------------------------------------------------------------
; Media info/Boot record for 1.2M 5.25" floppy.
;----------------------------------------------------------------------
MEDIA_1200 DB 54H ;Format gap length
DB 80 ;Number of tracks
DB 14 ;Root dir sectors

DB 0EBH,2EH,90H ;JMP 30H, NOP
DB "SCHAEFER" ;System ID
DW 512 ;200H ;Bytes per sector
DB 1 ;Sectors per cluster
DW 1 ;# reserved sectors
DB 2 ;# copies of FAT
DW 224 ;E0H ;# root directory entries
DW 2*15*80 ;960H ;Total # of sectors
DB 0F9H ;Format ID
DW 7 ;Sectors per FAT
DW 15 ;Sectors per track
DW 2 ;Number of heads
DD 0 ;Special reserved sectors
;----------------------------------------------------------------------
; Media info/Boot record for 720K 3.5" floppy.
;----------------------------------------------------------------------
MEDIA_720 DB 50H ;Format gap length
DB 80 ;Number of tracks
DB 7 ;Root dir sectors

DB 0EBH,2EH,90H ;JMP 30H, NOP
DB "SCHAEFER" ;System ID
DW 512 ;200H ;Bytes per sector
DB 2 ;Sectors per cluster
DW 1 ;# reserved sectors
DB 2 ;# copies of FAT
DW 112 ;E0H ;# root directory entries
DW 2*9*80 ;5A0H ;Total # of sectors
DB 0F9H ;Format ID
DW 3 ;Sectors per FAT
DW 9 ;Sectors per track
DW 2 ;Number of heads
DD 0 ;Special reserved sectors
;----------------------------------------------------------------------
; Media info/Boot record for 1.44M 3.5" floppy.
;----------------------------------------------------------------------
MEDIA_1440 DB 6CH ;Format gap length
DB 80 ;Number of tracks
DB 14 ;Root dir sectors

DB 0EBH,2EH,90H ;JMP 30H, NOP
DB "SCHAEFER" ;System ID
DW 512 ;200H ;Bytes per sector
DB 1 ;Sectors per cluster
DW 1 ;# reserved sectors
DB 2 ;# copies of FAT
DW 224 ;E0H ;# root directory entries
DW 2*18*80 ;640H ;Total # of sectors
DB 0F0H ;Format ID
DW 9 ;Sectors per FAT
DW 18 ;Sectors per track
DW 2 ;Number of heads
DD 0 ;Special reserved sectors
;----------------------------------------------------------------------
; This bootstrap routine is the common suffix for each boot record.
; It is loaded beginning at offset 30h in the boot record. It displays
; a message saying that this is not a bootable disk.
;----------------------------------------------------------------------
BOOTCODE LABEL BYTE ;offset 30h

CLI ;No interrupts

SUB AX,AX ;AX = 0
MOV SS,AX ;Create stack
MOV SP,7C00H

MOV DS,AX ;DS=0000
MOV SI,OFFSET BOOTMSG - OFFSET BOOTCODE + 7C30h
MOV CX,OFFSET BOOTMSGEND - OFFSET BOOTMSG
CLD ;String moves forward

LODSB ;AL=DS:[SI++]
MOV AH,0EH ;Write TTY
MOV BX,7
INT 10H ; thru BIOS

LOOP $-8 ;Create relative label

SUB AX,AX ;Wait for key
INT 16H ; thru BIOS

MOV WORD PTR DS:[472H],1234H ;Warm boot
DB 0EAH ;Far jump
DW 0,0FFFFH ; to RESET routine

BOOTMSG DB 13,10,"You cannot boot from this disk; it does"
DB 13,10,"not contain the DOS system files."
DB 13,10,"Replace or remove the diskette and "
DB 13,10,"press Enter ",17,217," to reboot.",13,10
BOOTMSGEND EQU $

DB "Copyright (c) 1992, Robert L. Hummel"

BOOTCODELEN EQU $-OFFSET BOOTCODE

DSEG ENDS

;----------------------------------------------------------------------
; Unitialized data.
;----------------------------------------------------------------------
USEG SEGMENT WORD PUBLIC 'BSS'

SAVE_BASE DW 1 DUP (?)
SBUFPTR DW 1 DUP (?) ;ES:offset of sector buffer

DRIVENUM DB 1 DUP (?) ;Physical drive number
DRIVETYPE DB 1 DUP (?) ;Type of drive
FUNCTION DB 1 DUP (?) ;Used by format/verify proc
ERROR DB 1 DUP (?) ;Set if bad tracks detected

HEAD DB 1 DUP (?) ;Used by BIOS_WRITE
TRACK DB 1 DUP (?) ;Used by BIOS_WRITE
SECT DB 1 DUP (?) ;Used by BIOS_WRITE
NSECT DB 1 DUP (?) ;Used by BIOS_WRITE

USEG ENDS

;======================================================================
; Code segment.
;----------------------------------------------------------------------
CSEG SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

;======================================================================
; FormatDiskette$FAR
; Copyright (c) 1992 Schaefer Software, Robert L. Hummel
;----------------------------------------------------------------------
; The common assembly routine called by the HLL interface routines.
; May also be called directly from assembly language.
; All arguments are passed via register.
;----------------------------------------------------------------------
; Entry:
; CX = Valid capacity code as defined in header
; DH = Valid drive type as defined in header
; DL = Physical drive number (not checked)
; ES:DI = Far pointer to scratch buffer; size defined in header
; Exit:
; AX = Result as defined in header
;----------------------------------------------------------------------
; Changes: AX BX CX DX SI DI
;----------------------------------------------------------------------
FormatDiskette$FAR PROC FAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP
;----------------------------------------------------------------------
; Initialization.
;----------------------------------------------------------------------
CLD ;String moves forward
SUB AX,AX ;Create a zero
MOV [ERROR],AL ;Initialize error code

MOV [DRIVENUM],DL ;Save drive number
MOV [DRIVETYPE],DH ; and type
MOV [SBUFPTR],DI ;Save buffer offset
;----------------------------------------------------------------------
; The requested capacity (CX) must be supported by the drive type (DH).
;----------------------------------------------------------------------
CMP DH,DRIVE_1200 ;Check drive type
JA FD_1C ;type >2 if 3.5" drive
JB FD_1A ;type <2 if 360K

MOV SI,OFFSET DGROUP:MEDIA_1200 ;Media = 1.2M
CMP CX,1200 ;1.2M in 1.2M?
JE FD_1E
FD_1A:
MOV SI,OFFSET DGROUP:MEDIA_360 ;Media = 360K
CMP CX,360 ;360K in either
JE FD_1E
;----------------------------------------------------------------------
; Error: Drive and capacity do not match.
;----------------------------------------------------------------------
FD_1B:
MOV AL,ERR$INV_CAP ;Put error code in AL
JMP FD_EXIT
;----------------------------------------------------------------------
; Test for 3.5" drives.
;----------------------------------------------------------------------
FD_1C:
CMP DH,DRIVE_720 ;Is it 720k drive?
JE FD_1D

MOV SI,OFFSET DGROUP:MEDIA_1440 ;Assume 1.4M
CMP CX,1440 ;1.4M in 1.4M?
JE FD_1E
FD_1D:
MOV SI,OFFSET DGROUP:MEDIA_720 ;Media = 720K
CMP CX,720 ;720k in either
JNE FD_1B
FD_1E:
;----------------------------------------------------------------------
; Before altering the disk base parameters as required for this format,
; save the current values for later restoration.
;----------------------------------------------------------------------
PUSH ES ;Save register

MOV ES,AX ;Point ES to low memory
ASSUME ES:LOMEM

LES BX,ES:[DISK_BASE] ;ES:BX -> disk base
ASSUME ES:NOTHING

MOV CH,[SI] ;Format gap length
MOV CL,[SI+27] ;Sectors per track

XCHG CH,ES:[BX+7] ;Change values
XCHG CL,ES:[BX+4] ; as required

MOV [SAVE_BASE],CX ;Save old values

POP ES ;Restore register
ASSUME ES:NOTHING
;----------------------------------------------------------------------
; Reset the diskette system. (At the moment, AH=0 and DL=DRIVENUM.)
;----------------------------------------------------------------------
INT 13H ;Reset thru BIOS
;----------------------------------------------------------------------
; Attempt to set the correct media/drive combination. A failure here
; aborts the entire format. Returns its own error code in AL if failed.
;----------------------------------------------------------------------
CALL SET_MEDIA ;Return in AL if CY
JC FD_2B
;----------------------------------------------------------------------
; Initialize the work buffer. All zeros are written to intialize the
; FAT buffer. The track buffer starts right after the FAT buffer.
;----------------------------------------------------------------------
MOV AX,[SI+14] ;Bytes/sector
MUL WORD PTR [SI+25] ;* Sectors/FAT
MOV CX,AX ;= Bytes to init
SUB AL,AL ;Store zeros
REP STOSB ; to ES:DI (buffer)
;----------------------------------------------------------------------
; On all current floppy formats, track 0 contains all the critical
; structures for the diskette. If track 0 cannot be formatted
; successfully, the entire format operation is aborted.
;----------------------------------------------------------------------
MOV BX,DI ;Point ES:BX to buffer
MOV DL,[DRIVENUM] ;Drive
SUB CH,CH ;Track 0
SUB DH,DH ;Head 0
MOV AL,[SI+27] ;Sec/track
MOV AH,RETRY0 ;Retries

CALL FORMAT_TRACK ;Format track 0, Head 0
JC FD_2A

CALL VERIFY_TRACK ; and verify it
JC FD_2A

INC DH ;Next head

CALL FORMAT_TRACK ;Format track 0, Head 1
JC FD_2A

CALL VERIFY_TRACK ; and verify it
JNC FD_2C
FD_2A:
MOV AL,ERR$TRK_0_BAD ;Error msg if failed
FD_2B:
JMP FD_EXIT
FD_2C:
;----------------------------------------------------------------------
; Format a full track of this disk. Partial formats of tracks aren't
; supported (the same as DOS's format). Use fewer retries since the
; disk should already be spinning and warmed up.
;----------------------------------------------------------------------
DEC DH ;Head 0
INC CH ;Track 1
FD_3A:
MOV AH,RETRY ;Retries
MOV AL,[SI+27] ;Sector per track

CALL FORMAT_TRACK ;May change AX
JC FD_3B

CALL VERIFY_TRACK ;May change AX
JNC FD_3C
;----------------------------------------------------------------------
; If the verify operation fails, mark the entire track bad. Although
; the track could be checked sector by sector, DOS doesn't do it and
; most people just throw away a diskette if it has any bad sectors.
;----------------------------------------------------------------------
FD_3B:
MOV [ERROR],ERR$BAD_SECT ;Set return code
CALL MARK_TRACK_BAD ;Can't fail
;----------------------------------------------------------------------
; Advance to the next head. If HEAD is now 1, repeat the loop with the
; same value for the track. Otherwise, bump the track counter as well.
;----------------------------------------------------------------------
FD_3C:
XOR DH,1 ;Toggle head 0/1
JNZ FD_3A ;If head 1, rpt track

INC CH ;Next track
CMP CH,[SI+1] ;Compare # tracks
JB FD_3A ;Below since 0-based
;----------------------------------------------------------------------
; Physical format is complete. Perform the logical format to make this
; a DOS disk. The FATs are written first since the buffer area is
; required to build the other information areas.
;----------------------------------------------------------------------
MOV BX,[SBUFPTR] ;Ptr to buffer
MOV AL,[SI+24] ;Media ID byte
MOV ES:[BX],AL ;Save in FAT
MOV WORD PTR ES:[BX+1],-1 ; in first 2 entries

MOV AL,[SI+25] ;Sectors per FAT
MOV CX,0002H ;Track 0, Sector 2
SUB DH,DH ;Head 0
MOV DL,[DRIVENUM] ;Drive number
CALL BIOS_WRITE ;1st copy
JC FD_EXIT

MOV AL,[SI+25] ;Sectors per FAT
CALL BIOS_WRITE ;2nd copy
JC FD_EXIT
;----------------------------------------------------------------------
; Zero out one sector of the buffer. Write the root directory one
; sector at a time right after the FATs.
;----------------------------------------------------------------------
PUSH CX ;Preserve track/sect

MOV CX,[SI+14] ;Bytes per sector
SHR CX,1 ; to words
MOV DI,BX ;Start of buffer
SUB AX,AX ;Write zeros
REP STOSW ;Clear buffer

POP DI ;Hold track/sect

SUB CH,CH
MOV CL,[SI+2] ;CX = # root sectors
FD_8:
XCHG CX,DI ;CX = track/sect for write
MOV AL,1 ;Write 1 sector

CALL BIOS_WRITE ;Write to disk
JC FD_EXIT

XCHG CX,DI ;CX = count for loop
LOOP FD_8
;----------------------------------------------------------------------
; Construct the boot record and write it to the first sector.
;----------------------------------------------------------------------
PUSH SI ;Save pointer to media

MOV DI,BX ;ES:DI = dest
MOV WORD PTR ES:[DI+1FEh],0AA55H ;Boot signature

ADD SI,3 ;Point to prefix
MOV CX,32/2 ;Number of words
REP MOVSW ;Copy them

LEA DI,[BX+30H] ;Destination
MOV SI,OFFSET DGROUP:BOOTCODE ;Source

MOV CX,BOOTCODELEN ;Length
REP MOVSB ;Move 'em

MOV AL,1 ;Write 1 sector
MOV CX,0001H ;Track 0, Sector 1
SUB DH,DH ;Head 0
MOV DL,[DRIVENUM] ;Drive number
POP SI ;Restore media pointer
CALL BIOS_WRITE ;Write to disk
JC FD_EXIT
;----------------------------------------------------------------------
; The physical and basic logical format are done. Other operations,
; such as labeling the disk, can be done at the DOS level.
;----------------------------------------------------------------------
MOV AL,[ERROR] ;Retrieve any error
FD_EXIT:
SUB AH,AH ;AH = 0
;----------------------------------------------------------------------
; Restore the original values found in the disk base.
;----------------------------------------------------------------------
PUSH ES ;Preserve register

SUB DX,DX ;Create 0
MOV ES,DX ;Address low memory
ASSUME ES:LOMEM

LES DI,ES:[DISK_BASE] ;ES:DI -> base
ASSUME ES:NOTHING

MOV BX,[SAVE_BASE] ;Retrieve old values
MOV ES:[DI+7],BH ;Restore old base
MOV ES:[DI+4],BL

POP ES ;Restore register
ASSUME ES:NOTHING
;----------------------------------------------------------------------
; Exit to caller.
;----------------------------------------------------------------------
RET

FormatDiskette$FAR ENDP

;======================================================================
; SET_MEDIA (Near, Internal)
;----------------------------------------------------------------------
; Entry:
; DS:SI -> media table
; Exit :
; CF = NC, success
;
; CF = CY, failure
; AL = error code
;----------------------------------------------------------------------
; Changes: AX
;----------------------------------------------------------------------
SET_MEDIA PROC NEAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

PUSH BX ;Save used registers
PUSH CX
PUSH DX
PUSH DI
PUSH ES
PUSH AX ;May get discarded
;----------------------------------------------------------------------
; Attempt to set the correct media/drive combination using BIOS
; function 18h. This function is supported on late model XTs, ATs, and
; all PS/2s. If successful, the function returns ES:DI pointing to a
; useable disk_base for the specified media, but we ignore it.
;----------------------------------------------------------------------
MOV AH,18H ;Set media for format
MOV DL,[DRIVENUM] ; for this drive
MOV CH,[SI+1] ;Number of tracks
DEC CH ;0-based
MOV CL,[SI+27] ;Sectors per track
INT 13H ; thru BIOS
ASSUME ES:NOTHING
JNC SM_EXIT
;----------------------------------------------------------------------
; If the function was supported, but it still failed, bomb out with
; error code.
;----------------------------------------------------------------------
MOV AL,AH ;Error code in AL
CMP AL,1 ;1 = invalid command
JNE SM_ERR
;----------------------------------------------------------------------
; If Set Media failed because it wasn't supported, this BIOS doesn't
; support and we can't format a 1.44M diskette.
;----------------------------------------------------------------------
MOV AL,ERR$INV_CAP ;Specify error
CMP SI,OFFSET DGROUP:MEDIA_1440 ;Check media
JE SM_ERR
;----------------------------------------------------------------------
; Use function 17h, Set DASD (Direct Access Storage Device) type.
; AL = 1, to format 360K in 360K
; 2, to format 360K in 1.2M
; 3, to format 1.2M in 1.2M
; 4, to format 720K in 720K (not supported on all BIOSs)
;----------------------------------------------------------------------
MOV AH,17H ;Set DASD type
MOV DL,[DRIVENUM] ; for this drive
MOV AL,[DRIVETYPE] ; to this type

CMP AL,3 ;Change type 3 to 4
JE SM_4A

CMP AL,2 ;Change 2 to 3 if...
JNE SM_4B

CMP SI,OFFSET DGROUP:MEDIA_1200 ;...Cap = 1.2M
JNE SM_4B
SM_4A:
INC AL ;Adjust argument
SM_4B:
INT 13H ; thru BIOS
JNC SM_EXIT
;----------------------------------------------------------------------
; If supported, but still failed, bomb out with error code.
;----------------------------------------------------------------------
MOV AL,AH ;Error code in AL
CMP AL,1 ;1 = invalid command
JNE SM_ERR
;----------------------------------------------------------------------
; If Set DASD failed because it wasn't supported, we can't format a
; 720k or 1.2M diskette (if that's what was requested).
;----------------------------------------------------------------------
MOV AL,ERR$INV_CAP ;Assume error
CMP SI,OFFSET DGROUP:MEDIA_360 ;Check media
JE SM_EXIT
SM_ERR:
STC ;CF = 1, failure
POP BX ;Discard AX
JMP SHORT SM_5
SM_EXIT:
CLC ;CF = 0, success
POP AX ;Keep AX
SM_5:
POP ES ;Restore registers
ASSUME ES:NOTHING
POP DI
POP DX
POP CX
POP BX

RET

SET_MEDIA ENDP

;======================================================================
; FORMAT_TRACK (Near, Internal)
;----------------------------------------------------------------------
; Entry:
; AH = times to retry if error
; AL = sectors per track
; CH = track
; DL = physical drive number
; DH = head
; DS:SI -> internal media table
; ES:BX -> workspace for track buffer
; Exit:
; CF = NC, success
;
; CF = CY, failure
; AL = error code
;----------------------------------------------------------------------
; Changes: AX CX
;----------------------------------------------------------------------
FORMAT_TRACK PROC NEAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

MOV BYTE PTR [FUNCTION],5 ;Format function #
JMP SHORT FT_0 ;Jump into nest

;======================================================================
; VERIFY_TRACK (Near, Internal)
;----------------------------------------------------------------------
; Except for the function number, this procedure is identical to the
; FORMAT_TRACK procedure.
;----------------------------------------------------------------------
; Changes: AX CX
;----------------------------------------------------------------------
VERIFY_TRACK PROC NEAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

MOV BYTE PTR [FUNCTION],4 ;Verify function #
FT_0:
;----------------------------------------------------------------------
;
;----------------------------------------------------------------------
PUSH BP ;Save used registers
PUSH DI
PUSH AX

MOV CL,1 ;Starting sector
;----------------------------------------------------------------------
; Build the track buffer for this track (CHRN).
; Leave ES:BX pointing to the beginning of the track buffer.
;----------------------------------------------------------------------
PUSH AX ;Save passed info
PUSH CX
PUSH DX
;DH = head
MOV DL,CH ;Put track in DL

SUB CH,CH ;CH = 0
MOV CL,AL ;Number of sectors

MOV DI,CX ;Point DI 2 bytes
SHL DI,1 ; less than length
DEC DI ; of finished buffer
SHL DI,1
ADD DI,BX ;Point to end of buf

STD ;String moves reversed

MOV AL,CL ;Sector number
MOV AH,2 ;Bytes/sector code=512
FT_1:
STOSW ;Write sector/code

DEC AL ;Dec sector number
XCHG AX,DX ;Swap data

STOSW ;Write track/head

XCHG AX,DX ;Swap data back
LOOP FT_1 ;Build entire track

CLD ;String moves forward

POP DX ;Restore values
POP CX
POP AX
;----------------------------------------------------------------------
; Format or verify the track, depending on the function value.
;----------------------------------------------------------------------
FT_2A:
MOV DI,AX ;Save retries
MOV AH,[FUNCTION] ;Format or verify
INT 13H ; thru BIOS
JC FT_2B ;NC = success
;----------------------------------------------------------------------
; Exit the routine succesfully.
;----------------------------------------------------------------------
POP AX ;Restore AX
FT_EXIT:
POP DI ;Restore registers
POP BP
RET
;----------------------------------------------------------------------
; FUNCTION was unsuccessful. Retry, then fail.
;----------------------------------------------------------------------
FT_2B:
MOV BP,AX ;Save error code (AH)

SUB AH,AH ;Reset diskette system
INT 13H ; thru BIOS

CALL SET_MEDIA ;Set media type again
JC FT_ERR

MOV AX,DI ;Get back retries
DEC AH ;Dec them
JNZ FT_2A ;NZ = try again
;----------------------------------------------------------------------
; Exit as a failure.
;----------------------------------------------------------------------
MOV AX,BP ;Retrieve error code
FT_ERR:
MOV AL,AH ;Error code in AL
STC ;Signal failure

POP DI ;Discard old AX
JMP FT_EXIT

VERIFY_TRACK ENDP
FORMAT_TRACK ENDP

;======================================================================
; MARK_TRACK_BAD (Near, Internal)
;----------------------------------------------------------------------
; Given the C (CH), H (DH), and R (always 1) coordinates of the first
; sector to mark bad, mark AL contiguous sectors bad in the FAT.
;
; Note the following:
; BIOS sector numbers are 1-based
; LSNs (logical sector numbers) are 0-based
; CNs (cluster numbers) are 0-based
;----------------------------------------------------------------------
; Entry:
; CH = track
; DL = physical driver number
; DH = head
; DS:SI -> media table
;
; Exit: None
;----------------------------------------------------------------------
; Changes: None
;----------------------------------------------------------------------
MARK_TRACK_BAD PROC NEAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

PUSH AX ;Save used registers
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH ES
;----------------------------------------------------------------------
; Translate CHR coordinates to a 0-based logical sector number.
; LSN = SPT*(NH*C+H)+S-1
; where
; LSN = logical sector number (0-based)
; SPT = sectors per track
; NH = number of heads (always =2)
; C = track (0-based)
; H = head (0-based)
; S = BIOS sector number (1-based) (always =1)
;----------------------------------------------------------------------
SUB CL,CL ;CL = 0
XCHG CH,CL ;CX = Track #
ADD CL,CL ;*2 sides
ADD CL,DH ;Acct for odd head
SUB AH,AH ;AX = sect per track
MOV AL,[SI+27] ;Sect per track
MUL CX ;LSN in DX:AX
MOV CX,AX ;Save LSN of 1st bad
;----------------------------------------------------------------------
; Determine the LSN of the first data sector.
; FDS = NF*SPF + RDS + RS
;----------------------------------------------------------------------
MOV AX,[SI+25] ;Sectors per FAT
MUL BYTE PTR [SI+19] ;* copies of FAT
ADD AX,[SI+17] ;+ reserved sectors
ADD AL,[SI+2] ;+ root dir sectors
;----------------------------------------------------------------------
; Subtract the LSN of the first data sector from our target LSN.
; This gives the sector number offset from the first data sector.
;----------------------------------------------------------------------
NEG AX ;Make negative
ADD AX,CX ;Subtract from LSN
;----------------------------------------------------------------------
; Convert DSN to a 0-based cluster number (CN).
;----------------------------------------------------------------------
MOV BL,[SI+16] ;Sect per cluster
SUB BH,BH ;Extend to word
DIV BX
;----------------------------------------------------------------------
; The first data sector corresponds to cluster number 2.
; Bias the resulting CN by 2. This is the starting cluster number.
;----------------------------------------------------------------------
ADD AX,2 ;Bias cluster #
MOV DX,AX ;Starting cluster #
;----------------------------------------------------------------------
; Determine how many clusters (NC) we need to mark as bad.
;----------------------------------------------------------------------
SUB AH,AH ;AH = 0
MOV AL,[SI+27] ;Sect per track
INC AX ;Round up
DIV BYTE PTR [SI+16] ;AL=AX/sect per cluster
SUB CH,CH
MOV CL,AL ;CX = # bad clusters
;----------------------------------------------------------------------
; Point ES:DI to FAT buffer.
;----------------------------------------------------------------------
MOV DI,[SBUFPTR]
;----------------------------------------------------------------------
; Beginning with the first CN (in DX), mark NC (in CL) clusters bad.
; Assume a 12-bit fat.
;----------------------------------------------------------------------
MTB_1A:
MOV BX,DX ;Cluster number
SHL BX,1 ;* 2...
ADD BX,DX ;-> *3
SHR BX,1 ;\ 2 -> offset

TEST DL,1 ;Even or odd?
JNZ MTB_1B

OR WORD PTR ES:[DI][BX],0FF7H ;Even entry
JMP SHORT MTB_1C
MTB_1B:
OR WORD PTR ES:[DI][BX],0FF70H ;Odd entry
MTB_1C:
INC DX ;Next cluster number
LOOP MTB_1A
;----------------------------------------------------------------------
; Return to caller.
;----------------------------------------------------------------------
POP ES ;Restore registers
ASSUME ES:NOTHING

POP DI
POP DX
POP CX
POP BX
POP AX

RET

MARK_TRACK_BAD ENDP

;======================================================================
; BIOS_WRITE (Near, Internal)
;----------------------------------------------------------------------
; This proc automatically increments sectors, heads, and tracks and
; performs as many writes as required to output the total number of
; sectors requested. It leaves the counters pointing to the next
; available sector.
;----------------------------------------------------------------------
; Entry:
; AL = total sectors to write
; CL = starting sector
; CH = track
; DL = physical driver number
; DH = head
; DS:SI -> media table
; ES:BX -> workspace for track buffer
; Exit:
; CY = FAIL
; AL = error code
;
; NC = SUCCESS
; * = coordinates of first sector after write
; CL = starting sector *
; CH = track *
; DL = physical drive number *
; DH = head *
;----------------------------------------------------------------------
; Changes: AX CX DX
;----------------------------------------------------------------------
BIOS_WRITE PROC NEAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

PUSH BX ;Save registers
PUSH DI
;----------------------------------------------------------------------
; Save the current T:H:S coordinates.
;----------------------------------------------------------------------
MOV [NSECT],AL ;Save total sectors
MOV [SECT],CL ;Current sector
MOV [HEAD],DH ;Head
MOV [TRACK],CH ;Track
;----------------------------------------------------------------------
; Determine how many sectors can be written without having to change
; heads or tracks. Write either that many or the number of requested,
; whichever is fewer.
;----------------------------------------------------------------------
BW_1A:
MOV AH,[SI+27] ;Sectors per track
XCHG AH,AL ; in AL
SUB AL,CL ;Subtract starting sect
INC AL ;Sectors left this track
CMP AH,AL ;CMP want to have
JA BW_1B

MOV AL,AH ;Write AL sectors

BW_1B:
;----------------------------------------------------------------------
; This section calculates what the coordiantes of the next free sector
; will be AFTER the write is completed.
;----------------------------------------------------------------------
SUB [NSECT],AL ;Subtract # written
ADD CL,AL ; last used sector
BW_2A:
CMP CL,[SI+27] ;CMP sect to max
JBE BW_2B

SUB CL,[SI+27] ;Subtract sec per track
XOR DH,1 ;Move to next head
JNZ BW_2A

INC CH ;Next track
JMP BW_2A
BW_2B:
XCHG [SECT],CL ;Current sector
XCHG [HEAD],DH ;Head
XCHG [TRACK],CH ;Track
;----------------------------------------------------------------------
; Write the indicated number of sectors. Advance the buffer pointer.
;----------------------------------------------------------------------
MOV DI,AX ;Save sectors to write

MOV AH,3 ;Write sectors
INT 13H ; thru BIOS
MOV AL,AH ;Possible error in AL
JC BW_EXIT

PUSH DX ;Save over mult

MOV AX,DI ;Get sectors to write
SUB AH,AH ;AH=0
MUL WORD PTR [SI+14] ;Bytes per sector
ADD BX,AX ;Advance buffer pointer

POP DX
;----------------------------------------------------------------------
; Update the registers from the pointers.
;----------------------------------------------------------------------
MOV CL,[SECT] ;Current sector
MOV DH,[HEAD] ;Head
MOV CH,[TRACK] ;Track
;----------------------------------------------------------------------
; Continue if more sectors need to be written.
;----------------------------------------------------------------------
MOV AL,[NSECT] ;Get number left
OR AL,AL ;0 = no more to write
JNZ BW_1A

CLC ;Signal success
;----------------------------------------------------------------------
; Return to caller.
;----------------------------------------------------------------------
BW_EXIT:
POP DI ;Restore registers
POP BX
RET

BIOS_WRITE ENDP

;======================================================================
; BASIC, PASCAL entry point.
;----------------------------------------------------------------------
; 1. Arguments are passed by reference.
; 2. We clean up stack.
; 3. Per protocol, ES is not saved.
;----------------------------------------------------------------------
FormatDiskette PROC FAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

PUSH BP ;Create stack frame
MOV BP,SP

PUSH SI ;Preserve req'd regs
PUSH DI

MOV BX,[BP+0AH] ;Point to...
MOV CX,[BX] ;...media identifier

MOV BX,[BP+0CH] ;Pointer to...
MOV DH,[BX] ;...drive type

MOV BX,[BP+0EH] ;Pointer to...
MOV DL,[BX] ;...drive number

LES DI,DWORD PTR [BP+6] ;Far ptr to buffer
ASSUME ES:NOTHING

CALL FormatDiskette$FAR ;Attempt the format

POP DI ;Restore registers
POP SI

POP BP ;Destroy stack frame

RET 5*2 ;Discard arguments

FormatDiskette ENDP

;======================================================================
; C entry point.
;----------------------------------------------------------------------
; 1. Arguments are passed by value.
; 2. Caller cleans up stack.
; 3. Per protocol, ES is not saved.
;----------------------------------------------------------------------
_FormatDiskette PROC FAR
ASSUME CS:CSEG, DS:DGROUP, ES:NOTHING, SS:DGROUP

PUSH BP ;Create stack frame
MOV BP,SP

PUSH SI ;Preserve registers
PUSH DI

MOV DL,[BP+6] ;Drive number
MOV DH,[BP+8] ;Drive type
MOV CX,[BP+0AH] ;Media identifier
LES DI,DWORD PTR [BP+0CH] ;Far ptr to buffer
ASSUME ES:NOTHING

CALL FormatDiskette$FAR ;Attempt format

POP DI ;Restore registers
POP SI

POP BP ;Destroy stack frame
RET

_FormatDiskette ENDP

CSEG ENDS
END

;======================================================================
; Media information.
; 1. Despite what you read in some books, BIOS sectors are 1-based;
; head, track, logical sector, and FAT coordinates are 0-based.
; 2. ALL boot, FAT, and root directory sectors are located on track 0.
;----------------------------------------------------------------------
; BIOS INFORMATION 360K 1.2M 720K 1.44M
;----------------------------------------------------------------------
; Max head # (0-based) 1 1 1 1
;
; Max track # (0-based) 39 79 79 79
; (27h) (4Fh) (4Fh) (4Fh)
;
; Sectors per track 9 15 9 18
; (9h) (Fh) (9h) (12h)
;
; Total # sectors 720 2400 1440 2880
;----------------------------------------------------------------------
; DOS INFORMATION 360K 1.2M 720K 1.44M
;----------------------------------------------------------------------
; Media (format) ID FDh F9h F9h F0h
;
; # Boot sectors 1 1 1 1
;
; # Sectors per FAT 2 7 3 9
; # copies of FAT 2 2 2 2
; FAT entry type (bits) 12 12 12 12
;
; # Sectors in root directory 7 14 7 14
; # Root directory entries 112 224 112 224
;
; # Sectors per cluster 2 1 2 1
;
; # Data clusters 354 2371 713 2847
; (162h) (943h) (2C9h) (81Fh)
;----------------------------------------------------------------------


  3 Responses to “Category : Files from Magazines
Archive   : WDOCT92.ZIP
Filename : 3N10052A

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/