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

📄 dma.cpp

📁 ARM9基于WINDOWSCE的BSP源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    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 + -