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); 
 
}