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

📄 dmadrv.c

📁 NXP LPC3000系列 wince BSP包
💻 C
📖 第 1 页 / 共 2 页
字号:
//*********************************************************************
//* Software that is described herein is for illustrative purposes only  
//* which provides customers with programming information regarding the  
//* products. This software is supplied "AS IS" without any warranties.  
//* NXP Semiconductors assumes no responsibility or liability for the 
//* use of the software, conveys no license or title under any patent, 
//* copyright, or mask work right to the product. NXP Semiconductors 
//* reserves the right to make changes in the software without 
//* notification. NXP Semiconductors also make no representation or 
//* warranty that such application will be suitable for the specified 
//* use without further testing or modification. 
//*
//* Copyright NXP Semiconductors
//*********************************************************************
//
// dmadrv.c
//
// DMA driver
//

#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include "bsp.h"
#include "dmadrv.h"

// Number of DMA list entries
#define DMALISTENTRIES 16

// DMA list control structure
typedef struct
{
	DMAC_REGS_T *pDMARegs;   // Pointer to DMA registers
	DMAINFO_T dmaInfo;       // Saved DMA configuration info
	UINT32 chMaskBit;        // Preshifted channel bit
	DWORD savedControl;      // Control word used in LLIs
	DWORD savedConfig;       // Saved channel configuration value
	DWORD xferSize;          // Transfer size (in bytes)
	DMAC_CHAN_T *pDMAChan;

	// DMA linked list control data
	DMAC_LL_T *pDMAListVirt; // Virtual pointer to DMA list memory area
	DMAC_LL_T *pDMAListPhy;  // Physical pointer to DMA list memory area
	int GetListIdx;          // Next index for clearing a list
	int PutListIdx;          // Next index for placing a list
	int ListEntries;         // Number of entries currently in list
} DMADRVDATA_T;

//-----------------------------------------------------------------------------
//
// dmaStartDMA
//
// Start a DMA transfer
//
static void dmaStartDMA(DMADRVDATA_T *pDrvData,
						DWORD src,      // Physical address
				        DWORD dst,      // Physical address
						DWORD lli,      // Physical address
				        DWORD ctrl)     // Control word
{
	pDrvData->pDMAChan->src_addr = (UNS_32) src;
	pDrvData->pDMAChan->dest_addr = (UNS_32) dst;
	pDrvData->pDMAChan->lli = (UNS_32) lli;
	pDrvData->pDMAChan->control = ctrl;

	// Start transfer
	pDrvData->pDMAChan->config_ch |= DMAC_CTRL_ENABLE;
}

//-----------------------------------------------------------------------------
//
// dmaToPhy
//
// Converts a virtual DMA list address to a physical address
//
static DMAC_LL_T *dmaToPhy(DMADRVDATA_T *pDrvDat,
			               DMAC_LL_T *va)
{
	DWORD offset = 0;

	if ((DWORD) va != 0)
	{
		offset = (DWORD) va - (DWORD) pDrvDat->pDMAListVirt;
		offset = offset + (DWORD) pDrvDat->pDMAListPhy;
	}

	return (DMAC_LL_T *) offset;
}

//-----------------------------------------------------------------------------
//
// dmaToVirt
//
// Converts a physical DMA list address to a virtual address
//
static DMAC_LL_T *dmaToVirt(DMADRVDATA_T *pDrvDat,
			                DMAC_LL_T *pa)
{
	DWORD offset = 0;

	if ((DWORD) pa != 0)
	{
		offset = (DWORD) pa - (DWORD) pDrvDat->pDMAListPhy;
		offset = offset + (DWORD) pDrvDat->pDMAListVirt;
	}

	return (DMAC_LL_T *) offset;
}

//------------------------------------------------------------------------------
//
// dmaAllocList
//
// Allocate a space of DMA memory for a DMA linked list
//
DWORD dmaAllocate(DMASETUP_T *pDmaSetup,
				  DWORD buffSizeBytes)
{
	DMADRVDATA_T *pDrvData;
    PHYSICAL_ADDRESS pa;
    DMA_ADAPTER_OBJECT Adapter;
	DWORD bytesret;

	// Allocate space for the DMA control structure
	pDrvData = (DMADRVDATA_T *) malloc(sizeof(DMADRVDATA_T));
	if (pDrvData == NULL)
	{
		return 0;
	}

	// Setup some defaults
	pDrvData->pDMARegs = NULL;
	pDrvData->dmaInfo.irq = 0xFFFFFFFF;
	pDrvData->dmaInfo.dmaCh = pDmaSetup->dmaCh;
	pDrvData->dmaInfo.perID = pDmaSetup->perID;
	pDrvData->dmaInfo.pBuffPhy = 0;
	pDrvData->dmaInfo.pBuffVirt = (DWORD) NULL;
	pDrvData->dmaInfo.buffSize = buffSizeBytes;
	pDrvData->chMaskBit = _BIT(pDrvData->dmaInfo.dmaCh);
	pDrvData->savedControl = 0;
	pDrvData->savedConfig = 0;
	pDrvData->pDMAListVirt = NULL;
	pDrvData->pDMAListPhy = NULL;
	pDrvData->xferSize = 1;

	// Map space for DMA registers
	pa.HighPart = 0;
	pa.LowPart = DMA_BASE;
	pDrvData->pDMARegs = MmMapIoSpace(pa, sizeof (DMAC_REGS_T), FALSE);
	if (pDrvData->pDMARegs == NULL)
	{
        goto dmaErr;
	}

	// Enable the channel and clocking in the kernel
	if (KernelIoControl(IOCTL_LPC32XX_DMACHGET, &pDrvData->dmaInfo.dmaCh,
		sizeof(pDrvData->dmaInfo.dmaCh), &pDrvData->dmaInfo.irq,
		sizeof (pDrvData->dmaInfo.irq), &bytesret) == FALSE)
	{
		// Error setting up DMA channel
		pDrvData->dmaInfo.irq = 0xFFFFFFFF;
		goto dmaErr;
	}

	// Allocate space for the DMA buffers if buffers are requested
	if (buffSizeBytes != 0)
	{
	    memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
		Adapter.InterfaceType = Internal;
	    Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
		pDrvData->dmaInfo.pBuffVirt = (DWORD) HalAllocateCommonBuffer(&Adapter,
			(pDrvData->dmaInfo.buffSize), &pa, FALSE);
	    if (pDrvData->dmaInfo.pBuffVirt == (DWORD) NULL)
		{
	        goto dmaErr;
		}
		pDrvData->dmaInfo.pBuffPhy = pa.LowPart;
	}

	// Allocate space for the DMA list
    memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
    Adapter.InterfaceType = Internal;
    Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
    pDrvData->pDMAListVirt = (DMAC_LL_T *) HalAllocateCommonBuffer(&Adapter,
		(sizeof(DMAC_LL_T) * DMALISTENTRIES), &pa, FALSE);
    if (pDrvData->pDMAListVirt == NULL)
    {
        goto dmaErr;
    }
	pDrvData->pDMAListPhy = (DMAC_LL_T *) pa.LowPart;
    RETAILMSG(1, (TEXT("DMA list addr = (V)0x%x (P)0x%x\r\n"), pDrvData->pDMAListVirt, pDrvData->pDMAListPhy));

	// Setup sync and request
	pDrvData->pDMARegs->sync &= ~_BIT(pDrvData->dmaInfo.perID);

	// Save premade pointer to DMA channel registers
	pDrvData->pDMAChan = (DMAC_CHAN_T *) &pDrvData->pDMARegs->dma_chan[pDrvData->dmaInfo.dmaCh];

	// Make sure DMA is disabled
	dmaDisable((DWORD) pDrvData);

	// Clear initial channel values
	pDrvData->pDMAChan->src_addr = 0;
	pDrvData->pDMAChan->dest_addr = 0;
	pDrvData->pDMAChan->lli = 0;

	// Setup channel values
	dmaChanConfig((DWORD) pDrvData, pDmaSetup);

	// Reset DMA list
	dmaListReset((DWORD) pDrvData);

	return (DWORD) pDrvData;

dmaErr:
	dmaDeAllocate((DWORD) pDrvData);

	return 0;
}

//-----------------------------------------------------------------------------
//
// dmaDeAllocate
//
// Disables and deallocates a DMA channel used for peripheral operation
//
DWORD dmaDeAllocate(DWORD dmaData)
{
	DWORD bytesret;
    PHYSICAL_ADDRESS pa;
    DMA_ADAPTER_OBJECT Adapter;
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	if (pDrvData->pDMARegs != NULL)
	{
		// Disable DMA channel
		dmaDisable(dmaData);

		// Unmap DMA registers
		MmUnmapIoSpace((PVOID) pDrvData->pDMARegs,
			sizeof (DMAC_REGS_T));
	}

	// Remove DMA buffers
	if (pDrvData->dmaInfo.pBuffVirt == (DWORD) NULL)
	{
	    memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
	    Adapter.InterfaceType = Internal;
	    Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
		pa.HighPart = 0;
		pa.LowPart = pDrvData->dmaInfo.pBuffPhy;
		HalFreeCommonBuffer(&Adapter,
			(ULONG) (pDrvData->dmaInfo.buffSize), pa,
			(PVOID) pDrvData->dmaInfo.pBuffVirt, FALSE);
	}

	// Remove DMA list area
	if (pDrvData->pDMAListVirt != NULL)
	{
	    memset(&Adapter, 0, sizeof(DMA_ADAPTER_OBJECT));
	    Adapter.InterfaceType = Internal;
	    Adapter.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
		pa.HighPart = 0;
		pa.LowPart = (ULONG) pDrvData->pDMAListPhy;
		HalFreeCommonBuffer(&Adapter,
			(ULONG) (sizeof(DMAC_LL_T) * DMALISTENTRIES), pa,
			(PVOID) pDrvData->pDMAListVirt, FALSE);
	}

	// Free DMA channel in the kernel (also disables clocks)
	KernelIoControl(IOCTL_LPC32XX_DMACHFREE, &pDrvData->dmaInfo.dmaCh,
		sizeof(pDrvData->dmaInfo.dmaCh), NULL, 0, &bytesret);

	free(pDrvData);

	return TRUE;
}

//-----------------------------------------------------------------------------
//
// dmaGetInfo
//
// Returns DMA channel information
//
DMAINFO_T *dmaGetInfo(DWORD dmaData)
{
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	return &pDrvData->dmaInfo;
}

//-----------------------------------------------------------------------------
//
// dmaEnable
//
// Starts a DMA channel's data transfer
//
void dmaEnable(DWORD dmaData)
{
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	pDrvData->pDMAChan->config_ch |= DMAC_CHAN_ENABLE;
}

//-----------------------------------------------------------------------------
//
// dmaDisable
//
// Stops a DMA channel's data transfer
//
void dmaDisable(DWORD dmaData)
{
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	pDrvData->pDMAChan->config_ch &= ~DMAC_CHAN_ENABLE;
}

//-----------------------------------------------------------------------------
//
// dmaIsOn
//
// Returns DMA on status
//
DWORD dmaIsOn(DWORD dmaData)
{
	DMADRVDATA_T *pDrvData = (DMADRVDATA_T *) dmaData;

	if ((pDrvData->pDMAChan->config_ch & DMAC_CHAN_ENABLE) != 0)
	{
		return 1;
	}

	return 0;
}

//-----------------------------------------------------------------------------
//

⌨️ 快捷键说明

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