baseport/syborg/svpframebuffer/svpframebuffer.cpp
author andy simpson <andrews@symbian.org>
Fri, 08 Oct 2010 16:52:59 +0100
changeset 119 931f2bbaabf7
parent 46 b6935a90ca64
permissions -rw-r--r--
work-a-round for Bug 3645 change ARGB->XRGB pixel format

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