#include <stdio.h>

#include "bme.h"
#include "bme_app.h"
#include "mem.h"
#include "bme_dma.h"
#include "hostType.h"

extern int  tot_dma_out_standing;

DMA_DATABASE dmaDatabase[16];

void logDMA(char *title, DMA_DATABASE *db)
{
	logMsg("\n In %s:", title);
	logMsg("\n\t port = %d, dma_chan_num = %d, src = 0x%8x, dst = 0x%8x, len = %d, fifo_flag = %d", 
			db->portnum, db->channel, db->src, db->dst, db->length, db->isFifoSrc);
}

int isDMAChannelFree (int i)
{
    int stat;

	stat = readPIO_SingleRegChannel((int *)DMA_CCR0, i);	
	/*
		if the enable bit is 0
		or if the enable bit is 1  and done bit is 1
	*/				   
	if (!(stat & DMA_CCR_CHANNEL_ENABLE_BIT)) 
        return TRUE;
	else 
	{
		if ((stat & DMA_CCR_CHANNEL_ENABLE_BIT) &&(stat & DMA_CCR_CHANNEL_TRANSFER_DONE))
			return TRUE;
				 
	}
	return FALSE;
}


int getFreeDmaChannel()
{
    int     i;
    int     stat;

	// find an available channel by testing the bits in progress bits
	for (i = DMA_FREE_FIRST; i>=DMA_FREE_LAST;i--)
	{
        stat = isDMAChannelFree(i); 
        if(stat == TRUE)
            return i;
	}

	return NO_DMA_CHANNEL_AVAILABLE; 
}

void programDMAController (DMA_DATABASE *p, int channel)
{
	int dma_ccr;
		
	// set up all the ccr registers 	
	// length is input from 1..2K bytes
	// the ccr register goes 0..2K-1
	// also set the channel enable bit here as well
	// this also sets the DONE bit to 0
	dma_ccr = (((p->length-1) << DMA_CCR_TRANSFER_COUNT) | DMA_CCR_CHANNEL_ENABLE_BIT);
	
	// schedule an interrupt?
	if (p->dma_mode == DMA_INT)	
		dma_ccr |=  DMA_CCR_CHANNEL_INT_ENABLE_BIT;
		
	// is the SRC a FIFO or MEM		
	if (p->isFifoSrc)		
		dma_ccr |=  DMA_CCR_CHANNEL_SRC_FIFO;
	// is the DST a FIFO or MEM		
	if (p->isFifoDst)		
		dma_ccr |=  DMA_CCR_CHANNEL_DST_FIFO;
	 
	if((p->hwEvent&DMA_ECR_SW_INIT_DMA)!=0)
		dma_ccr |= DMA_CCR_CHANNEL_DMA_BEGIN;
	
	writePIO_SingleRegChannel((int *)DMA_ECR0, channel, p->hwEvent);
	writePIO_SingleRegChannel((int *)DMA_SAR0, channel, p->src & MASK_OUT_CACHE_ADDRESS_BIT);
	writePIO_SingleRegChannel((int *)DMA_DAR0, channel, p->dst & MASK_OUT_CACHE_ADDRESS_BIT);
	writePIO_SingleRegChannel((int *)DMA_CCR0, channel, dma_ccr);
}

void initDMA (DMA_DATABASE *p, int channel)
{
	
	// need to save the DMA_DATABASE if it causes an interrupt
	if (p->dma_mode == DMA_INT) {
		int		i;
		unsigned char	*dst = (unsigned char *)(dmaDatabase+channel);
		for(i=0;i<sizeof(DMA_DATABASE);i++)
			*dst++ = *((unsigned char *)p)++;
	}

	// program the actual DMA controller							 
	programDMAController (p, channel);
}


 
int DMAdone (int DMAchannel) 
{
  return (DMA_CCR_CHANNEL_TRANSFER_DONE& readPIO_SingleRegChannel((int *)DMA_CCR0, DMAchannel));
}

void check_dma_done_status()
{
	int	status;
	
	if(curr_dma_chan == -1)
		return;

	status = readPIO_SingleRegChannel((int *)DMA_CCR0, curr_dma_chan);
	
	if((status&DMA_CCR_CHANNEL_TRANSFER_DONE) == 0) {
		dma_status = DMA_IN_PROGRESS;	
	} else {
		curr_dma_chan = -1;
		dma_status = DMA_DONE; 
        tot_dma_out_standing--;
	}
}
