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

📄 sd_dma.c

📁 ARM9基于WINDOWSCE的BSP源代码
💻 C
字号:
/***************************************************************************
*   File:    sd_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 "sd.h"

//------------------------------------------------------------------------------
// Global Macros and Variables in SD_DMA.C
//------------------------------------------------------------------------------
unsigned char	ChannelLine = 0;	// Real DMA Channel Line
unsigned char	ChannelNumber;		// DMA Channel number
unsigned long	InterruptID;		// System interrupt ID
HANDLE		DMAIntrEvent;		// Event hooked to the interrupt

unsigned long	pdwPageList[20];		
unsigned char*	TempBufDMA;			// Page-head buffer used in SDI_StartDMA


//------------------------------------------------------------------------------
//
// Allocate DMA - Choose a DMA Line in 0,1,2, and allocate a free channel. 
//		Then connect the pre-created event to the DMA sys-interrupt. Another
//		thing is to allocate a page-head buffer used in SDI_StartDMA. 
//
//------------------------------------------------------------------------------
BOOL 
SDI_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 = ChannelLine;
	AllocateDMAParams.ucDestDevice = ChannelLine;
	// 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))
		return ret;

	// make a page-head buffer
	TempBufDMA = (unsigned char*)VirtualAlloc(NULL, BYTES_PER_SECTOR, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);

	RETAILMSG(MSG_DMA, (_T("SD: SDI_AllocateDMA - Line:%d, Channel:%d\r\n"), ChannelLine, ChannelNumber));
	return TRUE;
}

//------------------------------------------------------------------------------
//
// Init DMA - Initialize the DMA channel. Choose SD as the flow controller. 
//
// Arguments:
//		Opcode - indicate current operation is read or write, affect the flow
//		control and source/dest increment. 
//
//------------------------------------------------------------------------------
BOOL 
SDI_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 8
	InitializeDMAParams.ucSourceBurstSize = BURST_SIZE_8; 
	InitializeDMAParams.ucDestBurstSize = BURST_SIZE_8;
	// choose flow direction, controller, 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;

	return TRUE;
}

//------------------------------------------------------------------------------
//
// Start DMA - Go on config the DMA channel and set the source/dest address. 
//		Start Transmiting. When SD send a Last-burn signal, the DMA will 
//		trigger a interrupt. We wait the event connected to the interrupt. 
//		If no TIMEOUT, this transfer is succeed.
//		Indeed, as the SD is the flow controller, we don't need to tell DMA
//		the transfer size. But in this case, DMA can not jump to other page
//		list. So we can do only in-page transfer. That's why we use a temp buffer
//		to exchange data with the real buffer we needed. 
//
// Arguments:
//		Opcode - indicate current operation is read or write. 
//		FIFOAddr - SD FIFO register's physical address. 
//		buf - pointer of the buffer(virtual address) that exchange data with card
//
//------------------------------------------------------------------------------
BOOL 
SDI_StartDMA(
	unsigned long Opcode, 
	unsigned long FIFOAddr, 
	unsigned char* buf,
	unsigned long size
	)
{	
	unsigned long dwRet = 0;
	BOOL ret = FALSE;
	BOOL usetemp = FALSE;
	// start transmit
	START_DMA_PARAMS    StartDMAParams;
	START_DMA_RESULT    StartDMAResult;
	unsigned long Source, Dest;
	unsigned long * Dbuf;
	unsigned long DbufOffset = 0;
	unsigned long dwPages;
	unsigned long i;
	
	Dbuf = (unsigned long *)buf;
	DbufOffset = (unsigned long)BYTE_OFFSET(Dbuf);
	// account pages needed
	dwPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, size+DbufOffset);

	if (Opcode == DISK_IOCTL_READ) 
	{
		// Lock Virtual 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;
		// trans size
		StartDMAParams.dwTransferSize = size;
		
		if (KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
				&StartDMAParams, sizeof(StartDMAParams),
				&StartDMAResult, sizeof(StartDMAResult), &dwRet))
		{
			ret = TRUE;
		}
	}
	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;
		// trans size
		StartDMAParams.dwTransferSize = size;
		if (KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
				&StartDMAParams, sizeof(StartDMAParams),
				&StartDMAResult, sizeof(StartDMAResult), &dwRet))
		{
			ret = TRUE;
		}
	}
	return ret;
}

BOOL
SDI_WaitDMA(	
	unsigned long Opcode, 
	unsigned long FIFOAddr, 
	unsigned char* buf,
	unsigned long size
	)
{
	BOOL ret = FALSE;
	unsigned long * Dbuf;
	unsigned long DbufOffset = 0;
	Dbuf = (unsigned long *)buf;
	DbufOffset = (unsigned long)BYTE_OFFSET(Dbuf);
	
	// wait for DMA interrupt
	if (Opcode == DISK_IOCTL_READ) 
	{
		if (WaitForSingleObject(DMAIntrEvent, 500) == WAIT_TIMEOUT)
			RETAILMSG(MSG_DMA, (_T("SD: SDI_WaitDMA(read) - Intr TIMEOUT\r\n")));
		else 
			ret = TRUE;
	}
	else
	{
		if (WaitForSingleObject(DMAIntrEvent, 500) == WAIT_TIMEOUT)
			RETAILMSG(MSG_DMA, (_T("SD: SDI_WaitDMA(write) - Intr TIMEOUT\r\n")));
		else
			ret = TRUE;
	}
	InterruptDone(InterruptID);
	UnlockPages((unsigned long *)((unsigned long)Dbuf - DbufOffset), (size + DbufOffset));
	return ret;
}

//------------------------------------------------------------------------------
//
// Release DMA - Do all the clear job. 
//
//------------------------------------------------------------------------------
BOOL
SDI_ReleaseDMA(void)
{
	unsigned long dwRet;
	BOOL ret = FALSE;
	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;
	FreeSysIntrParams.ucChannelNumber = ChannelNumber;
	if (!KernelIoControl(IOCTL_HAL_FREE_DMA_SYSINTR,
			&FreeSysIntrParams, sizeof(FreeSysIntrParams),
			&FreeSysIntrResult, sizeof(FreeSysIntrResult), &dwRet))
			return ret;
	// free the page-head buffer
	VirtualFree(TempBufDMA, 0, MEM_RELEASE);

	return TRUE;
}

⌨️ 快捷键说明

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