/*
 * dspbridge/src/api/linux/DSPNode.c
 *
 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
 *
 * Copyright (C) 2007 Texas Instruments, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation version 2.1 of the License.
 *
 * This program is distributed .as is. WITHOUT ANY WARRANTY of any kind,
 * whether express or implied; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */


/*
 *  ======== DSPNode.c ========
 *  Description:
 *      This is the source for the DSP/BIOS Bridge API node module. The
 *      parameters are validated at the API level, but the bulk of the
 *      work is done at the driver level through the RM NODE module.
 *
 *  Public Functions:
 *      DSPNode_Allocate
 *      DSPNode_AllocMsgBuf
 *      DSPNode_ChangePriority
 *      DSPNode_Connect
 *      DSPNode_ConnectEx
 *      DSPNode_Create
 *      DSPNode_Delete
 *      DSPNode_FreeMsgBuf
 *      DSPNode_GetAttr
 *      DSPNode_GetMessage
 *      DSPNode_Pause
 *      DSPNode_PutMessage
 *      DSPNode_RegisterNotify
 *      DSPNode_Run
 *      DSPNode_Terminate
 *
 *! Revision History
 *! ================
 *! 14-Mar-2002 map Set *pBuffer to null before returning error status in
 *!		            DSPNode_AllocMsgBuf.
 *! 01-Oct-2001 rr  CMM error codes are converted to DSP_STATUS in
 *!                 DSPNode_Allocate.
 *! 11-Sep-2001 ag  Zero-copy message support.
 *! 08-Jun-2001 jeh Fixed priority range check in DSPNode_ChangePriority.
 *! 23-Apr-2001 jeh Added pStatus parameter to DSPNode_Terminate.
 *! 06-Feb-2001 kc: Added check for alignment value in DSPNode_AllocMsgBuf
 *! 08-Dec-2000 ag  Added alignment to DSPNode_AllocMsgBuf().
 *! 05-Dec-2000 ag  Added SM support to DSPNode_[Alloc][Free]MsgBuf().
 *! 09-Nov-2000 rr: Code cleaned up. Use of IsValidEvent/Mask Macros.
 *! 27-Oct-2000 jeh Updated to version 0.9 of API spec.
 *! 07-Sep-2000 jeh Changed type HANDLE in DSPNode_RegisterNotify to
 *!                 DSP_HNOTIFICATION. Added DSP_STRMATTR param to
 *!                 DSPNode_Connect.
 *! 04-Aug-2000 rr: Name changed to DSPNode.c
 *! 27-Jul-2000 rr: Types updated to ver 0.8 API.
 *! 18-Jul-2000 rr: Node calls into the Class driver.
 *!                 Only parameters are validated here.
 *! 17-May-2000 rr: DSPNode_Connect checks for GHPPNODE.
 *! 15-May-2000 gp: Made input args to DSPNode_Allocate() CONST.
 *!                 Return DSP_ENOTIMPL from DSPNode_ChangePriority().
 *! 02-May-2000 rr: Reg functions use SERVICES.
 *! 12-Apr-2000 ww: Created based on DirectDSP API specification, Version 0.6.
 *
 */

/*  ----------------------------------- Host OS */
#include <host_os.h>
#include <stdlib.h>
#include <malloc.h>

/*  ----------------------------------- DSP/BIOS Bridge */
#include <dbdefs.h>
#include <errbase.h>

/*  ----------------------------------- Trace & Debug */
#include <dbg.h>
#include <dbg_zones.h>

/*  ----------------------------------- Resource Manager */
#include <memry.h>

/*  ----------------------------------- Others */
#include <dsptrap.h>

/*  ----------------------------------- This */
#include "_dbdebug.h"
#include "_dbpriv.h"

#include <DSPNode.h>

#ifdef DEBUG_BRIDGE_PERF
#include <perfutils.h>
#endif

/*  ----------------------------------- Globals */
extern int hMediaFile;		/* class driver handle */

/* Declared here, not to users */
DSP_STATUS GetNodeType(DSP_HNODE hNode, DSP_NODETYPE *pNodeType);

/*
 *  ======== DSPNode_Allocate ========
 *  Purpose:
 *      Allocate data structures for controlling and communicating
 *      with a node on a specific DSP processor..
 */
DBAPI DSPNode_Allocate(DSP_HPROCESSOR hProcessor,
		 IN CONST struct DSP_UUID *pNodeID,
		 IN CONST OPTIONAL struct DSP_CBDATA *pArgs,
		 IN OPTIONAL struct DSP_NODEATTRIN *pAttrIn,
		 OUT DSP_HNODE *phNode)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;
	struct CMM_OBJECT *hCmm;		/* shared memory mngr handle */
	struct CMM_INFO pInfo;		/* Used for virtual space allocation */
	PVOID pVirtBase;
	struct DSP_BUFFERATTR bufAttr;
    DSP_NODETYPE nodeType;
    struct DSP_NDBPROPS    nodeProps;
    UINT            heapSize = 0;
    PVOID           pGPPVirtAddr = NULL;
    UINT            uProfileID;
	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_Allocate:\r\n")));
	if (!hProcessor) {
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_Allocate: "
				"hProcessor is Invalid \r\n")));
		goto func_cont;
	}
	if (!(pNodeID) || !(phNode)) {
		status = DSP_EPOINTER;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Allocate: "
			"Invalid pointer in the Input\r\n")));
		goto func_cont;
	}
	/* First get the NODE properties, allocate, reserve
				memory for Node heap */
	if (pAttrIn) {
		status = DSPNode_GetUUIDProps(hProcessor, pNodeID, &nodeProps);
		pAttrIn->pGPPVirtAddr = NULL;
		if (DSP_SUCCEEDED(status)) {
			uProfileID = pAttrIn->uProfileID;
			DEBUGMSG(DSPAPI_ZONE_FUNCTION,
					("DSPNodeAllocate: User requested"
						  "node heap profile \n"));
			if (uProfileID < nodeProps.uCountProfiles)
				heapSize =
				nodeProps.aProfiles[uProfileID].ulHeapSize;
			if (heapSize) {
				/* allocate heap memory */
				/* Make heap size multiple of page size * */
				heapSize = PG_ALIGN_HIGH(heapSize, PG_SIZE_4K);
				/* align memory on cache line boundary * */
				pGPPVirtAddr = memalign(GEM_CACHE_LINE_SIZE,
							heapSize);
				DEBUGMSG(DSPAPI_ZONE_FUNCTION,
					("DSPNodeAllocate: Node heap memory"
							  "addr, size \n"));
				if ((pGPPVirtAddr == NULL))
					status = DSP_EMEMORY;
				pAttrIn->uHeapSize = heapSize;
				pAttrIn->pGPPVirtAddr = pGPPVirtAddr;
			}
		} else {
			DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT(
				"NODE:DSPNode_Allocate: Failed to get Node "
				"UUID properties \r\n")));
		}
	}
	if (DSP_SUCCEEDED(status)) {
		/* Set up the structure  Call DSP Trap */
		tempStruct.ARGS_NODE_ALLOCATE.hProcessor = hProcessor;
		tempStruct.ARGS_NODE_ALLOCATE.pNodeID =
						(struct DSP_UUID *)pNodeID;
		tempStruct.ARGS_NODE_ALLOCATE.pArgs =
						(struct DSP_CBDATA *)pArgs;
		tempStruct.ARGS_NODE_ALLOCATE.pAttrIn =
					(struct DSP_NODEATTRIN *)pAttrIn;
		tempStruct.ARGS_NODE_ALLOCATE.phNode = phNode;
		status = DSPTRAP_Trap(&tempStruct, CMD_NODE_ALLOCATE_OFFSET);
	}
