?? sd_dma.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 + -