baseport/syborg/svpframebuffer/svpframebuffer.cpp
author johnathan.white@2718R8BGH51.accenture.com
Mon, 08 Mar 2010 18:45:03 +0000
changeset 46 b6935a90ca64
parent 38 33dfab4ab0fc
child 119 931f2bbaabf7
permissions -rw-r--r--
Modify framebuffer and NGA framebuffer to read screen size from board model dtb file. Optimise memory usuage of frame buffer Add example minigui application with hooks to profiler (which writes results to S:\). Modified NGA framebuffer to run its own dfc queue at high priority

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Accenture Ltd - Syborg framebuffer improvements, now auto determines frame size from board model, performance and memory improvements
*
* Description: Minimalistic frame buffer driver
*
*/
#include <videodriver.h>
#include "platform.h"
#include <nkern.h>
#include <kernel/kernel.h>
#include <kernel/kern_priv.h>
#include <kernel/kpower.h>

#include <syborg_priv.h>
#include "svpframebuffer.h"

DLcdPowerHandler	*  DLcdPowerHandler::pLcd			= NULL;

TPhysAddr Syborg::VideoRamPhys;
TPhysAddr Syborg::VideoRamPhysSecure;		// Secure display memory

TPhysAddr TSyborg::VideoRamPhys()
{
  __KTRACE_OPT(KEXTENSION,Kern::Printf("TSyborg::VideoRamPhys: VideoRamPhys=0x%x", Syborg::VideoRamPhys));
  return Syborg::VideoRamPhys;
}

TPhysAddr TSyborg::VideoRamPhysSecure()
{
  return Syborg::VideoRamPhysSecure;
}

LOCAL_C TInt DoHalFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
{
  DLcdPowerHandler* pH=(DLcdPowerHandler*)aPtr;
  return pH->HalFunction(aFunction,a1,a2);
}

static void rxMsg(TAny* aPtr)
{
  DLcdPowerHandler& h=*(DLcdPowerHandler*)aPtr;
  TMessageBase* pM = h.iMsgQ.iMessage;
  if(pM)
	h.HandleMsg(pM);
}

static void power_up_dfc(TAny* aPtr)
{
  ((DLcdPowerHandler*)aPtr)->PowerUpDfc();
}

void power_down_dfc(TAny* aPtr)
{
  ((DLcdPowerHandler*)aPtr)->PowerDownDfc();
}

void DLcdPowerHandler::DisplayOn()
{ 
  PowerUpLcd(iSecureDisplay);
  iDisplayOn = ETrue;
}

void DLcdPowerHandler::DisplayOff()
{
  PowerDownLcd();
  iDisplayOn = EFalse;
}

void DLcdPowerHandler::SwitchDisplay(TBool aSecure)
 {
   if(aSecure)
	 {
	   if(!iSecureDisplay)
		 {
		   DisplayOff();
		   iSecureDisplay = ETrue;
		   DisplayOn();
		 }
	 }
   else
	 {
	   if(iSecureDisplay)
		 {
		   DisplayOff();
		   iSecureDisplay = EFalse;
		   DisplayOn();
		 }
	 }
 }

void DLcdPowerHandler::PowerUpDfc()
{
  DisplayOn();
  PowerUpDone();
}

void DLcdPowerHandler::PowerDownDfc()
{
  DisplayOff();

  PowerDownDone();
}

void DLcdPowerHandler::PowerDown(TPowerState)
{
  iPowerDownDfc.Enque();
}

void DLcdPowerHandler::PowerUp()
{
  iPowerUpDfc.Enque();
}

void DLcdPowerHandler::PowerUpLcd(TBool aSecure)
{

  WriteReg(iPortAddr, FB_ENABLED, 0);
  WriteReg(iPortAddr, FB_BASE, aSecure ? iSecurevRamPhys : ivRamPhys);

  WriteReg(iPortAddr, FB_BLANK, 0);
  WriteReg(iPortAddr, FB_BPP, 32);
  WriteReg(iPortAddr, FB_COLOR_ORDER, 0);
  WriteReg(iPortAddr, FB_BYTE_ORDER, 0);
  WriteReg(iPortAddr, FB_PIXEL_ORDER, 0);
  WriteReg(iPortAddr, FB_INT_MASK, 0);
  WriteReg(iPortAddr, FB_ENABLED, 1);

// We don't write the Height and Width of the framebuffer, this is controlled by the board model

}

void DLcdPowerHandler::PowerDownLcd()
{
  WriteReg(iPortAddr, FB_BLANK, 1);
}