func_cont:
	 /* If 1st SM segment is configured then allocate and map it to
		this process.*/
	if (!DSP_SUCCEEDED(status)) {
		if (pGPPVirtAddr)
			free(pGPPVirtAddr);
		return status;
	}
	tempStruct.ARGS_CMM_GETHANDLE.hProcessor = hProcessor;
	tempStruct.ARGS_CMM_GETHANDLE.phCmmMgr = &hCmm;
	status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETHANDLE_OFFSET);
	if (DSP_SUCCEEDED(status)) {
		/* Get SM segment info from CMM */
		tempStruct.ARGS_CMM_GETINFO.hCmmMgr = hCmm;
		tempStruct.ARGS_CMM_GETINFO.pCmmInfo = &pInfo;
		status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETINFO_OFFSET);
		if (DSP_FAILED(status)) {
			status = DSP_EFAIL;
			DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT(
			"NODE: DSPNode_Allocate: "
			"Failed to get SM segment\r\n")));
		} else
			status = DSP_SOK;

	} else {
		status = DSP_EFAIL;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT(
			"NODE: DSPNode_Allocate:Failed to CMM handle\r\n")));
	}
	if (!DSP_SUCCEEDED(status)) {
		free(pGPPVirtAddr);
		return status;
	}

	GetNodeType(*phNode, &nodeType);
	if ((nodeType != NODE_DEVICE) && (pInfo.ulNumGPPSMSegs > 0)) {
		/* Messaging uses 1st segment */
		if ((pInfo.segInfo[0].dwSegBasePa != 0) &&
		    (pInfo.segInfo[0].ulTotalSegSize) > 0) {
			pVirtBase = mmap(NULL, pInfo.segInfo[0].ulTotalSegSize,
				 PROT_READ | PROT_WRITE, MAP_SHARED |
				 MAP_LOCKED, hMediaFile,
				 pInfo.segInfo[0].dwSegBasePa);
			if (!pVirtBase) {
				DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: "
				"DSPNode_Allocate:Virt alloc failed\r\n")));
				status = DSP_EMEMORY;
				/* Clean up */
				tempStruct.ARGS_NODE_DELETE.hNode = *phNode;
				DSPTRAP_Trap(&tempStruct,
					CMD_NODE_DELETE_OFFSET);
				return status;
			}
			/* set node translator's virt addr range for seg */
			bufAttr.uAlignment = 0;
			bufAttr.uSegment = 1 | MEMRY_SETVIRTUALSEGID;
			bufAttr.cbStruct = 0;
			status = DSPNode_AllocMsgBuf(*phNode,
					pInfo.segInfo[0].ulTotalSegSize,
					&bufAttr, (BYTE **)&pVirtBase);
			if (DSP_FAILED(status)) {
				/* If failed to set segment, unmap */
				munmap(pVirtBase,
					pInfo.segInfo[0].ulTotalSegSize);
				/* Clean up */
				tempStruct.ARGS_NODE_DELETE.hNode = *phNode;
				DSPTRAP_Trap(&tempStruct,
					CMD_NODE_DELETE_OFFSET);
			}
		}
	}
    return status;
}

/*
 *  ======== DSPNode_AllocMsgBuf ========
 */
DBAPI DSPNode_AllocMsgBuf(DSP_HNODE hNode, UINT uSize,
		   IN OPTIONAL struct DSP_BUFFERATTR *pAttr, OUT BYTE **pBuffer)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;
	DEBUGMSG(DSPAPI_ZONE_FUNCTION,
		(TEXT("NODE: DSPNode_AllocMsgBuf:\r\n")));

	if (uSize == 0) {
		status = DSP_ESIZE;
		if (pBuffer)
			*pBuffer = NULL;

	} else if (hNode) {
		if (pBuffer) {
			/* Set up the structure */
			tempStruct.ARGS_NODE_ALLOCMSGBUF.hNode = hNode;
			tempStruct.ARGS_NODE_ALLOCMSGBUF.uSize = uSize;
			tempStruct.ARGS_NODE_ALLOCMSGBUF.pAttr = pAttr;
			/* Va Base */
			tempStruct.ARGS_NODE_ALLOCMSGBUF.pBuffer = pBuffer;
			/* Call DSP Trap */
			status = DSPTRAP_Trap(&tempStruct,
				CMD_NODE_ALLOCMSGBUF_OFFSET);
			if (DSP_SUCCEEDED(status)) {
				if (*pBuffer == NULL) {
					DEBUGMSG(DSPAPI_ZONE_FUNCTION,
					(TEXT("NODE: DSPNode_AllocMsgBuf: "
					"No SM\r\n")));
					status = DSP_EMEMORY;	/* No SM */
				}
			} else
				*pBuffer = NULL;

		} else {
			/* Invalid pointer */
			status = DSP_EPOINTER;
			DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: "
			"DSPNode_AllocBuf: Invalid pointer in the Input\r\n")));
		}
	} else {
		/* Invalid handle */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_AllocMsgBuf: "
						"hNode is Invalid \r\n")));
		if (pBuffer)
			*pBuffer = NULL;

	}

	return status;
}

