os/kernelhwsrv/kernel/eka/drivers/display/display.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// os\kernelhwsrv\kernel\eka\drivers\display\display.cpp  
sl@0
    15
// LDD for a Display driver with GCE support
sl@0
    16
// 
sl@0
    17
//
sl@0
    18
sl@0
    19
/**
sl@0
    20
 @file
sl@0
    21
 @internalTechnology
sl@0
    22
 @prototype
sl@0
    23
*/
sl@0
    24
sl@0
    25
sl@0
    26
#include <drivers/display.h>
sl@0
    27
#include <kernel/kern_priv.h>
sl@0
    28
sl@0
    29
sl@0
    30
const TUint8  KMutexOrder             = 0x3f;
sl@0
    31
sl@0
    32
static const char KDisplayLddPanic[]  ="DISPLAY/GCE LDD";
sl@0
    33
sl@0
    34
_LIT(KClientRequestMutex, "ClientRequestMutex");
sl@0
    35
sl@0
    36
sl@0
    37
/************************************************************************************
sl@0
    38
 *            DDisplayLdd LDD class implementation
sl@0
    39
 ************************************************************************************/
sl@0
    40
DDisplayLdd::DDisplayLdd()		
sl@0
    41
	{	
sl@0
    42
	__DEBUG_PRINT("DDisplayLdd::DDisplayLdd()\n");
sl@0
    43
	// store the pointer to the current thread for request completion
sl@0
    44
  	iClient = &Kern::CurrentThread();
sl@0
    45
    __NK_ASSERT_DEBUG(iClient);
sl@0
    46
	// Open a reference on the client thread so it's control block can't disappear until the driver has finished with it.
sl@0
    47
    iClient->Open();
sl@0
    48
    iCurrentPostCount   = 0;
sl@0
    49
    iRequestedPostCount = 0;
sl@0
    50
    iCompositionBuffIdx = 0;
sl@0
    51
    iUnit				= -1;
sl@0
    52
    iThreadOpenCount    = 0;
sl@0
    53
    iAsyncReqCount		= 0;
sl@0
    54
    iClientRequestMutex = 0;	
sl@0
    55
	}
sl@0
    56
sl@0
    57
sl@0
    58
DDisplayLdd::~DDisplayLdd()
sl@0
    59
	{
sl@0
    60
	__DEBUG_PRINT("DDisplayLdd::~DDisplayLdd()  \n"); 
sl@0
    61
     // cancel outstanding requests and destroy the queue of TClientRequest objects
sl@0
    62
    for(TInt k = 0; k < KPendingReqArraySize ; k++)
sl@0
    63
    	{
sl@0
    64
		for(TInt i = 0; i < KMaxQueuedRequests; i++)
sl@0
    65
			{
sl@0
    66
			//Method IsReady() returns true if the client’s request SetStatus method has been called but the 
sl@0
    67
			//coresponding QueueRequestComplete method hasn't.			
sl@0
    68
			if(iPendingReq[k][i].iTClientReq)        
sl@0
    69
				{
sl@0
    70
				if(iPendingReq[k][i].iTClientReq->IsReady() )
sl@0
    71
					{
sl@0
    72
					CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel);        	
sl@0
    73
					}     		
sl@0
    74
				}			
sl@0
    75
			Kern::DestroyClientRequest(iClientRequest[k][i]);
sl@0
    76
			}
sl@0
    77
		}
sl@0
    78
    
sl@0
    79
    //Close User Buffer chunks not yet destroyed.
sl@0
    80
	for(TInt i = 0; i < KDisplayUBMax; i++)
sl@0
    81
		{
sl@0
    82
		if(iUserBuffer[i].iChunk != 0)
sl@0
    83
			{
sl@0
    84
    		Kern::ChunkClose(iUserBuffer[i].iChunk);
sl@0
    85
    		iUserBuffer[i].iChunk= NULL;
sl@0
    86
			}
sl@0
    87
		}
sl@0
    88
    	
sl@0
    89
    Kern::SafeClose((DObject*&)iClient, NULL);  
sl@0
    90
    
sl@0
    91
    
sl@0
    92
    if (iClientRequestMutex != NULL)
sl@0
    93
         {
sl@0
    94
         iClientRequestMutex->Close(NULL);
sl@0
    95
         }
sl@0
    96
    
sl@0
    97
    __ASSERT_DEBUG(iThreadOpenCount == 0,Kern::Fault(KDisplayLddPanic,__LINE__));
sl@0
    98
    __ASSERT_DEBUG(iAsyncReqCount   == 0,Kern::Fault(KDisplayLddPanic,__LINE__));  
sl@0
    99
    	
sl@0
   100
    // Clear the 'units open mask' in the LDD factory.
sl@0
   101
	if (iUnit>=0)
sl@0
   102
		((DDisplayLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse);	 	
sl@0
   103
sl@0
   104
#ifdef _DEBUG
sl@0
   105
	// Close the UDEB user mode chunk, if it exists
sl@0
   106
	if (iChunk)
sl@0
   107
		Kern::ChunkClose(iChunk);
sl@0
   108
#endif // _DEBUG
sl@0
   109
	}
sl@0
   110
 
sl@0
   111
sl@0
   112
/**
sl@0
   113
	LDD second stage constructor
sl@0
   114
*/
sl@0
   115
