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

 @Function                pciio_DeviceAttach

******************************************************************************/
static IMG_RESULT pciio_DeviceAttach(
    IMG_CHAR *      pszDevName,
    SECDEV_eMapArea  eArea
)
{
    IMG_UINT32  ui32Result;

    IMG_ASSERT(gpszDevName != IMG_NULL);
    if (gpszDevName != IMG_NULL)
    {
        IMG_ASSERT(IMG_STRCMP(pszDevName, gpszDevName) == 0);
    }
    else
    {
        return IMG_ERROR_GENERIC_FAILURE;
    }

    /* In this implementation we initialise the PCI component */
    ui32Result = pciio_PciDetectDevice(eArea);
    IMG_ASSERT(ui32Result == IMG_SUCCESS);
    if (ui32Result != IMG_SUCCESS)
    {
        return ui32Result;
    }

    return IMG_SUCCESS;
}
__inline static SYSDEVU_sInfo *findDeviceByName(IMG_CHAR *devName) {
	SYSDEVU_sInfo *dev = (SYSDEVU_sInfo *)LST_first(&gsDevList);
	while(dev != IMG_NULL)
	{
		if(!IMG_STRCMP(devName, dev->sDevInfo.pszDeviceName))
			return dev;
		dev = LST_next(dev);
	}
	return IMG_NULL;
}
/*!
******************************************************************************

 @Function				memmappedio_DeviceAttach

******************************************************************************/
static IMG_RESULT memmappedio_DeviceAttach(
    IMG_CHAR *				pszDevName,
	SECDEV_eMapArea    eArea
)
{
	IMG_ASSERT(gpszDevName != IMG_NULL);
	if (gpszDevName != IMG_NULL)
	{
		IMG_ASSERT(IMG_STRCMP(pszDevName, gpszDevName) == 0);
	}
	else
	{
		return IMG_ERROR_GENERIC_FAILURE;
	}

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

 @Function              DMANKM_LocateDevice

 ******************************************************************************/
IMG_RESULT DMANKM_LocateDevice(IMG_CHAR * pszDeviceName,
		IMG_HANDLE * phDevHandle) 
{
	DMANKM_sDevContext * psDevContext;

	/* Search list of registered devices for this device...*/
	IMG_ASSERT(gbDevListInitialised);
	psDevContext = (DMANKM_sDevContext *) LST_first(&gsDevList);
	while ((psDevContext != IMG_NULL )&&
	IMG_STRCMP(psDevContext->pszDeviceName, pszDeviceName)
	) {
		psDevContext = (DMANKM_sDevContext *) LST_next(psDevContext);
	}

	*phDevHandle = psDevContext;

	/* If not found...*/
	if (psDevContext == IMG_NULL ) 
    {
		return IMG_ERROR_DEVICE_NOT_FOUND;
	}

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

 @Function				dman_LocateComponentKM

 ******************************************************************************/
static IMG_BOOL dman_LocateComponentKM(IMG_CHAR * pszCompName,
		DMANKM_sConnContext * psConnContext,
		DMANKM_sAttachContext ** ppsAttachContext) 
{
	DMANKM_sAttachContext * psAttachContext;

	/* Search list of attached resource allocator for this connection...*/
	psAttachContext = (DMANKM_sAttachContext *) LST_first(
			&psConnContext->sAttachList);
	while ((psAttachContext != IMG_NULL )&&
	(IMG_STRCMP(psAttachContext->pszCompName, pszCompName) != 0)
	){
	psAttachContext = (DMANKM_sAttachContext *)LST_next(psAttachContext);
}

	/* If resource allocator found...*/
	if (psAttachContext != IMG_NULL ) {
		*ppsAttachContext = psAttachContext;
		return IMG_TRUE;
	}

	/* Device not found....*/
	return IMG_FALSE;
}
/*!
******************************************************************************

@Function				ADDR_Free

******************************************************************************/
IMG_RESULT ADDR_CxFree(
            ADDR_sContext * const   psContext,
    const   IMG_CHAR * const        pszName,
            IMG_UINT64              ui64Addr
)
{
    ADDR_sRegion * psTmpRegion;
    IMG_RESULT ui32Result;

    IMG_ASSERT(IMG_NULL != psContext);
    if (IMG_NULL == psContext)
    {
        ui32Result = IMG_ERROR_INVALID_PARAMETERS;
        goto error_invalid_parameters;
    }

	psTmpRegion = psContext->psRegions;

    addr_alloc_Lock();

	//Ignore given name, find using the address
    if (psContext->bUseRandomBlocks)  
    {
        //Try Default Region 
        psTmpRegion = psContext->psDefaultRegion;
        if ( IMG_NULL != psTmpRegion &&
            ui64Addr >= psTmpRegion->ui64BaseAddr &&
            ui64Addr < (psTmpRegion->ui64BaseAddr + psTmpRegion->ui64Size))
        { 
            //Memory is on the default region 
        }
        else
        {
            psTmpRegion = psContext->psRegions;
            //Continue looping while address is not inside current region 
            while ( (ui64Addr < psTmpRegion->ui64BaseAddr) 
                || (ui64Addr >= psTmpRegion->ui64BaseAddr + psTmpRegion->ui64Size) )
            {
                IMG_ASSERT(IMG_NULL != psTmpRegion->psNextRegion);
                if (IMG_NULL == psTmpRegion->psNextRegion)
                {
                    ui32Result = IMG_ERROR_INVALID_PARAMETERS;
                    goto error;
                }
                psTmpRegion = psTmpRegion->psNextRegion;
            }
        }
    }
	//If the allocation is for the default region
    else if (IMG_NULL == pszName) 
    {
        IMG_ASSERT(IMG_NULL != psContext->psDefaultRegion);
        if (IMG_NULL == psContext->psDefaultRegion)
        {
            ui32Result = IMG_ERROR_INVALID_PARAMETERS;
            goto error;
        }
        psTmpRegion = psContext->psDefaultRegion;
    }
    else
    {
        //Run down the list of existing named regions to locate this
        while ((IMG_NULL != psTmpRegion) &&
            (IMG_STRCMP(pszName, psTmpRegion->pszName) != 0) &&
            (psTmpRegion->psNextRegion))
        {
            psTmpRegion = psTmpRegion->psNextRegion;
        }

        //If there was no match.
        if ((IMG_NULL == psTmpRegion) ||
            (IMG_STRCMP(pszName, psTmpRegion->pszName) != 0))
        {
            //Use the default
            IMG_ASSERT(IMG_NULL != psContext->psDefaultRegion);
            if (IMG_NULL == psContext->psDefaultRegion)
            {
                ui32Result = IMG_ERROR_INVALID_PARAMETERS;
                goto error;
            }
            psTmpRegion = psContext->psDefaultRegion;
        }
    }

    //Free the address
    ui32Result = VID_RA_Free(psTmpRegion->phArena, ui64Addr);

error:
    addr_alloc_UnLock();

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

@Function				addr_CxMalloc1

******************************************************************************/
static IMG_RESULT addr_CxMalloc1(
    const   ADDR_sContext *     psContext,
    const   IMG_CHAR * const    pszName,
            IMG_UINT64          ui64Size,
            IMG_UINT64          ui64Alignment,
            IMG_UINT64 * const  pui64Base
)
{
    ADDR_sRegion * psTmpRegion = IMG_NULL;
    IMG_UINT32 ui32Result = IMG_ERROR_FATAL;

    IMG_ASSERT(IMG_NULL != psContext);
    IMG_ASSERT(IMG_NULL != pui64Base);
    IMG_ASSERT(IMG_NULL != pszName);

    if(IMG_NULL == psContext ||
        IMG_NULL == pui64Base ||
        IMG_NULL == pszName)
    {
        ui32Result = IMG_ERROR_INVALID_PARAMETERS;
        goto error_invalid_parameters;
    }

    do
    {
        psTmpRegion = psContext->psRegions;
		
        //If we are using random blocks, ignore the given blockname
        if (psContext->bUseRandomBlocks) 
        {
#if !defined (IMG_KERNEL_MODULE)
            IMG_UINT32 ui32BlockNo;

            //Select a random number from 0 to num blocks -1
            while (psContext->ui32NoRegions <= (ui32BlockNo = rand() / (RAND_MAX/psContext->ui32NoRegions)));

            //0 counts as default region
            if (0 == ui32BlockNo)
            {
                IMG_ASSERT(IMG_NULL != psContext->psDefaultRegion);
                if(IMG_NULL == psContext->psDefaultRegion)
                {
                    ui32Result = IMG_ERROR_UNEXPECTED_STATE;
                    goto error_null_region;
                }
                psTmpRegion = psContext->psDefaultRegion;
            }
            else
            {
                //Count through the region list to the random one which has been selected
                while (ui32BlockNo > 1)
                {
                    IMG_ASSERT(psTmpRegion->psNextRegion);
                    if(IMG_NULL == psTmpRegion->psNextRegion)
                    {
                        ui32Result = IMG_ERROR_UNEXPECTED_STATE;
                        goto error_null_region;
                    }
                    psTmpRegion = psTmpRegion->psNextRegion;
                    ui32BlockNo --;
                }
            }
#else
            IMG_ASSERT(IMG_FALSE);	//Not supported in kernel mode 
            return IMG_ERROR_OUT_OF_MEMORY;
#endif
        }
        //If the allocation is for the default region
        else if (IMG_NULL == pszName)
        {
            IMG_ASSERT(IMG_NULL != psContext->psDefaultRegion);
            if(IMG_NULL == psContext->psDefaultRegion)
            {
                ui32Result = IMG_ERROR_UNEXPECTED_STATE;
                goto error_null_region;
            }
            psTmpRegion = psContext->psDefaultRegion;
        }
        else
        {
            //Run down the list of existing named regions to locate this
            while((IMG_NULL != psTmpRegion) && 
                (IMG_STRCMP(pszName, psTmpRegion->pszName) != 0) &&
                (psTmpRegion->psNextRegion)
                )
            {
                psTmpRegion = psTmpRegion->psNextRegion;
            }

            //If there was no match.
            if ((IMG_NULL == psTmpRegion) ||
                (IMG_STRCMP(pszName, psTmpRegion->pszName) != 0)
                )
            {
                //Use the default
                IMG_ASSERT(IMG_NULL != psContext->psDefaultRegion);
                if(IMG_NULL == psContext->psDefaultRegion)
                {
                    ui32Result = IMG_ERROR_UNEXPECTED_STATE;
                    goto error_null_region;
                }
                psTmpRegion = psContext->psDefaultRegion;
            }
        }

        IMG_ASSERT(IMG_NULL != psTmpRegion);
        if(IMG_NULL == psTmpRegion)
        {
            ui32Result = IMG_ERROR_UNEXPECTED_STATE;
            goto error_null_region;
        }

        //Allocate size + guard band
        ui32Result = VID_RA_Alloc( psTmpRegion->phArena, 
            ui64Size + psTmpRegion->ui32GuardBand, 
            IMG_NULL,
            IMG_NULL, 
            (psContext->bUseRandomAllocation) ? RANDOM_ALLOCATION : SEQUENTIAL_ALLOCATION, 
            ui64Alignment, 
            pui64Base);

        if (IMG_SUCCESS != ui32Result)
        {
            if (psContext->bUseRandomBlocks)
            {
                continue; //If we have overrun, pick a different region 
            }
#if !defined (IMG_KERNEL_MODULE)
            if (psTmpRegion->pszName)
            {
                printf("ERROR: Memory Region %s is full\n", psTmpRegion->pszName);
            }
            else
            {
                printf("ERROR: Default Memory Region is full\n");
            }
#endif			
            IMG_ASSERT(IMG_FALSE);
            return IMG_ERROR_OUT_OF_MEMORY;
        }
        break;

    }while (IMG_TRUE);

error_invalid_parameters:
error_null_region:
    return ui32Result;
}
/*!
******************************************************************************

@Function				ADDR_CxDefineMemoryRegion

******************************************************************************/
IMG_RESULT ADDR_CxDefineMemoryRegion(
    ADDR_sContext *  const psContext,
    ADDR_sRegion *   const psRegion
)
{
    ADDR_sRegion * psTmpRegion = IMG_NULL;
    IMG_UINT32 ui32Result = IMG_SUCCESS;

    IMG_ASSERT(IMG_NULL != psContext);
    IMG_ASSERT(IMG_NULL != psRegion);
    if (IMG_NULL == psContext ||
        IMG_NULL == psRegion)
    {
        ui32Result = IMG_ERROR_INVALID_PARAMETERS;
        goto error;
    }

    addr_alloc_Lock();

    psTmpRegion = psContext->psRegions;

    //Ensure the link to the next is NULL
    psRegion->psNextRegion = IMG_NULL;

    //If this is the default memory region
    if (IMG_NULL == psRegion->pszName)
    {
        //Should not previously have been defined
        IMG_ASSERT(IMG_NULL == psContext->psDefaultRegion);
        if (IMG_NULL != psContext->psDefaultRegion)
        {
            addr_alloc_UnLock();
            ui32Result = IMG_ERROR_UNEXPECTED_STATE;
            goto error;
        }

        psContext->psDefaultRegion = psRegion;
        psContext->ui32NoRegions ++;

        //Create an arena for memory allocation 
        ui32Result = VID_RA_Create (
            "memory",					//name of resource arena for debug 
            psRegion->ui64BaseAddr,		//start of resource 
            psRegion->ui64Size,			//size of resource 
            1,							//allocation quantum 
            IMG_NULL,					//import allocator 
            IMG_NULL,					//import deallocator 
            IMG_NULL,					//import handle 
            &psRegion->phArena);

        IMG_ASSERT(IMG_SUCCESS == ui32Result);
        if(IMG_SUCCESS != ui32Result)
        {
            addr_alloc_UnLock();
            ui32Result = IMG_ERROR_UNEXPECTED_STATE;
            goto error;
        }
    }
    else
    {
        //Run down the list of existing named regions to check if there is a region with this name
        while ((IMG_NULL != psTmpRegion) &&
            (IMG_STRCMP(psRegion->pszName, psTmpRegion->pszName) != 0) &&
            (IMG_NULL != psTmpRegion->psNextRegion)
            )
        {
            psTmpRegion = psTmpRegion->psNextRegion;
        }

        //If we have items in the list
        if (IMG_NULL != psTmpRegion)
        {
            //Check we didn't stop because the name clashes with one already defined..
            IMG_ASSERT(IMG_STRCMP(psRegion->pszName, psTmpRegion->pszName) != 0);
            IMG_ASSERT(IMG_NULL == psTmpRegion->psNextRegion);

            if (IMG_STRCMP(psRegion->pszName, psTmpRegion->pszName) == 0 ||
                IMG_NULL != psTmpRegion->psNextRegion
                )
            {
                addr_alloc_UnLock();
                ui32Result = IMG_ERROR_UNEXPECTED_STATE;
                goto error;
            }

            //Add to end of list
            psTmpRegion->psNextRegion = psRegion;
        }
        else
        {
            //Add to head of list 
            psContext->psRegions = psRegion;
        }

        psContext->ui32NoRegions ++;

        //Create an arena for memory allocation 
        ui32Result = VID_RA_Create(
            psRegion->pszName,			//name of resource arena for debug 
            psRegion->ui64BaseAddr,		//start of resource 
            psRegion->ui64Size,			//size of resource 
            1,							//allocation quantum 
            IMG_NULL,					//import allocator 
            IMG_NULL,					//import deallocator 
            IMG_NULL,					//import handle 
            &psRegion->phArena);

        IMG_ASSERT(IMG_SUCCESS == ui32Result);
        if(IMG_SUCCESS != ui32Result)
        {
            addr_alloc_UnLock();
            ui32Result = IMG_ERROR_UNEXPECTED_STATE;
            goto error;
        }
    }

    addr_alloc_UnLock();

    //Check the arean was created OK
    IMG_ASSERT(IMG_NULL != psRegion->phArena);
    if (IMG_NULL == psRegion->phArena)
    {
        ui32Result = IMG_ERROR_UNEXPECTED_STATE;
        goto error;
    }

error:
    return ui32Result;
}