diff options
-rw-r--r-- | sys/amd64/isa/isa.c | 82 | ||||
-rw-r--r-- | sys/i386/isa/isa.c | 82 | ||||
-rw-r--r-- | sys/i386/isa/isa_device.h | 3 |
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 */ |