# HG changeset patch # User emilioc # Date 1264603332 0 # Node ID 33dfab4ab0fc53083efca48c48a59dd11932286b # Parent 2925e6e5efd7cc47c5c5c14512383b431c5a2f6f PDD Display Driver for Syborg diff -r 2925e6e5efd7 -r 33dfab4ab0fc baseport/syborg/svpframebuffer/svpframebuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/baseport/syborg/svpframebuffer/svpframebuffer.cpp Wed Jan 27 14:42:12 2010 +0000 @@ -0,0 +1,1055 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Minimalistic frame buffer driver +* +*/ +#include +#include "platform.h" +#include +#include +#include +#include + +#include +#include "svpframebuffer.h" + +DLcdPowerHandler * DLcdPowerHandler::pLcd = NULL; + +TPhysAddr Syborg::VideoRamPhys; +TPhysAddr Syborg::VideoRamPhysSecure; // Secure display memory + +TPhysAddr TSyborg::VideoRamPhys() +{ + __KTRACE_OPT(KEXTENSION,Kern::Printf("TSyborg::VideoRamPhys: VideoRamPhys=0x%x", Syborg::VideoRamPhys)); + return Syborg::VideoRamPhys; +} + +TPhysAddr TSyborg::VideoRamPhysSecure() +{ + return Syborg::VideoRamPhysSecure; +} + +LOCAL_C TInt DoHalFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2) +{ + DLcdPowerHandler* pH=(DLcdPowerHandler*)aPtr; + return pH->HalFunction(aFunction,a1,a2); +} + +static void rxMsg(TAny* aPtr) +{ + DLcdPowerHandler& h=*(DLcdPowerHandler*)aPtr; + TMessageBase* pM = h.iMsgQ.iMessage; + if(pM) + h.HandleMsg(pM); +} + +static void power_up_dfc(TAny* aPtr) +{ + ((DLcdPowerHandler*)aPtr)->PowerUpDfc(); +} + +void power_down_dfc(TAny* aPtr) +{ + ((DLcdPowerHandler*)aPtr)->PowerDownDfc(); +} + +void DLcdPowerHandler::DisplayOn() +{ + PowerUpLcd(iSecureDisplay); + iDisplayOn = ETrue; +} + +void DLcdPowerHandler::DisplayOff() +{ + PowerDownLcd(); + iDisplayOn = EFalse; +} + +void DLcdPowerHandler::SwitchDisplay(TBool aSecure) + { + if(aSecure) + { + if(!iSecureDisplay) + { + DisplayOff(); + iSecureDisplay = ETrue; + DisplayOn(); + } + } + else + { + if(iSecureDisplay) + { + DisplayOff(); + iSecureDisplay = EFalse; + DisplayOn(); + } + } + } + +void DLcdPowerHandler::PowerUpDfc() +{ + DisplayOn(); + PowerUpDone(); +} + +void DLcdPowerHandler::PowerDownDfc() +{ + DisplayOff(); + PowerDownDone(); +} + +void DLcdPowerHandler::PowerDown(TPowerState) +{ + iPowerDownDfc.Enque(); +} + +void DLcdPowerHandler::PowerUp() +{ + iPowerUpDfc.Enque(); +} + +void DLcdPowerHandler::PowerUpLcd(TBool aSecure) +{ +#if 1 + WriteReg(iPortAddr, FB_ENABLED, 0); + WriteReg(iPortAddr, FB_BASE, aSecure ? iSecurevRamPhys : ivRamPhys); + WriteReg(iPortAddr, FB_WIDTH, iVideoInfo.iSizeInPixels.iWidth); + WriteReg(iPortAddr, FB_BLANK, 0); + WriteReg(iPortAddr, FB_BPP, 32); + WriteReg(iPortAddr, FB_COLOR_ORDER, 0); + WriteReg(iPortAddr, FB_BYTE_ORDER, 0); + WriteReg(iPortAddr, FB_PIXEL_ORDER, 0); + WriteReg(iPortAddr, FB_INT_MASK, 0); + WriteReg(iPortAddr, FB_ENABLED, 1); + WriteReg(iPortAddr, FB_HEIGHT, iVideoInfo.iSizeInPixels.iHeight); +#endif +} + +void DLcdPowerHandler::PowerDownLcd() +{ + WriteReg(iPortAddr, FB_BLANK, 1); +} + +DLcdPowerHandler::DLcdPowerHandler() + : DPowerHandler(KLitLcd), + iMsgQ(rxMsg,this,NULL,1), + iPowerUpDfc(&power_up_dfc,this,6), + iPowerDownDfc(&power_down_dfc,this,7) +{ +} + +void DLcdPowerHandler::ScreenInfo(TScreenInfoV01& anInfo) +{ + anInfo.iWindowHandleValid = EFalse; + anInfo.iWindowHandle = NULL; + anInfo.iScreenAddressValid = ETrue; + anInfo.iScreenAddress = (TAny *)(iChunk->LinearAddress()); + anInfo.iScreenSize.iWidth = iVideoInfo.iSizeInPixels.iWidth; + anInfo.iScreenSize.iHeight = iVideoInfo.iSizeInPixels.iHeight; +} + +void DLcdPowerHandler::HandleMsg(TMessageBase* aMsg) +{ + if(aMsg->iValue) + DisplayOn(); + else + DisplayOff(); + aMsg->Complete(KErrNone,ETrue); +} + +void DLcdPowerHandler::WsSwitchOnScreen() +{ + TThreadMessage& m = Kern::Message(); + m.iValue = ETrue; + m.SendReceive(&iMsgQ); +} + +void DLcdPowerHandler::WsSwitchOffScreen() +{ + TThreadMessage& m = Kern::Message(); + m.iValue = EFalse; + m.SendReceive(&iMsgQ); +} + +TInt DLcdPowerHandler::GetCurrentDisplayModeInfo(TVideoInfoV01& aInfo, TBool aSecure) +{ + NKern::FMWait(&iLock); + if(aSecure) + aInfo = iSecureVideoInfo; + else + aInfo = iVideoInfo; + NKern::FMSignal(&iLock); + return KErrNone; +} + +TInt DLcdPowerHandler::GetSpecifiedDisplayModeInfo(TInt aMode, TVideoInfoV01& aInfo) +{ + if(aMode < 0 || aMode >= KConfigLcdNumberOfDisplayModes) + return KErrArgument; + + NKern::FMWait(&iLock); + aInfo = iVideoInfo; + NKern::FMSignal(&iLock); + + if(aMode != aInfo.iDisplayMode) + { + aInfo.iOffsetToFirstPixel = KCOnfigOffsetToFirstPixel; + aInfo.iIsPalettized = KConfigIsPalettized; + aInfo.iOffsetBetweenLines = KCOnfigOffsetBetweenLines; + aInfo.iBitsPerPixel = KConfigBitsPerPixel; + } + return KErrNone; +} + +TInt DLcdPowerHandler::AllocateFrameBuffer() +{ + // Allocate physical RAM for video + TInt vSize = TSyborg::VideoRamSize(); + + NKern::ThreadEnterCS(); + TInt r = Epoc::AllocPhysicalRam(vSize,Syborg::VideoRamPhys); + if (r != KErrNone) + { + NKern::ThreadLeaveCS(); + Kern::Fault("AllocVideoRam",r); + } + + // Map the video RAM + ivRamPhys = TSyborg::VideoRamPhys(); + + r = DPlatChunkHw::New(iChunk,ivRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC); + + NKern::ThreadLeaveCS(); + + if(r != KErrNone) + return r; + + TUint* pV = (TUint*)iChunk->LinearAddress(); + + // Allocate physical RAM for secure display + NKern::ThreadEnterCS(); + r = Epoc::AllocPhysicalRam(vSize,Syborg::VideoRamPhysSecure); + if (r != KErrNone) + { + NKern::ThreadLeaveCS(); + Kern::Fault("AllocVideoRam 2",r); + } + iSecurevRamPhys = ivRamPhys + vSize; + TInt r2 = DPlatChunkHw::New(iSecureChunk,iSecurevRamPhys,vSize,EMapAttrUserRw|EMapAttrBufferedC); + + NKern::ThreadLeaveCS(); + + if(r2 != KErrNone) + return r2; + + TUint* pV2 = (TUint*)iSecureChunk->LinearAddress(); + + iVideoInfo.iSizeInPixels.iWidth = KConfigLcdWidth; + iVideoInfo.iSizeInPixels.iHeight = KConfigLcdHeight; + iVideoInfo.iDisplayMode = KConfigLcdDisplayMode; + iVideoInfo.iOffsetToFirstPixel = KCOnfigOffsetToFirstPixel; + iVideoInfo.iOffsetBetweenLines = KCOnfigOffsetBetweenLines; + iVideoInfo.iIsPalettized = KConfigIsPalettized; + iVideoInfo.iBitsPerPixel = KConfigBitsPerPixel; + iVideoInfo.iSizeInTwips.iWidth = KConfigLcdWidthInTwips; + iVideoInfo.iSizeInTwips.iHeight = KConfigLcdHeightInTwips; + iVideoInfo.iIsMono = KConfigIsMono; + iVideoInfo.iVideoAddress = (TInt)pV; + iVideoInfo.iIsPixelOrderLandscape = KConfigPixelOrderLandscape; + iVideoInfo.iIsPixelOrderRGB = KConfigPixelOrderRGB; + + iSecureVideoInfo = iVideoInfo; + iSecureVideoInfo.iVideoAddress = (TInt)pV2; + + // Alloc Physical RAM for the Composition Buffers used by the GCE + iSize = 4*480*640;//FRAME_BUFFER_SIZE( iVideoInfo.iBitsPerPixel, iVideoInfo.iSizeInPixels.iWidth, iVideoInfo.iSizeInPixels.iHeight); + __GCE_DEBUG_PRINT2("DLcdPowerHandler.iSize = %d\n", iSize ); + // double and round the page size + TUint round = 2*Kern::RoundToPageSize(iSize); + + r=Epoc::AllocPhysicalRam(round , iCompositionPhysical); + if(r!=KErrNone) + { + return r; + } + + return KErrNone; +} + + +TInt DLcdPowerHandler::SetDisplayMode(TInt aMode) +{ + if(aMode < 0 || aMode >= KConfigLcdNumberOfDisplayModes) + return KErrArgument; + + // store the current mode + iVideoInfo.iDisplayMode = aMode; + + // store the current mode for secure screen + iSecureVideoInfo.iDisplayMode = aMode; + + return KErrNone; +} + +TInt DLcdPowerHandler::HalFunction(TInt aFunction, TAny* a1, TAny* a2) +{ + TInt r=KErrNone; + switch(aFunction) + { + case EDisplayHalScreenInfo: + { + TPckgBuf vPckg; + ScreenInfo(vPckg()); + Kern::InfoCopy(*(TDes8*)a1,vPckg); + break; + } + case EDisplayHalWsRegisterSwitchOnScreenHandling: + { + iWsSwitchOnScreen=(TBool)a1; + break; + } + case EDisplayHalWsSwitchOnScreen: + { + WsSwitchOnScreen(); + break; + } + case EDisplayHalModeCount: + { + TInt ndm = KConfigLcdNumberOfDisplayModes; + kumemput32(a1, &ndm, sizeof(ndm)); + break; + } + case EDisplayHalSetMode: + { + __KTRACE_OPT(KEXTENSION,Kern::Printf("EDisplayHalSetMode")); + __SECURE_KERNEL( + if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetMode"))) + return KErrPermissionDenied; + ) + r = SetDisplayMode((TInt)a1); + break; + } + case EDisplayHalMode: + { + kumemput32(a1, &iVideoInfo.iDisplayMode, sizeof(iVideoInfo.iDisplayMode)); + r = KErrNone; + break; + } + case EDisplayHalSetPaletteEntry: + { + __SECURE_KERNEL( + if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetPaletteEntry"))) + return KErrPermissionDenied; + ) + r = KErrNotSupported; + break; + } + case EDisplayHalPaletteEntry: + { + TInt entry; + kumemget32(&entry, a1, sizeof(TInt)); + r = KErrNotSupported; + break; + } + case EDisplayHalSetState: + { + __SECURE_KERNEL( + if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetState"))) + return KErrPermissionDenied; + ) + if((TBool)a1) + WsSwitchOnScreen(); + else + WsSwitchOffScreen(); + break; + } + case EDisplayHalState: + { + kumemput32(a1, &iDisplayOn, sizeof(TBool)); + break; + } + case EDisplayHalColors: + { + TInt mdc = 1<<24; + kumemput32(a1, &mdc, sizeof(mdc)); + break; + } + case EDisplayHalCurrentModeInfo: + { + TPckgBuf vPckg; + r = GetCurrentDisplayModeInfo(vPckg(), (TBool)a2); + if(KErrNone == r) + Kern::InfoCopy(*(TDes8*)a1,vPckg); + break; + } + case EDisplayHalSpecifiedModeInfo: + { + TPckgBuf vPckg; + TInt mode; + kumemget32(&mode, a1, sizeof(mode)); + r = GetSpecifiedDisplayModeInfo(mode, vPckg()); + if(KErrNone == r) + Kern::InfoCopy(*(TDes8*)a2,vPckg); + break; + } + case EDisplayHalSecure: + { + kumemput32(a1, &iSecureDisplay, sizeof(TBool)); + break; + } + case EDisplayHalSetSecure: + { + __SECURE_KERNEL( + if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDisplayHalSetSecure"))) + return KErrPermissionDenied; + ) + SwitchDisplay((TBool)a1); + break; + } + default: + { + r = KErrNotSupported; + break; + } + } + return r; +} + +TInt DLcdPowerHandler::Create() +{ + __KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::Create") ); + pLcd = this; + + iPortAddr = KHwBaseClcd; + + iVideoInfo.iSizeInPixels.iWidth = KConfigLcdWidth; + iVideoInfo.iSizeInPixels.iHeight = KConfigLcdHeight; + iVideoInfo.iDisplayMode = KConfigLcdDisplayMode; + iVideoInfo.iOffsetToFirstPixel = KCOnfigOffsetToFirstPixel; + iVideoInfo.iOffsetBetweenLines = KCOnfigOffsetBetweenLines; + iVideoInfo.iIsPalettized = KConfigIsPalettized; + iVideoInfo.iBitsPerPixel = KConfigBitsPerPixel; + iVideoInfo.iSizeInTwips.iWidth = KConfigLcdWidthInTwips; + iVideoInfo.iSizeInTwips.iHeight = KConfigLcdHeightInTwips; + iVideoInfo.iIsMono = KConfigIsMono; + // !@! iVideoInfo.iVideoAddress = (TInt)pV; + iVideoInfo.iIsPixelOrderLandscape = KConfigPixelOrderLandscape; + iVideoInfo.iIsPixelOrderRGB = KConfigPixelOrderRGB; + + iSecureVideoInfo = iVideoInfo; + // !@! iSecureVideoInfo.iVideoAddress = (TInt)pV2; + + TInt r = AllocateFrameBuffer(); + if(r == KErrNone) + { + r = Kern::AddHalEntry(EHalGroupDisplay,DoHalFunction,this); + } + + if(r != KErrNone) + { + __KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::Create failed %d", r) ); + return r; + } + + iPowerUpDfc.SetDfcQ(iDfcQ); + iPowerDownDfc.SetDfcQ(iDfcQ); + iMsgQ.SetDfcQ(iDfcQ); + iMsgQ.Receive(); + + Add(); + DisplayOn(); + + return KErrNone; +} + +/** + * Register the call back function. + * Components interested in receiving notification of the Vsync interrupt should register a callback function. + */ +EXPORT_C TInt DLcdPowerHandler::RegisterCallback(TLcdUserCallBack* aCbPtr) +{ + __KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::RegisterCallBack %08x\n",aCbPtr->iCbFn) ); + + TInt irq=__SPIN_LOCK_IRQSAVE(callbackLock); + + if(aCbPtr != NULL) + { + if ( pLcd->iAppCallBk[0] == NULL ) + { + pLcd->iAppCallBk[0] = aCbPtr; + } + else + { + if((pLcd->iAppCallBk[1] == NULL) && (pLcd->iAppCallBk[0]->iCbFn != aCbPtr->iCbFn)) + { + pLcd->iAppCallBk[1] = aCbPtr; + } + else + { + __SPIN_UNLOCK_IRQRESTORE(callbackLock,irq); + return KErrInUse; + } + } + + __SPIN_UNLOCK_IRQRESTORE(callbackLock,irq); + __KTRACE_OPT(KEXTENSION ,Kern::Printf("iCbFn) ); + return KErrNone; + } + else + { + __SPIN_UNLOCK_IRQRESTORE(callbackLock,irq); + __KTRACE_OPT(KEXTENSION, Kern::Printf("Error: The supplied listener's callback is NULL")); + return KErrArgument; + } +} + + +/** + *DeRegister the call back function + */ +EXPORT_C void DLcdPowerHandler::DeRegisterCallback(TLcdUserCallBack* aCbPtr) +{ + __KTRACE_OPT(KEXTENSION ,Kern::Printf("DLcdPowerHandler::DeRegisterCallBack %08x\n ",aCbPtr->iCbFn) ); + + TInt irq=__SPIN_LOCK_IRQSAVE(callbackLock); + if(aCbPtr != NULL) + { + if( pLcd->iAppCallBk[0] != NULL) + { + if ( (pLcd->iAppCallBk[0]->iDataPtr == aCbPtr->iDataPtr) && (pLcd->iAppCallBk[0]->iCbFn == aCbPtr->iCbFn) ) + { + pLcd->iAppCallBk[0] = NULL; + } + } + + if( pLcd->iAppCallBk[1] != NULL) + { + if ( (pLcd->iAppCallBk[1]->iDataPtr == aCbPtr->iDataPtr) && (pLcd->iAppCallBk[1]->iCbFn == aCbPtr->iCbFn) ) + { + pLcd->iAppCallBk[1] = NULL; + } + } + } + __SPIN_UNLOCK_IRQRESTORE(callbackLock,irq); + __KTRACE_OPT(KEXTENSION ,Kern::Printf("iCbFn) ); +} + +/** + Constructor +*/ +DDisplayPddSyborg::DDisplayPddSyborg(): + iPendingBuffer(NULL), + iActiveBuffer(NULL), + iChunk(NULL), + iLcdCallback(NULL), + iVSyncDfc(&VSyncDfcFn, this, KVSyncDfcPriority) + { + __GCE_DEBUG_PRINT("DDisplayPddSyborg::DDisplayPddSyborg\n"); + + iPostFlag = EFalse; + } + +/** + Destructor +*/ +DDisplayPddSyborg::~DDisplayPddSyborg() + { + __GCE_DEBUG_PRINT("DDisplayPddSyborg::~DDisplayPddSyborg() \n"); + + if(iLcdCallback) + { + DLcdPowerHandler::pLcd->DeRegisterCallback(iLcdCallback) ; + delete iLcdCallback; + iLcdCallback = NULL; + } + + //The DFC Queue is owned by DLcdPowerHandler so we shouldn't call Destroy() at this point. + if (iDfcQ) + { + iDfcQ=NULL; + } + + DChunk* chunk = (DChunk*) __e32_atomic_swp_ord_ptr(&iChunk, 0); + + if(chunk) + { + Kern::ChunkClose(chunk); + } + + } + +/** + Set the Legacy Mode by setting the appropriate Frame control value. + +*/ +TInt DDisplayPddSyborg::SetLegacyMode() + { + __GCE_DEBUG_PRINT("DDisplayPddSyborg::SetLegacyMode()\n"); + + return KErrNone; + } + +/** + Set the GCE mode by posting a composition buffer. + +*/ +TInt DDisplayPddSyborg::SetGceMode() + { + __GCE_DEBUG_PRINT("DDisplayPddSyborg::SetGceMode()\n"); + + PostCompositionBuffer(&iLdd->iCompositionBuffer[0]); + return KErrNone; + } + +/** + @param aDegOfRot The requested rotation + @return KErrNone +*/ +TInt DDisplayPddSyborg::SetRotation(TInt aDegOfRot) + { + return KErrNone; + } + +/** + Remove any previous post operations, set the appropriate layer as the next layer to be displayed( This value is updated in synchronization + with V Sync so it will take affect in the next V Sync after that) and also set the buffer provided as the buffer to + be posted next. Layer 3 is associated with user buffers. + + @param aNode Pointer to the User buffer to post. +*/ +TInt DDisplayPddSyborg::PostUserBuffer(TBufferNode* aNode) + { + + __GCE_DEBUG_PRINT2("DDisplayPddSyborg::PostUserBuffer : aNode->iAddress = %08x\n", aNode->iAddress); + + if(iPendingBuffer) + { + iPendingBuffer->iState = EBufferFree; + if (!(iPendingBuffer->iType == EBufferTypeUser) ) + { + iPendingBuffer->iFree = ETrue; + } + } + + aNode->iState = EBufferPending; + iPendingBuffer = aNode; + iPostFlag = ETrue; + + // Activate the posted buffer + TUint32 physicalAddress = Epoc::LinearToPhysical( aNode->iAddress ); + WriteReg(DLcdPowerHandler::pLcd->iPortAddr, DLcdPowerHandler::FB_BASE, physicalAddress ); + /* Queue a DFC to complete the request*/ + iVSyncDfc.Enque(); + + return KErrNone; + } + +/** + Remove any previous post operations, set the appropriate layer as the next layer to be displayed( This value is updated in synchronization + with V Sync so it will take affect in the next V Sync after that) and also set the buffer provided as the buffer to + be posted next. Layer 1 and 2 are associated with composition buffers 0 and 1 respectively. + + @param aNode Pointer to the Composition buffer to post. +*/ +TInt DDisplayPddSyborg::PostCompositionBuffer(TBufferNode* aNode) + { + + __GCE_DEBUG_PRINT2("DDisplayPddSyborg::PostCompositionBuffer : aNode->iAddress = %08x\n", aNode->iAddress); + + if(iPendingBuffer) + { + iPendingBuffer->iState = EBufferFree; + if (iPendingBuffer->iType == EBufferTypeUser) + { + RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrCancel); + } + else + { + iPendingBuffer->iFree = ETrue; + } + } + aNode->iState = EBufferPending; + aNode->iFree = EFalse; + iPendingBuffer = aNode; + iPostFlag = ETrue; + + // Activate the posted buffer + TUint32 physicalAddress = Epoc::LinearToPhysical( aNode->iAddress ); + WriteReg(DLcdPowerHandler::pLcd->iPortAddr, DLcdPowerHandler::FB_BASE, physicalAddress ); + + /* Queue a DFC to complete the request*/ + iVSyncDfc.Enque(); + + return KErrNone; + } + +/** + Remove any previous post operations, set the appropriate layer as the next layer to be displayed( This value is updated in synchronization + with V Sync so it will take affect in the next V Sync after that) and also set the Legacy Buffer as the buffer to + be posted next.Layer 0 is associated with legacy buffer. + + @param aNode Pointer to the Composition buffer to post. +*/ +TInt DDisplayPddSyborg::PostLegacyBuffer() + { + __GCE_DEBUG_PRINT("DDisplayPddSyborg::PostLegacyBuffer() \n"); + + if(iPendingBuffer) + { + iPendingBuffer->iState = EBufferFree; + if (iPendingBuffer->iType == EBufferTypeUser) + { + + RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrCancel); + } + else + { + iPendingBuffer->iFree = ETrue; + } + } + + + iLdd->iLegacyBuffer[0].iState = EBufferPending; + iLdd->iLegacyBuffer[0].iFree = EFalse; + iPendingBuffer = &iLdd->iLegacyBuffer[0]; + iPostFlag = ETrue; + + // Activate the posted buffer + WriteReg(DLcdPowerHandler::pLcd->iPortAddr, DLcdPowerHandler::FB_BASE, TSyborg::VideoRamPhys() ); + + /* Queue a DFC to complete the request*/ + iVSyncDfc.Enque(); + + return KErrNone; + } + +/** + Handles device specific operations when a close message has been sent to the Logical Channel. + +*/ +TInt DDisplayPddSyborg::CloseMsg() + { + __GCE_DEBUG_PRINT("DDisplayPddSyborg::CloseMsg()\n"); + + iPendingBuffer = NULL; + iActiveBuffer = NULL; + + iVSyncDfc.Cancel(); + return KErrNone; + } + +/** + Called by the LDD's DoCreate function to handle the device specific part of opening the channel. + (DoCreate is called by RDisplayChannel::Open) + + @param aUnit The screen unit + + @return KErrNone if successful; or one of the other system wide error codes. +*/ +TInt DDisplayPddSyborg::CreateChannelSetup(TInt aUnit) + { + __GCE_DEBUG_PRINT("DDisplayPddSyborg::CreateChannelSetup\n"); + + iScreenInfo = DLcdPowerHandler::pLcd->iVideoInfo; + iLdd->iUnit = aUnit; + + iLdd->iDisplayInfo.iAvailableRotations = RDisplayChannel::ERotationNormal; + iLdd->iDisplayInfo.iNormal.iOffsetBetweenLines = iScreenInfo.iOffsetBetweenLines; + iLdd->iDisplayInfo.iNormal.iHeight = iScreenInfo.iSizeInPixels.iHeight; + iLdd->iDisplayInfo.iNormal.iWidth = iScreenInfo.iSizeInPixels.iWidth; + iLdd->iDisplayInfo.iNumCompositionBuffers = KDisplayCBMax; + iLdd->iDisplayInfo.iBitsPerPixel = iScreenInfo.iBitsPerPixel; + iLdd->iDisplayInfo.iRefreshRateHz = 60; + + + switch (iScreenInfo.iBitsPerPixel) + { + case 16: + iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatRGB_565; + break; + case 24: + iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatRGB_888; + break; + case 32: + iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatARGB_8888; + break; + default: + iLdd->iDisplayInfo.iPixelFormat = EUidPixelFormatUnknown; + break; + } + + iLdd->iCurrentRotation = RDisplayChannel::ERotationNormal; + + // Open shared chunk to the composition framebuffer + + DChunk* chunk = 0; + TLinAddr chunkKernelAddr = 0; + TUint32 chunkMapAttr = 0; + + // round to twice the page size + TUint round = 2*Kern::RoundToPageSize(DLcdPowerHandler::pLcd->iSize); + + __GCE_DEBUG_PRINT2("DDisplayPddSyborg::CreateChannelSetup DLcdPowerHandler::pLcd->iSize = %d\n", DLcdPowerHandler::pLcd->iSize ); + + TChunkCreateInfo info; + info.iType = TChunkCreateInfo::ESharedKernelMultiple; + info.iMaxSize = round; + info.iMapAttr = EMapAttrFullyBlocking; + info.iOwnsMemory = EFalse; + info.iDestroyedDfc = 0; + + TInt r = Kern::ChunkCreate(info, chunk, chunkKernelAddr, chunkMapAttr); + + __GCE_DEBUG_PRINT2("CreateChannelSetup:ChunkCreate called for composition chunk. Set iChunkKernelAddr = %08x\n", chunkKernelAddr ); + + if( r == KErrNone) + { + // map our chunk + r = Kern::ChunkCommitPhysical(chunk, 0,round , DLcdPowerHandler::pLcd->iCompositionPhysical); + __GCE_DEBUG_PRINT2("Mapping chunk %d", r); + if(r != KErrNone) + { + Kern::ChunkClose(chunk); + } + } + + if ( r!= KErrNone) + { + return r; + } + + iChunk = chunk; + + // init CB 0 + iLdd->iCompositionBuffer[0].iType = EBufferTypeComposition; + iLdd->iCompositionBuffer[0].iBufferId = 0; + iLdd->iCompositionBuffer[0].iFree = ETrue; + iLdd->iCompositionBuffer[0].iState = EBufferFree; + iLdd->iCompositionBuffer[0].iAddress = chunkKernelAddr; + iLdd->iCompositionBuffer[0].iPhysicalAddress = Epoc::LinearToPhysical(chunkKernelAddr); + iLdd->iCompositionBuffer[0].iChunk = chunk; + iLdd->iCompositionBuffer[0].iHandle = 0; + iLdd->iCompositionBuffer[0].iOffset = 0; + iLdd->iCompositionBuffer[0].iSize = DLcdPowerHandler::pLcd->iSize; + iLdd->iCompositionBuffer[0].iPendingRequest = 0; + + // init CB 1 + iLdd->iCompositionBuffer[1].iType = EBufferTypeComposition; + iLdd->iCompositionBuffer[1].iBufferId = 1; + iLdd->iCompositionBuffer[1].iFree = ETrue; + iLdd->iCompositionBuffer[1].iState = EBufferFree; + iLdd->iCompositionBuffer[1].iAddress = chunkKernelAddr + DLcdPowerHandler::pLcd->iSize; + iLdd->iCompositionBuffer[1].iPhysicalAddress = Epoc::LinearToPhysical(chunkKernelAddr + DLcdPowerHandler::pLcd->iSize); + iLdd->iCompositionBuffer[1].iChunk = chunk; + iLdd->iCompositionBuffer[1].iHandle = 0; + iLdd->iCompositionBuffer[1].iOffset = DLcdPowerHandler::pLcd->iSize; + iLdd->iCompositionBuffer[1].iSize = DLcdPowerHandler::pLcd->iSize; + iLdd->iCompositionBuffer[1].iPendingRequest = 0; + + iLdd->iCompositionBuffIdx = 0; + //Use the same DFC queue created by the DLcdPowerHandler so all hardware accesses are executed under the same DFC thread. + iDfcQ= DLcdPowerHandler::pLcd->iDfcQ; + + // Set the Post DFC. + iVSyncDfc.SetDfcQ(iDfcQ); + + + return KErrNone; + } + +/** +Detect whether a post operation is pending +*/ +TBool DDisplayPddSyborg::PostPending() + { + return (iPendingBuffer != NULL); + } + +/** + Return the DFC queue to be used for this device. + */ +TDfcQue * DDisplayPddSyborg::DfcQ(TInt aUnit) + { + return iDfcQ; + } + +void DDisplayPddSyborg::VSyncDfcFn(TAny* aChannel) + { + DDisplayPddSyborg * channel =(DDisplayPddSyborg*)aChannel; + + if (channel->iPostFlag) + { + channel->iPostFlag = EFalse; + + if (channel->iActiveBuffer) + { + //When a User buffer is registered its iFree member becomes EFalse and Deregister sets it + //back to ETrue. Composition and Legacy buffers are not free when they are in the pending or + //active state. + if (channel->iActiveBuffer->iType == EBufferTypeUser) + { + channel->RequestComplete(RDisplayChannel::EReqPostUserBuffer, KErrNone); + } + else + { + channel->iActiveBuffer->iFree = ETrue; + } + + channel->iActiveBuffer->iState = EBufferFree; + + + //If no buffer was available during a call to GetCompositionBuffer the active buffer has + //been returned as the next available one, so we must set the buffer to the proper state before we + //send the notification. + if(channel->iLdd->iPendingReq[RDisplayChannel::EReqGetCompositionBuffer].iStatus) + { + channel->iActiveBuffer->iState = EBufferCompose; + channel->RequestComplete(RDisplayChannel::EReqGetCompositionBuffer, KErrNone); + + } + + channel->iActiveBuffer = NULL; + } + + if (channel->iPendingBuffer) + { + __GCE_DEBUG_PRINT2("DDisplayPddSyborg::VSyncDfcFn moving pending buffer at address %08x to the active state\n", channel->iPendingBuffer->iAddress); + channel->iActiveBuffer = channel->iPendingBuffer; + channel->iActiveBuffer->iState = EBufferActive; + channel->iPendingBuffer = NULL; + + channel->RequestComplete(RDisplayChannel::EReqWaitForPost, KErrNone); + } + } + } +//***************************************************************** +//DDisplayPddFactory +//*****************************************************************/ + + +/** + Constructor +*/ +DDisplayPddFactory::DDisplayPddFactory() + { + __GCE_DEBUG_PRINT("DDisplayPddFactory::DDisplayPddFactory()\n"); + + iVersion = TVersion(KDisplayChMajorVersionNumber, + KDisplayChMinorVersionNumber, + KDisplayChBuildVersionNumber); + } + +/** + PDD factory function. Creates a PDD object. + + @param aChannel A pointer to an PDD channel object which will be initialised on return. + + @return KErrNone if object successfully allocated, KErrNoMemory if not. +*/ +TInt DDisplayPddFactory::Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer) + { + DDisplayPddSyborg *device= new DDisplayPddSyborg() ; + aChannel=device; + if (!device) + { + return KErrNoMemory; + } + return KErrNone; + } + + +/** + Set the Pdd name and return error code +*/ +TInt DDisplayPddFactory::Install() + { + __GCE_DEBUG_PRINT("DDisplayPddFactory::Install() \n"); + + TBuf<32> name(RDisplayChannel::Name()); + _LIT(KPddExtension,".pdd"); + name.Append(KPddExtension); + return SetName(&name); + } + + +void DDisplayPddFactory::GetCaps(TDes8& /*aDes*/) const + { + //Not supported + } + + +/** + Validate version and number of units. +*/ +TInt DDisplayPddFactory::Validate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& aVer) + { + if (!Kern::QueryVersionSupported(iVersion,aVer)) + { + return KErrNotSupported; + } + + if (aUnit != 0) + { + return KErrNotSupported; + } + + return KErrNone; + } + +DECLARE_EXTENSION_PDD() +/** + "Standard PDD" entrypoint.Creates PDD factory when Kern::InstallPhysicalDevice is called + + @return pointer to the PDD factory object. +*/ + { + __GCE_DEBUG_PRINT("DECLARE_EXTENSION_PDD()\n"); + return new DDisplayPddFactory ; + } + + +DECLARE_STANDARD_EXTENSION() +{ + TInt r = KErrNoMemory; + DLcdPowerHandler* pH=new DLcdPowerHandler; + if(pH) + { + r = pH->Create(); + if ( r == KErrNone) + { + pH->iDfcQ = Kern::DfcQue0(); // use low priority DFC queue for this driver + + 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; +} diff -r 2925e6e5efd7 -r 33dfab4ab0fc baseport/syborg/svpframebuffer/svpframebuffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/baseport/syborg/svpframebuffer/svpframebuffer.h Wed Jan 27 14:42:12 2010 +0000 @@ -0,0 +1,297 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Minimalistic frame buffer driver +* +*/ + +#ifndef _SVPFRAMEBUFFER_H +#define _SVPFRAMEBUFFER_H + +#include + +#include +#include + +#define __SVPFRAMEBUFFER_DEBUG + +#ifdef __SVPFRAMEBUFFER_DEBUG + +#define __GCE_DEBUG_PRINT(a) Kern::Printf(a) +#define __GCE_DEBUG_PRINT2(a,b) Kern::Printf(a,b) + +#else + +#define __GCE_DEBUG_PRINT(a) +#define __GCE_DEBUG_PRINT2(a,b) + +#endif + +// Macro to calculate the screen buffer size +// aBpp is the number of bits-per-pixel, aPpl is the number of pixels per line and aLpp number of lines per panel +#define FRAME_BUFFER_SIZE(aBpp,aPpl,aLpp) ((aBpp/8)*aPpl*aLpp) + +_LIT(KLitLcd,"SYBORG_FB"); + +const TUint KConfigLcdWidth = 640; +const TUint KConfigLcdHeight = 480; +const TInt KConfigLcdWidthInTwips = 9638; +const TInt KConfigLcdHeightInTwips = 7370; +const TBool KConfigIsMono = 0; +const TBool KConfigIsPalettized = 0; +const TInt KCOnfigOffsetToFirstPixel = 0; +const TBool KConfigPixelOrderRGB = 0; +const TBool KConfigPixelOrderLandscape = 1; +const TInt KConfigLcdDisplayMode = 2; +//const TInt KConfigLcdDisplayMode = 1; +const TInt KConfigLcdNumberOfDisplayModes = 3; + + +const TInt KConfigBitsPerPixel = 24; +const TInt KCOnfigOffsetBetweenLines = 2560; + +const TInt KVSyncDfcPriority = 7 ; //priority of DFC within the queue (0 to 7, where 7 is highest) + +/********************************************************************/ +/* Class Definition */ +/********************************************************************/ +/** + * This class defines a callback mechanism that is used by a resource user to specify its callback. It contains a + * function pointer and data pointer. The function pointer specifies the user callback function to be invoked by the + * resource while the data pointer specifies the data to be passed to the callback function. + */ +class TLcdUserCallBack + { +public: + // The constructor for the callback mechanism. + TLcdUserCallBack(TInt (*aFunction)(TUint aResID, TAny* aPtr), TAny* aPtr) + + { + iCbFn = aFunction; + iDataPtr = aPtr; + } + +public: + // The callback function pointer. + TInt (*iCbFn)(TUint aResID, TAny* aPtr); + + // Pointer to the data structure to be passed to the callback function. + TAny *iDataPtr; + }; + +class DLcdPowerHandler : public DPowerHandler +{ +public: // from DPowerHandler + void PowerDown(TPowerState); + void PowerUp(); +public: // to prevent a race condition with WServer trying to power up/down at the same time + void PowerUpDfc(); + void PowerDownDfc(); +public: + DLcdPowerHandler(); + TInt Create(); + void DisplayOn(); + void DisplayOff(); + TInt HalFunction(TInt aFunction, TAny* a1, TAny* a2); + + void PowerUpLcd(TBool aSecure); + void PowerDownLcd(); + + void ScreenInfo(TScreenInfoV01& aInfo); + void WsSwitchOnScreen(); + void WsSwitchOffScreen(); + void HandleMsg(TMessageBase* aMsg); + void SwitchDisplay(TBool aSecure); + +private: + TInt GetCurrentDisplayModeInfo(TVideoInfoV01& aInfo, TBool aSecure); + TInt GetSpecifiedDisplayModeInfo(TInt aMode, TVideoInfoV01& aInfo); + TInt SetDisplayMode(TInt aMode); + TInt AllocateFrameBuffer(); + +public: + IMPORT_C static TInt RegisterCallback(TLcdUserCallBack* aCbPtr); + IMPORT_C static void DeRegisterCallback(TLcdUserCallBack* aCbPtr); + +private: + TBool iDisplayOn; + DPlatChunkHw* iChunk; + DPlatChunkHw* iSecureChunk; + TBool iWsSwitchOnScreen; + TBool iSecureDisplay; + +public: + TDfcQue* iDfcQ; + TMessageQue iMsgQ; // to prevent a race condition with Power Manager trying to power up/down at the same time + TDfc iPowerUpDfc; + TDfc iPowerDownDfc; + +private: + NFastMutex iLock; + TPhysAddr ivRamPhys; + TPhysAddr iSecurevRamPhys; + TLcdUserCallBack * iAppCallBk[2]; + +public: + TVideoInfoV01 iVideoInfo; + TVideoInfoV01 iSecureVideoInfo; + TInt iSize; + TLinAddr iPortAddr; + TPhysAddr iCompositionPhysical; + static DLcdPowerHandler * pLcd; + +enum { + FB_ID = 0, + FB_BASE = 1, + FB_HEIGHT = 2, + FB_WIDTH = 3, + FB_ORIENTATION = 4, + FB_BLANK = 5, + FB_INT_MASK = 6, + /* begin new interface */ + FB_INTERRUPT_CAUSE = 7, + FB_BPP = 8, + FB_COLOR_ORDER = 9, + FB_BYTE_ORDER = 10, + FB_PIXEL_ORDER = 11, + FB_ROW_PITCH = 12, + FB_ENABLED = 13, + FB_PALETTE_START = 0x400 >> 2, + FB_PALETTE_END = FB_PALETTE_START+256-1, + /* end new interface */ + }; + +#define FB_INT_VSYNC (1U << 0) +#define FB_INT_BASE_UPDATE_DONE (1U << 1) + +}; + +class DDisplayPddSyborg : public DDisplayPdd + { + + public: + DDisplayPddSyborg(); + ~DDisplayPddSyborg(); + + /** + Called by the LDD to handle the device specific part of switching to Legacy mode. + + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt SetLegacyMode(); + + /** + Called by the LDD to handle the device specific part of switching to GCE mode. + + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt SetGceMode(); + + /** + Called by the LDD to handle the device specific part of setting the rotation. + + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt SetRotation(TInt aRotation); + + /** + Called by the LDD to handle the device specific part of posting a User Buffer. + + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt PostUserBuffer(TBufferNode* aNode); + + /** + Called by the LDD to handle the device specific part of posting a Composition Buffer + + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt PostCompositionBuffer(TBufferNode* aNode); + + /** + Called by the LDD to handle the device specific part of posting the Legacy Buffuer + + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt PostLegacyBuffer(); + + /** + Called by the LDD to handle device specific cleanup operations when a channel is closed. + + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt CloseMsg(); + + /** + Called by the LDD to handle device specific initialisation tasks when a channel is opened. + + @param aUnit The screen/hardware unit number. + @return KErrNone if successful; or one of the other system wide error codes. + */ + virtual TInt CreateChannelSetup(TInt aUnit); + + /** + Called by the LDD in order to detect whether a post operation is pending. This type of + information is specific to the actual physical device. + + @return ETrue if a Post operation is pending otherwise EFalse. + */ + virtual TBool PostPending(); + + /** + Called by the LDD to retrieve the DFC Queue created in the PDD. + + @param aUnit The screen/hardware unit number. + @return A pointer to the TDfcQue object created in the PDD. + */ + virtual TDfcQue* DfcQ(TInt aUnit); + +public: + static void VSyncDfcFn(TAny* aChannel); + +private: + TDfcQue* iDfcQ; + + //generic display info + TVideoInfoV01 iScreenInfo; + + //Pointer to a buffer in the Pending state + TBufferNode* iPendingBuffer; + + //Pointer to a buffer in the Active state + TBufferNode* iActiveBuffer; + + DChunk * iChunk; + TLcdUserCallBack* iLcdCallback; + + public: + TDfc iVSyncDfc; + }; + + +/** + PDD Factory class + */ + +class DDisplayPddFactory : public DPhysicalDevice + { +public: + DDisplayPddFactory(); + + virtual TInt Install(); + virtual void GetCaps(TDes8& aDes) const; + virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); + virtual TInt Validate(TInt aDeviceType, const TDesC8* anInfo, const TVersion& aVer); + }; + +#endif diff -r 2925e6e5efd7 -r 33dfab4ab0fc baseport/syborg/svpframebuffer/svpframebuffer.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/baseport/syborg/svpframebuffer/svpframebuffer.mmp Wed Jan 27 14:42:12 2010 +0000 @@ -0,0 +1,40 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include +#include "kernel/kern_ext.mmh" + +TARGET VariantTarget(svpframebuffer,dll) +TARGETTYPE kext + +SYMBIAN_BASE_SYSTEMINCLUDE(drivers) +SYSTEMINCLUDE AsspNKernIncludePath +SYSTEMINCLUDE . + +SOURCEPATH . +SOURCE svpframebuffer.cpp + +LIBRARY PlatformLib + +EPOCALLOWDLLDATA + +UID 0x1000008d 0x100039e8 +VENDORID 0x70000001 + +ROMTARGET lcd.dll + +CAPABILITY all