/***************************************************************************
* 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 <stdio.h>
#include <dos.h>
#include <conio.h>
#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);
}