IMG_VOID 
TLStreamClose(IMG_HANDLE hStream)
{
	PTL_STREAM	psTmp;

	PVR_DPF_ENTERED;

	if ( IMG_NULL == hStream )
	{
		PVR_DPF((PVR_DBG_WARNING,
				 "TLStreamClose failed as NULL stream handler passed, nothing done.\n"));
		PVR_DPF_RETURN;
	}

	psTmp = (PTL_STREAM)hStream;

	/* Decrement reference counter */	
//Thread Safety: Not yet implemented	OSLockAcquire(psTmp->hLock);
	psTmp->uiRefCount--;
//Thread Safety: Not yet implemented	OSLockRelease(psTmp->hLock);

	/* The stream is still being used in other context(s) do not destroy anything */
	if ( 0 != psTmp->uiRefCount )
	{
		PVR_DPF_RETURN;
	}
	else
	{
		if ( psTmp->bWaitForEmptyOnDestroy == IMG_TRUE )
		{
			while (psTmp->ui32Read != psTmp->ui32Write)
			{
				OSEventObjectWaitTimeout(psTmp->hProducerEvent,
										 EVENT_OBJECT_TIMEOUT_MS);
			}
		}
		/* First remove it from the global structures to prevent access
		 * while it is being free'd. Lock it?
		 */
		TLRemoveStreamAndTryFreeStreamNode(psTmp->psNode);

//Thread Safety: Not yet implemented			OSLockDestroy(psTmp->hLock);

		// In block-while-reserve streams those not be NULL 
		if ( IMG_TRUE == psTmp->bBlock ) 
		{
			OSEventObjectClose(psTmp->hProducerEvent);
			OSEventObjectDestroy(psTmp->hProducerEventObj);
		}

		DevmemUnexport(psTmp->psStreamMemDesc, &psTmp->sExportCookie);
		DevmemReleaseCpuVirtAddr(psTmp->psStreamMemDesc);
		DevmemFree(psTmp->psStreamMemDesc);

		OSFREEMEM(psTmp);
		PVR_DPF_RETURN;
	}
}
PVRSRV_ERROR
TLServerCloseStreamKM(PTL_STREAM_DESC psSD)
{
	PVRSRV_ERROR    eError = PVRSRV_OK;
	PTL_GLOBAL_DATA psGD = TLGGD();
	PTL_SNODE		psNode = 0;

	PVR_DPF_ENTERED;

	PVR_ASSERT(psSD);

	// Sanity check, quick exit if there are no streams
	if (psGD->psHead == NULL)
	{
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
	}

	// Check stream still valid
	psNode = TLFindStreamNodeByDesc(psSD);
	if ((psNode == NULL) || (psNode != psSD->psNode))
	{
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_HANDLE_NOT_FOUND);
	}

	// Close and free the event handle resource used by this descriptor
	eError = OSEventObjectClose(psSD->hDataEvent);
	if (eError != PVRSRV_OK)
	{
		// Log error but continue as it seems best
		PVR_DPF((PVR_DBG_ERROR, "OSEventObjectClose() failed error %d", eError));
		eError = PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT;
	}

	// Remove descriptor from stream object/list
	TLRemoveDescAndTryFreeStreamNode(psNode);

	// Free the stream descriptor object
	OSFREEMEM(psSD);

	// Assert the counter is sane after input data validated.
	PVR_ASSERT(TLGGD()->uiClientCnt > 0);
	TLGGD()->uiClientCnt--;

	PVR_DPF_RETURN_RC(eError);
}
PVRSRV_ERROR
TLServerOpenStreamKM(IMG_PCHAR  	 	   pszName,
			   	     IMG_UINT32 		   ui32Mode,
			   	     PTL_STREAM_DESC* 	   ppsSD,
			   	     DEVMEM_EXPORTCOOKIE** ppsBufCookie)
{
	PVRSRV_ERROR 	eError = PVRSRV_OK;
	PVRSRV_ERROR 	eErrorEO = PVRSRV_OK;
	PTL_SNODE		psNode = 0;
	TL_STREAM_DESC* psNewSD = 0;
	IMG_HANDLE 		hEvent;
	PTL_GLOBAL_DATA psGD = TLGGD();

#if defined(PVR_DPF_FUNCTION_TRACE_ON)
    PVR_DPF((PVR_DBG_CALLTRACE, "--> %s:%d entered (%s, %x)", __func__, __LINE__, pszName, ui32Mode));
#endif

	PVR_ASSERT(pszName);

	psNode = TLFindStreamNodeByName(pszName);
	if ((psNode == NULL) && (ui32Mode & PVRSRV_STREAM_FLAG_OPEN_WAIT))
	{	/* Blocking code to wait for stream to be created if it does not exist
	     */
		eError = OSEventObjectOpen(psGD->hTLEventObj, &hEvent);
		PVR_LOGR_IF_ERROR(eError, "OSEventObjectOpen");

		do
		{
			if ((psNode = TLFindStreamNodeByName(pszName)) == NULL)
			{
				PVR_DPF((PVR_DBG_MESSAGE, "Stream %s does not exist, waiting...", pszName));
				/* Will exit OK or with timeout, both cases safe to ignore */
				eErrorEO = OSEventObjectWaitTimeout(hEvent, NO_STREAM_WAIT_PERIOD);
			}
		}
		while ((psNode == NULL) && (eErrorEO == PVRSRV_OK));

		eError = OSEventObjectClose(hEvent);
		PVR_LOGR_IF_ERROR(eError, "OSEventObjectClose");
	}

	/* Make sure we have found a stream node after wait/search */
	if (psNode == NULL)
	{
		/* Did we exit the wait with timeout, inform caller */
		if (eErrorEO == PVRSRV_ERROR_TIMEOUT)
		{
			PVR_DPF_RETURN_RC(eErrorEO);
		}
		PVR_DPF((PVR_DBG_ERROR, "Stream does not exist"));
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_NOT_FOUND);
	}

	// Only one client/descriptor per stream supported
	if (psNode->psDesc != NULL)
	{
		PVR_DPF((PVR_DBG_ERROR, "Can not open stream, stream already opened"));
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_ALREADY_OPEN);
	}

	// Create an event handle for this client to wait on when no data in stream
	// buffer.
	eError = OSEventObjectOpen(psNode->hDataEventObj, &hEvent);
	if (eError != PVRSRV_OK)
	{
		PVR_DPF((PVR_DBG_ERROR, "Not possible to open node's event object"));
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_UNABLE_TO_CREATE_EVENT);
	}

	psNewSD = TLMakeStreamDesc(psNode, ui32Mode, hEvent);
	if (!psNewSD)
	{
		PVR_DPF((PVR_DBG_ERROR, "Not possible to make a new stream descriptor"));
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_OUT_OF_MEMORY);
	}

	TLGGD()->uiClientCnt++;

	// Copy the export cookie back to the user mode API to enable access to
	// the stream buffer from user-mode process.
	*ppsBufCookie = TLStreamGetBufferCookie(psNode->psStream);

	psNode->psDesc = psNewSD;
	*ppsSD = psNewSD;

	PVR_DPF((PVR_DBG_VERBOSE, 
			 "TLServerOpenStreamKM evList=%p, evObj=%p", 
			 psNode->hDataEventObj, 
			 psNode->psDesc->hDataEvent));

	PVR_DPF_RETURN_OK;
}
static IMG_INT
PVRSRVBridgeEventObjectOpen(IMG_UINT32 ui32BridgeID,
					 PVRSRV_BRIDGE_IN_EVENTOBJECTOPEN *psEventObjectOpenIN,
					 PVRSRV_BRIDGE_OUT_EVENTOBJECTOPEN *psEventObjectOpenOUT,
					 CONNECTION_DATA *psConnection)
{
	IMG_HANDLE hEventObjectInt = IMG_NULL;
	IMG_HANDLE hEventObjectInt2 = IMG_NULL;
	IMG_HANDLE hOSEventInt = IMG_NULL;
	IMG_HANDLE hOSEventInt2 = IMG_NULL;

	PVRSRV_BRIDGE_ASSERT_CMD(ui32BridgeID, PVRSRV_BRIDGE_SRVCORE_EVENTOBJECTOPEN);





				{
					/* Look up the address from the handle */
					psEventObjectOpenOUT->eError =
						PVRSRVLookupHandle(psConnection->psHandleBase,
											(IMG_HANDLE *) &hEventObjectInt2,
											psEventObjectOpenIN->hEventObject,
											PVRSRV_HANDLE_TYPE_SHARED_EVENT_OBJECT);
					if(psEventObjectOpenOUT->eError != PVRSRV_OK)
					{
						goto EventObjectOpen_exit;
					}

					/* Look up the data from the resman address */
					psEventObjectOpenOUT->eError = ResManFindPrivateDataByPtr(hEventObjectInt2, (IMG_VOID **) &hEventObjectInt);

					if(psEventObjectOpenOUT->eError != PVRSRV_OK)
					{
						goto EventObjectOpen_exit;
					}
				}

	psEventObjectOpenOUT->eError =
		OSEventObjectOpen(
					hEventObjectInt,
					&hOSEventInt);
	/* Exit early if bridged call fails */
	if(psEventObjectOpenOUT->eError != PVRSRV_OK)
	{
		goto EventObjectOpen_exit;
	}

	/* Create a resman item and overwrite the handle with it */
	hOSEventInt2 = ResManRegisterRes(psConnection->hResManContext,
												RESMAN_TYPE_EVENT_OBJECT,
												hOSEventInt,
												/* FIXME: how can we avoid this cast? */
												(RESMAN_FREE_FN)&OSEventObjectClose);
	if (hOSEventInt2 == IMG_NULL)
	{
		psEventObjectOpenOUT->eError = PVRSRV_ERROR_UNABLE_TO_REGISTER_RESOURCE;
		goto EventObjectOpen_exit;
	}
	psEventObjectOpenOUT->eError = PVRSRVAllocHandle(psConnection->psHandleBase,
							&psEventObjectOpenOUT->hOSEvent,
							(IMG_HANDLE) hOSEventInt2,
							PVRSRV_HANDLE_TYPE_EVENT_OBJECT_CONNECT,
							PVRSRV_HANDLE_ALLOC_FLAG_MULTI
							);
	if (psEventObjectOpenOUT->eError != PVRSRV_OK)
	{
		goto EventObjectOpen_exit;
	}


EventObjectOpen_exit:
	if (psEventObjectOpenOUT->eError != PVRSRV_OK)
	{
		/* If we have a valid resman item we should undo the bridge function by freeing the resman item */
		if (hOSEventInt2)
		{
			PVRSRV_ERROR eError = ResManFreeResByPtr(hOSEventInt2);

			/* Freeing a resource should never fail... */
			PVR_ASSERT((eError == PVRSRV_OK) || (eError == PVRSRV_ERROR_RETRY));
		}
		else if (hOSEventInt)
		{
			OSEventObjectClose(hOSEventInt);
		}
	}


	return 0;
}
/******************************************************************************* 
 * TL Server public API implementation.
 ******************************************************************************/
