📄 cfc_dma.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 + -