--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/display/display.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,876 @@
+// Copyright (c) 1998-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:
+// e32\drivers\display\display.cpp
+// LDD for a Display driver with GCE support
+// LDD for a Display driver with GCE support
+//
+//
+
+/**
+ @file
+ @internalTechnology
+ @prototype
+*/
+
+
+#include <drivers/display.h>
+#include <kernel/kern_priv.h>
+
+
+
+static const char KDisplayLddPanic[]="DISPLAY/GCE LDD";
+
+
+/************************************************************************************
+ * DDisplayLdd LDD class implementation
+ ************************************************************************************/
+DDisplayLdd::DDisplayLdd()
+ {
+ __DEBUG_PRINT("DDisplayLdd::DDisplayLdd()\n");
+ // store the pointer to the current thread for request completion
+ iClient = &Kern::CurrentThread();
+ __NK_ASSERT_DEBUG(iClient);
+ // Open a reference on the client thread so it's control block can't disappear until the driver has finished with it.
+ iClient->Open();
+ iCurrentPostCount = 0;
+ iRequestedPostCount = 0;
+ iCompositionBuffIdx = 0;
+ iUnit = -1;
+ iThreadOpenCount = 0;
+ }
+
+
+DDisplayLdd::~DDisplayLdd()
+ {
+ __DEBUG_PRINT("DDisplayLdd::~DDisplayLdd() \n");
+ // cancel outstanding requests
+ for(TInt k = 0; k < KPendingReqArraySize ; k++)
+ {
+ if(iPendingReq[k].iStatus)
+ {
+ CompleteRequest(iPendingReq[k].iOwningThread,iPendingReq[k].iStatus,KErrCancel);
+ }
+ }
+
+ //Close User Buffer chunks not yet destroyed.
+ for(TInt i = 0; i < KDisplayUBMax; i++)
+ {
+ if(iUserBuffer[i].iChunk != 0)
+ {
+ Kern::ChunkClose(iUserBuffer[i].iChunk);
+ iUserBuffer[i].iChunk= NULL;
+ }
+ }
+
+ Kern::SafeClose((DObject*&)iClient, NULL);
+
+ __ASSERT_DEBUG(iThreadOpenCount==0,Kern::Fault(KDisplayLddPanic,__LINE__));
+
+ // Clear the 'units open mask' in the LDD factory.
+ if (iUnit>=0)
+ ((DDisplayLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse);
+ }
+
+
+/**
+ LDD second stage constructor
+*/
+TInt DDisplayLdd::DoCreate(TInt aUnit, const TDesC8* /* anInfo*/, const TVersion& aVer)
+ {
+
+ __DEBUG_PRINT("DDisplayLdd::DoCreate()\n");
+
+ if( !Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
+ && !Kern::CurrentThreadHasCapability(ECapabilityReadDeviceData, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
+ && !Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
+ && !Kern::CurrentThreadHasCapability(ECapabilityProtServ, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) )
+ {
+ return KErrPermissionDenied;
+ }
+
+ // Check that the display driver version specified by the client is compatible.
+ if (!Kern::QueryVersionSupported(RDisplayChannel::VersionRequired(),aVer))
+ {
+ return(KErrNotSupported);
+ }
+
+ // Check that a channel hasn't already been opened on this unit.
+ TInt r=((DDisplayLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory.
+ if (r!=KErrNone)
+ {
+ return r;
+ }
+
+ Pdd()->iLdd = this;
+
+ r = Pdd()->CreateChannelSetup(aUnit);
+ if ( r!= KErrNone)
+ {
+ return r;
+ }
+
+ // set up user buffer nodes
+ for (TInt node = 0; node < KDisplayUBMax; node++)
+ {
+ iUserBuffer[node].iType = EBufferTypeUser;
+ iUserBuffer[node].iBufferId = (node + 1);
+ iUserBuffer[node].iFree = ETrue;
+ iUserBuffer[node].iState = EBufferFree;
+ iUserBuffer[node].iAddress = 0;
+ iUserBuffer[node].iSize = 0;
+ iUserBuffer[node].iHandle = 0;
+ iUserBuffer[node].iChunk = 0;
+ iUserBuffer[node].iOffset = 0;
+ iUserBuffer[node].iPendingRequest = 0;
+ }
+
+ //Initialise pending queue for asynchronous requests
+ for(int k = 0; k < KPendingReqArraySize; k++)
+ {
+ iPendingReq[k].iStatus = 0;
+ iPendingReq[k].iOwningThread = 0;
+ }
+
+ Pdd()->SetGceMode();
+ SetDfcQ(Pdd()->DfcQ(aUnit));
+ iMsgQ.Receive();
+
+ return KErrNone;
+}
+
+
+/**
+ * All driver's client requests (synchronous and asynchronous) are sent as
+ * kernel messages by generic kernel to logical channel. This function
+ * catches messages sent by the generic kernel
+ *
+ * @param aMsg KErnel side thread messaging
+ */
+void DDisplayLdd::HandleMsg(TMessageBase* aMsg)
+ {
+ TThreadMessage& m = *(TThreadMessage*)aMsg ;
+ TInt id = m.iValue ;
+ DThread* client = m.Client();
+
+ // close message
+ if (id == (TInt)ECloseMsg)
+ {
+ //Device specific cleanup operations
+ Pdd()->CloseMsg();
+
+ // cancel outstanding requests
+ for(int k = 0; k < KPendingReqArraySize; k++)
+ {
+ if(iPendingReq[k].iStatus)
+ {
+ CompleteRequest(iPendingReq[k].iOwningThread,iPendingReq[k].iStatus,KErrCancel);
+ }
+ }
+ Pdd()->SetLegacyMode();
+ m.Complete(KErrNone, EFalse);
+ return;
+ }
+ // cancel
+ if (id == KMaxTInt)
+ {
+ // DoCancel
+ TInt req = m.Int0() >> 1;
+ DoCancel(req);
+ m.Complete(KErrNone,ETrue);
+ return;
+ }
+ // asynchronous request
+ else if (id < 0)
+ {
+ TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+ TInt r = DoRequest(~id,pS,m.Ptr1(),m.Ptr2(), client);
+ m.Complete(r, ETrue);
+ }
+ // synchronous request
+ else
+ {
+ TInt r = DoControl(id,m.Ptr0(),m.Ptr1(), client);
+ m.Complete(r,ETrue);
+ }
+ }
+
+
+/**
+ Cancel outstanding request.
+
+ @param aReqNumber Any value from the RDisplayChannel::TRequest enumeration.
+*/
+void DDisplayLdd::DoCancel(TUint aReqNumber)
+ {
+ __DEBUG_PRINT2("DDisplayLdd::DoCancel %d\n",aReqNumber);
+
+ switch (aReqNumber)
+ {
+ case RDisplayChannel::ECtrlCancelGetCompositionBuffer:
+ case RDisplayChannel::ECtrlCancelPostUserBuffer:
+ case RDisplayChannel::ECtrlCancelWaitForPost:
+ if(iPendingReq[aReqNumber].iStatus)
+ {
+ CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel);
+
+ iPendingReq[aReqNumber].iStatus = 0;
+ iPendingReq[aReqNumber].iOwningThread = 0;
+ }
+ break;
+ }
+
+ }
+
+/**
+ Asynchronous request processing.
+
+ @param aFunction request function number
+ @param apRqStat pointer to the user's request status object.
+ @param apArg1 pointer to the 1st parameter
+ @param apArg2 pointer to the 2nd parameter
+
+ @return request scheduling result, system-wide error code.
+*/
+TInt DDisplayLdd::DoRequest(TInt aReqNumber, TRequestStatus* aRqStat, TAny* aArg1, TAny* aArg2, DThread* aClient)
+ {
+ TUint count;
+ TInt pack[2];
+ TInt r = KErrNone;
+ TBufferNode* node = 0;
+ TInt buffer_id = 0;
+
+ // Open a reference on the client thread while the request is pending so it's control block can't disappear until this driver has finished with it.
+ r=aClient->Open();
+ __ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__));
+#ifdef _DEBUG
+ __e32_atomic_add_ord32(&iThreadOpenCount, 1);
+#endif
+
+ // check if this request is valid
+ if(aReqNumber >= 0 && aReqNumber <= RDisplayChannel::EReqWaitForPost)
+ {
+ // cancel outstanding request
+ if(iPendingReq[aReqNumber].iStatus)
+ {
+ CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel);
+ iPendingReq[aReqNumber].iStatus = 0;
+ iPendingReq[aReqNumber].iOwningThread = 0;
+ }
+
+ // store request and client
+ iPendingReq[aReqNumber].iStatus = aRqStat;
+ iPendingReq[aReqNumber].iOwningThread = aClient;
+ }
+
+ switch (aReqNumber)
+ {
+ case RDisplayChannel::EReqGetCompositionBuffer:
+
+ if(aArg1 == 0 )
+ {
+ r = KErrGeneral;
+ CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,r);
+ iPendingReq[aReqNumber].iStatus = 0;
+ iPendingReq[aReqNumber].iOwningThread = 0;
+ }
+ else
+ {
+ TInt index;
+ TBool found = EFalse;
+
+ for(index =0; index< KDisplayCBMax; index++)
+ {
+ if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose )
+ {
+ __DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index);
+
+ iCompositionBuffIdx = index;
+ r = Kern::ThreadRawWrite(aClient, aArg1, &iCompositionBuffIdx, sizeof(TInt), aClient);
+ if ( r == KErrNone)
+ {
+ iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose;
+ CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,r);
+ iPendingReq[aReqNumber].iStatus = 0;
+ iPendingReq[aReqNumber].iOwningThread = 0;
+ found = ETrue;
+ break;
+ }
+ }
+ }
+ if(!found) //There are no free buffers schedule request for completion
+ {
+ //Case of a single composition buffer.
+ if (iDisplayInfo.iNumCompositionBuffers == 1)
+ {
+ iCompositionBuffIdx = 0;
+ r = Kern::ThreadRawWrite(aClient, aArg1, &iCompositionBuffIdx, sizeof(TInt), aClient);
+ __DEBUG_PRINT("EReqGetCompositionBuffer The single Composition buffer is currently being used\n");
+ break;
+ }
+
+
+ for( index=0; index< KDisplayCBMax; index++)
+ {
+ if(iCompositionBuffer[index].iState == EBufferActive)
+ {
+ iCompositionBuffIdx = index;
+ r = Kern::ThreadRawWrite(aClient, aArg1,&iCompositionBuffIdx, sizeof(TInt), aClient);
+ __DEBUG_PRINT2("EReqGetCompositionBuffer No composition buffer available. Next available is iCompositionBuffIdx %d.\n",iCompositionBuffIdx );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case RDisplayChannel::EReqPostUserBuffer:
+ r= Kern::ThreadRawRead(aClient, aArg1, &pack, (sizeof(TInt)*2));
+ if ( r == KErrNone)
+ {
+ r = KErrArgument;
+ buffer_id = pack[0];
+ if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) )
+ {
+ node = FindUserBufferNode(buffer_id);
+ if(node && (!(node->iFree) && node->iChunk ) )
+ {
+ __DEBUG_PRINT2("EReqPostUserBuffer Posting buffer id: %d \n",buffer_id );
+ r = Pdd()->PostUserBuffer(node);
+ if(r == KErrNone)
+ {
+ ++iCurrentPostCount;
+ r=Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient);
+ break;
+ }
+ }
+ }
+ RequestComplete(RDisplayChannel::EReqPostUserBuffer, r);
+ }
+ break;
+
+ case RDisplayChannel::EReqWaitForPost:
+ r= Kern::ThreadRawRead(aClient, aArg1, &count, sizeof(RDisplayChannel::TPostCount));
+ if ( r == KErrNone)
+ {
+ iRequestedPostCount = count;
+ //Any post operation increases iCurrentPostCount instantly but the actual post completes later on.
+ if( ! Pdd()->PostPending() )
+ {
+ RequestComplete(RDisplayChannel::EReqWaitForPost, KErrNone);
+ }
+ }
+ break;
+
+ default:
+ r = KErrNotSupported;
+ break;
+ }
+ return r;
+ }
+
+
+/**
+ Synchronous requests processing.
+
+ @param aFunction request function number,
+ @param apArg1 pointer to the 1st parameter
+ @param apArg2 pointer to the 2n parameter
+
+ @return request processing result
+*/
+TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient)
+ {
+ TInt r = KErrNotSupported;
+ TBool changedRot = ETrue;
+ TBufferNode* node = 0;
+ TInt buffer_id;
+ TInt pack[2] = {0,0};
+ TInt handle, offset;
+ TInt index = 0;
+
+ TPckgBuf<RDisplayChannel::TDisplayInfo> pckgInfo(iDisplayInfo);
+
+ switch (aFunction)
+ {
+ case RDisplayChannel::ECtrlGetDisplayInfo:
+ r=Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&pckgInfo, sizeof(pckgInfo), aClient);
+ break;
+
+ case RDisplayChannel::ECtrlPostCompositionBuffer:
+ node = &iCompositionBuffer[iCompositionBuffIdx];
+ r = Pdd()->PostCompositionBuffer(node);
+ if(r == KErrNone)
+ {
+ ++iCurrentPostCount;
+ r=Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient);
+ }
+ else
+ {
+ r = KErrGeneral;
+ }
+ break;
+
+ case RDisplayChannel::ECtrlPostLegacyBuffer:
+ r= Pdd()->PostLegacyBuffer();
+ if ( r == KErrNone)
+ {
+ ++iCurrentPostCount;
+ r = Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient);
+ }
+ break;
+
+ case RDisplayChannel::ECtrlRegisterUserBuffer:
+ node = FindUserBufferNode(0);
+ if(node)
+ {
+ r= Kern::ThreadRawRead(aClient, aArg1, &pack, (sizeof(TInt)*2));
+ if(r == KErrNone)
+ {
+ handle = pack[0];
+ offset = pack[1];
+ r = CheckAndOpenUserBuffer(node, handle, offset, aClient);
+
+ if(r == KErrNone)
+ {
+ r= Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&node->iBufferId, sizeof(TInt), aClient);
+ }
+ }
+ }
+ else
+ {
+ r = KErrTooBig;
+ }
+ break;
+
+ case RDisplayChannel::ECtrlDeregisterUserBuffer:
+ r= Kern::ThreadRawRead(aClient, aArg1, &buffer_id, sizeof(TInt));
+ if ( r == KErrNone)
+ {
+ r = KErrArgument;
+ if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) )
+ {
+ node = FindUserBufferNode(buffer_id);
+ if(node && (!(node->iFree) && node->iChunk ) )
+ {
+ if(node->iState==EBufferFree || node->iState==EBufferCompose )
+ {
+ r = FreeUserBufferNode(node);
+ }
+ else
+ {
+ r = KErrInUse;
+ }
+ }
+ }
+ }
+ break;
+
+ case RDisplayChannel::ECtrlPostCount:
+ r= Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&iCurrentPostCount, sizeof(TUint), aClient);
+ break;
+
+ case RDisplayChannel::ECtrlSetRotation:
+ {
+ RDisplayChannel::TDisplayRotation rot;
+ TInt previousRot = iCurrentRotation;
+ r= Kern::ThreadRawRead(aClient, aArg1, &rot, sizeof(RDisplayChannel::TDisplayRotation));
+ if ( r == KErrNone)
+ {
+ r = Pdd()->SetRotation((TInt)rot);
+ changedRot=(previousRot!=iCurrentRotation);
+ if( r == KErrNone)
+ {
+ r= Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&changedRot, sizeof(TBool), aClient);
+ }
+ }
+ }
+ break;
+
+ case RDisplayChannel::ECtrlCurrentRotation:
+ r=Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&iCurrentRotation, sizeof(RDisplayChannel::TDisplayRotation), aClient);
+ break;
+
+ case RDisplayChannel::ECtrlGetCompositionBufferInfo:
+ {
+ r= Kern::ThreadRawRead(aClient, aArg1, &index, sizeof(TInt));
+ if ( r == KErrNone)
+ {
+ if( (index >= KDisplayCBMax ) || (index < 0 ) )
+ {
+ r = KErrArgument;
+ break;
+ }
+ r = Kern::MakeHandleAndOpen(aClient, iCompositionBuffer[index].iChunk);
+
+ if(r >= KErrNone)
+ {
+ pack[0] = r;
+ pack[1] = iCompositionBuffer[index].iOffset;
+ r=Kern::ThreadRawWrite(aClient, aArg2, &pack, (sizeof(TInt)*2), aClient);
+ }
+ }
+ break;
+ }
+
+ default:
+ r = KErrNotSupported;
+ break;
+ };
+ return r;
+ }
+
+
+/**
+ Open a shared Chunk for the User buffer and then set the appropriate values for the
+ User buffer node attributes.
+
+*/
+TInt DDisplayLdd::CheckAndOpenUserBuffer(TBufferNode* aNode, TInt aHandle, TInt aOffset, DThread* aClient)
+ {
+
+ TInt size = 0;
+ DChunk* chunk = 0;
+ TLinAddr kernelAddress = 0;
+ TUint32 mapAttr = 0;
+ TUint32 physicalAddress = 0;
+ TUint32 *physicalPageList = 0;
+ TInt r = KErrBadHandle;
+
+ NKern::ThreadEnterCS();
+ chunk = Kern::OpenSharedChunk(aClient, aHandle, EFalse);
+ NKern::ThreadLeaveCS();
+ if(chunk)
+ {
+ // Using iOffsetBetweenLines rather than iWidth as the controller may be using stride
+ size = iDisplayInfo.iNormal.iOffsetBetweenLines * iDisplayInfo.iNormal.iHeight;
+
+ r = Kern::ChunkPhysicalAddress(chunk, aOffset, size, kernelAddress, mapAttr, physicalAddress, physicalPageList);
+ if( r == KErrNone )
+ {
+ aNode->iChunk = chunk;
+ aNode->iFree = EFalse;
+ aNode->iState = EBufferCompose;
+ aNode->iAddress = (TUint32)kernelAddress;
+ aNode->iHandle = aHandle;
+ aNode->iPhysicalAddress = physicalAddress;
+ }
+ else
+ { // we have an error here, close the chunk
+ r = KErrArgument;
+ Kern::ChunkClose(chunk);
+ }
+ }
+ return (r);
+ }
+
+
+/**
+ Return any free buffer when trying to register a User buffer( aBufferId ==0 )
+ or return the specified User buffer( used by Deregister and PostUserBuffer).
+ In the second case checks about the state of the user buffer are specific to
+ each case.
+
+*/
+TBufferNode* DDisplayLdd::FindUserBufferNode(TInt aBufferId)
+ {
+ TBufferNode* node = 0;
+
+ if(aBufferId == 0)
+ {
+ for(TInt i = 0; i < KDisplayUBMax; i++)
+ {
+ if(iUserBuffer[i].iFree)
+ {
+ node = &iUserBuffer[i];
+ break;
+ }
+ }
+ }
+ else
+ {
+ node = &iUserBuffer[aBufferId-1];
+ }
+ return (node);
+ }
+
+
+/**
+ Free user buffer by reseting all the appropriate fields and closing the corresponding chunk.
+*/
+TInt DDisplayLdd::FreeUserBufferNode(TBufferNode* aNode)
+ {
+ __DEBUG_PRINT2("FreeUserBufferNode with aNode->iAddress %08x.\n",aNode->iAddress );
+ TInt r = KErrNone;
+ NKern::ThreadEnterCS();
+ if(aNode->iChunk != 0)
+ {
+ r= Kern::ChunkClose(aNode->iChunk);
+ }
+ if( r== KErrNone)
+ {
+ aNode->iState = EBufferFree;
+ aNode->iFree = ETrue;
+ aNode->iAddress = 0;
+ aNode->iSize = 0;
+ aNode->iHandle = 0;
+ aNode->iChunk = 0;
+ }
+ else
+ {
+ __DEBUG_PRINT("Failed to close chunk\n");
+ }
+ NKern::ThreadLeaveCS();
+
+ return r;
+ }
+
+
+/**
+ Calls CompleteRequest( which internally sends a Kern::RequestComplete message )for the specified request and with the reason passed,
+ in case such an asynchronous request is pending. Also resets the pending queue fields for that request if it was actually pending.
+ Called by both the LDD and PDD.
+
+*/
+TInt DDisplayLdd::RequestComplete(TInt aRequest, TInt aReason)
+ {
+ TBool flag = EFalse;
+
+ switch (aRequest)
+ {
+ case RDisplayChannel::EReqGetCompositionBuffer:
+ {
+ __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqGetCompositionBuffer request and reason %d\n",aReason );
+
+ if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer].iStatus)
+ {
+ __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqGetCompositionBuffer \n");
+ flag = ETrue;
+ }
+ break;
+ }
+
+ case RDisplayChannel::EReqWaitForPost:
+ {
+ __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqWaitForPost request and reason %d\n",aReason );
+
+ if((iPendingReq[RDisplayChannel::EReqWaitForPost].iStatus != 0) && (iCurrentPostCount >= iRequestedPostCount) )
+ {
+ __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqWaitForPost \n");
+ flag = ETrue;
+ }
+ break;
+ }
+
+ case RDisplayChannel::EReqPostUserBuffer:
+ {
+ __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqPostUserBuffer request and reason %d\n",aReason );
+
+ if((iPendingReq[RDisplayChannel::EReqPostUserBuffer].iStatus != 0) )
+ {
+ __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqPostUserBuffer \n");
+ flag = ETrue;
+ }
+ break;
+ }
+ default:
+ __DEBUG_PRINT("RequestComplete() called for an unknown request\n");
+ return KErrGeneral;
+
+ }
+
+ if (flag)
+ {
+ CompleteRequest(iPendingReq[aRequest].iOwningThread,iPendingReq[aRequest].iStatus,aReason);
+ iPendingReq[aRequest].iStatus = 0;
+ iPendingReq[aRequest].iOwningThread = 0;
+ }
+
+ return KErrNone;
+ }
+
+
+/**
+Complete an asynchronous request back to the client.
+@param aThread The client thread which issued the request.
+@param aStatus The TRequestStatus instance that will receive the request status code.
+@param aReason The request status code.
+@pre The thread must be in a critical section.
+*/
+void DDisplayLdd::CompleteRequest(DThread* aThread, TRequestStatus*& aStatus, TInt aReason)
+ {
+ Kern::RequestComplete(aThread,aStatus,aReason); // Complete the request back to the client.
+
+ aThread->AsyncClose(); // Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference.
+
+#ifdef _DEBUG
+ __e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1));
+#endif
+
+ }
+
+
+
+/**
+ static factory function for the LDD.
+
+ @return pointer to the created (or existing) instance of the class
+*/
+DDisplayLdd* DDisplayLdd::CreateInstance()
+ {
+ __DEBUG_PRINT("DDisplayLdd::CreateInstance()\n");
+ // create LDD channel instance
+ DDisplayLdd* obj = new DDisplayLdd();
+ return obj;
+
+ }
+
+
+/************************************************************************************
+ * LDD factory, DDisplayLddFactory class implementation
+ ************************************************************************************/
+
+/**
+ Constructor
+*/
+DDisplayLddFactory::DDisplayLddFactory()
+ {
+ __DEBUG_PRINT("DDisplayLddFactory::DDisplayLddFactory() \n");
+
+ iParseMask = KDeviceAllowPhysicalDevice | KDeviceAllowUnit ;
+
+ iVersion = TVersion( KDisplayChMajorVersionNumber,
+ KDisplayChMinorVersionNumber,
+ KDisplayChBuildVersionNumber);
+
+ iUnitsOpenMask =0;
+ }
+
+
+/**
+ Destructor
+*/
+DDisplayLddFactory::~DDisplayLddFactory()
+ {
+ }
+
+
+/**
+ static factory function for the LDD factory.
+
+ @return pointer to the created instance of the class
+*/
+DDisplayLddFactory* DDisplayLddFactory::CreateInstance()
+
+ {
+ __DEBUG_PRINT("DDisplayLddFactory::CreateInstance() \n");
+
+ DDisplayLddFactory* obj = new DDisplayLddFactory;
+ return obj;
+ }
+
+
+/**
+ Set our name and return error code
+*/
+TInt DDisplayLddFactory::Install()
+
+ {
+ __DEBUG_PRINT("DDisplayLddFactory::Install() \n");
+ return SetName(&RDisplayChannel::Name());
+ }
+
+
+void DDisplayLddFactory::GetCaps(TDes8& /*aDes*/) const
+
+ {
+ //No action.
+ }
+
+
+/**
+ LDD factory function. Creates LDD object.
+
+ @param aChannel A pointer to an LDD channel object which will be initialised on return.
+
+ @return KErrNone if object successfully allocated, KErrNoMemory if not.
+*/
+TInt DDisplayLddFactory::Create(DLogicalChannelBase*& aChannel)
+ {
+ __DEBUG_PRINT("DDisplayLddFactory::Create \n");
+ aChannel = DDisplayLdd::CreateInstance();
+ return (!aChannel)? KErrNoMemory : KErrNone;
+ }
+
+
+
+/**
+Check whether a channel is currently open on the specified unit.
+@param aUnit The number of the unit to be checked.
+@return ETrue if a channel is open on the specified channel, EFalse otherwise.
+@pre The unit info. mutex must be held.
+*/
+TBool DDisplayLddFactory::IsUnitOpen(TInt aUnit)
+ {
+ return(iUnitsOpenMask&(1<<aUnit));
+ }
+
+
+/**
+Attempt to change the state of the channel open status for a particular channel.
+@param aUnit The number of the unit to be updated.
+@param aIsOpenSetting The required new state for the channel open status: either ETrue to set the status to open or
+ EFalse to set the status to closed.
+@return KErrNone if the status was updated successfully, KErrInUse if an attempt has been made to set the channnel status
+ to open while it is already open.
+*/
+TInt DDisplayLddFactory::SetUnitOpen(TInt aUnit,TBool aIsOpenSetting)
+ {
+
+ NKern::FMWait(&iUnitInfoMutex); // Acquire the unit info. mutex.
+
+ // Fail a request to open an channel that is already open
+ if (aIsOpenSetting && IsUnitOpen(aUnit))
+ {
+ NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
+ return(KErrInUse);
+ }
+
+ // Update the open status as requested
+ if (aIsOpenSetting)
+ iUnitsOpenMask|=(1<<aUnit);
+ else
+ iUnitsOpenMask&=~(1<<aUnit);
+
+ NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
+ return(KErrNone);
+ }
+
+
+/**
+ "Standard LDD" entrypoint.
+
+ Is called on CreateLogicalDevice() if the user calls LoadLogicalDevice(). Creates LDD factory.
+
+ @return pointer to the LDD factory object.
+*/
+DECLARE_STANDARD_LDD()
+ {
+ __DEBUG_PRINT("DECLARE_STANDARD_LDD() \n");
+ DDisplayLddFactory* pLDDFactory = DDisplayLddFactory::CreateInstance();
+ return pLDDFactory;
+ }
+
+
+
+