M pc/devfloppy.c => pc/devfloppy.c +22 -20
@@ 29,15 29,10 @@ enum
Fwrite= 0x47, /* write cmd */
Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */
- DMAmode0= 0xb,
- DMAmode1= 0xc,
- DMAaddr= 0x4,
- DMAtop= 0x81,
- DMAinit= 0xa,
- DMAcount= 0x5,
-
Nfloppy= 4, /* floppies/controller */
+ DMAchan= 2, /* floppy dma channel */
+
/* sector size encodings */
S128= 0,
S256= 1,
@@ 48,6 43,11 @@ enum
Drivemask= 3<<0,
Seekend= 1<<5,
Codemask= (3<<6)|(3<<3),
+
+ /* file types */
+ Qdir= 0,
+ Qdata= 16,
+ Qstruct= 32,
};
/*
@@ 117,7 117,7 @@ struct Controller
int confused;
};
-Controller floppy[1];
+Controller floppy;
/*
* start a floppy drive's motor. set an alarm for 1 second later to
@@ 151,8 151,6 @@ floppystop(Drive *dp)
{
int cmd;
- if(!canqlock(dp))
- return;
cmd = Fintena | Fena | dp->dev;
outb(Fmotor, cmd);
dp->motoron = 0;
@@ 162,14 160,13 @@ floppykproc(Alarm* a)
{
Drive *dp;
- if(waserror())
for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){
- if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5)
+ if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5
+ && canqlock(dp)){
floppystop(dp);
+ qunlock(dp);
+ }
}
-
- alarm(5*1000, floppyalarm, 0);
- cancel(a);
}
int
@@ 341,18 338,23 @@ floppyrecal(Drive *dp)
}
void
-floppyinit(void)
+floppyreset(void)
{
Drive *dp;
for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){
- dp->t = &floppytype[0];
- dp->cyl = -1;
+ dp->dev = dp - floppy.d;
+ dp->t = &floppytype[0]; /* default type */
dp->motoron = 1;
+ dp->cyl = -1;
floppystop(dp);
}
- setvec(22, floppyintr);
- alarm(5*1000, floppyalarm, (void *)0);
+}
+
+void
+floppyinit(void)
+{
+ kproc(floppykproc, 0);
}
void
M pc/headland.c => pc/headland.c +100 -20
@@ 5,9 5,7 @@
#include "fns.h"
/*
- * headland hip set for the safari.
- *
- * serious magic!!!
+ * headland chip set for the safari.
*/
enum
@@ 18,10 16,24 @@ enum
};
/*
- * ports used by the DMA controllers
+ * state of a dma transfer
*/
-typedef struct DMA DMA;
-struct DMA {
+typedef struct DMAxfer DMAxfer;
+struct DMAxfer
+{
+ Page pg; /* page used by dma */
+ void *va; /* virtual address destination/src */
+ long len; /* bytes to be transferred */
+ int isread;
+};
+
+/*
+ * the dma controllers. the first half of this structure specifies
+ * the I/O ports used by the DMA controllers.
+ */
+typedef struct DMAport DMAport;
+struct DMAport
+{
uchar addr[4]; /* current address (4 channels) */
uchar count[4]; /* current count (4 channels) */
uchar page[4]; /* page registers (4 channels) */
@@ 33,6 45,16 @@ struct DMA {
uchar mc; /* master clear */
uchar cmask; /* clear mask register */
uchar wam; /* write all mask register bit */
+
+ Lock;
+};
+
+typdef struct DMA DMA;
+struct DMA
+{
+ DMAport;
+ Lock;
+ DMAxfer x[4];
};
DMA dma[2] = {
@@ 69,25 91,83 @@ exit(void)
}
/*
- * setup a dma transfer. return count actually set up. we DMA up
- * to a page.
+ * setup a dma transfer. if the destination is not in kernel
+ * memory, allocate a page for the transfer.
+ *
+ * we assume BIOS has set up the command register before we
+ * are booted.
*/
long
-dmasetup(int d, int chan, Page *pg, long len, int isread)
+dmasetup(int chan, void *va, long len, int isread)
{
DMA *dp;
- ulong addr;
+ DMAxfer *xp;
+ ulong pa;
+ uchar mode;
+
+ dp = &dma[(chan>>2)&1];
+ chan &= 3;
+ xp = &dp->x[chan];
- dp = &dma[d];
- addr = (ulong)a;
- addr &= ~KZERO;
+ /*
+ * if this isn't kernel memory, we can't count on it being
+ * there during the DMA. Allocate a page for the DMA.
+ */
+ if(isphys(va)){
+ pa = va & ~KZERO;
+ } else {
+ xp->pg = newpage(1, 0, 0);
+ if(len > BY2PG)
+ len = BY2PG;
+ if(!isread)
+ memmove(KZERO|xp->pg->pa, a, len);
+ xp->va = va;
+ xp->len = len;
+ xp->isread = isread;
+ pa = xp->pg->pa;
+ }
- outb(dp->cbp, isread ? 0x46 : 0x4a);
- outb(dp->mode, isread ? 0x46 : 0x4a);
- outb(dp->addr, addr);
- outb(dp->addr, addr>>8);
- outb(dp->page, addr>>16);
- outb(dp->count, len-1);
+ /*
+ * this setup must be atomic
+ */
+ lock(dp);
+ outb(dp->cbp, 0); /* set count & address to their first byte */
+ mode = (isread ? 0x44 : 0x48) | chan;
+ outb(dp->mode, mode); /* single mode dma (give CPU a chance at mem) */
+ outb(dp->addr, pa); /* set address */
+ outb(dp->addr, pa>>8);
+ outb(dp->page, pa>>16);
+ outb(dp->count, len-1); /* set count */
outb(dp->count, (len-1)>>8);
- outb(dp->sbm, 2);
+ outb(dp->sbm, chan); /* enable the channel */
+ unlock(dp);
+
+ return n;
+}
+
+/*
+ * this must be called after a dma has been completed.
+ *
+ * if a page has been allocated for the dma,
+ * copy the data into the actual destination
+ * and free the page.
+ */
+void
+dmaend(int chan)
+{
+ DMA *dp;
+ DMAxfer *xp;
+ ulong addr;
+ uchar mode;
+
+ dp = &dma[(chan>>2)&1];
+ chan &= 3;
+ outb(dp->sbm, 4|chan); /* disable the channel */
+ xp = &dp->x[chan];
+ if(xp->pg == 0)
+ return;
+
+ memmove(a, KZERO|xp->pg->pa, xp->len);
+ putpage(xp->pg);
+ xp->pg = 0;
}