www.pudn.com > DMBDRV.rar > SianoDMA.c
#include "SianoDMA.h"
#define MIN(a, b) ((ab)?a:b)
#define ENABLED_DEBUG_ZONE ZONE_ERROR_SET | ZONE_INIT_SET
DBGPARAM dpCurSettings =
{
TEXT("Pxa Dma Driver"),
{ /* Note: the order of the following must */
/* match the definitions in debug.h: */
TEXT("Errors"), TEXT("Warnings"), TEXT("Init"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Temporary"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined"), TEXT("Undefined"), TEXT("Undefined"),
TEXT("Undefined")
},
ENABLED_DEBUG_ZONE
};
static VOID sendDmaTransactionFromDb(LPVOID* dev)
{
DMA_DATABASE_ST* dataBase;
dataBase = ((DMA_DRV_PARAMS_ST*)dev)->dataBase;
if (dataBase->firstMsg != dataBase->lastMsg)
{ //We have a transaction in the database
PhyDmaSendDescriptor( (DMA_DRV_PARAMS_ST*)dev,
&dataBase->transactions[dataBase->firstMsg]);
}
}
static BOOL addDmaTransactionToDb( LPVOID* dev,
DMA_DESCRIPTOR_ST* desc,
DMA_CallBackF callBack,
DWORD transactionId)
{
DMA_DATABASE_ST* dataBase;
BOOL sendNow;
DWORD status;
dataBase = ((DMA_DRV_PARAMS_ST*)dev)->dataBase;
WaitForSingleObject(((DMA_DRV_PARAMS_ST*)dev)->databaseSemaphore, INFINITE);
if (dataBase->firstMsg == dataBase->lastMsg)
sendNow = TRUE;
else
sendNow = FALSE;
if (dataBase->firstMsg == (dataBase->lastMsg + 1) % MAX_NUM_OF_WAITING_TRANSACTIONS)
{
return FALSE;
}
dataBase->transactions[dataBase->lastMsg].desc = desc;
dataBase->transactions[dataBase->lastMsg].callBack = callBack;
dataBase->transactions[dataBase->lastMsg].transactionId = transactionId;
dataBase->lastMsg = (dataBase->lastMsg + 1) % MAX_NUM_OF_WAITING_TRANSACTIONS;
ReleaseSemaphore(((DMA_DRV_PARAMS_ST*)dev)->databaseSemaphore, 1, &status);
if (sendNow == TRUE)
sendDmaTransactionFromDb(dev);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// DmaIst
// The thread handles interrupts form DMA controller. When interrupt is
// recieved, the startus is checked to verify success, and at either way, next
// DMA transfer if exist at the the channel's database is launched.
///////////////////////////////////////////////////////////////////////////////
DWORD DmaIst(LPVOID* dev)
{
DMA_DRV_PARAMS_ST* devHandle = (DMA_DRV_PARAMS_ST *)dev;
DWORD status;
DMA_DATABASE_ST* dataBase;
DMA_DB_NODE_ST* transaction;
BOOL sendNow;
while (1)
{
status = WaitForSingleObject(devHandle->dmaIntEvent, INFINITE);
if (devHandle->activeChannel == FALSE)
{
return 0;
}
dataBase = devHandle->dataBase;
transaction = &dataBase->transactions[dataBase->firstMsg];
status = PhyDmaIntHandler(devHandle, transaction);
WaitForSingleObject(devHandle->databaseSemaphore, INFINITE);
if (status != DMA_STATUS_OK)
{
DBGMSG(ZONE_ERROR, (TEXT("Siano PxaDMA, DmaIst() - Bad status after DMA transfer\n")));
}
if (dataBase->firstMsg != dataBase->lastMsg)
{
dataBase->firstMsg = (dataBase->firstMsg + 1) % MAX_NUM_OF_WAITING_TRANSACTIONS;
if (dataBase->firstMsg == dataBase->lastMsg)
sendNow = FALSE;
else
sendNow = TRUE;
LocalFree(transaction->desc);
if (sendNow)
sendDmaTransactionFromDb(dev);
if (transaction->callBack!= NULL)
transaction->callBack(transaction->transactionId, status);
}
ReleaseSemaphore(devHandle->databaseSemaphore, 1, &status);
}
}
/***************************************************
* *
* Driver's interface routines exported by .DEF *
* *
***************************************************/
///////////////////////////////////////////////////////////////////////////////
// Function Name: DllMain
// Purpose......: Main entry point for the DLL.
// Returns......: The result of the DLL attachment TRUE for success
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI DllMain(HINSTANCE DLLinstance,
DWORD Reason,
LPVOID Reserved)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
{
DEBUGREGISTER(DLLinstance);
DBGMSG(ZONE_DLLINIT, (TEXT("PxaDMA, DllMain(): PxaDMA DLL_PROCESS_ATTACH\r\n")));
}
case DLL_PROCESS_DETACH:
{
DBGMSG(ZONE_DLLINIT, (TEXT("PxaDMA, DllMain(): DLL_PROCESS_DETACH \r\n")));
return TRUE;
}
default:
return TRUE;
}
}
///////////////////////////////////////////////////////////////////////////////
// DMA_SetUp
// Initialization routine of DMA channel. This routine should be called in
// order to allocate and initialize a DMA channel. The pointer returned by
// this routine is used for all other calls to DMA driver in order to identify
// the specific channel.
///////////////////////////////////////////////////////////////////////////////
LPVOID DMA_SetUpChannel(DMA_INIT_PARAMS_ST* userParam)
{
DMA_DRV_PARAMS_ST* drvHandle;
TCHAR eventName[20];
//Allocate memory for DMA channel handle.
drvHandle = (DMA_DRV_PARAMS_ST*)VirtualAlloc(NULL, sizeof(DMA_DRV_PARAMS_ST), MEM_COMMIT, PAGE_READWRITE);
if (drvHandle == NULL)
{
DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("PxaDMA, DMA_SetUp(): Error! Could not allocate memory for device handle.\n")));
return NULL;
}
//Create semaphore to take care of channel database.
drvHandle->databaseSemaphore = CreateSemaphore(NULL, 1, 1, NULL);
if (drvHandle->databaseSemaphore == NULL)
{
DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("PxaDMA, DMA_SetUp(): Error! Could not create semaphore for device dataBase.\n")));
VirtualFree (drvHandle, 0, MEM_RELEASE);
return NULL;
}
//Allocate the driver database memory.
drvHandle->dataBase = (DMA_DATABASE_ST*)VirtualAlloc(NULL, sizeof(DMA_DATABASE_ST), MEM_COMMIT, PAGE_READWRITE);
if (drvHandle->dataBase == NULL)
{
DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("PxaDMA, DMA_SetUp(): Error! Allocating memory for DMA module failed.\n")));
CloseHandle(drvHandle->databaseSemaphore);
VirtualFree (drvHandle, 0, MEM_RELEASE);
return NULL;
}
drvHandle->burstSize = userParam->burstSize;
drvHandle->busWidth = userParam->busWidth;
if (userParam->flags & DMA_USE_HW_FLOW_CTRL)
{
drvHandle->useHWFlowCtrl = TRUE;
drvHandle->dmaReq = userParam->dmaReq;
}
if (PhyDmaSetUp(drvHandle) == FALSE)
{
DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("PxaDMA, DMA_SetUp(): Error! PhyDma Setup failed.\n")));
CloseHandle(drvHandle->databaseSemaphore);
VirtualFree (drvHandle, 0, MEM_RELEASE);
return NULL;
}
DBGMSG(1, (TEXT("PxaDMA, DMA_SetUp(): Channel %d will be used.\r\n"), drvHandle->channel));
wsprintf(eventName, TEXT("DMA_CHANNEL_%d"),drvHandle->channel);
drvHandle->dmaIntEvent = CreateEvent(NULL, FALSE, FALSE, eventName);
if (drvHandle->dmaIntEvent == NULL)
{
DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("PxaDMA, DMA_SetUp(): Error! Couild not create event for DMA interrupt.\n")));
CloseHandle(drvHandle->databaseSemaphore);
VirtualFree (drvHandle, 0, MEM_RELEASE);
return NULL;
}
//Create IST thread for DMA controller.
drvHandle->ist = CreateThread( NULL,
0,
DmaIst,
drvHandle,
0,
NULL);
if (drvHandle->ist == NULL)
{
DBGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("PxaDMA, DMA_SetUp(): Error! Couild not create event for DMA interrupt.\n")));
CloseHandle(drvHandle->databaseSemaphore);
CloseHandle(drvHandle->dmaIntEvent);
VirtualFree (drvHandle, 0, MEM_RELEASE);
return NULL;
}
CeSetThreadPriority(drvHandle->ist, 0);
drvHandle->activeChannel = TRUE;
return drvHandle;
}
///////////////////////////////////////////////////////////////////////////////
// DMA_RemoveChannel
// DeInitialization routine of DMA channel. This routine should be called when
// chyannel is no longer needed in order to deallocate all DMA plugin memory.
// After deallocating a channel - all transaction except for current processed
// are stopped, and the channel may not be used again (unless setUp is recalled
// and a new handle recieived).
///////////////////////////////////////////////////////////////////////////////
VOID DMA_RemoveChannel(LPVOID dev)
{
DMA_DRV_PARAMS_ST* drvHandle = (DMA_DRV_PARAMS_ST*)dev;
DWORD exitCode;
drvHandle->activeChannel = FALSE;
if (drvHandle->dmaIntEvent)
SetEvent(drvHandle->dmaIntEvent);
//Wait until the thread exits.
while (GetExitCodeThread(drvHandle->ist, &exitCode) == STILL_ACTIVE);
if (drvHandle->ist)
CloseHandle(drvHandle->ist);
if (drvHandle->dmaIntEvent)
CloseHandle(drvHandle->dmaIntEvent);
PhyDmaRemoveChannel(drvHandle);
if (drvHandle->dataBase)
VirtualFree(drvHandle->dataBase, sizeof(DMA_DATABASE_ST), MEM_RELEASE);
CloseHandle(drvHandle->databaseSemaphore);
//Allocate memory for DMA channel handle.
if (drvHandle)
VirtualFree(drvHandle, sizeof(DMA_DRV_PARAMS_ST), MEM_RELEASE);
}
///////////////////////////////////////////////////////////////////////////////
// DMA_ConfigChannel
// Start a DMA transfer. This routine gets DMA tranfere parameters, analyze
// them and put it into the driver's database. The transfer itself will start
// when the DMA channel is ready for the next transfer (which might be immediatly
// if channel is free). The routine returns immediatly without waitong for the
// end of transfer. If a callback is set by the user, the callback is done after
// the DMA transfer has completed. Each DMA transfer has it's own indevidual callback.
///////////////////////////////////////////////////////////////////////////////
void DMA_ConfigChannel(LPVOID dev, DMA_PARAMS_ST* dmaParam)
{
DMA_DESCRIPTOR_ST* desc;
DMA_DRV_PARAMS_ST* devHandle = (DMA_DRV_PARAMS_ST *)dev;
desc = LocalAlloc(LPTR, sizeof(DMA_DESCRIPTOR_ST));
desc->srcPhyAddr = dmaParam->srcAddr;
desc->dstPhyAddr = dmaParam->dstAddr;
desc->len = dmaParam->len;
desc->flags = dmaParam->flags;
addDmaTransactionToDb( dev,
desc,
dmaParam->callBack,
dmaParam->transactionId);
}