FreeBSD/sys/x86/isa/isa_dma.c
/*
 * 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.
 *
 */
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 .



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.
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 . 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 .
static int
isa_dmastatus_locked(int chan)
{
	u_long	cnt = 0;
	int	ffport, waport;
	u_long	low1, high1, low2, high2;
	mtx_assert(&isa_dma_lock, MA_OWNED);
	if ((dma_inuse & (1 << chan)) == 0) {
		printf("isa_dmastatus: channel %d not active\n", chan);
		return(-1);
	}
	if (((dma_busy & (1 << chan)) == 0) &&
	    (dma_auto_mode & (1 << chan)) == 0 ) {
	    printf("chan %d not busy\n", chan);
	    return -2 ;
	}	
	if (chan < 4) {			
		ffport = DMA1_FFC;
		waport = DMA1_CHN(chan) + 1;
	} else {			
		ffport = DMA2_FFC;
		waport = DMA2_CHN(chan - 4) + 2;
	}
	disable_intr();			
	outb(ffport, 0);		
	low1 = inb(waport);
	high1 = inb(waport);
	outb(ffport, 0);		
	low2 = inb(waport);
	high2 = inb(waport);
	enable_intr();			
	if (low1 >= low2) {
		cnt = (low1 + (high1 << 8) + 1) & 0xffff;
	} else {
		cnt = (low2 + (high2 << 8) + 1) & 0xffff;
	}
	if (chan >= 4)			
		cnt *= 2;
	return(cnt);
}
static int isa_dmastatus_locked ( int chan ) { u_long cnt = 0 ; int ffport , waport ; u_long low1 , high1 , low2 , high2 ; mtx_assert ( & isa_dma_lock , MA_OWNED ) ; if ( ( dma_inuse & ( 1 << chan ) ) == 0 ) { printf ( " \n " , chan ) ; return ( -1 ) ; } if ( ( ( dma_busy & ( 1 << chan ) ) == 0 ) && ( dma_auto_mode & ( 1 << chan ) ) == 0 ) { printf ( " \n " , chan ) ; return -2 ; } if ( chan < 4 ) { ffport = DMA1_FFC ; waport = DMA1_CHN ( chan ) + 1 ; } else { ffport = DMA2_FFC ; waport = DMA2_CHN ( chan - 4 ) + 2 ; } disable_intr ( ) ; outb ( ffport , 0 ) ; low1 = inb ( waport ) ; high1 = inb ( waport ) ; outb ( ffport , 0 ) ; low2 = inb ( waport ) ; high2 = inb ( waport ) ; enable_intr ( ) ; if ( low1 >= low2 ) { cnt = ( low1 + ( high1 << 8 ) + 1 ) & 0xffff ; } else { cnt = ( low2 + ( high2 << 8 ) + 1 ) & 0xffff ; } if ( chan >= 4 ) cnt *= 2 ; return ( cnt ) ; }
Query the progress of a transfer on a DMA channel.
Query the progress of a transfer on a DMA channel .
/* channel active? */ /* channel busy? */ /* low DMA controller */ /* high DMA controller */ /* no interrupts Mr Jones! */ /* clear register LSB flipflop */ /* clear again */ /* enable interrupts again */ /* 
	 * Now decide if a wrap has tried to skew our results.
	 * Note that after TC, the count will read 0xffff, while we want 
	 * to return zero, so we add and then mask to compensate.
	 */ /* high channels move words */