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

📄 dma.cpp

📁 ARM9基于WINDOWSCE的BSP源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_DPER;
    pDMACChannelRegs->DMACCxConfiguration |= 
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucDestDevice << DMAC_DPER_SHIFT);
    // Setup the source device
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_SPER;
    pDMACChannelRegs->DMACCxConfiguration |= 
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucSourceDevice << DMAC_SPER_SHIFT);
    // Setup the flow control
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_FLOW;
    pDMACChannelRegs->DMACCxConfiguration |= 
        ((DWORD)DMAInfo.DMAChannels[ucDMAChannel].ucFlowControl << DMAC_FLOW_SHIFT);

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("-InitializeDMAChannel\r\n")));

    return TRUE;
}

//
// FreeDMAChannel - Frees the specified DMA channel
//
extern "C" BOOL FreeDMAChannel(PFREE_DMA_PARAMS pParams, PFREE_DMA_RESULT pResults)
{
    UCHAR   ucDMAChannel;
    volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
    pvstSP810Regs pstSP810 = (pvstSP810Regs)(VA_SC_BASE);

    DEBUGMSG(1, (TEXT("+FreeDMAChannel(channel %d)\r\n"), pParams->ucChannelNumber));

    ucDMAChannel = pParams->ucChannelNumber;
    pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;

    // Disable the DMA channel to ensure no more transfers can occur on it
    pDMACChannelRegs->DMACCxConfiguration &= ~(DWORD)DMAC_CHCONFIG_E;

    DMAInfo.DMAChannels[ucDMAChannel].fInUse = FALSE;   // Set this channel to 'free'
   
    DEBUGMSG(1, (TEXT("-FreeDMAChannel\r\n")));

    // Disable the DMA's peripheral clock if there are no more channels allocated
    for(ucDMAChannel=0; ucDMAChannel<MAX_DMA_CHANNELS; ucDMAChannel++)
    {
        if(DMAInfo.DMAChannels[ucDMAChannel].fInUse) break;
    }
    DEBUGMSG(1, (TEXT("Freed a channel, no of channels = %d\r\n"),(DWORD)ucDMAChannel));
        
    if(MAX_DMA_CHANNELS == ucDMAChannel)
    {
        DEBUGMSG(1, (TEXT("Switching DMA clock off.\r\n")));
 //       pstSP810->SCPERDIS = HCLKDMA;

    }


    return TRUE;
}

//
// FreeDmaSysIntr - Removes the SYSINTR mapping from the chosen channel
//
extern "C" BOOL FreeDmaSysIntr(PFREE_DMA_SYSINTR_PARAMS pParams, PFREE_DMA_SYSINTR_RESULT pResults )
{
    DEBUGMSG(1, (TEXT("+FreeDmaSysIntr(Freeing Channel: %d)\r\n"), pParams->ucChannelNumber));

    /* Channel number out of range */
    if(pParams->ucChannelNumber >= MAX_DMA_CHANNELS)
        return FALSE; 

    /* Attempting to remove an unmapped SYSINTR */
    if(SYSINTR_UNDEFINED == DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr) {
        DEBUGMSG(1, (TEXT("[ERR]FreeDmaSysIntr(Chennel not mapped)\r\n")));
        return FALSE;
    }
    
    /* Remove from OAL mapping */
    if(ERROR_SUCCESS == OEMReleaseSysIntr(DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr))
    {
        DEBUGMSG(1, (TEXT("FreeDmaSysIntr(SYSINTR: %d now free)\r\n"), 
            DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr));
        
        /* Clear in DMAInfo structure */
        DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr=SYSINTR_UNDEFINED;
        return TRUE;
    } else {
        DEBUGMSG(1, (TEXT("[ERR]FreeDmaSysIntr(SYSINTR: %d unable to free)\r\n"), 
            DMAInfo.DMAChannels[pParams->ucChannelNumber].dwDMASysIntr));
    }

    /* Failed to remove mapping */
    return FALSE;
}