PVRSRV_ERROR
TLStreamCreate(IMG_HANDLE *phStream,
			   IMG_CHAR *szStreamName,
			   IMG_UINT32 ui32Size,
			   IMG_UINT32 ui32StreamFlags,
               TL_STREAM_SOURCECB pfProducerCB,
               IMG_PVOID pvProducerUD)
{
	PTL_STREAM     psTmp;
	PVRSRV_ERROR   eError;
	IMG_HANDLE     hEventList;
	PTL_SNODE      psn = 0;
	IMG_CHAR       pszBufferLabel[PRVSRVTL_MAX_STREAM_NAME_SIZE+20];

	DEVMEM_FLAGS_T uiMemFlags =  PVRSRV_MEMALLOCFLAG_CPU_READABLE |
								 PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE | 
								 PVRSRV_MEMALLOCFLAG_GPU_READABLE |
								 PVRSRV_MEMALLOCFLAG_GPU_WRITEABLE |
								 PVRSRV_MEMALLOCFLAG_UNCACHED | /* GPU & CPU */
								 PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC |
								 PVRSRV_MEMALLOCFLAG_CPU_WRITE_COMBINE;

	PVR_DPF_ENTERED;
	/* Sanity checks:  */
	/* non NULL handler required */
	if ( NULL == phStream ) 
	{ 
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
	}
	if (OSStringLength(szStreamName) >= PRVSRVTL_MAX_STREAM_NAME_SIZE) 
	{
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_INVALID_PARAMS);
	}
	
	/* Check if there already exists a stream with this name. */
	psn = TLFindStreamNodeByName( szStreamName );
	if ( IMG_NULL != psn )
	{
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_ALREADY_EXISTS);
	}
	
	/* Allocate stream structure container (stream struct) for the new stream */
	psTmp = OSAllocZMem(sizeof(TL_STREAM)) ;
	if ( NULL == psTmp ) 
	{
		PVR_DPF_RETURN_RC(PVRSRV_ERROR_OUT_OF_MEMORY);
	}

	OSStringCopy(psTmp->szName, szStreamName);

	if ( ui32StreamFlags & TL_FLAG_FORCE_FLUSH )
	{
		psTmp->bWaitForEmptyOnDestroy = IMG_TRUE;
	}

	psTmp->bNoSignalOnCommit = (ui32StreamFlags&TL_FLAG_NO_SIGNAL_ON_COMMIT) ?  IMG_TRUE : IMG_FALSE;

	if ( ui32StreamFlags & TL_FLAG_DROP_DATA ) 
	{
		if ( ui32StreamFlags & TL_FLAG_BLOCKING_RESERVE ) 
		{
			eError = PVRSRV_ERROR_INVALID_PARAMS;
			goto e0;
		}
		psTmp->bDrop = IMG_TRUE;
	}
	else if ( ui32StreamFlags & TL_FLAG_BLOCKING_RESERVE ) 
    {	/* Additional synchronization object required for this kind of stream */
        psTmp->bBlock = IMG_TRUE;

		eError = OSEventObjectCreate(NULL, &psTmp->hProducerEventObj);
		if (eError != PVRSRV_OK)
		{
			goto e0;
		}
		/* Create an event handle for this kind of stream */
		eError = OSEventObjectOpen(psTmp->hProducerEventObj, &psTmp->hProducerEvent);
		if (eError != PVRSRV_OK)
		{
			goto e1;
		}
    }

	/* Remember producer supplied CB and data for later */
	psTmp->pfProducerCallback = (IMG_VOID(*)(IMG_VOID))pfProducerCB;
	psTmp->pvProducerUserData = pvProducerUD;

	/* Round the requested bytes to a multiple of array elements' size, eg round 3 to 4 */
	psTmp->ui32Size = PVRSRVTL_ALIGN(ui32Size);
	psTmp->ui32Read = 0;
	psTmp->ui32Write = 0;
	psTmp->ui32Pending = NOTHING_PENDING;

	OSSNPrintf(pszBufferLabel, sizeof(pszBufferLabel), "TLStreamBuf-%s", szStreamName);

	/* Allocate memory for the circular buffer and export it to user space. */
	eError = DevmemAllocateExportable( IMG_NULL,
									   (IMG_HANDLE) TLGetGlobalRgxDevice(),
									   (IMG_DEVMEM_SIZE_T)psTmp->ui32Size,
									   (IMG_DEVMEM_ALIGN_T) OSGetPageSize(),
									   uiMemFlags | PVRSRV_MEMALLOCFLAG_KERNEL_CPU_MAPPABLE,
									   pszBufferLabel,
									   &psTmp->psStreamMemDesc);
	PVR_LOGG_IF_ERROR(eError, "DevmemAllocateExportable", e2);

	eError = DevmemAcquireCpuVirtAddr( psTmp->psStreamMemDesc, (IMG_VOID**) &psTmp->pbyBuffer );
	PVR_LOGG_IF_ERROR(eError, "DevmemAcquireCpuVirtAddr", e3);

	eError = DevmemExport(psTmp->psStreamMemDesc, &(psTmp->sExportCookie));
	PVR_LOGG_IF_ERROR(eError, "DevmemExport", e4);

	/* Synchronization object to synchronize with user side data transfers. */
	eError = OSEventObjectCreate(psTmp->szName, &hEventList);
	if (eError != PVRSRV_OK)
	{
		goto e5;
	}

	/* Stream created, now reset the reference count to 1 */
	psTmp->uiRefCount = 1;