TInt DDisplayLdd::DoCreate(TInt aUnit, const TDesC8* /* anInfo*/, const TVersion& aVer)
sl@0
   116
	{ 
sl@0
   117
	
sl@0
   118
	__DEBUG_PRINT("DDisplayLdd::DoCreate()\n"); 
sl@0
   119
sl@0
   120
	if(    !Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,      __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
sl@0
   121
		|| !Kern::CurrentThreadHasCapability(ECapabilityReadDeviceData, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
sl@0
   122
		|| !Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
sl@0
   123
		|| !Kern::CurrentThreadHasCapability(ECapabilityProtServ,       __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) )
sl@0
   124
		{
sl@0
   125
		return KErrPermissionDenied;
sl@0
   126
		}
sl@0
   127
		  
sl@0
   128
	// Check that the display driver version specified by the client is compatible.
sl@0
   129
	if (!Kern::QueryVersionSupported(RDisplayChannel::VersionRequired(),aVer))
sl@0
   130
		{
sl@0
   131
		return(KErrNotSupported);		
sl@0
   132
		}
sl@0
   133
				
sl@0
   134
	// Check that a channel hasn't already been opened on this unit.
sl@0
   135
	TInt r=((DDisplayLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory.
sl@0
   136
	if (r!=KErrNone)
sl@0
   137
		return r;
sl@0
   138
	iUnit=aUnit;
sl@0
   139
sl@0
   140
 	Pdd()->iLdd	= this;
sl@0
   141
 	
sl@0
   142
 	r		= Pdd()->CreateChannelSetup(aUnit); 	
sl@0
   143
 	if ( r!= KErrNone)
sl@0
   144
 		{
sl@0
   145
 		return r; 		
sl@0
   146
 		}
sl@0
   147
 
sl@0
   148
     // set up user buffer nodes
sl@0
   149
    for (TInt node = 0; node < KDisplayUBMax; node++)
sl@0
   150
    	{
sl@0
   151
        iUserBuffer[node].iType 	= EBufferTypeUser;
sl@0
   152
        iUserBuffer[node].iBufferId = (node + 1);
sl@0
   153
        iUserBuffer[node].iFree 	= ETrue;
sl@0
   154
        iUserBuffer[node].iState 	= EBufferFree;
sl@0
   155
        iUserBuffer[node].iAddress  = 0;
sl@0
   156
        iUserBuffer[node].iSize  	= 0;
sl@0
   157
        iUserBuffer[node].iHandle  	= 0;
sl@0
   158
        iUserBuffer[node].iChunk  	= 0;
sl@0
   159
        iUserBuffer[node].iOffset 	= 0;
sl@0
   160
        iUserBuffer[node].iPendingRequest = 0;
sl@0
   161
    	}
sl@0
   162
sl@0
   163
    //Initialise pending queue for asynchronous requests and queue of TClientRequests
sl@0
   164
    for(TInt k = 0; k < KPendingReqArraySize; k++) 
sl@0
   165
    	{
sl@0
   166
    	
sl@0
   167
    	iPendingIndex[k]=0;
sl@0
   168
    	
sl@0
   169
		for(TInt i = 0; i < KMaxQueuedRequests; i++)
sl@0
   170
			{
sl@0
   171
			iPendingReq[k][i].iTClientReq   = 0;
sl@0
   172
			iPendingReq[k][i].iOwningThread = 0;
sl@0
   173
			
sl@0
   174
			
sl@0
   175
			r = Kern::CreateClientRequest(iClientRequest[k][i]);
sl@0
   176
			if (r != KErrNone)
sl@0
   177
				{
sl@0
   178
				return r;      	
sl@0
   179
				}
sl@0
   180
			}	
sl@0
   181
    	} 
sl@0
   182
    
sl@0
   183
    r = Kern::MutexCreate(iClientRequestMutex, KClientRequestMutex, KMutexOrder);	
sl@0
   184
	if (r != KErrNone)
sl@0
   185
		{
sl@0
   186
		return r;
sl@0
   187
		}	
sl@0
   188
    
sl@0
   189
          
sl@0
   190
    Pdd()->SetGceMode();	
sl@0
   191
	SetDfcQ(Pdd()->DfcQ(aUnit));	   
sl@0
   192
    iMsgQ.Receive();
sl@0
   193
    
sl@0
   194
    return KErrNone;		
sl@0
   195
}
sl@0
   196
sl@0
   197
sl@0
   198
/**
sl@0
   199
Override DLogicalChannel::SendMsg to process a client message before and after sending the message 
sl@0
   200
to the DFC thread for processing by HandleMsg().
sl@0
   201
 
sl@0
   202
This function is called in the context of the client thread.
sl@0
   203
sl@0
   204
The function is used to pin client data in the context of the client thread, so that data can be safely
sl@0
   205
accessed from kernel threads without the possibility of taking page faults.
sl@0
   206
 
sl@0
   207
@param aMsg  The message to process.
sl@0
   208
             The iValue member of this distinguishes the message type:
sl@0
   209
			 iValue==ECloseMsg, channel close message
sl@0
   210
			 iValue==KMaxTInt, a 'DoCancel' message
sl@0
   211
			 iValue>=0, a 'DoControl' message with function number equal to iValue
sl@0
   212
			 iValue<0, a 'DoRequest' message with function number equal to ~iValue
sl@0
   213
  
sl@0
   214
 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error
sl@0
   215
        codes.
sl@0
   216
 
sl@0
   217
 */ 
sl@0
   218
sl@0
   219
TInt DDisplayLdd::SendMsg(TMessageBase* aMsg)
sl@0
   220
	{
sl@0
   221
	TThreadMessage& m=*(TThreadMessage*)aMsg;
sl@0
   222
    TInt id = m.iValue;
sl@0
   223
	
sl@0
   224
	TInt r = KErrNone;	
sl@0
   225
	 // close msg or cancel
sl@0
   226
	if (id == (TInt)ECloseMsg || id == KMaxTInt)
sl@0
   227
		{
sl@0
   228
		r = DLogicalChannel::SendMsg(aMsg);
sl@0
   229
		}
sl@0
   230
	//asynchronous request
sl@0
   231
	else if (id < 0)
sl@0
   232
		{
sl@0
   233
		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
sl@0
   234
		r = SendRequest(aMsg);
sl@0
   235
		if (r != KErrNone)
sl@0
   236
			Kern::RequestComplete(pS,r);
sl@0
   237
		}
sl@0
   238
	 // synchronous request
sl@0
   239
	else{
sl@0
   240
		r = SendControl(aMsg);
sl@0
   241
		}
sl@0
   242
	
sl@0
   243
	return r;
sl@0
   244
	}
sl@0
   245
sl@0
   246
sl@0
   247
/**
sl@0
   248
Validate, pre-process, send and post-process data for an asynchronous client request, so that data can be safely
sl@0
   249
accessed from kernel threads without the possibility of taking page faults. 
sl@0
   250
sl@0
   251
This function is called in the context of the client thread.
sl@0
   252
 
sl@0
   253
@param aMsg  The message to process.
sl@0
   254
             The iValue member of this distinguishes the message type:
sl@0
   255
			 iValue==ECloseMsg, channel close message
sl@0
   256
			 iValue==KMaxTInt, a 'DoCancel' message
sl@0
   257
			 iValue>=0, a 'DoControl' message with function number equal to iValue
sl@0
   258
			 iValue<0, a 'DoRequest' message with function number equal to ~iValue
sl@0
   259
 
sl@0
   260
 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error
sl@0
   261
        codes.
sl@0
   262
 */ 
sl@0
   263
TInt DDisplayLdd::SendRequest(TMessageBase* aMsg)
sl@0
   264
	{
sl@0
   265
	TThreadMessage& m	=*(TThreadMessage*)aMsg;
sl@0
   266
    TInt aReqNumber 	= ~m.iValue;
sl@0
   267
	TRequestStatus* pS	=(TRequestStatus*)m.Ptr0();
sl@0
   268
	
sl@0
   269
	#ifdef _GCE_DISPLAY_DEBUG
sl@0
   270
	DThread* client 	= m.Client();
sl@0
   271
	#endif		
sl@0
   272
			
sl@0
   273
	TInt r 				= KErrNotSupported;
sl@0
   274
	TInt pendingIndex;
sl@0
   275
sl@0
   276
	/*Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. 
sl@0
   277
	Using thread local copies is possible even for asynchronous requests, since the values to be returned are known 
sl@0
   278
	when processing the request( inside DoRequest ) and not at a later stage.*/
sl@0
   279
	
sl@0
   280
	TInt kernelCompBuffIdx;
sl@0
   281
	TInt kernelpack[2];	
sl@0
   282
	RDisplayChannel::TPostCount  kernelCount;
sl@0
   283
	
sl@0
   284
	
sl@0
   285
	//In asynchronous requests m.Ptr0 is used for the TRequestStatus object.
sl@0
   286
	TAny* userConfigData1 = m.Ptr1();
sl@0
   287
	TAny* userConfigData2 = m.Ptr2();
sl@0
   288
	
sl@0
   289
	/*
sl@0
   290
	If the client request needs to pass some data to the DFC thread then we copy these to a thread local
sl@0
   291
	copy(created in the thread supervisor stack) and then update the message to point to that local copy. 
sl@0
   292
	If the client will have to read a value updated in the DFC thread, then the message should just be 
sl@0
   293
	updated and point to the local copy. After the request has completed the updated data will be copied
sl@0
   294
	from the local copy to the client, in the context of the client thread. 
sl@0
   295
	*/
sl@0
   296
    
sl@0
   297
    switch (aReqNumber)
sl@0
   298
		{
sl@0
   299
	    case RDisplayChannel::EReqGetCompositionBuffer:	//Client should read data updated in the DFC thread.
sl@0
   300
				m.iArg[1] = &kernelCompBuffIdx;				
sl@0
   301
				break;
sl@0
   302
sl@0
   303
        case RDisplayChannel::EReqPostUserBuffer:    	//Both the client and DFC thread need to read data.
sl@0
   304
				umemget32(&kernelpack, userConfigData1, (sizeof(TInt)*2) );
sl@0
   305
				m.iArg[1] = &kernelpack;
sl@0
   306
				m.iArg[2] = &kernelCount;
sl@0
   307
				break;		
sl@0
   308
		
sl@0
   309
		case RDisplayChannel::EReqWaitForPost:			//Client data should be passed to the DFC thread.	
sl@0
   310
				umemget32(&kernelCount, userConfigData1, sizeof(RDisplayChannel::TPostCount) );
sl@0
   311
				m.iArg[1] = &kernelCount;							
sl@0
   312
				break;
sl@0
   313
		default:
sl@0
   314
				return KErrNotSupported; 
sl@0
   315
		
sl@0
   316
		}
sl@0
   317
		
sl@0
   318
	/* 		
sl@0
   319
	The TClientRequest objects associated with each asynchronous request need to be accessed by both the client and DFC
sl@0
   320
	threads. To resolve the potential synchronization problem we maintain two seperate pointers(iClientRequest and 
sl@0
   321
	iPendingReq.iClientReq )to the same TClientRequest object. iClientRequestMutex is used to synchronise access to 
sl@0
   322
	iClientRequest from different client threads. The first client thread that acquires the mutex will set the status
sl@0
   323
	of an available TClientRequest object and send the message(call SendMsg). Consequently method DoRequest is queued for 
sl@0
   324
	execution by the DFC thread. DoRequest initialy saves iClientRequest to iPendingReq.iClientReq and queues the request. 
sl@0
   325
	Only then, the mutex is signaled. Another client thread trying to access iClientRequest will block in the mutex until
sl@0
   326
	DoRequest has updated iPendingReq.iClientReq. Even more the DFC thread only accesses iClientRequest in DoRequest and 
sl@0
   327
	then iPendingReq.iClientReq is only used, so synchronizing access to iPendingReq.iClientReq is handled by the DFC queue.
sl@0
   328
	*/
sl@0
   329
	
sl@0
   330
	// Need to be in critical section whilst holding a DMutex
sl@0
   331
	NKern::ThreadEnterCS();
sl@0
   332
	
sl@0
   333
	Kern::MutexWait(*iClientRequestMutex);	
sl@0
   334
	//Save the TRequestStatus in any available TClientRequest object for that asynchronous request.
sl@0
   335
	
sl@0
   336
	for( TInt k=0; k< KMaxQueuedRequests; k++) 
sl@0
   337
		{
sl@0
   338
		//setStatus will return KErrInUse if a previous client request hasn't completed yet.
sl@0
   339
		r = iClientRequest[aReqNumber][k]->SetStatus(pS);
sl@0
   340
		if( r == KErrNone)
sl@0
   341
			{
sl@0
   342
			pendingIndex = k;
sl@0
   343
			//The current available index for this pending request will be passed as 
sl@0
   344
			//another message argument to the DFC thread.
sl@0
   345
			m.iArg[3] =  (TAny*) pendingIndex; 
sl@0
   346
			break;
sl@0
   347
			}		 			
sl@0
   348
		}
sl@0
   349
					 						
sl@0
   350
	if (r == KErrNone)
sl@0
   351
		{
sl@0
   352
		r = DLogicalChannel::SendMsg(aMsg);
sl@0
   353
		}
sl@0
   354
	else
sl@0
   355
		{
sl@0
   356
		__DEBUG_PRINT3("Client %08x trying to issue asynchronous request %d", client, aReqNumber);
sl@0
   357
		//Fail if there aren't any available TClientRequest object
sl@0
   358
		__ASSERT_DEBUG(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__));				
sl@0
   359
		}
sl@0
   360
	
sl@0
   361
	Kern::MutexSignal(*iClientRequestMutex);
sl@0
   362
sl@0
   363
    NKern::ThreadLeaveCS();
sl@0
   364
    
sl@0
   365
    //Copy config data from local copies to client, in context of client thread
sl@0
   366
    switch (aReqNumber)
sl@0
   367
		{
sl@0
   368
	    case RDisplayChannel::EReqGetCompositionBuffer:
sl@0
   369
	    		__DEBUG_PRINT2("EReqGetCompositionBuffer: kernelCompBuffIdx returned =%d",kernelCompBuffIdx);						
sl@0
   370
				umemput32(userConfigData1, &kernelCompBuffIdx, sizeof(TInt) );
sl@0
   371
				break;
sl@0
   372
				
sl@0
   373
        case RDisplayChannel::EReqPostUserBuffer:
sl@0
   374
        		__DEBUG_PRINT2("EReqPostUserBuffer: kernelCount returned = %d",kernelCount);
sl@0
   375
				umemput32(userConfigData2, &kernelCount, sizeof(RDisplayChannel::TPostCount) );	
sl@0
   376
				break;							
sl@0
   377
		}		 	
sl@0
   378
	return r;
sl@0
   379
	}
sl@0
   380
sl@0
   381
sl@0
   382
/**
sl@0
   383
Validate, pre-process, send and post-process data for a synchronous client request, so that data can be safely
sl@0
   384
accessed from kernel threads without the possibility of taking page faults. 
sl@0
   385
sl@0
   386
This function is called in the context of the client thread.
sl@0
   387
sl@0
   388
@param aMsg  The message to process.
sl@0
   389
             The iValue member of this distinguishes the message type:
sl@0
   390
			 iValue==ECloseMsg, channel close message
sl@0
   391
			 iValue==KMaxTInt, a 'DoCancel' message
sl@0
   392
			 iValue>=0, a 'DoControl' message with function number equal to iValue
sl@0
   393
			 iValue<0, a 'DoRequest' message with function number equal to ~iValue
sl@0
   394
						 
sl@0
   395
@return KErrNone if the message was send successfully, otherwise one of the other system-wide error
sl@0
   396
        codes.
sl@0
   397
 */ 
sl@0
   398
sl@0
   399
TInt DDisplayLdd::SendControl(TMessageBase* aMsg)
sl@0
   400
	{	
sl@0
   401
	TThreadMessage& m	= *(TThreadMessage*)aMsg;
sl@0
   402
    TInt aReqNumber 	= m.iValue;
sl@0
   403
	
sl@0
   404
sl@0
   405
	//Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. 
sl@0
   406
		
sl@0
   407
	RDisplayChannel::TPostCount  			kernelPostCount;
sl@0
   408
	RDisplayChannel::TDisplayRotation 		kernelRotation;
sl@0
   409
	
sl@0
   410
	TPckgBuf<RDisplayChannel::TDisplayInfo> pckgInfo(iDisplayInfo);
sl@0
   411
sl@0
   412
	TInt  kernelpack[2];	
sl@0
   413
	TInt  kernelBufferId;
sl@0
   414
	TBool kernelRotChanged;
sl@0
   415
	TInt  kernelIndex;
sl@0
   416
	
sl@0
   417
	TAny* userConfigData0 = m.Ptr0();
sl@0
   418
	TAny* userConfigData1 = m.Ptr1();
sl@0
   419
		
sl@0
   420
			
sl@0
   421
	switch (aReqNumber)
sl@0
   422
		{
sl@0
   423
		//iDisplayInfo doesn't change after the driver initialisation so copy in client thread context
sl@0
   424
		case RDisplayChannel::ECtrlGetDisplayInfo:
sl@0
   425
			umemput32(userConfigData0, &pckgInfo, sizeof(TPckgBuf<RDisplayChannel::TDisplayInfo>) );	
sl@0
   426
			return KErrNone;
sl@0
   427
sl@0
   428
		case RDisplayChannel::ECtrlPostCompositionBuffer:  		//Client should read data updated in the DFC thread.
sl@0
   429
			m.iArg[1] = &kernelPostCount;
sl@0
   430
			break;
sl@0
   431
		
sl@0
   432
		case RDisplayChannel::ECtrlPostLegacyBuffer:			//Client should read data updated in the DFC thread.
sl@0
   433
			m.iArg[1] = &kernelPostCount;			
sl@0
   434
			break;	
sl@0
   435
		
sl@0
   436
		case RDisplayChannel::ECtrlRegisterUserBuffer:			//Both the client and DFC thread need to read data.
sl@0
   437
			umemget32(&kernelpack, userConfigData0, (sizeof(TInt)*2) );
sl@0
   438
			m.iArg[0] = &kernelpack;			
sl@0
   439
			m.iArg[1] = &kernelBufferId;	
sl@0
   440
			break;
sl@0
   441
		
sl@0
   442
		case RDisplayChannel::ECtrlDeregisterUserBuffer:		//Client data should be passed to the DFC thread.	
sl@0
   443
			umemget32(&kernelBufferId, userConfigData0, sizeof(TInt) );
sl@0
   444
			m.iArg[0] = &kernelBufferId;				
sl@0
   445
			break;	
sl@0
   446
				
sl@0
   447
	 	case RDisplayChannel::ECtrlSetRotation:					//Both the client and DFC thread need to read data.
sl@0
   448
			umemget32(&kernelRotation, userConfigData0, sizeof(RDisplayChannel::TDisplayRotation) );
sl@0
   449
			m.iArg[0] = &kernelRotation;
sl@0
   450
			m.iArg[1] = &kernelRotChanged;
sl@0
   451
			break;
sl@0
   452
			
sl@0
   453
		case RDisplayChannel::ECtrlCurrentRotation:				//Client should read data updated in the DFC thread.
sl@0
   454
			m.iArg[0] = &kernelRotation;
sl@0
   455
			break;
sl@0
   456
			
sl@0
   457
		case RDisplayChannel::ECtrlGetCompositionBufferInfo:	//Both the client and DFC thread need to read data.		
sl@0
   458
			umemget32(&kernelIndex, userConfigData0, sizeof(TInt) );
sl@0
   459
			m.iArg[0] = &kernelIndex;
sl@0
   460
			m.iArg[1] = &kernelpack;		
sl@0
   461
			break;
sl@0
   462
sl@0
   463
#ifdef _DEBUG
sl@0
   464
		case RDisplayChannel::ECtrlCreateUserBuffer:
sl@0
   465
		    m.iArg[0] = userConfigData0;
sl@0
   466
            m.iArg[1] = userConfigData1;
sl@0
   467
            break;
sl@0
   468
#endif // _DEBUG
sl@0
   469
sl@0
   470
		default:
sl@0
   471
			return KErrNotSupported; 
sl@0
   472
				
sl@0
   473
		}
sl@0
   474
	
sl@0
   475
	TInt r = DLogicalChannel::SendMsg(aMsg);	
sl@0
   476
	if (r != KErrNone)
sl@0
   477
		{
sl@0
   478
		return r;
sl@0
   479
		}
sl@0
   480
sl@0
   481
	 //Copy config data from local copies to client, in context of client thread
sl@0
   482
    switch (aReqNumber)
sl@0
   483
		{					
sl@0
   484
	    case RDisplayChannel::ECtrlPostCompositionBuffer:  				
sl@0
   485
			__DEBUG_PRINT2("ECtrlPostCompositionBuffer =%d", kernelPostCount );
sl@0
   486
			umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) );	
sl@0
   487
			break;
sl@0
   488
		
sl@0
   489
		case RDisplayChannel::ECtrlPostLegacyBuffer:
sl@0
   490
			__DEBUG_PRINT2("ECtrlPostLegacyBuffer=%d", kernelPostCount );	
sl@0
   491
			umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) );			
