Formatting a Floppy Disk Using ROM BIOS Calls

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, &reg, &reg); /* 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, &reg, &reg, &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.