//Thread Safety: Not yet implemented		eError = OSLockCreate(&psTmp->hLock, LOCK_TYPE_PASSIVE);
//Thread Safety: Not yet implemented		if (eError != PVRSRV_OK)
//Thread Safety: Not yet implemented		{
//Thread Safety: Not yet implemented			goto e6;
//Thread Safety: Not yet implemented		}

	/* Now remember the stream in the global TL structures */
	psn = TLMakeSNode(hEventList, (TL_STREAM *)psTmp, 0);
	if (psn == NULL)
	{
		eError=PVRSRV_ERROR_OUT_OF_MEMORY;
		goto e7;
	}
	TLAddStreamNode(psn);

	/* Best effort signal, client wait timeout will ultimately let it find the
	 * new stream if this fails, acceptable to avoid cleanup as it is tricky
	 * at this point */
	(void) OSEventObjectSignal(TLGGD()->hTLEventObj);

	/* Pass the newly created stream handle back to caller */
	*phStream = (IMG_HANDLE)psTmp;
	PVR_DPF_RETURN_OK;

e7:
//Thread Safety: Not yet implemented		OSLockDestroy(psTmp->hLock);
//Thread Safety: Not yet implemented e6:
	OSEventObjectDestroy(hEventList);
e5:
	DevmemUnexport(psTmp->psStreamMemDesc, &(psTmp->sExportCookie));
e4:
	DevmemReleaseCpuVirtAddr( psTmp->psStreamMemDesc );
e3:
	DevmemFree(psTmp->psStreamMemDesc);
e2:
	OSEventObjectClose(psTmp->hProducerEvent);
e1:
	OSEventObjectDestroy(psTmp->hProducerEventObj);
e0:
	OSFREEMEM(psTmp);
	PVR_DPF_RETURN_RC(eError);
}