⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cfc_dma.c

📁 ARM9基于WINDOWSCE的BSP源代码
💻 C
字号:
/***************************************************************************
*   File:    cfc_dma.c  -   Do DMA operations with KernelIoControl
* 
*   The content of this file or document is CONFIDENTIAL and PROPRIETARY
*   to Jade Technologies Co., Ltd.  It is subject to the terms of a
*   License Agreement between Licensee and Jade Technologies Co., Ltd.
*   restricting among other things, the use, reproduction, distribution
*   and transfer.  Each of the embodiments, including this information 
*   and any derivative work shall retain this copyright notice.
* 
*   Copyright (c) 2005 Jade Technologies Co., Ltd. 
*   All rights reserved.
****************************************************************************/
#include "cfcard.h"

//------------------------------------------------------------------------------
// Global Variables in CF_DMA.C
//------------------------------------------------------------------------------
unsigned long	pdwPageList[0x4000];
unsigned char	ChannelNumber = -1;
unsigned long	InterruptID = 0;
HANDLE			DMAIntrEvent = NULL;

//------------------------------------------------------------------------------
//
// Allocate DMA - Allocate a free channel. Then connect the 
//		pre-created event to the DMA sys-interrupt. 
//
//------------------------------------------------------------------------------
BOOL 
CFC_AllocateDMA(
	void
	)
{
	unsigned long dwRet = 0;
	BOOL ret = FALSE;
	// allocate channel
	ALLOCATE_DMA_PARAMS AllocateDMAParams;
	ALLOCATE_DMA_RESULT AllocateDMAResult;
	
	// set the number of device
	AllocateDMAParams.ucSourceDevice = 20;
	AllocateDMAParams.ucDestDevice = 21;
	// for device the priority can be any value
	AllocateDMAParams.ucPreferedPriority = 0xff;    // no preference
	if (!KernelIoControl(IOCTL_HAL_ALLOCATE_DMA_CHANNEL,
             &AllocateDMAParams, sizeof(AllocateDMAParams),
             &AllocateDMAResult, sizeof(AllocateDMAResult), &dwRet))
			 return ret;
	// the allocated channel and interrupt is returned by "&AllocateDMAResult"
	ChannelNumber = AllocateDMAResult.ucChannelNumber;
	InterruptID = AllocateDMAResult. dwInterruptID;
	// make a interrupt event
	if (InterruptInitialize(InterruptID, DMAIntrEvent, NULL, 0))
	{
		ret = TRUE;
	}
	return ret;
}

//------------------------------------------------------------------------------
//
// Init DMA - Initialize the DMA channel. Choose DMA as the flow controler. 
//
// Arguments:
//		Opcode - indicate current operation is read or write, affect the flow
//		control and source/dest increment. 
//
//------------------------------------------------------------------------------
BOOL 
CFC_InitDMA(
	unsigned long Opcode
	)
{		
	unsigned long dwRet = 0;
	BOOL ret = FALSE;
	// initialize channel
	INITIALIZE_DMA_PARAMS InitializeDMAParams;
	INITIALIZE_DMA_RESULT InitializeDMAResult;
	InitializeDMAParams.ucChannelNumber = ChannelNumber;
	// set trans width both 32 bits
	InitializeDMAParams.ucSourceWidth = TRANSFER_WIDTH_DWORD; 
	InitializeDMAParams.ucDestWidth = TRANSFER_WIDTH_DWORD; 
	// set trans burst size 16
	InitializeDMAParams.ucSourceBurstSize = BURST_SIZE_16; 
	InitializeDMAParams.ucDestBurstSize = BURST_SIZE_16;
	// choose flow direction, controler, and whether addr increase
	if (Opcode == DISK_IOCTL_READ)
	{
		InitializeDMAParams.fIncrementSource = FALSE;	//source - constant
		InitializeDMAParams.fIncrementDest = TRUE;		//dest - auto increment
		InitializeDMAParams.ucFlowControl = FLOW_PER_MEM_DMAC;
	}
	else
	{
		InitializeDMAParams.fIncrementSource = TRUE;	//source - auto increment
		InitializeDMAParams.fIncrementDest = FALSE;		//dest - constant
		InitializeDMAParams.ucFlowControl = FLOW_MEM_PER_DMAC;
	}
	if (!KernelIoControl(IOCTL_HAL_INITIALIZE_DMA_CHANNEL,
		 &InitializeDMAParams, sizeof(InitializeDMAParams),
		 &InitializeDMAResult, sizeof(InitializeDMAResult), &dwRet))
		 return ret;
	RETAILMSG(MSG_DMA, (_T("CFCARD: CFC_InitDMA finished\r\n")));

	return TRUE;
}

