home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
qbnewsl
/
qbnws105
/
qbformat
/
qbformat.bas
< prev
Wrap
BASIC Source File
|
1990-10-25
|
17KB
|
525 lines
DECLARE FUNCTION QBFORMAT% (drive%, media%)
DECLARE FUNCTION FormatDisk% (drive%)
DECLARE FUNCTION FormatTrack% (drive%, track%, head%)
DECLARE FUNCTION ValidateDisk% (drive%, media%)
DECLARE FUNCTION WriteBoot% (drive%)
DECLARE FUNCTION WriteDir% (drive%)
DECLARE FUNCTION WriteFAT% (drive%)
DECLARE FUNCTION WriteSector% (drive%, cyl%, hd%, sec%)
DECLARE FUNCTION WriteBootSector% (drive%)
DECLARE SUB ComputeCHS (LogSec%, cyl%, hd%, sec%)
DECLARE SUB InitFormatParms (media%)
DECLARE SUB ResetFDC (drive%)
'QBFORMAT.BAS by Cornel Huth 31-Oct-90
'format MS-DOS floppy disks using QB and BIOS
'requires QB.QLB/QB.LIB (specifically INTERRUPTX())
'{5.25-inch media types supported in this code}
'{DS9=double-sided 9-sector(360K) DS15=double-sided 15-sector (1.2M)}
CONST DS9 = &HFD, DS15 = &HF9
'{3.5-inch media types partially supported in this code}
'{DX9=double-sided 9-sector(720K) DX18=double-sided 18-sector (1.44M)}
'{*** DX9 media byte is NEGATIVE to differ from DS15 ***}
CONST DX9 = -&HF9, DX18 = &HF0
CONST RETRIES = 3 '{retries on BIOS error}
TYPE REGtypeX
ax AS INTEGER
bx AS INTEGER
cx AS INTEGER
dx AS INTEGER
bp AS INTEGER
si AS INTEGER
di AS INTEGER
flags AS INTEGER
ds AS INTEGER
es AS INTEGER
END TYPE '20
TYPE ADDRFIELDtype
track AS STRING * 1
head AS STRING * 1
sector AS STRING * 1
bytesec AS STRING * 1
END TYPE '4
TYPE INFOtype
OEM AS STRING * 8 'system name
BS AS INTEGER 'bytes/sector
SC AS STRING * 1 'sectors/cluster
RS AS INTEGER 'reserved sectors
NF AS STRING * 1 'FATs
DE AS INTEGER 'root directory entries
TS AS INTEGER 'total sectors on volume
MB AS STRING * 1 'media byte
SF AS INTEGER 'sectors/FAT
ST AS INTEGER 'sectors/track
NH AS INTEGER 'heads
HS AS INTEGER 'hidden sectors
END TYPE '27
TYPE BOOTRECtype
jmp AS STRING * 3
parms AS INFOtype
code AS STRING * 482
END TYPE '512
'{External routine included with QB 4.0 in QB.LIB & QB.QLB}
'{The INTRPT.ASM supplied with QB 4.00 has 2 known bugs, one of}
'{which is so bad that this code cannot work properly with it.}
'{The INTRPT.ASM supplied with QB 4.00b has 1 known bug, this}
'{code will work with it but DOS BIOS INT25/26h calls will not.}
'{Later versions may still have that bug!}
DECLARE SUB INTERRUPTX (intnum%, ireg AS REGtypeX, oreg AS REGtypeX)
DEFINT A-Z
'{INT 1Eh disk parameter table vectors}
DIM SHARED OldDPTseg, OldDPToff
DIM SHARED NewDPTseg, NewDPToff
'{Number of tracks on media}
DIM SHARED NoTracks
'{format info for media}
DIM SHARED Info AS INFOtype
'{interface with INTERRUPTX routine}
DIM SHARED ireg AS REGtypeX, oreg AS REGtypeX
'{boot record buffer}
DIM SHARED BootRec AS BOOTRECtype
'{sector buffer to write FAT & root directory sectors}
DIM SHARED SectorBuff AS STRING * 512
REM $STATIC
'{Allocate address field data to max possible sectors per track}
DIM SHARED AddrField(1 TO 18) AS ADDRFIELDtype
BootSector:
DATA &HEB,&H3E,&H90,&H20,&H20,&H20,&H20,&H20,&H20,&H20,&H20,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &HA,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H2B,&HC0,&H8E,&HD0,&HBC,&H0,&H7C,&HB8,&HC0,&H7,&H8E,&HD8,&H8E,&HC0,&HBE,&H3
DATA &H0,&HBF,&HAF,&H0,&HB9,&H4,&H0,&HF3,&HA5,&HBE,&HAF,&H0,&HB4,&HE,&H8A,&H4
DATA &HA,&HC0,&H74,&H7,&H56,&HCD,&H10,&H5E,&H46,&HEB,&HF1,&HFC,&HBE,&H7A,&H0,&HBF
DATA &H0,&H2,&HB9,&H0,&H2,&HF3,&HA4,&HE9,&H86,&H1,&HB8,&H1,&H2,&H2B,&HDB,&HB9
DATA &H1,&H0,&HBA,&H50,&H0,&HCD,&H13,&H72,&HC,&HBB,&HFE,&H1,&H81,&H3F,&H55,&HAA
DATA &H75,&H3,&HE9,&HE5,&HFD,&HBE,&H58,&H2,&HB4,&HE,&H8A,&H4,&HA,&HC0,&H74,&H7
DATA &H56,&HCD,&H10,&H5E,&H46,&HEB,&HF1,&H2B,&HC0,&HCD,&H16,&HCD,&H19,&HCD,&H18,&H20
DATA &H20,&H20,&H20,&H20,&H20,&H20,&H20,&H20,&H6E,&H6F,&H6E,&H2D,&H62,&H6F,&H6F,&H74
DATA &H61,&H62,&H6C,&H65,&H20,&H64,&H69,&H73,&H6B,&H20,&H69,&H6E,&H20,&H41,&H3A,&HD
DATA &HA,&H0,&H4E,&H6F,&H20,&H62,&H6F,&H6F,&H74,&H20,&H64,&H69,&H73,&H6B,&H20,&H66
DATA &H6F,&H75,&H6E,&H64,&H2C,&H20,&H72,&H65,&H70,&H6C,&H61,&H63,&H65,&H20,&H61,&H6E
DATA &H64,&H20,&H70,&H72,&H65,&H73,&H73,&H20,&H61,&H20,&H6B,&H65,&H79,&H20,&HD,&HA
DATA &HD,&HA,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0
DATA &H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H0,&H55,&HAA
'============================================================================
'{The following code is a sample run to format a disk}
'{All other code can be compiled and put in a library}
'{format test drive A: double-sided/9-sector media (360K)}
'{...and you thought that this was going to be hard}
drive = 0: media = DS9
CLS : DO: LOOP WHILE INKEY$ <> ""
INPUT "Insert DS9 disk to format in drive A: and press a key", a$
INPUT "Press a key to start QBFORMAT", a$
PRINT "formatting..."
xerr = QBFORMAT(drive, media)
IF xerr THEN
errl = xerr \ 256
errc = xerr AND 255
PRINT "*** Error level:"; errl; " code:"; errc
ELSE
PRINT "done."
END IF
STOP
SUB ComputeCHS (LogSec, cyl, hd, sec)
'{convert a DOS logical sector to BIOS form}
CylSec = Info.ST * Info.NH
cyl = LogSec \ CylSec
rm = LogSec - (cyl * CylSec)
hd = rm \ Info.ST
sec = rm - (hd * Info.ST) + 1
END SUB
FUNCTION FormatDisk (drive)
'{format a track at a time a side at a time}
'{any error aborts format,diskette presumed unreliable}
'{retry format 1 or 2 more times before trashing the diskette}
FOR track = 0 TO (NoTracks - 1)
FOR head = 0 TO (Info.NH - 1)
FOR i = 1 TO RETRIES
xerr = FormatTrack(drive, track, head)
IF xerr = 0 THEN EXIT FOR
NEXT
IF xerr THEN FormatDisk = xerr: EXIT FUNCTION
NEXT
NEXT
FormatDisk = 0
END FUNCTION
FUNCTION FormatTrack (drive, track, head)
'{Initialize address field for each sector on this track}
FOR sec = 1 TO Info.ST
AddrField(sec).track = CHR$(track)
AddrField(sec).head = CHR$(head)
AddrField(sec).sector = CHR$(sec)
AddrField(sec).bytesec = CHR$(2) '{bytecode 2 = 512-byte sector}
NEXT
ireg.ax = &H500 + Info.ST '{format track with sectors/track}
ireg.cx = (track * 256) + 1 '{track to format,start with sector 1}
ireg.dx = (head * 256) + drive '{head,drive}
ireg.es = VARSEG(AddrField(1)) '{point to address field data}
ireg.bx = VARPTR(AddrField(1))
INTERRUPTX &H13, ireg, oreg
cf = oreg.flags AND 1 '{cf=1 if disk error}
IF cf THEN
e& = oreg.ax
IF e& < 0 THEN e& = e& + 65536
FormatTrack = e& \ 256 '{return with status byte}
ResetFDC drive
ELSE ireg.ax = &H400 + Info.ST '{ok, verify track integrity-}
INTERRUPTX &H13, ireg, oreg '{-optional but recommended on format}
cf = oreg.flags AND 1 '{cf=1 if disk error}
IF cf THEN
e& = oreg.ax
IF e& < 0 THEN e& = e& + 65536
FormatTrack = e& \ 256 '{return with status byte}
ResetFDC drive
ELSE
FormatTrack = 0 '{format ok}
END IF
END IF
END FUNCTION
SUB InitFormatParms (media)
'{set up media's format data}
Info.OEM = "IBM 3.1" '{avoid changing 'IBM'}
Info.BS = 512
Info.RS = 1
Info.NF = CHR$(2)
Info.NH = 2
Info.HS = 0
SELECT CASE media
CASE DS9
Info.SC = CHR$(2)
Info.DE = 112
Info.TS = 720
Info.MB = CHR$(DS9)
Info.SF = 2
Info.ST = 9
CASE DS15
Info.SC = CHR$(1)
Info.DE = 224
Info.TS = 2400
Info.MB = CHR$(DS15)
Info.SF = 7
Info.ST = 15
CASE DX9
Info.SC = CHR$(2)
Info.DE = 112
Info.TS = 720
Info.MB = CHR$(ABS(DX9))
Info.SF = 3
Info.ST = 9
CASE DX18
Info.SC = CHR$(1)
Info.DE = 224
Info.TS = 2880
Info.MB = CHR$(DX18)
Info.SF = 9
Info.ST = 18
CASE ELSE
Info.OEM = ""
Info.BS = 0
Info.RS = 0
Info.NF = CHR$(0)
Info.NH = 0
Info.HS = 0
Info.SC = CHR$(0)
Info.DE = 0
Info.TS = 0
Info.MB = CHR$(0)
Info.SF = 0
Info.ST = 0
END SELECT
NoTracks = Info.TS \ Info.NH \ Info.ST
NewDPTseg = 0 'INT 1Eh vector
NewDPToff = 0 'new -> disk parameter table for formatted media
OldDPTseg = 0 'original-
OldDPToff = 0 '-vector
END SUB
FUNCTION QBFORMAT (drive, media)
'{control routine}
xerr = ValidateDisk(drive, media)
IF xerr = 0 THEN xerr = FormatDisk(drive) ELSE level = 1
IF xerr = 0 THEN xerr = WriteBoot(drive) ELSE IF level = 0 THEN level = 2
IF xerr = 0 THEN xerr = WriteFAT(drive) ELSE IF level = 0 THEN level = 3
IF xerr = 0 THEN xerr = WriteDir(drive) ELSE IF level = 0 THEN level = 4
IF xerr THEN IF level = 0 THEN level = 5
'{reset INT 1Eh vector to original,check both for <>0}
IF OldDPTseg <> 0 OR OldDPToff <> 0 THEN
ireg.ax = &H251E
ireg.ds = OldDPTseg
ireg.dx = OldDPToff
INTERRUPTX &H21, ireg, oreg
END IF
QBFORMAT = (level * 256) + xerr
'sample call
'xerr = QBFORMAT(drive, media)
'IF xerr THEN errl = xerr \ 256: errc = xerr AND 255
'level error codes
'0:no error
'1:validate error
'2:format error
'3:boot record write error
'4:FAT write error
'5:directory write error
'floppy disk error codes (xerr,in decimal):
'0:no error
'1:invalid function request
'2:address mark not found
'3:write protected
'4:sector not found
'6:diskette changed
'8:DMA overrun
'9:DMA boundary error
'12:media type not available
'16:bad CRC
'32:diskette controller failed
'64:seek failed
'128:time-out/drive not ready
END FUNCTION
SUB ResetFDC (drive)
'{reset the controller after any BIOS FDC error}
tax = ireg.ax
tdx = ireg.dx
ireg.ax = 0
ireg.dx = drive
INTERRUPTX &H13, ireg, oreg
ireg.ax = tax
ireg.dx = tdx
END SUB
FUNCTION ValidateDisk (drive, media)
'{check if media supported by program,by drive,and if drive is ready}
InitFormatParms media
IF Info.ST THEN
'{check to see if there is CMOS RAM (means we have an AT BIOS)}
OUT &H70, &H10
CMOS = (INP(&H71) <> &HFF)
ResetFDC drive
IF CMOS THEN
'{get original INT 1Eh vector to disk parameter table}
ireg.ax = &H351E
INTERRUPTX &H21, ireg, oreg
OldDPTseg = oreg.es
OldDPToff = oreg.bx
'{set media type for format on AT BIOS/multi-media drive}
'{let BIOS determine if drive can format media with a DPT in BIOS ROM}
ireg.ax = &H1800
ireg.cx = ((NoTracks - 1) * 256) + Info.ST
ireg.dx = drive
FOR checks = 1 TO RETRIES '{zerr=0 no error}
INTERRUPTX &H13, ireg, oreg '{zerr=1 drive invalid}
zerr = oreg.ax \ 256 '{zerr=&H0C unknown media/maybe invalid CMOS}
IF zerr THEN ResetFDC drive ELSE EXIT FOR
NEXT
'{set INT 1Eh vector to this media's disk parameter table in BIOS ROM}
IF zerr = 0 THEN
NewDPTseg = oreg.es
NewDPToff = oreg.di
ireg.ax = &H251E
ireg.ds = NewDPTseg
ireg.dx = NewDPToff
INTERRUPTX &H21, ireg, oreg
ELSE
OldDPTseg = 0
OldDPToff = 0
END IF
ELSE
'{pre-AT BIOS}
'{much more work involved}
'{if you want more than DS9 support, you need to add it}
DEF SEG = 0: Equip = PEEK(&H410): DEF SEG
IF Equip AND 1 THEN
MaxDrive = ((Equip AND &HC0) \ 64) '{MaxDrive=0=1drive, 1=2}
IF (drive >= 0) AND (drive <= MaxDrive) THEN
'get diskette parameter table vector
ireg.ax = &H351E
INTERRUPTX &H21, ireg, oreg
DEF SEG = oreg.es: MaxSectors = PEEK(oreg.bx + 4): DEF SEG
IF MaxSectors = 9 THEN
SELECT CASE media
CASE DS9 '{supported media}
CASE ELSE
zerr = &HC '{invalid media}
END SELECT
'{any other max sectors not supported here}
ELSE
SELECT CASE media
CASE ELSE
zerr = &HC '{invalid media}
END SELECT
END IF
ELSE
zerr = 1 '{invalid drive}
END IF
ELSE
zerr = 1 '{no drives to format}
END IF
END IF
ELSE
zerr = &HC '{media not supported by program}
END IF
'{physical check for disk in the drive}
IF zerr = 0 THEN
ireg.ax = &H401 '{verify 1 sector from drive}
ireg.cx = &H1 '{track=0 sector=1}
ireg.dx = drive '{head=0 drive=drive}
FOR checks = 1 TO RETRIES
INTERRUPTX &H13, ireg, oreg
IF oreg.flags AND 1 THEN '{bad read}
e& = oreg.ax
'{need to detect an unformatted disk}
IF e& < 0 THEN e& = e& + 65536
zerr = e& \ 256
ResetFDC drive
ELSE
zerr = 0 '{good read,already formatted disk in drive}
EXIT FOR
END IF
NEXT
'{zerr may be any of the BIOS diskette error codes if non-zero here}
'{address mark not found(2)=unformatted disk in drive}
'{sector not found(4)=wacko disk but okay to proceed}
IF zerr = 2 OR zerr = 4 THEN zerr = 0
END IF
ValidateDisk = zerr
END FUNCTION
FUNCTION WriteBoot (drive)
RESTORE BootSector
'{read default boot record data}
DEF SEG = VARSEG(BootRec): offset = VARPTR(BootRec)
FOR i = 0 TO 511: READ byte: POKE offset + i, byte: NEXT: DEF SEG
'{update OEM name and BIOS parameter block}
BootRec.parms = Info
'{write the boot record}
FOR i = 1 TO RETRIES
xerr = WriteBootSector(drive)
IF xerr = 0 THEN EXIT FOR
NEXT
WriteBoot = xerr
END FUNCTION
FUNCTION WriteBootSector (drive)
ireg.ax = &H300 + 1 '{write 1 sector}
ireg.cx = 1 '{track 0,sector 1}
ireg.dx = drive '{head 0,drive}
ireg.es = VARSEG(BootRec) '{point to boot record data}
ireg.bx = VARPTR(BootRec)
INTERRUPTX &H13, ireg, oreg
cf = oreg.flags AND 1 '{cf=1 if disk error}
IF cf THEN
e& = oreg.ax
IF e& < 0 THEN e& = e& + 65536
WriteBootSector = e& \ 256 '{return with status byte}
ResetFDC drive
ELSE
WriteBootSector = 0 '{ok}
END IF
END FUNCTION
FUNCTION WriteDir (drive)
MID$(SectorBuff, 1, 1) = CHR$(0)
FOR i = 2 TO 512
IF (i - 1) MOD 32 = 0 THEN
MID$(SectorBuff, i, 1) = CHR$(0)
ELSE
MID$(SectorBuff, i, 1) = CHR$(&HF6)
END IF
NEXT
LogSec = Info.RS + Info.HS + (Info.SF * ASC(Info.NF)) 'first logical dir sector
FOR i = 1 TO (Info.DE \ 16) 'sectors needed for root directory
ComputeCHS LogSec, cyl, hd, sec
FOR k = 1 TO RETRIES
xerr = WriteSector(drive, cyl, hd, sec)
IF xerr = 0 THEN EXIT FOR
NEXT
IF xerr THEN WriteDir = xerr: EXIT FUNCTION
LogSec = LogSec + 1
NEXT
WriteDir = 0
END FUNCTION
FUNCTION WriteFAT (drive)
'{do the hussle}
FAT1$ = Info.MB + CHR$(255) + CHR$(255)
FAT2$ = CHR$(0) + CHR$(0) + CHR$(0)
FOR i = 1 TO 512: MID$(SectorBuff, i, 1) = CHR$(0): NEXT
LogSec = Info.RS + Info.HS 'first logical FAT sector
FOR i = 1 TO ASC(Info.NF)
FOR j = 1 TO Info.SF
IF j = 1 THEN MID$(SectorBuff, 1) = FAT1$ ELSE MID$(SectorBuff, 1) = FAT2$
ComputeCHS LogSec, cyl, hd, sec
FOR k = 1 TO RETRIES
xerr = WriteSector(drive, cyl, hd, sec)
IF xerr = 0 THEN EXIT FOR
NEXT
IF xerr THEN WriteFAT = xerr: EXIT FUNCTION
LogSec = LogSec + 1
NEXT
NEXT
WriteFAT = 0
END FUNCTION
FUNCTION WriteSector (drive, cyl, hd, sec)
'{BIOS write a FAT or directory sector}
ireg.ax = &H300 + 1
ireg.cx = (cyl * 256) + sec
ireg.dx = (hd * 256) + drive
ireg.es = VARSEG(SectorBuff)
ireg.bx = VARPTR(SectorBuff)
INTERRUPTX &H13, ireg, oreg
cf = oreg.flags AND 1
IF cf THEN
e& = oreg.ax
IF e& < 0 THEN e& = e& + 65536
WriteSector = e& \ 256
ResetFDC drive
ELSE
WriteSector = 0
END IF
END FUNCTION