static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice,
                                       IMG_HANDLE hSwapChain)
{
	DC_NOHW_DEVINFO	*psDevInfo;
	DC_NOHW_SWAPCHAIN *psSwapChain;

	
	if(!hDevice
	|| !hSwapChain)
	{
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	psDevInfo = (DC_NOHW_DEVINFO*)hDevice;
	psSwapChain = (DC_NOHW_SWAPCHAIN*)hSwapChain;

	
	FreeKernelMem(psSwapChain->psBuffer);
	FreeKernelMem(psSwapChain);

	
	psDevInfo->psSwapChain = 0;

	

	return (PVRSRV_OK);
}
static PVRSRV_ERROR DestroyDCSwapChain(IMG_HANDLE hDevice,
                                       IMG_HANDLE hSwapChain)
{
	DC_NOHW_DEVINFO	*psDevInfo;
	DC_NOHW_SWAPCHAIN *psSwapChain;

	/* check parameters */
	if(!hDevice
	|| !hSwapChain)
	{
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	psDevInfo = (DC_NOHW_DEVINFO*)hDevice;
	psSwapChain = (DC_NOHW_SWAPCHAIN*)hSwapChain;

	/* free resources */
	FreeKernelMem(psSwapChain->psBuffer);
	FreeKernelMem(psSwapChain);

	/* mark swapchain as not existing */
	psDevInfo->psSwapChain = 0;

	/* INTEGRATION_POINT: disable Vsync ISR */

	return (PVRSRV_OK);
}
DC_ERROR Deinit(void)
{
	DC_NOHW_DEVINFO *psDevInfo, *psDevFirst;
#if !defined(USE_BASE_VIDEO_FRAMEBUFFER)
	unsigned long i;
#endif

	psDevFirst = GetAnchorPtr();
	psDevInfo = psDevFirst;

	
	if (psDevInfo == 0)
	{
		return (DC_ERROR_GENERIC);
	}

	
	psDevInfo->ulRefCount--;

	if (psDevInfo->ulRefCount == 0UL)
	{
		
		PVRSRV_DC_DISP2SRV_KMJTABLE	*psJTable = &psDevInfo->sPVRJTable;

		
		if (psJTable->pfnPVRSRVRemoveDCDevice((IMG_UINT32)psDevInfo->uiDeviceID) != PVRSRV_OK)
		{
			return (DC_ERROR_GENERIC);
		}

		if (psDevInfo->sPVRJTable.pfnPVRSRVRemoveCmdProcList(psDevInfo->uiDeviceID,
															 DC_NOHW_COMMAND_COUNT) != PVRSRV_OK)
		{
			return (DC_ERROR_GENERIC);
		}

		if (ClosePVRServices(psDevInfo->hPVRServices) != DC_OK)
		{
			psDevInfo->hPVRServices = 0;
			return (DC_ERROR_GENERIC);
		}

#if !defined(USE_BASE_VIDEO_FRAMEBUFFER)
		for(i=0; i<DC_NOHW_MAX_BACKBUFFERS; i++)
		{
			if (psDevInfo->asBackBuffers[i].sCPUVAddr)
			{
				#if defined(DC_NOHW_DISCONTIG_BUFFERS)
				FreeDiscontigMemory(psDevInfo->ui32BufferSize,
							 psDevInfo->asBackBuffers[i].hMemChunk,
							 psDevInfo->asBackBuffers[i].sCPUVAddr,
							 psDevInfo->asBackBuffers[i].psSysAddr);
				#else

				FreeContigMemory(psDevInfo->ui32BufferSize,
							 psDevInfo->asBackBuffers[i].hMemChunk,
							 psDevInfo->asBackBuffers[i].sCPUVAddr,
							 SysPAddrToCpuPAddr(psDevInfo->asBackBuffers[i].sSysAddr));
				#endif
			}
		}
#endif 

		
		FreeKernelMem(psDevInfo);
	}

#if defined (ENABLE_DISPLAY_MODE_TRACKING)
	CloseMiniport();
#endif
	
	SetAnchorPtr(0);

	
	return (DC_OK);
}
DC_ERROR Init(void)
{
	DC_NOHW_DEVINFO *psDevInfo;
	DC_ERROR         eError;
	unsigned long    ulBBuf;
	unsigned long    ulNBBuf;
	



	



	

	psDevInfo = GetAnchorPtr();

	if (psDevInfo == 0)
	{
		PFN_CMD_PROC  pfnCmdProcList[DC_NOHW_COMMAND_COUNT];
		IMG_UINT32    aui32SyncCountList[DC_NOHW_COMMAND_COUNT][2];

		
		psDevInfo = (DC_NOHW_DEVINFO *)AllocKernelMem(sizeof(*psDevInfo));

		if(!psDevInfo)
		{
			eError = DC_ERROR_OUT_OF_MEMORY;
			goto ExitError;
		}

		
		memset(psDevInfo, 0, sizeof(*psDevInfo));

		
		SetAnchorPtr((void*)psDevInfo);

		
		psDevInfo->ulRefCount = 0UL;

		if(OpenPVRServices(&psDevInfo->hPVRServices) != DC_OK)
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitFreeDevInfo;
		}
		if(GetLibFuncAddr (psDevInfo->hPVRServices, "PVRGetDisplayClassJTable", &pfnGetPVRJTable) != DC_OK)
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitCloseServices;
		}

		
		if((*pfnGetPVRJTable)(&psDevInfo->sPVRJTable) == IMG_FALSE)
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitCloseServices;
		}

		

		psDevInfo->psSwapChain = 0;
		psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0UL;
		psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 1UL;
		psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1UL;
		psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = DC_NOHW_MAX_BACKBUFFERS;
		strncpy(psDevInfo->sDisplayInfo.szDisplayName, DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE);

		psDevInfo->ulNumFormats = 1UL;

		psDevInfo->ulNumDims = 1UL;

#if defined(DC_NOHW_GET_BUFFER_DIMENSIONS)
		if (!GetBufferDimensions(&psDevInfo->asDisplayDimList[0].ui32Width,
			&psDevInfo->asDisplayDimList[0].ui32Height,
			&psDevInfo->asDisplayFormatList[0].pixelformat,
			&psDevInfo->asDisplayDimList[0].ui32ByteStride))
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitCloseServices;
		}
#else	
	#if defined (ENABLE_DISPLAY_MODE_TRACKING)
		
		psDevInfo->asDisplayFormatList[0].pixelformat = DC_NOHW_BUFFER_PIXEL_FORMAT;
		psDevInfo->asDisplayDimList[0].ui32Width =  0;
		psDevInfo->asDisplayDimList[0].ui32Height =  0;
		psDevInfo->asDisplayDimList[0].ui32ByteStride = 0;
	#else
		psDevInfo->asDisplayFormatList[0].pixelformat = DC_NOHW_BUFFER_PIXEL_FORMAT;
		psDevInfo->asDisplayDimList[0].ui32Width =  DC_NOHW_BUFFER_WIDTH;
		psDevInfo->asDisplayDimList[0].ui32Height =  DC_NOHW_BUFFER_HEIGHT;
		psDevInfo->asDisplayDimList[0].ui32ByteStride = DC_NOHW_BUFFER_BYTE_STRIDE;
	#endif
#endif	

		psDevInfo->sSysFormat = psDevInfo->asDisplayFormatList[0];
		psDevInfo->sSysDims.ui32Width = psDevInfo->asDisplayDimList[0].ui32Width;
		psDevInfo->sSysDims.ui32Height = psDevInfo->asDisplayDimList[0].ui32Height;
		psDevInfo->sSysDims.ui32ByteStride = psDevInfo->asDisplayDimList[0].ui32ByteStride;
		psDevInfo->ui32BufferSize = psDevInfo->sSysDims.ui32Height * psDevInfo->sSysDims.ui32ByteStride;


		
		for(ulBBuf=0; ulBBuf<DC_NOHW_MAX_BACKBUFFERS; ulBBuf++)
		{
#if defined(USE_BASE_VIDEO_FRAMEBUFFER) || defined (ENABLE_DISPLAY_MODE_TRACKING)
			psDevInfo->asBackBuffers[ulBBuf].sSysAddr.uiAddr = IMG_NULL;
			psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr = IMG_NULL;
#else
#if defined(DC_NOHW_DISCONTIG_BUFFERS)
			if (AllocDiscontigMemory(psDevInfo->ui32BufferSize,
								  &psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
								  &psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
								  &psDevInfo->asBackBuffers[ulBBuf].psSysAddr) != DC_OK)
			{
				eError = DC_ERROR_INIT_FAILURE;
				goto ExitFreeMem;
			}
#else
			IMG_CPU_PHYADDR		sBufferCPUPAddr;

			if (AllocContigMemory(psDevInfo->ui32BufferSize,
								  &psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
								  &psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
								  &sBufferCPUPAddr) != DC_OK)
			{
				eError = DC_ERROR_INIT_FAILURE;
				goto ExitFreeMem;
			}

			psDevInfo->asBackBuffers[ulBBuf].sSysAddr =  CpuPAddrToSysPAddr(sBufferCPUPAddr);
#endif
#endif 
			
			psDevInfo->asBackBuffers[ulBBuf].sDevVAddr.uiAddr = 0UL;
			psDevInfo->asBackBuffers[ulBBuf].hSwapChain = 0;
			psDevInfo->asBackBuffers[ulBBuf].psSyncData = 0;
			psDevInfo->asBackBuffers[ulBBuf].psNext = 0;
		}

		

		psDevInfo->sDCJTable.ui32TableSize = sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE);
		psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice;
		psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice;
		psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats;
		psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims;
		psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer;
		psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo;
		psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr;
		psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain;
		psDevInfo->sDCJTable.pfnDestroyDCSwapChain = DestroyDCSwapChain;
		psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect;
		psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect;
		psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey;
		psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey;
		psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers;
		psDevInfo->sDCJTable.pfnSwapToDCBuffer = SwapToDCBuffer;
		psDevInfo->sDCJTable.pfnSwapToDCSystem = SwapToDCSystem;
		psDevInfo->sDCJTable.pfnSetDCState = IMG_NULL;

		
		if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice (&psDevInfo->sDCJTable,
															&psDevInfo->uiDeviceID ) != PVRSRV_OK)
		{
			eError = DC_ERROR_DEVICE_REGISTER_FAILED;
			goto ExitFreeMem;
		}

		

		pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip;

		

		aui32SyncCountList[DC_FLIP_COMMAND][0] = 0UL;
		aui32SyncCountList[DC_FLIP_COMMAND][1] = 2UL;

		



		if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList(psDevInfo->uiDeviceID,
															   &pfnCmdProcList[0],
															   aui32SyncCountList,
															   DC_NOHW_COMMAND_COUNT) != PVRSRV_OK)
		{
			eError = DC_ERROR_CANT_REGISTER_CALLBACK;
			goto ExitRemoveDevice;
		}
	}

	
	psDevInfo->ulRefCount++;

	
	return (DC_OK);

ExitRemoveDevice:
	(IMG_VOID) psDevInfo->sPVRJTable.pfnPVRSRVRemoveDCDevice(psDevInfo->uiDeviceID);

ExitFreeMem:
	ulNBBuf = ulBBuf;
	for(ulBBuf=0; ulBBuf<ulNBBuf; ulBBuf++)
	{
#if defined(DC_NOHW_DISCONTIG_BUFFERS)
		FreeDiscontigMemory(psDevInfo->ui32BufferSize,
			 psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
			 psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
			 psDevInfo->asBackBuffers[ulBBuf].psSysAddr);
#else
#if !defined(USE_BASE_VIDEO_FRAMEBUFFER)

		FreeContigMemory(psDevInfo->ui32BufferSize,
			 psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
			 psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
			 SysPAddrToCpuPAddr(psDevInfo->asBackBuffers[ulBBuf].sSysAddr));


#endif 
#endif 
	}

ExitCloseServices:
	(void)ClosePVRServices(psDevInfo->hPVRServices);

ExitFreeDevInfo:
	FreeKernelMem(psDevInfo);
	SetAnchorPtr(0);

ExitError:
	return eError;
}
static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice,
                                      IMG_UINT32 ui32Flags,
                                      DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib,
                                      DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib,
                                      IMG_UINT32 ui32BufferCount,
                                      PVRSRV_SYNC_DATA **ppsSyncData,
                                      IMG_UINT32 ui32OEMFlags,
                                      IMG_HANDLE *phSwapChain,
                                      IMG_UINT32 *pui32SwapChainID)
{
	DC_NOHW_DEVINFO	*psDevInfo;
	DC_NOHW_SWAPCHAIN *psSwapChain;
	DC_NOHW_BUFFER *psBuffer;
	IMG_UINT32 i;

	UNREFERENCED_PARAMETER(ui32OEMFlags);
	UNREFERENCED_PARAMETER(pui32SwapChainID);

	
	if(!hDevice
	|| !psDstSurfAttrib
	|| !psSrcSurfAttrib
	|| !ppsSyncData
	|| !phSwapChain)
	{
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	psDevInfo = (DC_NOHW_DEVINFO*)hDevice;

	
	if(psDevInfo->psSwapChain)
	{
		return (PVRSRV_ERROR_FLIP_CHAIN_EXISTS);
	}

	
	if(ui32BufferCount > DC_NOHW_MAX_BACKBUFFERS)
	{
		return (PVRSRV_ERROR_TOOMANYBUFFERS);
	}

	


	if(psDstSurfAttrib->pixelformat != psDevInfo->sSysFormat.pixelformat
	|| psDstSurfAttrib->sDims.ui32ByteStride != psDevInfo->sSysDims.ui32ByteStride
	|| psDstSurfAttrib->sDims.ui32Width != psDevInfo->sSysDims.ui32Width
	|| psDstSurfAttrib->sDims.ui32Height != psDevInfo->sSysDims.ui32Height)
	{
		
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	if(psDstSurfAttrib->pixelformat != psSrcSurfAttrib->pixelformat
	|| psDstSurfAttrib->sDims.ui32ByteStride != psSrcSurfAttrib->sDims.ui32ByteStride
	|| psDstSurfAttrib->sDims.ui32Width != psSrcSurfAttrib->sDims.ui32Width
	|| psDstSurfAttrib->sDims.ui32Height != psSrcSurfAttrib->sDims.ui32Height)
	{
		
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	
	UNREFERENCED_PARAMETER(ui32Flags);

	
	psSwapChain = (DC_NOHW_SWAPCHAIN*)AllocKernelMem(sizeof(DC_NOHW_SWAPCHAIN));
	if(!psSwapChain)
	{
		return (PVRSRV_ERROR_OUT_OF_MEMORY);
	}

	psBuffer = (DC_NOHW_BUFFER*)AllocKernelMem(sizeof(DC_NOHW_BUFFER) * ui32BufferCount);
	if(!psBuffer)
	{
		FreeKernelMem(psSwapChain);
		return (PVRSRV_ERROR_OUT_OF_MEMORY);
	}

	
	memset(psSwapChain, 0, sizeof(DC_NOHW_SWAPCHAIN));
	memset(psBuffer, 0, sizeof(DC_NOHW_BUFFER) * ui32BufferCount);

	psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount;
	psSwapChain->psBuffer = psBuffer;

	
	for(i=0; i<ui32BufferCount-1; i++)
	{
		psBuffer[i].psNext = &psBuffer[i+1];
	}
	
	psBuffer[i].psNext = &psBuffer[0];

	
	for(i=0; i<ui32BufferCount; i++)
	{
		psBuffer[i].psSyncData = ppsSyncData[i];
#if defined(DC_NOHW_DISCONTIG_BUFFERS)
		psBuffer[i].psSysAddr = psDevInfo->asBackBuffers[i].psSysAddr;
#else
		psBuffer[i].sSysAddr = psDevInfo->asBackBuffers[i].sSysAddr;
#endif
		psBuffer[i].sDevVAddr = psDevInfo->asBackBuffers[i].sDevVAddr;
		psBuffer[i].sCPUVAddr = psDevInfo->asBackBuffers[i].sCPUVAddr;
		psBuffer[i].hSwapChain = (DC_HANDLE)psSwapChain;
	}

	
	psDevInfo->psSwapChain = psSwapChain;

	
	*phSwapChain = (IMG_HANDLE)psSwapChain;

	

	return (PVRSRV_OK);
}
/*
 *	Deinit
 */
DC_ERROR Deinit(void)
{
	DC_NOHW_DEVINFO *psDevInfo, *psDevFirst;
#if !defined(USE_BASE_VIDEO_FRAMEBUFFER)
	unsigned long i;
#endif

	psDevFirst = GetAnchorPtr();
	psDevInfo = psDevFirst;

	/* check DevInfo has been setup */
	if (psDevInfo == 0)
	{
		return (DC_ERROR_GENERIC);/* failure */
	}

	/* decrement ref count */
	psDevInfo->ulRefCount--;

	if (psDevInfo->ulRefCount == 0UL)
	{
		/* all references gone - de-init device information */
		PVRSRV_DC_DISP2SRV_KMJTABLE	*psJTable = &psDevInfo->sPVRJTable;

		/* Remove display class device from kernel services device register */
		if (psJTable->pfnPVRSRVRemoveDCDevice((IMG_UINT32)psDevInfo->uiDeviceID) != PVRSRV_OK)
		{
			return (DC_ERROR_GENERIC);/* failure */
		}

		if (psDevInfo->sPVRJTable.pfnPVRSRVRemoveCmdProcList(psDevInfo->uiDeviceID,
															 DC_NOHW_COMMAND_COUNT) != PVRSRV_OK)
		{
			return (DC_ERROR_GENERIC);/* failure */
		}

		if (ClosePVRServices(psDevInfo->hPVRServices) != DC_OK)
		{
			psDevInfo->hPVRServices = 0;
			return (DC_ERROR_GENERIC);/* failure */
		}

#if !defined(USE_BASE_VIDEO_FRAMEBUFFER)
		for(i=0; i<DC_NOHW_MAX_BACKBUFFERS; i++)
		{
			if (psDevInfo->asBackBuffers[i].sCPUVAddr)
			{
				#if defined(DC_NOHW_DISCONTIG_BUFFERS)
				FreeDiscontigMemory(psDevInfo->ui32BufferSize,
							 psDevInfo->asBackBuffers[i].hMemChunk,
							 psDevInfo->asBackBuffers[i].sCPUVAddr,
							 psDevInfo->asBackBuffers[i].psSysAddr);
				#else

				FreeContigMemory(psDevInfo->ui32BufferSize,
							 psDevInfo->asBackBuffers[i].hMemChunk,
							 psDevInfo->asBackBuffers[i].sCPUVAddr,
							 SysPAddrToCpuPAddr(psDevInfo->asBackBuffers[i].sSysAddr));
				#endif
			}
		}
#endif /* #if !defined(USE_BASE_VIDEO_FRAMEBUFFER) */

		/* de-allocate data structure */
		FreeKernelMem(psDevInfo);
	}

#if defined (ENABLE_DISPLAY_MODE_TRACKING)
	CloseMiniport();
#endif
	/* clear the top-level anchor */
	SetAnchorPtr(0);

	/* return success */
	return (DC_OK);
}
DC_ERROR Init(void)
{
	DC_NOHW_DEVINFO *psDevInfo;
	DC_ERROR         eError;
	unsigned long    ulBBuf;
	unsigned long    ulNBBuf;
	/*
		- connect to services
		- register with services
		- allocate and setup private data structure
	*/


	/*
		in kernel driver, data structures must be anchored to something for subsequent retrieval
		this may be a single global pointer or TLS or something else - up to you
		call API to retrieve this ptr
	*/

	/*
		get the anchor pointer
	*/
	psDevInfo = GetAnchorPtr();

	if (psDevInfo == 0)
	{
		PFN_CMD_PROC  pfnCmdProcList[DC_NOHW_COMMAND_COUNT];
		IMG_UINT32    aui32SyncCountList[DC_NOHW_COMMAND_COUNT][2];

		/* allocate device info. structure */
		psDevInfo = (DC_NOHW_DEVINFO *)AllocKernelMem(sizeof(*psDevInfo));

		if(!psDevInfo)
		{
			eError = DC_ERROR_OUT_OF_MEMORY;/* failure */
			goto ExitError;
		}

		/* initialise allocation */
		memset(psDevInfo, 0, sizeof(*psDevInfo));

		/* set the top-level anchor */
		SetAnchorPtr((void*)psDevInfo);

		/* set ref count */
		psDevInfo->ulRefCount = 0UL;

		if(OpenPVRServices(&psDevInfo->hPVRServices) != DC_OK)
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitFreeDevInfo;
		}
		if(GetLibFuncAddr (psDevInfo->hPVRServices, "PVRGetDisplayClassJTable", &pfnGetPVRJTable) != DC_OK)
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitCloseServices;
		}

		/* got the kernel services function table */
		if((*pfnGetPVRJTable)(&psDevInfo->sPVRJTable) == IMG_FALSE)
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitCloseServices;
		}

		/*
			Setup the devinfo
		*/
		psDevInfo->psSwapChain = 0;
		psDevInfo->sDisplayInfo.ui32MinSwapInterval = 0UL;
		psDevInfo->sDisplayInfo.ui32MaxSwapInterval = 1UL;
		psDevInfo->sDisplayInfo.ui32MaxSwapChains = 1UL;
		psDevInfo->sDisplayInfo.ui32MaxSwapChainBuffers = DC_NOHW_MAX_BACKBUFFERS;
		strncpy(psDevInfo->sDisplayInfo.szDisplayName, DISPLAY_DEVICE_NAME, MAX_DISPLAY_NAME_SIZE);

		psDevInfo->ulNumFormats = 1UL;

		psDevInfo->ulNumDims = 1UL;

#if defined(DC_NOHW_GET_BUFFER_DIMENSIONS)
		if (!GetBufferDimensions(&psDevInfo->asDisplayDimList[0].ui32Width,
			&psDevInfo->asDisplayDimList[0].ui32Height,
			&psDevInfo->asDisplayFormatList[0].pixelformat,
			&psDevInfo->asDisplayDimList[0].ui32ByteStride))
		{
			eError = DC_ERROR_INIT_FAILURE;
			goto ExitCloseServices;
		}
#else	/* defined(DC_NOHW_GET_BUFFER_DIMENSIONS) */
	#if defined (ENABLE_DISPLAY_MODE_TRACKING)
		// Set sizes to zero to force re-alloc on display mode change.
		psDevInfo->asDisplayFormatList[0].pixelformat = DC_NOHW_BUFFER_PIXEL_FORMAT;
		psDevInfo->asDisplayDimList[0].ui32Width =  0;
		psDevInfo->asDisplayDimList[0].ui32Height =  0;
		psDevInfo->asDisplayDimList[0].ui32ByteStride = 0;
	#else
		psDevInfo->asDisplayFormatList[0].pixelformat = DC_NOHW_BUFFER_PIXEL_FORMAT;
		psDevInfo->asDisplayDimList[0].ui32Width =  DC_NOHW_BUFFER_WIDTH;
		psDevInfo->asDisplayDimList[0].ui32Height =  DC_NOHW_BUFFER_HEIGHT;
		psDevInfo->asDisplayDimList[0].ui32ByteStride = DC_NOHW_BUFFER_BYTE_STRIDE;
	#endif
#endif	/* defined(DC_NOHW_GET_BUFFER_DIMENSIONS) */

		psDevInfo->sSysFormat = psDevInfo->asDisplayFormatList[0];
		psDevInfo->sSysDims.ui32Width = psDevInfo->asDisplayDimList[0].ui32Width;
		psDevInfo->sSysDims.ui32Height = psDevInfo->asDisplayDimList[0].ui32Height;
		psDevInfo->sSysDims.ui32ByteStride = psDevInfo->asDisplayDimList[0].ui32ByteStride;
		psDevInfo->ui32BufferSize = psDevInfo->sSysDims.ui32Height * psDevInfo->sSysDims.ui32ByteStride;


		/* setup swapchain details */
		for(ulBBuf=0; ulBBuf<DC_NOHW_MAX_BACKBUFFERS; ulBBuf++)
		{
#if defined(USE_BASE_VIDEO_FRAMEBUFFER) || defined (ENABLE_DISPLAY_MODE_TRACKING)
			psDevInfo->asBackBuffers[ulBBuf].sSysAddr.uiAddr = IMG_NULL;
			psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr = IMG_NULL;
#else
#if defined(DC_NOHW_DISCONTIG_BUFFERS)
			if (AllocDiscontigMemory(psDevInfo->ui32BufferSize,
								  &psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
								  &psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
								  &psDevInfo->asBackBuffers[ulBBuf].psSysAddr) != DC_OK)
			{
				eError = DC_ERROR_INIT_FAILURE;
				goto ExitFreeMem;
			}
#else
			IMG_CPU_PHYADDR		sBufferCPUPAddr;

			if (AllocContigMemory(psDevInfo->ui32BufferSize,
								  &psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
								  &psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
								  &sBufferCPUPAddr) != DC_OK)
			{
				eError = DC_ERROR_INIT_FAILURE;
				goto ExitFreeMem;
			}

			psDevInfo->asBackBuffers[ulBBuf].sSysAddr =  CpuPAddrToSysPAddr(sBufferCPUPAddr);
#endif
#endif /* #if defined(USE_BASE_VIDEO_FRAMEBUFFER) */
			/* sDevVAddr not meaningful for nohw */
			psDevInfo->asBackBuffers[ulBBuf].sDevVAddr.uiAddr = 0UL;
			psDevInfo->asBackBuffers[ulBBuf].hSwapChain = 0;
			psDevInfo->asBackBuffers[ulBBuf].psSyncData = 0;
			psDevInfo->asBackBuffers[ulBBuf].psNext = 0;
		}

		/*
			setup the DC Jtable so SRVKM can call into this driver
		*/
		psDevInfo->sDCJTable.ui32TableSize = sizeof(PVRSRV_DC_SRV2DISP_KMJTABLE);
		psDevInfo->sDCJTable.pfnOpenDCDevice = OpenDCDevice;
		psDevInfo->sDCJTable.pfnCloseDCDevice = CloseDCDevice;
		psDevInfo->sDCJTable.pfnEnumDCFormats = EnumDCFormats;
		psDevInfo->sDCJTable.pfnEnumDCDims = EnumDCDims;
		psDevInfo->sDCJTable.pfnGetDCSystemBuffer = GetDCSystemBuffer;
		psDevInfo->sDCJTable.pfnGetDCInfo = GetDCInfo;
		psDevInfo->sDCJTable.pfnGetBufferAddr = GetDCBufferAddr;
		psDevInfo->sDCJTable.pfnCreateDCSwapChain = CreateDCSwapChain;
		psDevInfo->sDCJTable.pfnDestroyDCSwapChain = DestroyDCSwapChain;
		psDevInfo->sDCJTable.pfnSetDCDstRect = SetDCDstRect;
		psDevInfo->sDCJTable.pfnSetDCSrcRect = SetDCSrcRect;
		psDevInfo->sDCJTable.pfnSetDCDstColourKey = SetDCDstColourKey;
		psDevInfo->sDCJTable.pfnSetDCSrcColourKey = SetDCSrcColourKey;
		psDevInfo->sDCJTable.pfnGetDCBuffers = GetDCBuffers;
		psDevInfo->sDCJTable.pfnSwapToDCBuffer = SwapToDCBuffer;
		psDevInfo->sDCJTable.pfnSetDCState = IMG_NULL;

		/* register device with services and retrieve device index */
		if(psDevInfo->sPVRJTable.pfnPVRSRVRegisterDCDevice (&psDevInfo->sDCJTable,
															&psDevInfo->uiDeviceID ) != PVRSRV_OK)
		{
			eError = DC_ERROR_DEVICE_REGISTER_FAILED;
			goto ExitFreeMem;
		}

		/*
			setup private command processing function table
		*/
		pfnCmdProcList[DC_FLIP_COMMAND] = ProcessFlip;

		/*
			and associated sync count(s)
		*/
		aui32SyncCountList[DC_FLIP_COMMAND][0] = 0UL;/* no writes */
		aui32SyncCountList[DC_FLIP_COMMAND][1] = 2UL;/* 2 reads: To / From */

		/*
			register private command processing functions with
			the Command Queue Manager and setup the general
			command complete function in the devinfo
		*/
		if (psDevInfo->sPVRJTable.pfnPVRSRVRegisterCmdProcList(psDevInfo->uiDeviceID,
															   &pfnCmdProcList[0],
															   aui32SyncCountList,
															   DC_NOHW_COMMAND_COUNT) != PVRSRV_OK)
		{
			eError = DC_ERROR_CANT_REGISTER_CALLBACK;
			goto ExitRemoveDevice;
		}
	}

	/* increment the ref count */
	psDevInfo->ulRefCount++;

	/* return success */
	return (DC_OK);

ExitRemoveDevice:
	(IMG_VOID) psDevInfo->sPVRJTable.pfnPVRSRVRemoveDCDevice(psDevInfo->uiDeviceID);

ExitFreeMem:
	ulNBBuf = ulBBuf;
	for(ulBBuf=0; ulBBuf<ulNBBuf; ulBBuf++)
	{
#if defined(DC_NOHW_DISCONTIG_BUFFERS)
		FreeDiscontigMemory(psDevInfo->ui32BufferSize,
			 psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
			 psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
			 psDevInfo->asBackBuffers[ulBBuf].psSysAddr);
#else
#if !defined(USE_BASE_VIDEO_FRAMEBUFFER)

		FreeContigMemory(psDevInfo->ui32BufferSize,
			 psDevInfo->asBackBuffers[ulBBuf].hMemChunk,
			 psDevInfo->asBackBuffers[ulBBuf].sCPUVAddr,
			 SysPAddrToCpuPAddr(psDevInfo->asBackBuffers[ulBBuf].sSysAddr));


#endif /* #if defined(USE_BASE_VIDEO_FRAMEBUFFER) */
#endif /* #if defined(DC_NOHW_DISCONTIG_BUFFERS) */
	}

ExitCloseServices:
	(void)ClosePVRServices(psDevInfo->hPVRServices);

ExitFreeDevInfo:
	FreeKernelMem(psDevInfo);
	SetAnchorPtr(0);

ExitError:
	return eError;
}
static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice,
                                      IMG_UINT32 ui32Flags,
                                      DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib,
                                      DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib,
                                      IMG_UINT32 ui32BufferCount,
                                      PVRSRV_SYNC_DATA **ppsSyncData,
                                      IMG_UINT32 ui32OEMFlags,
                                      IMG_HANDLE *phSwapChain,
                                      IMG_UINT32 *pui32SwapChainID)
{
	DC_NOHW_DEVINFO	*psDevInfo;
	DC_NOHW_SWAPCHAIN *psSwapChain;
	DC_NOHW_BUFFER *psBuffer;
	IMG_UINT32 i;

	UNREFERENCED_PARAMETER(ui32OEMFlags);
	UNREFERENCED_PARAMETER(pui32SwapChainID);

	/* check parameters */
	if(!hDevice
	|| !psDstSurfAttrib
	|| !psSrcSurfAttrib
	|| !ppsSyncData
	|| !phSwapChain)
	{
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	psDevInfo = (DC_NOHW_DEVINFO*)hDevice;

	/* the dc_nohw only supports a single swapchain */
	if(psDevInfo->psSwapChain)
	{
		return (PVRSRV_ERROR_FLIP_CHAIN_EXISTS);
	}

	/* check the buffer count */
	if(ui32BufferCount > DC_NOHW_MAX_BACKBUFFERS)
	{
		return (PVRSRV_ERROR_TOOMANYBUFFERS);
	}

	/*
		verify the DST/SRC attributes
		- SRC/DST must match the current display mode config
	*/
	if(psDstSurfAttrib->pixelformat != psDevInfo->sSysFormat.pixelformat
	|| psDstSurfAttrib->sDims.ui32ByteStride != psDevInfo->sSysDims.ui32ByteStride
	|| psDstSurfAttrib->sDims.ui32Width != psDevInfo->sSysDims.ui32Width
	|| psDstSurfAttrib->sDims.ui32Height != psDevInfo->sSysDims.ui32Height)
	{
		/* DST doesn't match the current mode */
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	if(psDstSurfAttrib->pixelformat != psSrcSurfAttrib->pixelformat
	|| psDstSurfAttrib->sDims.ui32ByteStride != psSrcSurfAttrib->sDims.ui32ByteStride
	|| psDstSurfAttrib->sDims.ui32Width != psSrcSurfAttrib->sDims.ui32Width
	|| psDstSurfAttrib->sDims.ui32Height != psSrcSurfAttrib->sDims.ui32Height)
	{
		/* DST doesn't match the SRC */
		return (PVRSRV_ERROR_INVALID_PARAMS);
	}

	/* INTEGRATION_POINT: check the flags */
	UNREFERENCED_PARAMETER(ui32Flags);

	/* create a swapchain structure */
	psSwapChain = (DC_NOHW_SWAPCHAIN*)AllocKernelMem(sizeof(DC_NOHW_SWAPCHAIN));
	if(!psSwapChain)
	{
		return (PVRSRV_ERROR_OUT_OF_MEMORY);
	}

	psBuffer = (DC_NOHW_BUFFER*)AllocKernelMem(sizeof(DC_NOHW_BUFFER) * ui32BufferCount);
	if(!psBuffer)
	{
		FreeKernelMem(psSwapChain);
		return (PVRSRV_ERROR_OUT_OF_MEMORY);
	}

	/* initialise allocations */
	memset(psSwapChain, 0, sizeof(DC_NOHW_SWAPCHAIN));
	memset(psBuffer, 0, sizeof(DC_NOHW_BUFFER) * ui32BufferCount);

	psSwapChain->ulBufferCount = (unsigned long)ui32BufferCount;
	psSwapChain->psBuffer = psBuffer;

	/* link the buffers */
	for(i=0; i<ui32BufferCount-1; i++)
	{
		psBuffer[i].psNext = &psBuffer[i+1];
	}
	/* and link last to first */
	psBuffer[i].psNext = &psBuffer[0];

	/* populate the buffers */
	for(i=0; i<ui32BufferCount; i++)
	{
		psBuffer[i].psSyncData = ppsSyncData[i];
#if defined(DC_NOHW_DISCONTIG_BUFFERS)
		psBuffer[i].psSysAddr = psDevInfo->asBackBuffers[i].psSysAddr;
#else
		psBuffer[i].sSysAddr = psDevInfo->asBackBuffers[i].sSysAddr;
#endif
		psBuffer[i].sDevVAddr = psDevInfo->asBackBuffers[i].sDevVAddr;
		psBuffer[i].sCPUVAddr = psDevInfo->asBackBuffers[i].sCPUVAddr;
		psBuffer[i].hSwapChain = (DC_HANDLE)psSwapChain;
	}

	/* mark swapchain's existence */
	psDevInfo->psSwapChain = psSwapChain;

	/* return swapchain handle */
	*phSwapChain = (IMG_HANDLE)psSwapChain;

	/* INTEGRATION_POINT: enable Vsync ISR */

	return (PVRSRV_OK);
}