DLcdPowerHandler::DLcdPowerHandler()
	:	DPowerHandler(KLitLcd),
		iMsgQ(rxMsg,this,NULL,1),
		iPowerUpDfc(&power_up_dfc,this,6),
		iPowerDownDfc(&power_down_dfc,this,7)
{
}

void DLcdPowerHandler::ScreenInfo(TScreenInfoV01& anInfo)
{
  anInfo.iWindowHandleValid = EFalse;
  anInfo.iWindowHandle = NULL;
  anInfo.iScreenAddressValid = ETrue;
  anInfo.iScreenAddress = (TAny *)(iChunk->LinearAddress());
  anInfo.iScreenSize.iWidth = iVideoInfo.iSizeInPixels.iWidth;
  anInfo.iScreenSize.iHeight = iVideoInfo.iSizeInPixels.iHeight;
}

void DLcdPowerHandler::HandleMsg(TMessageBase* aMsg)
{
  if(aMsg->iValue)
	DisplayOn();
  else
	DisplayOff();
  aMsg->Complete(KErrNone,ETrue);
}

void DLcdPowerHandler::WsSwitchOnScreen()
{
  TThreadMessage& m = Kern::Message();
  m.iValue = ETrue;
  m.SendReceive(&iMsgQ);
}

void DLcdPowerHandler::WsSwitchOffScreen()
{
  TThreadMessage& m = Kern::Message();
  m.iValue = EFalse;
  m.SendReceive(&iMsgQ);
}

TInt DLcdPowerHandler::GetCurrentDisplayModeInfo(TVideoInfoV01& aInfo, TBool aSecure)
{
  NKern::FMWait(&iLock);
  if(aSecure)
	aInfo = iSecureVideoInfo;
  else
	aInfo = iVideoInfo;
  NKern::FMSignal(&iLock);
  return KErrNone;
}

TInt DLcdPowerHandler::GetSpecifiedDisplayModeInfo(TInt aMode, TVideoInfoV01& aInfo)
{
  if(aMode < 0 || aMode >= KConfigLcdNumberOfDisplayModes)
	return KErrArgument;
  
  NKern::FMWait(&iLock);
  aInfo = iVideoInfo;
  NKern::FMSignal(&iLock);

  if(aMode != aInfo.iDisplayMode)
	{
	  aInfo.iOffsetToFirstPixel = KCOnfigOffsetToFirstPixel;
	  aInfo.iIsPalettized       = KConfigIsPalettized;
	  aInfo.iOffsetBetweenLines = iVideoInfo.iSizeInPixels.iWidth*4; //Offset depends on width of framebuffer
	  aInfo.iBitsPerPixel       = KConfigBitsPerPixel;
	}
  return KErrNone;
}

TInt DLcdPowerHandler::AllocateFrameBuffer()
{
	// Allocate physical RAM for video
	
	//read width and height of display from board model and allocate size
	TInt width = ReadReg(iPortAddr, FB_WIDTH);
	TInt height = ReadReg(iPortAddr, FB_HEIGHT);
	
	iSize = 4*width*height; //*4 as 32bits per pixel

	NKern::ThreadEnterCS();
	TInt r = Epoc::AllocPhysicalRam(iSize,Syborg::VideoRamPhys);
	if (r != KErrNone)
	{
	        NKern::ThreadLeaveCS();
		Kern::Fault("AllocVideoRam",r);
	}

	// Map the video RAM
	ivRamPhys = TSyborg::VideoRamPhys();

	r = DPlatChunkHw::New(iChunk,ivRamPhys,iSize,EMapAttrUserRw|EMapAttrBufferedC);

	NKern::ThreadLeaveCS();

	if(r != KErrNone)
	  return r;

	TUint* pV = (TUint*)iChunk->LinearAddress();

	// Allocate physical RAM for secure display
	NKern::ThreadEnterCS();
	r = Epoc::AllocPhysicalRam(iSize,Syborg::VideoRamPhysSecure);
	if (r != KErrNone)
	{
	        NKern::ThreadLeaveCS();
		Kern::Fault("AllocVideoRam 2",r);
	}
	iSecurevRamPhys = ivRamPhys + iSize;
	TInt r2 = DPlatChunkHw::New(iSecureChunk,iSecurevRamPhys,iSize,EMapAttrUserRw|EMapAttrBufferedC);

	NKern::ThreadLeaveCS();

	if(r2 != KErrNone)
	  return r2;

	TUint* pV2 = (TUint*)iSecureChunk->LinearAddress();

	//width and height set by reading board model
	iVideoInfo.iSizeInPixels.iWidth  = width;
	iVideoInfo.iSizeInPixels.iHeight = height;

	//offset between lines depends on width of screen
	iVideoInfo.iOffsetBetweenLines = width*4;

	iVideoInfo.iDisplayMode = KConfigLcdDisplayMode;
	iVideoInfo.iOffsetToFirstPixel = KConfigOffsetToFirstPixel;
	
	iVideoInfo.iIsPalettized = KConfigIsPalettized;
	iVideoInfo.iBitsPerPixel = KConfigBitsPerPixel;
	iVideoInfo.iSizeInTwips.iWidth = KConfigLcdWidthInTwips;
	iVideoInfo.iSizeInTwips.iHeight = KConfigLcdHeightInTwips;
	iVideoInfo.iIsMono = KConfigIsMono;
	iVideoInfo.iVideoAddress = (TInt)pV;
	iVideoInfo.iIsPixelOrderLandscape = KConfigPixelOrderLandscape;
	iVideoInfo.iIsPixelOrderRGB = KConfigPixelOrderRGB;

	iSecureVideoInfo = iVideoInfo;
	iSecureVideoInfo.iVideoAddress = (TInt)pV2;

	// Alloc Physical RAM for the Composition Buffers used by OpenWF
	// double and round the page size
	TUint round = 2*Kern::RoundToPageSize(iSize);

	r=Epoc::AllocPhysicalRam(round , iCompositionPhysical);
	if(r!=KErrNone)
		{
		return r;
		}
	
	return KErrNone;
}


TInt DLcdPowerHandler::SetDisplayMode(TInt aMode)
{
  if(aMode < 0 || aMode >= KConfigLcdNumberOfDisplayModes)
	return KErrArgument;

  // store the current mode
  iVideoInfo.iDisplayMode = aMode;

  // store the current mode for secure screen
  iSecureVideoInfo.iDisplayMode = aMode;

  return KErrNone;
}

TInt DLcdPowerHandler::HalFunction(TInt aFunction, TAny* a1, TAny* a2)
{
  TInt r=KErrNone;
  switch(aFunction)
	{
	case EDisplayHalScreenInfo:
	  {
		TPckgBuf<TScreenInfoV01> vPckg;
		ScreenInfo(vPckg());
		Kern::InfoCopy(*(TDes8*)a1,vPckg);
		break;
	  }
	case EDisplayHalWsRegisterSwitchOnScreenHandling:
	  {
		iWsSwitchOnScreen=(TBool)a1;
		break;
	  }
	case EDisplayHalWsSwitchOnScreen:
	  {
		WsSwitchOnScreen();
		break;
	  }
	case EDisplayHalModeCount:
	  {
		TInt ndm = KConfigLcdNumberOfDisplayModes;
		kumemput32(a1, &ndm, sizeof(ndm));
		break;
	  }
	case EDisplayHalSetMode:
	  {
		__KTRACE_OPT(KEXTENSION,Kern::Printf("EDisplayHalSetMode"));
		__SECURE_KERNEL(
						if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetMode")))
						return KErrPermissionDenied;
						)
		  r = SetDisplayMode((TInt)a1);
		break;
	  }
	case EDisplayHalMode:
	  {
		kumemput32(a1, &iVideoInfo.iDisplayMode, sizeof(iVideoInfo.iDisplayMode));
		r = KErrNone;
		break;
	  }
	case EDisplayHalSetPaletteEntry:
	  {
		__SECURE_KERNEL(
						if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetPaletteEntry")))
						return KErrPermissionDenied;
						)
		  r = KErrNotSupported;
		break;
	  }
	case EDisplayHalPaletteEntry:
	  {
		TInt entry;
		kumemget32(&entry, a1, sizeof(TInt));
		r = KErrNotSupported;
		break;
	  }
	case EDisplayHalSetState:
	  {
		__SECURE_KERNEL(
						if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetState")))
						return KErrPermissionDenied;
						)
		  if((TBool)a1)
			WsSwitchOnScreen();
		  else
			WsSwitchOffScreen();
		break;
	  }
	case EDisplayHalState:
	  {
		kumemput32(a1, &iDisplayOn, sizeof(TBool));
		break;
	  }
	case EDisplayHalColors:
	  {
		TInt mdc = 1<<24;
		kumemput32(a1, &mdc, sizeof(mdc));
		break;
	  }
	case EDisplayHalCurrentModeInfo:
	  {
		TPckgBuf<TVideoInfoV01> vPckg;
		r = GetCurrentDisplayModeInfo(vPckg(), (TBool)a2);
		if(KErrNone == r)
		  Kern::InfoCopy(*(TDes8*)a1,vPckg);
		break;
	  }
	case EDisplayHalSpecifiedModeInfo:
	  {
		TPckgBuf<TVideoInfoV01> vPckg;
		TInt mode;
		kumemget32(&mode, a1, sizeof(mode));
		r = GetSpecifiedDisplayModeInfo(mode, vPckg());
		if(KErrNone == r)
		  Kern::InfoCopy(*(TDes8*)a2,vPckg);
		break;
	  }	
	case EDisplayHalSecure:
	  {
		kumemput32(a1, &iSecureDisplay, sizeof(TBool));
		break;
	  }
	case EDisplayHalSetSecure:
	  {
		__SECURE_KERNEL(
						if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetSecure")))
						return KErrPermissionDenied;
						)
		  SwitchDisplay((TBool)a1);
		break;
	  }
	default:
	  {
		r = KErrNotSupported;
		break;
	  }			
	}
  return r;
}

TInt DLcdPowerHandler::Create()
{
	__KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::Create") );
	pLcd			= this;

	iPortAddr = KHwBaseClcd;

	TInt r = AllocateFrameBuffer();
	if(r == KErrNone)
		{
		r = Kern::AddHalEntry(EHalGroupDisplay,DoHalFunction,this);
		}
	    
	if(r != KErrNone)
		{
		__KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::Create failed %d", r) );
		return r;
		}

	iPowerUpDfc.SetDfcQ(iDfcQ);
	iPowerDownDfc.SetDfcQ(iDfcQ);
	iMsgQ.SetDfcQ(iDfcQ);
	iMsgQ.Receive();

	Add();
	DisplayOn();

	return KErrNone;
}

/**
 * Register the call back function.
 * Components interested in receiving notification of the Vsync interrupt should register a callback function.
 */
EXPORT_C TInt DLcdPowerHandler::RegisterCallback(TLcdUserCallBack* aCbPtr)
{
	__KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::RegisterCallBack %08x\n",aCbPtr->iCbFn) );

	TInt irq=__SPIN_LOCK_IRQSAVE(callbackLock);

	if(aCbPtr != NULL)
		{
		if ( pLcd->iAppCallBk[0] == NULL  )
			{
			pLcd->iAppCallBk[0] = aCbPtr;
			}
		else
			{
			if((pLcd->iAppCallBk[1] == NULL) && (pLcd->iAppCallBk[0]->iCbFn != aCbPtr->iCbFn))
				{
				pLcd->iAppCallBk[1] = aCbPtr;
				}
			else
				{
				__SPIN_UNLOCK_IRQRESTORE(callbackLock,irq);
				return KErrInUse;
				}
			}

		__SPIN_UNLOCK_IRQRESTORE(callbackLock,irq);
		__KTRACE_OPT(KEXTENSION ,Kern::Printf("<DLcdPowerHandler::RegisterCallBack ok %08x\n",aCbPtr->iCbFn) );
		return KErrNone;
		}
	else
		{
		__SPIN_UNLOCK_IRQRESTORE(callbackLock,irq);
		__KTRACE_OPT(KEXTENSION, Kern::Printf("Error: The supplied listener's callback is NULL"));
		return KErrArgument;
		}
}


/**
 *DeRegister the call back function
 */
EXPORT_C void DLcdPowerHandler::DeRegisterCallback(TLcdUserCallBack* aCbPtr)
{
	__KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::DeRegisterCallBack %08x\n ",aCbPtr->iCbFn)  );

	TInt irq=__SPIN_LOCK_IRQSAVE(callbackLock);
	if(aCbPtr != NULL)
		{
	    if( pLcd->iAppCallBk[0] != NULL)
			{
			if ( (pLcd->iAppCallBk[0]->iDataPtr == aCbPtr->iDataPtr) && (pLcd->iAppCallBk[0]->iCbFn == aCbPtr->iCbFn) )
				{
				pLcd->iAppCallBk[0] = NULL;
				}
			}

		if( pLcd->iAppCallBk[1] != NULL)
			{
			if ( (pLcd->iAppCallBk[1]->iDataPtr == aCbPtr->iDataPtr) && (pLcd->iAppCallBk[1]->iCbFn == aCbPtr->iCbFn) )
				{
				pLcd->iAppCallBk[1] = NULL;
				}
			}
		}
	__SPIN_UNLOCK_IRQRESTORE(callbackLock,irq);
	__KTRACE_OPT(KEXTENSION ,Kern::Printf("<DLcdPowerHandler::DeRegisterCallBack %08x\n ",aCbPtr->iCbFn)  );
}

/**
	Constructor
*/
DDisplayPddSyborg::DDisplayPddSyborg():
	iPendingBuffer(NULL),
	iActiveBuffer(NULL),
	iChunk(NULL),
	iLcdCallback(NULL),
	iVSyncDfc(&VSyncDfcFn, this, KVSyncDfcPriority)
	{
	__GCE_DEBUG_PRINT("DDisplayPddSyborg::DDisplayPddSyborg\n");

	iPostFlag = EFalse;
	}

/**
	Destructor
*/
DDisplayPddSyborg::~DDisplayPddSyborg()
	{
	__GCE_DEBUG_PRINT("DDisplayPddSyborg::~DDisplayPddSyborg()  \n");

	if(iLcdCallback)
		{
		DLcdPowerHandler::pLcd->DeRegisterCallback(iLcdCallback) ;
		delete iLcdCallback;
		iLcdCallback = NULL;
		}

	//The DFC Queue is owned by DLcdPowerHandler so we shouldn't call Destroy() at this point.
	if (iDfcQ)
		{
		iDfcQ=NULL;
		}

	DChunk* chunk = (DChunk*) __e32_atomic_swp_ord_ptr(&iChunk, 0);

	if(chunk)
		{
		Kern::ChunkClose(chunk);
		}

	}

/**
    Set the Legacy Mode by setting the appropriate Frame control value.

*/
TInt DDisplayPddSyborg::SetLegacyMode()
	{
	__GCE_DEBUG_PRINT("DDisplayPddSyborg::SetLegacyMode()\n");

    return KErrNone;
	}

/**
    Set the GCE mode by posting a composition buffer.

*/
TInt DDisplayPddSyborg::SetGceMode()
	{
	__GCE_DEBUG_PRINT("DDisplayPddSyborg::SetGceMode()\n");

    PostCompositionBuffer(&iLdd->iCompositionBuffer[0]);
    return KErrNone;
	}

/**
	@param	aDegOfRot  The requested rotation
	@return KErrNone
*/
TInt DDisplayPddSyborg::SetRotation(RDisplayChannel::TDisplayRotation aDegOfRot)
	{
	return KErrNone;
	}

/**
    Remove any previous post operations, set the appropriate layer as the next layer to be displayed( This value is updated in synchronization
    with V Sync so it will take affect in the next V Sync after that) and also set the buffer provided as the buffer to
    be posted next. Layer 3 is associated with user buffers.

	@param	aNode  Pointer to the User buffer to post.
*/
TInt DDisplayPddSyborg::PostUserBuffer(TBufferNode* aNode)
	{

	__GCE_DEBUG_PRINT2("DDisplayPddSyborg::PostUserBuffer :  aNode->iAddress = %08x\n", aNode->iAddress);

	if(iPendingBuffer)
		{
		iPendingBuffer->iState = EBufferFree;
		if (!(iPendingBuffer->iType == EBufferTypeUser) )
			{
			iPendingBuffer->iFree  = ETrue;
			}
		}

	aNode->iState   = EBufferPending;
	iPendingBuffer	= aNode;
	iPostFlag		= ETrue;
	
  	// Activate the posted buffer
	TUint32 physicalAddress = Epoc::LinearToPhysical( aNode->iAddress );
  	WriteReg(DLcdPowerHandler::pLcd->iPortAddr, DLcdPowerHandler::FB_BASE, physicalAddress );
	/* Queue a DFC to complete the request*/
	iVSyncDfc.Enque();

	return KErrNone;
	}

/**
    Remove any previous post operations, set the appropriate layer as the next layer to be displayed( This value is updated in synchronization
    with V Sync so it will take affect in the next V Sync after that) and also set the buffer provided as the buffer to
    be posted next. Layer 1 and 2 are associated with composition buffers 0 and 1 respectively.

	@param	aNode  Pointer to the Composition buffer to post.
*/
TInt DDisplayPddSyborg::PostCompositionBuffer(TBufferNode* aNode)
	{

	__GCE_DEBUG_PRINT2("DDisplayPddSyborg::PostCompositionBuffer :  aNode->iAddress = %08x\n", aNode->iAddress);

	if(iPendingBuffer)
		{
		iPendingBuffer->iState = EBufferFree;
		if (iPendingBuffer->iType == EBufferTypeUser)
			{
			RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrCancel);
			}
		else
			{
			iPendingBuffer->iFree  = ETrue;
			}
		}
	aNode->iState	= EBufferPending;
	aNode->iFree	= EFalse;
	iPendingBuffer	= aNode;
	iPostFlag		= ETrue;

  	// Activate the posted buffer
	TUint32 physicalAddress = Epoc::LinearToPhysical( aNode->iAddress );
  	WriteReg(DLcdPowerHandler::pLcd->iPortAddr, DLcdPowerHandler::FB_BASE, physicalAddress );
	
	/* Queue a DFC to complete the request*/
	iVSyncDfc.Enque();

	return KErrNone;
	}

/**
    Remove any previous post operations, set the appropriate layer as the next layer to be displayed( This value is updated in synchronization
    with V Sync so it will take affect in the next V Sync after that) and also set the Legacy Buffer as the buffer to
    be posted next.Layer 0 is associated with legacy buffer.

	@param	aNode  Pointer to the Composition buffer to post.
*/
TInt DDisplayPddSyborg::PostLegacyBuffer()
	{
	__GCE_DEBUG_PRINT("DDisplayPddSyborg::PostLegacyBuffer() \n");

	if(iPendingBuffer)
		{
		iPendingBuffer->iState = EBufferFree;
		if (iPendingBuffer->iType == EBufferTypeUser)
			{

			RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrCancel);
			}
		else
			{
			iPendingBuffer->iFree  = ETrue;
			}
		}


	iLdd->iLegacyBuffer[0].iState		= EBufferPending;
	iLdd->iLegacyBuffer[0].iFree		= EFalse;
	iPendingBuffer						= &iLdd->iLegacyBuffer[0];
	iPostFlag		= ETrue;

  	// Activate the posted buffer
  	WriteReg(DLcdPowerHandler::pLcd->iPortAddr, DLcdPowerHandler::FB_BASE, TSyborg::VideoRamPhys() );

	/* Queue a DFC to complete the request*/
	iVSyncDfc.Enque();

	return KErrNone;
	}

/**
    Handles device specific operations when a close message has been sent to the Logical Channel.

*/
TInt DDisplayPddSyborg::CloseMsg()
	{
	__GCE_DEBUG_PRINT("DDisplayPddSyborg::CloseMsg()\n");

	iPendingBuffer  = NULL;
	iActiveBuffer	= NULL;

	iVSyncDfc.Cancel();
    return KErrNone;
	}

/**
    Called by the LDD's DoCreate function to handle the device specific part of opening the channel.
    (DoCreate is called by RDisplayChannel::Open)

	@param aUnit	The screen unit

    @return KErrNone if successful; or one of the other system wide error codes.
*/
TInt DDisplayPddSyborg::CreateChannelSetup(TInt aUnit)
	{
	__GCE_DEBUG_PRINT("DDisplayPddSyborg::CreateChannelSetup\n");

	iScreenInfo = DLcdPowerHandler::pLcd->iVideoInfo;
	iLdd->iUnit = aUnit;

	iLdd->iDisplayInfo.iAvailableRotations			= RDisplayChannel::ERotationNormal;
	iLdd->iDisplayInfo.iNormal.iOffsetBetweenLines	= iScreenInfo.iOffsetBetweenLines;
	iLdd->iDisplayInfo.iNormal.iHeight				= iScreenInfo.iSizeInPixels.iHeight;
	iLdd->iDisplayInfo.iNormal.iWidth				= iScreenInfo.iSizeInPixels.iWidth;
	iLdd->iDisplayInfo.iNumCompositionBuffers		= KDisplayCBMax;
	iLdd->iDisplayInfo.iBitsPerPixel				= iScreenInfo.iBitsPerPixel;
    iLdd->iDisplayInfo.iRefreshRateHz = 60;


	switch (iScreenInfo.iBitsPerPixel)
		{
		case 16:
			iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatRGB_565;
			break;
		case 24:
			iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatRGB_888;
			break;
		case 32:
			iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatARGB_8888;
			break;
		default:
			iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatUnknown;
			break;
		}

	iLdd->iCurrentRotation = RDisplayChannel::ERotationNormal;

	// Open shared chunk to the composition framebuffer

	DChunk* chunk = 0;
	TLinAddr chunkKernelAddr  = 0;
	TUint32 chunkMapAttr = 0;

	// round to twice the page size
	TUint round  =  2*Kern::RoundToPageSize(DLcdPowerHandler::pLcd->iSize);

	__GCE_DEBUG_PRINT2("DDisplayPddSyborg::CreateChannelSetup DLcdPowerHandler::pLcd->iSize  = %d\n", DLcdPowerHandler::pLcd->iSize );

	TChunkCreateInfo info;
	info.iType					 = TChunkCreateInfo::ESharedKernelMultiple;
	info.iMaxSize				 = round;
	info.iMapAttr				 = EMapAttrFullyBlocking;
	info.iOwnsMemory			 = EFalse;
	info.iDestroyedDfc			 = 0;

	TInt r = Kern::ChunkCreate(info, chunk, chunkKernelAddr, chunkMapAttr);

	__GCE_DEBUG_PRINT2("CreateChannelSetup:ChunkCreate called for composition chunk. Set iChunkKernelAddr  = %08x\n", chunkKernelAddr );

	if( r == KErrNone)
		{
		// map our chunk
		r = Kern::ChunkCommitPhysical(chunk, 0,round , DLcdPowerHandler::pLcd->iCompositionPhysical);
		__GCE_DEBUG_PRINT2("Mapping chunk %d", r);
		if(r != KErrNone)
			{
			Kern::ChunkClose(chunk);
			}
		}

	if ( r!= KErrNone)
		{
		return r;
		}

	iChunk	= chunk;

	// init CB 0
	iLdd->iCompositionBuffer[0].iType			= EBufferTypeComposition;
	iLdd->iCompositionBuffer[0].iBufferId		= 0;
	iLdd->iCompositionBuffer[0].iFree			= ETrue;
	iLdd->iCompositionBuffer[0].iState			= EBufferFree;
	iLdd->iCompositionBuffer[0].iAddress		= chunkKernelAddr;
	iLdd->iCompositionBuffer[0].iPhysicalAddress = Epoc::LinearToPhysical(chunkKernelAddr);
	iLdd->iCompositionBuffer[0].iChunk			= chunk;
	iLdd->iCompositionBuffer[0].iHandle			= 0;
	iLdd->iCompositionBuffer[0].iOffset			= 0;
	iLdd->iCompositionBuffer[0].iSize			= DLcdPowerHandler::pLcd->iSize;
	iLdd->iCompositionBuffer[0].iPendingRequest = 0;

	// init CB 1
	iLdd->iCompositionBuffer[1].iType			= EBufferTypeComposition;
	iLdd->iCompositionBuffer[1].iBufferId		= 1;
	iLdd->iCompositionBuffer[1].iFree			= ETrue;
	iLdd->iCompositionBuffer[1].iState			= EBufferFree;
	iLdd->iCompositionBuffer[1].iAddress		= chunkKernelAddr + DLcdPowerHandler::pLcd->iSize;
	iLdd->iCompositionBuffer[1].iPhysicalAddress = Epoc::LinearToPhysical(chunkKernelAddr + DLcdPowerHandler::pLcd->iSize);
	iLdd->iCompositionBuffer[1].iChunk			= chunk;
	iLdd->iCompositionBuffer[1].iHandle			= 0;
	iLdd->iCompositionBuffer[1].iOffset			= DLcdPowerHandler::pLcd->iSize;
	iLdd->iCompositionBuffer[1].iSize			= DLcdPowerHandler::pLcd->iSize;
	iLdd->iCompositionBuffer[1].iPendingRequest = 0;

	iLdd->iCompositionBuffIdx					= 0;
	//Use the same DFC queue created by the DLcdPowerHandler so all hardware accesses are executed under the same DFC thread.
	iDfcQ= DLcdPowerHandler::pLcd->iDfcQ;

	// Set the Post DFC.
	iVSyncDfc.SetDfcQ(iDfcQ);


	return KErrNone;
	}

/**
Detect whether a post operation is pending
*/
TBool DDisplayPddSyborg::PostPending()
	{
	return (iPendingBuffer != NULL);
	}

/**
	Return the DFC queue to be used for this device.
 */
TDfcQue * DDisplayPddSyborg::DfcQ(TInt aUnit)
	{
	return iDfcQ;
	}

void DDisplayPddSyborg::VSyncDfcFn(TAny* aChannel)
	{
	DDisplayPddSyborg * channel =(DDisplayPddSyborg*)aChannel;

	if (channel->iPostFlag)
		{
		 channel->iPostFlag = EFalse;

		if (channel->iActiveBuffer)
			{
			//When a User buffer is registered its iFree member becomes EFalse and Deregister sets it
			//back to ETrue. Composition and Legacy buffers are not free when they are in the pending or
			//active state.
			if (channel->iActiveBuffer->iType == EBufferTypeUser)
				{
				channel->RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrNone);
				}
			else
				{
				channel->iActiveBuffer->iFree	= ETrue;
				}

			channel->iActiveBuffer->iState		= EBufferFree;


			//If no buffer was available during a call to GetCompositionBuffer the active buffer has
			//been returned as the next available one, so we must set the buffer to the proper state before we
			//send the notification.
			TInt pendingIndex = channel->iLdd->iPendingIndex[RDisplayChannel::EReqGetCompositionBuffer];
			if(channel->iLdd->iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq)
			{
				if(channel->iLdd->iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq->IsReady())
				{
				channel->iActiveBuffer->iState = EBufferCompose;
				channel->RequestComplete(RDisplayChannel::EReqGetCompositionBuffer,KErrNone);
				}

			}

			channel->iActiveBuffer				= NULL;
			}

		if (channel->iPendingBuffer)
			{
			__GCE_DEBUG_PRINT2("DDisplayPddSyborg::VSyncDfcFn moving pending buffer at address %08x to the active state\n", channel->iPendingBuffer->iAddress);
			channel->iActiveBuffer			= channel->iPendingBuffer;
			channel->iActiveBuffer->iState	= EBufferActive;
			channel->iPendingBuffer			= NULL;

			channel->RequestComplete(RDisplayChannel::EReqWaitForPost,  KErrNone);
			}
		}
	}
//*****************************************************************
//DDisplayPddFactory
//*****************************************************************/


/**
	Constructor
*/
DDisplayPddFactory::DDisplayPddFactory()
	{
	__GCE_DEBUG_PRINT("DDisplayPddFactory::DDisplayPddFactory()\n");

	iVersion		= TVersion(KDisplayChMajorVersionNumber,
                      KDisplayChMinorVersionNumber,
                      KDisplayChBuildVersionNumber);
	}

/**
	PDD factory function. Creates a PDD object.

	@param  aChannel  A pointer to an PDD channel object which will be initialised on return.

	@return KErrNone  if object successfully allocated, KErrNoMemory if not.
*/
TInt DDisplayPddFactory::Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
	{
	DDisplayPddSyborg *device= new DDisplayPddSyborg() ;
	aChannel=device;
	if (!device)
		{
		return KErrNoMemory;
		}
	return KErrNone;
	}


/**
    Set the Pdd name and return error code
*/
TInt DDisplayPddFactory::Install()
	{
	__GCE_DEBUG_PRINT("DDisplayPddFactory::Install() \n");

	TBuf<32> name(RDisplayChannel::Name());
	_LIT(KPddExtension,".pdd");
	name.Append(KPddExtension);
	return SetName(&name);
	}


void DDisplayPddFactory::GetCaps(TDes8& /*aDes*/) const
	{
	//Not supported
	}


/**
    Validate version and number of units.
*/
TInt DDisplayPddFactory::Validate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& aVer)
	{
	if (!Kern::QueryVersionSupported(iVersion,aVer))
		{
		return KErrNotSupported;
		}

	if (aUnit != 0)
		{
		return KErrNotSupported;
		}

	return KErrNone;
	}

DECLARE_EXTENSION_PDD()
/**
	"Standard PDD" entrypoint.Creates PDD factory when Kern::InstallPhysicalDevice is called

	@return pointer to the PDD factory object.
*/
	{
	__GCE_DEBUG_PRINT("DECLARE_EXTENSION_PDD()\n");
	return new DDisplayPddFactory ;
	}


DECLARE_STANDARD_EXTENSION()
{
  TInt r = KErrNoMemory;
  DLcdPowerHandler* pH=new DLcdPowerHandler;
  if(pH)
	{
	r = pH->Create();
	if ( r == KErrNone)
		{
		TInt r = Kern::DfcQCreate(pH->iDfcQ, 29 , &KLitLcd);

		if(r!=KErrNone)
		{
			return r;
		}

		DDisplayPddFactory * device = new DDisplayPddFactory;

		if (device==NULL)
			{
			r=KErrNoMemory;
			}
		else
			{
			r=Kern::InstallPhysicalDevice(device);
			}

		#ifdef CPU_AFFINITY_ANY
        NKern::ThreadSetCpuAffinity((NThread*) pH->iDfcQ->iThread, KCpuAffinityAny);
		#endif

		__KTRACE_OPT(KEXTENSION,Kern::Printf("Installing the display device from the kernel extension returned with error code %d",r));

		}
	}
  
  return r;
}