sl@0
   492
			break;	
sl@0
   493
		
sl@0
   494
		case RDisplayChannel::ECtrlRegisterUserBuffer:
sl@0
   495
			__DEBUG_PRINT2("ECtrlRegisterUserBuffer kernelBufferId=%d", kernelBufferId );	
sl@0
   496
			umemput32(userConfigData1, &kernelBufferId, sizeof(TInt) );
sl@0
   497
			break;
sl@0
   498
		
sl@0
   499
		case RDisplayChannel::ECtrlSetRotation:
sl@0
   500
			__DEBUG_PRINT2("ECtrlSetRotation  kernelRotChanged=%d", kernelRotChanged );
sl@0
   501
			umemput32(userConfigData1, &kernelRotChanged, sizeof(TBool) );
sl@0
   502
			break;	
sl@0
   503
		
sl@0
   504
		case RDisplayChannel::ECtrlCurrentRotation:
sl@0
   505
			__DEBUG_PRINT2("ECtrlCurrentRotation kernelRotation=%d",  kernelRotation );
sl@0
   506
			umemput32(userConfigData0, &kernelRotation, sizeof(RDisplayChannel::TDisplayRotation) );
sl@0
   507
			break;
sl@0
   508
		
sl@0
   509
		case RDisplayChannel::ECtrlGetCompositionBufferInfo:				
