navienginebsp/naviengine_assp/lcdgce/lcdgce.cpp
changeset 0 5de814552237
child 5 bf4661c6bc44
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/navienginebsp/naviengine_assp/lcdgce/lcdgce.cpp	Tue Sep 28 18:00:05 2010 +0100
@@ -0,0 +1,1841 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+*
+* Description:  
+* \hwip_nec_naviengine\naviengine_assp\lcdgce\lcdgce.cpp
+* Implementation of an LCD driver with GCE support.
+* This file is part of the NE1_TBVariant Base port
+* N.B. This sample code assumes that the display supports setting the backlight on or off,
+* as well as adjusting the contrast and the brightness.
+*
+*/
+
+
+
+/**
+ @file Implementation of an LCD driver with GCE support.
+ @internalTechnology
+ @prototype
+*/
+
+#include <videodriver.h>
+#include "platform.h"
+#include <nkern.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <kernel/kpower.h>
+#include <naviengine_priv.h>
+#include "lcdgce.h"
+#include <naviengine_lcd.h>
+#include "powerresources.h"
+#include <resourcecontrol.h>
+
+// define the characteristics of the LCD display
+// This is only example code... you need to modify it for your hardware
+const TBool	KConfigLcdIsMono				= EFalse;
+const TBool	KConfigLcdPixelOrderLandscape	= ETrue;
+const TBool	KConfigLcdPixelOrderRGB			= ETrue;
+const TInt	KConfigLcdMaxDisplayColors		= 65536;
+const TUint32 KShiftBitsPerByte				= 3;
+const TInt	KConfigBitsPerPixel16			= 16;
+const TInt	KConfigBitsPerPixel32			= 32;
+
+#define RESOLUTION_AND_CYCLE		DISPLAY_RESOLUTION_AND_CYCLE(Lcd_Mode_Config[iInitialMode].iConfigLcdHeight, Lcd_Mode_Config[iInitialMode].iConfigLcdWidth, Lcd_Mode_Config[iInitialMode].iLinesInFrame, Lcd_Mode_Config[iInitialMode].iPixelsInLine)
+
+#define SCREEN_UNIT					0
+#define SCREEN_UNIT_COUNT			1
+
+struct SLcdConfig
+	{
+	TInt    iOffsetToFirstVideoBuffer;
+	TInt    iConfigLcdWidth;    // The width of the physical display
+	TInt    iConfigLcdHeight;   // The height of the physical display
+	TBool   iIsPalettized;
+	TInt    iBitsPerPixel;
+	TUint64 iPulseWidth;
+	TUint   iLinesInFrame;      // This appears to be a magic number that has no resemblence to the height
+	TUint   iPixelsInLine;      // This appears to be a magic number that has no resemblence to the width
+	TInt    iReportedLcdWidth;  // The width reported to the higher levels of software
+	TInt    iReportedLcdHeight; // The height reported to the higher levels of software
+	};
+
+static const SLcdConfig Lcd_Mode_Config[]=
+	{
+	// 0: DISPLAY_MODE_ANALOG_VGA: No LCD, Landscape VGA 640x480
+		{ 0, 640, 480, EFalse, KConfigBitsPerPixel32, KPulseWidthVga,    525, 800,  640, 480, },
+	// 1: DISPLAY_MODE_HITACHI_VGA: Hitachi LCD, Portrait VGA 480x640 (for this mode, SW4-1 should be turned OFF on the LCD panel)
+		{ 0, 480, 640, EFalse, KConfigBitsPerPixel32, KPulseWidthVgaLCD, 650, 650,  480, 640, },
+	// 2: DISPLAY_MODE_ANALOG_QVGA_LANDSCAPE_OLD: No LCD, Landscape QVGA 320x240
+		{ 0, 320, 240, EFalse, KConfigBitsPerPixel32, KPulseWidthVga,    525, 800,  320, 240, },
+	// 3: DISPLAY_MODE_HITACHI_QVGA: Hitachi LCD, Portrait QVGA 240x320
+		{ 0, 240, 320, EFalse, KConfigBitsPerPixel32, KPulseWidth,       525, 800,  240, 320, },
+	// 4: DISPLAY_MODE_NEC_WVGA: NEC LCD, Landscape WVGA
+		{ 0, 800, 480, EFalse, KConfigBitsPerPixel32, KPulseWidthWvga,   525, 1024, 800, 480, },
+	// 5: DISPLAY_MODE_ANALOG_QVGA_PORTRAIT: No LCD, Portrait QVGA 240x320
+	// Note! this screen mode reports different dimensions than the real panel size
+		{ 0, 640, 480, EFalse, KConfigBitsPerPixel16, KPulseWidthVga,    525, 800,  240, 320, },
+	// 6: DISPLAY_MODE_ANALOG_QVGA_LANDSCAPE: No LCD, Landscape QVGA 320x240
+		{ 0, 640, 480, EFalse, KConfigBitsPerPixel16, KPulseWidthVga,    525, 800,  320, 240, },
+	};
+
+// Hack function to convert pixels to TWIPS
+// Twips are screen-independent units to ensure that the proportion of screen elements
+// are the same on all display systems. A twip is defined as being 1/20th of a point.
+inline TInt PixelsToTwips(TInt aPixels)
+	{
+	return (119*aPixels)/10;
+	}
+
+DLcdPowerHandler	*  DLcdPowerHandler::pLcd			= NULL;
+
+
+const TInt   KDisplay0ThreadPriority					= 26;
+
+const TInt   KVSyncDfcPriority							= 7 ;   //priority of DFC within the queue (0 to 7, where 7 is highest)
+
+
+_LIT(KLitLcd,"LCD");
+_LIT(KDisplay0DfcThread,"Display0DfcThread-");
+
+TInt vsync_irq_callback(TUint a, TAny* b);
+
+#ifdef __SMP__
+static TSpinLock callbackLock = TSpinLock(TSpinLock::EOrderGenericIrqHigh0);
+#endif
+
+
+/**********************************************
+*    Class DDisplayPddNaviEng
+***********************************************/
+
+void DDisplayPddNaviEng::VSyncDfcFn(TAny* aChannel)
+	{
+	DDisplayPddNaviEng * channel =(DDisplayPddNaviEng*)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)
+				{
+				//If a subsequent PostUserRequest has occured,so there is a pending user buffer which has 
+				//cancelled the previous post( the one that  queued the current active buffer), calling 
+				//RequestComplete would mistakenly complete the latest PostUserRequest. 
+				
+				if (!(channel->iPendingBuffer && channel->iPendingBuffer->iType == EBufferTypeUser) )
+					{	
+					channel->RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrNone);	
+					}
+				
+				}
+			else
+				{
+				channel->iActiveBuffer->iFree	= ETrue;
+				}
+			
+			channel->iActiveBuffer->iState		= EBufferFree;
+							
+			
+			if (channel->iActiveBuffer->iType == EBufferTypeComposition)
+				{
+				//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("DDisplayPddNaviEng::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);
+			}
+		}
+		
+	}
+
+
+
+/**
+	Constructor
+*/
+DDisplayPddNaviEng::DDisplayPddNaviEng():
+	iPendingBuffer(NULL),
+	iActiveBuffer(NULL),
+	iChunk(NULL),
+	iLcdCallback(NULL),
+	iVSyncDfc(&VSyncDfcFn, this, KVSyncDfcPriority)
+	{
+	__GCE_DEBUG_PRINT("DDisplayPddNaviEng::DDisplayPddNaviEng\n");
+
+	iPostFlag = EFalse;
+	}
+
+/**
+	Destructor
+*/
+DDisplayPddNaviEng::~DDisplayPddNaviEng()
+	{
+	__GCE_DEBUG_PRINT("DDisplayPddNaviEng::~DDisplayPddNaviEng()  \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);
+		}
+
+	}
+
+
+/**
+    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 DDisplayPddNaviEng::CreateChannelSetup(TInt aUnit)
+	{
+	__GCE_DEBUG_PRINT("DDisplayPddNaviEng::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  =  Kern::RoundToPageSize(2*DLcdPowerHandler::pLcd->iSize);
+
+	__GCE_DEBUG_PRINT2("DDisplayPddNaviEng::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);
+		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].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].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;
+
+	TUint64 reg64 = AsspRegister::Read64(KHwDisplayMemoryFrameAddress);
+
+	//set up Start address for frames 0 and 1 (The actual Physical addresses must be passed)
+	AsspRegister::Write64(KHwDisplayMemoryFrameAddress , ( (TUint64)DLcdPowerHandler::pLcd->iCompositionPhysical<<32  | reg64 ) );
+
+	//set up layer 2
+    TUint64 layer2Physical =  DLcdPowerHandler::pLcd->iCompositionPhysical+ DLcdPowerHandler::pLcd->iSize ;
+    AsspRegister::Write64(KHwDisplayMemoryFrameAddress + KHex8,layer2Physical ) ;
+
+	//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);
+
+	//Register callback function. The function will be called when V Sync is triggered
+	iLcdCallback = new TLcdUserCallBack(vsync_irq_callback, (TAny*)this);
+
+	r = KErrNoMemory;
+	if (iLcdCallback)
+		{
+		r = DLcdPowerHandler::pLcd->RegisterCallback(iLcdCallback) ;
+		}
+
+	if( r!= KErrNone)
+		{
+		delete iLcdCallback ;
+		iLcdCallback = NULL ;
+		return r;
+		}
+
+	return KErrNone;
+	}
+
+
+/**
+	Called by the Vsync callback method and queues the corresponding DFC.
+ */
+void DDisplayPddNaviEng::VSyncIsr()
+	{
+	iVSyncDfc.Add();
+	}
+
+
+/**
+	Return the DFC queue to be used for this device.
+ */
+TDfcQue * DDisplayPddNaviEng:: DfcQ(TInt aUnit)
+	{
+	return iDfcQ;
+	}
+
+
+/**
+    Handles device specific operations when a close message has been sent to the Logical Channel.
+
+*/
+TInt DDisplayPddNaviEng::CloseMsg()
+	{
+	__GCE_DEBUG_PRINT("DDisplayPddNaviEng::CloseMsg()\n");
+
+	iPendingBuffer  = NULL;
+	iActiveBuffer	= NULL;
+
+	iVSyncDfc.Cancel();
+    return KErrNone;
+	}
+
+
+/**
+    Set the GCE mode by posting a composition buffer.
+
+*/
+TInt DDisplayPddNaviEng::SetGceMode()
+	{
+	__GCE_DEBUG_PRINT("DDisplayPddNaviEng::SetGceMode()\n");
+
+    PostCompositionBuffer(&iLdd->iCompositionBuffer[0]);
+    return KErrNone;
+	}
+
+
+/**
+    Set the Legacy Mode by setting the appropriate Frame control value.
+
+*/
+TInt DDisplayPddNaviEng::SetLegacyMode()
+	{
+	__GCE_DEBUG_PRINT("DDisplayPddNaviEng::SetLegacyMode()\n");
+
+	//Set the default frame 0 which corresponds to the Legacy Buffer.
+	AsspRegister::Write64(KHwDisplayDisplayFrameControl, KDisplayFrameControlValue);
+    return KErrNone;
+	}
+
+
+/**
+	If the specified rotation is supported set it as the current rotation.  The NaviEngine
+	version supports only the RDisplayChannel::ERotationNormal rotation.
+
+	@param  aDegOfRot The requested rotation to be set.
+
+	@return KErrNone if the rotation is supported else KErrArgument.
+*/
+TInt DDisplayPddNaviEng::SetRotation(RDisplayChannel::TDisplayRotation aDegOfRot)
+	{
+	TInt r;
+
+	switch (aDegOfRot)
+		{
+		case RDisplayChannel::ERotationNormal:
+			r = KErrNone;
+			break;
+		default:
+			r = KErrArgument;
+		}
+
+	return r;
+	}
+
+
+/**
+    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 DDisplayPddNaviEng::PostUserBuffer(TBufferNode* aNode)
+	{
+
+	__GCE_DEBUG_PRINT2("PostUserBuffer :  aNode->iAddress = %08x\n", aNode->iAddress);
+
+	if(iPendingBuffer)
+		{
+		iPendingBuffer->iState = EBufferFree;
+		if (!(iPendingBuffer->iType == EBufferTypeUser) )
+			{
+			iPendingBuffer->iFree  = ETrue;
+			}
+		}
+
+	//Set the Physical address for layer3 and then set layer3 as the frame to be displayed.
+	AsspRegister::Write64(KHwDisplayMemoryFrameAddress + KHex8 ,(TUint64)aNode->iPhysicalAddress<<32 );
+	AsspRegister::Write64(KHwDisplayDisplayFrameControl, KDisplayFrame3ControlValue);
+
+	aNode->iState   = EBufferPending;
+	iPendingBuffer	= aNode;
+	iPostFlag		= ETrue;
+
+	TUint64 reg64 = AsspRegister::Read64(KHwDisplayInterruptEnable);
+	reg64 |= KVSyncEnable;
+	AsspRegister::Write64(KHwDisplayInterruptEnable , reg64 ); //Enable Vsync
+
+	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 DDisplayPddNaviEng::PostCompositionBuffer(TBufferNode* aNode)
+	{
+
+	__GCE_DEBUG_PRINT2("PostCompositionBuffer :  aNode->iAddress = %08x\n", aNode->iAddress);
+
+	if(iPendingBuffer)
+		{
+		iPendingBuffer->iState = EBufferFree;
+		if (iPendingBuffer->iType == EBufferTypeUser)
+			{
+			RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrCancel);
+			}
+		else
+			{
+			iPendingBuffer->iFree  = ETrue;
+			}
+		}
+
+	if ( aNode->iBufferId == 0)
+		{
+		// Display frame control registers	(Layer 1)
+		AsspRegister::Write64(KHwDisplayDisplayFrameControl , KDisplayFrame1ControlValue );
+		}
+	else if	( aNode->iBufferId == 1)
+		{
+		// Display frame control registers	(Layer 2)
+		AsspRegister::Write64(KHwDisplayDisplayFrameControl , KDisplayFrame2ControlValue);
+
+		//Reset Layer2 ( The value might have been overwriten by a PostUserBuffer operation).
+		AsspRegister::Write64(KHwDisplayMemoryFrameAddress + KHex8, DLcdPowerHandler::pLcd->iCompositionPhysical + DLcdPowerHandler::pLcd->iSize);
+		}
+
+	aNode->iState	= EBufferPending;
+	aNode->iFree	= EFalse;
+	iPendingBuffer	= aNode;
+	iPostFlag		= ETrue;
+
+	TUint64 reg64 = AsspRegister::Read64(KHwDisplayInterruptEnable);
+	reg64 |= KVSyncEnable;
+	AsspRegister::Write64(KHwDisplayInterruptEnable , reg64 ); //Enable Vsync
+
+	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 DDisplayPddNaviEng::PostLegacyBuffer()
+	{
+	__GCE_DEBUG_PRINT("PostLegacyBuffer() \n");
+
+	if(iPendingBuffer)
+		{
+		iPendingBuffer->iState = EBufferFree;
+		if (iPendingBuffer->iType == EBufferTypeUser)
+			{
+
+			RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrCancel);
+			}
+		else
+			{
+			iPendingBuffer->iFree  = ETrue;
+			}
+		}
+
+
+	AsspRegister::Write64(KHwDisplayDisplayFrameControl, KDisplayFrameControlValue);
+
+	iLdd->iLegacyBuffer[0].iState		= EBufferPending;
+	iLdd->iLegacyBuffer[0].iFree		= EFalse;
+	iPendingBuffer						= &iLdd->iLegacyBuffer[0];
+	iPostFlag		= ETrue;
+
+	TUint64 reg64 = AsspRegister::Read64(KHwDisplayInterruptEnable);
+	reg64 |= KVSyncEnable;
+	AsspRegister::Write64(KHwDisplayInterruptEnable , reg64 ); //Enable Vsync
+
+	return KErrNone;
+	}
+
+/**
+Detect whether a post operation is pending
+*/
+TBool DDisplayPddNaviEng::PostPending()
+	{
+	return (iPendingBuffer != NULL);
+	}
+
+/**
+VSync Callback function
+ */
+TInt vsync_irq_callback(TUint a, TAny* ch)
+	{
+	// get channel
+	if(ch)
+		{
+		DDisplayPddNaviEng * channel=(DDisplayPddNaviEng*)ch;
+		channel->VSyncIsr();
+		}
+	return 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)
+	{
+	DDisplayPddNaviEng *device= new DDisplayPddNaviEng() ;
+	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 ;
+	}
+
+
+/**
+HAL handler function
+
+@param	aPtr a pointer to an instance of DLcdPowerHandler
+@param	aFunction the function number
+@param	a1 an arbitrary parameter
+@param	a2 an arbitrary parameter
+*/
+LOCAL_C TInt halFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
+	{
+	DLcdPowerHandler* pH=(DLcdPowerHandler*)aPtr;
+	return pH->HalFunction(aFunction,a1,a2);
+	}
+
+/**
+DFC for receiving messages from the power handler
+@param	aPtr a pointer to an instance of DLcdPowerHandler
+*/
+void rxMsg(TAny* aPtr)
+	{
+	DLcdPowerHandler& h=*(DLcdPowerHandler*)aPtr;
+	TMessageBase* pM=h.iMsgQ.iMessage;
+	if (pM)
+		{
+		h.HandleMsg(pM);
+		}
+	}
+
+/**
+DFC for powering up the device
+
+@param aPtr	aPtr a pointer to an instance of DLcdPowerHandler
+*/
+void power_up_dfc(TAny* aPtr)
+	{
+	((DLcdPowerHandler*)aPtr)->PowerUpDfc();
+	}
+
+/**
+DFC for powering down the device
+
+@param aPtr	aPtr a pointer to an instance of DLcdPowerHandler
+*/
+void power_down_dfc(TAny* aPtr)
+	{
+	((DLcdPowerHandler*)aPtr)->PowerDownDfc();
+	}
+
+
+/**
+Default constructor
+*/
+DLcdPowerHandler::DLcdPowerHandler() :
+		DPowerHandler(KLitLcd),
+		iPowerUpDfc(&power_up_dfc,this,6),
+		iPowerDownDfc(&power_down_dfc,this,7),
+		iBacklightOn(EFalse),
+		iContrast(KConfigInitialDisplayContrast),
+		iBrightness(KConfigInitialDisplayBrightness),
+		iMsgQ(rxMsg,this,NULL,1)
+	{
+	}
+
+
+TInt DLcdPowerHandler::InitialiseController()
+	{
+	// Call Power Resource Manager to set clk value, immediately after it initialises the resource
+	DPowerResourceController::PostBootLevel(ENE1_TBDisplayDclkResource,	EDisplayDclk24937KHz);
+
+	//Set up layers 0-3 needed by the GCE.
+	//Layer 0 is associated with legacy buffer.
+	//Layer 1 and 2 are associated with composition buffers 0 and 1 respectively.
+	//Layer 3 is associated with user buffers.
+
+	// Memory Frame control registers
+	AsspRegister::Write64(KHwDisplayEndianConversion,	KEndianConversionValue);
+
+	// Default to 32bpp
+	TUint64 PixelFormatValue = KPixelFormatValue32bpp;
+	if (iVideoInfo.iBitsPerPixel == 32)
+		{
+		PixelFormatValue = KPixelFormatValue32bpp;
+		}
+	else if (iVideoInfo.iBitsPerPixel == 16)
+		{
+		PixelFormatValue = KPixelFormatValue16bpp;
+		}
+
+	AsspRegister::Write64(KHwDisplayPixelFormat, PixelFormatValue<<48 | PixelFormatValue<<32 | PixelFormatValue<<16 | PixelFormatValue);
+
+	//Set up the the memory frame 0 start address to be the one of the Legacy Buffer
+	AsspRegister::Write64(KHwDisplayMemoryFrameAddress, ivRamPhys);
+
+	//Memory frame 0-3 size H
+	TInt HValue		= Lcd_Mode_Config[iInitialMode].iConfigLcdWidth-1 ;
+	AsspRegister::Write64(KHwDisplayMemoryFrameSizeH,  (TUint64) HValue<<48  | (TUint64) HValue<<32 | HValue<<16 | HValue ) ;
+
+	//Memory frame 0-3 size V
+	TInt VValue		= Lcd_Mode_Config[iInitialMode].iConfigLcdHeight-1 ;
+	AsspRegister::Write64(KHwDisplayMemoryFrameSizeV,  (TUint64) VValue<<48 | (TUint64) VValue<<32 | VValue<<16 | VValue ) ;
+
+	//0 for all layers
+    AsspRegister::Write64(KHwDisplayMemoryFrameStartPointX, 0);
+	AsspRegister::Write64(KHwDisplayMemoryFrameStartPointY, 0);
+
+	//Memory frame 0-3 display frame size H
+	HValue			= Lcd_Mode_Config[iInitialMode].iConfigLcdWidth-1 ;
+	AsspRegister::Write64(KHwDisplayMemoryFrameDisplayFrameSizeH, (TUint64) HValue<<48 | (TUint64) HValue<<32 | HValue<<16 | HValue );
+
+	//Memory frame 1-3 display frame size V
+	VValue			= Lcd_Mode_Config[iInitialMode].iConfigLcdHeight-1 ;
+	AsspRegister::Write64(KHwDisplayMemoryFrameDisplayFrameSizeV,  (TUint64) VValue<<48 |(TUint64) VValue<<32 | VValue<<16 | VValue);
+
+
+	// Display frame control registers ( Frame 0 is associated to the Legacy buffer)
+	AsspRegister::Write64(KHwDisplayDisplayFrameControl, KDisplayFrameControlValue);
+
+	//0 for all layers
+	AsspRegister::Write64(KHwDisplayDisplayFrameStartPointX, 1);
+	AsspRegister::Write64(KHwDisplayDisplayFrameStartPointY, 0);
+
+	// Display frames 1-3 size H - Sets the horizontal size to be displayed in pixel units
+	TInt width		= Lcd_Mode_Config[iInitialMode].iConfigLcdWidth-1;
+	AsspRegister::Write64(KHwDisplayDisplayFrameSizeH,  (TUint64) width<<48 | (TUint64) width<<32 | width<<16 | width   );
+
+
+	 // Display frames 0-3 size V - Sets the vertical  size to be displayed in pixel units
+	TInt height       = Lcd_Mode_Config[iInitialMode].iConfigLcdHeight-1;
+	AsspRegister::Write64(KHwDisplayDisplayFrameSizeV,  (TUint64)height<<48 |(TUint64) height<<32 | height<<16 | height   );
+
+
+	// Display frames    0-3 Constant color R - G - B
+	AsspRegister::Write64(KHwDisplayDisplayFrameConstantColour,         (TUint64) 0x404<<32 | 0x404  );
+	AsspRegister::Write64(KHwDisplayDisplayFrameConstantColour + KHex8, (TUint64) 0x404<<32 | 0x404  );
+	AsspRegister::Write64(KHwDisplayDisplayFrameBackgroundColour,	    0x404);
+
+	// Display control registers
+	AsspRegister::Write64(KHwDisplayResolutionAndCycle,  RESOLUTION_AND_CYCLE);
+	AsspRegister::Write64(KHwDisplayPulseWidth,          Lcd_Mode_Config[iInitialMode].iPulseWidth);
+
+	AsspRegister::Write64(KHwDisplaySettings,	   KDisplaySettingsValue);
+	AsspRegister::Write64(KHwDisplayBrightness,   KDisplayBrightnessVal);
+
+	// Interface control registers
+
+	AsspRegister::Write64(KHwDisplayInterfaceControl, KInterfaceControlValue); //sends signals out
+
+	// Set DCLK frequency:
+	AsspRegister::Write32(KHwSystemCtrlBase+KHoSCUDisplayDCLKCtrl, 11);
+
+	return KErrNone;
+	}
+
+/**
+Second-phase constructor
+
+Called by factory function at ordinal 0
+*/
+TInt DLcdPowerHandler::Create()
+	{
+	pLcd			= this;
+
+	// map the video RAM
+	TInt vSize		= ((NaviEngineAssp*)Arch::TheAsic())->VideoRamSize();
+	ivRamPhys		= TNaviEngine::VideoRamPhys();
+	TInt r			= DPlatChunkHw::New(iChunk,ivRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC);
+	if (r != KErrNone)
+		return r;
+
+	//create "secure" screen immediately after normal one
+	iSecurevRamPhys = ivRamPhys + vSize;
+	TInt r2 = DPlatChunkHw::New(iSecureChunk,iSecurevRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC);
+	if (r2 != KErrNone)
+		return r2;
+
+	TUint* pV		= (TUint*)iChunk->LinearAddress();
+
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("DLcdPowerHandler::Create: VideoRamSize=%x, VideoRamPhys=%08x, VideoRamLin=%08x",vSize,ivRamPhys,pV));
+
+	TUint* pV2		= (TUint*)iSecureChunk->LinearAddress();
+
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("DLcdPowerHandler::Create: Secure display VideoRamSize=%x, VideoRamPhys=%08x, VideoRamLin=%08x",vSize,iSecurevRamPhys,pV2));
+
+	// Read display mode set with DIP switches 7 & 8
+	// to get the requested LCD display mode
+	iInitialMode = ReadDipSwitchDisplayMode();
+
+	// setup the video info structure, this'll be used to remember the video settings
+	iVideoInfo.iDisplayMode				= SCREEN_UNIT;
+	iVideoInfo.iOffsetToFirstPixel		= Lcd_Mode_Config[iInitialMode].iOffsetToFirstVideoBuffer;
+	iVideoInfo.iIsPalettized			= Lcd_Mode_Config[iInitialMode].iIsPalettized;
+	iVideoInfo.iOffsetBetweenLines		= Lcd_Mode_Config[iInitialMode].iConfigLcdWidth * (Lcd_Mode_Config[iInitialMode].iBitsPerPixel >> KShiftBitsPerByte);
+	iVideoInfo.iBitsPerPixel			= Lcd_Mode_Config[iInitialMode].iBitsPerPixel;
+	iVideoInfo.iSizeInPixels.iWidth		= Lcd_Mode_Config[iInitialMode].iReportedLcdWidth;
+	iVideoInfo.iSizeInPixels.iHeight	= Lcd_Mode_Config[iInitialMode].iReportedLcdHeight;
+	iVideoInfo.iSizeInTwips.iWidth		= PixelsToTwips(iVideoInfo.iSizeInPixels.iWidth);
+	iVideoInfo.iSizeInTwips.iHeight		= PixelsToTwips(iVideoInfo.iSizeInPixels.iHeight);
+	iVideoInfo.iIsMono					= KConfigLcdIsMono;
+	iVideoInfo.iVideoAddress			= (TInt)pV;
+	iVideoInfo.iIsPixelOrderLandscape	= KConfigLcdPixelOrderLandscape;
+	iVideoInfo.iIsPixelOrderRGB			= KConfigLcdPixelOrderRGB;
+
+	iSecureVideoInfo					= iVideoInfo;
+	iSecureVideoInfo.iVideoAddress		= (TInt)pV2;
+
+	iDisplayOn							= EFalse;
+	iSecureDisplay						= EFalse;
+
+	// install the HAL function
+	r=Kern::AddHalEntry(EHalGroupDisplay, halFunction, this);
+	if (r!=KErrNone)
+		return r;
+
+	iPowerUpDfc.SetDfcQ(iDfcQ);
+	iPowerDownDfc.SetDfcQ(iDfcQ);
+	iMsgQ.SetDfcQ(iDfcQ);
+	iMsgQ.Receive();
+
+	// Alloc Physical RAM for the Composition Buffers used by the GCE
+	iSize = FRAME_BUFFER_SIZE(Lcd_Mode_Config[iInitialMode].iBitsPerPixel, Lcd_Mode_Config[iInitialMode].iConfigLcdWidth, Lcd_Mode_Config[iInitialMode].iConfigLcdHeight);
+	// double and round the page size
+	TUint round = Kern::RoundToPageSize(2*iSize);
+
+	r=Epoc::AllocPhysicalRam(round , iCompositionPhysical);
+	if(r!=KErrNone)
+		{
+		return r;
+		}
+
+	// clear interrupts
+	AsspRegister::Write64(KHwDisplayInterruptClear, 0x7f);
+
+	//Set up V Sync interrupt.
+	//Bind Interrupt
+	TInt interruptId= Interrupt::Bind(EIntDisp0,Service,this);
+
+	if (interruptId<0)
+		{
+		return interruptId;
+		}
+
+	Interrupt::Enable(interruptId);
+
+	//In case more display related interrupts are enabled KHwDisplayInterruptEnableSelection
+	// should be changed appropriately
+
+	AsspRegister::Write64(KHwDisplayInterruptEnableSelection , KVSyncSelectToChannel1 );
+
+	// install the power handler
+	// power up the screen
+	Add();
+	DisplayOn();
+
+	InitialiseController();
+
+	__KTRACE_OPT(KEXTENSION, Kern::Printf(
+				"Lcd_Mode_Config: mode = %d, iInitialMode %d, physical %dx%d, reporting %dx%d, bpp %d, obl %d",
+				iVideoInfo.iDisplayMode, iInitialMode, Lcd_Mode_Config[iInitialMode].iConfigLcdWidth, Lcd_Mode_Config[iInitialMode].iConfigLcdHeight,
+				iVideoInfo.iSizeInPixels.iWidth, iVideoInfo.iSizeInPixels.iHeight, iVideoInfo.iBitsPerPixel, iVideoInfo.iOffsetBetweenLines)
+	);
+
+	SplashScreen();
+
+	return KErrNone;
+	}
+
+
+
+/**
+ * Dispatch interrupts received by the display subsystem
+ * @param aPtr Argument passed to the ISR
+ */
+void DLcdPowerHandler::Service(TAny* aPtr)
+	{
+	DLcdPowerHandler& display = *(DLcdPowerHandler*)aPtr;
+
+	TInt irq=__SPIN_LOCK_IRQSAVE(callbackLock);
+
+	TUint64 dispStatus = AsspRegister::Read64(KHwDisplayInterruptStatus);
+	TUint64 dispEnable = AsspRegister::Read64(KHwDisplayInterruptEnable);
+
+	TUint64 reg64 =  dispEnable;
+
+	//disable VSYNC
+	reg64 &= KVSyncDisable;
+	AsspRegister::Write64(KHwDisplayInterruptEnable , reg64 );
+
+	//V sync interrupt signal has been received
+	if(  ((dispStatus & KVSyncStatus) == KVSyncStatus ) && ( ( dispEnable & KVSyncEnable ) == KVSyncEnable  )    )
+		{
+		// Call the GCE call back function in case of VSync
+		if ((display.iAppCallBk[0] != NULL) && (display.iAppCallBk[0]->iCbFn != NULL))
+			{
+			(*(display.iAppCallBk[0]->iCbFn))(0,display.iAppCallBk[0]->iDataPtr);
+			}
+		if((display.iAppCallBk[1] != NULL) && (display.iAppCallBk[1]->iCbFn != NULL))
+			{
+			(*(display.iAppCallBk[1]->iCbFn))(1,display.iAppCallBk[1]->iDataPtr);
+			}
+		}
+
+	__SPIN_UNLOCK_IRQRESTORE(callbackLock,irq);
+
+	reg64 = AsspRegister::Read64(KHwDisplayInterruptClear);
+	AsspRegister::Write64(KHwDisplayInterruptClear, reg64 | KVSyncClear);   //CLear Vsync interrupt bit
+
+	}
+
+
+/**
+ * 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);
+		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);
+}
+
+
+/**
+Turn the display on
+May be called as a result of a power transition or from the HAL
+If called from HAL, then the display may be already be on (iDisplayOn == ETrue)
+*/
+void DLcdPowerHandler::DisplayOn()
+	{
+	__KTRACE_OPT(KPOWER, Kern::Printf("DisplayOn %d", iDisplayOn));
+	if (!iDisplayOn)				// may have been powered up already
+		{
+		iDisplayOn = ETrue;
+		PowerUpLcd(iSecureDisplay);
+		SetContrast(iContrast);
+		SetBrightness(iBrightness);
+		}
+	}
+
+/**
+Turn the display off
+May be called as a result of a power transition or from the HAL
+If called from Power Manager, then the display may be already be off (iDisplayOn == EFalse)
+if the platform is in silent running mode
+*/
+void DLcdPowerHandler::DisplayOff()
+	{
+	__KTRACE_OPT(KPOWER, Kern::Printf("DisplayOff %d", iDisplayOn));
+	if (iDisplayOn)
+		{
+		iDisplayOn = EFalse;
+		PowerDownLcd();
+		}
+	}
+
+/**
+Switch between secure and non-secure displays
+
+@param aSecure ETrue if switching to secure display
+*/
+void DLcdPowerHandler::SwitchDisplay(TBool aSecure)
+	{
+	if (aSecure)
+		{
+		if (!iSecureDisplay)
+			{
+			TThreadMessage& m=Kern::Message();
+			m.iValue = EDisplayHalSetSecure;
+			m.SendReceive(&iMsgQ);		// send a message and block Client thread until secure display has been enabled.
+			}
+		}
+	else
+		{
+		if (iSecureDisplay)
+			{
+			TThreadMessage& m=Kern::Message();
+			m.iValue = -EDisplayHalSetSecure;
+			m.SendReceive(&iMsgQ);		// send a message and block Client thread until secure display has been disabled.
+			}
+		}
+	}
+
+
+/**
+Switch to secure display
+
+*/
+void DLcdPowerHandler::SwitchToSecureDisplay()
+	{
+	DisplayOff();
+	iSecureDisplay = ETrue;
+	DisplayOn();
+	}
+
+
+/**
+Switch from secure display
+
+*/
+void DLcdPowerHandler::SwitchFromSecureDisplay()
+	{
+	DisplayOff();
+	iSecureDisplay = EFalse;
+	DisplayOn();
+	}
+
+
+/**
+DFC to power up the display
+*/
+void DLcdPowerHandler::PowerUpDfc()
+	{
+	__KTRACE_OPT(KPOWER, Kern::Printf("PowerUpDfc"));
+	DisplayOn();
+
+	PowerUpDone();				// must be called from a different thread than PowerUp()
+	}
+
+/**
+DFC to power down the display
+*/
+void DLcdPowerHandler::PowerDownDfc()
+	{
+	__KTRACE_OPT(KPOWER, Kern::Printf("PowerDownDfc"));
+	DisplayOff();
+	PowerDownDone();			// must be called from a different thread than PowerUp()
+	}
+
+/**
+Schedule the power-down DFC
+*/
+void DLcdPowerHandler::PowerDown(TPowerState)
+	{
+	iPowerDownDfc.Enque();		// schedules DFC to execute on this driver's thread
+	}
+
+/**
+Schedule the power-up DFC
+*/
+void DLcdPowerHandler::PowerUp()
+	{
+	iPowerUpDfc.Enque();		// schedules DFC to execute on this driver's thread
+	}
+
+/**
+Power up the display
+
+@param aSecure ETrue if powering up the secure display
+*/
+void DLcdPowerHandler::PowerUpLcd(TBool aSecure)
+	{
+	AsspRegister::Write16(KHwLCDDispBase,0x140); //power-up board and backlight
+	}
+
+/**
+Power down the display and the backlight
+*/
+void DLcdPowerHandler::PowerDownLcd()
+	{
+	SetBacklightState(EFalse);
+	AsspRegister::Write16(KHwLCDDispBase, 0x143); //power-down board and backlight
+	}
+
+/**
+Set the Lcd contrast
+
+@param aValue the contrast setting
+*/
+TInt DLcdPowerHandler::SetContrast(TInt aValue)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("SetContrast(%d)", aValue));
+
+	if (aValue >= KConfigLcdMinDisplayContrast && aValue <= KConfigLcdMaxDisplayContrast)
+		{
+		iContrast=aValue;
+		return KErrNone;
+		}
+
+	return KErrArgument;
+	}
+
+/**
+Queue a message to set the Lcd Contrast
+
+@param aValue the contrast setting
+*/
+TInt DLcdPowerHandler::HalSetContrast(TInt aValue)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("HalSetContrast(%d)", aValue));
+
+	TThreadMessage& m=Kern::Message();
+	m.iValue = EDisplayHalSetDisplayContrast;
+	m.iArg[0] = (TAny *) aValue;
+
+	return ( m.SendReceive(&iMsgQ) );		// send a message and block Client thread until contrast has been set.
+	}
+
+
+
+/**
+Set the Lcd brightness
+
+@param aValue the brightness setting
+*/
+TInt DLcdPowerHandler::SetBrightness(TInt aValue)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("SetBrightness(%d)", aValue));
+
+	if (aValue >= KConfigLcdMinDisplayBrightness && aValue <= KConfigLcdMaxDisplayBrightness)
+		{
+		iBrightness=aValue;
+
+		return KErrNone;
+		}
+	return KErrArgument;
+	}
+
+/**
+Queue a message to set the Lcd brightness
+
+@param aValue the brightness setting
+*/
+TInt DLcdPowerHandler::HalSetBrightness(TInt aValue)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("HalSetBrightness(%d)", aValue));
+
+	TThreadMessage& m=Kern::Message();
+	m.iValue = EDisplayHalSetDisplayBrightness;
+	m.iArg[0]= (TAny *) aValue;
+
+	return (m.SendReceive(&iMsgQ));		// send a message and block Client thread until brightness has been set.
+	}
+
+
+/**
+Turn the backlight on
+*/
+void DLcdPowerHandler::BacklightOn()
+	{
+	// turn the backlight on
+	AsspRegister::Write16(KHwLCDDispBase, 0x140);
+	}
+
+/**
+Turn the backlight off
+*/
+void DLcdPowerHandler::BacklightOff()
+	{
+	// turn the backlight off
+	AsspRegister::Write16(KHwLCDDispBase, 0x142);
+	}
+
+/**
+Set the state of the backlight
+
+@param aState ETrue if setting the backlight on
+*/
+void DLcdPowerHandler::SetBacklightState(TBool aState)
+	{
+	iBacklightOn=aState;
+	if (iBacklightOn)
+		BacklightOn();
+	else
+		BacklightOff();
+	}
+
+void DLcdPowerHandler::ScreenInfo(TScreenInfoV01& anInfo)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("DLcdPowerHandler::ScreenInfo"));
+
+	anInfo.iWindowHandleValid	 = EFalse;
+	anInfo.iWindowHandle		 = NULL;
+	anInfo.iScreenAddressValid	 = ETrue;
+	anInfo.iScreenAddress		 = (TAny *)(iChunk->LinearAddress());
+	anInfo.iScreenSize.iWidth	 = Lcd_Mode_Config[iInitialMode].iReportedLcdWidth;
+	anInfo.iScreenSize.iHeight	 = Lcd_Mode_Config[iInitialMode].iReportedLcdHeight;
+	}
+
+/**
+Handle a message from the power handler
+*/
+void DLcdPowerHandler::HandleMsg(TMessageBase* aMsg)
+{
+	TInt r = KErrNone;
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+	switch(m.iValue)
+		{
+		case EDisplayHalWsSwitchOnScreen:
+			DisplayOn();
+			break;
+		case (-EDisplayHalWsSwitchOnScreen):
+			DisplayOff();
+			break;
+		case EDisplayHalSetSecure:
+			SwitchToSecureDisplay();
+			break;
+		case (-EDisplayHalSetSecure):
+			SwitchFromSecureDisplay();
+			break;
+		case EDisplayHalSetDisplayContrast:
+			{
+			r = SetContrast(m.Int0());
+			break;
+			}
+		case EDisplayHalSetDisplayBrightness:
+			{
+			r = SetBrightness(m.Int0());
+			break;
+		default:
+			r = KErrNotSupported;
+			__KTRACE_OPT(KHARDWARE,Kern::Printf("DLcdPowerHandler::HalFunction %d defaulted", m.iValue));
+			break;
+			}
+		}
+
+	m.Complete(r, ETrue);
+	}
+
+/**
+Send a message to the power-handler message queue to turn the display on
+*/
+void DLcdPowerHandler::WsSwitchOnScreen()
+	{
+	TThreadMessage& m=Kern::Message();
+	m.iValue = EDisplayHalWsSwitchOnScreen;
+	m.SendReceive(&iMsgQ);		// send a message and block Client thread until keyboard has been powered up
+	}
+
+/**
+Send a message to the power-handler message queue to turn the display off
+*/
+void DLcdPowerHandler::WsSwitchOffScreen()
+	{
+	TThreadMessage& m=Kern::Message();
+	m.iValue = -EDisplayHalWsSwitchOnScreen;
+	m.SendReceive(&iMsgQ);		// send a message and block Client thread until keyboard has been powered down
+	}
+
+/**
+Return information about the current display mode
+
+@param	aInfo a structure supplied by the caller to be filled by this function.
+@param	aSecure ETrue if requesting information about the secure display
+@return	KErrNone if successful
+*/
+TInt DLcdPowerHandler::GetCurrentDisplayModeInfo(TVideoInfoV01& aInfo, TBool aSecure)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("GetCurrentDisplayModeInfo"));
+	NKern::FMWait(&iLock);
+	if (aSecure)
+		aInfo = iSecureVideoInfo;
+	else
+		aInfo = iVideoInfo;
+	NKern::FMSignal(&iLock);
+	return KErrNone;
+	}
+
+/**
+Return information about the specified display mode
+
+@param	aScreenNumber the screen number to query
+@param	aInfo a structure supplied by the caller to be filled by this function.
+@return	KErrNone if successful
+*/
+TInt DLcdPowerHandler::GetSpecifiedDisplayModeInfo(TInt aScreenNumber, TVideoInfoV01& aInfo)
+	{
+	__KTRACE_OPT(KEXTENSION, Kern::Printf("GetSpecifiedDisplayModeInfo screen unit is %d",aScreenNumber));
+
+	if (aScreenNumber < 0 || aScreenNumber >= SCREEN_UNIT_COUNT)
+		return KErrArgument;
+
+	NKern::FMWait(&iLock);
+	aInfo = iVideoInfo;
+	NKern::FMSignal(&iLock);
+
+	return KErrNone;
+	}
+
+/**
+Set the display mode
+
+@param	aScreenNumber the screen number to set
+*/
+TInt DLcdPowerHandler::SetDisplayMode(TInt aScreenNumber)
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("SetDisplayMode ( screen unit) = %d", aScreenNumber));
+
+	if (aScreenNumber < 0 || aScreenNumber >= SCREEN_UNIT_COUNT)
+		return KErrArgument;
+
+	NKern::FMWait(&iLock);
+
+	// store the current mode
+	iVideoInfo.iDisplayMode					= SCREEN_UNIT;
+	iVideoInfo.iOffsetToFirstPixel			= Lcd_Mode_Config[iInitialMode].iOffsetToFirstVideoBuffer;
+	iVideoInfo.iIsPalettized				= Lcd_Mode_Config[iInitialMode].iIsPalettized;
+	iVideoInfo.iOffsetBetweenLines			= Lcd_Mode_Config[iInitialMode].iConfigLcdWidth * (Lcd_Mode_Config[iInitialMode].iBitsPerPixel >> KShiftBitsPerByte);
+	iVideoInfo.iBitsPerPixel				= Lcd_Mode_Config[iInitialMode].iBitsPerPixel;
+
+	// store the current mode for secure screen
+	iSecureVideoInfo.iDisplayMode			= SCREEN_UNIT;
+	iSecureVideoInfo.iOffsetToFirstPixel	= Lcd_Mode_Config[iInitialMode].iOffsetToFirstVideoBuffer;
+	iSecureVideoInfo.iIsPalettized			= Lcd_Mode_Config[iInitialMode].iIsPalettized;
+	iSecureVideoInfo.iOffsetBetweenLines	= Lcd_Mode_Config[iInitialMode].iConfigLcdWidth * (Lcd_Mode_Config[iInitialMode].iBitsPerPixel >> KShiftBitsPerByte);
+	iSecureVideoInfo.iBitsPerPixel			= Lcd_Mode_Config[iInitialMode].iBitsPerPixel;
+
+	NKern::FMSignal(&iLock);
+
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("SetDisplayMode screenNumber = %d, otfp = %d, palettized = %d, bpp = %d, obl = %d",
+		aScreenNumber, iVideoInfo.iOffsetToFirstPixel, iVideoInfo.iIsPalettized, iVideoInfo.iBitsPerPixel, iVideoInfo.iOffsetBetweenLines));
+
+	return KErrNone;
+	}
+
+/**
+Fill the video memory with an initial pattern or image
+This will be displayed on boot-up
+*/
+const TInt KGranularity = 4;
+
+void DLcdPowerHandler::SplashScreen()
+	{
+	//initialise the video ram to be a splash screen
+
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("SplashScreen"));
+
+	TInt xres, yres, bpp, bpl, ofp;
+	TLinAddr addr;
+	addr = (TLinAddr)iVideoInfo.iVideoAddress;
+	xres = iVideoInfo.iSizeInPixels.iWidth;
+	yres = iVideoInfo.iSizeInPixels.iHeight;
+	bpp  = iVideoInfo.iBitsPerPixel;
+	bpl  = iVideoInfo.iOffsetBetweenLines;
+	ofp  = iVideoInfo.iOffsetToFirstPixel;
+
+	TInt xb, yb;
+
+	for (yb=0; yb<yres/KGranularity; ++yb)
+		{
+		for (xb=0; xb<xres/KGranularity; ++xb)
+			{
+			TUint c=((xb*xb+yb*yb)>>1)%251;
+			c^=0xff;
+			TUint r=c&7;
+			TUint g=(c>>3)&7;
+			TUint b=(c>>6);
+			TUint c16=(b<<14)|(g<<8)|(r<<2);
+			c16 |= (c16<<16);
+			TUint c8=c|(c<<8);
+			c8 |= (c8<<16);
+			TUint c32=(b<<22)|(g<<13)|(r<<5);
+			TInt baddr=addr+ofp+yb*KGranularity*bpl+xb*KGranularity*bpp/8;
+			TInt l;
+			for (l=0; l<KGranularity; ++l, baddr+=bpl)
+				{
+				TUint32* p=(TUint32*)baddr;
+				if (bpp==8)
+					*p++=c8;
+				else if (bpp==16)
+					*p++=c16, *p++=c16;
+				else
+					{
+					*p++=c32+0x0;
+					*p++=c32+0x4;
+					*p++=c32+0x8;
+					*p++=c32+0xc;
+					c32+=0x100;
+					}
+				}
+			}
+		}
+
+	// Secure screen
+	TUint8* linePtr = (TUint8*)iSecureVideoInfo.iVideoAddress+
+					   iSecureVideoInfo.iOffsetToFirstPixel;
+	TInt pixelSize  = iSecureVideoInfo.iBitsPerPixel;
+	if(pixelSize>8)
+		pixelSize = (pixelSize+7)&~7; // Round up to whole number of bytes
+	TInt bytesPerLine = (pixelSize*iSecureVideoInfo.iSizeInPixels.iWidth) >> 3;
+	for(TInt y=0; y<iSecureVideoInfo.iSizeInPixels.iHeight; y++)
+		{
+		for(TInt x=0; x<bytesPerLine; x++)
+			linePtr[x] = x+y;
+		linePtr += iSecureVideoInfo.iOffsetBetweenLines;
+		}
+	}
+
+
+
+/**
+Get the size of the pallete
+
+@return	the number of pallete entries
+*/
+TInt DLcdPowerHandler::NumberOfPaletteEntries()
+	{
+	TInt num = iVideoInfo.iIsPalettized ? 1<<iVideoInfo.iBitsPerPixel : 0;
+
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("NumberOfPaletteEntries = %d", num));
+
+	return num;
+	}
+
+
+/**
+Retrieve the palette entry at a particular offset
+
+@param	aEntry the palette index
+@param	aColor a caller-supplied pointer to a location where the returned RGB color is to be stored
+@return	KErrNone if successful
+		KErrNotSupported if the current vide mode does not support a palette
+		KErrArgument if aEntry is out of range
+*/
+TInt DLcdPowerHandler::GetPaletteEntry(TInt aEntry, TInt* aColor)
+	{
+	NKern::FMWait(&iLock);
+	if (!iVideoInfo.iIsPalettized)
+		{
+		NKern::FMSignal(&iLock);
+		return KErrNotSupported;
+		}
+
+	if ((aEntry < 0) || (aEntry >= NumberOfPaletteEntries()))
+		{
+		NKern::FMSignal(&iLock);
+		return KErrArgument;
+		}
+
+	NKern::FMSignal(&iLock);
+
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("GetPaletteEntry %d color 0x%x", aEntry, aColor));
+
+	return KErrNone;
+	}
+
+/**
+Set the palette entry at a particular offset
+
+@param	aEntry the palette index
+@param	aColor the RGB color to store
+@return	KErrNone if successful
+		KErrNotSupported if the current vide mode does not support a palette
+		KErrArgument if aEntry is out of range
+*/
+TInt DLcdPowerHandler::SetPaletteEntry(TInt aEntry, TInt aColor)
+	{
+
+	NKern::FMWait(&iLock);
+	if (!iVideoInfo.iIsPalettized)
+		{
+		NKern::FMSignal(&iLock);
+		return KErrNotSupported;
+		}
+
+	if ((aEntry < 0) || (aEntry >= NumberOfPaletteEntries()))	//check entry in range
+		{
+		NKern::FMSignal(&iLock);
+		return KErrArgument;
+		}
+
+	NKern::FMSignal(&iLock);
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("SetPaletteEntry %d to 0x%x", aEntry, aColor ));
+
+	return KErrNone;
+	}
+
+/**
+a HAL entry handling function for HAL group attribute EHalGroupDisplay.
+The HalFunction is called in the context of the user thread which is
+requesting the particular HAL display function.
+
+@param	a1 an arbitrary argument
+@param	a2 an arbitrary argument
+@return	KErrNone if successful
+*/
+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 EDisplayHalMaxDisplayContrast:
+			{
+			TInt mc=KConfigLcdMaxDisplayContrast;
+			kumemput32(a1,&mc,sizeof(mc));
+			break;
+			}
+		case EDisplayHalSetDisplayContrast:
+			if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetDisplayContrast")))
+				return KErrPermissionDenied;
+			r=HalSetContrast(TInt(a1));
+			break;
+
+		case EDisplayHalDisplayContrast:
+			kumemput32(a1,&iContrast,sizeof(iContrast));
+			break;
+
+		case EDisplayHalMaxDisplayBrightness:
+			{
+			TInt mc=KConfigLcdMaxDisplayBrightness;
+			kumemput32(a1,&mc,sizeof(mc));
+			break;
+			}
+
+		case EDisplayHalSetDisplayBrightness:
+			if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetDisplayBrightness")))
+				return KErrPermissionDenied;
+			r=HalSetBrightness(TInt(a1));
+			break;
+
+		case EDisplayHalDisplayBrightness:
+			kumemput32(a1,&iBrightness,sizeof(iBrightness));
+			break;
+
+		case EDisplayHalSetBacklightOn:
+			if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetBacklightOn")))
+				return KErrPermissionDenied;
+			if (Kern::MachinePowerStatus()<ELow)
+				r=KErrBadPower;
+			else
+				SetBacklightState(TBool(a1));
+			break;
+
+		case EDisplayHalBacklightOn:
+			kumemput32(a1,&iBacklightOn,sizeof(TInt));
+			break;
+
+		case EDisplayHalModeCount:
+			{
+			TInt ndm = SCREEN_UNIT_COUNT;
+			kumemput32(a1, &ndm, sizeof(ndm));
+			break;
+			}
+
+		case EDisplayHalSetMode:
+			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));
+			break;
+
+		case EDisplayHalSetPaletteEntry:
+			if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetPaletteEntry")))
+				return KErrPermissionDenied;
+			r = SetPaletteEntry((TInt)a1, (TInt)a2);
+			break;
+
+		case EDisplayHalPaletteEntry:
+			{
+			TInt entry;
+			kumemget32(&entry, a1, sizeof(TInt));
+			TInt x;
+			r = GetPaletteEntry(entry, &x);
+			if (r == KErrNone)
+				kumemput32(a2, &x, sizeof(x));
+			break;
+			}
+
+		case EDisplayHalSetState:
+			{
+			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 = KConfigLcdMaxDisplayColors;
+			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 screenNumber;
+			kumemget32(&screenNumber, a1, sizeof(screenNumber));
+			r = GetSpecifiedDisplayModeInfo(screenNumber, vPckg());
+			if (KErrNone == r)
+				Kern::InfoCopy(*(TDes8*)a2,vPckg);
+			}
+			break;
+
+		case EDisplayHalSecure:
+			kumemput32(a1, &iSecureDisplay, sizeof(TBool));
+			break;
+
+		case EDisplayHalSetSecure:
+			{
+			if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetSecure")))
+				return KErrPermissionDenied;
+			SwitchDisplay((TBool)a1);
+			}
+			break;
+
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	return r;
+	}
+
+
+DECLARE_STANDARD_EXTENSION()
+	{
+	__KTRACE_OPT(KPOWER,Kern::Printf("Starting LCD power manager"));
+
+	// create LCD power handler
+	TInt r=KErrNoMemory;
+	DLcdPowerHandler* pH=new DLcdPowerHandler;
+	if (pH)
+		{
+		//The same DFC queue will be used by both the LCD extension and GCE PDD
+		r= Kern::DfcQCreate( pH->iDfcQ, KDisplay0ThreadPriority, &KDisplay0DfcThread );
+		if ( r == KErrNone)
+			{
+			 r =pH->Create();
+			__KTRACE_OPT(KPOWER,Kern::Printf("Returns %d",r));
+
+			if ( r == KErrNone)
+				{
+				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;
+	}
+