home *** CD-ROM | disk | FTP | other *** search
- /* ----------------------------------------------------------------
- Copyright 1988 by Edward V. Dong, All Rights Reserved.
-
- This source code is placed into the public domain. However,
- contributions are always welcome. This is a modified form of the
- source code used in the author's ZIP program.
-
- Edward V Dong's Floppy Formattor is a Turbo C program to format
- floppy diskettes, based on earlier work by Frank Nystrom
- (COPYIT.C;CIS 71631,355), Kim Kokkonen (FMAT.PAS; Compuserve
- 72457,2131), and Peter Norton (BOOT.ASM). This programs formats,
- accurately, 360K diskettes in either standard 360K drives or 1.2M
- drives.
-
- Essentially, formatting is all performed by the BIOS, through calls
- to Turbo C's biosdisk() routine. To format a disk, the tracks are
- first formatted, then boot record, two copies of the file allocation
- table (FAT), and the root directory are written to the diskette.
- This program then verifies each track, again via the BIOS. The
- basic formatting and verification routines are derived from
- Nystrom's COPYIT.C; the boot record used is a custom one, based on
- Norton's BOOT.ASM. The FAT and root directory routines are rehosted
- versions based on Kokkonen's FMAT.PAS.
-
- To format 360K diskettes in 1.2 megabyte drives, the DASD must be
- set - this is only possible for DOS 3.0 or higher and for AT class
- machines. The routines here are based on Kokkonen's Turbo Pascal
- work, ported to Turbo C. Through some experimentation and analysis,
- the only difference with running on an AT machine is to use a delay
- of about 0.3 seconds between biosdisk calls to allow the disk heads
- to settle.
-
- Quick disk reformat is here done as a rewrite of the diskette's boot
- sector, FAT, and root directory. A "quick" reformat ASSUMES that the
- diskette has no bad sectors at all. Depending on configuration,
- DOS retains a copy of the old FAT which shows the old free space,
- even though the directory has been cleared. This is only true for
- AT's and 1.2 meg drives; as a workaround, one track is formatted,
- which seem to force AT floppy disk controller to recognize that the
- disk has been changed; and therefore DOS will read the diskette to
- acquire the new FAT and directory information.
-
- Programming Note: Character bytes are set as unsigned. This was
- compiled using the Large Model, but is essentially independent of
- C memory model.
-
- Edward V. Dong, 12205 Alexandria Pl, Chino, CA 91710. 18 May 1988
- Change History
- --------------
- 08 Jun 88 - Add check for type of drive (360K or 1.2Meg)
- 04 Jun 88 - set up logical disk sectoring -
- 01 Jun 88 - fix message on disk space -
- 18 May 88 - original issue
- ----------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <dir.h>
- #include <dos.h>
- #include <mem.h>
- #include <string.h>
- #include <bios.h> /* bioskey() */
- #include <conio.h> /* getch() */
- #include <alloc.h> /* farcoreleft() */
-
- /* defines for readability */
-
- #define YES 1
- #define ERR -1
- #define NO_ERR 0
- #define NO 0
- #define VIDEO 16 /* BIOS interrupt number */
-
- /* Disk Constants...*/
-
- #define BYTES_PER_SECTOR 512
- #define SECTORS_PER_TRACK 9
- #define SD_PER_DSK 2
- #define TR_PER_DSK 40
-
- /* biosdisk() BIOS function cmd calls */
-
- #define READ_TRK 2
- #define WRITE_TRK 3
- #define VERIFY_TRK 4
- #define FORMAT_TRK 5
-
- /* When you initialize the disk you need to pass the bios some things.
- */
-
- struct {
- struct {
- struct {
- char cyl,
- head,
- rec,
- num;
- } format_record[SECTORS_PER_TRACK];
- } side[SD_PER_DSK];
- } trk_fmt[TR_PER_DSK];
-
-
- typedef struct {
- struct {
- char data[BYTES_PER_SECTOR * SECTORS_PER_TRACK];
- }head[ SD_PER_DSK];
- }TRACK;
-
- char buffer[BYTES_PER_SECTOR * SECTORS_PER_TRACK];
-
- /* The following is a custom boot record created using Peter Norton's
- BOOT.ASM, modified for DSDD 9-sector disks. */
-
- char boot_rec[] = { /* custom boot record */
- 0xEB,0x2A,0x90,0x20,0x45,0x2E,0x44,0x6F,0x6E,0x67,0x20,0,0x02,0x02,0x01,0,
- 0x02,0x70,0,0xD0,0x02,0xFD,0x02,0,0x09,0,0x02,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0xB8,0xC0,0x07,0x50,
- 0x1F,0xBB,0x56,0,0x90,0xB9,0x49,0x01,0x90,0xB4,0x0E,0x8A,0x07,0x1E,0x51,0x53,
- 0xCD,0x10,0x5B,0x59,0x1F,0x43,0xE2,0xF1,0xB4,0,0xCD,0x16,0xB4,0x0F,0xCD,0x10,
- 0xB4,0,0xCD,0x10,0xCD,0x19,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,0x20,0x20,
- 0x20,0x20,0x20,0x53,0x74,0x61,0x72,0x74,0x20,0x79,0x6F,0x75,0x72,0x20,0x63,0x6F,
- 0x6D,0x70,0x75,0x74,0x65,0x72,0x20,0x77,0x69,0x74,0x68,0x0D,0x0A,0x20,0x20,0x20,
- 0x20,0x20,0x61,0x20,0x44,0x4F,0x53,0x20,0x73,0x79,0x73,0x74,0x65,0x6D,0x20,0x64,
- 0x69,0x73,0x6B,0x65,0x74,0x74,0x65,0x2E,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,0x20,0x20,
- 0x20,0x20,0x20,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x0D,0x0A,0x20,0x20,0x20,0x20,
- 0x20,0x20,0x20,0x20,0x20,0x20,0x44,0x72,0x61,0x67,0x6F,0x6E,0x57,0x61,0x72,0x65,
- 0x20,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,0x0D,0x0A,0x20,0x20,0x20,0x20,0x20,
- 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x56,0x65,0x72,0x73,0x69,0x6F,0x6E,0x20,
- 0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20,0x0D,0x0A,0x0D,0x0A,0x20,0x20,0x20,0x20,
- 0x20,0x66,0x72,0x6F,0x6D,0x0D,0x0A,0x20,0x20,0x20,0x20,0x20,0x45,0x64,0x77,0x61,
- 0x72,0x64,0x20,0x56,0x2E,0x20,0x44,0x6F,0x6E,0x67,0x0D,0x0A,0x20,0x20,0x20,0x20,
- 0x20,0x31,0x32,0x32,0x30,0x35,0x20,0x41,0x6C,0x65,0x78,0x61,0x6E,0x64,0x72,0x69,
- 0x61,0x20,0x50,0x6C,0x61,0x63,0x65,0x0D,0x0A,0x20,0x20,0x20,0x20,0x20,0x43,0x68,
- 0x69,0x6E,0x6F,0x2C,0x20,0x43,0x41,0x20,0x39,0x31,0x37,0x31,0x30,0x0D,0x0A,0x0D,
- 0x0A,0x5A,0x49,0x50,0x3A,0x20,0x54,0x68,0x65,0x20,0x55,0x6C,0x74,0x69,0x6D,0x61,
- 0x74,0x65,0x20,0x55,0x74,0x69,0x6C,0x69,0x74,0x79,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,
- 0x0D,0x0A,0x20,0x20,0x20,0x20,0x49,0x6E,0x73,0x65,0x72,0x74,0x20,0x61,0x20,0x44,
- 0x4F,0x53,0x20,0x64,0x69,0x73,0x6B,0x65,0x74,0x74,0x65,0x0D,0x0A,0x20,0x20,0x20,
- 0x20,0x70,0x72,0x65,0x73,0x73,0x20,0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,
- 0x6F,0x20,0x73,0x74,0x61,0x72,0x74,0x20,0x44,0x4F,0x53,0x2E,0x2E,0x2E,0x20,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x55,0xAA
- };
-
- /* ----------------------------------------------------------------- */
- /* setDASD is used to command a 1.2M drive to format for 360K disks */
- /* ----------------------------------------------------------------- */
-
- int setDASD(int drive,char dType) /* set DASD to format 360K floppies */
- {
- union REGS inregs;
- union REGS outregs;
- int i;
- char drive2;
- drive2 = (drive); /* cast operation */
- i = 0;
- while ((i<3) && (!outregs.x.cflag))
- { inregs.h.ah = 0x17;
- inregs.h.al = dType;
- inregs.h.dl = drive2;
- int86(0x13,&inregs,&outregs);
- i++;
- }
- if (outregs.x.cflag) return(-1);
- return(0);
- }
-
- /* -----------------------------------------------------------------
- The following routine inserts a delay of 0.3 seconds between calls
- to biosdisk(), to provide for disk head settling for AT class
- machines. Delay is not needed for standard PC's or XT's. A delay
- might be needed for Turbo PC/XT's, however.
-
- FLOPPY is the Turbo C "direct BIOS" call, with the embedded delay.
- DISKOP calls FLOPPY, but uses DOS logical sector number (0==boot
- sector, etc.). This simplifies the programming for writing the
- boot sector (0), FAT sectors (1-4), and root directory sectors
- (5-12).
-
- DOS logical sector numbers sequences through physical disk sectors
- by first using head 0, track 0, then physical sectors 1 through
- maximum sectors per track; then head 1, track 0, then sectors again;
- then back to head 0, etc.
- ----------------------------------------------------------------- */
-
- int DISKOP(int cmd,int drive,int sect,int nsects,void *buffer,int sect_per_trk)
- {
- return(FLOPPY(cmd,drive,(sect/sect_per_trk) % 2,
- (sect/sect_per_trk) % sect_per_trk,
- (sect % sect_per_trk) + 1,nsects,buffer));
- }
-
- int FLOPPY(int cmd,int drive,int head,int track,int sector,int nsects,
- void *buffer)
- {
- int value;
- char MachineType;
- MachineType = peekb(0xf000,0xfffe);
- value = biosdisk(cmd,drive,head,track,sector,nsects,buffer);
- if (MachineType == 0x0fc) delay(300);
- return(value);
- }
-
- /* ---------------------------------------------------------------------
- The theory in chk_disk is that the first two sectors aren't formatted,
- if the disk is not formatted. Generally, if these sectors aren't
- formatted (or readable), the diskette needs formatting anyway.
- --------------------------------------------------------------------- */
-
- int chk_dsk(int drive,int *quick) /* check if disk already formatted */
- {
- *quick = 0;
- if( (FLOPPY(READ_TRK, drive, 0, 0, 1, 9, buffer) == 0) &&
- (FLOPPY(READ_TRK, drive, 1, 0, 1, 9, buffer) == 0))
- { printf("Disk in %c: already formatted...Reformat? [y/N]",
- drive+'A');
- if (toupper(getch()) != 'Y')
- return(ERR);
- printf("\nQuick reformat (IF diskette has NO bad sectors) [y/N]");
- if (toupper(getch()) == 'Y')
- *quick = 1;
- }
- return(NO_ERR); /* not formatted */
- }
-
- int verify_error(int drive,int sd,int tr,char FAT[])
- {
- int iptr, cluster, topcluster;
- if (FLOPPY(VERIFY_TRK,drive,sd,tr,1,9,buffer))
- { cluster = ((9*(sd+2*tr)) >> 1) - 4;
- topcluster = cluster + 5;
- while (cluster < topcluster)
- { iptr = (3 * cluster) >> 1;
- if ((cluster & 1)==1)
- FAT[iptr] |= 0xff70;
- else FAT[iptr] |= 0x0ff7;
- cluster++;
- }
- return(ERR);
- }
- return(NO_ERR);
- }
-
- int disk_format(int drive,int verify) /* this does the formatting */
- {
- register int loop, tr, sd;
- int iptr, cluster, topcluster, i, s, tries, success, quick;
- char dType, NoOfCyl;
- char DirSector[512], FAT[1024];
- char MachineType;
- union REGS inregs,outregs;
- struct SREGS sregs;
-
- /* initialize file allocation table (FAT) */
- setmem(FAT,1024,0); /* fill fat with all zeroes */
- /* fill in the ID bytes */
- FAT[0] = 0xfd; /* 9 sector DSDD drive */
- FAT[1] = 0xff; /* boilerplate */
- FAT[2] = 0xff;
-
- /* check machine type & DOS version, to handle 1.2meg drives */
- MachineType = peekb(0xf000,0xfffe);
- printf("\nFormatting Drive %c: \n", drive+'A');
- if ((MachineType == 0x0fc) && ((_version & 0x00ff) == 3))
- { /* get drive type */
- tries = 0;
-
- /* call BIOS to determine number of cylinders formattable by drive */
- inregs.h.ah = 8; /* call needed */
- inregs.h.dl = drive;
- int86(0x13,&inregs,&outregs); /* call BIOS */
- NoOfCyl = outregs.h.ch;
-
- /* if NoOfCyl = 79, then it's a 1.2 meg drive; else if 39, then it's a
- 360K drive; anything else is not supported! */
- if (NoOfCyl == 79) /* 1.2 meg drive */
- { inregs.x.ax = drive;
- inregs.h.ah = 0x15;
- int86(0x13,&inregs,&outregs); /* invoke BIOS */
- dType = outregs.h.ah; /* see if 360k supported */
- if ((dType==0) || (dType==3))
- { printf("ERROR: Invalid drive %c (dType=%d)\n",
- drive+'A',dType);
- if (getch()==0) getch();
- return(ERR);
- }
- if (dType==2)
- setDASD(drive,dType); /* set DASD type */
- }
- else if (NoOfCyl != 39) /* not 1.2M or 360K drive! */
- { printf("Drive Type Not Supported: #%d\n",
- NoOfCyl+1);
- return(ERR);
- }
-
- }
-
- /* see if disk already formatted */
- if (chk_dsk(drive,&quick)) return(ERR);
-
- /* use BIOS to format a track & format 40 tracks */
- for(tr = 0; tr < TR_PER_DSK; tr++)
- for(sd = 0; sd < SD_PER_DSK; sd++)
- { for(s = 0; s < SECTORS_PER_TRACK; s++)
- { trk_fmt[tr].side[sd].format_record[s].cyl = tr;
- trk_fmt[tr].side[sd].format_record[s].head = sd;
- trk_fmt[tr].side[sd].format_record[s].rec = s +1;
- trk_fmt[tr].side[sd].format_record[s].num = 2;
- }
- success = tries = 0;
- while (!success && (tries < 3))
- { if (!FLOPPY(FORMAT_TRK, drive, sd, tr, 1, 9,
- &(trk_fmt[tr].side[sd].format_record[0])))
- success = 1;
- else tries++;
- }
- if (success)
- { if (quick) goto WriteBOOT;
- printf("Head %d, Cyl %d(F)\r",sd,tr);
- if (verify)
- { if (verify_error(drive,sd,tr,FAT))
- printf("Head %d, Cyl %d(E)\r",sd,tr);
- else printf("Head %d, Cyl %d(V)\r",sd,tr);
- }
- }
- else
- { printf("Format Error - aborting...\n");
- return(ERR);
- }
- }
-
- WriteBOOT: /* create boot record on the floppy */
- printf("DiskFormat: Writing BOOT record\r");
- DISKOP(WRITE_TRK,drive,0,1,boot_rec,9);
-
- /* create 2 copies of file allocation table (FAT) on the floppy */
- printf("DiskFormat: Writing FAT blocks\r");
- for (i=1; i<3; i++)
- if (DISKOP(WRITE_TRK,drive,2*i-1,2,FAT,9))
- printf("Error writing FAT #%d\n",i);
-
- /* create root directory on the floppy */
- printf("DiskFormat: Writing root directory\r");
- setmem(DirSector,512,0xf6); /* fill with format bytes */
- for (i=0;i<481;i++) /* mark each directory entry as avail */
- if ((i % 32) == 0)
- DirSector[i] = 0;
- for (i=5; i<12; i++) /* 7 sectors */
- DISKOP(WRITE_TRK,drive,i,1,DirSector,9);
-
- /* all done */
- return(NO_ERR);
- }
-
- void DiskFormat(void)
- {
- int drive, verify;
- drive = 2;
- while ((drive!=0)&&(drive!=1))
- { printf("Enter drive to format [A,B]:");
- drive = toupper(getch());
- if (drive==27) return;
- drive -= 'A';
- }
- printf("\rVerify during formatting? [Y/n]: ");
- if (toupper(getch())=='N')
- verify = 0;
- else verify = 1;
- if (disk_format(drive,verify) == 0)
- printf("Format [%c] Complete: \n",drive+'A');
- }
-
- main(void)
- {
- DiskFormat();
- }
-