/*
 *  ======== DSPNode_ChangePriority ========
 *  Purpose:
 *      Change a task node's runtime priority within the DSP RTOS.
 */
DBAPI DSPNode_ChangePriority(DSP_HNODE hNode, INT iPriority)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION,
			(TEXT("NODE: DSPNode_ChangePriority:\r\n")));

	if (hNode) {
		/* Set up the structure */
		if (iPriority >= DSP_NODE_MIN_PRIORITY &&
		    iPriority <= DSP_NODE_MAX_PRIORITY) {
			/* Call DSP Trap */
			tempStruct.ARGS_NODE_CHANGEPRIORITY.hNode = hNode;
			tempStruct.ARGS_NODE_CHANGEPRIORITY.iPriority =
							iPriority;
			status = DSPTRAP_Trap(&tempStruct,
					CMD_NODE_CHANGEPRIORITY_OFFSET);
		} else
			status = DSP_ERANGE;

	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_ChangePriority: "
			"hNode is Invalid \r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_Connect ========
 *  Purpose:
 *      Make a stream connection, either between two nodes on a DSP,
 *      or between a node on a DSP and the GPP.
 */
DBAPI DSPNode_Connect(DSP_HNODE hNode, UINT uStream, DSP_HNODE hOtherNode,
		UINT uOtherStream, IN OPTIONAL struct DSP_STRMATTR *pAttrs)
{
	return DSPNode_ConnectEx(hNode, uStream, hOtherNode, uOtherStream,
				 pAttrs, NULL);
}

/*
 *  ======== DSPNode_ConnectEx ========
 *  Purpose:
 *      Make a stream connection, either between two nodes on a DSP,
 *      or between a node on a DSP and the GPP.
 */
DBAPI DSPNode_ConnectEx(DSP_HNODE hNode, UINT uStream, DSP_HNODE hOtherNode,
		  UINT uOtherStream, IN OPTIONAL struct DSP_STRMATTR *pAttrs,
		  IN OPTIONAL struct DSP_CBDATA *pConnParam)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_ConnectEx:\r\n")));

	if ((hNode) && (hOtherNode)) {
		/* Set up the structure */
		/* Call DSP Trap */
		tempStruct.ARGS_NODE_CONNECT.hNode = hNode;
		tempStruct.ARGS_NODE_CONNECT.uStream = uStream;
		tempStruct.ARGS_NODE_CONNECT.hOtherNode = hOtherNode;
		tempStruct.ARGS_NODE_CONNECT.uOtherStream = uOtherStream;
		tempStruct.ARGS_NODE_CONNECT.pAttrs = pAttrs;
		tempStruct.ARGS_NODE_CONNECT.pConnParam = pConnParam;
		status = DSPTRAP_Trap(&tempStruct, CMD_NODE_CONNECT_OFFSET);
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Connect: "
		"hNode or hOtherNode is Invalid Handle\r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_Create ========
 *  Purpose:
 *      Create a node in a pre-run (i.e., inactive) state on its
 *		DSP processor.
 */
DBAPI DSPNode_Create(DSP_HNODE hNode)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;
#ifdef DEBUG_BRIDGE_PERF
	struct timeval tv_beg;
	struct timeval tv_end;
	struct timezone tz;
	int timeRetVal = 0;

	timeRetVal = getTimeStamp(&tv_beg);
#endif


	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_Create:\r\n")));

	if (hNode) {
		/* Set up the structure */
		/* Call DSP Trap */
		tempStruct.ARGS_NODE_CREATE.hNode = hNode;
		status = DSPTRAP_Trap(&tempStruct, CMD_NODE_CREATE_OFFSET);
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
		(TEXT("NODE: DSPNode_Create: hNode is Invalid Handle\r\n")));
	}

#ifdef DEBUG_BRIDGE_PERF
	timeRetVal = getTimeStamp(&tv_end);
	PrintStatistics(&tv_beg, &tv_end, "DSPNode_Create", 0);

#endif

	return status;
}

