/*************************************************************************** * NAME: SAMPLE.C ** COPYRIGHT: ** "Copyright (c) 1992, by FORTE ** ** "This software is furnished under a license and may be used, ** copied, or disclosed only in accordance with the terms of such ** license and with the inclusion of the above copyright notice. ** This software or any other copies thereof may not be provided or ** otherwise made available to any other person. No title to and ** ownership of the software is hereby transfered." **************************************************************************** * CREATION DATE: 11/18/92 *--------------------------------------------------------------------------* * VERSION DATE NAME DESCRIPTION *> 1.0 11/18/92 Original ***************************************************************************/ #include #include #include #include "forte.h" #include "gf1proto.h" #include "osproto.h" #include "gf1hware.h" #include "gf1os.h" #include "ultraerr.h" #include "dma.h" /* Hardware defs for PC's dma controllers */ extern DMA_ENTRY _gf1_dma[]; /* Structure that holds data on PC's dma chan */ extern ULTRA_DATA _gf1_data; int UltraRecordDmaBusy(void) { return(_gf1_dma[_gf1_data.adc_dma_chan-1].flags & DMA_PENDING); } void UltraWaitRecordDma(void) { _gf1_data.flags &= ~ADC_DMA_NOWAIT; ENTER_CRITICAL_ON; while (_gf1_data.flags & ADC_DMA_BUSY) /* wait for irq to clear this */ { } LEAVE_CRITICAL_ON; } void UltraSetRecordFrequency(unsigned long rate) { unsigned char adsr; /* First calculate as if its for a record */ /* Use the formula: rate = CLOCK_RATE / (16*(ADRS+2)) */ adsr = ((CLOCK_RATE>>4)/rate)-2; ENTER_CRITICAL; outp(_gf1_data.reg_select,SET_SAMPLE_RATE); outp(_gf1_data.data_hi,(unsigned char)adsr); LEAVE_CRITICAL; } int UltraPrimeRecord(void far *pc_ptr,unsigned int size,int repeat) { int mode; int val; if (repeat) mode = INDEF_READ; else mode = READ_DMA; /* Make sure the channel is not busy (recording or playback ... )*/ val = PrimeDma(pc_ptr,mode,size,_gf1_data.adc_dma_chan); return(val); } int UltraGoRecord(unsigned char control) { DMA_ENTRY *tdma; tdma = &_gf1_dma[_gf1_data.adc_dma_chan-1]; /* point to this dma data */ /* Set flag that irq handler clears when the xfer is complete */ _gf1_data.flags |= ADC_DMA_BUSY; /* Now tell GF1 to start xfer ... */ tdma->cur_control = control; UltraStartRecordDma(control); return(ULTRA_OK); } int UltraRecordData(void far *pc_ptr,unsigned char control,unsigned int size,int wait,int repeat) { int ret; ret=UltraPrimeRecord(pc_ptr,size,repeat); if (ret != ULTRA_OK) return(ret); UltraGoRecord(control); /* if required, wait till dma is done ... */ if (wait) UltraWaitRecordDma(); else _gf1_data.flags |= ADC_DMA_NOWAIT; return(ULTRA_OK); } #ifdef NEVER // This code will hang if there is a memory manager that virtualizes // the dma controller. It takes too much time and we will never read // the same count twice .... // Use the other GetRecordDmaPos routine .... unsigned int GetRecordDmaPos(int chan_num) { DMA_ENTRY *tdma; unsigned int val1,val2; unsigned int low1,low2; unsigned int high1,high2; tdma = &_gf1_dma[chan_num-1]; /* point to this dma data */ ENTER_CRITICAL; while (TRUE) { outp(tdma->clear_ff,0); /* clear f/f */ low1 = (unsigned int)inp( tdma->count ); high1 = (unsigned int)inp( tdma->count ); outp(tdma->clear_ff,0); /* clear f/f */ low2 = (unsigned int)inp( tdma->count ); high2 = (unsigned int)inp( tdma->count ); val1 = (high1<<8) + low1; val2 = (high2<<8) + low2; if( val1 < val2 ) val1 = val2 - val1; else val1 = val1 - val2; if( val1 < 10 ) break; } LEAVE_CRITICAL; return(val2); } #endif unsigned int GetRecordDmaPos(int chan_num) { DMA_ENTRY *tdma; unsigned int val1,val2; unsigned int low1,low2; unsigned int high1,high2; static unsigned int threshold[MAX_DMA+1] = {30,30,30,30,30,30,30,30}; int i=5; tdma = &_gf1_dma[chan_num-1]; /* point to this dma data */ ENTER_CRITICAL; if (tdma->flags & CALIB_COUNT) { // This code is necessary to accomodate a virtualized DMA controller. // If something (like emm386) virtualizes the DMA controller, we have // to adjust our threshold point to accomodate the rollover problem // in the DMA controller. The problem is when you read the low byte // and the high byte rolls over before we get a chance to read it. // A virtualized DMA controller aggravates the problem since it will // take longer between reads ... tdma->flags &= ~CALIB_COUNT; while(i-- > 0) /* try up to 5 times, then use default */ { outp(tdma->clear_ff,0); /* clear f/f */ low1 = (unsigned int)inp( tdma->count ); high1 = (unsigned int)inp( tdma->count ); low2 = (unsigned int)inp( tdma->count ); high2 = (unsigned int)inp( tdma->count ); if (high1 == high2) { threshold[chan_num] = (low1 - low2)/2 + 2; break; } } } val2 = 1; /* first time thru condition ... */ while (TRUE) { outp(tdma->clear_ff,0); /* clear f/f */ low1 = (unsigned int)inp( tdma->count ); high1 = (unsigned int)inp( tdma->count ); val1 = (high1<<8) + low1; /* If count is not about to roll over, use this count */ /* or if count equals 0xffff (dma complete) use this count */ if ((low1 > threshold[chan_num] && low1 != 0xff) || (val1 == 0xffff)) { val2 = val1; break; } if (val2 == val1) break; val2 = val1; } LEAVE_CRITICAL; return(val2+1); } unsigned int UltraReadRecordPosition(void) { DMA_ENTRY *tdma; unsigned int actual_dma; unsigned int this_size; unsigned int total_size; tdma = &_gf1_dma[_gf1_data.adc_dma_chan-1]; /* point to this dma data */ actual_dma = GetRecordDmaPos(_gf1_data.adc_dma_chan); /* Since it counts backwards, subtract this from size of transfer */ this_size = tdma->cur_size - actual_dma; /* Now add in the amount sent (in case it crosses page) */ total_size = tdma->amnt_sent + this_size; if ( _gf1_data.adc_dma_chan >= 4) total_size <<= 1; return(total_size); }