diff -r 4122176ea935 -r 56f325a607ea kernel/eka/drivers/display/display.cpp --- a/kernel/eka/drivers/display/display.cpp Mon Dec 21 16:14:42 2009 +0000 +++ b/kernel/eka/drivers/display/display.cpp Wed Dec 23 11:43:31 2009 +0000 @@ -11,8 +11,7 @@ // Contributors: // // Description: -// e32\drivers\display\display.cpp -// LDD for a Display driver with GCE support +// os\kernelhwsrv\kernel\eka\drivers\display\display.cpp // LDD for a Display driver with GCE support // // @@ -28,8 +27,11 @@ #include +const TUint8 KMutexOrder = 0x3f; -static const char KDisplayLddPanic[]="DISPLAY/GCE LDD"; +static const char KDisplayLddPanic[] ="DISPLAY/GCE LDD"; + +_LIT(KClientRequestMutex, "ClientRequestMutex"); /************************************************************************************ @@ -47,21 +49,32 @@ iRequestedPostCount = 0; iCompositionBuffIdx = 0; iUnit = -1; - iThreadOpenCount = 0; + iThreadOpenCount = 0; + iAsyncReqCount = 0; + iClientRequestMutex = 0; } DDisplayLdd::~DDisplayLdd() { __DEBUG_PRINT("DDisplayLdd::~DDisplayLdd() \n"); - // cancel outstanding requests + // cancel outstanding requests and destroy the queue of TClientRequest objects for(TInt k = 0; k < KPendingReqArraySize ; k++) { - if(iPendingReq[k].iStatus) - { - CompleteRequest(iPendingReq[k].iOwningThread,iPendingReq[k].iStatus,KErrCancel); - } - } + for(TInt i = 0; i < KMaxQueuedRequests; i++) + { + //Method IsReady() returns true if the client’s request SetStatus method has been called but the + //coresponding QueueRequestComplete method hasn't. + if(iPendingReq[k][i].iTClientReq) + { + if(iPendingReq[k][i].iTClientReq->IsReady() ) + { + CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel); + } + } + Kern::DestroyClientRequest(iClientRequest[k][i]); + } + } //Close User Buffer chunks not yet destroyed. for(TInt i = 0; i < KDisplayUBMax; i++) @@ -75,11 +88,24 @@ Kern::SafeClose((DObject*&)iClient, NULL); - __ASSERT_DEBUG(iThreadOpenCount==0,Kern::Fault(KDisplayLddPanic,__LINE__)); + + if (iClientRequestMutex != NULL) + { + iClientRequestMutex->Close(NULL); + } + + __ASSERT_DEBUG(iThreadOpenCount == 0,Kern::Fault(KDisplayLddPanic,__LINE__)); + __ASSERT_DEBUG(iAsyncReqCount == 0,Kern::Fault(KDisplayLddPanic,__LINE__)); // Clear the 'units open mask' in the LDD factory. if (iUnit>=0) ((DDisplayLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse); + +#ifdef _DEBUG + // Close the UDEB user mode chunk, if it exists + if (iChunk) + Kern::ChunkClose(iChunk); +#endif // _DEBUG } @@ -92,9 +118,9 @@ __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)") ) ) + || !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; } @@ -108,10 +134,9 @@ // 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; - } - + iUnit=aUnit; + Pdd()->iLdd = this; r = Pdd()->CreateChannelSetup(aUnit); @@ -135,12 +160,32 @@ iUserBuffer[node].iPendingRequest = 0; } - //Initialise pending queue for asynchronous requests - for(int k = 0; k < KPendingReqArraySize; k++) + //Initialise pending queue for asynchronous requests and queue of TClientRequests + for(TInt k = 0; k < KPendingReqArraySize; k++) { - iPendingReq[k].iStatus = 0; - iPendingReq[k].iOwningThread = 0; - } + + iPendingIndex[k]=0; + + for(TInt i = 0; i < KMaxQueuedRequests; i++) + { + iPendingReq[k][i].iTClientReq = 0; + iPendingReq[k][i].iOwningThread = 0; + + + r = Kern::CreateClientRequest(iClientRequest[k][i]); + if (r != KErrNone) + { + return r; + } + } + } + + r = Kern::MutexCreate(iClientRequestMutex, KClientRequestMutex, KMutexOrder); + if (r != KErrNone) + { + return r; + } + Pdd()->SetGceMode(); SetDfcQ(Pdd()->DfcQ(aUnit)); @@ -151,11 +196,337 @@ /** - * 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 +Override DLogicalChannel::SendMsg to process a client message before and after sending the message +to the DFC thread for processing by HandleMsg(). + +This function is called in the context of the client thread. + +The function is used to pin client data in the context of the client thread, so that data can be safely +accessed from kernel threads without the possibility of taking page faults. + +@param aMsg The message to process. + The iValue member of this distinguishes the message type: + iValue==ECloseMsg, channel close message + iValue==KMaxTInt, a 'DoCancel' message + iValue>=0, a 'DoControl' message with function number equal to iValue + iValue<0, a 'DoRequest' message with function number equal to ~iValue + + @return KErrNone if the message was send successfully, otherwise one of the other system-wide error + codes. + + */ + +TInt DDisplayLdd::SendMsg(TMessageBase* aMsg) + { + TThreadMessage& m=*(TThreadMessage*)aMsg; + TInt id = m.iValue; + + TInt r = KErrNone; + // close msg or cancel + if (id == (TInt)ECloseMsg || id == KMaxTInt) + { + r = DLogicalChannel::SendMsg(aMsg); + } + //asynchronous request + else if (id < 0) + { + TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); + r = SendRequest(aMsg); + if (r != KErrNone) + Kern::RequestComplete(pS,r); + } + // synchronous request + else{ + r = SendControl(aMsg); + } + + return r; + } + + +/** +Validate, pre-process, send and post-process data for an asynchronous client request, so that data can be safely +accessed from kernel threads without the possibility of taking page faults. + +This function is called in the context of the client thread. + +@param aMsg The message to process. + The iValue member of this distinguishes the message type: + iValue==ECloseMsg, channel close message + iValue==KMaxTInt, a 'DoCancel' message + iValue>=0, a 'DoControl' message with function number equal to iValue + iValue<0, a 'DoRequest' message with function number equal to ~iValue + + @return KErrNone if the message was send successfully, otherwise one of the other system-wide error + codes. + */ +TInt DDisplayLdd::SendRequest(TMessageBase* aMsg) + { + TThreadMessage& m =*(TThreadMessage*)aMsg; + TInt aReqNumber = ~m.iValue; + TRequestStatus* pS =(TRequestStatus*)m.Ptr0(); + + #ifdef _GCE_DISPLAY_DEBUG + DThread* client = m.Client(); + #endif + + TInt r = KErrNotSupported; + TInt pendingIndex; + + /*Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. + Using thread local copies is possible even for asynchronous requests, since the values to be returned are known + when processing the request( inside DoRequest ) and not at a later stage.*/ + + TInt kernelCompBuffIdx; + TInt kernelpack[2]; + RDisplayChannel::TPostCount kernelCount; + + + //In asynchronous requests m.Ptr0 is used for the TRequestStatus object. + TAny* userConfigData1 = m.Ptr1(); + TAny* userConfigData2 = m.Ptr2(); + + /* + If the client request needs to pass some data to the DFC thread then we copy these to a thread local + copy(created in the thread supervisor stack) and then update the message to point to that local copy. + If the client will have to read a value updated in the DFC thread, then the message should just be + updated and point to the local copy. After the request has completed the updated data will be copied + from the local copy to the client, in the context of the client thread. + */ + + switch (aReqNumber) + { + case RDisplayChannel::EReqGetCompositionBuffer: //Client should read data updated in the DFC thread. + m.iArg[1] = &kernelCompBuffIdx; + break; + + case RDisplayChannel::EReqPostUserBuffer: //Both the client and DFC thread need to read data. + umemget32(&kernelpack, userConfigData1, (sizeof(TInt)*2) ); + m.iArg[1] = &kernelpack; + m.iArg[2] = &kernelCount; + break; + + case RDisplayChannel::EReqWaitForPost: //Client data should be passed to the DFC thread. + umemget32(&kernelCount, userConfigData1, sizeof(RDisplayChannel::TPostCount) ); + m.iArg[1] = &kernelCount; + break; + default: + return KErrNotSupported; + + } + + /* + The TClientRequest objects associated with each asynchronous request need to be accessed by both the client and DFC + threads. To resolve the potential synchronization problem we maintain two seperate pointers(iClientRequest and + iPendingReq.iClientReq )to the same TClientRequest object. iClientRequestMutex is used to synchronise access to + iClientRequest from different client threads. The first client thread that acquires the mutex will set the status + of an available TClientRequest object and send the message(call SendMsg). Consequently method DoRequest is queued for + execution by the DFC thread. DoRequest initialy saves iClientRequest to iPendingReq.iClientReq and queues the request. + Only then, the mutex is signaled. Another client thread trying to access iClientRequest will block in the mutex until + DoRequest has updated iPendingReq.iClientReq. Even more the DFC thread only accesses iClientRequest in DoRequest and + then iPendingReq.iClientReq is only used, so synchronizing access to iPendingReq.iClientReq is handled by the DFC queue. + */ + + // Need to be in critical section whilst holding a DMutex + NKern::ThreadEnterCS(); + + Kern::MutexWait(*iClientRequestMutex); + //Save the TRequestStatus in any available TClientRequest object for that asynchronous request. + + for( TInt k=0; k< KMaxQueuedRequests; k++) + { + //setStatus will return KErrInUse if a previous client request hasn't completed yet. + r = iClientRequest[aReqNumber][k]->SetStatus(pS); + if( r == KErrNone) + { + pendingIndex = k; + //The current available index for this pending request will be passed as + //another message argument to the DFC thread. + m.iArg[3] = (TAny*) pendingIndex; + break; + } + } + + if (r == KErrNone) + { + r = DLogicalChannel::SendMsg(aMsg); + } + else + { + __DEBUG_PRINT3("Client %08x trying to issue asynchronous request %d", client, aReqNumber); + //Fail if there aren't any available TClientRequest object + __ASSERT_DEBUG(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__)); + } + + Kern::MutexSignal(*iClientRequestMutex); + + NKern::ThreadLeaveCS(); + + //Copy config data from local copies to client, in context of client thread + switch (aReqNumber) + { + case RDisplayChannel::EReqGetCompositionBuffer: + __DEBUG_PRINT2("EReqGetCompositionBuffer: kernelCompBuffIdx returned =%d",kernelCompBuffIdx); + umemput32(userConfigData1, &kernelCompBuffIdx, sizeof(TInt) ); + break; + + case RDisplayChannel::EReqPostUserBuffer: + __DEBUG_PRINT2("EReqPostUserBuffer: kernelCount returned = %d",kernelCount); + umemput32(userConfigData2, &kernelCount, sizeof(RDisplayChannel::TPostCount) ); + break; + } + return r; + } + + +/** +Validate, pre-process, send and post-process data for a synchronous client request, so that data can be safely +accessed from kernel threads without the possibility of taking page faults. + +This function is called in the context of the client thread. + +@param aMsg The message to process. + The iValue member of this distinguishes the message type: + iValue==ECloseMsg, channel close message + iValue==KMaxTInt, a 'DoCancel' message + iValue>=0, a 'DoControl' message with function number equal to iValue + iValue<0, a 'DoRequest' message with function number equal to ~iValue + +@return KErrNone if the message was send successfully, otherwise one of the other system-wide error + codes. + */ + +TInt DDisplayLdd::SendControl(TMessageBase* aMsg) + { + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt aReqNumber = m.iValue; + + + //Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. + + RDisplayChannel::TPostCount kernelPostCount; + RDisplayChannel::TDisplayRotation kernelRotation; + + TPckgBuf pckgInfo(iDisplayInfo); + + TInt kernelpack[2]; + TInt kernelBufferId; + TBool kernelRotChanged; + TInt kernelIndex; + + TAny* userConfigData0 = m.Ptr0(); + TAny* userConfigData1 = m.Ptr1(); + + + switch (aReqNumber) + { + //iDisplayInfo doesn't change after the driver initialisation so copy in client thread context + case RDisplayChannel::ECtrlGetDisplayInfo: + umemput32(userConfigData0, &pckgInfo, sizeof(TPckgBuf) ); + return KErrNone; + + case RDisplayChannel::ECtrlPostCompositionBuffer: //Client should read data updated in the DFC thread. + m.iArg[1] = &kernelPostCount; + break; + + case RDisplayChannel::ECtrlPostLegacyBuffer: //Client should read data updated in the DFC thread. + m.iArg[1] = &kernelPostCount; + break; + + case RDisplayChannel::ECtrlRegisterUserBuffer: //Both the client and DFC thread need to read data. + umemget32(&kernelpack, userConfigData0, (sizeof(TInt)*2) ); + m.iArg[0] = &kernelpack; + m.iArg[1] = &kernelBufferId; + break; + + case RDisplayChannel::ECtrlDeregisterUserBuffer: //Client data should be passed to the DFC thread. + umemget32(&kernelBufferId, userConfigData0, sizeof(TInt) ); + m.iArg[0] = &kernelBufferId; + break; + + case RDisplayChannel::ECtrlSetRotation: //Both the client and DFC thread need to read data. + umemget32(&kernelRotation, userConfigData0, sizeof(RDisplayChannel::TDisplayRotation) ); + m.iArg[0] = &kernelRotation; + m.iArg[1] = &kernelRotChanged; + break; + + case RDisplayChannel::ECtrlCurrentRotation: //Client should read data updated in the DFC thread. + m.iArg[0] = &kernelRotation; + break; + + case RDisplayChannel::ECtrlGetCompositionBufferInfo: //Both the client and DFC thread need to read data. + umemget32(&kernelIndex, userConfigData0, sizeof(TInt) ); + m.iArg[0] = &kernelIndex; + m.iArg[1] = &kernelpack; + break; + +#ifdef _DEBUG + case RDisplayChannel::ECtrlCreateUserBuffer: + m.iArg[0] = userConfigData0; + m.iArg[1] = userConfigData1; + break; +#endif // _DEBUG + + default: + return KErrNotSupported; + + } + + TInt r = DLogicalChannel::SendMsg(aMsg); + if (r != KErrNone) + { + return r; + } + + //Copy config data from local copies to client, in context of client thread + switch (aReqNumber) + { + case RDisplayChannel::ECtrlPostCompositionBuffer: + __DEBUG_PRINT2("ECtrlPostCompositionBuffer =%d", kernelPostCount ); + umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) ); + break; + + case RDisplayChannel::ECtrlPostLegacyBuffer: + __DEBUG_PRINT2("ECtrlPostLegacyBuffer=%d", kernelPostCount ); + umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) ); + break; + + case RDisplayChannel::ECtrlRegisterUserBuffer: + __DEBUG_PRINT2("ECtrlRegisterUserBuffer kernelBufferId=%d", kernelBufferId ); + umemput32(userConfigData1, &kernelBufferId, sizeof(TInt) ); + break; + + case RDisplayChannel::ECtrlSetRotation: + __DEBUG_PRINT2("ECtrlSetRotation kernelRotChanged=%d", kernelRotChanged ); + umemput32(userConfigData1, &kernelRotChanged, sizeof(TBool) ); + break; + + case RDisplayChannel::ECtrlCurrentRotation: + __DEBUG_PRINT2("ECtrlCurrentRotation kernelRotation=%d", kernelRotation ); + umemput32(userConfigData0, &kernelRotation, sizeof(RDisplayChannel::TDisplayRotation) ); + break; + + case RDisplayChannel::ECtrlGetCompositionBufferInfo: + __DEBUG_PRINT3("ECtrlGetCompositionBufferInfo kernelpack[0] =%d and kernelpack[1] =%d", kernelpack[0], kernelpack[1]); + umemput32(userConfigData1, &kernelpack, (sizeof(TInt)*2) ); + break; + } + return r; + } + + +/** + 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 message to process. + + The iValue member of this distinguishes the message type: + iValue==ECloseMsg, channel close message + iValue==KMaxTInt, a 'DoCancel' message + iValue>=0, a 'DoControl' message with function number equal to iValue + iValue<0, a 'DoRequest' message with function number equal to ~iValue */ void DDisplayLdd::HandleMsg(TMessageBase* aMsg) { @@ -170,12 +541,18 @@ Pdd()->CloseMsg(); // cancel outstanding requests - for(int k = 0; k < KPendingReqArraySize; k++) - { - if(iPendingReq[k].iStatus) - { - CompleteRequest(iPendingReq[k].iOwningThread,iPendingReq[k].iStatus,KErrCancel); - } + for(TInt k = 0; k < KPendingReqArraySize; k++) + { + for(TInt i = 0; i < KMaxQueuedRequests; i++) + { + if( iPendingReq[k][i].iTClientReq) + { + if(iPendingReq[k][i].iTClientReq->IsReady() ) + { + CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel); + } + } + } } Pdd()->SetLegacyMode(); m.Complete(KErrNone, EFalse); @@ -193,8 +570,8 @@ // asynchronous request else if (id < 0) { - TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); - TInt r = DoRequest(~id,pS,m.Ptr1(),m.Ptr2(), client); + //m.Int3() is the index, in the array of pending requests, to be used. + TInt r = DoRequest(~id,m.Ptr1(),m.Ptr2(),m.Int3(), client); m.Complete(r, ETrue); } // synchronous request @@ -219,13 +596,14 @@ { case RDisplayChannel::ECtrlCancelGetCompositionBuffer: case RDisplayChannel::ECtrlCancelPostUserBuffer: - case RDisplayChannel::ECtrlCancelWaitForPost: - if(iPendingReq[aReqNumber].iStatus) + case RDisplayChannel::ECtrlCancelWaitForPost: + TInt pendingIndex = iPendingIndex[aReqNumber]; + if(iPendingReq[aReqNumber][pendingIndex].iTClientReq) { - CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel); - - iPendingReq[aReqNumber].iStatus = 0; - iPendingReq[aReqNumber].iOwningThread = 0; + if( iPendingReq[aReqNumber][pendingIndex].iTClientReq->IsReady() ) + { + CompleteRequest(iPendingReq[aReqNumber][pendingIndex].iOwningThread,iPendingReq[aReqNumber][pendingIndex].iTClientReq,KErrCancel); + } } break; } @@ -235,146 +613,156 @@ /** 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 + @param aFunction Request function number + @param apArg1 Pointer to kernel message argument 1. + @param apArg2 Pointer to kernel message argument 2. + @param aPendingIndex Index pointing to the appropriate TClientRequest object to use. + @param aClient Pointer to the client thread that issued the asynchronous request. - @return request scheduling result, system-wide error code. + @return request scheduling result, system-wide error code. */ -TInt DDisplayLdd::DoRequest(TInt aReqNumber, TRequestStatus* aRqStat, TAny* aArg1, TAny* aArg2, DThread* aClient) +TInt DDisplayLdd::DoRequest(TInt aReqNumber, TAny* aArg1, TAny* aArg2, TInt aPendingIndex, DThread* aClient) { - TUint count; + TInt pack[2]; TInt r = KErrNone; TBufferNode* node = 0; - TInt buffer_id = 0; - + TInt buffer_id = 0; + + TInt* configBufferIdx ; + RDisplayChannel::TPostCount* postCount; + TInt* configPack; + + __DEBUG_PRINT5("DoRequest: iClientRequest[aReqNumber=%d][aPendingIndex=%d] is %08x and aClient=%08x\n",aReqNumber, aPendingIndex,iClientRequest[aReqNumber][aPendingIndex], aClient); + // 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) - { + + for(TInt i = 0; i < KMaxQueuedRequests; i++) + { + //Don't cancel the asyncrhonous request we currently process. + if (i == aPendingIndex) + { + continue; + } // cancel outstanding request - if(iPendingReq[aReqNumber].iStatus) + if(iPendingReq[aReqNumber][i].iTClientReq) { - CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel); - iPendingReq[aReqNumber].iStatus = 0; - iPendingReq[aReqNumber].iOwningThread = 0; + //If IsReady() returns true, setStatus has been called for that TCientRequest but QueueRequestComplete hasn't. + //In that case we want to cancel this outstanding request. Given that all QueueRequestComplete calls execute + // in the same DFC thread we currently run, there is no need to synchronise request completion calls. + if(iPendingReq[aReqNumber][i].iTClientReq->IsReady() ) + { + CompleteRequest(iPendingReq[aReqNumber][i].iOwningThread,iPendingReq[aReqNumber][i].iTClientReq,KErrCancel); + break; + } } - - // store request and client - iPendingReq[aReqNumber].iStatus = aRqStat; - iPendingReq[aReqNumber].iOwningThread = aClient; } - + // store index, request and client + iPendingIndex[aReqNumber] = aPendingIndex; + iPendingReq[aReqNumber][aPendingIndex].iTClientReq = iClientRequest[aReqNumber][aPendingIndex]; + iPendingReq[aReqNumber][aPendingIndex].iOwningThread = aClient; + + #ifdef _DEBUG + __e32_atomic_add_ord32(&iAsyncReqCount, 1); + #endif + switch (aReqNumber) { - case RDisplayChannel::EReqGetCompositionBuffer: + case RDisplayChannel::EReqGetCompositionBuffer: //DFC thread updates a value the client thread should read. + { + configBufferIdx = (TInt*) aArg1; + + TInt index; + TBool found = EFalse; + + for(index = 0; index < (TInt) iDisplayInfo.iNumCompositionBuffers; index++) + { + if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose ) + { + __DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index); - 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; - } + iCompositionBuffIdx = index; + *configBufferIdx = iCompositionBuffIdx; + iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose; + CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread,iPendingReq[aReqNumber][aPendingIndex].iTClientReq,r); + 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; + *configBufferIdx = iCompositionBuffIdx; + CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread, iPendingReq[aReqNumber][aPendingIndex].iTClientReq, r); + __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; + *configBufferIdx = iCompositionBuffIdx; + __DEBUG_PRINT2("EReqGetCompositionBuffer No composition buffer available. Next available is iCompositionBuffIdx %d.\n",iCompositionBuffIdx ); + 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; + } + } + + 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); - } + case RDisplayChannel::EReqPostUserBuffer: //DFC thread should read client message data and update a value the client will read. + configPack = (TInt*) aArg1; + pack[0] = *configPack; + configPack++; + pack[1] = *configPack; + + 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) + { + postCount = (RDisplayChannel::TPostCount*) aArg2; + ++iCurrentPostCount; + *postCount= iCurrentPostCount; + 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); - } - } + case RDisplayChannel::EReqWaitForPost: //DFC thread should read client message data. + postCount = (RDisplayChannel::TPostCount*) aArg1; + iRequestedPostCount = *postCount; + + //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; + __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number } return r; } @@ -383,69 +771,75 @@ /** Synchronous requests processing. - @param aFunction request function number, - @param apArg1 pointer to the 1st parameter - @param apArg2 pointer to the 2n parameter + @param aFunction Request function number, + @param apArg1 Pointer to kernel message argument 0. + @param apArg2 Pointer to kernel message argument 1. + @param aClient Pointer to the client thread that issued the synchronous request. @return request processing result */ TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient) { - TInt r = KErrNotSupported; + TInt r = KErrNone; TBool changedRot = ETrue; TBufferNode* node = 0; TInt buffer_id; TInt pack[2] = {0,0}; TInt handle, offset; TInt index = 0; - - TPckgBuf pckgInfo(iDisplayInfo); - + + RDisplayChannel::TPostCount *postCount ; + RDisplayChannel::TDisplayRotation *rotation; + + TInt *configPack; + TInt *bufferId; + + TBool *rotationChanged; + TInt *idx; + switch (aFunction) { - case RDisplayChannel::ECtrlGetDisplayInfo: - r=Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&pckgInfo, sizeof(pckgInfo), aClient); - break; - - case RDisplayChannel::ECtrlPostCompositionBuffer: + case RDisplayChannel::ECtrlPostCompositionBuffer: //DFC thread updates a value the client thread should read. + postCount = (RDisplayChannel::TPostCount*) aArg2; + node = &iCompositionBuffer[iCompositionBuffIdx]; r = Pdd()->PostCompositionBuffer(node); if(r == KErrNone) { ++iCurrentPostCount; - r=Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient); - } + *postCount = iCurrentPostCount; + } else { r = KErrGeneral; } break; - case RDisplayChannel::ECtrlPostLegacyBuffer: + case RDisplayChannel::ECtrlPostLegacyBuffer: //DFC thread updates a value the client thread should read. + postCount = (RDisplayChannel::TPostCount*) aArg2; r= Pdd()->PostLegacyBuffer(); if ( r == KErrNone) { - ++iCurrentPostCount; - r = Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient); - } + ++iCurrentPostCount; + *postCount = iCurrentPostCount; + } break; - case RDisplayChannel::ECtrlRegisterUserBuffer: + case RDisplayChannel::ECtrlRegisterUserBuffer: //DFC thread should read client message data and update a value the client will read. 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); - } - } + { + configPack = (TInt*) aArg1; + handle = *configPack; + configPack++; + offset = *configPack; + r = CheckAndOpenUserBuffer(node, handle, offset, aClient); + + if(r == KErrNone) + { + bufferId = (TInt*) aArg2; + *bufferId = node->iBufferId; + } } else { @@ -453,79 +847,124 @@ } 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; - } - } - } - } + case RDisplayChannel::ECtrlDeregisterUserBuffer: //DFC thread should read client message data. + bufferId = (TInt*) aArg1; + buffer_id = *bufferId; + + + 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); + case RDisplayChannel::ECtrlSetRotation: //DFC thread should read client message data and update a value the client will read. + { + RDisplayChannel::TDisplayRotation rot; + RDisplayChannel::TDisplayRotation previousRot = iCurrentRotation; + + rotation = (RDisplayChannel::TDisplayRotation*) aArg1; + rot = *rotation; + + __DEBUG_PRINT3("ECtrlSetRotation previousRot= %d and rot =%d \n",previousRot, rot ); + + r = Pdd()->SetRotation(rot); + changedRot = (previousRot != iCurrentRotation); + if( r == KErrNone) + { + rotationChanged = (TBool*) aArg2; + *rotationChanged = changedRot ; + } + break; + } + + case RDisplayChannel::ECtrlCurrentRotation: //DFC thread updates a value the client thread should read. + rotation = (RDisplayChannel::TDisplayRotation*) aArg1; + *rotation = iCurrentRotation; 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::ECtrlGetCompositionBufferInfo: //DFC thread should read client message data and update a value the client will read. + idx = ( TInt * ) aArg1; + index = *idx; + + if( (index >= (TInt) iDisplayInfo.iNumCompositionBuffers ) || (index < 0 ) ) + { + r = KErrArgument; + break; + } + r = Kern::MakeHandleAndOpen(aClient, iCompositionBuffer[index].iChunk); - case RDisplayChannel::ECtrlCurrentRotation: - r=Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&iCurrentRotation, sizeof(RDisplayChannel::TDisplayRotation), aClient); - break; + if(r >= KErrNone) + { + pack[0] = r; + pack[1] = iCompositionBuffer[index].iOffset; + + configPack = (TInt * ) aArg2; + *configPack = pack[0]; + configPack++; + *configPack = pack[1]; + + r = KErrNone; + } + break; + +#ifdef _DEBUG + case RDisplayChannel::ECtrlCreateUserBuffer: + { + TUint32 chunkMapAttr; + TLinAddr chunkBase; + TPhysAddr physicalAddr; + RDisplayChannel::TBufferFormat bufferFormat; - 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); + // Read the information from the user thread pertaining to the buffer to be allocated + Kern::ThreadRawRead(aClient, aArg1, &bufferFormat, sizeof(bufferFormat)); + + // Allocate a chunk that can be used as a user buffer. Don't worry about the # of bytes + // per pixel as this is UDEB only test code - just set it to 4 and that will ensure that + // it is large enough + TChunkCreateInfo chunkCreateInfo; + chunkCreateInfo.iType = TChunkCreateInfo::ESharedKernelSingle; +#ifndef __WINS__ + chunkCreateInfo.iMapAttr = EMapAttrFullyBlocking; +#endif // ! __WINS__ + chunkCreateInfo.iOwnsMemory = ETrue; + chunkCreateInfo.iDestroyedDfc = NULL; + chunkCreateInfo.iMaxSize = (bufferFormat.iSize.iWidth * bufferFormat.iSize.iHeight * 4); - 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; + if ((r = Kern::ChunkCreate(chunkCreateInfo, iChunk, chunkBase, chunkMapAttr)) == KErrNone) + { + // Commit some contiguous physical RAM for use in the chunk + r = Kern::ChunkCommitContiguous(iChunk, 0, chunkCreateInfo.iMaxSize, physicalAddr); + + // And open a handle to the chunk that will be returned to user side for use in the user + // side's RChunk object + if (r == KErrNone) + r = Kern::MakeHandleAndOpen(aClient, iChunk); + else + { + Kern::ChunkClose(iChunk); + iChunk = NULL; + } + } + + break; + } +#endif // _DEBUG + + default: + __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number }; return r; } @@ -551,7 +990,8 @@ 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; @@ -637,25 +1077,28 @@ /** - 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. + Calls CompleteRequest( which internally calls Kern::QueueRequestComplete )for the specified request and with the reason passed, + in case such an asynchronous request is pending. Called by both the LDD and PDD. */ TInt DDisplayLdd::RequestComplete(TInt aRequest, TInt aReason) { - TBool flag = EFalse; - + TBool flag = EFalse; + + TInt pendingIndex = iPendingIndex[aRequest] ; + switch (aRequest) - { + { case RDisplayChannel::EReqGetCompositionBuffer: { __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqGetCompositionBuffer request and reason %d\n",aReason ); - if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer].iStatus) + if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq ) { - __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqGetCompositionBuffer \n"); - flag = ETrue; + if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq->IsReady() ) + { + flag = ETrue; + } } break; } @@ -664,10 +1107,12 @@ { __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqWaitForPost request and reason %d\n",aReason ); - if((iPendingReq[RDisplayChannel::EReqWaitForPost].iStatus != 0) && (iCurrentPostCount >= iRequestedPostCount) ) + if(iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq) { - __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqWaitForPost \n"); - flag = ETrue; + if( iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq->IsReady() && (iCurrentPostCount >= iRequestedPostCount) ) + { + flag = ETrue; + } } break; } @@ -676,10 +1121,12 @@ { __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqPostUserBuffer request and reason %d\n",aReason ); - if((iPendingReq[RDisplayChannel::EReqPostUserBuffer].iStatus != 0) ) + if(iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq) { - __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqPostUserBuffer \n"); - flag = ETrue; + if( iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq->IsReady() ) + { + flag = ETrue; + } } break; } @@ -691,9 +1138,7 @@ if (flag) { - CompleteRequest(iPendingReq[aRequest].iOwningThread,iPendingReq[aRequest].iStatus,aReason); - iPendingReq[aRequest].iStatus = 0; - iPendingReq[aRequest].iOwningThread = 0; + CompleteRequest(iPendingReq[aRequest][pendingIndex].iOwningThread,iPendingReq[aRequest][pendingIndex].iTClientReq,aReason); } return KErrNone; @@ -702,19 +1147,27 @@ /** 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. + +@param aThread The client thread which issued the request. +@param aTClientReq Pointer reference to the TClientRequest object +@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. +void DDisplayLdd::CompleteRequest(DThread* aThread, TClientRequest*& aTClientReq, TInt aReason) + { + __DEBUG_PRINT4("Complete aTClientReq %08x with reason %d for aThread = %08x\n", aTClientReq, aReason,aThread ); + Kern::QueueRequestComplete(aThread,aTClientReq,aReason); + aThread->AsyncClose(); // Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference. - + + aThread =0; + aTClientReq =0; + #ifdef _DEBUG __e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1)); + __e32_atomic_add_ord32(&iAsyncReqCount, TUint32(-1)); #endif }