📄 dmadrv.c
字号:
//*********************************************************************
//* 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 + -