/* * fc - floppy copy for Disk Jockey DMA * * Len Edmondson * Morrow Designs * 1982 * */ # define STATLENGTH 6 # define DOIT 0 # define GETC 1 # define PUTC 2 # define TIME 40000 # define TIMEOUT 4 # define READ 0 # define WRITE 1 # define BANK 0 # define COMMAND 0x50 # define OKSTAT 0x40 # define NOSTAT 0 # define READS 0x20 # define STATUS 0x22 # define SETDMA 0x23 # define HALT 0x25 # define TRACK2 2 # define SIDE0S1 1 # define VERSO 0200 # define S128 0 # define S256 1 # define S512 2 # define S1024 3 # define SIDE2 0x04 # define START 0xEF # define MAXSEC 26 # define MAXDATA 8192 # define YES 1 # define NO 0 # define FIVE 4 # define TREAD 0x29 # define TWRITE 0x2A struct status { unsigned char command, device, dchar, slength, dstat, retstat; }; unsigned char from = 0, to = 0, errno = 0, sectab [MAXSEC] = {0}; unsigned bps = 0, bpt = 0, spt = 0, nsides = 0, ncyl = 0; int (*x) () = 0x38; cpybuf (a, b, c) register char *a, *b; register c; { for (; c--; *a++ = *b++) ; } tio (op, cyl, side, drive, addr) { register char *p; unsigned char *haltstat, *iostat, i; long t; p = COMMAND; *p++ = SETDMA; *p++ = addr; *p++ = (unsigned) addr >> 8; *p++ = BANK; *p++ = (op == READ) ? TREAD : TWRITE; *p++ = cyl; *p++ = side ? VERSO : 0; *p++ = drive; *p++ = sectab; *p++ = (unsigned) sectab >> 8; *p++ = BANK; *(iostat = p++) = NOSTAT; /* status will be returned here */ *p++ = HALT; *(haltstat = p++) = NOSTAT; fill (sectab, spt, DOIT); out (START, 0); for (t = TIME; t && *haltstat == NOSTAT; t--); if (!t) { errno = TIMEOUT; return NO; } if (*iostat != OKSTAT) { errno = *iostat; return NO; } if (*haltstat != OKSTAT) { errno = *haltstat; return NO; } for (i = 0; i < spt; i++) { if (sectab[i] != OKSTAT) { errno = sectab[i]; return NO; } } return YES; } fill (a, b, c) register char *a; register b, c; { while (b) *a++ = c, b--; } _main () { intro (); for (;;) if (gather ()) if (statem ()) if (copy ()) verify (); } req (a) { char c; puts (a); c = getc (); if (c == 3) { puts ("Returning to CP/M\n"); exit (); } return c; } exit () { int (*a) (); a = 0; (*a) (); } intro () { int i; for (i = 0; i < 12; i++) puts ("\n"); puts ( " Floppy Copy\n" ); puts ( " (being a fast floppy diskette copier using the DJDMA controller)\n" ); puts ( " L.E. - February 1982\n" ); puts ( " Morrow Designs Inc.\n" ); for (i = 0; i < 10; i++) puts ("\n"); } gather () { for (;;) { from = req ("\n\nDrive to copy FROM (0-7) ? "); if (octal (from)) { puts ("\n\n\t\tCopying from Floppy drive "), putc (from), puts ("\n\n"); from -= '0'; break; } } for (;;) { to = req ("\n\nDrive to copy TO (0-7) ? "); if (octal (to)) { puts ("\n\n\t\tCopying to Floppy drive "), putc (to), puts ("\n\n"); to -= '0'; break; } } if (from == to) { puts ("\tNothing to do, all done\n"); return NO; } req ("\n\nInsert diskettes, close drive doors, press RETURN:"); return YES; } octal (a) unsigned char a; { return '0' <= a && a <= '7'; } tohex (a) unsigned char a; { putnib (a >> 4); putnib (a); } putnib (a) { a &= 15; if (a < 10) a += '0'; else a += 'a'-10; putc (a); } putc (a) register char a; { cpm (PUTC, a); } puts (a) register char *a; { for (; *a; a++) { if (*a == '\r') continue; if (*a == '\n') putc ('\r'); putc (*a); } } getc () { return cpm (GETC); } copy () { char data [MAXDATA]; static unsigned cyl, side; for (cyl = 2; cyl < ncyl; cyl++) { for (side = 0; side < nsides; side++) { if (!tio (READ, cyl, side, from, data)) { ferror (from); return NO; } if (!tio (WRITE, cyl, side, to, data)) { ferror (to); return NO; } } } return YES; } verify () { char data [MAXDATA], check [MAXDATA]; static unsigned cyl, side; for (cyl = 2; cyl < ncyl; cyl++) { for (side = 0; side < nsides; side++) { if (!tio (READ, cyl, side, from , data)) { ferror (from); return NO; } if (!tio (READ, cyl, side, to, check)) { ferror (to); return NO; } if (!cmpbuf (data, check, bpt)) { puts ("Verify error - copy failed\n"); return NO; } } } return YES; } statem () { char five, slength; static struct status fromstat, tostat; if (!stat (from, &fromstat)) { ferror (from); return NO; } if (!stat (to, &tostat)) { ferror (to); return NO; } if (fromstat.slength != tostat.slength) { puts ("Different sector sizes - no copy\n"); return NO; } if ((fromstat.dstat & SIDE2) != (tostat.dstat & SIDE2)) { puts ("Different number of sides - no copy\n"); return NO; } if ((fromstat.dchar & FIVE) != (tostat.dchar & FIVE)) { puts ("Different diskette sizes - no copy\n"); return NO; } five = fromstat.dchar & FIVE; slength = fromstat.slength; nsides = (fromstat.dstat & SIDE2) ? 2 : 1; ncyl = 77; if (five) { ncyl = 80; nsides = 2; spt = 10; bps = 512; } else if (slength == S128) spt = 26, bps = 128; else if (slength == S256) spt = 26, bps = 256; else if (slength == S512) spt = 15, bps = 512; else if (slength == S1024) spt = 8, bps = 1024; else { puts ("Unknown sector size\n"); return NO; } bpt = spt * bps; /* puts ("\nslength "); * tohex (slength); * puts ("\nspt "); * tohex (spt); * puts ("\nfromstat.command "); * tohex (fromstat.command); * puts ("\nfromstat.device "); * tohex (fromstat.device); * puts ("\nfromstat.dchar "); * tohex (fromstat.dchar); * puts ("\nfromstat.slength "); * tohex (fromstat.slength); * puts ("\nfromstat.dstat "); * tohex (fromstat.dstat); * puts ("\nfromstat.retstat "); * tohex (fromstat.retstat); * puts ("\n"); */ return YES; } stat (a, b) unsigned a; struct status *b; { static char *statcom, *readstat, *retstat, *haltstat, *p; char tempb [MAXDATA]; long t; p = COMMAND; *p++ = SETDMA; *p++ = tempb; *p++ = (unsigned) tempb >> 8; *p++ = BANK; *p++ = READS; *p++ = TRACK2; *p++ = SIDE0S1; *p++ = a; *(readstat = p++) = NOSTAT; *(statcom = p++) = STATUS; *p++ = a; *p++ = NOSTAT; *p++ = NOSTAT; *p++ = NOSTAT; *(retstat = p++) = NOSTAT; *p++ = HALT; *(haltstat = p++) = NOSTAT; out (START, 0); for (t = TIME; *haltstat == NOSTAT && t; t--); if (!t) { errno = TIMEOUT; return NO; } if (*readstat != OKSTAT) { errno = *readstat; return NO; } if (*retstat != OKSTAT) { errno = *retstat; return NO; } if (*haltstat != OKSTAT) { errno = *haltstat; return NO; } cpybuf (b, statcom, STATLENGTH); return YES; } cmpbuf (a, b, c) register char *a, *b; register unsigned c; { while (c--) if (*a++ != *b++) return NO; return YES; } ferror (a) { puts ("\n\nDrive "), putc (a + '0'), puts (": "); switch (errno) { case TIMEOUT: puts ("Timeout"); break; case 0x80: puts ("Improper command code"); break; case 0x81: puts ("Improper disk drive value"); break; case 0x82: puts ("Disk drive not ready"); break; case 0x83: puts ("Improper track value"); break; case 0x84: puts ("Unreadable media"); break; case 0x85: puts ("Improper sector header - No sync byte(s)"); break; case 0x86: puts ("CRC error in sector header scan"); break; case 0x87: puts ("Seek error"); break; case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: puts ("Compare error in sector header scan"); break; case 0x8E: puts ("CRC error in data field"); break; case 0x8F: puts ("Improper sector value"); break; case 0x90: puts ("Media write protected"); break; case 0x91: puts ("Lost data - DMA channel did not respond"); break; case 0x92: puts ("Lost command - channel did not respond"); break; default: puts ("Unknown error, returned code was "); tohex (errno); } puts ("\n"); }