Floppy driver now supports MSDOS track format. Minor device 1 (/dev/fd?b)
uses MSDOS MFM track encoding. From Ezra Story (ezy@panix.com) with a couple of changes by me.
This commit is contained in:
parent
d4339afe48
commit
c871eb1ec2
|
@ -1,7 +1,8 @@
|
|||
/* $NetBSD: fd.c,v 1.31 1996/04/30 06:09:51 mhitch Exp $ */
|
||||
/* $NetBSD: fd.c,v 1.32 1996/05/04 04:54:00 mhitch Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 Christian E. Hopps
|
||||
* Copyright (c) 1996 Ezra Story
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -15,6 +16,7 @@
|
|||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Christian E. Hopps.
|
||||
* This product includes software developed by Ezra Story.
|
||||
* 4. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
|
@ -57,9 +59,7 @@ enum fdc_bits { FDB_CHANGED = 2, FDB_PROTECT, FDB_CYLZERO, FDB_READY };
|
|||
*/
|
||||
enum fd_parttypes {
|
||||
FDAMIGAPART = 0,
|
||||
#ifdef not_yet
|
||||
FDMSDOSPART,
|
||||
#endif
|
||||
FDMAXPARTS
|
||||
};
|
||||
|
||||
|
@ -71,6 +71,8 @@ enum fd_parttypes {
|
|||
#define FDPART(dev) DISKPART(dev)
|
||||
#define FDMAKEDEV(m, u, p) MAKEDISKDEV((m), (u), (p))
|
||||
|
||||
/* that's nice, but we don't want to always use this as an amiga drive
|
||||
bunghole :-) */
|
||||
#define FDNHEADS (2) /* amiga drives always have 2 heads */
|
||||
#define FDSECSIZE (512) /* amiga drives always have 512 byte sectors */
|
||||
#define FDSECLWORDS (128)
|
||||
|
@ -94,6 +96,28 @@ enum fd_parttypes {
|
|||
#define DMABUFSZ ((DISKLEN_WRITE - 1) * 2) /* largest dma possible */
|
||||
|
||||
#define FDMFMSYNC (0x4489)
|
||||
#define FDMFMID (0x5554)
|
||||
#define FDMFMDATA (0x5545)
|
||||
#define FDMFMGAP1 (0x9254)
|
||||
#define FDMFMGAP2 (0xAAAA)
|
||||
#define FDMFMGAP3 (0x9254)
|
||||
#define CRC16POLY (0x1021) /* (x^16) + x^12 + x^5 + x^0 */
|
||||
|
||||
/*
|
||||
* Msdos-type MFM encode/decode
|
||||
*/
|
||||
static u_char msdecode[128];
|
||||
static u_char msencode[16] =
|
||||
{
|
||||
0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
|
||||
0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
|
||||
};
|
||||
static u_short mscrctab[256];
|
||||
|
||||
/*
|
||||
5554 aaaa aaaa aaa5 2aa4 4452 aa51
|
||||
00 00 03 02 ac 0d
|
||||
*/
|
||||
|
||||
/*
|
||||
* floppy device type
|
||||
|
@ -131,6 +155,7 @@ struct fd_softc {
|
|||
int openpart; /* which partition [ab] == [12] is open */
|
||||
short retries; /* number of times to retry failed io */
|
||||
short retried; /* number of times current io retried */
|
||||
int bytespersec; /* number of bytes per sector */
|
||||
};
|
||||
|
||||
/* fd_softc->flags */
|
||||
|
@ -181,10 +206,16 @@ void fddone __P((struct fd_softc *));
|
|||
void fdfindwork __P((int));
|
||||
void fdminphys __P((struct buf *));
|
||||
void fdcachetoraw __P((struct fd_softc *));
|
||||
void amcachetoraw __P((struct fd_softc *));
|
||||
int amrawtocache __P((struct fd_softc *));
|
||||
u_long *fdfindsync __P((u_long *, u_long *));
|
||||
int fdrawtocache __P((struct fd_softc *));
|
||||
void mscachetoraw __P((struct fd_softc *));
|
||||
int msrawtocache __P((struct fd_softc *));
|
||||
u_long *mfmblkencode __P((u_long *, u_long *, u_long *, int));
|
||||
u_long *mfmblkdecode __P((u_long *, u_long *, u_long *, int));
|
||||
u_short *msblkdecode __P((u_short *, u_char *, int));
|
||||
u_short *msblkencode __P((u_short *, u_char *, int, u_short *));
|
||||
|
||||
struct dkdriver fddkdriver = { fdstrategy };
|
||||
|
||||
|
@ -299,7 +330,8 @@ fdcattach(pdp, dp, auxp)
|
|||
{
|
||||
struct fdcargs args;
|
||||
|
||||
printf(": dmabuf pa 0x%x\n", kvtop(fdc_dmap));
|
||||
printf(": dmabuf pa 0x%x", kvtop(fdc_dmap));
|
||||
printf(": dmabuf ka %p\n", fdc_dmap);
|
||||
args.unit = 0;
|
||||
args.type = fdcgetfdtype(args.unit);
|
||||
|
||||
|
@ -351,6 +383,7 @@ fdattach(pdp, dp, auxp)
|
|||
{
|
||||
struct fdcargs *ap;
|
||||
struct fd_softc *sc;
|
||||
int i;
|
||||
|
||||
ap = auxp;
|
||||
sc = (struct fd_softc *)dp;
|
||||
|
@ -362,6 +395,7 @@ fdattach(pdp, dp, auxp)
|
|||
sc->unitmask = 1 << (3 + ap->unit);
|
||||
sc->retries = FDRETRIES;
|
||||
sc->stepdelay = FDSTEPDELAY;
|
||||
sc->bytespersec = 512;
|
||||
printf(" unit %d: %s %d cyl, %d head, %d sec [%d sec], 512 bytes/sec\n",
|
||||
sc->hwunit, sc->type->desc, sc->type->ncylinders, FDNHEADS,
|
||||
sc->type->amiga_nsectors, sc->type->msdos_nsectors);
|
||||
|
@ -381,6 +415,18 @@ fdattach(pdp, dp, auxp)
|
|||
fdsetpos(sc, 0, 0);
|
||||
fdmotoroff(sc);
|
||||
|
||||
/*
|
||||
* precalc msdos MFM and CRC
|
||||
*/
|
||||
for (i = 0; i < 128; i++)
|
||||
msdecode[i] = 0xff;
|
||||
for (i = 0; i < 16; i++)
|
||||
msdecode[msencode[i]] = i;
|
||||
for (i = 0; i < 256; i++) {
|
||||
mscrctab[i] = (0x1021 * (i & 0xf0)) ^ (0x1021 * (i & 0x0f)) ^
|
||||
(0x1021 * (i >> 4));
|
||||
}
|
||||
|
||||
/*
|
||||
* enable disk related interrupts
|
||||
*/
|
||||
|
@ -463,7 +509,7 @@ done:
|
|||
* if we were not open and we marked us so reverse that.
|
||||
*/
|
||||
if (error && wasopen == 0)
|
||||
sc->openpart = 0;
|
||||
sc->openpart = -1;
|
||||
return(error);
|
||||
}
|
||||
|
||||
|
@ -677,18 +723,18 @@ fdloaddisk(sc)
|
|||
fdsetpos(sc, 0, 0);
|
||||
if (FDTESTC(FDB_CHANGED)) {
|
||||
fdmotoroff(sc);
|
||||
FDDESELECT(sc->unitmask);
|
||||
return(ENXIO);
|
||||
}
|
||||
}
|
||||
FDDESELECT(sc->unitmask);
|
||||
fdmotoroff(sc);
|
||||
sc->type = fdcgetfdtype(sc->hwunit);
|
||||
if (sc->type == NULL)
|
||||
return(ENXIO);
|
||||
#ifdef not_yet
|
||||
if (sc->openpart == FDMSDOSPART)
|
||||
sc->nsectors = sc->type->msdos_nsectors;
|
||||
else
|
||||
#endif
|
||||
sc->nsectors = sc->type->amiga_nsectors;
|
||||
return(0);
|
||||
}
|
||||
|
@ -707,7 +753,8 @@ fdgetdisklabel(sc, dev)
|
|||
struct buf *bp;
|
||||
int error, part;
|
||||
|
||||
if (sc->flags & FDF_HAVELABEL)
|
||||
if (sc->flags & FDF_HAVELABEL &&
|
||||
sc->dkdev.dk_label->d_npartitions == (FDPART(dev) + 1))
|
||||
return(0);
|
||||
#ifdef FDDEBUG
|
||||
printf("fdgetdisklabel()\n");
|
||||
|
@ -1123,6 +1170,7 @@ fdselunit(sc)
|
|||
* process next buf on device queue.
|
||||
* normall sequence of events:
|
||||
* fdstart() -> fddmastart();
|
||||
* fdidxintr();
|
||||
* fdintr() -> fddmadone() -> fddone();
|
||||
* if the track is in the cache then fdstart() will short-circuit
|
||||
* to fddone() else if the track cache is dirty it will flush. If
|
||||
|
@ -1134,6 +1182,7 @@ fdstart(sc)
|
|||
{
|
||||
int trk, error, write;
|
||||
struct buf *bp, *dp;
|
||||
int changed;
|
||||
|
||||
#ifdef FDDEBUG
|
||||
printf("fdstart: unit %d\n", sc->hwunit);
|
||||
|
@ -1166,12 +1215,15 @@ fdstart(sc)
|
|||
* make sure same disk is loaded
|
||||
*/
|
||||
fdselunit(sc);
|
||||
if (FDTESTC(FDB_CHANGED)) {
|
||||
changed = FDTESTC(FDB_CHANGED);
|
||||
FDDESELECT(sc->unitmask);
|
||||
if (changed) {
|
||||
/*
|
||||
* disk missing, invalidate all future io on
|
||||
* this unit until re-open()'ed also invalidate
|
||||
* all current io
|
||||
*/
|
||||
printf("fdstart: disk changed\n");
|
||||
#ifdef FDDEBUG
|
||||
printf(" disk was removed invalidating all io\n");
|
||||
#endif
|
||||
|
@ -1351,7 +1403,20 @@ fddmastart(sc, trk)
|
|||
custom.adkcon = adkmask;
|
||||
}
|
||||
custom.dskpt = (u_char *)kvtop(fdc_dmap);
|
||||
FDDMASTART(ndmaw, write);
|
||||
|
||||
/*
|
||||
* If writing an MSDOS track, activate disk index pulse
|
||||
* interrupt, dma will be started in the intr routine fdidxintr()
|
||||
* Otherwise, start the DMA here.
|
||||
*/
|
||||
if (write && sc->openpart == FDMSDOSPART) {
|
||||
fdc_dmalen = ndmaw;
|
||||
fdc_dmawrite = write;
|
||||
ciab.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
|
||||
} else {
|
||||
FDDMASTART(ndmaw, write);
|
||||
fdc_dmalen = 0;
|
||||
}
|
||||
|
||||
#ifdef FDDEBUG
|
||||
printf(" dma started\n");
|
||||
|
@ -1643,8 +1708,33 @@ fdminphys(bp)
|
|||
* when we go to multiple disk formats, this will call type dependent
|
||||
* functions
|
||||
*/
|
||||
void fdcachetoraw(sc)
|
||||
struct fd_softc *sc;
|
||||
{
|
||||
if (sc->openpart == FDMSDOSPART)
|
||||
mscachetoraw(sc);
|
||||
else
|
||||
amcachetoraw(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode raw MFM from dma into units track cache.
|
||||
* when we go to multiple disk formats, this will call type dependent
|
||||
* functions
|
||||
*/
|
||||
int
|
||||
fdrawtocache(sc)
|
||||
struct fd_softc *sc;
|
||||
{
|
||||
|
||||
if (sc->openpart == FDMSDOSPART)
|
||||
return(msrawtocache(sc));
|
||||
else
|
||||
return(amrawtocache(sc));
|
||||
}
|
||||
|
||||
void
|
||||
fdcachetoraw(sc)
|
||||
amcachetoraw(sc)
|
||||
struct fd_softc *sc;
|
||||
{
|
||||
static u_long mfmnull[4];
|
||||
|
@ -1698,7 +1788,7 @@ fdcachetoraw(sc)
|
|||
*crp &= 0x7fffffff; /* clock bit correction */
|
||||
else if ((*crp & 0x40000000) == 0)
|
||||
*crp |= 0x80000000;
|
||||
}
|
||||
}
|
||||
*rp = 0xaaa80000;
|
||||
if (*(rp - 1) & 0x1)
|
||||
*rp &= 0x7fffffff;
|
||||
|
@ -1720,13 +1810,8 @@ fdfindsync(rp, ep)
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode raw MFM from dma into units track cache.
|
||||
* when we go to multiple disk formats, this will call type dependent
|
||||
* functions
|
||||
*/
|
||||
int
|
||||
fdrawtocache(sc)
|
||||
amrawtocache(sc)
|
||||
struct fd_softc *sc;
|
||||
{
|
||||
u_long mfmnull[4];
|
||||
|
@ -1797,6 +1882,155 @@ again:
|
|||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
mscachetoraw(sc)
|
||||
struct fd_softc *sc;
|
||||
{
|
||||
u_short *rp, *erp, crc;
|
||||
u_char *cp, tb[5];
|
||||
int sec, i;
|
||||
|
||||
rp = (u_short *)fdc_dmap;
|
||||
erp = rp + sc->type->nwritew;
|
||||
cp = sc->cachep;
|
||||
|
||||
/*
|
||||
* initial track filler (828 * GAP1)
|
||||
*/
|
||||
for (i = 0; i < sc->type->gap; i++) {
|
||||
*rp++ = FDMFMGAP1;
|
||||
*rp++ = FDMFMGAP1;
|
||||
}
|
||||
|
||||
for (sec = 0; sec < sc->nsectors; sec++) {
|
||||
|
||||
/*
|
||||
* leading sector gap
|
||||
* (12 * GAP2) + (3 * SYNC)
|
||||
*/
|
||||
for (i = 0; i < 12; i++)
|
||||
*rp++ = FDMFMGAP2;
|
||||
*rp++ = FDMFMSYNC;
|
||||
*rp++ = FDMFMSYNC;
|
||||
*rp++ = FDMFMSYNC;
|
||||
|
||||
/*
|
||||
* sector information
|
||||
* (ID) + track + side + sector + sector size + CRC16
|
||||
*/
|
||||
*rp++ = FDMFMID;
|
||||
tb[0] = sc->cachetrk / FDNHEADS;
|
||||
tb[1] = sc->cachetrk % FDNHEADS;
|
||||
tb[2] = sec + 1;
|
||||
i = sc->bytespersec;
|
||||
tb[3] = i < 256 ? 0 : (i < 512 ? 1 : (i < 1024 ? 2 : 3));
|
||||
rp = msblkencode(rp, tb, 4, &crc);
|
||||
tb[0] = crc >> 8;
|
||||
tb[1] = crc & 0xff;
|
||||
tb[2] = 0x4e; /* GAP1 decoded */
|
||||
rp = msblkencode(rp, tb, 3, 0);
|
||||
|
||||
/*
|
||||
* sector info/data gap
|
||||
* (22 * GAP1) + (12 * GAP2) + (3 * SYNC)
|
||||
*/
|
||||
for (i = 0; i < 21; i++)
|
||||
*rp++ = FDMFMGAP1;
|
||||
for (i = 0; i < 12; i++)
|
||||
*rp++ = FDMFMGAP2;
|
||||
*rp++ = FDMFMSYNC;
|
||||
*rp++ = FDMFMSYNC;
|
||||
*rp++ = FDMFMSYNC;
|
||||
|
||||
/*
|
||||
* sector data
|
||||
* (DATA) + ...data... + CRC16
|
||||
*/
|
||||
*rp++ = FDMFMDATA;
|
||||
rp = msblkencode(rp, cp, sc->bytespersec, &crc);
|
||||
cp += sc->bytespersec;
|
||||
tb[0] = crc >> 8;
|
||||
tb[1] = crc & 0xff;
|
||||
tb[2] = 0x4e; /* GAP3 decoded */
|
||||
rp = msblkencode(rp, tb, 3, 0);
|
||||
|
||||
/*
|
||||
* trailing sector gap
|
||||
* (80 * GAP3)
|
||||
*/
|
||||
for (i = 0; i < 79; i++)
|
||||
*rp++ = FDMFMGAP3;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill rest of track with GAP3
|
||||
*/
|
||||
while (rp != erp)
|
||||
*rp++ = FDMFMGAP3;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
msrawtocache(sc)
|
||||
struct fd_softc *sc;
|
||||
{
|
||||
u_short *rp, *srp, *erp;
|
||||
u_char tb[5], *cp;
|
||||
int ct, sec, retry;
|
||||
|
||||
srp = rp = (u_short *)fdc_dmap;
|
||||
erp = rp + sc->type->nreadw;
|
||||
cp = sc->cachep;
|
||||
|
||||
for (ct = 0; ct < sc->nsectors; ct++) {
|
||||
retry = 1;
|
||||
do {
|
||||
/*
|
||||
* skip leading gap to sync
|
||||
*/
|
||||
if ((rp = (u_short *)fdfindsync((u_long *)rp, (u_long *)erp)) == NULL) {
|
||||
#ifdef DIAGNOSTIC
|
||||
printf("%s: corrupted track (%d) data.\n",
|
||||
sc->sc_dv.dv_xname, sc->cachetrk);
|
||||
#endif
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab sector info
|
||||
*/
|
||||
if (*rp++ != FDMFMID)
|
||||
continue;
|
||||
rp = msblkdecode(rp, tb, 4);
|
||||
#ifdef FDDEBUG
|
||||
printf("sector id: sector %d, track %d, side %d,"
|
||||
"bps %d\n", tb[2], tb[0], tb[1], 128 << tb[3]);
|
||||
#endif
|
||||
if ((tb[0] * FDNHEADS + tb[1]) != sc->cachetrk ||
|
||||
tb[2] > sc->nsectors)
|
||||
continue;
|
||||
|
||||
sec = tb[2];
|
||||
sc->bytespersec = 128 << tb[3];
|
||||
rp += 2; /* skip CRC-16 */
|
||||
|
||||
/*
|
||||
* skip gap and read in data
|
||||
*/
|
||||
if ((rp = (u_short *)fdfindsync((u_long *)rp, (u_long *)erp)) == NULL)
|
||||
return(-1);
|
||||
if (*rp++ != FDMFMDATA)
|
||||
continue;
|
||||
rp = msblkdecode(rp, cp + ((sec-1) * sc->bytespersec),
|
||||
sc->bytespersec);
|
||||
rp += 2; /* skip CRC-16 */
|
||||
|
||||
retry = 0;
|
||||
} while (retry);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* encode len longwords of `dp' data in amiga mfm block format (`rp')
|
||||
* this format specified that the odd bits are at current pos and even
|
||||
|
@ -1901,6 +2135,74 @@ mfmblkdecode(rp, dp, cp, len)
|
|||
return(rp + len);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode len words in standard MFM format to len bytes
|
||||
* of data.
|
||||
*/
|
||||
u_short *
|
||||
msblkdecode(rp, cp, len)
|
||||
u_short *rp;
|
||||
u_char *cp;
|
||||
int len;
|
||||
{
|
||||
while (len--) {
|
||||
*cp++ = msdecode[*rp & 0x7f] |
|
||||
(msdecode[(*rp >> 8) & 0x7f] << 4);
|
||||
rp++;
|
||||
}
|
||||
|
||||
return(rp);
|
||||
}
|
||||
|
||||
/*
|
||||
* encode len bytes of data into len words in standard MFM format.
|
||||
* If a pointer is supplied for crc, calculate the CRC-16 of the data
|
||||
* as well.
|
||||
*/
|
||||
u_short *
|
||||
msblkencode(rp, cp, len, crc)
|
||||
u_short *rp;
|
||||
u_char *cp;
|
||||
int len;
|
||||
u_short *crc;
|
||||
{
|
||||
u_short td;
|
||||
u_short mycrc;
|
||||
|
||||
/* preload crc for header (4 bytes)
|
||||
* or data (anything else)
|
||||
*/
|
||||
mycrc = (len == 4) ? 0xb230 : 0xe295;
|
||||
|
||||
while (len--) {
|
||||
td = (msencode[*cp >> 4] << 8) | msencode[*cp & 0x0f];
|
||||
|
||||
/* Check for zeros in top bit of encode and bottom
|
||||
* bit of previous encode. if so, slap a one in betweem
|
||||
* them.
|
||||
*/
|
||||
if ((td & 0x140) == 0)
|
||||
td |= 0x80;
|
||||
if ((td & 0x4000) == 0 && (rp[-1] & 1) == 0)
|
||||
td |= 0x8000;
|
||||
|
||||
*rp++ = td;
|
||||
|
||||
/*
|
||||
* calc crc if requested
|
||||
*/
|
||||
if (crc)
|
||||
mycrc = (mycrc << 8) ^ mscrctab[*cp ^ (mycrc >> 8)];
|
||||
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (crc)
|
||||
*crc = mycrc;
|
||||
|
||||
return(rp);
|
||||
}
|
||||
|
||||
int
|
||||
fddump(dev, blkno, va, size)
|
||||
dev_t dev;
|
||||
|
|
Loading…
Reference in New Issue