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; } }
IMG_INTERNAL PVRSRV_ERROR TLClientCloseStream(IMG_HANDLE hSrvHandle, IMG_HANDLE hSD) { PVRSRV_ERROR eError = PVRSRV_OK; TL_STREAM_DESC* psSD = (TL_STREAM_DESC*) hSD; PVR_ASSERT(hSrvHandle); PVR_ASSERT(hSD); /* Check the caller provided connection is valid */ if(!psSD->hServerSD) { PVR_DPF((PVR_DBG_ERROR, "TLClientCloseStream: descriptor already closed/not open")); return PVRSRV_ERROR_HANDLE_NOT_FOUND; } /* Check if acquire is outstanding, perform release if it is, ignore result * as there is not much we can do if it is an error other than close */ if (psSD->uiReadLen != NO_ACQUIRE) { (void) BridgeTLReleaseData(hSrvHandle, psSD->hServerSD, psSD->uiReadOffset, psSD->uiReadLen); psSD->uiReadLen = psSD->uiReadOffset = NO_ACQUIRE; } /* Clean up DevMem resources used for this stream in this client */ DevmemReleaseCpuVirtAddr(psSD->psUMmemDesc); DevmemFree(psSD->psUMmemDesc); /* Ignore error, not much that can be done */ (void) DevmemUnmakeServerExportClientExport(hSrvHandle, &psSD->sExportCookie); /* Send close to server to clean up kernel mode resources for this * handle and release the memory. */ eError = BridgeTLCloseStream(hSrvHandle, psSD->hServerSD); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BridgeTLCloseStream: KM returned %d", eError)); /*/ Not much we can do with error, fall through to clean up * return eError; */ } OSMemSet(psSD, 0x00, sizeof(TL_STREAM_DESC)); OSFreeMem (psSD); return eError; }
IMG_INTERNAL PVRSRV_ERROR TLClientOpenStream(IMG_HANDLE hSrvHandle, IMG_PCHAR pszName, IMG_UINT32 ui32Mode, IMG_HANDLE* phSD) { PVRSRV_ERROR eError = PVRSRV_OK; TL_STREAM_DESC* psSD = 0; DEVMEM_SERVER_EXPORTCOOKIE hServerExportCookie; PVR_ASSERT(hSrvHandle); PVR_ASSERT(pszName); PVR_ASSERT(phSD); *phSD = NULL; /* Allocate memory for the stream descriptor object, initialise with * "no data read" yet. */ psSD = OSAllocZMem(sizeof(TL_STREAM_DESC)); if (psSD == NULL) { eError = PVRSRV_ERROR_OUT_OF_MEMORY; PVR_DPF((PVR_DBG_ERROR, "BridgeTLOpenStream: KM returned %d", eError)); goto e0; } psSD->uiReadLen = psSD->uiReadOffset = NO_ACQUIRE; /* Send open stream request to kernel server to get stream handle and * buffer cookie so we can get access to the buffer in this process. */ eError = BridgeTLOpenStream(hSrvHandle, pszName, ui32Mode, &psSD->hServerSD, &hServerExportCookie); if (eError != PVRSRV_OK) { if ((ui32Mode & PVRSRV_STREAM_FLAG_OPEN_WAIT) && (eError == PVRSRV_ERROR_TIMEOUT)) { goto e1; } PVR_LOGG_IF_ERROR(eError, "BridgeTLOpenStream", e1); } /* Convert server export cookie into a cookie for use by this client */ eError = DevmemMakeServerExportClientExport(hSrvHandle, hServerExportCookie, &psSD->sExportCookie); PVR_LOGG_IF_ERROR(eError, "DevmemMakeServerExportClientExport", e2); /* Now convert client cookie into a client handle on the buffer's * physical memory region */ eError = DevmemImport(hSrvHandle, &psSD->sExportCookie, PVRSRV_MEMALLOCFLAG_CPU_READABLE, "TLClientCookie", &psSD->psUMmemDesc); PVR_LOGG_IF_ERROR(eError, "DevmemImport", e3); /* Now map the memory into the virtual address space of this process. */ eError = DevmemAcquireCpuVirtAddr(psSD->psUMmemDesc, (IMG_PVOID *) &psSD->pBaseAddr); PVR_LOGG_IF_ERROR(eError, "DevmemAcquireCpuVirtAddr", e4); /* Return client descriptor handle to caller */ *phSD = psSD; return PVRSRV_OK; /* Clean up post buffer setup */ e4: DevmemFree(psSD->psUMmemDesc); e3: (void) DevmemUnmakeServerExportClientExport(hSrvHandle, &psSD->sExportCookie); /* Clean up post stream open */ e2: BridgeTLCloseStream(hSrvHandle, psSD->hServerSD); /* Cleanup post allocation of the descriptor object */ e1: OSFreeMem(psSD); e0: return eError; }
/******************************************************************************* * 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); }