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

📄 sd_dma.c

📁 linux 2.6下的sd卡驱动
💻 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 Lineunsigned char	ChannelNumber;		// DMA Channel numberunsigned long	InterruptID;		// System interrupt IDHANDLE		DMAIntrEvent;		// Event hooked to the interruptunsigned 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;}BOOLSDI_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. ////------------------------------------------------------------------------------BOOLSDI_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 + -