//
// StartDMATransfer - Starts a DMA transfer between two devices
//
extern "C" BOOL StartDMATransfer(PSTART_DMA_PARAMS pParams, PSTART_DMA_RESULT pResults)
{
    UCHAR   ucDMAChannel;
    volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;
    PDWORD  pdwSourceBuffer;
    PDWORD  pdwDestBuffer;
    DWORD   dwTotalSize, dwListOffset , control;	

    if (!fDMAInitialised) { /* not present */
        DEBUGMSG(1, (TEXT("NO DMA blocking StartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));
        return FALSE;
        }

    ucDMAChannel = pParams->ucChannelNumber;

    if (ucDMAChannel >= MAX_DMA_CHANNELS) { /* Illegal */
        DEBUGMSG(1, (TEXT("ERROR : DMA blocked: Illegal channel %d\r\n"), pParams->ucChannelNumber));
        return FALSE;
        }
		
    DEBUGMSG(1, (TEXT("+StartDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));

    // Save the parameters in case we need to restart the transfer
    dwTotalSize = pParams->dwTransferSize;
    DMAInfo.DMAChannels[ucDMAChannel].dwTransferSize = pParams->dwTransferSize;
    DMAInfo.DMAChannels[ucDMAChannel].pdwSourceBuffer = pParams->pdwSourceBuffer;
    DMAInfo.DMAChannels[ucDMAChannel].pdwDestBuffer = pParams->pdwDestBuffer;

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: source buffer = 0x%X\r\n"), pParams->pdwSourceBuffer));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: dest buffer = 0x%X\r\n"), pParams->pdwDestBuffer));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: total size = 0x%X\r\n"), dwTotalSize));

    pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;

    // Store the buffer locations
    pdwSourceBuffer = pParams->pdwSourceBuffer;
    pdwDestBuffer = pParams->pdwDestBuffer;

    // Setup the DMA control register
    pDMACChannelRegs->DMACCxControl &= ~((DWORD)DMAC_TRANSFER_SIZE);  // Clear the size
	control = pDMACChannelRegs->DMACCxControl&(~( (DWORD)DMAC_TRANSFER_SIZE | DMAC_CTRL_I ));
	control |= DMAC_CTRL_PRIV;
	//pDMACChannelRegs->DMACCxControl |= DMAC_CTRL_PRIV;  // We are always in privileged mode

    // Setup the address registers to the first physical address
//    pDMACChannelRegs->DMACCxSrcAddr = pdwSourceBuffer[0];
//    pDMACChannelRegs->DMACCxDestAddr = pdwDestBuffer[0];
	
	PLLI_ENTRY lli_vir , lli_phy;
	dwListOffset = ucDMAChannel * sizeof(LLI_ENTRY) * MAX_DMA_LIST_ENTRIES;
	lli_vir = (PLLI_ENTRY)(DMA_LIST_BUFFER_VIRT + dwListOffset);
	lli_phy = (PLLI_ENTRY)(DMA_LIST_BUFFER_PHYS + dwListOffset);
	
	DWORD maxtransfer , firsttransfer , totaltrans;
	DWORD flowcontrol = DMAInfo.DMAChannels[ucDMAChannel].ucFlowControl ;
	
	if( flowcontrol == FLOW_PER_MEM_DMAC || flowcontrol == FLOW_PER_MEM_SOURCE) 
	{		
		DWORD singlesize ;
		if( DMAInfo.DMAChannels[ucDMAChannel].ucDestWidth == TRANSFER_WIDTH_DWORD )
			singlesize = sizeof(DWORD);
		else if(DMAInfo.DMAChannels[ucDMAChannel].ucDestWidth == TRANSFER_WIDTH_WORD )
			singlesize = sizeof(WORD);
		else 
			singlesize = sizeof(BYTE);
		maxtransfer = PAGE_SIZE/singlesize ;
		firsttransfer = (PAGE_SIZE - BYTE_OFFSET( pdwDestBuffer[0]))/singlesize;
		pdwDestBuffer[0] &= ~(PAGE_SIZE-1);
		totaltrans = dwTotalSize/singlesize;
		
		DWORD lastleft = firsttransfer , totrans;
		do
		{			
			lli_vir->dwSourceAddress = pdwSourceBuffer[0];
			lli_vir->dwDestAddress = (DWORD)(*pdwDestBuffer) + PAGE_SIZE - lastleft*singlesize;
			
			totrans = min( totaltrans , min( lastleft , DMAC_TRANSFER_SIZE ));
	
			lastleft -= totrans;				
			totaltrans -= totrans;
			
			lli_vir->dwControl = control | totrans;
			lli_vir->pNextEntry = (PLLI_ENTRY)( (DWORD)(lli_phy+1) | DMAC_LLI_LM);
			if( !lastleft )
			{
				pdwDestBuffer ++;			
				lastleft = maxtransfer;
			}
			lli_vir ++ ; lli_phy ++ ;
		}while( totaltrans );
	}
	else if( flowcontrol == FLOW_MEM_PER_DMAC || flowcontrol == FLOW_MEM_PER_DEST )
	{		
		DWORD singlesize;		
		if( DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth == TRANSFER_WIDTH_DWORD )
			singlesize = sizeof(DWORD);
		else if(DMAInfo.DMAChannels[ucDMAChannel].ucSourceWidth == TRANSFER_WIDTH_WORD )
			singlesize = sizeof(WORD);
		else 
			singlesize = sizeof(BYTE);
		firsttransfer = (PAGE_SIZE - BYTE_OFFSET( pdwSourceBuffer[0]))/singlesize;
		pdwSourceBuffer[0] &= ~(PAGE_SIZE-1);
		maxtransfer = PAGE_SIZE/singlesize;
		totaltrans = dwTotalSize/singlesize;
		
		DWORD lastleft = firsttransfer , totrans;
		do
		{
			lli_vir->dwDestAddress = pdwDestBuffer[0];
			lli_vir->dwSourceAddress = (DWORD)(*pdwSourceBuffer) + PAGE_SIZE - lastleft*singlesize;
			
			totrans = min( totaltrans , min( lastleft , DMAC_TRANSFER_SIZE ));
			
			lastleft -= totrans;				
			totaltrans -= totrans;
			lli_vir->dwControl = control | totrans;
			lli_vir->pNextEntry = (PLLI_ENTRY)( (DWORD)(lli_phy+1) | DMAC_LLI_LM);
			if( !lastleft )
			{
				pdwSourceBuffer ++;			
				lastleft = maxtransfer;
			}
			lli_vir ++ ; lli_phy ++ ;
		}while( totaltrans );				
	}
	else if( flowcontrol == FLOW_MEM_MEM_DMAC )
	{
		DWORD totrans;
		totaltrans = dwTotalSize/sizeof(DWORD);
		do
		{
			lli_vir->dwDestAddress = *pdwDestBuffer++;
			lli_vir->dwSourceAddress = *pdwSourceBuffer++;
			
			totrans = min( totaltrans , PAGE_SIZE/sizeof(DWORD) );
			totaltrans -= totrans;
			lli_vir->dwControl = control | totrans;
			lli_vir->pNextEntry = (PLLI_ENTRY)( (DWORD)(lli_phy+1) | DMAC_LLI_LM);
			lli_vir ++ ; lli_phy ++ ;
		}while( totaltrans );
	}
	lli_vir --;
	lli_vir->pNextEntry = 0;
	lli_vir->dwControl |= DMAC_CTRL_I;
	
	lli_vir = (PLLI_ENTRY)(DMA_LIST_BUFFER_VIRT + dwListOffset);
	pDMACChannelRegs->DMACCxSrcAddr = lli_vir->dwSourceAddress;
	pDMACChannelRegs->DMACCxDestAddr = lli_vir->dwDestAddress;
	pDMACChannelRegs->DMACCxLLI = (DWORD)lli_vir->pNextEntry;
	pDMACChannelRegs->DMACCxControl = lli_vir->dwControl;
	
	// Flush the data cache as the DMA controller needs the LLI information in
    // DMA accessible memory
    OEMCacheRangeFlush(NULL, 0, CACHE_SYNC_DISCARD);

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Source = 0x%X\r\n"), pDMACChannelRegs->DMACCxSrcAddr));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Dest = 0x%X\r\n"), pDMACChannelRegs->DMACCxDestAddr));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: LLI = 0x%X\r\n"), pDMACChannelRegs->DMACCxLLI));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Control = 0x%X\r\n"), pDMACChannelRegs->DMACCxControl));
    DEBUGMSG(DMA_ZONE_OPT, (TEXT("DMA transfer: Config = 0x%X\r\n"), pDMACChannelRegs->DMACCxConfiguration));

    // Enable the channel, this should start the transfer or allow a peripheral to do so

    pDMACChannelRegs->DMACCxConfiguration |= DMAC_CHCONFIG_E;

    DEBUGMSG(1, (TEXT("-StartDMATransfer\r\n")));


    return TRUE;
}

//
// HaltDMATransfer - Halts 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 HaltDMATransfer(PHALT_DMA_PARAMS pParams, PHALT_DMA_RESULT pResults)
{
    UCHAR   ucDMAChannel;
    volatile PDMAC_CHANNEL_REGS pDMACChannelRegs;

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("+HaltDMATransfer(channel %d)\r\n"), pParams->ucChannelNumber));

    ucDMAChannel = pParams->ucChannelNumber;
    pDMACChannelRegs = DMAInfo.DMAChannels[ucDMAChannel].pDMACChannelRegs;

    // Halt any transfer (don't disable the channel as this will lose data!)
    pDMACChannelRegs->DMACCxConfiguration |= (DWORD)DMAC_CHCONFIG_H;

    // Wait for channel to become inactive
    while(pDMACChannelRegs->DMACCxConfiguration&(DWORD)DMAC_CHCONFIG_A);

    DEBUGMSG(DMA_ZONE_OPT, (TEXT("-HaltDMATransfer\r\n")));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -