diff -r 000000000000 -r 4e1aa6a622a0 accessoryservices/pluggeddisplay/pluggeddisplayengine/src/edidhandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/accessoryservices/pluggeddisplay/pluggeddisplayengine/src/edidhandler.cpp Tue Feb 02 00:53:00 2010 +0200 @@ -0,0 +1,1397 @@ +/* + * 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 "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: EDID data Handler class for HDMI Cable Status FSM. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pdeconstants.h" +#include "tvoutconfigforhdmi.h" +#include "edidhandler.h" +#include "edidparserbase.h" +#include "cea861edidparser.h" +#include "multifinitestatemachine.h" +#include "trace.h" +#include "traceediddata.h" + +const TReal K16d9 = 1.778; +const TReal K4d3 = 1.333; + +const TInt KDefaultCEAMode = E640x480p59_94d60Hz4d3; +const TInt KDefaultCEAModeIndex = 0; + +// Retry Delay for EDID access +const TInt KRetryDelay = 50 * 1000; // 50 milliseconds + +// Maximum retry count for EDID access +const TInt KMaxRetryCount = 40; // 40 * 50ms = 2 Seconds + +const TUint16 KDefaultCEAModePhysImgAspRatioNr = 4; + +const TUint16 KDefaultCEAModePhysImgAspRatioDr = 3; + +//------------------------------------------------------------------------------ +// Symbian two-phased constructor +//------------------------------------------------------------------------------ +// +CEDIDHandler* CEDIDHandler::NewL( MFSMForBody& aFSM, + CTVOutConfigForHDMI& aTVOutConfigForHDMI ) + { + FUNC_LOG; + CEDIDHandler* self = new ( ELeave ) CEDIDHandler( + aFSM, aTVOutConfigForHDMI ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +//------------------------------------------------------------------------------ +// Destructor +//------------------------------------------------------------------------------ +// +CEDIDHandler::~CEDIDHandler() + { + FUNC_LOG; + + Cancel(); + delete iDdcPortAccess; + delete iDataBlockPtr; + delete iExtensionParserPtr; + delete iEdidParserPtr; + iRetryTimer.Close(); + } + +//------------------------------------------------------------------------------ +// FetchEDIDData +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::FetchEDIDData() + { + FUNC_LOG; + + TInt retVal( KErrNone ); + TUint apiVersion = iDdcPortAccess->ApiVersion(); + if( KDdcAccessVersion != apiVersion ) + { + INFO_1( "iDdcPortAccess->ApiVersion() returned unsupported version != KDdcAccessVersion: %d", apiVersion ); + retVal = KErrNotSupported; + } + else + { + iRetryCounter = KErrNone; + TInt err = KErrNone; + TRAP( retVal , err = ReadEDIDDataL() ); + if ( err != KErrNone ) + { + retVal = err; + } + } + INFO_1( "CEDIDHandler::FetchEDIDData() retVal: %d", retVal ); + return retVal; + } + +//------------------------------------------------------------------------------ +// SetVideoParameters +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::SetVideoParameters() + { + FUNC_LOG; + + TInt retVal = KErrNone; + RArray analogConfigs; + RArray hdmiConfigs; + + // Update overscan values from cenrep + UpdateOverscanValues(); + + // Set video parameters + INFO( "--------------------------------------------------------------------" ); + INFO( "SETTING CEA AND DMT TIMINGS:" ); + retVal = SetCeaModes( hdmiConfigs ); + ERROR( retVal, "Failed to set CEA modes" ); + + if( KErrNone == retVal ) + { + retVal = SetDmtModes( hdmiConfigs ); + ERROR( retVal, "Failed to set DMT modes" ); + INFO( "--------------------------------------------------------------------" ); + + if( KErrNone == retVal ) + { + // Filtering out the unsupported modes + // Logical AND(Sink supported modes AND HW supported modes) + INFO( "Filtering out the unsupported modes" ); + retVal = FilterAvailableTvConfigList( hdmiConfigs ); + ERROR( retVal, "Failed to filter the TV config list." ); + + if( KErrNone == retVal ) + { + retVal = iTVOutConfigForHDMI.SetAvailableTvConfigList( analogConfigs, hdmiConfigs ); + ERROR( retVal, "Failed to set available TV config list." ); + } + } + } + + // Clean up + hdmiConfigs.Close(); + analogConfigs.Close(); + + return retVal; + } + +//------------------------------------------------------------------------------ +// GetEDIDDataL +//------------------------------------------------------------------------------ +// +void CEDIDHandler::ResetData() + { + FUNC_LOG; + + delete iDataBlockPtr; + iDataBlockPtr = NULL; + delete iEdidParserPtr; + iEdidParserPtr = NULL; + delete iExtensionParserPtr; + iExtensionParserPtr = NULL; + } + +//------------------------------------------------------------------------------ +// CreateHdmiSinkL +//------------------------------------------------------------------------------ +// +CAccPolHdmiSink* CEDIDHandler::CreateHdmiSinkL() + { + FUNC_LOG; + + CAccPolHdmiSink* hdmiSink( NULL ); + if( iExtensionParserPtr && iTVOutConfigForHDMI.GetTvOutConfig() ) + { + hdmiSink = CAccPolHdmiSink::NewL( + iExtensionParserPtr->BasicAudio(), + iTVOutConfigForHDMI.GetTvOutConfig()->CopyProtectionStatus() ); + } + else + { + User::Leave( KErrNotFound ); + } + + return hdmiSink; + } + +//------------------------------------------------------------------------------ +// CreateHdmiVideoFormatL +//------------------------------------------------------------------------------ +// +void CEDIDHandler::CreateHdmiVideoFormatL( RAccPolHdmiVideoFormatArray& aHdmiVideoFormatArray ) + { + FUNC_LOG; + + // Active Video Format object values can be fetched from TvOutConfig interface. + if( iEdidParserPtr && iTVOutConfigForHDMI.GetTvOutConfig() ) + { + THdmiDviTimings hdmiDviTimings; + TInt retVal = iTVOutConfigForHDMI.GetTvOutConfig()->GetConfig( + hdmiDviTimings ); + if( KErrNone == retVal ) + { + CAccPolHdmiVideoFormat* hdmiVideoFormat = CAccPolHdmiVideoFormat::NewLC(); + hdmiVideoFormat->SetCeaFixedMode( hdmiDviTimings.iCeaMode ); + hdmiVideoFormat->SetDmtFixedMode( EDmtFixedModeNone ); + hdmiVideoFormat->SetPixelRepeat( hdmiDviTimings.iPixelRepeat ); + hdmiVideoFormat->SetInterlaced( hdmiDviTimings.iInterlaced ); + aHdmiVideoFormatArray.AppendL( hdmiVideoFormat ); + CleanupStack::Pop( hdmiVideoFormat ); + } + else + { + User::Leave( retVal ); + } + } + else + { + User::Leave( KErrNotFound ); + } + } + +//------------------------------------------------------------------------------ +// CreateHdmiLatencyL +//------------------------------------------------------------------------------ +// +void CEDIDHandler::CreateHdmiLatencyL( RAccPolHdmiLatencyArray& aHdmiLatencyArray ) + { + FUNC_LOG; + + if( iEdidParserPtr && iExtensionParserPtr ) + { + // Interlaced audio and video latency + CAccPolHdmiLatency* hdmiLatency = CAccPolHdmiLatency::NewLC( + HdmiLatency::KUidInterlacedLatency, + iExtensionParserPtr->GetInterlacedAudioLatency(), + iExtensionParserPtr->GetInterlacedVideoLatency() ); + aHdmiLatencyArray.AppendL( hdmiLatency ); + CleanupStack::Pop( hdmiLatency ); + + // Progressive audio and video latency + hdmiLatency = CAccPolHdmiLatency::NewLC( + HdmiLatency::KUidLatency, + iExtensionParserPtr->GetAudioLatency(), + iExtensionParserPtr->GetVideoLatency() ); + aHdmiLatencyArray.AppendL( hdmiLatency ); + CleanupStack::Pop( hdmiLatency ); + } + else + { + User::Leave( KErrNotFound ); + } + } + +//------------------------------------------------------------------------------ +// CreateHdmiAudioFormatL +//------------------------------------------------------------------------------ +// +void CEDIDHandler::CreateHdmiAudioFormatL( RAccPolHdmiAudioFormatArray& aHdmiAudioFormatArray ) + { + FUNC_LOG; + + if( iExtensionParserPtr ) + { + if( iExtensionParserPtr->IsAudioDataBlockSupported() ) + { + TCEA861AudioDataBlock + * audioDataBlock = + iExtensionParserPtr->GetParsedInformation()->iShortAudioDescriptors; + while( audioDataBlock ) + { + CAccPolHdmiAudioFormat* hdmiAudioFormat = + CAccPolHdmiAudioFormat::NewL(); + CleanupStack::PushL( hdmiAudioFormat ); + + // Set audio format + TUid audioFormat; + audioFormat.iUid = audioDataBlock->iAudioFormatCode; + hdmiAudioFormat->SetAudioFormat( audioFormat ); // const TUid aAudioFormat, + + // Set bit resolution + TUint32 bitResolution( CAccPolHdmiAudioFormat::EUnknownBitsPerSample ); + if( audioDataBlock->iSupport24Bit ) + { + bitResolution |= CAccPolHdmiAudioFormat::EBitsPerSample24; + } + if( audioDataBlock->iSupport20Bit ) + { + bitResolution |= CAccPolHdmiAudioFormat::EBitsPerSample20; + } + if( audioDataBlock->iSupport16Bit ) + { + bitResolution |= CAccPolHdmiAudioFormat::EBitsPerSample16; + } + hdmiAudioFormat->SetBitResolution( bitResolution ); // const TUint32 aBitResolution, + hdmiAudioFormat->SetMaxBitResolution( audioDataBlock->iMaxBitrate ); // const TUint32 aMaxBitResolution, + hdmiAudioFormat->SetChannelCount( audioDataBlock->iMaxChannels ); // const TUint32 aMaxChannelCount, + + // Set sample frequency + TUint32 samFreq( CAccPolHdmiAudioFormat::EUnknownFrequency ); + if( audioDataBlock->iSupport192kHz ) + { + samFreq + |= CAccPolHdmiAudioFormat::ESamplingFreq192KHz; + } + if( audioDataBlock->iSupport176kHz ) + { + samFreq + |= CAccPolHdmiAudioFormat::ESamplingFreq176KHz; + } + if( audioDataBlock->iSupport96kHz ) + { + samFreq + |= CAccPolHdmiAudioFormat::ESamplingFreq96KHz; + } + if( audioDataBlock->iSupport88kHz ) + { + samFreq + |= CAccPolHdmiAudioFormat::ESamplingFreq88KHz; + } + if( audioDataBlock->iSupport48kHz ) + { + samFreq + |= CAccPolHdmiAudioFormat::ESamplingFreq48KHz; + } + if( audioDataBlock->iSupport44kHz ) + { + samFreq + |= CAccPolHdmiAudioFormat::ESamplingFreq44KHz; + } + if( audioDataBlock->iSupport32kHz ) + { + samFreq + |= CAccPolHdmiAudioFormat::ESamplingFreq32KHz; + } + hdmiAudioFormat->SetSamFreq( samFreq ); // const TUint32 aSamFreq, + hdmiAudioFormat->SetFormatDependentValue( audioDataBlock->iAudioFormatCodeExtension ); // const TUint32 aFormatDependentValue + aHdmiAudioFormatArray.AppendL( hdmiAudioFormat ); + CleanupStack::Pop( hdmiAudioFormat ); + + audioDataBlock = audioDataBlock->iNext; + } + } + } + else + { + User::Leave( KErrNotFound ); + } + } + +//------------------------------------------------------------------------------ +// CreateHdmiAudioFormatL +//------------------------------------------------------------------------------ +// +CAccPolHdmiSpeakerAllocation* CEDIDHandler::CreateHdmiSpeakerAllocationL() + { + FUNC_LOG; + + CAccPolHdmiSpeakerAllocation* hdmiSpeakerAllocation( NULL ); + if( iExtensionParserPtr ) + { + if( iExtensionParserPtr->IsSpeakerAllocationDataBlockSupported() ) + { + TCEA861SpeakerAllocationData + * speakerAllocationData = + &( iExtensionParserPtr->GetParsedInformation()->iSpeakerAllocationData ); + if( speakerAllocationData ) + { + hdmiSpeakerAllocation + = CAccPolHdmiSpeakerAllocation::NewL( speakerAllocationData->FL_FR(), //const TBool aFrontSpeakers, + speakerAllocationData->RL_RR(), //const TBool aRearSpeakers, + speakerAllocationData->LFE(), //const TBool aLowFrequencyEffect, + speakerAllocationData->FC(), //const TBool aFrontCenter, + speakerAllocationData->FCH(), //const TBool aFrontCenterHigh, + speakerAllocationData->TC(), //const TBool aTopCenter, + speakerAllocationData->RC(), //const TBool aRearCenter, + speakerAllocationData->FLC_FRC(), //const TBool aFrontLeftRightCenter, + speakerAllocationData->RLC_RRC(), //const TBool aRearLeftRightCenter, + speakerAllocationData->FLW_FRW(), //const TBool aFrontWideSpeakers, + speakerAllocationData->FLH_FRH() //const TBool aFrontHighSpeakers + ); + } + } + } + else + { + User::Leave( KErrNotFound ); + } + return hdmiSpeakerAllocation; + } + +//------------------------------------------------------------------------------ +// GetHdcpSupportStatus +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::GetHdcpSupportStatus( TBool& aHdcpSupportStatus ) const + { + FUNC_LOG; + + TInt retVal( KErrNone ); + if( iTVOutConfigForHDMI.GetTvOutConfig() ) + { + aHdcpSupportStatus + = ( iTVOutConfigForHDMI.GetTvOutConfig() )->CopyProtectionStatus(); + } + else + { + retVal = KErrNotFound; + } + return retVal; + } + +//------------------------------------------------------------------------------ +// RunL +//------------------------------------------------------------------------------ +// +void CEDIDHandler::RunL() + { + + FUNC_LOG; + + switch ( iRequestID ) + { + case EDdcReadRequest: + { + if( KErrNone == iStatus.Int() ) + { + TPtrC8 + dataBlockDes( iDataBlockPtr->iDataBlock, sizeof( *iDataBlockPtr ) ); + iEdidParserPtr = CEdidParserBase::NewL( dataBlockDes ); + TInt nbrOfExtensions = iEdidParserPtr->GetNumberOfExtensions(); + for( TInt i = 0; i < nbrOfExtensions; ++i ) + { + if( ECea861Ext == iEdidParserPtr->GetExtensionType( i + 1 ) ) + { + INFO_1( "ECea861Ext extension data block number: %d", ( i+1 ) ); + iExtensionParserPtr + = iEdidParserPtr->CreateCea861ExtensionParserL( i + 1 ); + break; + } + } + INFO_1( "Data block count in nbrOfExtensions: %d", nbrOfExtensions ); + iFSM.Input( EPDEIfEDIDHandler, EPDEIfEDIDHandlerEventEdidDataFetched ); + iRetryCounter = KErrNone; + } + else + { + INFO_1( "CDdcPortAccess::Read failed, error code: %d", iStatus.Int() ); + + if( (iStatus.Int() == KErrNotReady) && (iRetryCounter < KMaxRetryCount) ) + { + iRetryCounter++; + iRequestID = ERetryTimerRequest; + iRetryTimer.After( iStatus, KRetryDelay ); + SetActive(); + } + else + { + iRetryCounter = KErrNone; + iFSM.Input( EPDEIfEDIDHandler, + EPDEIfEDIDHandlerEventEdidDataFetchFailed ); + } + } + break; + } + case ERetryTimerRequest: + { + INFO_1( "Retrying... count: %d", iRetryCounter ); + if( ReadEDIDDataL() != KErrNone ) + { + iFSM.Input( EPDEIfEDIDHandler, EPDEIfEDIDHandlerEventEdidDataFetchFailed ); + } + break; + } + default: + { + INFO_1( "Undefined Request ID %d", iRequestID ); + break; + } + } + } + +//------------------------------------------------------------------------------ +// From class CActive. +// RunL +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::RunError( TInt aError ) + { + FUNC_LOG; + + /*TInt err( aError ); + // Avoid Panic in CActiveScheduler + if ( err ) + { + INFO_1( "aError %d", err ); + }*/ + iFSM.Input( EPDEIfEDIDHandler, EPDEIfEDIDHandlerEventEdidDataFetchFailed ); + + return KErrNone; + } + +//------------------------------------------------------------------------------- +// DoCancel +// +//------------------------------------------------------------------------------- +// +void CEDIDHandler::DoCancel() + { + FUNC_LOG; + + iDdcPortAccess->CancelAll(); + } + +//------------------------------------------------------------------------------ +// ReadEDIDDataL +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::ReadEDIDDataL() + { + FUNC_LOG; + + TInt retVal( KErrNone ); + + iRequestID = EDdcReadRequest; + + if( iDataBlockPtr == NULL ) + { + iDataBlockPtr = new(ELeave) TDataBlock; + } + + retVal = iDdcPortAccess->Read( EMonitorPort, 0, // First block contains EDID data if that exists + iDataBlockPtr->iDataBlock, + iStatus ); + + SetActive(); + + ERROR(retVal, "iDdcPortAccess->Read failed" ); + + return retVal; + } + +//------------------------------------------------------------------------------ +// CEDIDHandler::FillCommonHdmiDviTimings +//------------------------------------------------------------------------------ +// +void CEDIDHandler::FillCommonHdmiDviTimings( THdmiDviTimings& aTimings ) const + { + FUNC_LOG; + + aTimings.iTvPhysicalImageWidthMm = iEdidParserPtr->GetHorizontalScreenSize() * 10; + aTimings.iTvPhysicalImageHeightMm = iEdidParserPtr->GetVerticalScreenSize() * 10; + aTimings.iTvPhysicalImageAspectRatioNumerator = 0; + aTimings.iTvPhysicalImageAspectRatioDenominator = 0; + aTimings.iHorizontalBorderPixels = 0; + aTimings.iVerticalBorderLinesField1 = 0; + aTimings.iVerticalBorderLinesField2 = 0; + aTimings.iLeftBorderPixels = 0; + aTimings.iRightBorderPixels = 0; + aTimings.iUnderscanEnabled = EFalse; + + if( iExtensionParserPtr ) + { + aTimings.iUnderscanEnabled = iExtensionParserPtr->Underscan(); + } + + if( aTimings.iUnderscanEnabled ) + { + // Underscan + aTimings.iLeftTopCorner.iX = 0; + aTimings.iLeftTopCorner.iY = 0; + aTimings.iRightBottomCorner.iX = aTimings.iHorizontalActivePixels; + aTimings.iRightBottomCorner.iY = aTimings.iVerticalActiveLines; + } + else + { + // Calculate overscan + CalculateOverscan( aTimings.iLeftTopCorner, + aTimings.iRightBottomCorner ); + } + aTimings.iTvPhysicalImageAspectRatioNumerator = iEdidParserPtr->GetAspectRatioLandscape(); + aTimings.iTvPhysicalImageAspectRatioDenominator = iEdidParserPtr->GetAspectRatioPortrait(); + aTimings.iConnector = TTvSettings::EHDMI; + aTimings.iTvColorCoordinates.iRed.iX = iEdidParserPtr->GetColorCoordinatesRedX(); + aTimings.iTvColorCoordinates.iRed.iY = iEdidParserPtr->GetColorCoordinatesRedY(); + aTimings.iTvColorCoordinates.iGreen.iX = iEdidParserPtr->GetColorCoordinatesGreenX(); + aTimings.iTvColorCoordinates.iGreen.iY = iEdidParserPtr->GetColorCoordinatesGreenY(); + aTimings.iTvColorCoordinates.iBlue.iX = iEdidParserPtr->GetColorCoordinatesBlueX(); + aTimings.iTvColorCoordinates.iBlue.iY = iEdidParserPtr->GetColorCoordinatesBlueY(); + aTimings.iTvColorCoordinates.iWhite.iX = iEdidParserPtr->GetColorCoordinatesWhiteX(); + aTimings.iTvColorCoordinates.iWhite.iY = iEdidParserPtr->GetColorCoordinatesWhiteY(); + aTimings.iTvHdmiVersion = iEdidParserPtr->GetVersion(); + aTimings.iTvHdmiRevision = iEdidParserPtr->GetRevision(); + Mem::FillZ( ( TAny* )&aTimings.iProductName, ( sizeof( TChar ) * KProductNameChars ) ); + Mem::FillZ( ( TAny* )&aTimings.iProductDescription, ( sizeof( TChar ) * KProductDescriptorsChars ) ); + aTimings.iSourceType = THdmiDviTimings::ESourceTypeUnknown; + } + +//------------------------------------------------------------------------------ +// CEDIDHandler::FillHdmiDviTimings +//------------------------------------------------------------------------------ +// +void CEDIDHandler::FillHdmiDviTimings( const TTimingItem& aItem, + THdmiDviTimings& aTimings ) const + { + FUNC_LOG; + + // Fill attributes from the static table + if( aItem.iTimingType == ETimingModeCEA ) + { + // CEA + aTimings.iCeaMode = static_cast( aItem.iTimingId ); + } + else + { + // DMT + aTimings.iDmtMode = static_cast( aItem.iTimingId ); + } + aTimings.iPixelClockKHz = aItem.iDotClock; + aTimings.iHorizontalActivePixels = aItem.iHorizontalActive; + aTimings.iHorizontalBlankingPixels = aItem.iHorizontalBlanking; + aTimings.iHorizontalSyncOffsetPixels = aItem.iHorizontalFrontPorch; + aTimings.iHorizontalSyncPulseWidthPixels = aItem.iHorizontalSync; + aTimings.iVerticalActiveLines = aItem.iVertical1stActive; + aTimings.iVerticalBlankingLines = aItem.iVertical1stBlanking; + aTimings.iVerticalSyncOffsetLinesField1 = aItem.iVertical1stFrontPorch; + aTimings.iVerticalSyncPulseWidthLinesField1 = aItem.iVertical1stSync; + aTimings.iVerticalSyncOffsetLinesField2 = aItem.iVertical2ndFrontPorch; + aTimings.iVerticalSyncPulseWidthLinesField2 = aItem.iVertical2ndSync; + aTimings.iInterlaced = aItem.iInterlaced; + aTimings.iHorizontalSyncPolarity = aItem.iHorizontalSyncPolarity; + aTimings.iVerticalSyncPolarity = aItem.iVerticalSyncPolarity; + aTimings.iPixelRepeat = aItem.iPixelRepeat; + aTimings.iRightBottomCorner.iX = aItem.iWidth; + aTimings.iRightBottomCorner.iY = aItem.iHeight; + aTimings.iImageAspectRatio = aItem.iAspectRatio; + if( aTimings.iImageAspectRatio == TTvSettings::EUndefRatio ) + { + // Resolve ratio from width and height + aTimings.iImageAspectRatio = ResolveAspectRatio( aItem.iWidth, aItem.iHeight ); + } + aTimings.iPixelAspectRatioNumerator = aItem.iPixelAspectRatioNumerator; + aTimings.iPixelAspectRatioDenominator = aItem.iPixelAspectRatioDenominator; + + // Fill the common attributes + FillCommonHdmiDviTimings( aTimings ); + + TRACE_TIMINGS( aTimings ); + } + +//------------------------------------------------------------------------------ +// CEDIDHandler::FillHdmiDviTimings +//------------------------------------------------------------------------------ +// +void CEDIDHandler::FillHdmiDviTimings( const TEdidDescriptorBlock& aDescBlock, + THdmiDviTimings& aTimings ) const + { + FUNC_LOG; + + // Fill attributes from timing descriptor + aTimings.iCeaMode = ECeaFixedModeNone; + aTimings.iDmtMode = EDmtFixedModeNone; + aTimings.iPixelClockKHz = aDescBlock.iPixelClock; + aTimings.iHorizontalActivePixels = aDescBlock.iHorizontalAddressableVideoPixels; + aTimings.iHorizontalBlankingPixels = aDescBlock.iHorizontalBlanking; + aTimings.iHorizontalSyncOffsetPixels = aDescBlock.iHorizontalFrontPorch; + aTimings.iHorizontalSyncPulseWidthPixels = aDescBlock.iHorizontalSyncPulse; + aTimings.iHorizontalBorderPixels = aDescBlock.iHorizontalBorder; + aTimings.iVerticalActiveLines = aDescBlock.iVerticalAddressableVideoPixels; + aTimings.iVerticalBlankingLines = aDescBlock.iVerticalBlanking; + aTimings.iVerticalSyncOffsetLinesField1 = aDescBlock.iVerticalFrontPorch; + aTimings.iVerticalSyncPulseWidthLinesField1 = aDescBlock.iVerticalSyncPulse; + aTimings.iVerticalBorderLinesField1 = aDescBlock.iVerticalBorder; + aTimings.iInterlaced = aDescBlock.iInterlacedVideo; + if( aDescBlock.iSyncs == + EDigitalSeparateSyncVerticalSyncIsNegativeHorizontalSyncIsNegative ) + { + aTimings.iVerticalSyncPolarity = EFalse; + aTimings.iHorizontalSyncPolarity = EFalse; + } + else if( aDescBlock.iSyncs == + EDigitalSeparateSyncVerticalSyncIsNegativeHorizontalSyncIsPositive ) + { + aTimings.iVerticalSyncPolarity = EFalse; + aTimings.iHorizontalSyncPolarity = ETrue; + } + else if( aDescBlock.iSyncs == + EDigitalSeparateSyncVerticalSyncIsPositiveHorizontalSyncIsNegative ) + { + aTimings.iVerticalSyncPolarity = ETrue; + aTimings.iHorizontalSyncPolarity = EFalse; + } + else if( aDescBlock.iSyncs == + EDigitalSeparateSyncVerticalSyncIsPositiveHorizontalSyncIsPositive ) + { + aTimings.iVerticalSyncPolarity = ETrue; + aTimings.iHorizontalSyncPolarity = ETrue; + } + aTimings.iPixelRepeat = 1; + aTimings.iRightBottomCorner.iX = aDescBlock.iHorizontalAddressableVideoPixels; + aTimings.iRightBottomCorner.iY = aDescBlock.iVerticalAddressableVideoPixels; + aTimings.iImageAspectRatio = ResolveAspectRatio( + aTimings.iHorizontalActivePixels, + aTimings.iVerticalActiveLines ); + + // Fill the common attributes + FillCommonHdmiDviTimings( aTimings ); + + TRACE_TIMINGS( aTimings ); + } + +//------------------------------------------------------------------------------ +// SetCeaModes +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::SetCeaModes( RArray& aTimings ) const + { + FUNC_LOG; + + TInt retVal(KErrNone); + + // Use only CEA-861 extension parser + if( iExtensionParserPtr ) + { + // Get parsed information + CCea861ExtEdidInformation* info = + iExtensionParserPtr->GetParsedInformation(); + if( info ) + { + // Go through all supported CEA modes + TCEA861VideoDataBlock* vdb = info->iShortVideoDescriptors; + THdmiDviTimings timings; + while( vdb ) + { + // Get a timing item matched with the VIC mode + TInt index = vdb->iVIC - 1; + if( ( index >= 0 ) && ( index < KCEATimingCount ) ) + { + const TTimingItem* item = TimingByIndex( index, ETimingModeCEA ); + if( item ) + { + Mem::FillZ( ( TAny* )&timings, sizeof( timings ) ); + FillHdmiDviTimings( *item, timings ); + retVal = aTimings.Append( timings ); + ERROR_1( retVal, "Failed to append CEA timing: %S in array", item->iTimingName ); + } + else + { + ERROR_1( KErrArgument, "CEA timing item not found for VIC mode: %d", index ); + } + } + vdb = vdb->iNext; + } + } + } + + return retVal; + } + +//------------------------------------------------------------------------------ +// SetDmtModes +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::SetDmtModes( RArray& aTimings ) const + { + FUNC_LOG; + + TInt retVal(KErrNone); + + // Check established timings 1 and 2 + retVal = SetDmtModesFromEstablishedTimings( aTimings ); + + if( KErrNone == retVal ) + { + // Check standard timings + retVal = SetDmtModesFromStandardTimings( aTimings ); + + if( KErrNone == retVal ) + { + // Check timing descriptors + retVal = SetDmtModesFromTimingDescriptors( aTimings ); + } + } + + return retVal; + } + +//------------------------------------------------------------------------------ +// SetDmtModesFromEstablishedTimings +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::SetDmtModesFromEstablishedTimings( + RArray& aTimings ) const + { + FUNC_LOG; + + TUint8 timings = 0; + TUint16 width = 0; + TUint16 height = 0; + TUint16 refreshRate = 0; + TInt retVal(KErrNone); + + // Established timings 1 + // Bits 4, 6 and 7 left out since these does not match to DMT + timings = iEdidParserPtr->GetEstablishedTimings1(); + if( timings & E800x600_60Hz ) // Bit 0 + { + width = 800; + height = 600; + refreshRate = 60; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E800x600_56Hz ) // Bit 1 + { + width = 800; + height = 600; + refreshRate = 56; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E640x480_75Hz ) // Bit 2 + { + width = 640; + height = 480; + refreshRate = 75; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E640x480_72Hz ) // Bit 3 + { + width = 640; + height = 480; + refreshRate = 72; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E640x480_60Hz ) // Bit 5 + { + width = 640; + height = 480; + refreshRate = 60; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + + // Established timings 2 + // Bit 5 left out since it does not match to DMT + timings = iEdidParserPtr->GetEstablishedTimings2(); + if( timings & E1280x1024_75Hz ) // Bit 0 + { + width = 1280; + height = 1024; + refreshRate = 75; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E1024x768_75Hz ) // Bit 1 + { + width = 1024; + height = 768; + refreshRate = 75; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E1024x768_70Hz ) // Bit 2 + { + width = 1280; + height = 768; + refreshRate = 70; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E1024x768_60Hz ) // Bit 3 + { + width = 1280; + height = 768; + refreshRate = 60; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E1024x768_87Hz ) // Bit 4 + { + width = 1280; + height = 768; + refreshRate = 87; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E800x600_75Hz ) // Bit 6 + { + width = 800; + height = 600; + refreshRate = 75; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + if( timings & E800x600_72Hz ) // Bit 7 + { + width = 800; + height = 600; + refreshRate = 72; + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + + return retVal; + } + +//------------------------------------------------------------------------------ +// SetDmtModesFromStandardTimings +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::SetDmtModesFromStandardTimings( + RArray& aTimings ) const + { + FUNC_LOG; + + // One timing descriptor is specified in two bytes: + // 26h: + // ------------------------------------------------------------------------- + // 01h-FFh: + // Horizontal addressable pixels: Value Stored (in hex) = + // (Horizontal addressable pixels / 8) – 31 + // Range: 256 pixels -> 2288 pixels, in increments of 8 pixels + // -------------------------------------------------------------------- + // 00h: + // Reserved. Do not use! + // ------------------------------------------------------------------------- + // 27h: + // ------------------------------------------------------------------------- + // Bits 7 - 6: + // Image Aspect Ratio: + // 0 0 _ _ _ _ _ _ (16 : 10 AR) + // 0 1 _ _ _ _ _ _ ( 4 : 3 AR) + // 1 0 _ _ _ _ _ _ ( 5 : 4 AR) + // 1 1 _ _ _ _ _ _ (16 : 9 AR) + // -------------------------------------------------------------------- + // Bits 0 - 5: + // Field Refresh Rate: Value Stored (in binary) = + // Field Refresh Rate (in Hz) – 60 + // Range: 60 Hz -> 123Hz + // ------------------------------------------------------------------------- + // 27h: + // 28h: + // ------------------------------------------------------------------------- + // etc. + + // There can be up to 8 standard timings (2 bytes * 8) + const TInt KStandardTimingBytes = 16; + const TUint KRefreshRateMask = 0x3F; // --XXXXXX + TInt retVal(KErrNone); + + TUint16 width = 0; + TUint16 height = 0; + TUint16 refreshRate = 0; + TUint8 byte1 = 0; + TUint8 byte2 = 0; + for( TInt i = 0; i < KStandardTimingBytes; i += 2 ) + { + byte1 = iEdidParserPtr->GetStandardTimings( i ); + byte2 = iEdidParserPtr->GetStandardTimings( i + 1 ); + + // Horizontal pixels + width = ( byte1 + 31 ) * 8; + + // Aspect ratio & vertical lines + if( !( byte2 & KBit7 ) && !( byte2 & KBit6 ) ) + { + // 16 : 10 AR + height = ( width * 10 ) / 16; + } + else if( !( byte2& KBit7 ) && ( byte2 & KBit6 ) ) + { + // 4 : 3 AR + height = ( width * 3 ) / 4; + } + else if( ( byte2 & KBit7 ) && !( byte2& KBit6 ) ) + { + // 5 : 4 AR + height = ( width * 4 ) / 5; + } + else // ( byte2 & KBit7 ) && ( byte2 & KBit6 ) + { + // 16 : 9 AR + height = ( width * 9 ) / 16; + } + + // Refresh rate + // Nullify bits 6 and 7 + byte2 = byte2 & KRefreshRateMask; + refreshRate = byte2 + 60; + + // Set timing item by resolution + retVal = SetDmtModeByResolution( aTimings, width, height, refreshRate ); + } + + return retVal; + } + +//------------------------------------------------------------------------------ +// SetDmtModesFromTimingDescriptors +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::SetDmtModesFromTimingDescriptors( + RArray& aTimings ) const + { + FUNC_LOG; + + // 1st 18 byte timing descriptor + THdmiDviTimings timings; + TInt retVal(KErrNone); + + TEdidDescriptorBlock first = + iEdidParserPtr->GetDescriptorBlock( EEdidDescriptorBlockFirstTiming ); + FillHdmiDviTimings( first, timings ); + retVal = aTimings.Append( timings ); + ERROR( retVal, "Failed to append 1st timing descriptor in array" ); + + if( KErrNone == retVal ) + { + // 2nd 18 byte timing descriptor + Mem::FillZ( ( TAny* )&timings, sizeof( timings ) ); + TEdidDescriptorBlock second = + iEdidParserPtr->GetDescriptorBlock( EEdidDescriptorBlockSecondTiming ); + FillHdmiDviTimings( second, timings ); + retVal = aTimings.Append( timings ); + ERROR( retVal, "Failed to append 2nd timing descriptor in array" ); + } + + return retVal; + } + +//------------------------------------------------------------------------------ +// TimingByIndex +//------------------------------------------------------------------------------ +// +const TTimingItem* CEDIDHandler::TimingByIndex( TInt aIndex, + TTimingModeType aType ) const + { + FUNC_LOG; + + const TTimingItem* item = NULL; + if( aIndex >= 0 ) + { + if( aType == ETimingModeCEA ) + { + if( aIndex < KCEATimingCount ) + { + item = &KCEATimings[aIndex]; + } + } + else + { + if( aIndex < KDMTTimingCount ) + { + item = &KDMTTimings[aIndex]; + } + } + } + + return item; + } + +//------------------------------------------------------------------------------ +// TimingByResolution +//------------------------------------------------------------------------------ +// +const TTimingItem* CEDIDHandler::TimingByResolution( TUint16 aWidth, + TUint16 aHeight, + TUint16 aRefreshRate, + TTimingModeType aType ) const + { + FUNC_LOG; + + const TTimingItem* item = NULL; + if( aType == ETimingModeCEA ) + { + // CEA mode + for( TInt i = 0; i < KCEATimingCount; i++ ) + { + item = &KCEATimings[i]; + if( item->iWidth == aWidth && + item->iHeight == aHeight && + item->iFieldRate == aRefreshRate ) + { + // Item found, break + break; + } + item = NULL; + } + } + else + { + // DMT mode + for( TInt i = 0; i < KDMTTimingCount; i++ ) + { + item = &KDMTTimings[i]; + if( item->iWidth == aWidth && + item->iHeight == aHeight && + item->iFieldRate == aRefreshRate ) + { + // Item found, break + break; + } + item = NULL; + } + } + + return item; + } + +//------------------------------------------------------------------------------ +// SetDmtModeByResolution +//------------------------------------------------------------------------------ +// +TInt CEDIDHandler::SetDmtModeByResolution( RArray& aTimings, + TUint16 aWidth, + TUint16 aHeight, + TUint16 aRefreshRate ) const + { + FUNC_LOG; + + TInt retVal(KErrNone); + + const TTimingItem* item = TimingByResolution( aWidth, + aHeight, aRefreshRate, ETimingModeDMT ); + if( item ) + { + THdmiDviTimings timings; + FillHdmiDviTimings( *item, timings ); + retVal = aTimings.Append( timings ); + ERROR_1( retVal, "Failed to append DMT timing: %S in array", + item->iTimingName ); + } + else + { + ERROR_3( KErrArgument, "DMT timing item not found for width: %d, height: %d, refresh rate: %d", + aWidth, aHeight, aRefreshRate ); + } + + return retVal; + } + +//------------------------------------------------------------------------------ +// SetDmtModeByResolution +//------------------------------------------------------------------------------ +// +TTvSettings::TAspectRatio CEDIDHandler::ResolveAspectRatio( TUint16 aWidth, + TUint16 aHeight ) const + { + FUNC_LOG; + + TTvSettings::TAspectRatio aspectRatio = TTvSettings::EUndefRatio; + TReal source = ( TReal )aWidth / ( TReal )aHeight; + TReal target = 0.0; + if( Math::Round( target, source, 3 ) == KErrNone ) + { + if( target == K16d9 ) + { + // 16:9 + aspectRatio = TTvSettings::E16d9; + } + else if( target == K4d3 ) + { + // 4:3 + aspectRatio = TTvSettings::E4d3; + } + } + + return aspectRatio; + } + +//------------------------------------------------------------------------------ +// CalculateOverscan +//------------------------------------------------------------------------------ +// +void CEDIDHandler::CalculateOverscan( TPoint& aTLCorner, + TPoint& aBRCorner ) const + { + FUNC_LOG; + + // No need to calculate if the screen size is zero + if( aBRCorner.iX > 0 && aBRCorner.iY > 0 ) + { + // hOverscanPixels = ( ( Width * hOverscan ) + 50 ) / 20000 + // + // hOverscanPixels: + // pixels which are needed to be added to top left X + // pixels which are needed to be reduced from bottom right X + // Width: + // Horizontal resolution + // hOverscan: + // Horizontal overscan in percents (1% == 100) + // 50: + // Used to round up possible decimals + // 20000: + // Used to get rid of percentage multiplier and to get the overscan value + // for one side + TInt hOverscanPixels = ( aBRCorner.iX * iHOverscan + 50 ) / 20000; + aTLCorner.iX = hOverscanPixels; + aBRCorner.iX = ( aBRCorner.iX - hOverscanPixels ); + + // vOverscanPixels = ( ( Height * vOverscan ) + 50 ) / 20000 + // + // vOverscanPixels: + // pixels which are needed to be added to top left Y + // pixels which are needed to be reduced from bottom right Y + // Height: + // Horizontal resolution + // vOverscan: + // Vertical overscan in percents (1% == 100) + // 50: + // Used to round up possible decimals + // 20000: + // Used to get rid of percentage multiplier and to get the overscan value + // for one side + TInt vOverscanPixels = ( aBRCorner.iY * iVOverscan + 50 ) / 20000; + aTLCorner.iY = vOverscanPixels; + aBRCorner.iY = ( aBRCorner.iY - vOverscanPixels ); + } + } + +//------------------------------------------------------------------------------ +// CalculateOverscan +//------------------------------------------------------------------------------ +// +void CEDIDHandler::UpdateOverscanValues() + { + FUNC_LOG; + + // Overscan from cenrep + TInt hOverscan = 0; + TInt vOverscan = 0; + CRepository* cenRep = NULL; + TInt err = KErrNone; + + TRAP( err, cenRep = CRepository::NewL( KCRUidTvoutSettings ) ); + if( err == KErrNone ) + { + + // Horizontal + err = cenRep->Get( KSettingsTvoutHorizontalOverscan, hOverscan ); + if( err != KErrNone ) + { + hOverscan = 0; + } + + // Vertical + err = cenRep->Get( KSettingsTvoutVerticalOverscan, vOverscan ); + if( err != KErrNone ) + { + vOverscan = 0; + } + + // Cleanup + delete cenRep; + } + + // Update overscan values + iHOverscan = hOverscan; + iVOverscan = vOverscan; + } + +// ---------------------------------------------------------------------------- +// CEDIDHandler::FilterAvailableTvConfigList +// +// ---------------------------------------------------------------------------- +// +TInt CEDIDHandler::FilterAvailableTvConfigList( RArray& aHdmiConfigs ) + { + FUNC_LOG; + + TUint supportedCount; + TInt retVal( KErrNotFound ); + TInt availableCount( aHdmiConfigs.Count() ); + RArray supportedModes; + + INFO_1( "HDMI CONFIGS --- From SINK -- Total : %d", availableCount ); + + retVal = iTVOutConfigForHDMI.GetSupportedHdmiModes( supportedModes ); + + if( KErrNone == retVal ) + { + TInt availableIndex = 0; + TBool found( EFalse ); + TBool defaultCEAmode( EFalse ); + supportedCount = supportedModes.Count(); + INFO_1( "HDMI CONFIGS --- From HW -- Total : %d", supportedCount ); + + INFO( "Filtered list -- START" ); + while( availableIndex < availableCount ) + { + found = EFalse; + + for( TInt supportedIndex = 0; (supportedIndex < supportedCount); supportedIndex++ ) + { + // Check CEA mode + if( aHdmiConfigs[ availableIndex ].iCeaMode && + (TSupportedHdmiDviMode::ECea == supportedModes[ supportedIndex ].iStandardModeType) && + (aHdmiConfigs[ availableIndex ].iCeaMode == supportedModes[ supportedIndex ].iStandardMode) ) + { + found = ETrue; + if( aHdmiConfigs[ availableIndex].iCeaMode == KDefaultCEAMode ) + { + defaultCEAmode = ETrue; + } + TRACE_TIMINGS( (aHdmiConfigs[ availableIndex ]) ); + break; + } + + // Check DMT mode + if( aHdmiConfigs[ availableIndex ].iDmtMode && + (TSupportedHdmiDviMode::EDmt == supportedModes[ supportedIndex ].iStandardModeType) && + (aHdmiConfigs[ availableIndex ].iDmtMode == supportedModes[ supportedIndex ].iStandardMode) ) + { + found = ETrue; + TRACE_TIMINGS( (aHdmiConfigs[ availableIndex ]) ); + break; + } + } + + if( EFalse == found ) + { + // Remove from the list + aHdmiConfigs.Remove( availableIndex ); + availableCount--; + continue; + } + + availableIndex++; + } + + if( ( (KDefaultCEAModePhysImgAspRatioNr == iEdidParserPtr->GetAspectRatioLandscape()) + && (KDefaultCEAModePhysImgAspRatioDr == iEdidParserPtr->GetAspectRatioPortrait()) ) + && !defaultCEAmode ) + + { + THdmiDviTimings timings; + + // Get a timing item for default CEA Mode (1) + const TTimingItem* item = TimingByIndex( KDefaultCEAModeIndex, ETimingModeCEA ); + if( item ) + { + Mem::FillZ( ( TAny* )&timings, sizeof( timings ) ); + FillHdmiDviTimings( *item, timings ); + retVal = aHdmiConfigs.Append( timings ); + ERROR( retVal, "Failed to append CEA timing in available config array" ); + } + } + + INFO( "Filtered list -- END" ); + supportedModes.Close(); + } + + return retVal; + } + +//------------------------------------------------------------------------------ +// C++ constructor +//------------------------------------------------------------------------------ +// +CEDIDHandler::CEDIDHandler( MFSMForBody& aFSM, + CTVOutConfigForHDMI& aTVOutConfigForHDMI ) : + CActive( CActive::EPriorityLow ), + iFSM( aFSM ), + iTVOutConfigForHDMI( aTVOutConfigForHDMI ), + iRetryCounter( 0 ), + iRequestID( EUndefRequest ) + { + FUNC_LOG; + } + +//------------------------------------------------------------------------------ +// ConstructL +//------------------------------------------------------------------------------ +// +void CEDIDHandler::ConstructL() + { + FUNC_LOG; + + INFO( "Creating Retry Timer object" ); + User::LeaveIfError(iRetryTimer.CreateLocal()); + + INFO( "Creating CDdcPortAccess object" ); + iDdcPortAccess = CDdcPortAccess::NewL(); + + CActiveScheduler::Add( this ); + } + +// ======== GLOBAL FUNCTIONS ======== + +