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

📄 dma.c

📁 编译环境为PB,或AK,实现27x平台上对DMA的控制,由于270平台上DMA都处在同一个一级中断下,要使用单个的DMA通道,通常也可以在OAL重新映射其中断号,但比较费事,本驱动实现对DMA的管理,
💻 C
📖 第 1 页 / 共 3 页
字号:
    XLLP_DMAC_ALIGNMENT_T   *aLign
)
{

    XLLP_UINT32_T   i;
    XLLP_UINT32_T   maxPages;
	XLLP_UINT32_T   *aPages;
	BOOL            fResult;
	XLLP_UINT32_T   firstPageOffset;
	XLLP_UINT32_T   lastPageOffset;
    XLLP_STATUS_T   status=XLLP_STATUS_SUCCESS;

	//
	// In case there are errors, that's what we shall return
	//
	*pBufferMdl = NULL;

    if(!pBuffer)
		return XLLP_ERR_MEM_ALLOC;
    
	//
	// Find maximum number of pages that can be occupied by this buffer
	//
	maxPages = OSGetMaxPages(pBuffer, bufferLength);
	aPages = (XLLP_UINT32_T*) OSMemAlloc( maxPages*sizeof(XLLP_UINT32_T));
	if(!aPages)
		return XLLP_ERR_MEM_ALLOC;

	//
	// Get list of all physical pages occupied by this buffer
	//
	fResult = OSLockPhysicalPages(pBuffer, bufferLength, aPages, LOCKFLAG_WRITE);
	if (!fResult)
    {
        RETAILMSG(1,(TEXT("DMA:>XllpDmacCreateBufferMdl Error..\r\n")));
        status = XLLP_ERR_MEM_ALLOC;
		goto Label_CreateBufferMdl;			 
    }

	//
	// Allocate space for MDL for the number of entries we calculated above
	//
    if( (*pBufferMdl = XllpDmacAllocateMdl(maxPages)) == NULL)
	{
		fResult = XLLP_ERR_MEM_ALLOC;
		goto Label_CreateBufferMdl;
	}

	//
	// Initialize entries in the MDL
	// The buffer can be starting from middle of a page and also ending in middle of a page
	//
	firstPageOffset					= ((XLLP_UINT32_T)pBuffer & (PAGE_SIZE-1));
	lastPageOffset					= (((XLLP_UINT32_T)pBuffer + bufferLength) & (PAGE_SIZE-1));
	(*pBufferMdl)->numEntries		= maxPages;
	(*pBufferMdl)->bufferPtr		= pBuffer;

	//
	// Add the starting page offset for the first physical block
	// Set the length to buffer length for default case of no page breaks in between
	// If there are page breaks, then the length will get adjusted below.
	//
	(*pBufferMdl)->physBlock[0].physicalAds	= (aPages[0] + firstPageOffset);
	(*pBufferMdl)->physBlock[0].blockLength	= bufferLength;
		
	if(maxPages > 1)
	{
		//
		// Since there are page breaks, set the size of first block to only the size on first page
		//		
		(*pBufferMdl)->physBlock[0].blockLength = (PAGE_SIZE - firstPageOffset);
		for(i=1; i<maxPages-1; ++i)
		{			
			//
			// We got a page break
			// Set the starting address of next block
			// Initialize the size of next physical block to PAGE_SIZE
			//		
			(*pBufferMdl)->physBlock[i].physicalAds = aPages[i];
			(*pBufferMdl)->physBlock[i].blockLength = PAGE_SIZE;			
		}

		//
		// Adjust the size of last block with the last page offset in case the 
		// buffer ends in middle of a page
		//
		(*pBufferMdl)->physBlock[i].physicalAds		= aPages[i];			
		(*pBufferMdl)->physBlock[i].blockLength		= lastPageOffset == 0 ? PAGE_SIZE : lastPageOffset;
	}   
   	
    //
    // If physical address of any of the blocks does not start at 8 byte boundary we may
    // need to turn on the alignment flag
    //
    *aLign = XLLP_DMAC_ALIGNMENT_OFF;
    for(i=1; i<maxPages-1; ++i)
        if ((*pBufferMdl)->physBlock[i].physicalAds & 0x7)
            *aLign = XLLP_DMAC_ALIGNMENT_ON;

Label_CreateBufferMdl:
	OSMemFree(aPages);

	return XLLP_STATUS_SUCCESS;
}


//******************************************************************************
//
// Function Name: XllpDmacAllocDmaDescriptorList
//
// Description: Allocates a DMA descriptor list for the buffer
//  			   
//  
// Input Arguments:
//  numEntries:     Number of descriptor entries for which space needs to be allocated
//                
// Output Arguments:
//
// Return Value: 
//  pDmaDescInfo:   Pointer to structure which contains information about allocated
//                  DMA descriptors.
//
// Notes:
//  The allocated DMA descriptors will be aligned on 16 byte physical boundaries
//
//*******************************************************************************
PDmaDescInfo  XllpDmacAllocDmaDescriptorList
(
	XLLP_UINT32_T		numEntries
)
{
    XLLP_UINT32_T       memSize;
    XLLP_UINT32_T       descAlignOffset;    
    PDmaDescInfo        pDmaDescInfo;

    //
    // Allocate an extra descriptor so that we can align the decriptors appropriately
    // The DMA descriptors need to be aligned on 16 byte boundaries.
    //
    memSize = sizeof(DmaDescInfo) + ((numEntries + 1) * sizeof(XLLP_DMAC_DESCRIPTOR_T));              
       
    pDmaDescInfo = (PDmaDescInfo) OSMemAlloc( memSize );
    if(pDmaDescInfo)
    {
        pDmaDescInfo->memPtr        = (XLLP_UINT8_T*)pDmaDescInfo;
        pDmaDescInfo->numEntries    = numEntries;
        descAlignOffset             = (XLLP_UINT32_T)pDmaDescInfo + sizeof(DmaDescInfo) + 
                                       sizeof(XLLP_DMAC_DESCRIPTOR_T);
        descAlignOffset             &= XLLP_DMAC_ALIGN_MASK;
        pDmaDescInfo->pDmaDescList  = (P_XLLP_DMAC_DESCRIPTOR_T) descAlignOffset;
    }

	return (pDmaDescInfo);
}

//******************************************************************************
//
// Function Name: XllpDmacFreeDescriptorList
//
// Description: Frees a previously allocated DMA descriptor list for the buffer
//  			   
//  
// Input Arguments:
//  pDmaDescInfo:   Pointer to structure which contains information about allocated
//                  DMA descriptors.
//	                 
// Output Arguments:
//
// Return Value: 
//
// Notes:
//
//
//*******************************************************************************
VOID  XllpDmacFreeDescriptorList
(
	PDmaDescInfo        pDmaDescInfo
)
{         
    OSMemFree( pDmaDescInfo->memPtr );    
}

//******************************************************************************
//
// Function Name: XllpDmacGetXfrDone
//
// Description: Gets the number of bytes transferred for a particular descriptor
//  			list   
//  
// Input Arguments:
//
//	                 
// Output Arguments:
//
// Return Value: 
//
// Notes:
//
//
//*******************************************************************************
XLLP_STATUS_T XllpDmacGetXfrDone
(
    XLLP_DMAC_CHANNEL_T             dmaChannel,    
    PBufferMdl                      pBufferMdl,
    XLLP_DMAC_TRANSFER_TYPE_T       transferType,
    XLLP_UINT32_T                   *bytesXferred
)
{

    XLLP_UINT32_T       currAddress;
    XLLP_UINT32_T       i;
    XLLP_UINT32_T       bytesDone=0;
    XLLP_UINT32_T       bytesRem=0;
    PPhysBlock          pPhys=pBufferMdl->physBlock;
    *bytesXferred = 0;
   
    if(transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM)    
        currAddress = pDmacHandle->DDG[dmaChannel].DTADR;            
    else
        currAddress = pDmacHandle->DDG[dmaChannel].DSADR;        

    for(i=0;i<pBufferMdl->numEntries;++i)
    {
        bytesDone += pPhys[i].blockLength;
        if(currAddress >= pPhys[i].physicalAds && 
           currAddress <= pPhys[i].physicalAds + pPhys[i].blockLength )
           break;        
    }

    if(i==pBufferMdl->numEntries)
    {
        RETAILMSG(1,(TEXT("DMA:>XllpDmacGetXfrDone bad Mdl. dmaChan=%d \r\n"), dmaChannel ));
        return XLLP_ERR_BAD_MDL;
    }

    bytesRem        = XllpDmacGetRemainingXfrLength(dmaChannel);
    bytesDone      -= bytesRem;
    *bytesXferred   = bytesDone;

    RETAILMSG(1,(TEXT("DMA:>XllpDmacGetXfrDone dmaChan=%d bytesDone=%d curAds=0x%08x \r\n"), dmaChannel, bytesDone, currAddress));
    return XLLP_STATUS_SUCCESS;
}


//******************************************************************************
//
// Function Name: XllpDmacSetupTransfer
//
// Description: Sets up a complete transfer operation
//  
// Input Arguments:
//  aChannelPriority    DMA channel priority
//  pUserBuffer         Pointer to user buffer
//  xferByteCount       Number of bytes to be transferred
//  transferType        Transfer type
//  deviceAddress       Address on device. This can be 4 byte aligned
//  aDeviceDrcmr        Device DRCMR for mapping the DMA Channel
//  dmaIntHandler       DMA interrupt handle to be called on completion or errors
//  pUserContext        User context to be passed back in callback
//  intEnableBitmask    Bitmask of interrupts that can be enabled during the transfer
//  descBasedXfr        Descriptor based transfer or not.
//  pCmd                Pointer to value of DCMD register for current operation
//
//	                 
// Output Arguments:
//    dmaChannel        DMA channel allocated for current operation
//    pUserDmaDescInfo  UserDMA descriptor information
//    pUserBufferMdl    Mdl decribing the user buffer
//
// Return Value: 
//      XLLP_STATUS_SUCCESS:  on success
//
// Notes: This is a workhorse routine which sets up either descriptor based
//        or non-descriptor based transfer operation.  
//
//*******************************************************************************
XLLP_STATUS_T XllpDmacSetupTransfer
(    
    XLLP_DMAC_CHANNEL_PRIORITY_T    aChannelPriority,
    XLLP_UINT8_T*                   pUserBuffer,
    XLLP_UINT32_T                   xferByteCount,
    XLLP_DMAC_TRANSFER_TYPE_T       transferType,
    XLLP_UINT32_T                   deviceAddress,
    XLLP_DMAC_DEVICE_T              aDeviceDrcmr,
    DeviceDmaIntHandler             dmaIntHandler,
    PVOID                           pUserContext,
    XLLP_UINT32_T                   intEnableBitmask,
    XLLP_UINT32_T                   descBasedXfr,
    XLLP_DMAC_COMMAND_T*            pCmd,
    XLLP_DMAC_CHANNEL_T*            dmaChannel,
    PDmaDescInfo*                   pUserDmaDescInfo,
    PBufferMdl*                     pUserBufferMdl
)
{

    XLLP_STATUS_T           status;
    XLLP_DMAC_CHANNEL_T     aChannel=XLLP_INVALID_DMA_CHANNEL;
    PBufferMdl              pBufferMdl=NULL;
    PDmaDescInfo            pDmaDescInfo=NULL;
    XLLP_DMAC_ALIGNMENT_T   aLign=XLLP_DMAC_ALIGNMENT_ON;
    XLLP_UINT32_T           physAds;
    
    physAds = XllpDmacGetPhysicalAds(pUserBuffer);  
    //RETAILMSG(1,(TEXT("DMA: XllpDmacSetupTransfer physAds=0x%08x devAds=0x%08x \r\n"), physAds, deviceAddress));    

    //
    // Allocate a DMA channel based on specified user priority
    //
    status = XllpDmacAllocChannel(&aChannel, aChannelPriority );
    if (status != XLLP_STATUS_SUCCESS)
        return status;

    //
    // Register a handler for the allocated DMA channel
    //
    *dmaChannel = (UINT32)(aChannel);
    status = XllpDmacRegisterDeviceHandler(aChannel, dmaIntHandler,pUserContext);
    if (status != XLLP_STATUS_SUCCESS)
        goto Label_CleanSetupDmacTransfer;


    if(descBasedXfr)
    {
        //
        // Create a MDL for the buffer
        //
        status = XllpDmacCreateBufferMdl(pUserBuffer, xferByteCount, &pBufferMdl, &aLign);
        if (status != XLLP_STATUS_SUCCESS)
            goto Label_CleanSetupDmacTransfer;

        //
        // Create the DMA descriptor list for this buffer
        //
        status = XllpDmacCreateDescriptorListFromMdl(pBufferMdl, 
                                                     transferType, 
                                                     &pDmaDescInfo, 
                                                     deviceAddress, 
                                                     pCmd);
    


        if (status != XLLP_STATUS_SUCCESS)
            goto Label_CleanSetupDmacTransfer;
 	
        //
        // Load the DMA descriptors into the DMA registers
        //
        XllpDmacCfgChannelDescTransfer((XLLP_DMAC_DESCRIPTOR_T*)XllpDmacGetPhysicalAds((void*) pDmaDescInfo->pDmaDescList), 
                                       aChannel, 
                                       aDeviceDrcmr, 
                                       aLign);

        //
        // Just need to call XllpDmacStartTransfer to initiate transfer at this point
        // Return the DMA descriptor information, since the user will have to free this later on
        //
        *pUserDmaDescInfo = pDmaDescInfo;        
        *pUserBufferMdl   = pBufferMdl;
    }    

    if(!descBasedXfr)
    {
        XllpDmacCfgChannelNoDescTransfer(((transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM) ? deviceAddress : physAds),
		    				  			 ((transferType==XLLP_DMAC_TRANSFER_IO_TO_MEM) ? physAds : deviceAddress),
			    			  			 pCmd,
                                         aChannel,
                                         aDeviceDrcmr, 
                                         aLign);
    }

    //
    // Enable specified interrupts for the DMA channel
    //    
    status = XllpDmacEnableInterrupts(aChannel, intEnableBitmask);
    if (status != XLLP_STATUS_SUCCESS)
        goto Label_CleanSetupDmacTransfer;

    //
    // Just need to call XllpDmacStartTransfer to initiate transfer at this point    
    //
    return XLLP_STATUS_SUCCESS;
    
Label_CleanSetupDmacTransfer:

    if(pBufferMdl)
        XllpDmacFreeBufferMdl(pUserBuffer, xferByteCount, pBufferMdl);

    if (pDmaDescInfo)
        XllpDmacFreeDescriptorList(pDmaDescInfo);

    if (aChannel != XLLP_INVALID_DMA_CHANNEL)
    {
        XllpDmacDisableInterrupts(aChannel, XLLP_ALL_INTERRUPTS_SOURCE);
        XllpDmacUnregisterDeviceHandler(aChannel);  
        XllpDmacFreeChannel(aChannel, aDeviceDrcmr);
    }

    return status;
}

⌨️ 快捷键说明

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