sl@0
   510
			__DEBUG_PRINT3("ECtrlGetCompositionBufferInfo kernelpack[0] =%d and kernelpack[1] =%d",  kernelpack[0], kernelpack[1]);
sl@0
   511
			umemput32(userConfigData1, &kernelpack, (sizeof(TInt)*2) );
sl@0
   512
			break;					
sl@0
   513
		}			
sl@0
   514
	return r;
sl@0
   515
	}
sl@0
   516
	
sl@0
   517
	
sl@0
   518
/**
sl@0
   519
  All driver's client requests (synchronous and asynchronous) are sent as
sl@0
   520
  kernel messages by generic kernel to logical channel. This function
sl@0
   521
  catches messages sent by the generic kernel.
sl@0
   522
 
sl@0
   523
  @param aMsg Kernel side thread message to process.
sl@0
   524
sl@0
   525
	The iValue member of this distinguishes the message type:
sl@0
   526
	iValue==ECloseMsg, channel close message
sl@0
   527
	iValue==KMaxTInt, a 'DoCancel' message
sl@0
   528
	iValue>=0, a 'DoControl' message with function number equal to iValue
sl@0
   529
	iValue<0, a 'DoRequest' message with function number equal to ~iValue
sl@0
   530
 */ 
sl@0
   531
void DDisplayLdd::HandleMsg(TMessageBase* aMsg)
sl@0
   532
	{
sl@0
   533
    TThreadMessage& m	= *(TThreadMessage*)aMsg ;
sl@0
   534
	TInt id 			= m.iValue ;
sl@0
   535
    DThread* client 	= m.Client();
sl@0
   536
sl@0
   537
    // close message
sl@0
   538
    if (id == (TInt)ECloseMsg)
sl@0
   539
    	{
sl@0
   540
    	//Device specific cleanup operations
sl@0
   541
    	Pdd()->CloseMsg();
sl@0
   542
    	
sl@0
   543
        // cancel outstanding requests
sl@0
   544
        for(TInt k = 0; k < KPendingReqArraySize; k++)
sl@0
   545
        	{ 
sl@0
   546
			for(TInt i = 0; i < KMaxQueuedRequests; i++)
sl@0
   547
				{
sl@0
   548
	        	if( iPendingReq[k][i].iTClientReq) 
sl@0
   549
	            	{
sl@0
   550
	            	if(iPendingReq[k][i].iTClientReq->IsReady() )
sl@0
   551
	            		{
sl@0
   552
	            		CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel);
sl@0
   553
	            		}            	            		
sl@0
   554
	            	}
sl@0
   555
				}
sl@0
   556
        	}
sl@0
   557
        Pdd()->SetLegacyMode();
sl@0
   558
		m.Complete(KErrNone, EFalse);
sl@0
   559
		return;
sl@0
   560
		}
sl@0
   561
    // cancel
sl@0
   562
    if (id == KMaxTInt)
sl@0
   563
		{
sl@0
   564
		// DoCancel
sl@0
   565
		TInt req = m.Int0() >> 1;
sl@0
   566
		DoCancel(req);
sl@0
   567
		m.Complete(KErrNone,ETrue);
sl@0
   568
    	return;
sl@0
   569
		}
sl@0
   570
    // asynchronous request
sl@0
   571
	else if (id < 0)
sl@0
   572
		{
sl@0
   573
		//m.Int3() is the index, in the array of pending requests, to be used.
sl@0
   574
		TInt r = DoRequest(~id,m.Ptr1(),m.Ptr2(),m.Int3(), client);
sl@0
   575
		m.Complete(r, ETrue);
sl@0
   576
		}
sl@0
   577
    // synchronous request
sl@0
   578
	else
sl@0
   579
		{
sl@0
   580
	   	TInt r = DoControl(id,m.Ptr0(),m.Ptr1(), client);
sl@0
   581
		m.Complete(r,ETrue);
sl@0
   582
		}
sl@0
   583
	} 
sl@0
   584
sl@0
   585
sl@0
   586
/**
sl@0
   587
	Cancel outstanding request.
sl@0
   588
	
sl@0
   589
	@param  aReqNumber	Any value from the RDisplayChannel::TRequest enumeration.
sl@0
   590
*/
sl@0
   591
void DDisplayLdd::DoCancel(TUint aReqNumber)
sl@0
   592
	{
sl@0
   593
      __DEBUG_PRINT2("DDisplayLdd::DoCancel %d\n",aReqNumber);
sl@0
   594
sl@0
   595
       switch (aReqNumber)
sl@0
   596
		 {
sl@0
   597
		 case RDisplayChannel::ECtrlCancelGetCompositionBuffer:
sl@0
   598
		 case RDisplayChannel::ECtrlCancelPostUserBuffer:
sl@0
   599
		 case RDisplayChannel::ECtrlCancelWaitForPost:		 
sl@0
   600
			TInt pendingIndex = iPendingIndex[aReqNumber];
sl@0
   601
	        if(iPendingReq[aReqNumber][pendingIndex].iTClientReq)
sl@0
   602
	        	{
sl@0
   603
	        	if( iPendingReq[aReqNumber][pendingIndex].iTClientReq->IsReady() )
sl@0
   604
	        		{
sl@0
   605
	        		CompleteRequest(iPendingReq[aReqNumber][pendingIndex].iOwningThread,iPendingReq[aReqNumber][pendingIndex].iTClientReq,KErrCancel);
sl@0
   606
	        		}
sl@0
   607
            	}
sl@0
   608
			break;
sl@0
   609
		}	
sl@0
   610
	
sl@0
   611
	}
sl@0
   612
sl@0
   613
/**
sl@0
   614
	Asynchronous request processing.
sl@0
   615
	
sl@0
   616
    @param aFunction    	Request function number
sl@0
   617
    @param apArg1       	Pointer to kernel message argument 1.
sl@0
   618
    @param apArg2       	Pointer to kernel message argument 2.
sl@0
   619
    @param aPendingIndex    Index pointing to the appropriate TClientRequest object to use.
sl@0
   620
	@param aClient			Pointer to the client thread that issued the asynchronous request.
sl@0
   621
	
sl@0
   622
    @return request scheduling result, system-wide error code.
sl@0
   623
*/
sl@0
   624
TInt DDisplayLdd::DoRequest(TInt aReqNumber, TAny* aArg1, TAny* aArg2, TInt aPendingIndex, DThread* aClient)
sl@0
   625
	{	
sl@0
   626
sl@0
   627
    TInt pack[2];
sl@0
   628
    TInt r 				= KErrNone;
sl@0
   629
    TBufferNode* node 	= 0;
sl@0
   630
    TInt buffer_id  	= 0;   
sl@0
   631
    
sl@0
   632
    TInt* configBufferIdx  ;
sl@0
   633
    RDisplayChannel::TPostCount* postCount;	
sl@0
   634
    TInt* configPack; 
sl@0
   635
		
sl@0
   636
	__DEBUG_PRINT5("DoRequest: iClientRequest[aReqNumber=%d][aPendingIndex=%d] is %08x  and aClient=%08x\n",aReqNumber, aPendingIndex,iClientRequest[aReqNumber][aPendingIndex], aClient);    
sl@0
   637
    
sl@0
   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.
sl@0
   639
	r=aClient->Open();
sl@0
   640
	__ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__));
sl@0
   641
#ifdef _DEBUG
sl@0
   642
	__e32_atomic_add_ord32(&iThreadOpenCount, 1);
sl@0
   643
#endif	
sl@0
   644
    	
sl@0
   645
	for(TInt i = 0; i < KMaxQueuedRequests; i++)
sl@0
   646
		{
sl@0
   647
		//Don't cancel the asyncrhonous request we currently process.
sl@0
   648
		if (i == aPendingIndex)
sl@0
   649
			{
sl@0
   650
			continue;
sl@0
   651
			}
sl@0
   652
        // cancel outstanding request
sl@0
   653
        if(iPendingReq[aReqNumber][i].iTClientReq)        
sl@0
   654
			{
sl@0
   655
			//If IsReady() returns true, setStatus has been called for that TCientRequest but QueueRequestComplete hasn't. 
sl@0
   656
			//In that case we want to cancel this outstanding request. Given that all QueueRequestComplete calls execute 
sl@0
   657
			// in the same DFC thread we currently run, there is no need to synchronise request completion calls. 
sl@0
   658
			if(iPendingReq[aReqNumber][i].iTClientReq->IsReady() )
sl@0
   659
				{
sl@0
   660
				CompleteRequest(iPendingReq[aReqNumber][i].iOwningThread,iPendingReq[aReqNumber][i].iTClientReq,KErrCancel);
sl@0
   661
				break;				
sl@0
   662
				}
sl@0
   663
        	}
sl@0
   664
    	}
sl@0
   665
	// store  index, request  and client
sl@0
   666
	iPendingIndex[aReqNumber] 								= aPendingIndex;
sl@0
   667
	iPendingReq[aReqNumber][aPendingIndex].iTClientReq 		= iClientRequest[aReqNumber][aPendingIndex];
sl@0
   668
	iPendingReq[aReqNumber][aPendingIndex].iOwningThread 	= aClient;
sl@0
   669
	
sl@0
   670
	#ifdef _DEBUG
sl@0
   671
		__e32_atomic_add_ord32(&iAsyncReqCount, 1);
sl@0
   672
	#endif   	    	    	    	    	    	  
sl@0
   673
  
sl@0
   674
    switch (aReqNumber)
sl@0
   675
		{
sl@0
   676
	     case RDisplayChannel::EReqGetCompositionBuffer:		//DFC thread updates a value the client thread should read.
sl@0
   677
			 { 
sl@0
   678
			 configBufferIdx = (TInt*) aArg1;
sl@0
   679
		 
sl@0
   680
	          TInt  index;
sl@0
   681
			  TBool found = EFalse;
sl@0
   682
			  
sl@0
   683
			  for(index = 0; index < (TInt) iDisplayInfo.iNumCompositionBuffers; index++)
sl@0
   684
					{
sl@0
   685
					if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose )
sl@0
   686
						{
sl@0
   687
						__DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index);
sl@0
   688
sl@0
   689
						 iCompositionBuffIdx = index;
sl@0
   690
						 *configBufferIdx = iCompositionBuffIdx;
sl@0
   691
						 iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose;
sl@0
   692
						 CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread,iPendingReq[aReqNumber][aPendingIndex].iTClientReq,r);
sl@0
   693
						 found = ETrue;
sl@0
   694
						 break;
sl@0
   695
						 }
sl@0
   696
					}				
sl@0
   697
			  if(!found)  	//There are no free buffers schedule request for completion
sl@0
   698
					{	
sl@0
   699
					//Case of a single composition buffer. 
sl@0
   700
					if (iDisplayInfo.iNumCompositionBuffers == 1)
sl@0
   701
						{
sl@0
   702
						iCompositionBuffIdx = 0;
sl@0
   703
						 *configBufferIdx = iCompositionBuffIdx;							 
sl@0
   704
						 CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread, iPendingReq[aReqNumber][aPendingIndex].iTClientReq, r);
sl@0
   705
						 __DEBUG_PRINT("EReqGetCompositionBuffer  The single Composition buffer is currently being used\n");
sl@0
   706
						 break;													
sl@0
   707
						}
sl@0
   708
							
sl@0
   709
				 
sl@0
   710
					for( index=0; index< KDisplayCBMax; index++)
sl@0
   711
						 {
sl@0
   712
						 if(iCompositionBuffer[index].iState == EBufferActive)
sl@0
   713
							 {	
sl@0
   714
							 iCompositionBuffIdx = index;
sl@0
   715
							 *configBufferIdx = iCompositionBuffIdx;								 
sl@0
   716
							 __DEBUG_PRINT2("EReqGetCompositionBuffer  No composition buffer available. Next available is iCompositionBuffIdx  %d.\n",iCompositionBuffIdx );
sl@0
   717
							 break;
sl@0
   718
							 }
sl@0
   719
						 }
sl@0
   720
					}			 	 			            
sl@0
   721
          	
sl@0
   722
			  break;
sl@0
   723
			  }
sl@0
   724
sl@0
   725
         case RDisplayChannel::EReqPostUserBuffer:		//DFC thread should read client message data and update a value the client will read.	                                            
sl@0
   726
            configPack = (TInt*) aArg1;
sl@0
   727
            pack[0] = *configPack; 
sl@0
   728
            configPack++;           
sl@0
   729
            pack[1] = *configPack;
sl@0
   730
			
sl@0
   731
			r = KErrArgument;
sl@0
   732
            buffer_id = pack[0];
sl@0
   733
            if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) )
sl@0
   734
             	{
sl@0
   735
                node = FindUserBufferNode(buffer_id);
sl@0
   736
                if(node  && (!(node->iFree) && node->iChunk ) ) 
sl@0
   737
                	{
sl@0
   738
                  	__DEBUG_PRINT2("EReqPostUserBuffer Posting buffer id: %d \n",buffer_id );
sl@0
   739
                  	r = Pdd()->PostUserBuffer(node);
sl@0
   740
                  	if(r == KErrNone)
sl@0
   741
	                  	 {
sl@0
   742
	                  	 postCount = (RDisplayChannel::TPostCount*) aArg2;
sl@0
   743
	     		    	 ++iCurrentPostCount;
sl@0
   744
	                	 *postCount= iCurrentPostCount;	                	 
sl@0
   745
	           		     break;
sl@0
   746
	                  	 }
sl@0
   747
                	}
sl@0
   748
             	}
sl@0
   749
            RequestComplete(RDisplayChannel::EReqPostUserBuffer,  r); 
sl@0
   750
sl@0
   751
            break; 	        
sl@0
   752
sl@0
   753
         case RDisplayChannel::EReqWaitForPost:			 	//DFC thread should read client message data.
sl@0
   754
			postCount = (RDisplayChannel::TPostCount*) aArg1;
sl@0
   755
			iRequestedPostCount = *postCount;
sl@0
   756
									
sl@0
   757
			//Any post operation increases iCurrentPostCount instantly but the actual post completes later on.
sl@0
   758
			if( ! Pdd()->PostPending() )
sl@0
   759
				 {
sl@0
   760
				 RequestComplete(RDisplayChannel::EReqWaitForPost,  KErrNone);
sl@0
   761
				 } 					 
sl@0
   762
         	break;
sl@0
   763
sl@0
   764
        default:
sl@0
   765
			__NK_ASSERT_ALWAYS(EFalse);  // we already validated the request number
sl@0
   766
		}
sl@0
   767
    return r;	
sl@0
   768
	}
sl@0
   769
sl@0
   770
sl@0
   771
/**
sl@0
   772
	Synchronous requests processing.
sl@0
   773
	
sl@0
   774
	@param aFunction    Request function number,
sl@0
   775
	@param apArg1       Pointer to kernel message argument 0.
sl@0
   776
	@param apArg2       Pointer to kernel message argument 1.
sl@0
   777
	@param aClient		Pointer to the client thread that issued the synchronous request.
sl@0
   778
    
sl@0
   779
    @return request processing result
sl@0
   780
*/
sl@0
   781
TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient)
sl@0
   782
 {
sl@0
   783
	TInt r 			  = KErrNone;
sl@0
   784
    TBool changedRot  = ETrue;
sl@0
   785
    TBufferNode* node = 0;
sl@0
   786
	TInt buffer_id;
sl@0
   787
    TInt pack[2]      = {0,0};
sl@0
   788
    TInt handle, offset;
sl@0
   789
    TInt index        = 0;
sl@0
   790
	
sl@0
   791
	RDisplayChannel::TPostCount 		*postCount ;
sl@0
   792
	RDisplayChannel::TDisplayRotation   *rotation; 
sl@0
   793
	
sl@0
   794
	TInt	*configPack; 
sl@0
   795
	TInt	*bufferId; 	
sl@0
   796
	
sl@0
   797
	TBool   *rotationChanged;
sl@0
   798
	TInt    *idx;
sl@0
   799
	
sl@0
   800
    switch (aFunction)
sl@0
   801
		{
sl@0
   802
	    case RDisplayChannel::ECtrlPostCompositionBuffer: 	//DFC thread updates a value the client thread should read.
sl@0
   803
			postCount = (RDisplayChannel::TPostCount*) aArg2;		
sl@0
   804
					
sl@0
   805
	        node =  &iCompositionBuffer[iCompositionBuffIdx];
sl@0
   806
            r = Pdd()->PostCompositionBuffer(node);
sl@0
   807
		    if(r == KErrNone)
sl@0
   808
		    	{
sl@0
   809
    		    ++iCurrentPostCount;
sl@0
   810
    			*postCount = iCurrentPostCount;
sl@0
   811
				}
sl@0
   812
            else 
sl@0
   813
            	{
sl@0
   814
            	r = KErrGeneral;	
sl@0
   815
            	}            	    	            	
sl@0
   816
			break;
sl@0
   817
sl@0
   818
        case RDisplayChannel::ECtrlPostLegacyBuffer:		//DFC thread updates a value the client thread should read.
sl@0
   819
			postCount = (RDisplayChannel::TPostCount*) aArg2;
sl@0
   820
            r= Pdd()->PostLegacyBuffer();
sl@0
   821
            if ( r == KErrNone)
sl@0
   822
            	{
sl@0
   823
             	++iCurrentPostCount;         	
sl@0
   824
            	*postCount = iCurrentPostCount;
sl@0
   825
				}            
sl@0
   826
			break;
sl@0
   827
sl@0
   828
	    case RDisplayChannel::ECtrlRegisterUserBuffer:	//DFC thread should read client message data and update a value the client will read.
sl@0
   829
            node = FindUserBufferNode(0);
sl@0
   830
			if(node)
sl@0
   831
				{					                         
sl@0
   832
                configPack = (TInt*) aArg1;
sl@0
   833
                handle 	   = *configPack;
sl@0
   834
                configPack++;
sl@0
   835
                offset     = *configPack;                               
sl@0
   836
                r 	       = CheckAndOpenUserBuffer(node, handle, offset, aClient);
sl@0
   837
                
sl@0
   838
                if(r == KErrNone)
sl@0
   839
                	{
sl@0
   840
                	bufferId  = (TInt*) aArg2;
sl@0
   841
                	*bufferId = node->iBufferId;
sl@0
   842
                	}					
sl@0
   843
				}
sl@0
   844
            else
sl@0
   845
            	{
sl@0
   846
    			r = KErrTooBig;
sl@0
   847
            	}
sl@0
   848
			break;
sl@0
   849
sl@0
   850
	    case RDisplayChannel::ECtrlDeregisterUserBuffer:	//DFC thread should read client message data.
sl@0
   851
            bufferId  = (TInt*) aArg1;
sl@0
   852
            buffer_id = *bufferId;
sl@0
   853
            
sl@0
   854
            
sl@0
   855
			r = KErrArgument;          
sl@0
   856
            if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) )
sl@0
   857
            	{
sl@0
   858
	            node = FindUserBufferNode(buffer_id);	            
sl@0
   859
	            if(node  && (!(node->iFree) && node->iChunk ) ) 
sl@0
   860
	            	{	                
sl@0
   861
	                if(node->iState==EBufferFree  || node->iState==EBufferCompose )
sl@0
   862
	                	{
sl@0
   863
	                	r = FreeUserBufferNode(node);	                	
sl@0
   864
	                	}
sl@0
   865
	                else
sl@0
   866
	                	{
sl@0
   867
	                	r = KErrInUse;
sl@0
   868
	                	}
sl@0
   869
	            	}               	                                    
sl@0
   870
            	}
sl@0
   871
			break;
sl@0
   872
sl@0
   873
	    case RDisplayChannel::ECtrlSetRotation:	    //DFC thread should read client message data and update a value the client will read.	    			    
sl@0
   874
            {            	         
sl@0
   875
            RDisplayChannel::TDisplayRotation rot;
sl@0
   876
            RDisplayChannel::TDisplayRotation previousRot = iCurrentRotation;
sl@0
   877
                        
sl@0
   878
            rotation  = (RDisplayChannel::TDisplayRotation*) aArg1;
sl@0
   879
           	rot 	  = *rotation;
sl@0
   880
            
sl@0
   881
            __DEBUG_PRINT3("ECtrlSetRotation previousRot= %d and rot =%d \n",previousRot, rot );
sl@0
   882
             	
sl@0
   883
            r = Pdd()->SetRotation(rot);                  
sl@0
   884
            changedRot = (previousRot != iCurrentRotation);          
sl@0
   885
            if( r == KErrNone)
sl@0
   886
    	        {                  
sl@0
   887
           	    rotationChanged  = (TBool*) aArg2;
sl@0
   888
           	    *rotationChanged = changedRot ;         	    
sl@0
   889
           	    }					    	
sl@0
   890
    	    break;
sl@0
   891
            }
sl@0
   892
            
sl@0
   893
	    case RDisplayChannel::ECtrlCurrentRotation:				//DFC thread updates a value the client thread should read.
sl@0
   894
			rotation  = (RDisplayChannel::TDisplayRotation*) aArg1;
sl@0
   895
			*rotation = iCurrentRotation; 
sl@0
   896
			break;
sl@0
   897
sl@0
   898
	    case RDisplayChannel::ECtrlGetCompositionBufferInfo:	//DFC thread should read client message data and update a value the client will read.
sl@0
   899
            idx   = ( TInt * ) aArg1;
sl@0
   900
            index = *idx;
sl@0
   901
	  
sl@0
   902
			if( (index >= (TInt) iDisplayInfo.iNumCompositionBuffers ) || (index < 0 ) )
sl@0
   903
            	{
sl@0
   904
            	r = KErrArgument;
sl@0
   905
            	break;	
sl@0
   906
            	}
sl@0
   907
			r = Kern::MakeHandleAndOpen(aClient, iCompositionBuffer[index].iChunk);
sl@0
   908
sl@0
   909
			if(r >= KErrNone)
sl@0
   910
				{
sl@0
   911
				pack[0] 	= r;
sl@0
   912
				pack[1] 	= iCompositionBuffer[index].iOffset;	
sl@0
   913
				
sl@0
   914
				configPack  = (TInt * ) aArg2;
sl@0
   915
				*configPack = pack[0];
sl@0
   916
				configPack++;
sl@0
   917
				*configPack = pack[1];				 
sl@0
   918
				
sl@0
   919
				r = KErrNone;
sl@0
   920
				}					
sl@0
   921
		 	break;
sl@0
   922
sl@0
   923
#ifdef _DEBUG
sl@0
   924
	    case RDisplayChannel::ECtrlCreateUserBuffer:
sl@0
   925
	        {
sl@0
   926
	        TUint32 chunkMapAttr;
sl@0
   927
	        TLinAddr chunkBase;
sl@0
   928
	        TPhysAddr physicalAddr;
sl@0
   929
	        RDisplayChannel::TBufferFormat bufferFormat;
sl@0
   930
sl@0
   931
	        // Read the information from the user thread pertaining to the buffer to be allocated
sl@0
   932
	        Kern::ThreadRawRead(aClient, aArg1, &bufferFormat, sizeof(bufferFormat));
sl@0
   933
sl@0
   934
	        // Allocate a chunk that can be used as a user buffer.  Don't worry about the # of bytes
sl@0
   935
	        // per pixel as this is UDEB only test code - just set it to 4 and that will ensure that
sl@0
   936
	        // it is large enough
sl@0
   937
	        TChunkCreateInfo chunkCreateInfo;
sl@0
   938
	        chunkCreateInfo.iType = TChunkCreateInfo::ESharedKernelSingle;
sl@0
   939
#ifndef __WINS__
sl@0
   940
	        chunkCreateInfo.iMapAttr = EMapAttrFullyBlocking;
sl@0
   941
#endif // ! __WINS__
sl@0
   942
	        chunkCreateInfo.iOwnsMemory = ETrue;
sl@0
   943
	        chunkCreateInfo.iDestroyedDfc = NULL;
sl@0
   944
	        chunkCreateInfo.iMaxSize = (bufferFormat.iSize.iWidth * bufferFormat.iSize.iHeight * 4);
sl@0
   945
sl@0
   946
	        if ((r = Kern::ChunkCreate(chunkCreateInfo, iChunk, chunkBase, chunkMapAttr)) == KErrNone)
sl@0
   947
	            {
sl@0
   948
	            // Commit some contiguous physical RAM for use in the chunk 
sl@0
   949
	            r = Kern::ChunkCommitContiguous(iChunk, 0, chunkCreateInfo.iMaxSize, physicalAddr);
sl@0
   950
sl@0
   951
	            // And open a handle to the chunk that will be returned to user side for use in the user
sl@0
   952
	            // side's RChunk object
sl@0
   953
	            if (r == KErrNone)
sl@0
   954
	                r = Kern::MakeHandleAndOpen(aClient, iChunk);
sl@0
   955
	            else
sl@0
   956
	            	{
sl@0
   957
	                Kern::ChunkClose(iChunk);
sl@0
   958
	                iChunk = NULL;
sl@0
   959
	            	}
sl@0
   960
	            }
sl@0
   961
sl@0
   962
	        break;
sl@0
   963
	        }
sl@0
   964
#endif // _DEBUG
sl@0
   965
sl@0
   966
	    default:
sl@0
   967
			__NK_ASSERT_ALWAYS(EFalse);  // we already validated the request number
sl@0
   968
		};
sl@0
   969
    return r;	
sl@0
   970
	}
sl@0
   971
sl@0
   972
sl@0
   973
/**
sl@0
   974
    Open a shared Chunk for the User buffer and then set the appropriate values for the
sl@0
   975
    User buffer node attributes.
sl@0
   976
	
sl@0
   977
*/
sl@0
   978
TInt DDisplayLdd::CheckAndOpenUserBuffer(TBufferNode* aNode, TInt aHandle, TInt aOffset, DThread* aClient)
sl@0
   979
 {
sl@0
   980
 
sl@0
   981
  TInt     	size 				= 0;
sl@0
   982
  DChunk*  	chunk 				= 0;
sl@0
   983
  TLinAddr 	kernelAddress 		= 0;
sl@0
   984
  TUint32  	mapAttr 			= 0;
sl@0
   985
  TUint32  	physicalAddress 	= 0;
sl@0
   986
  TUint32  	*physicalPageList 	= 0;
sl@0
   987
  TInt 		r 					= KErrBadHandle;
sl@0
   988
	
sl@0
   989
  NKern::ThreadEnterCS();
sl@0
   990
  chunk = Kern::OpenSharedChunk(aClient, aHandle, EFalse);
sl@0
   991
  NKern::ThreadLeaveCS();
sl@0
   992
  if(chunk)
sl@0
   993
    	{                            
sl@0
   994
		
sl@0
   995
		// Using iOffsetBetweenLines rather than iWidth as the controller may be using stride
sl@0
   996
		size = iDisplayInfo.iNormal.iOffsetBetweenLines * iDisplayInfo.iNormal.iHeight;
sl@0
   997
                
sl@0
   998
        r = Kern::ChunkPhysicalAddress(chunk, aOffset, size, kernelAddress, mapAttr, physicalAddress, physicalPageList);
sl@0
   999
        if( r == KErrNone )
sl@0
  1000
        	{
sl@0
  1001
            aNode->iChunk 			= chunk;
sl@0
  1002
            aNode->iFree  			= EFalse;
sl@0
  1003
            aNode->iState 			= EBufferCompose;
sl@0
  1004
            aNode->iAddress 		= (TUint32)kernelAddress;
sl@0
  1005
            aNode->iHandle 			= aHandle;
sl@0
  1006
            aNode->iPhysicalAddress = physicalAddress;
sl@0
  1007
        	}
sl@0
  1008
        else
sl@0
  1009
        	{ // we have an error here, close the chunk
sl@0
  1010
        	r = KErrArgument;  
sl@0
  1011
            Kern::ChunkClose(chunk);
sl@0
  1012
        	}
sl@0
  1013
    }
sl@0
  1014
  return (r);
sl@0
  1015
  }
sl@0
  1016
sl@0
  1017
sl@0
  1018
/**
sl@0
  1019
    Return any free buffer when trying to register a User buffer( aBufferId ==0 )
sl@0
  1020
    or return the specified User buffer( used by Deregister and PostUserBuffer).
sl@0
  1021
    In the second case checks about the state of the user buffer are specific to 
sl@0
  1022
    each case. 
sl@0
  1023
    
sl@0
  1024
*/
sl@0
  1025
TBufferNode* DDisplayLdd::FindUserBufferNode(TInt aBufferId)
sl@0
  1026
	{
sl@0
  1027
    TBufferNode* node = 0;
sl@0
  1028
sl@0
  1029
    if(aBufferId == 0)
sl@0
  1030
		{
sl@0
  1031
		for(TInt i = 0; i < KDisplayUBMax; i++)
sl@0
  1032
			{
sl@0
  1033
			if(iUserBuffer[i].iFree)
sl@0
  1034
				{
sl@0
  1035
				node = &iUserBuffer[i];
sl@0
  1036
				break;
sl@0
  1037
				}
sl@0
  1038
			}
sl@0
  1039
		}
sl@0
  1040
	else
sl@0
  1041
		{		 
sl@0
  1042
		 node = &iUserBuffer[aBufferId-1];
sl@0
  1043
		}
sl@0
  1044
    return (node);
sl@0
  1045
	}
sl@0
  1046
sl@0
  1047
sl@0
  1048
/**
sl@0
  1049
    Free user buffer by reseting all the appropriate fields and closing the corresponding chunk.
sl@0
  1050
*/ 
sl@0
  1051
TInt DDisplayLdd::FreeUserBufferNode(TBufferNode* aNode)
sl@0
  1052
	{
sl@0
  1053
	__DEBUG_PRINT2("FreeUserBufferNode with aNode->iAddress %08x.\n",aNode->iAddress );
sl@0
  1054
	TInt r = KErrNone;
sl@0
  1055
	NKern::ThreadEnterCS();
sl@0
  1056
    if(aNode->iChunk != 0)
sl@0
  1057
    	{
sl@0
  1058
    	r= Kern::ChunkClose(aNode->iChunk);
sl@0
  1059
    	}    	
sl@0
  1060
    if( r== KErrNone)
sl@0
  1061
    	{
sl@0
  1062
    	aNode->iState 	= EBufferFree;
sl@0
  1063
    	aNode->iFree 	= ETrue;
sl@0
  1064
    	aNode->iAddress = 0;
sl@0
  1065
    	aNode->iSize 	= 0;
sl@0
  1066
    	aNode->iHandle 	= 0;
sl@0
  1067
    	aNode->iChunk 	= 0;
sl@0
  1068
    	}
sl@0
  1069
    else
sl@0
  1070
    	{
sl@0
  1071
    	__DEBUG_PRINT("Failed to close chunk\n");    	
sl@0
  1072
    	}
sl@0
  1073
	NKern::ThreadLeaveCS();	
sl@0
  1074
    
sl@0
  1075
    return r;
sl@0
  1076
	}	
sl@0
  1077
sl@0
  1078
sl@0
  1079
/**    
sl@0
  1080
   Calls CompleteRequest( which internally calls Kern::QueueRequestComplete )for the specified request and with the reason passed, 
sl@0
  1081
   in case such an asynchronous request is pending.  Called by both the LDD and PDD.
sl@0
  1082
   
sl@0
  1083
*/ 
sl@0
  1084
TInt DDisplayLdd::RequestComplete(TInt aRequest, TInt aReason)
sl@0
  1085
	{
sl@0
  1086
	TBool flag 		  = EFalse;
sl@0
  1087
	
sl@0
  1088
	TInt pendingIndex =   iPendingIndex[aRequest] ;	
sl@0
  1089
	
sl@0
  1090
	switch (aRequest)
sl@0
  1091
		{		
sl@0
  1092
	    case RDisplayChannel::EReqGetCompositionBuffer:	
sl@0
  1093
			{
sl@0
  1094
			__DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqGetCompositionBuffer request and reason %d\n",aReason );
sl@0
  1095
			
sl@0
  1096
	        if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq )
sl@0
  1097
				{
sl@0
  1098
				if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer][pendingIndex].iTClientReq->IsReady() )
sl@0
  1099
					{
sl@0
  1100
		            flag = ETrue;					
sl@0
  1101
					}
sl@0
  1102
	        	}
sl@0
  1103
	        break;											
sl@0
  1104
			}
sl@0
  1105
sl@0
  1106
		 case RDisplayChannel::EReqWaitForPost:		        
sl@0
  1107
			{
sl@0
  1108
			__DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqWaitForPost request and reason %d\n",aReason );
sl@0
  1109
			
sl@0
  1110
	 		if(iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq) 
sl@0
  1111
	    	    {
sl@0
  1112
	    	    if( iPendingReq[RDisplayChannel::EReqWaitForPost][pendingIndex].iTClientReq->IsReady()  && (iCurrentPostCount >= iRequestedPostCount) )
sl@0
  1113
	    	    	{
sl@0
  1114
					flag = ETrue;	    	    	
sl@0
  1115
	    	    	}
sl@0
  1116
	            }
sl@0
  1117
	        break;    												
sl@0
  1118
			}
sl@0
  1119
 		
sl@0
  1120
		case RDisplayChannel::EReqPostUserBuffer:	
sl@0
  1121
			{
sl@0
  1122
			__DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqPostUserBuffer request and reason %d\n",aReason );
sl@0
  1123
				
sl@0
  1124
			if(iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq)
sl@0
  1125
	    		{
sl@0
  1126
	    		if( iPendingReq[RDisplayChannel::EReqPostUserBuffer][pendingIndex].iTClientReq->IsReady() )
sl@0
  1127
	    			{
sl@0
  1128
					flag = ETrue;	    			
sl@0
  1129
	    			}
sl@0
  1130
	            }
sl@0
  1131
	        break;			
sl@0
  1132
			}
sl@0
  1133
		default:
sl@0
  1134
			__DEBUG_PRINT("RequestComplete() called for an unknown request\n");
sl@0
  1135
			return KErrGeneral;
sl@0
  1136
		
sl@0
  1137
		}
sl@0
  1138
		
sl@0
  1139
	if (flag)
sl@0
  1140
		{
sl@0
  1141
		CompleteRequest(iPendingReq[aRequest][pendingIndex].iOwningThread,iPendingReq[aRequest][pendingIndex].iTClientReq,aReason);		
sl@0
  1142
		}
sl@0
  1143
				
sl@0
  1144
	return KErrNone;	
sl@0
  1145
	}
sl@0
  1146
sl@0
  1147
sl@0
  1148
