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