work-a-round for Bug 3645 change ARGB->XRGB pixel format
(transplanted from bf4661c6bc44303cf0ecf72f57f09a5968309a10)
/*
* 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 = EUidPixelFormatXRGB_8888;
break;
default:
iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatUnknown;
break;
}
iLdd->iCurrentRotation = RDisplayChannel::ERotationNormal;
// Open shared chunk to the composition framebuffer
DChunk* chunk = 0;
TLinAddr chunkKernelAddr = 0;
TUint32 chunkMapAttr = 0;
// round to twice the page size
TUint round = 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;
}