/* Format a floppy disk (880k drive). * Author: Mark R. Rinfret * Date: 06/28/87 * Description: * This set of routines may be incorporated into a program which * has need of formatting a floppy disk. I wrote it to support my * hard disk backup utility. * * History: (most recent change first) * * 08/26/87 -MRR- Modified FormatDisk to delay 5 seconds after * uninhibiting the drive. This should give enough time * for the validator to do its thing and prevent the * "Insert disk..." requester from rearing its ugly head * if the application attempts to access the disk as * soon as we return. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct IOExtTD *CreateExtIO(); static int CkIOErr(); /* #define DEBUG */ #define MAX_NAME 30L #define TD_WRITE CMD_WRITE #define TRACKSIZE NUMSECS * TD_SECTOR /* Format a floppy disk - hardwired for the 3.5" 880k floppy drives. * Called with: * drivename: device name (DF0, etc.) * name: new volume name * Returns: * Zero on success, 1 on failure * Note: * This routine does not currently perform a verification, as * recommended by the RKM. Perhaps later... * I also discovered that there's some erroneous crap in * "The Amiga Programmer's Workbook, Vol. II", by * Eugene P. Mortimore. On page 339, he states that only 512 * bytes of track data are required for formatting. The RKM * correctly states that a "track's worth of data" is required. * It took some playing with DiskEd to discover this error. */ int FormatDisk(drivename,name) char *drivename; char *name; { long checksum; char *dos_id = "DOS"; long dosword = 0; SHORT error; struct MsgPort *diskport = NULL; struct IOExtTD *diskreq = NULL; ULONG diskchangecount; struct Process *myprocess; struct Window *mywindow; USHORT status = 0, i, retry, track; int unit; char *volname; char *diskbuffer; ULONG *diskblock; /* alias for diskbuffer, ULONG type */ if (strlen(name) >= MAX_NAME) { #ifdef DEBUG printf("Disk name is too long!\n"); #endif status = ERROR_INVALID_COMPONENT_NAME; goto cleanup; } if ((unit = (drivename[2]-'0')) < 0 || unit >= NUMUNITS) { #ifdef DEBUG printf("FormatDisk: invalid drive specification!\n"); #endif status = ERROR_INVALID_COMPONENT_NAME; goto cleanup; } if (!(diskbuffer = AllocMem((long) TRACKSIZE, MEMF_PUBLIC | MEMF_CHIP))) { status = ERROR_NO_FREE_STORE; goto cleanup; } /* Store DOS "magic word" in disk block to be written during * formatting. */ diskblock = (ULONG *) diskbuffer;/* we'll need this later */ for (i = 0; i < 3; ++i) dosword = (dosword << 8) | dos_id[i]; dosword = dosword << 8; #ifdef DEBUG printf("dosword is %lx\n",dosword); #endif for (i = 0; i < TRACKSIZE / 4; ++i) diskblock[i] = (dosword | (long) (i & 0xff)); if ((diskport = CreatePort(0L, 0L)) == NULL) { #ifdef DEBUG printf("FormatDisk can't create port!\n"); #endif status = 1; /* is there a better error code? */ goto cleanup; } if (!(diskreq = (struct IOExtTD *) CreateExtIO(diskport, (long) sizeof(struct IOExtTD)))) { status = 1; goto cleanup; } if (status = OpenDevice(TD_NAME, (long) unit, diskreq, 0L)) { #ifdef DEBUG printf("FormatDisk: OpenDevice error: %d\n",error); #endif goto cleanup; } if (status = Inhibit(drivename, 1)) { #ifdef DEBUG printf("FormatDisk: unable to inhibit drive!\n"); #endif goto cleanup; } /* Get the current disk change count. This allows the trackdisk * driver to detect unwanted disk changes later on. */ diskreq->iotd_Req.io_Command = TD_CHANGENUM; DoIO(diskreq); /* Save a copy of the disk change count. */ diskchangecount = diskreq->iotd_Req.io_Actual; #ifdef DEBUG printf("Current disk change count is %ld\n", diskchangecount); #endif /* Format the disk, one track at a time. */ for (track = 0; track < NUMTRACKS; ++track) { diskreq->iotd_Req.io_Command = TD_FORMAT; diskreq->iotd_Req.io_Flags = 0; diskreq->iotd_Req.io_Data = (APTR) diskbuffer; diskreq->iotd_Count = diskchangecount; diskreq->iotd_Req.io_Length = NUMSECS * TD_SECTOR; diskreq->iotd_Req.io_Offset = track * NUMSECS * TD_SECTOR; DoIO(diskreq); if (status = CkIOErr(diskreq,"Formatting error")) { #ifdef DEBUG printf(" Track: %d\n",track); #endif goto cleanup; } } /* Now comes some real KLUDGING. Fill in the root block and the * first hash block. The information for this was gathered from * the "AmigaDos Technical Reference Manual" and some sleuthing * with DiskEd. */ for (i = 0; i < 128; ++i) diskblock[i] = 0; diskblock[0] = 2; /* T.SHORT (type) */ diskblock[3] = 128 - 56; /* hashtable size */ diskblock[78] = 0xffffffff; /* BMFLAG */ diskblock[79] = 881; /* first bitmap block */ DateStamp(&diskblock[105]); /* volume last altered date/time */ DateStamp(&diskblock[121]); /* volume creation date/time */ volname = (char *) &diskblock[108]; /* convert input name to BSTR */ *volname = strlen(name); for (i = 0; i < *volname; ++i) *(volname + 1 + i) = *(name + i); diskblock[127] = 1; /* ST.ROOT (secondary type) */ checksum = 0; for (i = 0; i < 128; ++i) checksum += diskblock[i]; diskblock[5] = - checksum; /* Write the root block out to the disk. */ diskreq->iotd_Req.io_Command = TD_WRITE; diskreq->iotd_Req.io_Length = TD_SECTOR; diskreq->iotd_Req.io_Offset = TD_SECTOR * 880L; DoIO(diskreq); if (status = CkIOErr(diskreq, "Error writing root block")) { goto cleanup; } /* Write the first bitmap block. */ for (i = 0; i < 56; ++i) diskblock[i] = 0xffffffff; for (i = 56; i < 128; ++i) diskblock[i] = 0; diskblock[0] = 0xc000c037; /* hint: x37 = 55 (last word of map?) */ diskblock[28] = 0xffff3fff; /* blocks 880, 881 used */ diskblock[55] = 0x3fffffff; /* blocks 1760, 1761 used? */ diskreq->iotd_Req.io_Length = TD_SECTOR; diskreq->iotd_Req.io_Offset = 881L * TD_SECTOR; DoIO(diskreq); /* write out the bitmap */ if (status = CkIOErr(diskreq, "Error writing bitmap")) { goto cleanup; } diskreq->iotd_Req.io_Command = ETD_UPDATE; diskreq->iotd_Req.io_Flags = 0; DoIO(diskreq); /* Turn the disk motor off. */ diskreq->iotd_Req.io_Command = TD_MOTOR; diskreq->iotd_Req.io_Length = 0; DoIO(diskreq); Inhibit(drivename, 0); /* enable disk validator */ Delay(3L * TICKS_PER_SECOND); /* Give it a chance */ cleanup: CloseDevice(diskreq); if (diskbuffer) FreeMem(diskbuffer, (long) TRACKSIZE); if (diskreq) DeleteExtIO(diskreq, (long) sizeof(*diskreq)); if (diskport) DeletePort(diskport); return status; } /* Check the disk request block for an error code. If an error * occurred, print the argument string. * Called with: * req: pointer to I/O request structure * msg: error message string * Returns: * error code from request structure */ static int CkIOErr(req, msg) struct IOStdReq *req; char *msg; { register int code; if (code = req->io_Error) { #ifdef DEBUG printf("%s, code: %d\n",msg,code); #endif } return code; } #ifdef DEBUG main(argc, argv) int argc; char *argv[]; { char *diskname; char *volname; int unit; if (argc < 3) volname = "GoodJob!"; else volname = argv[2]; if (argc < 2) diskname = "DF1:"; else { diskname = argv[1]; if (strlen(diskname) != 4 || (strncmp(diskname,"df",2) && strncmp(diskname,"DF",2))) { bad_drive: printf("Drive name may only be df0: through df3:!\n"); exit(1); } if ((unit = (diskname[2] - '0')) < 0 || unit > 3) goto bad_drive; } printf("Insert disk in %s, then hit return\n",diskname); while (getchar() != '\n'); if (FormatDisk(diskname,volname)) printf("FormatDisk failed\n"); else { printf("FormatDisk succeeded\n"); } } #endif