📄 lmidma.c
字号:
#include "LMIfuncs.h"
#include "Dma.h"
//LMI DMA peripheral number
#define LMI_Tx_ID 30
/*! \brief allocate dma channel for lmi data transfer.
* and initalize interrupt
* \params hHead :the LMI driver head structure point
* \return BOOL :indicate success or not.
*/
BOOL LMIInitDma(PLMI_Header pHead)
{
BOOL fRC = TRUE;
DWORD dwRet;
//LMI DMA -
PLMI_DMA_INFO pDma = &(pHead->DmaInfo);
ALLOCATE_DMA_PARAMS AllocateDMAParams;
ALLOCATE_DMA_RESULT AllocateDMAResult;
// UART Tx Channel Alloc.
AllocateDMAParams.ucSourceDevice = 0; // Memory
AllocateDMAParams.ucDestDevice = LMI_Tx_ID; // Tx
AllocateDMAParams.ucPreferedPriority = 0xff; // no preference
if(!KernelIoControl(IOCTL_HAL_ALLOCATE_DMA_CHANNEL,
&AllocateDMAParams, sizeof(AllocateDMAParams),
&AllocateDMAResult, sizeof(AllocateDMAResult), &dwRet))
{
// No channels available
SetLastError(ERROR_ALREADY_ASSIGNED);
LMICloseDma(pDma);
return FALSE;
}
// Save the channel number and interrupt id
pDma->ucTxDMAChannel = AllocateDMAResult.ucChannelNumber;
pDma->dwTxDMASysIntr = AllocateDMAResult.dwInterruptID;
// Create the DMA interrupt event for the Tx
pDma->hTxUDmaISTEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(pDma->hTxUDmaISTEvent == NULL)
{
RETAILMSG(1,
(TEXT("PDD_Open: Error creating Tx DMA Interrupt event\r\n")));
LMICloseDma(pDma);
return FALSE;
}
// Enable the DMA interrupt for Tx
if(!InterruptInitialize(pDma->dwTxDMASysIntr, pDma->hTxUDmaISTEvent, NULL, 0))
{
RETAILMSG(1,
(TEXT("PDD_Open: Error enabling Tx DMA interrupt (%d)\r\n"),
GetLastError()));
LMICloseDma(pDma);
return FALSE;
}
//End of LMI DMA
return fRC;
}
/*! \brief initialize dma channel and start dma for lmi data transfer.
*
* \params hHead :the LMI driver head structure point
* \params pTxBuffer : the source of the Txbuffer
* \params pBuffLen : the length of the data in buffer.
* \return void
*/
void LMIStartDma(PLMI_Header pHead,ULONG* pTxBuffer, ULONG *pBuffLen)
{
PLMI_DMA_INFO pLmiDma = (PLMI_DMA_INFO)(&(pHead->DmaInfo));
INITIALIZE_DMA_PARAMS InitializeDMAParams;
INITIALIZE_DMA_RESULT InitializeDMAResult;
START_DMA_PARAMS StartDMAParams;
START_DMA_RESULT StartDMAResult;
PVOID pvSourceBuffer = pTxBuffer;
ULONG dwRet,Dest,DbufOffset;
int dwPages;
unsigned long *Dbuf;
ULONG BufLen=*pBuffLen,BufLenByte=0;
int i=0;
//UART Tx Channel Init.
InitializeDMAParams.ucChannelNumber = pLmiDma->ucTxDMAChannel;
InitializeDMAParams.ucSourceWidth = TRANSFER_WIDTH_DWORD; // Mem - DWORD
InitializeDMAParams.ucDestWidth = TRANSFER_WIDTH_WORD; // Tx 16 bit
InitializeDMAParams.ucSourceBurstSize = BURST_SIZE_4;
InitializeDMAParams.ucDestBurstSize = BURST_SIZE_16;
//Mem->Per, DMA as flow controller
InitializeDMAParams.ucFlowControl = FLOW_MEM_PER_DMAC;
// Increment source and keep destination constant
InitializeDMAParams.fIncrementSource = TRUE;
InitializeDMAParams.fIncrementDest = FALSE;
if(!KernelIoControl(IOCTL_HAL_INITIALIZE_DMA_CHANNEL,
&InitializeDMAParams, sizeof(InitializeDMAParams),
&InitializeDMAResult, sizeof(InitializeDMAResult), &dwRet))
{
RETAILMSG (1,
(TEXT("PDD: Tx, Error - Cannot initialize DMA channel\r\n")));
*pBuffLen = 0;
return;
}
//Only transfer DWORD aligned size
BufLen = (BufLen >> 2)<< 2;
BufLenByte = BufLen<<2;
// map the pointer to callers memory
Dbuf = (unsigned long *)MapPtrToProcess(pvSourceBuffer, GetCallerProcess());
//Dbuf = (unsigned long *)pvSourceBuffer;
//the offset from the page edge. add (3.8)
DbufOffset = (unsigned long)BYTE_OFFSET(Dbuf);
dwPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Dbuf,BufLenByte);
//we need to use DMA API
pLmiDma->pdwTxSourcePageList = (PDWORD)malloc(dwPages*sizeof(DWORD));
if (pLmiDma->pdwTxSourcePageList == NULL)
{
RETAILMSG (1,
(TEXT("PDD: Error - Cannot allocate for TxSourcePageList\r\n")));
*pBuffLen = 0;
return;
}
//change (3.8.2005)
if(!LockPages((unsigned long*)(((unsigned long)Dbuf)-DbufOffset),
BufLenByte+DbufOffset, (pLmiDma->pdwTxSourcePageList),LOCKFLAG_READ))
{
RETAILMSG (1, (TEXT("PDD: Error - Cannot lock pages\r\n")));
free(pLmiDma->pdwTxSourcePageList);
*pBuffLen = 0;
return;
}
// Just double check page alignment
for(i=0;i<dwPages;i++)
{
pLmiDma->pdwTxSourcePageList[i] &= ~(unsigned long)(PAGE_SIZE - 1);
}
//change 3.8
pLmiDma->pdwTxSourcePageList[0]+=DbufOffset;
pLmiDma->dwTxSourceSize = BufLen;
StartDMAParams.ucChannelNumber = pLmiDma->ucTxDMAChannel;
Dest = (ULONG) (&(((LMIReg*)LMI_BASE)->DATA)); // LMI Physical address
StartDMAParams.pdwDestBuffer = &Dest;
StartDMAParams.pdwSourceBuffer = pLmiDma->pdwTxSourcePageList;
StartDMAParams.dwTransferSize = BufLenByte;
if(!KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
&StartDMAParams, sizeof(StartDMAParams),
&StartDMAResult, sizeof(StartDMAResult), &dwRet))
{
RETAILMSG (1,
(TEXT("PDD: Error - Cannot start DMA transfer\r\n")));
// Unlock the virtual pages so that they can be paged out
UnlockPages(pvSourceBuffer, PAGE_SIZE);
free(pLmiDma->pdwTxSourcePageList);
*pBuffLen = 0;
return;
}
dwRet = WaitForSingleObject(pLmiDma->hTxUDmaISTEvent, INFINITE);
UnlockPages(Dbuf, BufLenByte);
free(pLmiDma->pdwTxSourcePageList);
InterruptDone(pLmiDma->dwTxDMASysIntr);
}
BOOL LMICloseDma(PLMI_DMA_INFO pDma)
{
BOOL RetCode = TRUE;
DWORD dwRet;
FREE_DMA_PARAMS FreeDMAParams;
FREE_DMA_RESULT FreeDMAResult;
if ( pDma->OpenCnt )
{
--(pDma->OpenCnt);
//VirtualFree(pDma->pvRxDestBuffer, PAGE_SIZE, MEM_DECOMMIT);
//VirtualFree(pDma->pvTxSourceBuffer, PAGE_SIZE, MEM_DECOMMIT);
RETAILMSG (1, (TEXT("PDD Dma_Close: (%d handles)\r\n"), pDma->OpenCnt));
// Free DMA Rx channel
/*FreeDMAParams.ucChannelNumber = pDma->ucRxDMAChannel;
if(!KernelIoControl(IOCTL_HAL_FREE_DMA_CHANNEL,
&FreeDMAParams, sizeof(FreeDMAParams),
&FreeDMAResult, sizeof(FreeDMAResult), &dwRet))
{
RETAILMSG (ZONE_ERROR, (TEXT("!!PDD Dma_Close: Cannot free DMA Rx channel!\r\n")));
return FALSE;
}*/
// Free DMA Tx channel
FreeDMAParams.ucChannelNumber = pDma->ucTxDMAChannel;
if(!KernelIoControl(IOCTL_HAL_FREE_DMA_CHANNEL,
&FreeDMAParams, sizeof(FreeDMAParams),
&FreeDMAResult, sizeof(FreeDMAResult), &dwRet))
{
RETAILMSG (1, (TEXT("!!PDD Dma_Close: Cannot free DMA Tx channel!\r\n")));
return FALSE;
}
//if(pDma->hRxUDmaISTEvent)
// CloseHandle(pDma->hRxUDmaISTEvent);
if(pDma->hTxUDmaISTEvent)
CloseHandle(pDma->hTxUDmaISTEvent);
//InterruptDisable(pDma->dwRxDMASysIntr);
InterruptDisable(pDma->dwTxDMASysIntr);
}
else
{
RETAILMSG (1, (TEXT("!!Close of non-open device\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
RetCode = FALSE;
}
return RetCode;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -