📄 dma.cpp
字号:
return TRUE;
}
//
// RestartDMATransfer - Restarts a halted DMA channel
//
// Note: Care should be taken over the state of the Cache at this point.
// It is up to the user to make sure the correct data will be accessed.
//
extern "C" BOOL RestartDMATransfer(PRESTART_DMA_PARAMS pParams, PRESTART_DMA_RESULT pResults)
{
UCHAR ucDMAChannel;
volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
if (!fDMAInitialised) { /* not present */
DEBUGMSG(DMA_ZONE_OPT, (TEXT("No DMA blocking RestartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
return FALSE;
}
DEBUGMSG(DMA_ZONE_OPT, (TEXT("+RestartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
ucDMAChannel = pParams->ucChannelNumber;
pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;
// Clear the halt bit
pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_H;
DEBUGMSG(DMA_ZONE_OPT, (TEXT("-RestartDMATransfer\r\n")));
return TRUE;
}
//
// StopDMATransfer - Stops a DMA channel
//
// Note: Care should be taken over the state of the Cache at this point.
// It is up to the user to make sure the correct data will be accessed.
//
extern "C" BOOL StopDMATransfer(PSTOP_DMA_PARAMS pParams, PSTOP_DMA_RESULT pResults)
{
UCHAR ucDMAChannel;
volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
DEBUGMSG(DMA_ZONE_OPT, (TEXT("+StopDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
ucDMAChannel = pParams->ucChannelNumber;
pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;
// Stop any transfer by disabling the DMA channel
pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_E;
DEBUGMSG(0, (TEXT("-StopDMATransfer\r\n")));
return TRUE;
}
//
// GetErrorStatus - Returns the DMA error status
//
// We don't want this function optimized as the compiler will code the I/O access as
// an 8 bit read instead of a 32 bit read (this is specific to Microsoft's ARM compiler).
#pragma optimize( "", off )
extern "C" BOOL GetErrorStatus(PGET_ERROR_PARAMS pParams, PGET_ERROR_RESULT pResults)
{
DEBUGMSG(1, (TEXT("+GetErrorStatus()\r\n")));
if( !fDMAInitialised )
{
DEBUGMSG(DMA_ZONE_OPT, (TEXT("AllocateDMAChannel: DMA not initialised\r\n")));
return FALSE;
}
// Read the DMA error status
pResults->ucErrorStatus = (UCHAR)pDMACRegs->DMACIntErrorStatus;
DEBUGMSG(1, (TEXT("-GetErrorStatus - 0x%X\r\n"), pResults->ucErrorStatus));
return TRUE;
}
#pragma optimize( "", on )
//
// ClearErrorStatus - Clears the DMA error status
//
extern "C" BOOL ClearErrorStatus(PCLEAR_ERROR_PARAMS pParams, PCLEAR_ERROR_RESULT pResults)
{
DEBUGMSG(1, (TEXT("+ClearErrorStatus(0x%X)\r\n"), pParams->ucErrorStatusMask));
// Clear the DMA error status
pDMACRegs->DMACIntErrClr = (DWORD)pParams->ucErrorStatusMask;
DEBUGMSG(1, (TEXT("-ClearErrorStatus\r\n")));
return TRUE;
}
//
// GetTCStatus - Returns the DMA terminal count interrupt status
//
// We don't want this function optimized as the compiler will code the I/O access as
// an 8 bit read instead of a 32 bit read (this is specific to Microsoft's ARM compiler).
#pragma optimize( "", off )
extern "C" BOOL GetTCStatus(PGET_TC_PARAMS pParams, PGET_TC_RESULT pResults)
{
DEBUGMSG(1, (TEXT("+GetTCStatus()\r\n")));
if( !fDMAInitialised )
{
DEBUGMSG(DMA_ZONE_OPT, (TEXT("AllocateDMAChannel: DMA not initialised\r\n")));
return FALSE;
}
// Read the DMA terminal count interrupt status
pResults->ucTCStatus = (UCHAR)pDMACRegs->DMACIntTCStatus;
DEBUGMSG(1, (TEXT("-GetTCStatus - 0x%X\r\n"), pResults->ucTCStatus));
return TRUE;
}
#pragma optimize( "", on )
//
// ClearTCStatus - Clears the DMA terminal count interrupt status
//
extern "C" BOOL ClearTCStatus(PCLEAR_TC_PARAMS pParams, PCLEAR_TC_RESULT pResults)
{
DEBUGMSG(1, (TEXT("+ClearTCStatus(0x%X)\r\n"), pParams->ucTCStatusMask));
if( !fDMAInitialised )
{
DEBUGMSG(DMA_ZONE_OPT, (TEXT("AllocateDMAChannel: DMA not initialised\r\n")));
return FALSE;
}
// Clear the DMA terminal count interrupt status
pDMACRegs->DMACIntTCClear = (DWORD)pParams->ucTCStatusMask;
DEBUGMSG(1, (TEXT("-ClearTCStatus\r\n")));
return TRUE;
}
//
// AddLLIEntry - Add a new entry to the DMA transfer list
// Each list entry transfer size must equal the virtual memory page size as pages may
// be scattered throughout physical memory space.
// As the DMAC cannot quite transfer a page in one go (with a byte wide transfer) we
// must add an additional list entry for each page to make up the difference.
//
void AddLLIEntry(UCHAR ucDMAChannel, DWORD dwPage, PDWORD pdwSourceBuffer,
PDWORD pdwDestBuffer, DWORD dwTransferSize)
{
DWORD dwTransfers;
volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;
// If the source is incrementing we need to update the source address
if(DMAInfo.DMAChannels[ucDMAChannel].fIncrementSource)
if(dwTransferSize == (DWORD)-1)
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwSourceAddress = pdwSourceBuffer[dwPage] + (PAGE_SIZE-1);
else
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwSourceAddress = pdwSourceBuffer[dwPage];
else
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwSourceAddress = pdwSourceBuffer[0];
// If the destination is incrementing we need to update the destination address
if(DMAInfo.DMAChannels[ucDMAChannel].fIncrementDest)
if(dwTransferSize == (DWORD)-1)
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwDestAddress = pdwDestBuffer[dwPage] + (PAGE_SIZE-1);
else
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwDestAddress = pdwDestBuffer[dwPage];
else
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwDestAddress = pdwDestBuffer[0];
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA list entry - source addr = 0x%X dest addr = 0x%X\r\n"),
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwSourceAddress,
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwDestAddress));
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwControl = pDMACChannelRegs->DMACCxControl &
~(DWORD)DMAC_TRANSFER_SIZE; // Copy our existing control settings
// Adjust the size to the number of transfers required
switch(DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth) {
case TRANSFER_WIDTH_BYTE:
dwTransfers = dwTransferSize;
if(dwTransferSize == (DWORD)PAGE_SIZE)dwTransfers--; // One less transfer for a page size of bytes
// Link the previous list entry to this one, Versatile must use AHB 2
if(dwPage>0) DMAInfo.DMAChannels[ucDMAChannel].pPrevLLIEntry->pNextEntry = (PLLI_ENTRY) ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntryPhys | DMAC_LLI_LM);
break;
case TRANSFER_WIDTH_WORD:
dwTransfers = dwTransferSize/sizeof(WORD);
// Link the previous list entry to this one, Versatile must use AHB 2
if(dwPage>1) DMAInfo.DMAChannels[ucDMAChannel].pPrevLLIEntry->pNextEntry = (PLLI_ENTRY) ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntryPhys | DMAC_LLI_LM); // Link the previous list entry to this one, use AHB 2
break;
case TRANSFER_WIDTH_DWORD:
dwTransfers = dwTransferSize/sizeof(DWORD);
// Link the previous list entry to this one, Versatile must use AHB 2
if(dwPage>1) DMAInfo.DMAChannels[ucDMAChannel].pPrevLLIEntry->pNextEntry = (PLLI_ENTRY) ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntryPhys | DMAC_LLI_LM); // Link the previous list entry to this one, use AHB 2
break;
} /* switch(DMAINFO.DMAChannels[]) */
// Set the number of DMA transfers in the list entry
if(dwTransferSize == (DWORD)-1) {
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwControl |= 1; // Just the one transfer
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA list entry - DMA transfers = 0x01\r\n")));
} else {
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry->dwControl |= dwTransfers; // Set the number of transfers
DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA list entry - DMA transfers = 0x%X\r\n"), dwTransfers));
} /* if(dwTransferSize == (DWORD)-1) */
DMAInfo.DMAChannels[ucDMAChannel].pPrevLLIEntry = DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry; // This is now the previous list entry
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntry++; // Point to the next list entry
DMAInfo.DMAChannels[ucDMAChannel].pNextLLIEntryPhys++; // Update the physical list pointer as well
}
//
// GetSysIntrMappings - The SYSINTR mappings are performed dynamically.
// This is an accessor function that will allow
// the mapping to be accessed from a module external the the dma.cpp module.
// It returns a pointer to the mapping value.
//
extern "C" BOOL GetSysIntrMappings(DMA_GLOB_SYSINTR * pdwSysIntr, UCHAR ucDMAChannel)
{
/* Range check - bail out if out of range */
if(ucDMAChannel >= MAX_DMA_CHANNELS)
return FALSE;
/* Return the interrupt ID */
*pdwSysIntr = (DMA_GLOB_SYSINTR)DMAInfo.DMAChannels[ucDMAChannel].dwDMASysIntr;
return TRUE;
}
//
// GetActiveDmaChannel - We need to find out which channel has mapped
// to which SYSINTR. We have stored DMA channel->SYSINTR
// but we do not have the reciprocal data stored (SYSINTR->DMA Channel)
// This function indexes each channel in the DMAInfo structure
// Until it finds a match an then returns the channel number.
//
extern "C" BOOL GetActiveDmaChannel(DWORD * pdwSysIntr, DWORD * pdwActiveChannel)
{
/* Count variable */
UCHAR ucChannel;
if (!fDMAInitialised) { /* not present */
return FALSE;
}
/* Check parameters passed by reference for validity */
if(NULL == pdwSysIntr) {
DEBUGMSG(1, (TEXT("[BAD PARAMS]GetActiveChannel\r\n")));
return FALSE;
}
/* Look through each DMA channel until we find a match */
for(ucChannel=0;ucChannel<MAX_DMA_CHANNELS;ucChannel++) {
if(*pdwSysIntr==DMAInfo.DMAChannels[ucChannel].dwDMASysIntr) {
break; /* We have a match */
}
}
/* We were within the valid range of channels available if this is true */
if(MAX_DMA_CHANNELS!=ucChannel) {
*pdwActiveChannel=ucChannel;
return TRUE;
}
else /* We did not find a matching channel so set up a failed value */
{
/* This value can be used by the calling function */
*pdwActiveChannel=0xFF;
}
/* Early returns mean that we are in a failure mode at this point */
return FALSE;
}
/* end of file DMA.CPP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -