sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // os\kernelhwsrv\kernel\eka\drivers\display\display.cpp sl@0: // LDD for a Display driver with GCE support sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalTechnology sl@0: @prototype sl@0: */ sl@0: sl@0: sl@0: #include sl@0: #include sl@0: sl@0: sl@0: const TUint8 KMutexOrder = 0x3f; sl@0: sl@0: static const char KDisplayLddPanic[] ="DISPLAY/GCE LDD"; sl@0: sl@0: _LIT(KClientRequestMutex, "ClientRequestMutex"); sl@0: sl@0: sl@0: /************************************************************************************ sl@0: * DDisplayLdd LDD class implementation sl@0: ************************************************************************************/ sl@0: DDisplayLdd::DDisplayLdd() sl@0: { sl@0: __DEBUG_PRINT("DDisplayLdd::DDisplayLdd()\n"); sl@0: // store the pointer to the current thread for request completion sl@0: iClient = &Kern::CurrentThread(); sl@0: __NK_ASSERT_DEBUG(iClient); sl@0: // Open a reference on the client thread so it's control block can't disappear until the driver has finished with it. sl@0: iClient->Open(); sl@0: iCurrentPostCount = 0; sl@0: iRequestedPostCount = 0; sl@0: iCompositionBuffIdx = 0; sl@0: iUnit = -1; sl@0: iThreadOpenCount = 0; sl@0: iAsyncReqCount = 0; sl@0: iClientRequestMutex = 0; sl@0: } sl@0: sl@0: sl@0: DDisplayLdd::~DDisplayLdd() sl@0: { sl@0: __DEBUG_PRINT("DDisplayLdd::~DDisplayLdd() \n"); sl@0: // cancel outstanding requests and destroy the queue of TClientRequest objects sl@0: for(TInt k = 0; k < KPendingReqArraySize ; k++) sl@0: { sl@0: for(TInt i = 0; i < KMaxQueuedRequests; i++) sl@0: { sl@0: //Method IsReady() returns true if the client’s request SetStatus method has been called but the sl@0: //coresponding QueueRequestComplete method hasn't. sl@0: if(iPendingReq[k][i].iTClientReq) sl@0: { sl@0: if(iPendingReq[k][i].iTClientReq->IsReady() ) sl@0: { sl@0: CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel); sl@0: } sl@0: } sl@0: Kern::DestroyClientRequest(iClientRequest[k][i]); sl@0: } sl@0: } sl@0: sl@0: //Close User Buffer chunks not yet destroyed. sl@0: for(TInt i = 0; i < KDisplayUBMax; i++) sl@0: { sl@0: if(iUserBuffer[i].iChunk != 0) sl@0: { sl@0: Kern::ChunkClose(iUserBuffer[i].iChunk); sl@0: iUserBuffer[i].iChunk= NULL; sl@0: } sl@0: } sl@0: sl@0: Kern::SafeClose((DObject*&)iClient, NULL); sl@0: sl@0: sl@0: if (iClientRequestMutex != NULL) sl@0: { sl@0: iClientRequestMutex->Close(NULL); sl@0: } sl@0: sl@0: __ASSERT_DEBUG(iThreadOpenCount == 0,Kern::Fault(KDisplayLddPanic,__LINE__)); sl@0: __ASSERT_DEBUG(iAsyncReqCount == 0,Kern::Fault(KDisplayLddPanic,__LINE__)); sl@0: sl@0: // Clear the 'units open mask' in the LDD factory. sl@0: if (iUnit>=0) sl@0: ((DDisplayLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse); sl@0: sl@0: #ifdef _DEBUG sl@0: // Close the UDEB user mode chunk, if it exists sl@0: if (iChunk) sl@0: Kern::ChunkClose(iChunk); sl@0: #endif // _DEBUG sl@0: } sl@0: sl@0: sl@0: /** sl@0: LDD second stage constructor sl@0: */ sl@0: TInt DDisplayLdd::DoCreate(TInt aUnit, const TDesC8* /* anInfo*/, const TVersion& aVer) sl@0: { sl@0: sl@0: __DEBUG_PRINT("DDisplayLdd::DoCreate()\n"); sl@0: sl@0: if( !Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) sl@0: || !Kern::CurrentThreadHasCapability(ECapabilityReadDeviceData, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) sl@0: || !Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) sl@0: || !Kern::CurrentThreadHasCapability(ECapabilityProtServ, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) ) sl@0: { sl@0: return KErrPermissionDenied; sl@0: } sl@0: sl@0: // Check that the display driver version specified by the client is compatible. sl@0: if (!Kern::QueryVersionSupported(RDisplayChannel::VersionRequired(),aVer)) sl@0: { sl@0: return(KErrNotSupported); sl@0: } sl@0: sl@0: // Check that a channel hasn't already been opened on this unit. sl@0: TInt r=((DDisplayLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory. sl@0: if (r!=KErrNone) sl@0: return r; sl@0: iUnit=aUnit; sl@0: sl@0: Pdd()->iLdd = this; sl@0: sl@0: r = Pdd()->CreateChannelSetup(aUnit); sl@0: if ( r!= KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: // set up user buffer nodes sl@0: for (TInt node = 0; node < KDisplayUBMax; node++) sl@0: { sl@0: iUserBuffer[node].iType = EBufferTypeUser; sl@0: iUserBuffer[node].iBufferId = (node + 1); sl@0: iUserBuffer[node].iFree = ETrue; sl@0: iUserBuffer[node].iState = EBufferFree; sl@0: iUserBuffer[node].iAddress = 0; sl@0: iUserBuffer[node].iSize = 0; sl@0: iUserBuffer[node].iHandle = 0; sl@0: iUserBuffer[node].iChunk = 0; sl@0: iUserBuffer[node].iOffset = 0; sl@0: iUserBuffer[node].iPendingRequest = 0; sl@0: } sl@0: sl@0: //Initialise pending queue for asynchronous requests and queue of TClientRequests sl@0: for(TInt k = 0; k < KPendingReqArraySize; k++) sl@0: { sl@0: sl@0: iPendingIndex[k]=0; sl@0: sl@0: for(TInt i = 0; i < KMaxQueuedRequests; i++) sl@0: { sl@0: iPendingReq[k][i].iTClientReq = 0; sl@0: iPendingReq[k][i].iOwningThread = 0; sl@0: sl@0: sl@0: r = Kern::CreateClientRequest(iClientRequest[k][i]); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: } sl@0: } sl@0: sl@0: r = Kern::MutexCreate(iClientRequestMutex, KClientRequestMutex, KMutexOrder); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: sl@0: Pdd()->SetGceMode(); sl@0: SetDfcQ(Pdd()->DfcQ(aUnit)); sl@0: iMsgQ.Receive(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Override DLogicalChannel::SendMsg to process a client message before and after sending the message sl@0: to the DFC thread for processing by HandleMsg(). sl@0: sl@0: This function is called in the context of the client thread. sl@0: sl@0: The function is used to pin client data in the context of the client thread, so that data can be safely sl@0: accessed from kernel threads without the possibility of taking page faults. sl@0: sl@0: @param aMsg The message to process. sl@0: The iValue member of this distinguishes the message type: sl@0: iValue==ECloseMsg, channel close message sl@0: iValue==KMaxTInt, a 'DoCancel' message sl@0: iValue>=0, a 'DoControl' message with function number equal to iValue sl@0: iValue<0, a 'DoRequest' message with function number equal to ~iValue sl@0: sl@0: @return KErrNone if the message was send successfully, otherwise one of the other system-wide error sl@0: codes. sl@0: sl@0: */ sl@0: sl@0: TInt DDisplayLdd::SendMsg(TMessageBase* aMsg) sl@0: { sl@0: TThreadMessage& m=*(TThreadMessage*)aMsg; sl@0: TInt id = m.iValue; sl@0: sl@0: TInt r = KErrNone; sl@0: // close msg or cancel sl@0: if (id == (TInt)ECloseMsg || id == KMaxTInt) sl@0: { sl@0: r = DLogicalChannel::SendMsg(aMsg); sl@0: } sl@0: //asynchronous request sl@0: else if (id < 0) sl@0: { sl@0: TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); sl@0: r = SendRequest(aMsg); sl@0: if (r != KErrNone) sl@0: Kern::RequestComplete(pS,r); sl@0: } sl@0: // synchronous request sl@0: else{ sl@0: r = SendControl(aMsg); sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Validate, pre-process, send and post-process data for an asynchronous client request, so that data can be safely sl@0: accessed from kernel threads without the possibility of taking page faults. sl@0: sl@0: This function is called in the context of the client thread. sl@0: sl@0: @param aMsg The message to process. sl@0: The iValue member of this distinguishes the message type: sl@0: iValue==ECloseMsg, channel close message sl@0: iValue==KMaxTInt, a 'DoCancel' message sl@0: iValue>=0, a 'DoControl' message with function number equal to iValue sl@0: iValue<0, a 'DoRequest' message with function number equal to ~iValue sl@0: sl@0: @return KErrNone if the message was send successfully, otherwise one of the other system-wide error sl@0: codes. sl@0: */ sl@0: TInt DDisplayLdd::SendRequest(TMessageBase* aMsg) sl@0: { sl@0: TThreadMessage& m =*(TThreadMessage*)aMsg; sl@0: TInt aReqNumber = ~m.iValue; sl@0: TRequestStatus* pS =(TRequestStatus*)m.Ptr0(); sl@0: sl@0: #ifdef _GCE_DISPLAY_DEBUG sl@0: DThread* client = m.Client(); sl@0: #endif sl@0: sl@0: TInt r = KErrNotSupported; sl@0: TInt pendingIndex; sl@0: sl@0: /*Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. sl@0: Using thread local copies is possible even for asynchronous requests, since the values to be returned are known sl@0: when processing the request( inside DoRequest ) and not at a later stage.*/ sl@0: sl@0: TInt kernelCompBuffIdx; sl@0: TInt kernelpack[2]; sl@0: RDisplayChannel::TPostCount kernelCount; sl@0: sl@0: sl@0: //In asynchronous requests m.Ptr0 is used for the TRequestStatus object. sl@0: TAny* userConfigData1 = m.Ptr1(); sl@0: TAny* userConfigData2 = m.Ptr2(); sl@0: sl@0: /* sl@0: If the client request needs to pass some data to the DFC thread then we copy these to a thread local sl@0: copy(created in the thread supervisor stack) and then update the message to point to that local copy. sl@0: If the client will have to read a value updated in the DFC thread, then the message should just be sl@0: updated and point to the local copy. After the request has completed the updated data will be copied sl@0: from the local copy to the client, in the context of the client thread. sl@0: */ sl@0: sl@0: switch (aReqNumber) sl@0: { sl@0: case RDisplayChannel::EReqGetCompositionBuffer: //Client should read data updated in the DFC thread. sl@0: m.iArg[1] = &kernelCompBuffIdx; sl@0: break; sl@0: sl@0: case RDisplayChannel::EReqPostUserBuffer: //Both the client and DFC thread need to read data. sl@0: umemget32(&kernelpack, userConfigData1, (sizeof(TInt)*2) ); sl@0: m.iArg[1] = &kernelpack; sl@0: m.iArg[2] = &kernelCount; sl@0: break; sl@0: sl@0: case RDisplayChannel::EReqWaitForPost: //Client data should be passed to the DFC thread. sl@0: umemget32(&kernelCount, userConfigData1, sizeof(RDisplayChannel::TPostCount) ); sl@0: m.iArg[1] = &kernelCount; sl@0: break; sl@0: default: sl@0: return KErrNotSupported; sl@0: sl@0: } sl@0: sl@0: /* sl@0: The TClientRequest objects associated with each asynchronous request need to be accessed by both the client and DFC sl@0: threads. To resolve the potential synchronization problem we maintain two seperate pointers(iClientRequest and sl@0: iPendingReq.iClientReq )to the same TClientRequest object. iClientRequestMutex is used to synchronise access to sl@0: iClientRequest from different client threads. The first client thread that acquires the mutex will set the status sl@0: of an available TClientRequest object and send the message(call SendMsg). Consequently method DoRequest is queued for sl@0: execution by the DFC thread. DoRequest initialy saves iClientRequest to iPendingReq.iClientReq and queues the request. sl@0: Only then, the mutex is signaled. Another client thread trying to access iClientRequest will block in the mutex until sl@0: DoRequest has updated iPendingReq.iClientReq. Even more the DFC thread only accesses iClientRequest in DoRequest and sl@0: then iPendingReq.iClientReq is only used, so synchronizing access to iPendingReq.iClientReq is handled by the DFC queue. sl@0: */ sl@0: sl@0: // Need to be in critical section whilst holding a DMutex sl@0: NKern::ThreadEnterCS(); sl@0: sl@0: Kern::MutexWait(*iClientRequestMutex); sl@0: //Save the TRequestStatus in any available TClientRequest object for that asynchronous request. sl@0: sl@0: for( TInt k=0; k< KMaxQueuedRequests; k++) sl@0: { sl@0: //setStatus will return KErrInUse if a previous client request hasn't completed yet. sl@0: r = iClientRequest[aReqNumber][k]->SetStatus(pS); sl@0: if( r == KErrNone) sl@0: { sl@0: pendingIndex = k; sl@0: //The current available index for this pending request will be passed as sl@0: //another message argument to the DFC thread. sl@0: m.iArg[3] = (TAny*) pendingIndex; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: r = DLogicalChannel::SendMsg(aMsg); sl@0: } sl@0: else sl@0: { sl@0: __DEBUG_PRINT3("Client %08x trying to issue asynchronous request %d", client, aReqNumber); sl@0: //Fail if there aren't any available TClientRequest object sl@0: __ASSERT_DEBUG(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__)); sl@0: } sl@0: sl@0: Kern::MutexSignal(*iClientRequestMutex); sl@0: sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: //Copy config data from local copies to client, in context of client thread sl@0: switch (aReqNumber) sl@0: { sl@0: case RDisplayChannel::EReqGetCompositionBuffer: sl@0: __DEBUG_PRINT2("EReqGetCompositionBuffer: kernelCompBuffIdx returned =%d",kernelCompBuffIdx); sl@0: umemput32(userConfigData1, &kernelCompBuffIdx, sizeof(TInt) ); sl@0: break; sl@0: sl@0: case RDisplayChannel::EReqPostUserBuffer: sl@0: __DEBUG_PRINT2("EReqPostUserBuffer: kernelCount returned = %d",kernelCount); sl@0: umemput32(userConfigData2, &kernelCount, sizeof(RDisplayChannel::TPostCount) ); sl@0: break; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Validate, pre-process, send and post-process data for a synchronous client request, so that data can be safely sl@0: accessed from kernel threads without the possibility of taking page faults. sl@0: sl@0: This function is called in the context of the client thread. sl@0: sl@0: @param aMsg The message to process. sl@0: The iValue member of this distinguishes the message type: sl@0: iValue==ECloseMsg, channel close message sl@0: iValue==KMaxTInt, a 'DoCancel' message sl@0: iValue>=0, a 'DoControl' message with function number equal to iValue sl@0: iValue<0, a 'DoRequest' message with function number equal to ~iValue sl@0: sl@0: @return KErrNone if the message was send successfully, otherwise one of the other system-wide error sl@0: codes. sl@0: */ sl@0: sl@0: TInt DDisplayLdd::SendControl(TMessageBase* aMsg) sl@0: { sl@0: TThreadMessage& m = *(TThreadMessage*)aMsg; sl@0: TInt aReqNumber = m.iValue; sl@0: sl@0: sl@0: //Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. sl@0: sl@0: RDisplayChannel::TPostCount kernelPostCount; sl@0: RDisplayChannel::TDisplayRotation kernelRotation; sl@0: sl@0: TPckgBuf pckgInfo(iDisplayInfo); sl@0: sl@0: TInt kernelpack[2]; sl@0: TInt kernelBufferId; sl@0: TBool kernelRotChanged; sl@0: TInt kernelIndex; sl@0: sl@0: TAny* userConfigData0 = m.Ptr0(); sl@0: TAny* userConfigData1 = m.Ptr1(); sl@0: sl@0: sl@0: switch (aReqNumber) sl@0: { sl@0: //iDisplayInfo doesn't change after the driver initialisation so copy in client thread context sl@0: case RDisplayChannel::ECtrlGetDisplayInfo: sl@0: umemput32(userConfigData0, &pckgInfo, sizeof(TPckgBuf) ); sl@0: return KErrNone; sl@0: sl@0: case RDisplayChannel::ECtrlPostCompositionBuffer: //Client should read data updated in the DFC thread. sl@0: m.iArg[1] = &kernelPostCount; sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlPostLegacyBuffer: //Client should read data updated in the DFC thread. sl@0: m.iArg[1] = &kernelPostCount; sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlRegisterUserBuffer: //Both the client and DFC thread need to read data. sl@0: umemget32(&kernelpack, userConfigData0, (sizeof(TInt)*2) ); sl@0: m.iArg[0] = &kernelpack; sl@0: m.iArg[1] = &kernelBufferId; sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlDeregisterUserBuffer: //Client data should be passed to the DFC thread. sl@0: umemget32(&kernelBufferId, userConfigData0, sizeof(TInt) ); sl@0: m.iArg[0] = &kernelBufferId; sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlSetRotation: //Both the client and DFC thread need to read data. sl@0: umemget32(&kernelRotation, userConfigData0, sizeof(RDisplayChannel::TDisplayRotation) ); sl@0: m.iArg[0] = &kernelRotation; sl@0: m.iArg[1] = &kernelRotChanged; sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlCurrentRotation: //Client should read data updated in the DFC thread. sl@0: m.iArg[0] = &kernelRotation; sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlGetCompositionBufferInfo: //Both the client and DFC thread need to read data. sl@0: umemget32(&kernelIndex, userConfigData0, sizeof(TInt) ); sl@0: m.iArg[0] = &kernelIndex; sl@0: m.iArg[1] = &kernelpack; sl@0: break; sl@0: sl@0: #ifdef _DEBUG sl@0: case RDisplayChannel::ECtrlCreateUserBuffer: sl@0: m.iArg[0] = userConfigData0; sl@0: m.iArg[1] = userConfigData1; sl@0: break; sl@0: #endif // _DEBUG sl@0: sl@0: default: sl@0: return KErrNotSupported; sl@0: sl@0: } sl@0: sl@0: TInt r = DLogicalChannel::SendMsg(aMsg); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: //Copy config data from local copies to client, in context of client thread sl@0: switch (aReqNumber) sl@0: { sl@0: case RDisplayChannel::ECtrlPostCompositionBuffer: sl@0: __DEBUG_PRINT2("ECtrlPostCompositionBuffer =%d", kernelPostCount ); sl@0: umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) ); sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlPostLegacyBuffer: sl@0: __DEBUG_PRINT2("ECtrlPostLegacyBuffer=%d", kernelPostCount ); sl@0: umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) ); sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlRegisterUserBuffer: sl@0: __DEBUG_PRINT2("ECtrlRegisterUserBuffer kernelBufferId=%d", kernelBufferId ); sl@0: umemput32(userConfigData1, &kernelBufferId, sizeof(TInt) ); sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlSetRotation: sl@0: __DEBUG_PRINT2("ECtrlSetRotation kernelRotChanged=%d", kernelRotChanged ); sl@0: umemput32(userConfigData1, &kernelRotChanged, sizeof(TBool) ); sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlCurrentRotation: sl@0: __DEBUG_PRINT2("ECtrlCurrentRotation kernelRotation=%d", kernelRotation ); sl@0: umemput32(userConfigData0, &kernelRotation, sizeof(RDisplayChannel::TDisplayRotation) ); sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlGetCompositionBufferInfo: sl@0: __DEBUG_PRINT3("ECtrlGetCompositionBufferInfo kernelpack[0] =%d and kernelpack[1] =%d", kernelpack[0], kernelpack[1]); sl@0: umemput32(userConfigData1, &kernelpack, (sizeof(TInt)*2) ); sl@0: break; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: All driver's client requests (synchronous and asynchronous) are sent as sl@0: kernel messages by generic kernel to logical channel. This function sl@0: catches messages sent by the generic kernel. sl@0: sl@0: @param aMsg Kernel side thread message to process. sl@0: sl@0: The iValue member of this distinguishes the message type: sl@0: iValue==ECloseMsg, channel close message sl@0: iValue==KMaxTInt, a 'DoCancel' message sl@0: iValue>=0, a 'DoControl' message with function number equal to iValue sl@0: iValue<0, a 'DoRequest' message with function number equal to ~iValue sl@0: */ sl@0: void DDisplayLdd::HandleMsg(TMessageBase* aMsg) sl@0: { sl@0: TThreadMessage& m = *(TThreadMessage*)aMsg ; sl@0: TInt id = m.iValue ; sl@0: DThread* client = m.Client(); sl@0: sl@0: // close message sl@0: if (id == (TInt)ECloseMsg) sl@0: { sl@0: //Device specific cleanup operations sl@0: Pdd()->CloseMsg(); sl@0: sl@0: // cancel outstanding requests sl@0: for(TInt k = 0; k < KPendingReqArraySize; k++) sl@0: { sl@0: for(TInt i = 0; i < KMaxQueuedRequests; i++) sl@0: { sl@0: if( iPendingReq[k][i].iTClientReq) sl@0: { sl@0: if(iPendingReq[k][i].iTClientReq->IsReady() ) sl@0: { sl@0: CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel); sl@0: } sl@0: } sl@0: } sl@0: } sl@0: Pdd()->SetLegacyMode(); sl@0: m.Complete(KErrNone, EFalse); sl@0: return; sl@0: } sl@0: // cancel sl@0: if (id == KMaxTInt) sl@0: { sl@0: // DoCancel sl@0: TInt req = m.Int0() >> 1; sl@0: DoCancel(req); sl@0: m.Complete(KErrNone,ETrue); sl@0: return; sl@0: } sl@0: // asynchronous request sl@0: else if (id < 0) sl@0: { sl@0: //m.Int3() is the index, in the array of pending requests, to be used. sl@0: TInt r = DoRequest(~id,m.Ptr1(),m.Ptr2(),m.Int3(), client); sl@0: m.Complete(r, ETrue); sl@0: } sl@0: // synchronous request sl@0: else sl@0: { sl@0: TInt r = DoControl(id,m.Ptr0(),m.Ptr1(), client); sl@0: m.Complete(r,ETrue); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Cancel outstanding request. sl@0: sl@0: @param aReqNumber Any value from the RDisplayChannel::TRequest enumeration. sl@0: */ sl@0: void DDisplayLdd::DoCancel(TUint aReqNumber) sl@0: { sl@0: __DEBUG_PRINT2("DDisplayLdd::DoCancel %d\n",aReqNumber); sl@0: sl@0: switch (aReqNumber) sl@0: { sl@0: case RDisplayChannel::ECtrlCancelGetCompositionBuffer: sl@0: case RDisplayChannel::ECtrlCancelPostUserBuffer: sl@0: case RDisplayChannel::ECtrlCancelWaitForPost: sl@0: TInt pendingIndex = iPendingIndex[aReqNumber]; sl@0: if(iPendingReq[aReqNumber][pendingIndex].iTClientReq) sl@0: { sl@0: if( iPendingReq[aReqNumber][pendingIndex].iTClientReq->IsReady() ) sl@0: { sl@0: CompleteRequest(iPendingReq[aReqNumber][pendingIndex].iOwningThread,iPendingReq[aReqNumber][pendingIndex].iTClientReq,KErrCancel); sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: sl@0: } sl@0: sl@0: /** sl@0: Asynchronous request processing. sl@0: sl@0: @param aFunction Request function number sl@0: @param apArg1 Pointer to kernel message argument 1. sl@0: @param apArg2 Pointer to kernel message argument 2. sl@0: @param aPendingIndex Index pointing to the appropriate TClientRequest object to use. sl@0: @param aClient Pointer to the client thread that issued the asynchronous request. sl@0: sl@0: @return request scheduling result, system-wide error code. sl@0: */ sl@0: TInt DDisplayLdd::DoRequest(TInt aReqNumber, TAny* aArg1, TAny* aArg2, TInt aPendingIndex, DThread* aClient) sl@0: { sl@0: sl@0: TInt pack[2]; sl@0: TInt r = KErrNone; sl@0: TBufferNode* node = 0; sl@0: TInt buffer_id = 0; sl@0: sl@0: TInt* configBufferIdx ; sl@0: RDisplayChannel::TPostCount* postCount; sl@0: TInt* configPack; sl@0: sl@0: __DEBUG_PRINT5("DoRequest: iClientRequest[aReqNumber=%d][aPendingIndex=%d] is %08x and aClient=%08x\n",aReqNumber, aPendingIndex,iClientRequest[aReqNumber][aPendingIndex], aClient); sl@0: sl@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. sl@0: r=aClient->Open(); sl@0: __ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__)); sl@0: #ifdef _DEBUG sl@0: __e32_atomic_add_ord32(&iThreadOpenCount, 1); sl@0: #endif sl@0: sl@0: for(TInt i = 0; i < KMaxQueuedRequests; i++) sl@0: { sl@0: //Don't cancel the asyncrhonous request we currently process. sl@0: if (i == aPendingIndex) sl@0: { sl@0: continue; sl@0: } sl@0: // cancel outstanding request sl@0: if(iPendingReq[aReqNumber][i].iTClientReq) sl@0: { sl@0: //If IsReady() returns true, setStatus has been called for that TCientRequest but QueueRequestComplete hasn't. sl@0: //In that case we want to cancel this outstanding request. Given that all QueueRequestComplete calls execute sl@0: // in the same DFC thread we currently run, there is no need to synchronise request completion calls. sl@0: if(iPendingReq[aReqNumber][i].iTClientReq->IsReady() ) sl@0: { sl@0: CompleteRequest(iPendingReq[aReqNumber][i].iOwningThread,iPendingReq[aReqNumber][i].iTClientReq,KErrCancel); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: // store index, request and client sl@0: iPendingIndex[aReqNumber] = aPendingIndex; sl@0: iPendingReq[aReqNumber][aPendingIndex].iTClientReq = iClientRequest[aReqNumber][aPendingIndex]; sl@0: iPendingReq[aReqNumber][aPendingIndex].iOwningThread = aClient; sl@0: sl@0: #ifdef _DEBUG sl@0: __e32_atomic_add_ord32(&iAsyncReqCount, 1); sl@0: #endif sl@0: sl@0: switch (aReqNumber) sl@0: { sl@0: case RDisplayChannel::EReqGetCompositionBuffer: //DFC thread updates a value the client thread should read. sl@0: { sl@0: configBufferIdx = (TInt*) aArg1; sl@0: sl@0: TInt index; sl@0: TBool found = EFalse; sl@0: sl@0: for(index = 0; index < (TInt) iDisplayInfo.iNumCompositionBuffers; index++) sl@0: { sl@0: if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose ) sl@0: { sl@0: __DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index); sl@0: sl@0: iCompositionBuffIdx = index; sl@0: *configBufferIdx = iCompositionBuffIdx; sl@0: iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose; sl@0: CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread,iPendingReq[aReqNumber][aPendingIndex].iTClientReq,r); sl@0: found = ETrue; sl@0: break; sl@0: } sl@0: } sl@0: if(!found) //There are no free buffers schedule request for completion sl@0: { sl@0: //Case of a single composition buffer. sl@0: if (iDisplayInfo.iNumCompositionBuffers == 1) sl@0: { sl@0: iCompositionBuffIdx = 0; sl@0: *configBufferIdx = iCompositionBuffIdx; sl@0: CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread, iPendingReq[aReqNumber][aPendingIndex].iTClientReq, r); sl@0: __DEBUG_PRINT("EReqGetCompositionBuffer The single Composition buffer is currently being used\n"); sl@0: break; sl@0: } sl@0: sl@0: sl@0: for( index=0; index< KDisplayCBMax; index++) sl@0: { sl@0: if(iCompositionBuffer[index].iState == EBufferActive) sl@0: { sl@0: iCompositionBuffIdx = index; sl@0: *configBufferIdx = iCompositionBuffIdx; sl@0: __DEBUG_PRINT2("EReqGetCompositionBuffer No composition buffer available. Next available is iCompositionBuffIdx %d.\n",iCompositionBuffIdx ); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: break; sl@0: } sl@0: sl@0: case RDisplayChannel::EReqPostUserBuffer: //DFC thread should read client message data and update a value the client will read. sl@0: configPack = (TInt*) aArg1; sl@0: pack[0] = *configPack; sl@0: configPack++; sl@0: pack[1] = *configPack; sl@0: sl@0: r = KErrArgument; sl@0: buffer_id = pack[0]; sl@0: if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) ) sl@0: { sl@0: node = FindUserBufferNode(buffer_id); sl@0: if(node && (!(node->iFree) && node->iChunk ) ) sl@0: { sl@0: __DEBUG_PRINT2("EReqPostUserBuffer Posting buffer id: %d \n",buffer_id ); sl@0: r = Pdd()->PostUserBuffer(node); sl@0: if(r == KErrNone) sl@0: { sl@0: postCount = (RDisplayChannel::TPostCount*) aArg2; sl@0: ++iCurrentPostCount; sl@0: *postCount= iCurrentPostCount; sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: RequestComplete(RDisplayChannel::EReqPostUserBuffer, r); sl@0: sl@0: break; sl@0: sl@0: case RDisplayChannel::EReqWaitForPost: //DFC thread should read client message data. sl@0: postCount = (RDisplayChannel::TPostCount*) aArg1; sl@0: iRequestedPostCount = *postCount; sl@0: sl@0: //Any post operation increases iCurrentPostCount instantly but the actual post completes later on. sl@0: if( ! Pdd()->PostPending() ) sl@0: { sl@0: RequestComplete(RDisplayChannel::EReqWaitForPost, KErrNone); sl@0: } sl@0: break; sl@0: sl@0: default: sl@0: __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Synchronous requests processing. sl@0: sl@0: @param aFunction Request function number, sl@0: @param apArg1 Pointer to kernel message argument 0. sl@0: @param apArg2 Pointer to kernel message argument 1. sl@0: @param aClient Pointer to the client thread that issued the synchronous request. sl@0: sl@0: @return request processing result sl@0: */ sl@0: TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient) sl@0: { sl@0: TInt r = KErrNone; sl@0: TBool changedRot = ETrue; sl@0: TBufferNode* node = 0; sl@0: TInt buffer_id; sl@0: TInt pack[2] = {0,0}; sl@0: TInt handle, offset; sl@0: TInt index = 0; sl@0: sl@0: RDisplayChannel::TPostCount *postCount ; sl@0: RDisplayChannel::TDisplayRotation *rotation; sl@0: sl@0: TInt *configPack; sl@0: TInt *bufferId; sl@0: sl@0: TBool *rotationChanged; sl@0: TInt *idx; sl@0: sl@0: switch (aFunction) sl@0: { sl@0: case RDisplayChannel::ECtrlPostCompositionBuffer: //DFC thread updates a value the client thread should read. sl@0: postCount = (RDisplayChannel::TPostCount*) aArg2; sl@0: sl@0: node = &iCompositionBuffer[iCompositionBuffIdx]; sl@0: r = Pdd()->PostCompositionBuffer(node); sl@0: if(r == KErrNone) sl@0: { sl@0: ++iCurrentPostCount; sl@0: *postCount = iCurrentPostCount; sl@0: } sl@0: else sl@0: { sl@0: r = KErrGeneral; sl@0: } sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlPostLegacyBuffer: //DFC thread updates a value the client thread should read. sl@0: postCount = (RDisplayChannel::TPostCount*) aArg2; sl@0: r= Pdd()->PostLegacyBuffer(); sl@0: if ( r == KErrNone) sl@0: { sl@0: ++iCurrentPostCount; sl@0: *postCount = iCurrentPostCount; sl@0: } sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlRegisterUserBuffer: //DFC thread should read client message data and update a value the client will read. sl@0: node = FindUserBufferNode(0); sl@0: if(node) sl@0: { sl@0: configPack = (TInt*) aArg1; sl@0: handle = *configPack; sl@0: configPack++; sl@0: offset = *configPack; sl@0: r = CheckAndOpenUserBuffer(node, handle, offset, aClient); sl@0: sl@0: if(r == KErrNone) sl@0: { sl@0: bufferId = (TInt*) aArg2; sl@0: *bufferId = node->iBufferId; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: r = KErrTooBig; sl@0: } sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlDeregisterUserBuffer: //DFC thread should read client message data. sl@0: bufferId = (TInt*) aArg1; sl@0: buffer_id = *bufferId; sl@0: sl@0: sl@0: r = KErrArgument; sl@0: if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) ) sl@0: { sl@0: node = FindUserBufferNode(buffer_id); sl@0: if(node && (!(node->iFree) && node->iChunk ) ) sl@0: { sl@0: if(node->iState==EBufferFree || node->iState==EBufferCompose ) sl@0: { sl@0: r = FreeUserBufferNode(node); sl@0: } sl@0: else sl@0: { sl@0: r = KErrInUse; sl@0: } sl@0: } sl@0: } sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlSetRotation: //DFC thread should read client message data and update a value the client will read. sl@0: { sl@0: RDisplayChannel::TDisplayRotation rot; sl@0: RDisplayChannel::TDisplayRotation previousRot = iCurrentRotation; sl@0: sl@0: rotation = (RDisplayChannel::TDisplayRotation*) aArg1; sl@0: rot = *rotation; sl@0: sl@0: __DEBUG_PRINT3("ECtrlSetRotation previousRot= %d and rot =%d \n",previousRot, rot ); sl@0: sl@0: r = Pdd()->SetRotation(rot); sl@0: changedRot = (previousRot != iCurrentRotation); sl@0: if( r == KErrNone) sl@0: { sl@0: rotationChanged = (TBool*) aArg2; sl@0: *rotationChanged = changedRot ; sl@0: } sl@0: break; sl@0: } sl@0: sl@0: case RDisplayChannel::ECtrlCurrentRotation: //DFC thread updates a value the client thread should read. sl@0: rotation = (RDisplayChannel::TDisplayRotation*) aArg1; sl@0: *rotation = iCurrentRotation; sl@0: break; sl@0: sl@0: case RDisplayChannel::ECtrlGetCompositionBufferInfo: //DFC thread should read client message data and update a value the client will read. sl@0: idx = ( TInt * ) aArg1; sl@0: index = *idx; sl@0: sl@0: if( (index >= (TInt) iDisplayInfo.iNumCompositionBuffers ) || (index < 0 ) ) sl@0: { sl@0: r = KErrArgument; sl@0: break; sl@0: } sl@0: r = Kern::MakeHandleAndOpen(aClient, iCompositionBuffer[index].iChunk); sl@0: sl@0: if(r >= KErrNone) sl@0: { sl@0: pack[0] = r; sl@0: pack[1] = iCompositionBuffer[index].iOffset; sl@0: sl@0: configPack = (TInt * ) aArg2; sl@0: *configPack = pack[0]; sl@0: configPack++; sl@0: *configPack = pack[1]; sl@0: sl@0: r = KErrNone; sl@0: } sl@0: break; sl@0: sl@0: #ifdef _DEBUG sl@0: case RDisplayChannel::ECtrlCreateUserBuffer: sl@0: { sl@0: TUint32 chunkMapAttr; sl@0: TLinAddr chunkBase; sl@0: TPhysAddr physicalAddr; sl@0: RDisplayChannel::TBufferFormat bufferFormat; sl@0: sl@0: // Read the information from the user thread pertaining to the buffer to be allocated sl@0: Kern::ThreadRawRead(aClient, aArg1, &bufferFormat, sizeof(bufferFormat)); sl@0: sl@0: // Allocate a chunk that can be used as a user buffer. Don't worry about the # of bytes sl@0: // per pixel as this is UDEB only test code - just set it to 4 and that will ensure that sl@0: // it is large enough sl@0: TChunkCreateInfo chunkCreateInfo; sl@0: chunkCreateInfo.iType = TChunkCreateInfo::ESharedKernelSingle; sl@0: #ifndef __WINS__ sl@0: chunkCreateInfo.iMapAttr = EMapAttrFullyBlocking; sl@0: #endif // ! __WINS__ sl@0: chunkCreateInfo.iOwnsMemory = ETrue; sl@0: chunkCreateInfo.iDestroyedDfc = NULL; sl@0: chunkCreateInfo.iMaxSize = (bufferFormat.iSize.iWidth * bufferFormat.iSize.iHeight * 4); sl@0: sl@0: if ((r = Kern::ChunkCreate(chunkCreateInfo, iChunk, chunkBase, chunkMapAttr)) == KErrNone) sl@0: { sl@0: // Commit some contiguous physical RAM for use in the chunk sl@0: r = Kern::ChunkCommitContiguous(iChunk, 0, chunkCreateInfo.iMaxSize, physicalAddr); sl@0: sl@0: // And open a handle to the chunk that will be returned to user side for use in the user sl@0: // side's RChunk object sl@0: if (r == KErrNone) sl@0: r = Kern::MakeHandleAndOpen(aClient, iChunk); sl@0: else sl@0: { sl@0: Kern::ChunkClose(iChunk); sl@0: iChunk = NULL; sl@0: } sl@0: } sl@0: sl@0: break; sl@0: } sl@0: #endif // _DEBUG sl@0: sl@0: default: sl@0: __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number sl@0: }; sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Open a shared Chunk for the User buffer and then set the appropriate values for the sl@0: User buffer node attributes. sl@0: sl@0: */ sl@0: TInt DDisplayLdd::CheckAndOpenUserBuffer(TBufferNode* aNode, TInt aHandle, TInt aOffset, DThread* aClient) sl@0: { sl@0: sl@0: TInt size = 0; sl@0: DChunk* chunk = 0; sl@0: TLinAddr kernelAddress = 0; sl@0: TUint32 mapAttr = 0; sl@0: TUint32 physicalAddress = 0; sl@0: TUint32 *physicalPageList = 0; sl@0: TInt r = KErrBadHandle; sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: chunk = Kern::OpenSharedChunk(aClient, aHandle, EFalse); sl@0: NKern::ThreadLeaveCS(); sl@0: if(chunk) sl@0: { sl@0: sl@0: // Using iOffsetBetweenLines rather than iWidth as the controller may be using stride sl@0: size = iDisplayInfo.iNormal.iOffsetBetweenLines * iDisplayInfo.iNormal.iHeight; sl@0: sl@0: r = Kern::ChunkPhysicalAddress(chunk, aOffset, size, kernelAddress, mapAttr, physicalAddress, physicalPageList); sl@0: if( r == KErrNone ) sl@0: { sl@0: aNode->iChunk = chunk; sl@0: aNode->iFree = EFalse; sl@0: aNode->iState = EBufferCompose; sl@0: aNode->iAddress = (TUint32)kernelAddress; sl@0: aNode->iHandle = aHandle; sl@0: aNode->iPhysicalAddress = physicalAddress; sl@0: } sl@0: else sl@0: { // we have an error here, close the chunk sl@0: r = KErrArgument; sl@0: Kern::ChunkClose(chunk); sl@0: } sl@0: } sl@0: return (r); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Return any free buffer when trying to register a User buffer( aBufferId ==0 ) sl@0: or return the specified User buffer( used by Deregister and PostUserBuffer). sl@0: In the second case checks about the state of the user buffer are specific to sl@0: each case. sl@0: sl@0: */ sl@0: TBufferNode* DDisplayLdd::FindUserBufferNode(TInt aBufferId) sl@0: { sl@0: TBufferNode* node = 0; sl@0: sl@0: if(aBufferId == 0) sl@0: { sl@0: for(TInt i = 0; i < KDisplayUBMax; i++) sl@0: { sl@0: if(iUserBuffer[i].iFree) sl@0: { sl@0: node = &iUserBuffer[i]; sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: node = &iUserBuffer[aBufferId-1]; sl@0: } sl@0: return (node); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Free user buffer by reseting all the appropriate fields and closing the corresponding chunk. sl@0: */ sl@0: TInt DDisplayLdd::FreeUserBufferNode(TBufferNode* aNode) sl@0: { sl@0: __DEBUG_PRINT2("FreeUserBufferNode with aNode->iAddress %08x.\n",aNode->iAddress ); sl@0: TInt r = KErrNone; sl@0: NKern::ThreadEnterCS(); sl@0: if(aNode->iChunk != 0) sl@0: { sl@0: r= Kern::ChunkClose(aNode->iChunk); sl@0: } sl@0: if( r== KErrNone) sl@0: { sl@0: aNode->iState = EBufferFree; sl@0: aNode->iFree = ETrue; sl@0: aNode->iAddress = 0; sl@0: aNode->iSize = 0; sl@0: aNode->iHandle = 0; sl@0: aNode->iChunk = 0; sl@0: } sl@0: else sl@0: { sl@0: __DEBUG_PRINT("Failed to close chunk\n"); sl@0: } sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Calls CompleteRequest( which internally calls Kern::QueueRequestComplete )for the specified request and with the reason passed, sl@0: in case such an asynchronous request is pending. Called by both the LDD and PDD. sl@0: sl@0: */ sl@0: TInt DDisplayLdd::RequestComplete(TInt aRequest, TInt aReason) sl@0: { sl@0: TBool flag = EFalse; sl@0: sl@0: TInt pendingIndex = iPendingIndex[aRequest] ; sl@0: sl@0: switch (aRequest) sl@0: { sl@0: case RDisplayChannel::EReqGetCompositionBuffer: sl@0: { sl@0: __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqGetCompositionBuffer request and reason %d\n",aReason ); sl@0: sl@0: if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq ) sl@0: { sl@0: if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq->IsReady() ) sl@0: { sl@0: flag = ETrue; sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: sl@0: case RDisplayChannel::EReqWaitForPost: sl@0: { sl@0: __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqWaitForPost request and reason %d\n",aReason ); sl@0: sl@0: if(iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq) sl@0: { sl@0: if( iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq->IsReady() && (iCurrentPostCount >= iRequestedPostCount) ) sl@0: { sl@0: flag = ETrue; sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: sl@0: case RDisplayChannel::EReqPostUserBuffer: sl@0: { sl@0: __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqPostUserBuffer request and reason %d\n",aReason ); sl@0: sl@0: if(iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq) sl@0: { sl@0: if( iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq->IsReady() ) sl@0: { sl@0: flag = ETrue; sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: default: sl@0: __DEBUG_PRINT("RequestComplete() called for an unknown request\n"); sl@0: return KErrGeneral; sl@0: sl@0: } sl@0: sl@0: if (flag) sl@0: { sl@0: CompleteRequest(iPendingReq[aRequest][pendingIndex].iOwningThread,iPendingReq[aRequest][pendingIndex].iTClientReq,aReason); sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Complete an asynchronous request back to the client. sl@0: sl@0: @param aThread The client thread which issued the request. sl@0: @param aTClientReq Pointer reference to the TClientRequest object sl@0: @param aReason The request status code. sl@0: sl@0: @pre The thread must be in a critical section. sl@0: */ sl@0: void DDisplayLdd::CompleteRequest(DThread* aThread, TClientRequest*& aTClientReq, TInt aReason) sl@0: { sl@0: __DEBUG_PRINT4("Complete aTClientReq %08x with reason %d for aThread = %08x\n", aTClientReq, aReason,aThread ); sl@0: sl@0: Kern::QueueRequestComplete(aThread,aTClientReq,aReason); sl@0: sl@0: aThread->AsyncClose(); // Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference. sl@0: sl@0: aThread =0; sl@0: aTClientReq =0; sl@0: sl@0: #ifdef _DEBUG sl@0: __e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1)); sl@0: __e32_atomic_add_ord32(&iAsyncReqCount, TUint32(-1)); sl@0: #endif sl@0: sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: static factory function for the LDD. sl@0: sl@0: @return pointer to the created (or existing) instance of the class sl@0: */ sl@0: DDisplayLdd* DDisplayLdd::CreateInstance() sl@0: { sl@0: __DEBUG_PRINT("DDisplayLdd::CreateInstance()\n"); sl@0: // create LDD channel instance sl@0: DDisplayLdd* obj = new DDisplayLdd(); sl@0: return obj; sl@0: sl@0: } sl@0: sl@0: sl@0: /************************************************************************************ sl@0: * LDD factory, DDisplayLddFactory class implementation sl@0: ************************************************************************************/ sl@0: sl@0: /** sl@0: Constructor sl@0: */ sl@0: DDisplayLddFactory::DDisplayLddFactory() sl@0: { sl@0: __DEBUG_PRINT("DDisplayLddFactory::DDisplayLddFactory() \n"); sl@0: sl@0: iParseMask = KDeviceAllowPhysicalDevice | KDeviceAllowUnit ; sl@0: sl@0: iVersion = TVersion( KDisplayChMajorVersionNumber, sl@0: KDisplayChMinorVersionNumber, sl@0: KDisplayChBuildVersionNumber); sl@0: sl@0: iUnitsOpenMask =0; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Destructor sl@0: */ sl@0: DDisplayLddFactory::~DDisplayLddFactory() sl@0: { sl@0: } sl@0: sl@0: sl@0: /** sl@0: static factory function for the LDD factory. sl@0: sl@0: @return pointer to the created instance of the class sl@0: */ sl@0: DDisplayLddFactory* DDisplayLddFactory::CreateInstance() sl@0: sl@0: { sl@0: __DEBUG_PRINT("DDisplayLddFactory::CreateInstance() \n"); sl@0: sl@0: DDisplayLddFactory* obj = new DDisplayLddFactory; sl@0: return obj; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Set our name and return error code sl@0: */ sl@0: TInt DDisplayLddFactory::Install() sl@0: sl@0: { sl@0: __DEBUG_PRINT("DDisplayLddFactory::Install() \n"); sl@0: return SetName(&RDisplayChannel::Name()); sl@0: } sl@0: sl@0: sl@0: void DDisplayLddFactory::GetCaps(TDes8& /*aDes*/) const sl@0: sl@0: { sl@0: //No action. sl@0: } sl@0: sl@0: sl@0: /** sl@0: LDD factory function. Creates LDD object. sl@0: sl@0: @param aChannel A pointer to an LDD channel object which will be initialised on return. sl@0: sl@0: @return KErrNone if object successfully allocated, KErrNoMemory if not. sl@0: */ sl@0: TInt DDisplayLddFactory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: __DEBUG_PRINT("DDisplayLddFactory::Create \n"); sl@0: aChannel = DDisplayLdd::CreateInstance(); sl@0: return (!aChannel)? KErrNoMemory : KErrNone; sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: Check whether a channel is currently open on the specified unit. sl@0: @param aUnit The number of the unit to be checked. sl@0: @return ETrue if a channel is open on the specified channel, EFalse otherwise. sl@0: @pre The unit info. mutex must be held. sl@0: */ sl@0: TBool DDisplayLddFactory::IsUnitOpen(TInt aUnit) sl@0: { sl@0: return(iUnitsOpenMask&(1<