/*
 *  ======== DSPNode_Delete ========
 *  Purpose:
 *      Delete all DSP-side and GPP-side resources for the node.
 */
DBAPI DSPNode_Delete(DSP_HNODE hNode)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;
	BYTE *pVirtBase = NULL;
	struct DSP_BUFFERATTR bufAttr;
	struct CMM_OBJECT *hCmm;		/* shared memory mngr handle */
	struct CMM_INFO pInfo;		/* Used for virtual space allocation */
	DSP_NODETYPE nodeType;
	struct DSP_NODEATTR    nodeAttr;
#ifdef DEBUG_BRIDGE_PERF
	struct timeval tv_beg;
	struct timeval tv_end;
	struct timezone tz;
	int timeRetVal = 0;

	timeRetVal = getTimeStamp(&tv_beg);
#endif

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_Delete:\r\n")));
	if (!hNode) {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Delete: "
					"hNode is Invalid Handle\r\n")));
		return status;
	}
	/* Get segment size.
	 >0 is SM segment. Get default SM Mgr*/
	tempStruct.ARGS_CMM_GETHANDLE.hProcessor = NULL;
	tempStruct.ARGS_CMM_GETHANDLE.phCmmMgr = &hCmm;
	status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETHANDLE_OFFSET);
	if (DSP_SUCCEEDED(status)) {
		/* Get SM segment info from CMM */
		tempStruct.ARGS_CMM_GETINFO.hCmmMgr = hCmm;
		tempStruct.ARGS_CMM_GETINFO.pCmmInfo = &pInfo;
		status = DSPTRAP_Trap(&tempStruct, CMD_CMM_GETINFO_OFFSET);
		if (DSP_FAILED(status)) {
			status = DSP_EFAIL;
			DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_Delete:"
					" Failed to get SM segment\r\n")));
		} else
			status = DSP_SOK;

	} else {
		status = DSP_EFAIL;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Delete: "
					"Failed to CMM handle\r\n")));
	}
	if (!DSP_SUCCEEDED(status)) {
		status = DSP_EBADSEGID;	/* no SM segments*/
		return status;
	}
    status = DSPNode_GetAttr(hNode, &nodeAttr, sizeof(nodeAttr));
	GetNodeType(hNode, &nodeType);
	if (nodeType != NODE_DEVICE) {
		/*segInfo index starts at 0.These checks may not be required*/
		if ((pInfo.segInfo[0].dwSegBasePa != 0) &&
		    (pInfo.segInfo[0].ulTotalSegSize) > 0) {
			/* get node translator's virtual address range
			   so we can free it */
			bufAttr.uAlignment = 0;
			bufAttr.uSegment = 1 | MEMRY_GETVIRTUALSEGID;
			DSPNode_AllocMsgBuf(hNode, 1, &bufAttr, &pVirtBase);
			/* Free virtual space */
			if (!pVirtBase)
				goto loop_end;

			if (munmap(pVirtBase,
					pInfo.segInfo[0].ulTotalSegSize)) {
				status = DSP_EFAIL;
			}
		}
	}
loop_end:
	if (DSP_SUCCEEDED(status)) {
		/* Set up the structure Call DSP Trap */
		tempStruct.ARGS_NODE_DELETE.hNode = hNode;
		status = DSPTRAP_Trap(&tempStruct, CMD_NODE_DELETE_OFFSET);
		/* Free any node heap memory */
		if (nodeAttr.inNodeAttrIn.pGPPVirtAddr) {
			DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("DSPNodeDelete:"
					"Freeing Node heap addr \n")));
			free(nodeAttr.inNodeAttrIn.pGPPVirtAddr);
		}
	}
