ID Number: Q65540
3.20 3.21 3.30 3.30a 4.00 4.01
MS-DOS
Summary:
The information below describes how to write a floppy disk formatting
routine that will use ROM BIOS calls.
Generally, to format a floppy disk you need to complete the following
three steps:
1. Set the media type.
2. Format all the tracks on the disk.
3. Write a valid boot sector, empty FATs, and a root directory.
Of these three steps, the first two make the most ROM BIOS calls;
these steps are described in depth in this article. The third step
involves several additional issues and will only be mentioned.
In the explanation of the general technique for formatting a floppy
disk using ROM BIOS calls, how to format a 1.2 MB, 5.25-inch disk is
used as an example.
More Information:
First, you need to set the media type. To do this, you must use
Interrupt (Int) 13h Function (Func) 18h, with the total number of
cylinders in the CH register, the number of sectors per track in the
CL register, and the drive number in the DL register. (Drive number:
0 = A:, 1 = B:...)
For this example, the C code fragment would be as follows:
#include <dos.h>
#include <fcntl.h>
.
.
.
union REGS, reg;
reg.h.ah = 0x18; /* function number */
reg.h.ch = 0x4f; /* set the max cylinder number to 79 */
reg.h.cl = 0x0f; /* set the sector per track to 15 */
reg.h.dl = 0x0; /* set the drive to the first floppy A: */
int86(0x13, ®, ®); /* trigger interrupt 13h */
If the Int 13h Func 18h call is successful, the carry flag will be
cleared and the AH register will equal 00h. Otherwise, the carry flag
will be set and the AH register will contain an error value.
Next, you need to set up a loop that will cycle the number of
cylinders present on the floppy disk. This number should be the same
as the number you put into the CH register for use in the Int 13h Func
18h call. In our example, the loop will need to cycle 80 times, going
from 0 (zero) to 79.
Inside this loop, you need to call a function as many times as there
are heads in the floppy drive. (The typical drive has two heads.)
Since there are two heads on a 1.2 MB disk drive, the functions will
be called twice each cycle, once with head value set to 0 (zero) and
once with the head value set to 1 (one).
This example would have the following C code fragment:
int cylinder;
int head;
int drive = 0x0; /* set drive to first floppy drive */
.
.
.
for (cylinder = 0; cylinder <= 79; cylinder++) {
head = 0; /* set first head */
format_track(drive, cylinder, head); /* format side one */
head++; /* set second head */
format_track(drive, cylinder, head); /* format side two */
}
The function you call from inside the loop should initialize an array
of structures and then call Int 13h, Func 5h. The number of structures
in the array should be the same as the number of sectors per track on
the floppy disk. Each structure corresponds to a sector in the track
and should contain the cylinder number, head number, sector number,
and the sector size code (02h), in the order given. Each element in
the structure is one byte in size. Also, the function should check the
return code from Int 13h, Func 5h call and if the call fails, attempt
the call three more times. This gives the disk drive time to come up
to speed.
The sample function would look something like the following C code
fragment:
char format_track(int drive, int cylinder, int head)
{
union REGS reg;
struct SREGS sreg;
char track_table[4*15]; /* define track table array */
int sector_number;
int loop_var = 0;
/* initialize the track table array */
for (sector_number = 0; sector_number < 15; sector_number++) {
track_table[sector_number * 4] = (char)cylinder;
track_table[sector_number * 4 + 1] = (char)head;
track_table[sector_number * 4 + 2] = (char)sector_number;
track_table[sector_number * 4 + 3] = (char)2;
}
/* format the track */
while (loop_var < 4) { /* loop max four times */
reg.h.ah = 0x05; /* function number */
reg.h.ch = (char)cylinder; /* set cylinder to format */
reg.h.dh = (char)head; /* set which head to use */
reg.h.dl = (char)drive; /* set which drive to use */
reg.x.bx = FPOFF(track_table); /* set offset of track array*/
sreg.es = FPSEG(track_table); /* set segment of track array*/
int86x(0x13, ®, ®, &seg); /* trigger Int 13h*/
if (reg.x.cflag == 0) /* check the Carry Flag */
loop_var = 3; /* success: end loop */
else /* failure... */
loop_var++; /* increment loop variable */
}
if (reg.x.cflag) /* check Carry Flag for return value */
return(reg.h.ah); /* return error code */
else
return(0); /* return success or 0 */
}
(The above function also returns an error code that is not tested for
in previous code fragments, but that could be easily incorporated into
the code. Also, you can add some code into the above function for
verification of the track.)
Finally, after you have formatted all the tracks, you need to write a
valid boot sector to the first sector on the floppy disk, write empty
File Allocation Tables (FATs), and write a blank root directory.
Information on the structure of the boot sector, FATs, and root
directory can be found in the following books:
1. "Advanced MS-DOS Programming," Second Edition (Microsoft Press)
2. "The MS-DOS Encyclopedia" (Microsoft Press)
3. "The Programmer's PC Sourcebook" (Microsoft Press)
4. "DOS Programmer's Reference," Second Edition (QUE Corp.)
A BIOS Note: If the machine you are using does not have a 100-percent
IBM compatible ROM BIOS, the steps described above may fail to work as
described. If this is the case, you may want to try writing your
format routine using Int 21h Func 44h calls.