--- /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;
+ }
+