#ifdef DEBUG_BRIDGE_PERF
	timeRetVal = getTimeStamp(&tv_end);
	PrintStatistics(&tv_beg, &tv_end, "DSPNode_Delete", 0);
#endif

	return status;
}

/*
 *  ======== DSPNode_FreeMsgBuf ========
 */
DBAPI DSPNode_FreeMsgBuf(DSP_HNODE hNode, IN BYTE *pBuffer,
				IN OPTIONAL struct DSP_BUFFERATTR *pAttr)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_FreeMsgBuf:\r\n")));

	if (hNode) {
		if (pBuffer) {
			/* Set up the structure */
			/* Call DSP Trap */
			tempStruct.ARGS_NODE_FREEMSGBUF.hNode = hNode;
			tempStruct.ARGS_NODE_FREEMSGBUF.pBuffer = pBuffer;
			tempStruct.ARGS_NODE_FREEMSGBUF.pAttr = pAttr;
			status = DSPTRAP_Trap(&tempStruct,
				CMD_NODE_FREEMSGBUF_OFFSET);
			if (DSP_FAILED(status)) {
				DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: "
						"DSPNode_FreeMsgBuf:"
						"Failed to Free SM buf\r\n")));
			}
		} else {
			/* Invalid parameter */
			status = DSP_EPOINTER;
			DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_FreeMsgBuf: "
				"Invalid pointer in the Input\r\n")));
		}
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_FreeMsgBuf: "
				"hNode is Invalid \r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_GetAttr ========
 *  Purpose:
 *      Copy the current attributes of the specified node.
 */
DBAPI DSPNode_GetAttr(DSP_HNODE hNode, OUT struct DSP_NODEATTR *pAttr,
		UINT uAttrSize)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_GetAttr:\r\n")));

	if (hNode) {
		if (pAttr) {
			if (uAttrSize >= sizeof(struct DSP_NODEATTR)) {
				/* Set up the structure */
				/* Call DSP Trap */
				tempStruct.ARGS_NODE_GETATTR.hNode = hNode;
				tempStruct.ARGS_NODE_GETATTR.pAttr = pAttr;
				tempStruct.ARGS_NODE_GETATTR.uAttrSize =
								uAttrSize;
				status = DSPTRAP_Trap(&tempStruct,
					CMD_NODE_GETATTR_OFFSET);
			} else {
				status = DSP_ESIZE;
				DEBUGMSG(DSPAPI_ZONE_ERROR,
					(TEXT("NODE: DSPNode_GetAttr: "
					"Size is too small \r\n")));
			}
		} else {
			/* Invalid parameter */
			status = DSP_EPOINTER;
			DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_GetAttr: "
				"Invalid pointer in the Input\r\n")));
		}
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_GetAttr: "
			"hNode is Invalid \r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_GetMessage ========
 *  Purpose:
 *      Retrieve an event message from a task node.
 */
DBAPI DSPNode_GetMessage(DSP_HNODE hNode, OUT struct DSP_MSG *pMessage,
				UINT uTimeout)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;
#ifdef DEBUG_BRIDGE_PERF
	struct timeval tv_beg;
	struct timeval tv_end;
	struct timezone tz;
	int timeRetVal = 0;

	timeRetVal = getTimeStamp(&tv_beg);

#endif

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_GetMessage:\r\n")));

	if (hNode) {
		if (pMessage) {
			/* Set up the structure */
			/* Call DSP Trap */
			tempStruct.ARGS_NODE_GETMESSAGE.hNode = hNode;
			tempStruct.ARGS_NODE_GETMESSAGE.pMessage = pMessage;
			tempStruct.ARGS_NODE_GETMESSAGE.uTimeout = uTimeout;
			status = DSPTRAP_Trap(&tempStruct,
				CMD_NODE_GETMESSAGE_OFFSET);
		} else {
			status = DSP_EPOINTER;
			DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_GetMessage:"
				"pMessage is Invalid \r\n")));
		}
	} else {
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_GetMessage: "
			"hNode is Invalid \r\n")));
	}