//------------------------------------------------------------------------------
//
// Start DMA - Go on config the DMA channel and set the source/dest address. 
//		Start Transmiting. When DMA finished the current transfer, it will 
//		trigger a interrupt. We wait the event that connected to the interrupt. 
//		If no TIMEOUT, this transfer is succeed.
//
// Arguments:
//		regs - Cf registers' base address
//		Opcode - indicate current operation is read or write. 
//		FIFOAddr - CFCARD FIFO register's physical address. 
//		buf - pointer of the buffer(virtual address) that exchange data with card
//		sectorcnt - number of sectors to transmit
//
//------------------------------------------------------------------------------
BOOL
CFC_StartDMA(
	CFRegs *regs,
	unsigned long Opcode, 
	unsigned long FIFOAddr, 
	unsigned short *buf, 
	unsigned long sectorcnt
	)
{	
	BOOL dwRet = FALSE;
	int i;
	// start transmit
	START_DMA_PARAMS    StartDMAParams;
	START_DMA_RESULT    StartDMAResult;
	STOP_DMA_PARAMS		StopDMAParams;
	STOP_DMA_RESULT		StopDMAResult;
	int dwPages;
	unsigned long DbufOffset = 0;
	unsigned long * Dbuf;
	unsigned long Source,Dest;
	unsigned long ret = 0;
	unsigned long size = sectorcnt * BYTES_PER_SECTOR;
	
	Dbuf = (unsigned long *)buf;
	DbufOffset = (unsigned long)BYTE_OFFSET(Dbuf);

	// as the Cf fifo burst exist some question
	// we must use cpu to transmit the bytes 
	size -= DbufOffset%CF_BURST_BYTES;

	// account pages needed
	dwPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, size+DbufOffset);

	if (Opcode == DISK_IOCTL_READ) 
	{
		// LockVirtual Page to physical page
		LockPages ((unsigned long *)((unsigned long)Dbuf - DbufOffset), (size + DbufOffset), pdwPageList, 0);
		for(i=0;i<dwPages;i++)
		{
			pdwPageList[i] &= ~(unsigned long)(PAGE_SIZE - 1);
		}
		pdwPageList[0] += DbufOffset;
		StartDMAParams.ucChannelNumber = ChannelNumber;
		// source address
		Source = FIFOAddr;
		StartDMAParams.pdwSourceBuffer = &Source;
		// dest address
		StartDMAParams.pdwDestBuffer = pdwPageList;
		//add by lfchen
//		RETAILMSG(MSG_DMA, (_T("pdwPageList = 0x%x\r\n"),pdwPageList));
		// trans size
		StartDMAParams.dwTransferSize = size;
		if (KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
				&StartDMAParams, sizeof(StartDMAParams),
				&StartDMAResult, sizeof(StartDMAResult), &dwRet))
		{
			// wait for interrupt
			if (WaitForSingleObject(DMAIntrEvent, 500) == WAIT_TIMEOUT )
			{
				InterruptDone(InterruptID);
				StopDMAParams.ucChannelNumber = ChannelNumber;
				KernelIoControl(IOCTL_HAL_STOP_DMA_TRANSFER,
					&StopDMAParams, sizeof(StopDMAParams),
					&StopDMAResult, sizeof(StopDMAResult), &dwRet);
				Sleep(1);
				RETAILMSG(1, (_T("CFCARD: CFC_StartDMA - Intr TIMEOUT\r\n")));
				RETAILMSG(1, (_T("CFCARD: CFC_StartDMA - Stop DMA\r\n")));
				ret = FALSE;
			}
			else
			{
				// announce interrupt finished
				InterruptDone(InterruptID);
				for (i=0;i<(int)((DbufOffset%CF_BURST_BYTES)/4);i++)	// read data from FIFO directly
				{
					*((unsigned long*)((unsigned long)Dbuf+size)+i) = regs->CF_ADDR_FIFO;
				}
				ret = TRUE;
			}
		}
		UnlockPages((unsigned long *)((unsigned long)Dbuf - DbufOffset), (size + DbufOffset));
	}
	else 
	{
		// LockVirtual Page to physical page
		LockPages ((unsigned long *)((unsigned long)Dbuf - DbufOffset), (size + DbufOffset), pdwPageList, 0);
		for(i=0;i<dwPages;i++)
		{
			pdwPageList[i] &= ~(unsigned long)(PAGE_SIZE - 1);
		}
		pdwPageList[0] += DbufOffset;
		StartDMAParams.ucChannelNumber = (unsigned char)ChannelNumber;
		// source address
		StartDMAParams.pdwSourceBuffer = pdwPageList;
		// dest address
		Dest = FIFOAddr;
		StartDMAParams.pdwDestBuffer = &Dest;
		//add by lfchen
		RETAILMSG(MSG_DMA, (_T("pdwPageList = 0x%x\r\n"),pdwPageList));
		// trans size
		StartDMAParams.dwTransferSize = size;
		if (KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
				&StartDMAParams, sizeof(StartDMAParams),
				&StartDMAResult, sizeof(StartDMAResult), &dwRet))
		{
			// wait for interrupt
			if (WaitForSingleObject(DMAIntrEvent, 500) == WAIT_TIMEOUT )
			{
				InterruptDone(InterruptID);
				StopDMAParams.ucChannelNumber = ChannelNumber;
				KernelIoControl(IOCTL_HAL_STOP_DMA_TRANSFER,
					&StopDMAParams, sizeof(StopDMAParams),
					&StopDMAResult, sizeof(StopDMAResult), &dwRet);
				Sleep(1);
				RETAILMSG(1, (_T("CFCARD: CFC_StartDMA - Intr TIMEOUT\r\n")));
				RETAILMSG(1, (_T("CFCARD: CFC_StartDMA - Stop DMA\r\n")));
				ret = FALSE;
			}
			else
			{
				// announce interrupt finished
				InterruptDone(InterruptID);
				for (i=0;i<(int)((DbufOffset%CF_BURST_BYTES)/4);i++)	// write data to FIFO directly
				{
					regs->CF_ADDR_FIFO = *((unsigned long*)((unsigned long)Dbuf+size)+i);
				}
				ret = TRUE;
			}
		}
		UnlockPages((unsigned long *)((unsigned long)Dbuf - DbufOffset), (size + DbufOffset));
	}
	return ret;
}

//------------------------------------------------------------------------------
//
// Release DMA - Do all the clear job. 
//
//------------------------------------------------------------------------------
BOOL 
CFC_ReleaseDMA(void)
{
	BOOL ret = FALSE;
	unsigned long dwRet;
	FREE_DMA_PARAMS FreeDMAParams;
	FREE_DMA_RESULT FreeDMAResult;
	FREE_DMA_SYSINTR_PARAMS FreeSysIntrParams;
	FREE_DMA_SYSINTR_RESULT FreeSysIntrResult;

	// release channel
	FreeDMAParams.ucChannelNumber = ChannelNumber;
	if (!KernelIoControl(IOCTL_HAL_FREE_DMA_CHANNEL,
			&FreeDMAParams, sizeof(FreeDMAParams),
			&FreeDMAResult, sizeof(FreeDMAResult), &dwRet))
			return ret;
	// release sys-interrupt
	FreeSysIntrParams.ucChannelNumber = ChannelNumber;
	if (!KernelIoControl(IOCTL_HAL_FREE_DMA_SYSINTR,
			&FreeSysIntrParams, sizeof(FreeSysIntrParams),
			&FreeSysIntrResult, sizeof(FreeSysIntrResult), &dwRet))
			return ret;
	return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -