/*!
******************************************************************************

 @Function                POOL_PoolCreate

******************************************************************************/
IMG_RESULT POOL_PoolCreate(
    IMG_HANDLE *  phPoolHandle
)
{
    POOL_sResPool *  psResPool;
    IMG_UINT32       ui32Result;

    IMG_ASSERT(gInitialised);

    /* Allocate a pool structure...*/
    psResPool = IMG_MALLOC(sizeof(*psResPool));
    IMG_ASSERT(psResPool != IMG_NULL);
    if (psResPool == IMG_NULL)
    {
        return IMG_ERROR_OUT_OF_MEMORY;
    }
    IMG_MEMSET(psResPool, 0, sizeof(*psResPool));

    /* Initialise the pool info...*/
    LST_init(&psResPool->sFreeResList);
    LST_init(&psResPool->sActResList);

    /* Create mutex...*/
    ui32Result = SYSOSKM_CreateMutex(&psResPool->hMutexHandle);
    IMG_ASSERT(ui32Result == IMG_SUCCESS);
    if (ui32Result != IMG_SUCCESS)
    {
        goto error_create_mutex;
    }

    /* Create context for the Id generator...*/
    ui32Result = IDGEN_CreateContext(POOL_IDGEN_MAX_ID, POOL_IDGEN_BLOCK_SIZE,IMG_FALSE, &psResPool->hIdGenHandle);
    IMG_ASSERT(ui32Result == IMG_SUCCESS);
    if (ui32Result != IMG_SUCCESS)
    {
        goto error_create_context;
    }

    /* Disable interrupts.  */
    SYSOSKM_DisableInt();

    /* Add to list of pools...*/
    LST_add(&gsPoolList, psResPool);

    /* Enable interrupts.  */
    SYSOSKM_EnableInt();

    /* Return handle to pool...*/
    *phPoolHandle = psResPool;

    return IMG_SUCCESS;

    /* Error handling. */
error_create_context:
    SYSOSKM_DestroyMutex(psResPool->hMutexHandle);
error_create_mutex:
    IMG_FREE(psResPool);

    return ui32Result;
}
/*!
******************************************************************************

 @Function              VDECDDUTILS_CreateStrUnit

 @Description           this function allocate a structure for a complete data unit

******************************************************************************/
IMG_RESULT VDECDDUTILS_CreateStrUnit(
    VDECDD_sStrUnit    ** ppsStrUnit,
    LST_T               * sBSList
)
{
    VDECDD_sStrUnit    * psStrUnit;
    BSPP_sBitStrSeg  * psBitStrSeg;

    VDEC_MALLOC(psStrUnit);
    IMG_ASSERT(psStrUnit != IMG_NULL);
    if (psStrUnit == IMG_NULL)
    {
        return IMG_ERROR_OUT_OF_MEMORY;
    }
    VDEC_BZERO(psStrUnit);
    if (sBSList != IMG_NULL)
    {
        // copy BS list to this list
        LST_init(&psStrUnit->sBitStrSegList);
        for ( psBitStrSeg = LST_first( sBSList); psBitStrSeg != NULL;   psBitStrSeg = LST_first(sBSList) )
        {
            psBitStrSeg = LST_removeHead(sBSList);
            LST_add(&psStrUnit->sBitStrSegList,psBitStrSeg);
        }
    }

    *ppsStrUnit = psStrUnit;

    return IMG_SUCCESS;
}
/*!
******************************************************************************

 @Function				SYSDEVU_Initialise

******************************************************************************/
IMG_RESULT SYSDEVU_Initialise(IMG_VOID)
{
	/* If not initialised...*/
	if (!gSysDevInitialised)
	{
		IMG_RESULT eResult;

		eResult = SYSOSKM_CreateAtomic(&gsActiveOpenCnt);
		IMG_ASSERT(eResult == IMG_SUCCESS);
		if (eResult != IMG_SUCCESS)
		{
			return eResult;
		}

		LST_init(&gsDevList);

		eResult = SYSOSKM_CreateMutex(&hNextDeviceIdMutex);
		IMG_ASSERT(eResult == IMG_SUCCESS);
		if (eResult != IMG_SUCCESS)
		{
			return eResult;
		}

		/* use a magic number to help detect dereferences of
		   DeviceId when (wrongly) casted as a pointer */
		gui32NextDeviceId = 0xbeef00;
		/* Now we are initialised...*/
		gSysDevInitialised = IMG_TRUE;
	}

	return IMG_SUCCESS;
}
/*!
******************************************************************************

 @Function                POOL_Initialise

******************************************************************************/
IMG_RESULT POOL_Initialise(IMG_VOID)
{
    /* Disable interrupts.  */
    SYSOSKM_DisableInt();

    /* If not initialised...*/
    if (!gInitialised)
    {
        /* Initialise the list of pools. */
        LST_init(&gsPoolList);

        /* Set initialised flag...*/
        gInitialised = IMG_TRUE;
    }

    /* Enable interrupts.  */
    SYSOSKM_EnableInt();

    /* Return success...*/
    return IMG_SUCCESS;
}
/*!
******************************************************************************

 @Function              VDECDDUTILS_CreateStrUnitOld

 @Description           this function allocate a structure for a complete data unit


******************************************************************************/
IMG_RESULT VDECDDUTILS_CreateStrUnitOld(
    VDECDD_sStrUnit    ** ppsStrUnit,
    BSPP_sSequHdrInfo   * psSeqInfo,
    BSPP_sPictHdrInfo   * psPicInfo,
    LST_T               * sBSList
)
{
    VDECDD_sStrUnit    * psStrUnit;
    BSPP_sBitStrSeg  * psBitStrSeg;

    VDEC_MALLOC(psStrUnit);
    IMG_ASSERT(psStrUnit != IMG_NULL);
    if (psStrUnit == IMG_NULL)
    {
        return IMG_ERROR_OUT_OF_MEMORY;
    }
    VDEC_BZERO(psStrUnit);
    if (sBSList != IMG_NULL)
    {
        // copy BS list to this list
        LST_init(&psStrUnit->sBitStrSegList);
        for ( psBitStrSeg = LST_first( sBSList); psBitStrSeg != NULL;   psBitStrSeg = LST_first(sBSList) )
        {
            psBitStrSeg = LST_removeHead(sBSList);
            LST_add(&psStrUnit->sBitStrSegList,psBitStrSeg);
        }

    }
    if(psSeqInfo !=IMG_NULL)
    {
        psStrUnit->psSequHdrInfo = psSeqInfo;
        psStrUnit->psSequHdrInfo->ui32RefCount = 1;
    }
    psStrUnit->psPictHdrInfo = psPicInfo;
    *ppsStrUnit = psStrUnit;

    return IMG_SUCCESS;
}
/*!
******************************************************************************

 @Function      perflog_InitialiseFile

 @Description

 Initialises new file in performance logger directory.

 @Output    pFileHandler : file to be initialised

 @Input     pszFileName : name of created file

 @Input     psPerfLogDir : directory where new file will be stored

 @Return    IMG_SUCCESS in case when file has been initialised successfully,
            error code otherwise

******************************************************************************/
static IMG_RESULT perflog_InitialiseFile(
    perflog_FileHandler *pFileHandler,
    const IMG_CHAR *pszFileName,
    struct dentry *psPerfLogDir
)
{
    if(pFileHandler == NULL || pszFileName == NULL || psPerfLogDir == NULL)
    {
        REPORT(REPORT_MODULE_PERFLOG, REPORT_ERR,
                "Performance logger cannot create buffer: invalid parameters");
        return IMG_ERROR_INVALID_PARAMETERS;
    }

    //creates mutex that sync access to list of buffers
    if( SYSOSKM_CreateMutex(&pFileHandler->hMutexHandle) != IMG_SUCCESS)
    {
        REPORT(REPORT_MODULE_PERFLOG, REPORT_ERR,
               "Performance logger cannot create internal mutex");
        return IMG_ERROR_FATAL;
    }

    //initialises list of buffers
    LST_init(&pFileHandler->sBufferList);

    //creates new file in debug file system
    pFileHandler->psFile = debugfs_create_file(pszFileName, 0644, psPerfLogDir, NULL, &perflog_FileOps);
    IMG_ASSERT(pFileHandler->psFile != IMG_NULL);
    if(pFileHandler->psFile == IMG_NULL)
    {
        SYSOSKM_DestroyMutex(pFileHandler->hMutexHandle);
        REPORT(REPORT_MODULE_PERFLOG, REPORT_ERR,
               "Performance logger cannot create file in debug file system");
        return IMG_ERROR_FATAL;
    }

    return IMG_SUCCESS;
}
/*!
 ******************************************************************************

 @Function				DMANKM_RegisterDevice

 ******************************************************************************/
IMG_RESULT DMANKM_RegisterDevice(IMG_CHAR * pszDeviceName,
		DMANKM_pfnDevRegister pfnDevRegister) 
{
	DMANKM_sDevContext * psDevContext;
	IMG_UINT32 ui32Result;

	/* If the device context list is not initialised...*/
	if (!gbDevListInitialised) {
		/* Initialise the device context list...*/
		LST_init(&gsDevList);

		gbDevListInitialised = IMG_TRUE;
	}

	/* Locate the device - ensure it's not registered twice...*/
	ui32Result = DMANKM_LocateDevice(pszDeviceName,
			(IMG_HANDLE *) &psDevContext);
	if (ui32Result != IMG_ERROR_DEVICE_NOT_FOUND) {
        IMG_ASSERT(ui32Result == IMG_ERROR_DEVICE_NOT_FOUND);
		return IMG_ERROR_GENERIC_FAILURE;
	}

	/* Allocate a device context structure...*/
	psDevContext = IMG_MALLOC(sizeof(*psDevContext));
	if (psDevContext == IMG_NULL ) 
    {
        IMG_ASSERT(psDevContext != IMG_NULL);
		return IMG_ERROR_OUT_OF_MEMORY;
	}

	IMG_MEMSET(psDevContext, 0, sizeof(*psDevContext));

	/* Setup the device context...*/
	psDevContext->ui32DeviceId = gui32NextDeviceID;
	gui32NextDeviceID++;
	psDevContext->pszDeviceName = IMG_STRDUP(pszDeviceName);
	if (psDevContext->pszDeviceName == IMG_NULL ) 
    {
        IMG_ASSERT(psDevContext->pszDeviceName != IMG_NULL);
		ui32Result = IMG_ERROR_OUT_OF_MEMORY;
		goto error_dev_name;
	}
	psDevContext->pfnDevRegister = pfnDevRegister;
	psDevContext->ui8ApmPpmFlags = 0;
	ui32Result = SYSOSKM_CreateMutex(&psDevContext->hMutexHandle);
	IMG_ASSERT(ui32Result == IMG_SUCCESS);
	if (ui32Result != IMG_SUCCESS) {
		goto error_create_mutex;
	}
	LST_init(&psDevContext->sConnList);

	/* Disable interrupts...*/
	SYSOSKM_DisableInt();

	/* Add device to list...*/
	LST_add(&gsDevList, psDevContext);

	/* Re-enable interrupts...*/
	SYSOSKM_EnableInt();

	/* If initialised...*/
	if (gDmanKmInitialised) {
		/* Call device registration function...*/
		ui32Result = psDevContext->pfnDevRegister(&psDevContext->sDevRegister);
		IMG_ASSERT(ui32Result == IMG_SUCCESS);
		if (ui32Result != IMG_SUCCESS) {
			goto error_dev_register;
		}

		/* Set default if required...*/
		if (psDevContext->sDevRegister.ui32ConnFlags == 0) {
			psDevContext->sDevRegister.ui32ConnFlags = DMAN_CFLAG_EXCLUSIVE;
		}
	}

	/* Return success...*/
	return IMG_SUCCESS;

	/* Error handling. */
	error_dev_register: SYSOSKM_DisableInt();
	LST_remove(&gsDevList, psDevContext);
	SYSOSKM_EnableInt();
	SYSOSKM_DestroyMutex(psDevContext->hMutexHandle);
	error_create_mutex:
	IMG_FREE(psDevContext->pszDeviceName);
	error_dev_name:
	IMG_FREE(psDevContext);

	return ui32Result;
}
/*!
 ******************************************************************************

 @Function				DMANKM_OpenDevice

 ******************************************************************************/
IMG_RESULT DMANKM_OpenDevice(IMG_HANDLE hDevHandle, DMAN_eOpenMode eOpenMode,
		IMG_HANDLE * phConnHandle, IMG_UINT32 * pui32ConnId) 
{
	DMANKM_sDevContext * psDevContext = (DMANKM_sDevContext *) hDevHandle;
	DMANKM_sConnContext * psConnContext;
	DMANKM_sConnContext * psInitConnContext = IMG_NULL;
	IMG_UINT32 ui32Result;
	IMG_HANDLE hProcessId;

	/* Check mode. */
	if ((eOpenMode != DMAN_OMODE_EXCLUSIVE)
			&& (eOpenMode != DMAN_OMODE_SHARED)) {
		IMG_ASSERT(IMG_FALSE);
		return IMG_ERROR_INVALID_PARAMETERS;
	}

	/* Loop over the device connections to see if this process already has a connection...*/
	hProcessId = SYSOSKM_GetProcessId();
	psConnContext = (DMANKM_sConnContext *) LST_first(&psDevContext->sConnList);
	while (psConnContext != IMG_NULL ) {
		/* If process already has a connection. */
		if (psConnContext->hProcessId == hProcessId) {
			/* Update the open count...*/
			psConnContext->ui32OpenCnt++;

			/* Return the connection handle and/or id...*/
			if (phConnHandle != IMG_NULL ) {
				*phConnHandle = psConnContext;
			}
			if (pui32ConnId != IMG_NULL ) {
				*pui32ConnId = psConnContext->ui32ConnId;
			}

			/* Return success...*/
			return IMG_SUCCESS;
		}

		/* Look at next connection. */
		psConnContext = (DMANKM_sConnContext *) LST_next(psConnContext);
	}

	/* See if we have a connection exclusive access required or only exclusive access available. */
	psConnContext = (DMANKM_sConnContext *) LST_first(&psDevContext->sConnList);
	if ((psConnContext != IMG_NULL )&&
	( (eOpenMode == DMAN_OMODE_EXCLUSIVE) ||
			(psConnContext->psDevContext->sDevRegister.ui32ConnFlags == DMAN_CFLAG_EXCLUSIVE) )
	){
	IMG_ASSERT(IMG_FALSE);
	return IMG_ERROR_DEVICE_UNAVAILABLE;
}

	/* Allocate connection context...*/
	psConnContext = IMG_MALLOC(sizeof(*psConnContext));
	if (psConnContext == IMG_NULL ) 
    {
        IMG_ASSERT(psConnContext != IMG_NULL);
		return IMG_ERROR_OUT_OF_MEMORY;
	}
	IMG_MEMSET(psConnContext, 0, sizeof(*psConnContext));

	/* Initialise list of resource allocator...*/
	LST_init(&psConnContext->sAttachList);

	/* Setup connection context...*/
	psConnContext->psDevContext = psDevContext;
	psConnContext->ui32OpenCnt = 1;
	psConnContext->hProcessId = hProcessId;

	/* Update the count of connections...*/
	psDevContext->ui32ConnCnt++;

	/* If this is the first connection...*/
	if (psDevContext->ui32ConnCnt == 1) {
		/* Create resource bucket for connections and attachments...*/
		RMAN_Initialise();
		ui32Result = RMAN_CreateBucket(&psDevContext->hResBHandle);
		IMG_ASSERT(ui32Result == IMG_SUCCESS);
		if (ui32Result != IMG_SUCCESS) {
			goto error_create_bucket;
		}
	}

	/* Add to list of connections...*/
	LST_add(&psDevContext->sConnList, psConnContext);
	ui32Result = RMAN_RegisterResource(psDevContext->hResBHandle,
			DMAN_CONN_TYPE_ID, IMG_NULL, psConnContext,
			&psConnContext->hResHandle, &psConnContext->ui32ConnId);
	IMG_ASSERT(ui32Result == IMG_SUCCESS);
	if (ui32Result != IMG_SUCCESS) {
		goto error_register_resource;
	}

	/* Register with the Process Manager in case the process dies...*/
	ui32Result = PMAN_Initialise();
	IMG_ASSERT(ui32Result == IMG_SUCCESS);
	if (ui32Result != IMG_SUCCESS) {
		goto error_pman_init;
	}
	PMAN_RegisterProcessLostCb(dmankm_fnProcessLostCb, psConnContext,
			&psConnContext->hProcLostCbHandle);
	IMG_ASSERT(ui32Result == IMG_SUCCESS);
	if (ui32Result != IMG_SUCCESS) {
		goto error_pman_register_cb;
	}

	/* If this the first connection and initialise function...*/
	if ((psDevContext->ui32ConnCnt == 1)
			&& (psDevContext->sDevRegister.pfnDevInit != IMG_NULL )) {
		/* Allocate implicit connection context...*/
		psInitConnContext = IMG_MALLOC(sizeof(*psInitConnContext));
		if (psInitConnContext == IMG_NULL ) 
        {
            IMG_ASSERT(psInitConnContext != IMG_NULL);
			ui32Result = IMG_ERROR_OUT_OF_MEMORY;
			goto error_init_conn_ctx;
		}
		IMG_MEMSET(psInitConnContext, 0, sizeof(*psInitConnContext));

		/* Associated this connection with the device and process...*/
		psInitConnContext->psDevContext = psDevContext;
		psInitConnContext->ui32OpenCnt = 1;
		psInitConnContext->hProcessId = hProcessId;

		/* Mark this as the init connection...*/
		psInitConnContext->bInitConn = IMG_TRUE;

		/* Add implicit to list of connections...*/
		LST_add(&psDevContext->sConnList, psInitConnContext);
		ui32Result = RMAN_RegisterResource(psDevContext->hResBHandle,
				DMAN_CONN_TYPE_ID, IMG_NULL, psInitConnContext,
				&psInitConnContext->hResHandle, &psInitConnContext->ui32ConnId);
		IMG_ASSERT(ui32Result == IMG_SUCCESS);
		if (ui32Result != IMG_SUCCESS) {
			goto error_register_resource_init_ctx;
		}

		IMG_ASSERT(
				(psDevContext->sDevRegister.ui32ConnFlags == DMAN_CFLAG_EXCLUSIVE) || (psDevContext->sDevRegister.ui32ConnFlags == DMAN_CFLAG_SHARED));

		/* If it's not a pseudo device...  */
		if ((psDevContext->sDevRegister.ui32DevFlags & DMAN_DFLAG_PSEUDO_DEVICE)
				== 0) {
			/* Open the device...*/
			ui32Result = SYSDEVU_OpenDevice(psDevContext->pszDeviceName,
					&psDevContext->hSysDevHandle);
			IMG_ASSERT(ui32Result == IMG_SUCCESS);
			if (ui32Result != IMG_SUCCESS) {
				goto error_open_device;
			}

			/* Power the device on.  */
			SYSDEVU_SetPowerState(psDevContext->hSysDevHandle,
					SYSOSKM_POWERSTATE_S0, IMG_FALSE);
		}

		ui32Result = psDevContext->sDevRegister.pfnDevInit(psDevContext,
				psInitConnContext, &psDevContext->pvDevInstanceData);
		if (ui32Result != IMG_SUCCESS) {
			REPORT(REPORT_MODULE_DMAN, REPORT_ERR, "dev init failed (%d)",
				ui32Result);
			goto error_dev_init;
		}

		/* If there is a Device Kernel mode HISR...*/
		if (psDevContext->sDevRegister.pfnDevKmHisr != IMG_NULL ) {
			IMG_ASSERT(psDevContext->sDevRegister.pfnDevKmLisr != IMG_NULL);
			ui32Result = SYSOSKM_CreateKmHisr(&dmankm_fnDevKmHisr, psDevContext,
					&psDevContext->hHISRHandle);
			IMG_ASSERT(ui32Result == IMG_SUCCESS);
			if (ui32Result != IMG_SUCCESS) {
				goto error_create_km_hisr;
			}
		}

		/* If there is a Device Kernel mode LISR...*/
		if (psDevContext->sDevRegister.pfnDevKmLisr != IMG_NULL ) {
			/* Register the LISR wrapper...*/
			SYSDEVU_RegisterDevKmLisr(psDevContext->hSysDevHandle,
					&dmankm_fnDevKmLisr, psDevContext);
		}
	}

	/* If connect/open function...*/
	if (psDevContext->sDevRegister.pfnDevConnect != IMG_NULL ) {
		ui32Result = psDevContext->sDevRegister.pfnDevConnect(psConnContext,
				psDevContext->pvDevInstanceData,
				&psConnContext->pvDevConnectionData);
		IMG_ASSERT(
				ui32Result == IMG_SUCCESS || ui32Result == IMG_ERROR_INTERRUPTED);
		if (ui32Result != IMG_SUCCESS && ui32Result != IMG_ERROR_INTERRUPTED) {
			goto error_dev_connect;
		}
	}

	/* Return the connection handle and/or id...*/
	if (phConnHandle != IMG_NULL ) {
		*phConnHandle = psConnContext;
	}
	if (pui32ConnId != IMG_NULL ) {
		*pui32ConnId = psConnContext->ui32ConnId;
	}

	/* Return success...*/
	return ui32Result;

	/* Error handling. */
error_dev_connect:
	/* If this not the first connection or there's no initialise function...*/
	if ((1 != psDevContext->ui32ConnCnt)
			|| (IMG_NULL == psDevContext->sDevRegister.pfnDevInit)) {
		/* ...skip de-initialisation of this part. */
		goto error_init_conn_ctx;
	}

	if (IMG_NULL != psDevContext->sDevRegister.pfnDevKmHisr) {
		SYSOSKM_DestroyKmHisr(psDevContext->hHISRHandle);
	}

error_create_km_hisr:
	if (IMG_NULL
			!= psDevContext->sDevRegister.pfnDevDeinit) {
		psDevContext->sDevRegister.pfnDevDeinit(psDevContext, psInitConnContext,
				psDevContext->pvDevInstanceData);
	}

error_dev_init:
	if ((psDevContext->sDevRegister.ui32DevFlags
			& DMAN_DFLAG_PSEUDO_DEVICE) == 0) {
		SYSDEVU_CloseDevice(psDevContext->hSysDevHandle);
	}

error_open_device:
	RMAN_FreeResource(psInitConnContext->hResHandle);

error_register_resource_init_ctx:
	LST_remove(&psDevContext->sConnList, psInitConnContext);
	IMG_FREE(psInitConnContext);

error_init_conn_ctx:
	PMAN_RemoveProcessLostCb(psConnContext->hProcLostCbHandle);
	/* release per-process resources in PMAN, allocated inside
	   PMAN_RegisterProcessLostCb. We have to use device disconnect,
	   although the device wasn't actually initialised, because no
	   other function is exposed by PMAN */
	PMAN_DevDisconnectComplete(hProcessId);

error_pman_register_cb:
error_pman_init:
	RMAN_FreeResource(psConnContext->hResHandle);

error_register_resource:
	LST_remove(&psDevContext->sConnList,psConnContext);
	if (1 == psDevContext->ui32ConnCnt) {
		RMAN_DestroyBucket(psDevContext->hResBHandle);
	}

error_create_bucket:
	psDevContext->ui32ConnCnt--;
	IMG_FREE(psConnContext);

	return ui32Result;
}
/*!
******************************************************************************

 @Function                POOL_ResRegister

******************************************************************************/
IMG_RESULT POOL_ResRegister(
    IMG_HANDLE          hPoolHandle,
    POOL_pfnDestructor  pfnDestructor,
    IMG_VOID *          pvParam,
    IMG_UINT32          ui32SizevParam,
    IMG_BOOL            bAlloc,
    IMG_UINT32 *        pui32ResId,
    IMG_HANDLE *        phPoolResHandle
)
{
    POOL_sResPool *   psResPool = hPoolHandle;
    POOL_sResource *  psResource;
    IMG_UINT32        ui32Result;

    IMG_ASSERT(gInitialised);
    IMG_ASSERT(psResPool != IMG_NULL);

    if (!gInitialised ||
        psResPool == IMG_NULL)
    {
        ui32Result = IMG_ERROR_INVALID_PARAMETERS;
        goto error_nolock;
    }

    /* Allocate a resource structure...*/
    psResource = IMG_MALLOC(sizeof(*psResource));
    IMG_ASSERT(psResource != IMG_NULL);
    if (psResource == IMG_NULL)
    {
        return IMG_ERROR_OUT_OF_MEMORY;
    }
    IMG_MEMSET(psResource, 0, sizeof(*psResource));

    /* Setup the resource...*/
    psResource->pfnDestructor  = pfnDestructor;
    psResource->pvParam        = pvParam;
    psResource->ui32SizevParam = ui32SizevParam;
    psResource->psResPool      = psResPool;
    LST_init(&psResource->sCloneResList);

    /* Lock the pool...*/
    SYSOSKM_LockMutex(psResPool->hMutexHandle);

    /* Set resource id...*/
    ui32Result = IDGEN_AllocId(psResPool->hIdGenHandle, (IMG_HANDLE)psResource, &psResource->ui32ResId);
    IMG_ASSERT(ui32Result == IMG_SUCCESS);
    if (ui32Result != IMG_SUCCESS)
    {
        IMG_FREE(psResource);
        /* Unlock the pool...*/
        SYSOSKM_UnlockMutex(psResPool->hMutexHandle);

        return ui32Result;
    }

    /* If allocated or free callback not set...*/
    if ( (bAlloc) || (psResPool->pfnFree != IMG_NULL) )
    {
        /* Add to active list...*/
        LST_add(&psResPool->sActResList, psResource);
        psResource->ui32RefCnt++;
    }
    else
    {
        /* Add to free list...*/
        LST_add(&psResPool->sFreeResList, psResource);
    }

    /* Return the resource id...*/
    if (pui32ResId != IMG_NULL)
    {
        *pui32ResId = psResource->ui32ResId;
    }

    /* Return the handle to the resource...*/
    if (phPoolResHandle != IMG_NULL)
    {
        *phPoolResHandle = psResource;
    }

    /* Unlock the pool...*/
    SYSOSKM_UnlockMutex(psResPool->hMutexHandle);


    /* If free callback set...*/
    if (psResPool->pfnFree != IMG_NULL)
    {
        /* Call the free callback...*/
        psResPool->pfnFree(psResource->ui32ResId, psResource->pvParam);
    }

    /* Return IMG_SUCCESS...*/
    return IMG_SUCCESS;

error_nolock:
    return ui32Result;
}
/*!
******************************************************************************

 @Function              MMU_DeviceCreate

******************************************************************************/
IMG_RESULT  MMU_DeviceCreate(
    MMU_eMmuType                    eMmuType,
    VDEC_eTileScheme                eTileScheme,
    VDECDDMMU_pfnDeviceCallback     pfnDeviceCallback,
    MSVDXIO_sMemPool                sMemPool,
    IMG_VOID                      * pvCallbackParameter,
    IMG_UINT32                      ui32PtdAlignment,
    IMG_HANDLE                    * phMmuDevHandle
)
{
    IMG_RESULT          ui32Result = IMG_SUCCESS;
    IMG_BOOL            bTiling = IMG_TRUE;
    TALMMU_eMMUType     eTalMmuType = TALMMU_MMUTYPE_4K_PAGES_32BIT_ADDR;
    IMG_UINT32          i;
    MMU_sDevContext *   psDevContext;
    TALMMU_sDevMemInfo  sDevMemInfo;

    // Set the TAL MMU type.
    switch (eMmuType)
    {
    case MMU_TYPE_32BIT:
        eTalMmuType = TALMMU_MMUTYPE_4K_PAGES_32BIT_ADDR;
        break;

    case MMU_TYPE_36BIT:
        eTalMmuType = TALMMU_MMUTYPE_4K_PAGES_36BIT_ADDR;
        break;

    case MMU_TYPE_40BIT:
        eTalMmuType = TALMMU_MMUTYPE_4K_PAGES_40BIT_ADDR;
        break;

    default:
        return IMG_ERROR_INVALID_PARAMETERS;
    }

    /* Allocate a device context structure...*/
    VDEC_MALLOC(psDevContext);
    IMG_ASSERT(psDevContext != IMG_NULL);
    if (psDevContext == IMG_NULL)
    {
        REPORT(REPORT_MODULE_MMU, REPORT_ERR,
               "Failed to allocate memory for MMU device context");
        return IMG_ERROR_OUT_OF_MEMORY;
    }
    VDEC_BZERO(psDevContext);

    /* Initialise stream list. */
    LST_init(&psDevContext->sStrList);

    psDevContext->pfnDeviceCallback = pfnDeviceCallback;
    psDevContext->pvCallbackParameter = pvCallbackParameter;

    /* Initialise TALMMU. */
    ui32Result = TALMMU_Initialise();
    IMG_ASSERT(ui32Result == IMG_SUCCESS);
    if (ui32Result != IMG_SUCCESS)
    {
        goto error_tal_init;
    }

    /* Create an MMU template */
    sDevMemInfo.pszDeviceName = "VDEC";
    sDevMemInfo.ui32DeviceId = 0;
    sDevMemInfo.eMMUType = eTalMmuType;
    sDevMemInfo.eDevFlags = TALMMU_DEVFLAGS_NONE;
    sDevMemInfo.pszPageDirMemSpaceName = "MEM";
    sDevMemInfo.pszPageTableMemSpaceName = IMG_NULL;
    sDevMemInfo.ui32PageSize = DEV_MMU_PAGE_SIZE;
    sDevMemInfo.ui32PageTableDirAlignment = ui32PtdAlignment;
    sDevMemInfo.eMemAttrib = (SYS_MEMATTRIB_UNCACHED | SYS_MEMATTRIB_WRITECOMBINE);
    sDevMemInfo.eMemPool = sMemPool.eMemPoolId;
    sDevMemInfo.eTilingScheme = (eTileScheme == VDEC_TS1_512x8) ? TALMMU_MMUTILING_SCHEME_1 : TALMMU_MMUTILING_SCHEME_0;

    ui32Result = TALMMU_DevMemTemplateCreate(&sDevMemInfo, &psDevContext->hDevMemTemplate);
    IMG_ASSERT(ui32Result == IMG_SUCCESS);
    if (ui32Result != IMG_SUCCESS)
    {
        goto error_tal_template;
    }

    TALMMU_AddCallback(psDevContext->hDevMemTemplate,
                       mmu_Callback,
                       (IMG_PVOID)psDevContext);

    /* Add heaps to template */
    for (i = 0; i < MMU_HEAP_MAX; i++)
    {
        sHeapInfo.ui32HeapId = asMmuHeaps[i].eHeapId;
        sHeapInfo.eHeapType = asMmuHeaps[i].eHeapType;
        sHeapInfo.pszMemSpaceName = asMmuHeaps[i].pszMemSpace;
        sHeapInfo.bTiled = (bTiling && asMmuHeaps[i].ui32TileStride) ? IMG_TRUE : IMG_FALSE;
        sHeapInfo.ui32BaseDevVirtAddr = asMmuHeaps[i].ui32StartOffset;
        sHeapInfo.ui32Size = asMmuHeaps[i].ui32Size;
        sHeapInfo.ui32XTileStride = 0;

        if (asMmuHeaps[i].ui32TileStride)
        {
            IMG_UINT32  ui32HwTileStride;
            IMG_UINT32  ui32Log2HwTileStride = 0;

            ui32HwTileStride = asMmuHeaps[i].ui32TileStride;
            // Calculate HW tile stride.
            // HW tile stride = log2((tile_stride / tile_width)/ 2)
            ui32HwTileStride >>= 1;
            switch (eTileScheme)
            {
            case VDEC_TS0_256x16:
                ui32HwTileStride >>= 8;
                break;
            case VDEC_TS1_512x8:
                ui32HwTileStride >>= 9;
                break;
            default:
                IMG_ASSERT(0);
                break;
            }

            ui32HwTileStride >>= 1;
            while (ui32HwTileStride)
            {
                ui32HwTileStride >>= 1;
                ui32Log2HwTileStride++;
            }
            // Calculated hardware coded stride value.
            ui32HwTileStride = ui32Log2HwTileStride;

            sHeapInfo.ui32XTileStride = ui32HwTileStride;
        }

        ui32Result = TALMMU_DevMemHeapAdd(psDevContext->hDevMemTemplate, &sHeapInfo);
        IMG_ASSERT(ui32Result == IMG_SUCCESS);
        if (ui32Result != IMG_SUCCESS)
        {
            goto error_tal_heap;
        }
    }