/** 
sl@0
  1149
Complete an asynchronous request back to the client.
sl@0
  1150
sl@0
  1151
@param aThread     The client thread which issued the request.
sl@0
  1152
@param aTClientReq Pointer reference to the TClientRequest object  
sl@0
  1153
@param aReason     The request status code.  
sl@0
  1154
sl@0
  1155
@pre The thread must be in a critical section. 
sl@0
  1156
*/
sl@0
  1157
void DDisplayLdd::CompleteRequest(DThread* aThread, TClientRequest*& aTClientReq, TInt aReason)
sl@0
  1158
	{			
sl@0
  1159
	__DEBUG_PRINT4("Complete aTClientReq %08x with reason %d for aThread = %08x\n", aTClientReq, aReason,aThread );		
sl@0
  1160
	
sl@0
  1161
	Kern::QueueRequestComplete(aThread,aTClientReq,aReason);
sl@0
  1162
		
sl@0
  1163
	aThread->AsyncClose();	// Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference. 
sl@0
  1164
				
sl@0
  1165
	aThread		  =0;
sl@0
  1166
	aTClientReq   =0;
sl@0
  1167
	
sl@0
  1168
#ifdef _DEBUG	
sl@0
  1169
	__e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1));
sl@0
  1170
	__e32_atomic_add_ord32(&iAsyncReqCount,   TUint32(-1));
sl@0
  1171
#endif	
sl@0
  1172
			
sl@0
  1173
	}
sl@0
  1174
sl@0
  1175
sl@0
  1176
sl@0
  1177
/**
sl@0
  1178
	static factory function for the LDD.
sl@0
  1179
	
sl@0
  1180
	@return pointer to the created (or existing) instance of the class
sl@0
  1181
*/
sl@0
  1182
DDisplayLdd* DDisplayLdd::CreateInstance()
sl@0
  1183
	{
sl@0
  1184
	__DEBUG_PRINT("DDisplayLdd::CreateInstance()\n");
sl@0
  1185
	 // create LDD channel instance
sl@0
  1186
    DDisplayLdd* obj = new DDisplayLdd();
sl@0
  1187
    return obj;
sl@0
  1188
	
sl@0
  1189
	}
sl@0
  1190
sl@0
  1191
sl@0
  1192
/************************************************************************************
sl@0
  1193
 *            LDD factory, DDisplayLddFactory class implementation
sl@0
  1194
 ************************************************************************************/
sl@0
  1195
 
sl@0
  1196
/**
sl@0
  1197
	Constructor
sl@0
  1198
*/  
sl@0
  1199
DDisplayLddFactory::DDisplayLddFactory()
sl@0
  1200
	{
sl@0
  1201
	__DEBUG_PRINT("DDisplayLddFactory::DDisplayLddFactory() \n");
sl@0
  1202
	
sl@0
  1203
	iParseMask 	= KDeviceAllowPhysicalDevice | KDeviceAllowUnit ;
sl@0
  1204
	
sl@0
  1205
    iVersion	= TVersion( KDisplayChMajorVersionNumber,
sl@0
  1206
                      	    KDisplayChMinorVersionNumber,
sl@0
  1207
                      	    KDisplayChBuildVersionNumber);
sl@0
  1208
                      	    
sl@0
  1209
	iUnitsOpenMask =0;                      	    
sl@0
  1210
	}
sl@0
  1211
sl@0
  1212
sl@0
  1213
/**
sl@0
  1214
    Destructor
sl@0
  1215
*/
sl@0
  1216
DDisplayLddFactory::~DDisplayLddFactory()
sl@0
  1217
	{
sl@0
  1218
	}
sl@0
  1219
sl@0
  1220
sl@0
  1221
/**
sl@0
  1222
	static factory function for the LDD factory.
sl@0
  1223
	
sl@0
  1224
	@return pointer to the created instance of the class
sl@0
  1225
*/
sl@0
  1226
DDisplayLddFactory* DDisplayLddFactory::CreateInstance()
sl@0
  1227
sl@0
  1228
	{
sl@0
  1229
	__DEBUG_PRINT("DDisplayLddFactory::CreateInstance() \n");
sl@0
  1230
	 
sl@0
  1231
	 DDisplayLddFactory* obj = new DDisplayLddFactory;
sl@0
  1232
    return obj;
sl@0
  1233
	}
sl@0
  1234
sl@0
  1235
sl@0
  1236
/**
sl@0
  1237
    Set our name and return error code
sl@0
  1238
*/
sl@0
  1239
TInt DDisplayLddFactory::Install()
sl@0
  1240
sl@0
  1241
	{
sl@0
  1242
	__DEBUG_PRINT("DDisplayLddFactory::Install() \n");
sl@0
  1243
    return SetName(&RDisplayChannel::Name());
sl@0
  1244
	}
sl@0
  1245
sl@0
  1246
sl@0
  1247
void DDisplayLddFactory::GetCaps(TDes8& /*aDes*/) const
sl@0
  1248
sl@0
  1249
	{
sl@0
  1250
	//No action.
sl@0
  1251
	}
sl@0
  1252
sl@0
  1253
sl@0
  1254
/**
sl@0
  1255
	LDD factory function. Creates LDD object.
sl@0
  1256
	
sl@0
  1257
	@param  aChannel  A pointer to an LDD channel object which will be initialised on return.
sl@0
  1258
	
sl@0
  1259
	@return KErrNone  if object successfully allocated, KErrNoMemory if not.			
sl@0
  1260
*/
sl@0
  1261
TInt DDisplayLddFactory::Create(DLogicalChannelBase*& aChannel)
sl@0
  1262
	{
sl@0
  1263
	__DEBUG_PRINT("DDisplayLddFactory::Create \n");
sl@0
  1264
    aChannel = DDisplayLdd::CreateInstance();
sl@0
  1265
    return (!aChannel)? KErrNoMemory : KErrNone;
sl@0
  1266
	}
sl@0
  1267
sl@0
  1268
sl@0
  1269
sl@0
  1270
/**
sl@0
  1271
Check whether a channel is currently open on the specified unit.
sl@0
  1272
@param aUnit The number of the unit to be checked.
sl@0
  1273
@return ETrue if a channel is open on the specified channel, EFalse otherwise.
sl@0
  1274
@pre The unit info. mutex must be held.
sl@0
  1275
*/
sl@0
  1276
TBool DDisplayLddFactory::IsUnitOpen(TInt aUnit)
sl@0
  1277
	{
sl@0
  1278
	return(iUnitsOpenMask&(1<<aUnit));
sl@0
  1279
	}
sl@0
  1280
sl@0
  1281
sl@0
  1282
/**
sl@0
  1283
Attempt to change the state of the channel open status for a particular channel.
sl@0
  1284
@param aUnit The number of the unit to be updated.
sl@0
  1285
@param aIsOpenSetting The required new state for the channel open status: either ETrue to set the status to open or 
sl@0
  1286
	EFalse to set the status to closed.
sl@0
  1287
@return KErrNone if the status was updated successfully, KErrInUse if an attempt has been made to set the channnel status
sl@0
  1288
	to open while it is already open.
sl@0
  1289
*/		
sl@0
  1290
TInt DDisplayLddFactory::SetUnitOpen(TInt aUnit,TBool aIsOpenSetting)
sl@0
  1291
	{
sl@0
  1292
		
sl@0
  1293
	NKern::FMWait(&iUnitInfoMutex); // Acquire the unit info. mutex.
sl@0
  1294
		
sl@0
  1295
	// Fail a request to open an channel that is already open
sl@0
  1296
	if (aIsOpenSetting && IsUnitOpen(aUnit))
sl@0
  1297
		{
sl@0
  1298
		NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
sl@0
  1299
		return(KErrInUse);
sl@0
  1300
		}
sl@0
  1301
	
sl@0
  1302
	// Update the open status as requested
sl@0
  1303
	if (aIsOpenSetting)
sl@0
  1304
		iUnitsOpenMask|=(1<<aUnit);
sl@0
  1305
	else
sl@0
  1306
		iUnitsOpenMask&=~(1<<aUnit);
sl@0
  1307
	
sl@0
  1308
	NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.	
sl@0
  1309
	return(KErrNone);
sl@0
  1310
	}
sl@0
  1311
sl@0
  1312
sl@0
  1313
/**
sl@0
  1314
	"Standard LDD" entrypoint.
sl@0
  1315
	
sl@0
  1316
	Is called on CreateLogicalDevice() if the user calls LoadLogicalDevice(). Creates LDD factory.
sl@0
  1317
	
sl@0
  1318
	@return pointer to the LDD factory object.
sl@0
  1319
*/
sl@0
  1320
DECLARE_STANDARD_LDD()
sl@0
  1321
	{
sl@0
  1322
	__DEBUG_PRINT("DECLARE_STANDARD_LDD() \n");
sl@0
  1323
     DDisplayLddFactory* pLDDFactory = DDisplayLddFactory::CreateInstance();
sl@0
  1324
    return  pLDDFactory;
sl@0
  1325
	}
sl@0
  1326
sl@0
  1327
sl@0
  1328
sl@0
  1329