home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2002 March
/
Chip_2002-03_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d5
/
cak
/
CAKDIR.ZIP
/
FLOPPY.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1999-10-21
|
41KB
|
941 lines
{------------------------------------------------------------------------------}
{ unit : floppy }
{ version : 1.0 }
{ last update: 1999/04/05 }
{ written for: Delphi 3 & 4 }
{ written by : Geir Wikran }
{ e-mail : gwikran@online.no }
{------------------------------------------------------------------------------}
unit floppy;
{==============================================================================}
interface
uses
Windows, vwin32;
{------------------------------------------------------------------------------}
{ }
{ This unit is designed for 3.5" 1.44Mb floppy drives. It is only meant to be }
{ used for accessing floppy disks. However, the functions in this unit does }
{ not set any restrictions on drive numbers that are pased as parameters, and }
{ no checking is done to see if a drive number really is a floppy drive. The }
{ user must make sure not to use these functions on drives other than floppy }
{ drives. }
{ }
{ Logical drives: 1=A, 2=B, etc. }
{ }
{------------------------------------------------------------------------------}
procedure AllocFloppyFSBR(BPB: TBPB; OEMName,VolumeLabel: String; var FSBR: PFSBR);
{ Allocates necessary memory (BPB.BytesPerSector) for and initiates }
{ a FSBS (File System Boot Record) structure based on the BPB, and }
{ sets OEMName and VolumeLabel fields as specified. }
function ReadFloppyFSBR(Drive: Byte; var FSBR: PFSBR): Boolean;
{ Allocates memory for and reads the FSBR from a floppy disk. If an }
{ error occures trying to read the sector on the disk FSBR will be }
{ nil on return. }
procedure FreeFloppyFSBR(var FSBR: PFSBR);
{ Releases memory allocated for a FSBR structure. }
function CreateFloppyBootRecord(Drive: Byte; FSBR: PFSBR): Boolean;
{ Writes the FSBR to logical sector 0 (cylinder 0, head 0, sector 1).}
function CreateFloppyFATs(Drive: Byte; FSBR: PFSBR): Boolean;
{ Creates the FATs on a disk. }
function CreateFloppyRootDir(Drive: Byte; FSBR: PFSBR): Boolean;
{ Creates an empty root directory on a disk. }
function FormatFloppyDisk(Drive: Byte; VolumeLabel: String): Boolean;
{ Formates a floppy disk with the default format for the drive, and }
{ creates an empty file system (FSBR,FAT, and root dir). }
{ This function can be used as it is, but is meant as an example to }
{ show the procedure for formating a floppy. In an application the }
{ formating procedure can be enhanced to show the progress of the }
{ the process, and maybe write zero-filled sectors to the tracks as }
{ they are formated. }
{ $DEFINE INT13}
{$IFDEF INT13}
{ Windows 95 and later does not support calling low-level BIOS disk functions }
{ (interrupt 13h) to gain access to hard disks. Interrupt 13h functions still }
{ work on floppy disks but always fail on hard disks. However, for performance }
{ reasons it is not recomended to use interrupt 13h functions for reading, }
{ writing, and formating floppy disks. Interrupt 13h functions are not ideal }
{ for use in a multitasking environment because they leave very little system }
{ time for other processes. It is therefore recomended to use interrupt 21h }
{ function 440Dh for direct access to floppy disks. }
const
{ Floppy disk types used with InitFloppyBPB function: }
FloppyDisk_720K = $01; { 720Kb standard format }
FloppyDisk_144M = $02; { 1.44Mb standard format }
FloppyDisk_168M = $03; { 1.68Mb nonstandard format }
FloppyDisk_DMF1K = $04; { 1Kb (2 sectors) per clusters DMF format }
FloppyDisk_DMF2K = $05; { 2Kb (4 sectors) per clusters DMF format }
procedure InitFloppyBPB(DiskType: Byte; var BPB: TBPB);
{ Initializes a BPB (BIOS Parameter Block) structure for a given }
{ disk type. }
type
PDPT = ^TDPT;
TDPT = packed record { Device Parameter Table (located at interrupt 1Eh): }
FirstSpecifyByte : Byte; { bits 7-4: step rate }
{ bits 3-0: head unload time ($0F=240ms) }
SecondSpecifyByte: Byte; { bits 7-1: head loaad time ($01=4ms) }
{ bits 0: non-DMA mode (always 0) }
TurnOffDelay : Byte; { Delay until motor turned off (in clock ticks). }
BytesPerSector : Byte; { Bytes per sector: 0=128 1=256 2=512 3=1024. }
SectorsPerTrack : Byte; { Number of sectors per track. }
LengthSectorGap : Byte; { Length of gap between sectors }
{ ($2A for 5.25", $1B for 3.5"). }
DataLength : Byte; { Data length (ignored if BytesPerSector field }
{ is nonzero). }
GapLength : Byte; { Gap length when formating ($50 for 5.25", }
{ $6C for 3.5"). }
FormatFiller : Byte; { Format filler byte (default $F6). }
HeadSettleTime : Byte; { Head settle time in milliseconds. }
MotorStartTime : Byte; { Motor start time in 1/8 seconds. }
end;
procedure InitFloppyDPT(BPB: TBPB; var DPT: TDPT);
{ Initialize a DPT (Device Parameter Table) stucture for a diskette }
{ based on the BPB. }
type
PInt13SectorHeader = ^TInt13SectorHeader;
TInt13SectorHeader = packed record
Track : Byte;
Head : Byte;
Sector : Byte;
SizeCode: Byte;
end;
PInt13TrackTable = ^TInt13TrackTable;
TInt13TrackTable = packed array[1..$FFFF] of TInt13SectorHeader;
function Int13HasChangeLine(Drive: Byte): Boolean;
{ Returnes true if drive is a floppy disk with change-line support. }
function Int13DiskHasChanged(Drive: Byte): Boolean;
{ Returnes true if the diskette in a floppy drive has been changed }
{ since the last time the drive was accessed, or if change-line is }
{ not supported by the drive. Because this function only returns }
{ true if the diskette has changed since the last time the drive }
{ was accessed, it is important not to access the drive in any way }
{ before calling this function. Even chech to see if change-line is }
{ supported (HasChangeLine function) may clear the changed-flag. }
function Int13ResetDisk(Drive: Byte): Boolean;
{ Resets a floppy disk to power-up state, and forces the controller }
{ to recalibrate drive heads (seek to track 0). }
function Int13ReadTrack(Drive,Cylinder,Head,Sector,Count: Byte; Buffer: Pointer): Boolean;
{ Reads Count number of sectors from a floppy disk using absolute }
{ cylinder, head, and sector address. }
function Int13WriteTrack(Drive,Cylinder,Head,Sector,Count: Byte; Buffer: Pointer): Boolean;
{ Writes Count number of sectors from a floppy disk using absolute }
{ cylinder, head, and sector address. }
function Int13FormatTrack(Drive,Cylinder,Head,Sectors: Byte; Table: PInt13TrackTable): Boolean;
{ Formates Sectors number of sectors on the given cylinder and head }
{ on a floppy disk. The number of sectors per track is read from the }
{ current drive parameter table. }
function Int13VerifyTrack(Drive,Cylinder,Head,Sector,Count: Byte; Buffer: Pointer): Boolean;
{ Verifies Count number of sectors at the absolute cylinder, head, }
{ and sector address on a floppy disk. Check whether the sectors were}
{ correctly written to disk by comparing the data in the sector }
{ against the CRC stored on the disk. }
procedure Int13SectorToTrack(Logical: DWord; BPB: TBPB; var Cylinder,Head,Sector: Byte);
{ Converts a logical sector number into absolute track, head, and }
{ sector address. Sector 0 is the first logical sector on a disk. }
function Int13ReadSector(Drive: Byte; Logical: DWord; BPB: TBPB; Buffer: Pointer): Boolean;
{ Reads a logical sector. }
function Int13WriteSector(Drive: Byte; Logical: DWord; BPB: TBPB; Buffer: Pointer): Boolean;
{ Writes a logical sector. }
function Int13VerifySector(Drive: Byte; Logical: DWord; BPB: TBPB; Buffer: Pointer): Boolean;
{ Verifies a logical sector. }
function Int13SetMediaFormat(Drive,MaxCylinder,MaxSector: Byte; var DPT: PDPT): Boolean;
{ Sets drive parameters to be used when formatting a floppy disk. }
{ Highest vaild value for MaxCylinder on a floppy is 79, but it is }
{ still possible to formate tracks 80. Highest valid value for }
{ MaxSector per track is 18, but it is still possible to formate }
{ 21 sectors per track. The function returns a pointer to the }
{ diskette parameters (located at interrupt address 1Eh). Use }
{ this pointer to manipulate the parameter values. }
function Int13SectorSizeCode(BPB: TBPB): Byte;
{ Returns the sector size code that shoud be used in sector headers }
{ when formating a track. }
function Int13FormatDisk(Drive: Byte; BPB: TBPB; Wipe: Boolean): Boolean;
{ Formates a floppy disk with the format specified in the BPB. If }
{ Wipe is true each sector will be overwriten with blank (zeros- }
{ filled) data. If Wipe is false only the formating data is writen }
{ to the disk without blanking out the sectors. }
{ NOTE: This function will not format successfully other formates }
{ than 1.44Mb standard format (type FloppyDisk_144M). Could }
{ not get it to work with other formates, not even 720Kb }
{ format. }
{ NOTE: If Norton Antivirus 5 (don't know about other versions) is }
{ running on the system diskettes formated with the FormatDisk }
{ function will not be formated correctly. I have not be able }
{ to locate the actuall problem, but suspect that the problem }
{ has to do with interrupt 13h function 5h (format track). If }
{ Norton Antivirus 5 is installed on the system the problem }
{ can be solved by opening autoexec.bat and rem out the command}
{ that runs navdx.exe when the system boots. }
{------------------------------------------------------------------------------}
{ }
{ Drives are numbered 1-> }
{ Floppy drive A=1 B=2. }
{ }
{ Cylinders are numbered 0->MaxCylinders }
{ On a floppy disk the highest valid value for MaxCylinder as parameter to }
{ the SetMediaFormat function is 79, but it is still possible to access and }
{ use (formate, read, and write) track 80. One a floppy disk formated by by }
{ DOS or Windows track 80 is not formated. }
{ }
{ Heads are numbered 0->MaxHead }
{ A floppy disk has two heads, 0 and 1. }
{ }
{ Sectors on each track are numbered 0->MaxSector }
{ DOS and Windows only uses sectors 1->MaxSector, but it is possible to }
{ access and use sector 0 also. When formating a track with the FormatTrack }
{ function all sectors from 0 to number of sectors are formated. Howeven, }
{ even if sector 0 is formated the sectors in the track table pased to the }
{ FormatDisk function MUST be numbered from 1 and up, not from 0. }
{ NOTE: Sector 0 is accessible on all tracks but track 0, head 0. The first }
{ sector on a disk (the boot sector) is track 0, head 0, sector 1. }
{ The higest valid value for MaxSector per track as pased as parameter to }
{ the SetMediaFormat function is 18, but it is actually possible to format }
{ 21 sectors per track with the FormatTrack function. }
{ }
{ Logical sectors are numbered 0->BPB.SectorsOnDrive-1 }
{ }
{------------------------------------------------------------------------------}
var
FloppyDiskRetries: Byte = 3; { Number of times to retry a disk operation if }
{ it fails. Error on a floppy may be due to the }
{ motor failing to spin up quickly enough; the }
{ operation should be retried at least three }
{ times, resetting the disk between attemps. }
{$ENDIF}
{==============================================================================}
implementation
const
FloppySectorSize = 512;
type
PFloppySectorArray = ^TFloppySectorArray;
TFloppySectorArray = array[1..FloppySectorSize] of Byte;
var
FloppyFSBSTemplate: TFloppySectorArray = (
$EB,$3E,$90,$29,$33,$75,$39,$68,$49,$48,$43,$00,$02,$01,$01,$00,
$02,$E0,$00,$40,$0B,$F0,$09,$00,$12,$00,$02,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$29,$43,$16,$EA,$18,$4E,$4F,$20,$4E,$41,
$4D,$45,$20,$20,$20,$20,$46,$41,$54,$31,$32,$20,$20,$20,$F1,$7D,
$FA,$33,$C9,$8E,$D1,$BC,$FC,$7B,$16,$07,$BD,$78,$00,$C5,$76,$00,
$1E,$56,$16,$55,$BF,$22,$05,$89,$7E,$00,$89,$4E,$02,$B1,$0B,$FC,
$F3,$A4,$06,$1F,$BD,$00,$7C,$C6,$45,$FE,$0F,$8B,$46,$18,$88,$45,
$F9,$FB,$38,$66,$24,$7C,$04,$CD,$13,$72,$3C,$8A,$46,$10,$98,$F7,
$66,$16,$03,$46,$1C,$13,$56,$1E,$03,$46,$0E,$13,$D1,$50,$52,$89,
$46,$FC,$89,$56,$FE,$B8,$20,$00,$8B,$76,$11,$F7,$E6,$8B,$5E,$0B,
$03,$C3,$48,$F7,$F3,$01,$46,$FC,$11,$4E,$FE,$5A,$58,$BB,$00,$07,
$8B,$FB,$B1,$01,$E8,$94,$00,$72,$47,$38,$2D,$74,$19,$B1,$0B,$56,
$8B,$76,$3E,$F3,$A6,$5E,$74,$4A,$4E,$74,$0B,$03,$F9,$83,$C7,$15,
$3B,$FB,$72,$E5,$EB,$D7,$2B,$C9,$B8,$D8,$7D,$87,$46,$3E,$3C,$D8,
$75,$99,$BE,$80,$7D,$AC,$98,$03,$F0,$AC,$84,$C0,$74,$17,$3C,$FF,
$74,$09,$B4,$0E,$BB,$07,$00,$CD,$10,$EB,$EE,$BE,$83,$7D,$EB,$E5,
$BE,$81,$7D,$EB,$E0,$33,$C0,$CD,$16,$5E,$1F,$8F,$04,$8F,$44,$02,
$CD,$19,$BE,$82,$7D,$8B,$7D,$0F,$83,$FF,$02,$72,$C8,$8B,$C7,$48,
$48,$8A,$4E,$0D,$F7,$E1,$03,$46,$FC,$13,$56,$FE,$BB,$00,$07,$53,
$B1,$04,$E8,$16,$00,$5B,$72,$C8,$81,$3F,$4D,$5A,$75,$A7,$81,$BF,
$00,$02,$42,$4A,$75,$9F,$EA,$00,$02,$70,$00,$50,$52,$51,$91,$92,
$33,$D2,$F7,$76,$18,$91,$F7,$76,$18,$42,$87,$CA,$F7,$76,$1A,$8A,
$F2,$8A,$56,$24,$8A,$E8,$D0,$CC,$D0,$CC,$0A,$CC,$B8,$01,$02,$CD,
$13,$59,$5A,$58,$72,$09,$40,$75,$01,$42,$03,$5E,$0B,$E2,$CC,$C3,
$03,$18,$01,$27,$0D,$0A,$49,$6E,$76,$61,$6C,$69,$64,$20,$73,$79,
$73,$74,$65,$6D,$20,$64,$69,$73,$6B,$FF,$0D,$0A,$44,$69,$73,$6B,
$20,$49,$2F,$4F,$20,$65,$72,$72,$6F,$72,$FF,$0D,$0A,$52,$65,$70,
$6C,$61,$63,$65,$20,$74,$68,$65,$20,$64,$69,$73,$6B,$2C,$20,$61,
$6E,$64,$20,$74,$68,$65,$6E,$20,$70,$72,$65,$73,$73,$20,$61,$6E,
$79,$20,$6B,$65,$79,$0D,$0A,$00,$49,$4F,$20,$20,$20,$20,$20,$20,
$53,$59,$53,$4D,$53,$44,$4F,$53,$20,$20,$20,$53,$59,$53,$80,$01,
$00,$57,$49,$4E,$42,$4F,$4F,$54,$20,$53,$59,$53,$00,$00,$55,$AA
);
procedure AllocFloppyFSBR;
var
SectorSize: Word;
StringPtr : PChar;
StringPos : Integer;
begin
GetMem(FSBR,BPB.BytesPerSector);
FillChar(FSBR^,BPB.BytesPerSector,0);
SectorSize := BPB.BytesPerSector;
if SectorSize > FloppySectorSize then SectorSize := FloppySectorSize;
CopyMemory(FSBR,@FloppyFSBSTemplate,SectorSize);
FSBR^.OEMName := ' ';
FSBR^.BPB := BPB;
FSBR^.BootSignature := $29;
FSBR^.VolumeSerial := MakeSerialNumber;
FSBR^.VolumeLabel := ' ';
FSBR^.SystemType := 'FAT12 ';
if OEMName <> '' then begin
StringPtr := PChar(OEMName);
StringPos := 0;
while (StringPtr^ <> #0) and (StringPos < SizeOf(FSBR^.OEMName)) do begin
FSBR^.OEMName[StringPos] := UpCase(StringPtr^);
Inc(StringPtr);
Inc(StringPos);
end;
end;
if VolumeLabel <> '' then begin
StringPtr := PChar(VolumeLabel);
StringPos := 0;
while (StringPtr^ <> #0) and (StringPos < SizeOf(FSBR^.VolumeLabel)) do begin
FSBR^.VolumeLabel[StringPos] := UpCase(StringPtr^);
Inc(StringPtr);
Inc(StringPos);
end;
end;
end;
function ReadFloppyFSBR;
begin
GetMem(FSBR,2024);
Result := ReadSector(Drive,0,1,FSBR);
if Result then ReallocMem(FSBR,FSBR^.BPB.BytesPerSector)
else ReallocMem(FSBR,0);
end;
procedure FreeFloppyFSBR;
begin
ReallocMem(FSBR,0);
end;
function CreateFloppyBootRecord;
begin
Result := WriteSector(Drive,0,1,FSBR,WRITE_MODE_UNSPECIFIED_DATA);
end;
function CreateFloppyFATs;
var
FATSector : Pointer;
SectorIndex : Byte;
FATIndex : Byte;
SectorNumber: Word;
begin
Result := true;
with FSBR^.BPB do begin
GetMem(FATSector,BytesPerSector);
for FatIndex := 1 to NumberOfFats do
for SectorIndex := 1 to SectorsPerFat do begin
FillChar(FATSector^,BytesPerSector,0);
if SectorIndex = 1 then
PDWord(FATSector)^ := $00FFFF00 or MediaDescriptor;
{ The first byte in a FAT must be a copy of the media desriptor }
{ byte. The second and third byte must be set to FFh. These tree }
{ bytes (24 bits) actually occupy FAT entries 0 and 1. In FAT12 }
{ system: 12 bits * 2 (entries 0 and 1) = 24 bits. So, the first }
{ data cluster entry in a FAT is entry 2 (cluster 2). }
SectorNumber := ReservedSectors+((FATIndex-1)*SectorsPerFat)+(SectorIndex-1);
Result := WriteSector(Drive,SectorNumber,1,FATSector,WRITE_MODE_UNSPECIFIED_DATA);
end;
ReallocMem(FATSector,0);
end;
end;
function CreateFloppyRootDir;
var
RootSector : PDirEntry;
FirstSector : Word;
LastSector : Word;
SectorNumber: Word;
SystemTime : TSystemTime;
FileTime : TFileTime;
begin
Result := true;
with FSBR^.BPB do begin
GetMem(RootSector,BytesPerSector);
FirstSector := ReservedSectors+(NumberOfFats*SectorsPerFat);
LastSector := FirstSector+((RootDirEntries*SizeOf(TDirEntry)) div BytesPerSector);
for SectorNumber := FirstSector to LastSector do begin
FillChar(RootSector^,BytesPerSector,0);
if SectorNumber = FirstSector then
if FSBR^.VolumeLabel <> ' ' then
with PVolumeLabelDirEntry(RootSector)^ do begin
CopyMemory(@VolumeLabel,@FSBR^.VolumeLabel,SizeOf(VolumeLabel));
Attributes := $08;
GetSystemTime(SystemTime);
SystemTimeToFileTime(SystemTime,FileTime);
FileTimeToDosDateTime(FileTime,CreationDate,CreationTime);
end;
Result := WriteSector(Drive,SectorNumber,1,RootSector,WRITE_MODE_UNSPECIFIED_DATA);
end;
ReallocMem(RootSector,0);
end;
end;
function FormatFloppyDisk;
var
DeviceParameters: PExtDeviceParameters;
CylinderIndex : Byte;
HeadIndex : Byte;
SectorIndex : Byte;
FSBR : PFSBR;
begin
if LockPhysicalVolume(1,0,LOCK_FOR_FORMATTING) then begin
LockPhysicalVolume(1,0,LOCK_FOR_FORMATTING);
GetMem(DeviceParameters,SizeOf(TExtDeviceParameters));
Result := GetDeviceParameters(Drive,DeviceParameters,SizeOf(TExtDeviceParameters));
if Result then with DeviceParameters^ do begin
ReallocMem(DeviceParameters,SizeOf(TExtDeviceParameters)
+SizeOf(TSectorEntry)*BPB.SectorsPerTrack);
SpecialFunctions := $05;
EntriesInTable := BPB.SectorsPerTrack;
for SectorIndex := 1 to BPB.SectorsPerTrack do begin
SectorTable[SectorIndex-1].SectorNumber := SectorIndex;
SectorTable[SectorIndex-1].SectorSize := BPB.BytesPerSector;
end;
Result := SetDeviceParameters(Drive,DeviceParameters,SizeOf(TExtDeviceParameters));
if Result then begin
for CylinderIndex := 0 to Cylinders do
for HeadIndex := 0 to BPB.NumberOfHeads-1 do begin
if Result then Result := FormatTrack(Drive,CylinderIndex,HeadIndex);
end;
SpecialFunctions := $04;
SetDeviceParameters(Drive,DeviceParameters,SizeOf(TExtDeviceParameters));
ReallocMem(DeviceParameters,0);
end;
AllocFloppyFSBR(PBPB(@BPB)^,'',VolumeLabel,FSBR);
if Result then Result := CreateFloppyBootRecord(Drive,FSBR);
if Result then Result := CreateFloppyFATs(Drive,FSBR);
if Result then Result := CreateFloppyRootDir(Drive,FSBR);
FreeFloppyFSBR(FSBR);
end;
UnlockPhysicalVolume(1);
UnlockPhysicalVolume(1);
end;
end;
{$IFDEF INT13}
procedure InitFloppyBPB;
begin
FillChar(BPB,SizeOf(BPB),0);
case DiskType of
FloppyDisk_720K: with BPB do begin { 720Kb standard format }
BytesPerSector := 512;
SectorsPerCluster := 2;
ReservedSectors := 1;
NumberOfFats := 2;
RootDirEntries := 112;
SectorsOnDrive := 1440;
MediaDescriptor := $F9;
SectorsPerFat := 3;
SectorsPerTrack := 9;
NumberOfHeads := 2;
end;
FloppyDisk_144M: with BPB do begin { 1.44Mb standard format }
BytesPerSector := 512;
SectorsPerCluster := 1;
ReservedSectors := 1;
NumberOfFats := 2;
RootDirEntries := 224;
SectorsOnDrive := 2880;
MediaDescriptor := $F0;
SectorsPerFat := 9;
SectorsPerTrack := 18;
NumberOfHeads := 2;
end;
FloppyDisk_168M: with BPB do begin { 1.68Mb nonstandard format }
BytesPerSector := 512;
SectorsPerCluster := 1;
ReservedSectors := 1;
NumberOfFats := 2;
RootDirEntries := 224;
SectorsOnDrive := 3360;
MediaDescriptor := $F0;
SectorsPerFat := 10;
SectorsPerTrack := 21;
NumberOfHeads := 2;
end;
FloppyDisk_DMF1K: with BPB do begin { 1Kb (2 sectors) per clusters DMF format }
BytesPerSector := 512;
SectorsPerCluster := 2;
ReservedSectors := 1;
NumberOfFats := 2;
RootDirEntries := 16;
SectorsOnDrive := 3360;
MediaDescriptor := $F0;
SectorsPerFat := 5;
SectorsPerTrack := 21;
NumberOfHeads := 2;
end;
FloppyDisk_DMF2K: with BPB do begin { 2Kb (4 sectors) per clusters DMF format }
BytesPerSector := 512;
SectorsPerCluster := 4;
ReservedSectors := 1;
NumberOfFats := 2;
RootDirEntries := 16;
SectorsOnDrive := 3360;
MediaDescriptor := $F0;
SectorsPerFat := 3;
SectorsPerTrack := 21;
NumberOfHeads := 2;
end;
end;
end;
procedure InitFloppyDPT;
begin
with BPB do begin
with DPT do begin
FirstSpecifyByte := $DF;
SecondSpecifyByte := $02;
TurnOffDelay := $25;
BytesPerSector := $02;
SectorsPerTrack := SectorsPerTrack;
LengthSectorGap := $02;
DataLength := $FF;
FormatFiller := $F6;
HeadSettleTime := $0F;
MotorStartTime := $08;
end;
case SectorsPerTrack of
9 : DPT.GapLength := $50;
18: DPT.GapLength := $6C;
21: DPT.GapLength := $0C;
end;
end;
end;
{ Interrupt 13h functions requires 0-based (0=A 1=B etc.) drive numbers. To }
{ conform with the 1-based (1=A 2=B etc.) drive numbers of other drive related }
{ functions in the, the implementation of the following functions converts }
{ from 1-based to 0-based drive numbers. However, the value 0=default drive is }
{ not supported by interrupt 13h. }
function Int13ResetDisk;
{ int 13h, func 00h }
{ in AH = 00h }
{ DL = drive (bit 7 set for hard disk) }
{ out AH = status }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Drive > 0 then Dec(Drive);
with Registers do begin
EAX := $0000;
EDX := Drive;
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (AX and $FF00) = 0 then Result := true
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
end;
end;
function Int13HasChangeLine;
{ int 13h, func 15h }
{ in AH = 15h }
{ DL = drive (bit 7 set for hard disk) }
{ out CF set on error }
{ AH = status }
{ out CF clear if successful }
{ AH = 00h no such drive }
{ 01h floppy without change-line support }
{ 02h floppy with change-line support }
{ 03h hard disk }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Drive > 0 then Dec(Drive);
with Registers do begin
EAX := $1500;
EDX := Drive;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then
Result := ((AX and $FF00) shr 8) = $02
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
end;
end;
function Int13DiskHasChanged;
{ int 13h, func 16h }
{ in AH = 16h }
{ DL = drive (bit 7 set for hard disk) }
{ out CF set if change line active }
{ AH = 06h change line active or not supported }
{ 80h drive not ready or not present }
{ out CF clear if chage line inactive }
{ AH = 00h no drive change }
var
Registers: TDIOC_Registers;
begin
VWIN32Error := ERROR_NON;
Result := true;
if Drive > 0 then Dec(Drive);
with Registers do begin
EAX := $1600;
EDX := Drive;
Flags := $00000000;
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then
Result := ((AX and $FF00) shr 8) <> $00
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
end;
end;
function Int13ReadTrack;
{ int 13h, func 02h }
{ in AH = 02h }
{ AL = number of sectors to read }
{ CH = low eight bits of track number }
{ CL = sector number (bits 5-0) }
{ high two bits of track number (bits 7-6) }
{ DH = head number }
{ DL = drive number (bit 7 set for hard disk) }
{ ES:BX -> data buffer }
{ out CF set on error }
{ AH = status }
{ out CF clear if successful }
{ AL = number of sectors transferred }
var
Registers: TDIOC_Registers;
Retries : Byte;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Drive > 0 then Dec(Drive);
Retries := FloppyDiskRetries;
while (not Result) and (Retries > 0) do with Registers do begin
EAX := $0200 or Count;
ECX := (Cylinder shl 8) or Sector;
EDX := (Head shl 8) or Drive;
EBX := DWord(Buffer);
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
Dec(Retries);
end;
end;
function Int13WriteTrack;
{ int 13h, func 03h }
{ in AH = 03h }
{ AL = number of sectors to write }
{ CH = low eight bits of track number }
{ CL = sector number (bits 5-0) }
{ high two bits of track number (bits 7-6) }
{ DH = head number }
{ DL = drive number (bit 7 set for hard disk) }
{ ES:BX -> data buffer }
{ out CF set on error }
{ AH = status }
{ out CF clear if successful }
{ AL = number of sectors transferred }
var
Registers: TDIOC_Registers;
Retries : Byte;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Drive > 0 then Dec(Drive);
Retries := FloppyDiskRetries;
while (not Result) and (Retries > 0) do with Registers do begin
EAX := $0300 or Count;
ECX := (Cylinder shl 8) or Sector;
EDX := (Head shl 8) or Drive;
EBX := DWord(Buffer);
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
Dec(Retries);
end;
end;
function Int13FormatTrack;
{ int 13h, func 05h }
{ in AH =05h }
{ AL = number of sectors to format }
{ CH = track number }
{ DH = head number }
{ DL = drive number }
{ ES:BX -> track table }
{ the Sector fields must be numbered }
{ from 1 (not 0) and upward }
{ out CF set on error }
{ AH = status }
{ out CF clear if successful }
var
Registers: TDIOC_Registers;
Retries : Byte;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Drive > 0 then Dec(Drive);
Retries := FloppyDiskRetries;
while (not Result) and (Retries > 0) do with Registers do begin
EAX := $0500 or Sectors;
ECX := (Cylinder shl 8);
EDX := (Head shl 8) or Drive;
EBX := DWord(Table);
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
Dec(Retries);
end;
end;
function Int13VerifyTrack;
{ int 13h, func 04h }
{ in AH = 04h }
{ AL = number of sectors to verify }
{ CH = low eight bits of track number }
{ CL = sector number (bits 5-0) }
{ high two bits of track number (bits 7-6) }
{ DH = head number }
{ DL = drive number (bit 7 set for hard disk) }
{ ES:BX -> data buffer }
{ out CF set on error }
{ AH = status }
{ out CF clear if successful }
{ AL = number of sectors verified }
var
Registers: TDIOC_Registers;
Retries : Byte;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Drive > 0 then Dec(Drive);
Retries := FloppyDiskRetries;
while (not Result) and (Retries > 0) do with Registers do begin
EAX := $0400 or Count;
ECX := (Cylinder shl 8) or Sector;
EDX := (Head shl 8) or Drive;
EBX := DWord(Buffer);
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (Flags and FLAG_CARRY) = 0 then Result := true
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
Dec(Retries);
end;
end;
procedure Int13SectorToTrack;
begin
Cylinder := (Logical div BPB.SectorsPerTrack) div BPB.NumberOfHeads;
Head := (Logical div BPB.SectorsPerTrack) mod BPB.NumberOfHeads;
Sector := (Logical mod BPB.SectorsPerTrack) + 1;
end;
function Int13ReadSector;
var
Cylinder : Byte;
Head : Byte;
Sector : Byte;
begin
Int13SectorToTrack(Logical,BPB,Cylinder,Head,Sector);
Result := Int13ReadTrack(Drive,Cylinder,Head,Sector,1,Buffer);
end;
function Int13WriteSector;
var
Cylinder : Byte;
Head : Byte;
Sector : Byte;
begin
Int13SectorToTrack(Logical,BPB,Cylinder,Head,Sector);
Result := Int13WriteTrack(Drive,Cylinder,Head,Sector,1,Buffer);
end;
function Int13VerifySector;
var
Cylinder : Byte;
Head : Byte;
Sector : Byte;
begin
Int13SectorToTrack(Logical,BPB,Cylinder,Head,Sector);
Result := Int13VerifyTrack(Drive,Cylinder,Head,Sector,1,Buffer);
end;
function Int13SetMediaFormat;
{ int 13h, func 18h }
{ in AH = 18h }
{ CH = low eight bits of max track number }
{ CL = max sector number on each track (bits 5-0) }
{ high two bits of max track number (bits 7-6) }
{ DL = drive number }
{ out AH = status }
{ ES:DI -> 11-byte parameter table }
var
Registers: TDIOC_Registers;
Retries : Byte;
begin
VWIN32Error := ERROR_NON;
Result := false;
if Drive > 0 then Dec(Drive);
Retries := FloppyDiskRetries;
while (not Result) and (Retries > 0) do with Registers do begin
EAX := $1800;
ECX := (MaxCylinder shl 8) or MaxSector;
EDX := Drive;
if VWIN32DIOC(VWIN32_DIOC_DOS_INT13,@Registers) then begin
if (AX and $FF00) = 0 then begin
Result := true;
DPT := PDPT(EDI);
end
else VWIN32Error := $10000 or ((AX and $FF00) shr 8);
end;
Dec(Retries);
end;
end;
function Int13SectorSizeCode;
var
SizeBase: Word;
begin
Result := 0;
SizeBase := 128;
while (SizeBase < BPB.BytesPerSector) and (SizeBase < $FFFF) do begin
Inc(Result);
Inc(SizeBase,SizeBase);
end;
end;
function Int13FormatDisk;
{ This function will only format standard 1.44Mb floppies. To formate floppies }
{ in nonstandard formates (1.68 etc.) the device parameter table has to be }
{ tweeked manually. The address for this table is located at interrupt 1Eh, }
{ and it is not possible (as far as I know) to change this interrupt in Win9x. }
{ In DOS the interrupte can be changed with calls to interrupt 21 function 25h }
{ (set interrupt vector) but I know no way to call this function from Win9x. }
var
DPT : PDPT;
NumberOfTracks: Byte;
TrackTable : PInt13TrackTable;
TableOffset : Byte;
TableDisplace : Byte;
SectorNumber : Byte;
SizeCode : Byte;
BlankTrack : Pointer;
CylinderIndex : Byte;
HeadIndex : Byte;
SectorIndex : Byte;
begin
Int13ResetDisk(1);
with BPB do begin
{ Set media type for formating: }
NumberOfTracks := (SectorsOnDrive div SectorsPerTrack div NumberOfHeads)-1;
if NumberOfTracks > 79 then NumberOfTracks := 79;
if SectorsPerTrack <= 18 then
Result := Int13SetMediaFormat(Drive,NumberOfTracks,SectorsPerTrack,DPT)
else
Result := Int13SetMediaFormat(Drive,NumberOfTracks,18,DPT);
{ Highest valid number of sectors per track is 18. }
{ Highest vaild number of tracks on a floppy is 79, }
{ but it is still possible to formate tracks 0-80. }
if Result then begin
{ Allocate track table: }
GetMem(TrackTable,SizeOf(TInt13SectorHeader)*(SectorsPerTrack));
{ Initialize TableOffset and TableDisplace based on SectorsPerTrack: }
TableOffset := (SectorsPerTrack+1) div 2;
TableDisplace := 1;
{ Get the sector size code to be used in track table: }
SizeCode := Int13SectorSizeCode(BPB);
{ Allocate and initialize blank sectors for wiping a track: }
if Wipe then begin
GetMem(BlankTrack,BytesPerSector*SectorsPerTrack);
FillChar(BlankTrack^,BytesPerSector*SectorsPerTrack,0);
end;
CylinderIndex := 0;
while Result and (CylinderIndex <= NumberOfTracks) do begin
{NumberOfTracks+1 to formate track 80}
HeadIndex := 0;
while Result and (HeadIndex < NumberOfHeads) do begin
{ Initialize track table for this track: }
if SectorsPerTrack <= 18 then begin
{ This works when SectorsPerTrack <= 18, }
{ but not when SectorsPerTrack > 18. }
for SectorIndex := 1 to SectorsPerTrack do begin
TrackTable[SectorIndex].Track := CylinderIndex;
TrackTable[SectorIndex].Head := HeadIndex;
TrackTable[SectorIndex].Sector := SectorIndex;
TrackTable[SectorIndex].SizeCode := SizeCode;
end;
end
else begin
{ Interleaving sector etries when SectorsPerTrack > 18. }
{ This will also work when SectorsPeTrack <= 18. }
for SectorIndex := 1 to SectorsPerTrack do begin
TrackTable[SectorIndex].Track := CylinderIndex;
TrackTable[SectorIndex].Head := HeadIndex;
SectorNumber := ((SectorIndex+TableDisplace) div 2);
if (SectorIndex+TableDisplace) and $01 = $01 then
SectorNumber := SectorNumber+TableOffset;
if SectorNumber > SectorsPerTrack then
SectorNumber := SectorNumber-SectorsPerTrack;
TrackTable[SectorIndex].Sector := SectorIndex;
TrackTable[SectorIndex].SizeCode := SizeCode;
end;
if HeadIndex = (NumberOfHeads-1) then begin
Inc(TableDisplace,SectorsPerTrack-18);
if TableDisplace > SectorsPerTrack then
TableDisplace := TableDisplace-SectorsPerTrack;
end;
end;
{ Set device parameters: }
{InitFloppyDPT(BPB,DPT^);}
{ Format the track: }
Result := Int13FormatTrack(Drive,CylinderIndex,HeadIndex,SectorsPerTrack,TrackTable);
{ Write black sectors to wipe out this track: }
if Result and Wipe then
Result := Int13WriteTrack(Drive,CylinderIndex,HeadIndex,1,SectorsPerTrack,BlankTrack);
{ This implementation does not wipe out sector 0. }
Inc(HeadIndex);
end;
Inc(CylinderIndex);
end;
if Wipe then FreeMem(BlankTrack,BytesPerSector*SectorsPerTrack);
FreeMem(Pointer(TrackTable),SizeOf(TInt13SectorHeader)*(SectorsPerTrack+1));
end;
end;
end;
{$ENDIF}
end.