/* * 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) ; else cnt = low2 + (high2 << 8) ; cnt = (cnt + 1) & 0xffff ; if (chan >=4) /* 16-bit chans transfer words */ cnt += cnt ; return(cnt); }