#ifdef DEBUG_BRIDGE_PERF
	timeRetVal = getTimeStamp(&tv_end);
	PrintStatistics(&tv_beg, &tv_end, "DSPNode_GetMessage", 0);
#endif


	return status;
}

/*
 *  ======== GetNodeType ========
 *  Purpose:
 *      Return the node type
 */
DSP_STATUS GetNodeType(DSP_HNODE hNode, DSP_NODETYPE *pNodeType)
{
	/*DSP_STATUS status;*/
	DSP_STATUS status = DSP_SOK;
	struct DSP_NODEATTR nodeAttr;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("GetNodeType:\r\n")));

	if (hNode) {
		status = DSPNode_GetAttr(hNode, &nodeAttr, sizeof(nodeAttr));
		if (DSP_SUCCEEDED(status)) {
			*pNodeType =
			nodeAttr.iNodeInfo.nbNodeDatabaseProps.uNodeType;
		}
	} else {
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("GetNodeType: "
					"hNode is Invalid \r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_Pause ========
 *  Purpose:
 *      Temporarily suspend execution of a node that is currently running
 *      on a DSP.
 */
DBAPI DSPNode_Pause(DSP_HNODE hNode)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_Pause:\r\n")));

	if (hNode) {
		/* Set up the structure */
		/* Call DSP Trap */
		tempStruct.ARGS_NODE_PAUSE.hNode = hNode;
		status = DSPTRAP_Trap(&tempStruct, CMD_NODE_PAUSE_OFFSET);
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Pause: "
				"hNode is Invalid Handle\r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_PutMessage ========
 *  Purpose:
 *      Send an event message to a task node.
 */
DBAPI DSPNode_PutMessage(DSP_HNODE hNode, IN CONST struct DSP_MSG *pMessage,
						UINT uTimeout)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;
#ifdef DEBUG_BRIDGE_PERF
	struct timeval tv_beg;
	struct timeval tv_end;
	struct timeval tz;
	int timeRetVal = 0;

	timeRetVal = getTimeStamp(&tv_beg);
#endif

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_PutMessage:\r\n")));

	if (hNode) {
		if (pMessage) {
			/* Set up the structure */
			/* Call DSP Trap */
			tempStruct.ARGS_NODE_PUTMESSAGE.hNode = hNode;
			tempStruct.ARGS_NODE_PUTMESSAGE.pMessage =
						(struct DSP_MSG *)pMessage;
			tempStruct.ARGS_NODE_PUTMESSAGE.uTimeout = uTimeout;
			status = DSPTRAP_Trap(&tempStruct,
				CMD_NODE_PUTMESSAGE_OFFSET);
		} else {
			status = DSP_EPOINTER;
			DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_PutMessage: "
						"pMessage is Invalid \r\n")));
		}
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_PutMessage: "
					"hNode is Invalid \r\n")));
	}
#ifdef DEBUG_BRIDGE_PERF
	timeRetVal = getTimeStamp(&tv_end);
	PrintStatistics(&tv_beg, &tv_end, "DSPNode_PutMessage", 0);
#endif


	return status;
}

/*
 *  ======== DSPNode_RegisterNotify ========
 *  Purpose:
 *      Register to be notified of specific events for this node.
 */
DBAPI
DSPNode_RegisterNotify(DSP_HNODE hNode, UINT uEventMask,
		       UINT uNotifyType, struct DSP_NOTIFICATION *hNotification)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION,
			(TEXT("NODE: DSPNode_RegisterNotify:\r\n")));

	if ((hNode) && (hNotification)) {
		if (IsValidNodeEvent(uEventMask)) {
			if (IsValidNotifyMask(uNotifyType)) {
				/* Set up the structure */
				/* Call DSP Trap */
				tempStruct.ARGS_NODE_REGISTERNOTIFY.hNode =
							hNode;
				tempStruct.ARGS_NODE_REGISTERNOTIFY.uEventMask =
							uEventMask;
				tempStruct.ARGS_NODE_REGISTERNOTIFY\
					.uNotifyType = uNotifyType;
				tempStruct.ARGS_NODE_REGISTERNOTIFY\
					.hNotification = hNotification;

				status = DSPTRAP_Trap(&tempStruct,
						CMD_NODE_REGISTERNOTIFY_OFFSET);
			} else {
				status = DSP_ENOTIMPL;
				DEBUGMSG(DSPAPI_ZONE_ERROR,
					(TEXT("NODE: DSPNode_RegisterNotify: "
					"Invalid Notification Mask \r\n")));
			}
		} else {
			status = DSP_EVALUE;
			DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_RegisterNotify:"
						"Invalid Event type\r\n")));
		}
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_RegisterNotify: "
				"hNode is Invalid \r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_Run ========
 *  Purpose:
 *      Start a task node running.
 */
