summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/isa/isa.c82
-rw-r--r--sys/i386/isa/isa.c82
-rw-r--r--sys/i386/isa/isa_device.h3
3 files changed, 164 insertions, 3 deletions
diff --git a/sys/amd64/isa/isa.c b/sys/amd64/isa/isa.c
index 0206662..c51b59b 100644
--- a/sys/amd64/isa/isa.c
+++ b/sys/amd64/isa/isa.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
- * $Id: isa.c,v 1.94 1997/07/09 17:58:16 ache Exp $
+ * $Id: isa.c,v 1.95 1997/07/20 14:10:03 bde Exp $
*/
/*
@@ -870,6 +870,86 @@ isa_dmarangecheck(caddr_t va, u_int length, int chan) {
}
/*
+ * Query the progress of a transfer on a DMA channel.
+ *
+ * To avoid having to interrupt a transfer in progress, we sample
+ * each of the high and low databytes twice, and apply the following
+ * logic to determine the correct count.
+ *
+ * Reads are performed with interrupts disabled, thus it is to be
+ * expected that the time between reads is very small. At most
+ * one rollover in the low count byte can be expected within the
+ * four reads that are performed.
+ *
+ * There are three gaps in which a rollover can occur :
+ *
+ * - read low1
+ * gap1
+ * - read high1
+ * gap2
+ * - read low2
+ * gap3
+ * - read high2
+ *
+ * If a rollover occurs in gap1 or gap2, the low2 value will be
+ * greater than the low1 value. In this case, low2 and high2 are a
+ * corresponding pair.
+ *
+ * In any other case, low1 and high1 can be considered to be correct.
+ *
+ * The function returns the number of bytes remaining in the transfer,
+ * or -1 if the channel requested is not active.
+ *
+ */
+int
+isa_dmastatus(int chan)
+{
+ u_long cnt = 0;
+ int ffport, waport, s;
+ u_long low, high, low2, high2;
+
+ /* channel active? */
+ if (dma_inuse & (1 << chan) == 0) {
+ printf("isa_dmastatus: channel %d not active\n", chan);
+ return(-1);
+ }
+
+ /* still busy? */
+ if (dma_busy & (1 << chan) == 0) {
+ return(0);
+ }
+
+ if (chan < 4) { /* low DMA controller */
+ ffport = DMA1_FFC;
+ waport = DMA1_CHN(chan) + 1;
+ } else { /* high DMA controller */
+ ffport = DMA2_FFC;
+ waport = DMA2_CHN(chan - 4) + 2;
+ }
+
+ s = splhigh(); /* no interrupts Mr Jones! */
+ outb(ffport, 0); /* clear register LSB flipflop */
+ low = inb(waport);
+ high = inb(waport);
+ outb(ffport, 0); /* clear again (paranoia?) */
+ low2 = inb(waport);
+ high2 = inb(waport);
+ splx(s);
+
+ /* now decide if a wrap has tried to skew our results */
+ if (low >= low2) {
+ cnt = low + (high << 8) + 1;
+ } else {
+ cnt = low2 + (high2 << 8) + 1;
+ }
+ cnt = (cnt + 1) & 0xffff;
+
+ if (chan >= 4) /* high channels move words */
+ cnt *= 2;
+ return(cnt);
+}
+
+/*
* Find the highest priority enabled display device. Since we can't
* distinguish display devices from ttys, depend on display devices
* being sensitive and before sensitive non-display devices (if any)
diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c
index 0206662..c51b59b 100644
--- a/sys/i386/isa/isa.c
+++ b/sys/i386/isa/isa.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa.c 7.2 (Berkeley) 5/13/91
- * $Id: isa.c,v 1.94 1997/07/09 17:58:16 ache Exp $
+ * $Id: isa.c,v 1.95 1997/07/20 14:10:03 bde Exp $
*/
/*
@@ -870,6 +870,86 @@ isa_dmarangecheck(caddr_t va, u_int length, int chan) {
}
/*
+ * Query the progress of a transfer on a DMA channel.
+ *
+ * To avoid having to interrupt a transfer in progress, we sample
+ * each of the high and low databytes twice, and apply the following
+ * logic to determine the correct count.
+ *
+ * Reads are performed with interrupts disabled, thus it is to be
+ * expected that the time between reads is very small. At most
+ * one rollover in the low count byte can be expected within the
+ * four reads that are performed.
+ *
+ * There are three gaps in which a rollover can occur :
+ *
+ * - read low1
+ * gap1
+ * - read high1
+ * gap2
+ * - read low2
+ * gap3
+ * - read high2
+ *
+ * If a rollover occurs in gap1 or gap2, the low2 value will be
+ * greater than the low1 value. In this case, low2 and high2 are a
+ * corresponding pair.
+ *
+ * In any other case, low1 and high1 can be considered to be correct.
+ *
+ * The function returns the number of bytes remaining in the transfer,
+ * or -1 if the channel requested is not active.
+ *
+ */
+int
+isa_dmastatus(int chan)
+{
+ u_long cnt = 0;
+ int ffport, waport, s;
+ u_long low, high, low2, high2;
+
+ /* channel active? */
+ if (dma_inuse & (1 << chan) == 0) {
+ printf("isa_dmastatus: channel %d not active\n", chan);
+ return(-1);
+ }
+
+ /* still busy? */
+ if (dma_busy & (1 << chan) == 0) {
+ return(0);
+ }
+
+ if (chan < 4) { /* low DMA controller */
+ ffport = DMA1_FFC;
+ waport = DMA1_CHN(chan) + 1;
+ } else { /* high DMA controller */
+ ffport = DMA2_FFC;
+ waport = DMA2_CHN(chan - 4) + 2;
+ }
+
+ s = splhigh(); /* no interrupts Mr Jones! */
+ outb(ffport, 0); /* clear register LSB flipflop */
+ low = inb(waport);
+ high = inb(waport);
+ outb(ffport, 0); /* clear again (paranoia?) */
+ low2 = inb(waport);
+ high2 = inb(waport);
+ splx(s);
+
+ /* now decide if a wrap has tried to skew our results */
+ if (low >= low2) {
+ cnt = low + (high << 8) + 1;
+ } else {
+ cnt = low2 + (high2 << 8) + 1;
+ }
+ cnt = (cnt + 1) & 0xffff;
+
+ if (chan >= 4) /* high channels move words */
+ cnt *= 2;
+ return(cnt);
+}
+
+/*
* Find the highest priority enabled display device. Since we can't
* distinguish display devices from ttys, depend on display devices
* being sensitive and before sensitive non-display devices (if any)
diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h
index 726a068..a0557fd 100644
--- a/sys/i386/isa/isa_device.h
+++ b/sys/i386/isa/isa_device.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91
- * $Id: isa_device.h,v 1.42 1997/06/02 08:19:05 dfr Exp $
+ * $Id: isa_device.h,v 1.43 1997/07/20 12:34:15 bde Exp $
*/
#ifndef _I386_ISA_ISA_DEVICE_H_
@@ -117,6 +117,7 @@ void isa_dmainit __P((int chan, u_int bouncebufsize));
void isa_dmastart __P((int flags, caddr_t addr, u_int nbytes, int chan));
int isa_dma_acquire __P((int chan));
void isa_dma_release __P((int chan));
+void isa_dmastatus __P((int chan));
void reconfig_isadev __P((struct isa_device *isdp, u_int *mp));
#endif /* KERNEL */
OpenPOWER on IntegriCloud