/***************************************************************************
* NAME: DMA.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 <conio.h>
#include <stdlib.h>
#include <dos.h>
#include "forte.h"
#include "gf1hware.h"
#include "extern.h"
#include "gf1os.h"
#include "dma.h" /* Hardware defs for PC's dma controllers */
#include "gf1proto.h"
#include "osproto.h"
#include "ultraerr.h"
extern DMA_ENTRY _gf1_dma[]; /* Structure that holds data on PC's dma chan */
extern ULTRA_DATA _gf1_data; /* OS data structure */
/***************************************************************
* This function will start up a DMA transfer to the UltraSound
***************************************************************/
void
UltraStartDramDma(unsigned char control)/* bits for card (see gf1hware.h) */
{
/* make sure only right bits are on. Ignore others. */
control = control & (DMA_READ|DMA_16|DMA_CVT_2);
/* Set xfer speed. */
control = control | DMA_R0; /* FAST ..... */
control = control | (DMA_ENABLE|DMA_IRQ_ENABLE); /* Enable & turn IRQ on */
if (_gf1_data.dram_dma_chan >= 4)
control |= DMA_WIDTH_16; /* 16 bit dma channel */
/* DMA xfer. begins here. */
ENTER_CRITICAL;
outp(_gf1_data.reg_select,DMA_CONTROL);
outp(_gf1_data.data_hi,control);
LEAVE_CRITICAL;
}
void
UltraStartRecordDma(unsigned char control)
{
/* make sure only right bits are on. Ignore others. */
control = control & (ADC_MODE|ADC_TWOS_COMP);
control = control | (ENABLE_ADC|ADC_IRQ_ENABLE); /* Enable & turn IRQ on */
if (_gf1_data.adc_dma_chan >= 4)
control |= ADC_DMA_WIDTH; /* 16 bit dma channel */
/* DMA xfer. begins here. */
ENTER_CRITICAL;
outp(_gf1_data.reg_select,SAMPLE_CONTROL);
outp(_gf1_data.data_hi,control);
LEAVE_CRITICAL;
}
void
UltraDmaNext(DMA_ENTRY *tdma,int record)
{
unsigned int tcount;
tdma->flags &= ~TWO_FLAG; /* shut off rollover */
tdma->amnt_sent = tdma->cur_size; /* save the amount xferred */
tdma->cur_size = tdma->nxt_size; /* set up for next buffer */
tcount = tdma->nxt_size;
outp(tdma->single,tdma->dma_disable); /* disable chan */
outp(tdma->clear_ff,0); /* clear f/f */
outp(tdma->addr,tdma->nxt_addr&0xff); /* LSB */
outp(tdma->addr,(tdma->nxt_addr>>8)&0xff); /* MSB */
outp(tdma->page,tdma->nxt_page); /* page # */
outp(tdma->mode,tdma->cur_mode); /* set mode */
outp(tdma->clear_ff,0); /* clear f/f */
outp(tdma->count,tcount&0x0ff); /* LSB count */
outp(tdma->count,(tcount>>8)&0x0ff); /* MSB count */
outp(tdma->single,tdma->dma_enable); /* enable */
/* Now start up xfer ... */
if (record)
UltraStartRecordDma(tdma->cur_control);
else
UltraStartDramDma(tdma->cur_control);
}
int
PrimeDma(void far *pc_ptr,int type,unsigned int size,unsigned int channel)
{
DMA_ENTRY *tdma;
unsigned long s_20bit,e_20bit;
unsigned int spage,saddr,tcount;
unsigned int epage,eaddr;
#ifndef FLAT_MODEL
unsigned int sseg,soff;
#endif
int i;
unsigned char *tptr;
tdma = &_gf1_dma[channel-1]; /* point to this dma data */
if (tdma->flags & DMA_PENDING)
return(DMA_BUSY);
tdma->flags |= DMA_PENDING;
tdma->flags |= CALIB_COUNT;
/* Convert the pc address to a 20 bit physical address that the DMA */
/* controller needs */
#ifdef FLAT_MODEL
s_20bit = (unsigned long)pc_ptr;
#else /* !FLAT_MODEL */
sseg = FP_SEG((void far*)pc_ptr);
soff = FP_OFF((void far*)pc_ptr);
s_20bit = (unsigned long)((((unsigned long)sseg)<< 4) + (unsigned long)soff);
#endif /* FLAT_MODEL */
e_20bit = s_20bit + size - 1;
spage = (unsigned int)((s_20bit & 0xffff0000L)>>16);
epage = (unsigned int)((e_20bit & 0xffff0000L)>>16);
if (channel >= 4)
{
/* if 16-bit xfer, then addr,count & size are divided by 2 */
s_20bit = s_20bit >> 1;
e_20bit = e_20bit >> 1;
size = size >> 1;
}
saddr = (unsigned int)(s_20bit & 0x0000ffffL);
eaddr = (unsigned int)(e_20bit & 0x0000ffffL);
#ifdef NEVER
printf("saddr = %x eaddr = %x\n",saddr,eaddr);
printf("s_20bit = %lx e_20bit = %lx\n",s_20bit,e_20bit);
printf("spage = %d epage = %d\n",spage,epage);
tptr = (unsigned char *)pc_ptr;
for (i=0;i<10;i++)
printf("%02x ",tptr[i]);
printf("\n");
#endif
/* In case the buffer goes over a page, save the data for the irq */
/* handler to use to finish sending the data */
if (spage != epage)
{
tdma->flags |= TWO_FLAG;
tdma->nxt_page = epage;
if (channel >= 4)
{
if (tdma->nxt_page & 0x01)
tdma->nxt_addr = 0x8000;
else
tdma->nxt_addr = 0;
eaddr &= 0x7fff;
}
else
tdma->nxt_addr = 0;
tdma->nxt_size = eaddr;
size = size - eaddr - 1; /* only supposed to send this much */
}
else
{
tdma->flags &= ~TWO_FLAG;
}
if ((type == INDEF_READ) && (tdma->flags & TWO_FLAG))
{
return(BAD_DMA_ADDR);
}
tdma->cur_page = spage;
tdma->cur_addr = saddr;
tdma->amnt_sent = 0; /* init the amount xferred so far */
tdma->cur_size = size; /* show how big THIS part of buffer is */
tcount = size-1;
switch (type)
{
case READ_DMA:
tdma->cur_mode = tdma->read;
break;
case WRITE_DMA:
tdma->cur_mode = tdma->write;
break;
case INDEF_READ:
/* with this mode, all we have to do is kick off the gf1 */
/* sample control to restart the dma recording .... */
tdma->cur_mode = tdma->read | 0x10; /* turn on auto init */
break;
case INDEF_WRITE:
tdma->cur_mode = tdma->write | 0x10; /* turn on auto init */
break;
}
outp(tdma->single,tdma->dma_disable); /* disable channel */
outp(tdma->mode,tdma->cur_mode); /* set mode */
outp(tdma->clear_ff,0); /* clear f/f */
outp(tdma->addr,tdma->cur_addr&0xff); /* LSB */
outp(tdma->addr,(tdma->cur_addr>>8)&0xff); /* MSB */
outp(tdma->page,tdma->cur_page); /* page # */
outp(tdma->clear_ff,0); /* clear f/f */
outp(tdma->count,tcount&0x0ff); /* LSB count */
outp(tdma->count,(tcount>>8)&0x0ff); /* MSB count */
outp(tdma->single,tdma->dma_enable); /* enable */
return(ULTRA_OK);
}
void
UltraStopRecordDma(void)
{
DMA_ENTRY *tdma;
unsigned char val;
ENTER_CRITICAL;
outp(_gf1_data.reg_select,SAMPLE_CONTROL);
val = inp(_gf1_data.data_hi);
val &= ~ENABLE_ADC;
outp(_gf1_data.data_hi,val);
tdma = &_gf1_dma[_gf1_data.adc_dma_chan-1]; /* point to this dma data */
outp(tdma->single,tdma->dma_disable); /* disable chan */
tdma->flags &= ~DMA_PENDING;
/* Clear flag that irq handler clears when the xfer is complete */
_gf1_data.flags &= ~ADC_DMA_BUSY;
LEAVE_CRITICAL;
}
void
UltraStopPlayDma(void)
{
DMA_ENTRY *tdma;
unsigned char val;
ENTER_CRITICAL;
outp(_gf1_data.reg_select,DMA_CONTROL);
val = inp(_gf1_data.data_hi);
val &= ~DMA_ENABLE;
outp(_gf1_data.data_hi,val);
tdma = &_gf1_dma[_gf1_data.dram_dma_chan-1]; /* point to this dma data */
outp(tdma->single,tdma->dma_disable); /* disable chan */
tdma->flags &= ~DMA_PENDING;
/* Clear flag that irq handler clears when the xfer is complete */
_gf1_data.flags &= ~DRAM_DMA_BUSY;
LEAVE_CRITICAL;
}