DBAPI DSPNode_Run(DSP_HNODE hNode)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_Run:\r\n")));

	if (hNode) {
		/* Set up the structure */
		/* Call DSP Trap */
		tempStruct.ARGS_NODE_RUN.hNode = hNode;
		status = DSPTRAP_Trap(&tempStruct, CMD_NODE_RUN_OFFSET);
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR, (TEXT("NODE: DSPNode_Run: "
					"hNode is Invalid Handle\r\n")));
	}

	return status;
}

/*
 *  ======== DSPNode_Terminate ========
 *  Purpose:
 *      Signal a task node running on a  DSP processor that it should
 *      exit its execute-phase function.
 */
DBAPI DSPNode_Terminate(DSP_HNODE hNode, DSP_STATUS *pStatus)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION, (TEXT("NODE: DSPNode_Terminate:\r\n")));

	if (hNode) {
		/* !DSP_ValidWritePtr means it is a valid write ptr */
		if (!DSP_ValidWritePtr(pStatus, sizeof(DSP_STATUS))) {
			/* Set up the structure */
			/* Call DSP Trap */
			tempStruct.ARGS_NODE_TERMINATE.hNode = hNode;
			tempStruct.ARGS_NODE_TERMINATE.pStatus = pStatus;
			status = DSPTRAP_Trap(&tempStruct,
				CMD_NODE_TERMINATE_OFFSET);
		} else
			status = DSP_EPOINTER;

	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_Terminate: "
					"hNode is Invalid Handle\r\n")));
	}

	return status;
}


/*
 *  ======== DSPNode_GetUUIDProps ========
 *  Purpose:
 *      Get Node properties from DCD/DOF file given the UUID
 */
DBAPI DSPNode_GetUUIDProps(DSP_HPROCESSOR hProcessor,
		IN CONST struct DSP_UUID *pNodeID,
		 OUT struct DSP_NDBPROPS *pNodeProps)
{
	DSP_STATUS status = DSP_SOK;
	Trapped_Args tempStruct;

	DEBUGMSG(DSPAPI_ZONE_FUNCTION,
				(TEXT("NODE:DSPNode_GetUUIDProps:\r\n")));

	if (hProcessor) {
		if ((pNodeID) && (pNodeProps)) {
			/* Set up the structure */
			/* Call DSP Trap */
			tempStruct.ARGS_NODE_GETUUIDPROPS.hProcessor =
						hProcessor;
			tempStruct.ARGS_NODE_GETUUIDPROPS.pNodeID =
						(struct DSP_UUID *)pNodeID;
			tempStruct.ARGS_NODE_GETUUIDPROPS.pNodeProps =
					(struct DSP_NDBPROPS *) pNodeProps;
			status = DSPTRAP_Trap(&tempStruct,
				CMD_NODE_GETUUIDPROPS_OFFSET);
		} else {
			/* Invalid parameter */
			status = DSP_EPOINTER;
			DEBUGMSG(DSPAPI_ZONE_ERROR,
				(TEXT("NODE: DSPNode_GetUUIDProps: "
				       "Invalid pointer in the Input\r\n")));
		}
	} else {
		/* Invalid pointer */
		status = DSP_EHANDLE;
		DEBUGMSG(DSPAPI_ZONE_ERROR,
			(TEXT("NODE: DSPNode_GetUUIDProps: "
					"hProcessor is Invalid \r\n")));
	}

	return status;
}