First public contribution.
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // os\kernelhwsrv\kernel\eka\drivers\display\display.cpp
15 // LDD for a Display driver with GCE support
26 #include <drivers/display.h>
27 #include <kernel/kern_priv.h>
30 const TUint8 KMutexOrder = 0x3f;
32 static const char KDisplayLddPanic[] ="DISPLAY/GCE LDD";
34 _LIT(KClientRequestMutex, "ClientRequestMutex");
37 /************************************************************************************
38 * DDisplayLdd LDD class implementation
39 ************************************************************************************/
40 DDisplayLdd::DDisplayLdd()
42 __DEBUG_PRINT("DDisplayLdd::DDisplayLdd()\n");
43 // store the pointer to the current thread for request completion
44 iClient = &Kern::CurrentThread();
45 __NK_ASSERT_DEBUG(iClient);
46 // Open a reference on the client thread so it's control block can't disappear until the driver has finished with it.
48 iCurrentPostCount = 0;
49 iRequestedPostCount = 0;
50 iCompositionBuffIdx = 0;
54 iClientRequestMutex = 0;
58 DDisplayLdd::~DDisplayLdd()
60 __DEBUG_PRINT("DDisplayLdd::~DDisplayLdd() \n");
61 // cancel outstanding requests and destroy the queue of TClientRequest objects
62 for(TInt k = 0; k < KPendingReqArraySize ; k++)
64 for(TInt i = 0; i < KMaxQueuedRequests; i++)
66 //Method IsReady() returns true if the client’s request SetStatus method has been called but the
67 //coresponding QueueRequestComplete method hasn't.
68 if(iPendingReq[k][i].iTClientReq)
70 if(iPendingReq[k][i].iTClientReq->IsReady() )
72 CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel);
75 Kern::DestroyClientRequest(iClientRequest[k][i]);
79 //Close User Buffer chunks not yet destroyed.
80 for(TInt i = 0; i < KDisplayUBMax; i++)
82 if(iUserBuffer[i].iChunk != 0)
84 Kern::ChunkClose(iUserBuffer[i].iChunk);
85 iUserBuffer[i].iChunk= NULL;
89 Kern::SafeClose((DObject*&)iClient, NULL);
92 if (iClientRequestMutex != NULL)
94 iClientRequestMutex->Close(NULL);
97 __ASSERT_DEBUG(iThreadOpenCount == 0,Kern::Fault(KDisplayLddPanic,__LINE__));
98 __ASSERT_DEBUG(iAsyncReqCount == 0,Kern::Fault(KDisplayLddPanic,__LINE__));
100 // Clear the 'units open mask' in the LDD factory.
102 ((DDisplayLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse);
105 // Close the UDEB user mode chunk, if it exists
107 Kern::ChunkClose(iChunk);
113 LDD second stage constructor
115 TInt DDisplayLdd::DoCreate(TInt aUnit, const TDesC8* /* anInfo*/, const TVersion& aVer)
118 __DEBUG_PRINT("DDisplayLdd::DoCreate()\n");
120 if( !Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
121 || !Kern::CurrentThreadHasCapability(ECapabilityReadDeviceData, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
122 || !Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
123 || !Kern::CurrentThreadHasCapability(ECapabilityProtServ, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) )
125 return KErrPermissionDenied;
128 // Check that the display driver version specified by the client is compatible.
129 if (!Kern::QueryVersionSupported(RDisplayChannel::VersionRequired(),aVer))
131 return(KErrNotSupported);
134 // Check that a channel hasn't already been opened on this unit.
135 TInt r=((DDisplayLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory.
142 r = Pdd()->CreateChannelSetup(aUnit);
148 // set up user buffer nodes
149 for (TInt node = 0; node < KDisplayUBMax; node++)
151 iUserBuffer[node].iType = EBufferTypeUser;
152 iUserBuffer[node].iBufferId = (node + 1);
153 iUserBuffer[node].iFree = ETrue;
154 iUserBuffer[node].iState = EBufferFree;
155 iUserBuffer[node].iAddress = 0;
156 iUserBuffer[node].iSize = 0;
157 iUserBuffer[node].iHandle = 0;
158 iUserBuffer[node].iChunk = 0;
159 iUserBuffer[node].iOffset = 0;
160 iUserBuffer[node].iPendingRequest = 0;
163 //Initialise pending queue for asynchronous requests and queue of TClientRequests
164 for(TInt k = 0; k < KPendingReqArraySize; k++)
169 for(TInt i = 0; i < KMaxQueuedRequests; i++)
171 iPendingReq[k][i].iTClientReq = 0;
172 iPendingReq[k][i].iOwningThread = 0;
175 r = Kern::CreateClientRequest(iClientRequest[k][i]);
183 r = Kern::MutexCreate(iClientRequestMutex, KClientRequestMutex, KMutexOrder);
191 SetDfcQ(Pdd()->DfcQ(aUnit));
199 Override DLogicalChannel::SendMsg to process a client message before and after sending the message
200 to the DFC thread for processing by HandleMsg().
202 This function is called in the context of the client thread.
204 The function is used to pin client data in the context of the client thread, so that data can be safely
205 accessed from kernel threads without the possibility of taking page faults.
207 @param aMsg The message to process.
208 The iValue member of this distinguishes the message type:
209 iValue==ECloseMsg, channel close message
210 iValue==KMaxTInt, a 'DoCancel' message
211 iValue>=0, a 'DoControl' message with function number equal to iValue
212 iValue<0, a 'DoRequest' message with function number equal to ~iValue
214 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error
219 TInt DDisplayLdd::SendMsg(TMessageBase* aMsg)
221 TThreadMessage& m=*(TThreadMessage*)aMsg;
225 // close msg or cancel
226 if (id == (TInt)ECloseMsg || id == KMaxTInt)
228 r = DLogicalChannel::SendMsg(aMsg);
230 //asynchronous request
233 TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
234 r = SendRequest(aMsg);
236 Kern::RequestComplete(pS,r);
238 // synchronous request
240 r = SendControl(aMsg);
248 Validate, pre-process, send and post-process data for an asynchronous client request, so that data can be safely
249 accessed from kernel threads without the possibility of taking page faults.
251 This function is called in the context of the client thread.
253 @param aMsg The message to process.
254 The iValue member of this distinguishes the message type:
255 iValue==ECloseMsg, channel close message
256 iValue==KMaxTInt, a 'DoCancel' message
257 iValue>=0, a 'DoControl' message with function number equal to iValue
258 iValue<0, a 'DoRequest' message with function number equal to ~iValue
260 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error
263 TInt DDisplayLdd::SendRequest(TMessageBase* aMsg)
265 TThreadMessage& m =*(TThreadMessage*)aMsg;
266 TInt aReqNumber = ~m.iValue;
267 TRequestStatus* pS =(TRequestStatus*)m.Ptr0();
269 #ifdef _GCE_DISPLAY_DEBUG
270 DThread* client = m.Client();
273 TInt r = KErrNotSupported;
276 /*Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread.
277 Using thread local copies is possible even for asynchronous requests, since the values to be returned are known
278 when processing the request( inside DoRequest ) and not at a later stage.*/
280 TInt kernelCompBuffIdx;
282 RDisplayChannel::TPostCount kernelCount;
285 //In asynchronous requests m.Ptr0 is used for the TRequestStatus object.
286 TAny* userConfigData1 = m.Ptr1();
287 TAny* userConfigData2 = m.Ptr2();
290 If the client request needs to pass some data to the DFC thread then we copy these to a thread local
291 copy(created in the thread supervisor stack) and then update the message to point to that local copy.
292 If the client will have to read a value updated in the DFC thread, then the message should just be
293 updated and point to the local copy. After the request has completed the updated data will be copied
294 from the local copy to the client, in the context of the client thread.
299 case RDisplayChannel::EReqGetCompositionBuffer: //Client should read data updated in the DFC thread.
300 m.iArg[1] = &kernelCompBuffIdx;
303 case RDisplayChannel::EReqPostUserBuffer: //Both the client and DFC thread need to read data.
304 umemget32(&kernelpack, userConfigData1, (sizeof(TInt)*2) );
305 m.iArg[1] = &kernelpack;
306 m.iArg[2] = &kernelCount;
309 case RDisplayChannel::EReqWaitForPost: //Client data should be passed to the DFC thread.
310 umemget32(&kernelCount, userConfigData1, sizeof(RDisplayChannel::TPostCount) );
311 m.iArg[1] = &kernelCount;
314 return KErrNotSupported;
319 The TClientRequest objects associated with each asynchronous request need to be accessed by both the client and DFC
320 threads. To resolve the potential synchronization problem we maintain two seperate pointers(iClientRequest and
321 iPendingReq.iClientReq )to the same TClientRequest object. iClientRequestMutex is used to synchronise access to
322 iClientRequest from different client threads. The first client thread that acquires the mutex will set the status
323 of an available TClientRequest object and send the message(call SendMsg). Consequently method DoRequest is queued for
324 execution by the DFC thread. DoRequest initialy saves iClientRequest to iPendingReq.iClientReq and queues the request.
325 Only then, the mutex is signaled. Another client thread trying to access iClientRequest will block in the mutex until
326 DoRequest has updated iPendingReq.iClientReq. Even more the DFC thread only accesses iClientRequest in DoRequest and
327 then iPendingReq.iClientReq is only used, so synchronizing access to iPendingReq.iClientReq is handled by the DFC queue.
330 // Need to be in critical section whilst holding a DMutex
331 NKern::ThreadEnterCS();
333 Kern::MutexWait(*iClientRequestMutex);
334 //Save the TRequestStatus in any available TClientRequest object for that asynchronous request.
336 for( TInt k=0; k< KMaxQueuedRequests; k++)
338 //setStatus will return KErrInUse if a previous client request hasn't completed yet.
339 r = iClientRequest[aReqNumber][k]->SetStatus(pS);
343 //The current available index for this pending request will be passed as
344 //another message argument to the DFC thread.
345 m.iArg[3] = (TAny*) pendingIndex;
352 r = DLogicalChannel::SendMsg(aMsg);
356 __DEBUG_PRINT3("Client %08x trying to issue asynchronous request %d", client, aReqNumber);
357 //Fail if there aren't any available TClientRequest object
358 __ASSERT_DEBUG(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__));
361 Kern::MutexSignal(*iClientRequestMutex);
363 NKern::ThreadLeaveCS();
365 //Copy config data from local copies to client, in context of client thread
368 case RDisplayChannel::EReqGetCompositionBuffer:
369 __DEBUG_PRINT2("EReqGetCompositionBuffer: kernelCompBuffIdx returned =%d",kernelCompBuffIdx);
370 umemput32(userConfigData1, &kernelCompBuffIdx, sizeof(TInt) );
373 case RDisplayChannel::EReqPostUserBuffer:
374 __DEBUG_PRINT2("EReqPostUserBuffer: kernelCount returned = %d",kernelCount);
375 umemput32(userConfigData2, &kernelCount, sizeof(RDisplayChannel::TPostCount) );
383 Validate, pre-process, send and post-process data for a synchronous client request, so that data can be safely
384 accessed from kernel threads without the possibility of taking page faults.
386 This function is called in the context of the client thread.
388 @param aMsg The message to process.
389 The iValue member of this distinguishes the message type:
390 iValue==ECloseMsg, channel close message
391 iValue==KMaxTInt, a 'DoCancel' message
392 iValue>=0, a 'DoControl' message with function number equal to iValue
393 iValue<0, a 'DoRequest' message with function number equal to ~iValue
395 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error
399 TInt DDisplayLdd::SendControl(TMessageBase* aMsg)
401 TThreadMessage& m = *(TThreadMessage*)aMsg;
402 TInt aReqNumber = m.iValue;
405 //Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread.
407 RDisplayChannel::TPostCount kernelPostCount;
408 RDisplayChannel::TDisplayRotation kernelRotation;
410 TPckgBuf<RDisplayChannel::TDisplayInfo> pckgInfo(iDisplayInfo);
414 TBool kernelRotChanged;
417 TAny* userConfigData0 = m.Ptr0();
418 TAny* userConfigData1 = m.Ptr1();
423 //iDisplayInfo doesn't change after the driver initialisation so copy in client thread context
424 case RDisplayChannel::ECtrlGetDisplayInfo:
425 umemput32(userConfigData0, &pckgInfo, sizeof(TPckgBuf<RDisplayChannel::TDisplayInfo>) );
428 case RDisplayChannel::ECtrlPostCompositionBuffer: //Client should read data updated in the DFC thread.
429 m.iArg[1] = &kernelPostCount;
432 case RDisplayChannel::ECtrlPostLegacyBuffer: //Client should read data updated in the DFC thread.
433 m.iArg[1] = &kernelPostCount;
436 case RDisplayChannel::ECtrlRegisterUserBuffer: //Both the client and DFC thread need to read data.
437 umemget32(&kernelpack, userConfigData0, (sizeof(TInt)*2) );
438 m.iArg[0] = &kernelpack;
439 m.iArg[1] = &kernelBufferId;
442 case RDisplayChannel::ECtrlDeregisterUserBuffer: //Client data should be passed to the DFC thread.
443 umemget32(&kernelBufferId, userConfigData0, sizeof(TInt) );
444 m.iArg[0] = &kernelBufferId;
447 case RDisplayChannel::ECtrlSetRotation: //Both the client and DFC thread need to read data.
448 umemget32(&kernelRotation, userConfigData0, sizeof(RDisplayChannel::TDisplayRotation) );
449 m.iArg[0] = &kernelRotation;
450 m.iArg[1] = &kernelRotChanged;
453 case RDisplayChannel::ECtrlCurrentRotation: //Client should read data updated in the DFC thread.
454 m.iArg[0] = &kernelRotation;
457 case RDisplayChannel::ECtrlGetCompositionBufferInfo: //Both the client and DFC thread need to read data.
458 umemget32(&kernelIndex, userConfigData0, sizeof(TInt) );
459 m.iArg[0] = &kernelIndex;
460 m.iArg[1] = &kernelpack;
464 case RDisplayChannel::ECtrlCreateUserBuffer:
465 m.iArg[0] = userConfigData0;
466 m.iArg[1] = userConfigData1;
471 return KErrNotSupported;
475 TInt r = DLogicalChannel::SendMsg(aMsg);
481 //Copy config data from local copies to client, in context of client thread
484 case RDisplayChannel::ECtrlPostCompositionBuffer:
485 __DEBUG_PRINT2("ECtrlPostCompositionBuffer =%d", kernelPostCount );
486 umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) );
489 case RDisplayChannel::ECtrlPostLegacyBuffer:
490 __DEBUG_PRINT2("ECtrlPostLegacyBuffer=%d", kernelPostCount );
491 umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) );
494 case RDisplayChannel::ECtrlRegisterUserBuffer:
495 __DEBUG_PRINT2("ECtrlRegisterUserBuffer kernelBufferId=%d", kernelBufferId );
496 umemput32(userConfigData1, &kernelBufferId, sizeof(TInt) );
499 case RDisplayChannel::ECtrlSetRotation:
500 __DEBUG_PRINT2("ECtrlSetRotation kernelRotChanged=%d", kernelRotChanged );
501 umemput32(userConfigData1, &kernelRotChanged, sizeof(TBool) );
504 case RDisplayChannel::ECtrlCurrentRotation:
505 __DEBUG_PRINT2("ECtrlCurrentRotation kernelRotation=%d", kernelRotation );
506 umemput32(userConfigData0, &kernelRotation, sizeof(RDisplayChannel::TDisplayRotation) );
509 case RDisplayChannel::ECtrlGetCompositionBufferInfo:
510 __DEBUG_PRINT3("ECtrlGetCompositionBufferInfo kernelpack[0] =%d and kernelpack[1] =%d", kernelpack[0], kernelpack[1]);
511 umemput32(userConfigData1, &kernelpack, (sizeof(TInt)*2) );
519 All driver's client requests (synchronous and asynchronous) are sent as
520 kernel messages by generic kernel to logical channel. This function
521 catches messages sent by the generic kernel.
523 @param aMsg Kernel side thread message to process.
525 The iValue member of this distinguishes the message type:
526 iValue==ECloseMsg, channel close message
527 iValue==KMaxTInt, a 'DoCancel' message
528 iValue>=0, a 'DoControl' message with function number equal to iValue
529 iValue<0, a 'DoRequest' message with function number equal to ~iValue
531 void DDisplayLdd::HandleMsg(TMessageBase* aMsg)
533 TThreadMessage& m = *(TThreadMessage*)aMsg ;
535 DThread* client = m.Client();
538 if (id == (TInt)ECloseMsg)
540 //Device specific cleanup operations
543 // cancel outstanding requests
544 for(TInt k = 0; k < KPendingReqArraySize; k++)
546 for(TInt i = 0; i < KMaxQueuedRequests; i++)
548 if( iPendingReq[k][i].iTClientReq)
550 if(iPendingReq[k][i].iTClientReq->IsReady() )
552 CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel);
557 Pdd()->SetLegacyMode();
558 m.Complete(KErrNone, EFalse);
565 TInt req = m.Int0() >> 1;
567 m.Complete(KErrNone,ETrue);
570 // asynchronous request
573 //m.Int3() is the index, in the array of pending requests, to be used.
574 TInt r = DoRequest(~id,m.Ptr1(),m.Ptr2(),m.Int3(), client);
575 m.Complete(r, ETrue);
577 // synchronous request
580 TInt r = DoControl(id,m.Ptr0(),m.Ptr1(), client);
587 Cancel outstanding request.
589 @param aReqNumber Any value from the RDisplayChannel::TRequest enumeration.
591 void DDisplayLdd::DoCancel(TUint aReqNumber)
593 __DEBUG_PRINT2("DDisplayLdd::DoCancel %d\n",aReqNumber);
597 case RDisplayChannel::ECtrlCancelGetCompositionBuffer:
598 case RDisplayChannel::ECtrlCancelPostUserBuffer:
599 case RDisplayChannel::ECtrlCancelWaitForPost:
600 TInt pendingIndex = iPendingIndex[aReqNumber];
601 if(iPendingReq[aReqNumber][pendingIndex].iTClientReq)
603 if( iPendingReq[aReqNumber][pendingIndex].iTClientReq->IsReady() )
605 CompleteRequest(iPendingReq[aReqNumber][pendingIndex].iOwningThread,iPendingReq[aReqNumber][pendingIndex].iTClientReq,KErrCancel);
614 Asynchronous request processing.
616 @param aFunction Request function number
617 @param apArg1 Pointer to kernel message argument 1.
618 @param apArg2 Pointer to kernel message argument 2.
619 @param aPendingIndex Index pointing to the appropriate TClientRequest object to use.
620 @param aClient Pointer to the client thread that issued the asynchronous request.
622 @return request scheduling result, system-wide error code.
624 TInt DDisplayLdd::DoRequest(TInt aReqNumber, TAny* aArg1, TAny* aArg2, TInt aPendingIndex, DThread* aClient)
629 TBufferNode* node = 0;
632 TInt* configBufferIdx ;
633 RDisplayChannel::TPostCount* postCount;
636 __DEBUG_PRINT5("DoRequest: iClientRequest[aReqNumber=%d][aPendingIndex=%d] is %08x and aClient=%08x\n",aReqNumber, aPendingIndex,iClientRequest[aReqNumber][aPendingIndex], aClient);
638 // 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.
640 __ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__));
642 __e32_atomic_add_ord32(&iThreadOpenCount, 1);
645 for(TInt i = 0; i < KMaxQueuedRequests; i++)
647 //Don't cancel the asyncrhonous request we currently process.
648 if (i == aPendingIndex)
652 // cancel outstanding request
653 if(iPendingReq[aReqNumber][i].iTClientReq)
655 //If IsReady() returns true, setStatus has been called for that TCientRequest but QueueRequestComplete hasn't.
656 //In that case we want to cancel this outstanding request. Given that all QueueRequestComplete calls execute
657 // in the same DFC thread we currently run, there is no need to synchronise request completion calls.
658 if(iPendingReq[aReqNumber][i].iTClientReq->IsReady() )
660 CompleteRequest(iPendingReq[aReqNumber][i].iOwningThread,iPendingReq[aReqNumber][i].iTClientReq,KErrCancel);
665 // store index, request and client
666 iPendingIndex[aReqNumber] = aPendingIndex;
667 iPendingReq[aReqNumber][aPendingIndex].iTClientReq = iClientRequest[aReqNumber][aPendingIndex];
668 iPendingReq[aReqNumber][aPendingIndex].iOwningThread = aClient;
671 __e32_atomic_add_ord32(&iAsyncReqCount, 1);
676 case RDisplayChannel::EReqGetCompositionBuffer: //DFC thread updates a value the client thread should read.
678 configBufferIdx = (TInt*) aArg1;
681 TBool found = EFalse;
683 for(index = 0; index < (TInt) iDisplayInfo.iNumCompositionBuffers; index++)
685 if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose )
687 __DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index);
689 iCompositionBuffIdx = index;
690 *configBufferIdx = iCompositionBuffIdx;
691 iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose;
692 CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread,iPendingReq[aReqNumber][aPendingIndex].iTClientReq,r);
697 if(!found) //There are no free buffers schedule request for completion
699 //Case of a single composition buffer.
700 if (iDisplayInfo.iNumCompositionBuffers == 1)
702 iCompositionBuffIdx = 0;
703 *configBufferIdx = iCompositionBuffIdx;
704 CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread, iPendingReq[aReqNumber][aPendingIndex].iTClientReq, r);
705 __DEBUG_PRINT("EReqGetCompositionBuffer The single Composition buffer is currently being used\n");
710 for( index=0; index< KDisplayCBMax; index++)
712 if(iCompositionBuffer[index].iState == EBufferActive)
714 iCompositionBuffIdx = index;
715 *configBufferIdx = iCompositionBuffIdx;
716 __DEBUG_PRINT2("EReqGetCompositionBuffer No composition buffer available. Next available is iCompositionBuffIdx %d.\n",iCompositionBuffIdx );
725 case RDisplayChannel::EReqPostUserBuffer: //DFC thread should read client message data and update a value the client will read.
726 configPack = (TInt*) aArg1;
727 pack[0] = *configPack;
729 pack[1] = *configPack;
733 if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) )
735 node = FindUserBufferNode(buffer_id);
736 if(node && (!(node->iFree) && node->iChunk ) )
738 __DEBUG_PRINT2("EReqPostUserBuffer Posting buffer id: %d \n",buffer_id );
739 r = Pdd()->PostUserBuffer(node);
742 postCount = (RDisplayChannel::TPostCount*) aArg2;
744 *postCount= iCurrentPostCount;
749 RequestComplete(RDisplayChannel::EReqPostUserBuffer, r);
753 case RDisplayChannel::EReqWaitForPost: //DFC thread should read client message data.
754 postCount = (RDisplayChannel::TPostCount*) aArg1;
755 iRequestedPostCount = *postCount;
757 //Any post operation increases iCurrentPostCount instantly but the actual post completes later on.
758 if( ! Pdd()->PostPending() )
760 RequestComplete(RDisplayChannel::EReqWaitForPost, KErrNone);
765 __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number
772 Synchronous requests processing.
774 @param aFunction Request function number,
775 @param apArg1 Pointer to kernel message argument 0.
776 @param apArg2 Pointer to kernel message argument 1.
777 @param aClient Pointer to the client thread that issued the synchronous request.
779 @return request processing result
781 TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient)
784 TBool changedRot = ETrue;
785 TBufferNode* node = 0;
787 TInt pack[2] = {0,0};
791 RDisplayChannel::TPostCount *postCount ;
792 RDisplayChannel::TDisplayRotation *rotation;
797 TBool *rotationChanged;
802 case RDisplayChannel::ECtrlPostCompositionBuffer: //DFC thread updates a value the client thread should read.
803 postCount = (RDisplayChannel::TPostCount*) aArg2;
805 node = &iCompositionBuffer[iCompositionBuffIdx];
806 r = Pdd()->PostCompositionBuffer(node);
810 *postCount = iCurrentPostCount;
818 case RDisplayChannel::ECtrlPostLegacyBuffer: //DFC thread updates a value the client thread should read.
819 postCount = (RDisplayChannel::TPostCount*) aArg2;
820 r= Pdd()->PostLegacyBuffer();
824 *postCount = iCurrentPostCount;
828 case RDisplayChannel::ECtrlRegisterUserBuffer: //DFC thread should read client message data and update a value the client will read.
829 node = FindUserBufferNode(0);
832 configPack = (TInt*) aArg1;
833 handle = *configPack;
835 offset = *configPack;
836 r = CheckAndOpenUserBuffer(node, handle, offset, aClient);
840 bufferId = (TInt*) aArg2;
841 *bufferId = node->iBufferId;
850 case RDisplayChannel::ECtrlDeregisterUserBuffer: //DFC thread should read client message data.
851 bufferId = (TInt*) aArg1;
852 buffer_id = *bufferId;
856 if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) )
858 node = FindUserBufferNode(buffer_id);
859 if(node && (!(node->iFree) && node->iChunk ) )
861 if(node->iState==EBufferFree || node->iState==EBufferCompose )
863 r = FreeUserBufferNode(node);
873 case RDisplayChannel::ECtrlSetRotation: //DFC thread should read client message data and update a value the client will read.
875 RDisplayChannel::TDisplayRotation rot;
876 RDisplayChannel::TDisplayRotation previousRot = iCurrentRotation;
878 rotation = (RDisplayChannel::TDisplayRotation*) aArg1;
881 __DEBUG_PRINT3("ECtrlSetRotation previousRot= %d and rot =%d \n",previousRot, rot );
883 r = Pdd()->SetRotation(rot);
884 changedRot = (previousRot != iCurrentRotation);
887 rotationChanged = (TBool*) aArg2;
888 *rotationChanged = changedRot ;
893 case RDisplayChannel::ECtrlCurrentRotation: //DFC thread updates a value the client thread should read.
894 rotation = (RDisplayChannel::TDisplayRotation*) aArg1;
895 *rotation = iCurrentRotation;
898 case RDisplayChannel::ECtrlGetCompositionBufferInfo: //DFC thread should read client message data and update a value the client will read.
899 idx = ( TInt * ) aArg1;
902 if( (index >= (TInt) iDisplayInfo.iNumCompositionBuffers ) || (index < 0 ) )
907 r = Kern::MakeHandleAndOpen(aClient, iCompositionBuffer[index].iChunk);
912 pack[1] = iCompositionBuffer[index].iOffset;
914 configPack = (TInt * ) aArg2;
915 *configPack = pack[0];
917 *configPack = pack[1];
924 case RDisplayChannel::ECtrlCreateUserBuffer:
926 TUint32 chunkMapAttr;
928 TPhysAddr physicalAddr;
929 RDisplayChannel::TBufferFormat bufferFormat;
931 // Read the information from the user thread pertaining to the buffer to be allocated
932 Kern::ThreadRawRead(aClient, aArg1, &bufferFormat, sizeof(bufferFormat));
934 // Allocate a chunk that can be used as a user buffer. Don't worry about the # of bytes
935 // per pixel as this is UDEB only test code - just set it to 4 and that will ensure that
936 // it is large enough
937 TChunkCreateInfo chunkCreateInfo;
938 chunkCreateInfo.iType = TChunkCreateInfo::ESharedKernelSingle;
940 chunkCreateInfo.iMapAttr = EMapAttrFullyBlocking;
942 chunkCreateInfo.iOwnsMemory = ETrue;
943 chunkCreateInfo.iDestroyedDfc = NULL;
944 chunkCreateInfo.iMaxSize = (bufferFormat.iSize.iWidth * bufferFormat.iSize.iHeight * 4);
946 if ((r = Kern::ChunkCreate(chunkCreateInfo, iChunk, chunkBase, chunkMapAttr)) == KErrNone)
948 // Commit some contiguous physical RAM for use in the chunk
949 r = Kern::ChunkCommitContiguous(iChunk, 0, chunkCreateInfo.iMaxSize, physicalAddr);
951 // And open a handle to the chunk that will be returned to user side for use in the user
952 // side's RChunk object
954 r = Kern::MakeHandleAndOpen(aClient, iChunk);
957 Kern::ChunkClose(iChunk);
967 __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number
974 Open a shared Chunk for the User buffer and then set the appropriate values for the
975 User buffer node attributes.
978 TInt DDisplayLdd::CheckAndOpenUserBuffer(TBufferNode* aNode, TInt aHandle, TInt aOffset, DThread* aClient)
983 TLinAddr kernelAddress = 0;
985 TUint32 physicalAddress = 0;
986 TUint32 *physicalPageList = 0;
987 TInt r = KErrBadHandle;
989 NKern::ThreadEnterCS();
990 chunk = Kern::OpenSharedChunk(aClient, aHandle, EFalse);
991 NKern::ThreadLeaveCS();
995 // Using iOffsetBetweenLines rather than iWidth as the controller may be using stride
996 size = iDisplayInfo.iNormal.iOffsetBetweenLines * iDisplayInfo.iNormal.iHeight;
998 r = Kern::ChunkPhysicalAddress(chunk, aOffset, size, kernelAddress, mapAttr, physicalAddress, physicalPageList);
1001 aNode->iChunk = chunk;
1002 aNode->iFree = EFalse;
1003 aNode->iState = EBufferCompose;
1004 aNode->iAddress = (TUint32)kernelAddress;
1005 aNode->iHandle = aHandle;
1006 aNode->iPhysicalAddress = physicalAddress;
1009 { // we have an error here, close the chunk
1011 Kern::ChunkClose(chunk);
1019 Return any free buffer when trying to register a User buffer( aBufferId ==0 )
1020 or return the specified User buffer( used by Deregister and PostUserBuffer).
1021 In the second case checks about the state of the user buffer are specific to
1025 TBufferNode* DDisplayLdd::FindUserBufferNode(TInt aBufferId)
1027 TBufferNode* node = 0;
1031 for(TInt i = 0; i < KDisplayUBMax; i++)
1033 if(iUserBuffer[i].iFree)
1035 node = &iUserBuffer[i];
1042 node = &iUserBuffer[aBufferId-1];
1049 Free user buffer by reseting all the appropriate fields and closing the corresponding chunk.
1051 TInt DDisplayLdd::FreeUserBufferNode(TBufferNode* aNode)
1053 __DEBUG_PRINT2("FreeUserBufferNode with aNode->iAddress %08x.\n",aNode->iAddress );
1055 NKern::ThreadEnterCS();
1056 if(aNode->iChunk != 0)
1058 r= Kern::ChunkClose(aNode->iChunk);
1062 aNode->iState = EBufferFree;
1063 aNode->iFree = ETrue;
1064 aNode->iAddress = 0;
1071 __DEBUG_PRINT("Failed to close chunk\n");
1073 NKern::ThreadLeaveCS();
1080 Calls CompleteRequest( which internally calls Kern::QueueRequestComplete )for the specified request and with the reason passed,
1081 in case such an asynchronous request is pending. Called by both the LDD and PDD.
1084 TInt DDisplayLdd::RequestComplete(TInt aRequest, TInt aReason)
1086 TBool flag = EFalse;
1088 TInt pendingIndex = iPendingIndex[aRequest] ;
1092 case RDisplayChannel::EReqGetCompositionBuffer:
1094 __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqGetCompositionBuffer request and reason %d\n",aReason );
1096 if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq )
1098 if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq->IsReady() )
1106 case RDisplayChannel::EReqWaitForPost:
1108 __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqWaitForPost request and reason %d\n",aReason );
1110 if(iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq)
1112 if( iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq->IsReady() && (iCurrentPostCount >= iRequestedPostCount) )
1120 case RDisplayChannel::EReqPostUserBuffer:
1122 __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqPostUserBuffer request and reason %d\n",aReason );
1124 if(iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq)
1126 if( iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq->IsReady() )
1134 __DEBUG_PRINT("RequestComplete() called for an unknown request\n");
1141 CompleteRequest(iPendingReq[aRequest][pendingIndex].iOwningThread,iPendingReq[aRequest][pendingIndex].iTClientReq,aReason);
1149 Complete an asynchronous request back to the client.
1151 @param aThread The client thread which issued the request.
1152 @param aTClientReq Pointer reference to the TClientRequest object
1153 @param aReason The request status code.
1155 @pre The thread must be in a critical section.
1157 void DDisplayLdd::CompleteRequest(DThread* aThread, TClientRequest*& aTClientReq, TInt aReason)
1159 __DEBUG_PRINT4("Complete aTClientReq %08x with reason %d for aThread = %08x\n", aTClientReq, aReason,aThread );
1161 Kern::QueueRequestComplete(aThread,aTClientReq,aReason);
1163 aThread->AsyncClose(); // Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference.
1169 __e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1));
1170 __e32_atomic_add_ord32(&iAsyncReqCount, TUint32(-1));
1178 static factory function for the LDD.
1180 @return pointer to the created (or existing) instance of the class
1182 DDisplayLdd* DDisplayLdd::CreateInstance()
1184 __DEBUG_PRINT("DDisplayLdd::CreateInstance()\n");
1185 // create LDD channel instance
1186 DDisplayLdd* obj = new DDisplayLdd();
1192 /************************************************************************************
1193 * LDD factory, DDisplayLddFactory class implementation
1194 ************************************************************************************/
1199 DDisplayLddFactory::DDisplayLddFactory()
1201 __DEBUG_PRINT("DDisplayLddFactory::DDisplayLddFactory() \n");
1203 iParseMask = KDeviceAllowPhysicalDevice | KDeviceAllowUnit ;
1205 iVersion = TVersion( KDisplayChMajorVersionNumber,
1206 KDisplayChMinorVersionNumber,
1207 KDisplayChBuildVersionNumber);
1216 DDisplayLddFactory::~DDisplayLddFactory()
1222 static factory function for the LDD factory.
1224 @return pointer to the created instance of the class
1226 DDisplayLddFactory* DDisplayLddFactory::CreateInstance()
1229 __DEBUG_PRINT("DDisplayLddFactory::CreateInstance() \n");
1231 DDisplayLddFactory* obj = new DDisplayLddFactory;
1237 Set our name and return error code
1239 TInt DDisplayLddFactory::Install()
1242 __DEBUG_PRINT("DDisplayLddFactory::Install() \n");
1243 return SetName(&RDisplayChannel::Name());
1247 void DDisplayLddFactory::GetCaps(TDes8& /*aDes*/) const
1255 LDD factory function. Creates LDD object.
1257 @param aChannel A pointer to an LDD channel object which will be initialised on return.
1259 @return KErrNone if object successfully allocated, KErrNoMemory if not.
1261 TInt DDisplayLddFactory::Create(DLogicalChannelBase*& aChannel)
1263 __DEBUG_PRINT("DDisplayLddFactory::Create \n");
1264 aChannel = DDisplayLdd::CreateInstance();
1265 return (!aChannel)? KErrNoMemory : KErrNone;
1271 Check whether a channel is currently open on the specified unit.
1272 @param aUnit The number of the unit to be checked.
1273 @return ETrue if a channel is open on the specified channel, EFalse otherwise.
1274 @pre The unit info. mutex must be held.
1276 TBool DDisplayLddFactory::IsUnitOpen(TInt aUnit)
1278 return(iUnitsOpenMask&(1<<aUnit));
1283 Attempt to change the state of the channel open status for a particular channel.
1284 @param aUnit The number of the unit to be updated.
1285 @param aIsOpenSetting The required new state for the channel open status: either ETrue to set the status to open or
1286 EFalse to set the status to closed.
1287 @return KErrNone if the status was updated successfully, KErrInUse if an attempt has been made to set the channnel status
1288 to open while it is already open.
1290 TInt DDisplayLddFactory::SetUnitOpen(TInt aUnit,TBool aIsOpenSetting)
1293 NKern::FMWait(&iUnitInfoMutex); // Acquire the unit info. mutex.
1295 // Fail a request to open an channel that is already open
1296 if (aIsOpenSetting && IsUnitOpen(aUnit))
1298 NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
1302 // Update the open status as requested
1304 iUnitsOpenMask|=(1<<aUnit);
1306 iUnitsOpenMask&=~(1<<aUnit);
1308 NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
1314 "Standard LDD" entrypoint.
1316 Is called on CreateLogicalDevice() if the user calls LoadLogicalDevice(). Creates LDD factory.
1318 @return pointer to the LDD factory object.
1320 DECLARE_STANDARD_LDD()
1322 __DEBUG_PRINT("DECLARE_STANDARD_LDD() \n");
1323 DDisplayLddFactory* pLDDFactory = DDisplayLddFactory::CreateInstance();