/***************************************************************************
*	NAME:  DMADRAM.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 <stdlib.h>
#include <dos.h>
#include <conio.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 */

int
UltraDramDmaBusy(void)
{
return(_gf1_dma[_gf1_data.dram_dma_chan-1].flags & DMA_PENDING);
}

void
UltraWaitDramDma(void)
{
	_gf1_data.flags &= ~DRAM_DMA_NOWAIT;

	ENTER_CRITICAL_ON;

	while (_gf1_data.flags & DRAM_DMA_BUSY)	/* wait for irq to clear this */
		{
		}

	LEAVE_CRITICAL_ON;
}

/***************************************************************
 * This function will prime the pc's dma controller for sending to
 * or receiving data from the UltraSound. The last thing it does is
 * start the transfer. It either wait for it to complete or it
 * could return immediately ... 
 *
 * NOTE: This example will NOT attempt to explain how the pc's
 *       dma controller works. If you want to know more than you
 *       can by looking at this code, there are lots of documents
 *       available that go into great detail.
 ***************************************************************/

int	
UltraDmaDram_64K(void far *pc_ptr, unsigned int size, unsigned long ultra_ptr, unsigned char control, int wait)
//void far *pc_ptr;			/* pointer to buffer in pc ram */
//unsigned int size;		/* # of bytes to send/recieve */
//unsigned long ultra_ptr;	/* physical addr in ultrasound to get/put data */
//unsigned char control;	/* read or write dram (see gf1hware.h) */
//int wait;
{
DMA_ENTRY *tdma;
unsigned long dram_address;
int type;
int ret;

tdma  = &_gf1_dma[_gf1_data.dram_dma_chan-1];		/* point to this dma data */

if (control & DMA_READ)
	{
	if (control & DMA_AUTO_INIT)
		type = INDEF_READ;
	else
		type = READ_DMA;
	}
else
	{
	if (control & DMA_AUTO_INIT)
		type = INDEF_WRITE;
	else
		type = WRITE_DMA;
	}

control &= ~DMA_AUTO_INIT;	/* turn this off now ... */

ret = PrimeDma(pc_ptr,type,size,_gf1_data.dram_dma_chan);
if (ret != ULTRA_OK)
	return(ret);

/* If its a 16 bit dma channel, an extra translation is necessary */
if (_gf1_data.dram_dma_chan >= 4)
	dram_address = convert_to_16bit(ultra_ptr);
else
	dram_address = ultra_ptr;

/* Only use the upper 16 bits. This means that an 8 bit xfer MUST */
/* start on a 16 byte boundary and a 16 bit xfer MUST start on a 32 */
/* byte boundary. */

ENTER_CRITICAL;
	
outp(_gf1_data.reg_select,SET_DMA_ADDRESS);
outpw(_gf1_data.data_low,(unsigned int)(dram_address>>4));

LEAVE_CRITICAL;

/* Set flag that irq handler clears when the xfer is complete */
_gf1_data.flags |= DRAM_DMA_BUSY;

/* Now tell GF1 to start xfer ... */
tdma->cur_control = control;
UltraStartDramDma(control);

/* if required, wait till dma is done ... */
if (wait)
	UltraWaitDramDma();
else
	_gf1_data.flags |= DRAM_DMA_NOWAIT;
return(ULTRA_OK);
}

/***************************************************************
 * This function will download/upload up to 64K of data into/out the 
 * dram on the ultrasound card. Since the card cannot DMA
 * across 256K boundaries, this routine will split up the xfer .... 
 ***************************************************************/

static int	
UltraDmaDram(void far *pc_ptr, unsigned int size, unsigned long ultra_ptr, unsigned char control, int wait)
// void far *pc_ptr;	/* pointer to buffer in pc ram */
// unsigned int size;	/* # of bytes to send/recieve */
// unsigned long ultra_ptr;	/* physical addr in ultrasound to get/put data */
// unsigned char control;/* read or write dram (see gf1defs.h) */
// int wait;			/* flag to wait until xfer is complete.... */
{
unsigned long end;
long start_page,end_page;
unsigned int start_size;
void far *nxt_pc_ptr;
unsigned long nxt_ptr;
unsigned int nxt_size;
int two_flag = 0;
int ret;

end = ultra_ptr + (unsigned long)size - 1;

start_page = ultra_ptr >> 18;	/* isolate the 256K page */
end_page   = end >> 18; 		/* isolate the 256K page */

if (start_page != end_page)		/* crossed page boundary ... */
	{
	nxt_ptr = end_page << 18;		/* where second part goes in DRAM */
	nxt_size = end - nxt_ptr;		/* How much to put there */
	start_size = size - nxt_size;	/* How much in first page of DRAM */
	nxt_pc_ptr = (void far *)((char far *)pc_ptr + start_size);	/* where in PC RAM is second part */
	two_flag = 1;
	}
else
	{
	start_size = size;
	}

ret = UltraDmaDram_64K(pc_ptr, start_size, ultra_ptr, control, wait);
if (ret != ULTRA_OK)
	return(ret);

/* Now send second half */
/* Probably SHOULD put this in the IRQ handler ... */
if (two_flag)
	{
	if (!wait)		/* Gotta wait so I can send next page ... */
		UltraWaitDramDma();

	ret = UltraDmaDram_64K(nxt_pc_ptr, nxt_size, nxt_ptr, control, wait);

	if (ret != ULTRA_OK)
		return(ret);
	}
return(ULTRA_OK);
}

int
UltraDownload(void far *dataptr,unsigned char control,unsigned long dram_loc,unsigned int len,int wait)
// void far *dataptr;
// unsigned char control;
// unsigned long dram_loc;
// unsigned int len;
// int wait;
{
int val;
#ifdef METAWARE
unsigned int i;
unsigned char *ptr = (unsigned char *)dataptr;

for (i=0;i<len;i++)
	{
	UltraPokeData(_gf1_data.base_port,dram_loc,*ptr);
	dram_loc++;
	ptr++;
	}
val = ULTRA_OK;
#else
control &= ~DMA_READ;	/* turn off read bit ... (write to dram) */
val = UltraDmaDram(dataptr, len, dram_loc, control, wait);
#endif
return(val);
}

int
UltraUpload(void far *dataptr,unsigned char control,unsigned long dram_loc,unsigned int len,int wait)
// void far *dataptr;
// unsigned char control;
// unsigned long dram_loc;
// unsigned int len;
// int wait;
{
int val;

control |= DMA_READ;	/* turn on read bit ... */
val = UltraDmaDram(dataptr, len, dram_loc, control, wait);
return(val);
}

