os/boardsupport/emulator/emulatorbsp/specific/display_chan.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2007-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 "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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 
    17 #include <kernel/kern_priv.h>
    18 #include <kernel/kernel.h>
    19 #include <winsdef.h>
    20 #include <emulator.h>
    21 #include <pixelformats.h>
    22 #include "gui.h"
    23 #include "display_chan.h"
    24 
    25 #define WIN32_LEAN_AND_MEAN
    26 #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
    27 #include <windows.h>
    28 #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
    29 
    30 #ifndef DD_TRACE
    31 #ifdef DD_TRACE_ENABLED
    32 #define DD_TRACE(X) X
    33 #else
    34 #define DD_TRACE(X)
    35 #endif
    36 #endif
    37 
    38 
    39 
    40 DDisplayChannel::DDisplayChannel() :
    41 		iVSync(&DDisplayChannel::VSyncTimerFn, this),
    42 		iVSyncDfc(&DDisplayChannel::VSyncDfcFn, this, Kern::DfcQue0(), KDfcPriority),
    43 		iPostedBuffer((TUint)KBufferNotSet),
    44 		iGetBuffer((TUint)KFirstCompositionBuffer),
    45 		iDisplayStateSpinner(0),
    46 		iVersion(KDisplayChMajorVersionNumber, 
    47 			     KDisplayChMinorVersionNumber, 
    48 			     KDisplayChBuildVersionNumber)
    49 	{
    50 	DD_TRACE(Kern::Printf("DDisplayChannel Creation");)
    51 	}
    52 
    53 
    54 DDisplayChannel::~DDisplayChannel()
    55 	{
    56 	DD_TRACE(Kern::Printf("DDisplayChannel Destruction");)
    57 	//clean up.
    58 
    59 	NKern::ThreadEnterCS();
    60 	Kern::Free(iBuffer);
    61 	NKern::ThreadLeaveCS();
    62 
    63 	}
    64 
    65 
    66 /**
    67   Second stage constructor called by the kernel's device driver framework.
    68   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
    69   (E.g. through a call to RBusLogicalChannel::DoCreate)
    70   The thread is in a critical section.
    71 
    72   @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
    73   @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
    74   @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
    75 
    76   @return KErrNone if successful, otherwise one of the other system wide error codes.
    77 */
    78 TInt DDisplayChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& aVer)
    79 	{
    80 	// Check version
    81 	if (!Kern::QueryVersionSupported(iDevice->iVersion, aVer))
    82 		{
    83 		return KErrNotSupported;
    84 		}
    85 
    86 	iScreenNumber = aUnit;	/*aUnit?*/
    87 	SetDfcQ(Kern::DfcQue0());
    88 	iMsgQ.Receive();
    89 
    90 	// Ask the GUI code to initialize the rest of the object.
    91 	return Kern::HalFunction(EHalGroupEmulator, EEmulatorHalSetDisplayChannel,
    92 			(TAny*)iScreenNumber, this);
    93 	}
    94 
    95 
    96 void DDisplayChannel::ValidateSpecificInfo(TInt aBytesPerPixel, RDisplayChannel::TOrientationSpecificInfo& aInfo)
    97 	{
    98 	__ASSERT_DEBUG(aInfo.iWidth > 0 && aInfo.iHeight > 0, Panic(EDisplayPanicInvalidDimensions));
    99 	__ASSERT_DEBUG(aInfo.iOffsetBetweenLines > 0, Panic(EDisplayPanicInvalidStride));
   100 	__ASSERT_DEBUG(aInfo.iWidth * aBytesPerPixel <= (TUint)aInfo.iOffsetBetweenLines, Panic(EDisplayPanicInvalidStride));
   101 	
   102 	//this is just to stop compiler complaining..
   103 	(TAny)aBytesPerPixel;
   104 	(TAny)aInfo;
   105 	}
   106 
   107 /**
   108 Finish creating the display channel object.
   109 
   110 @param aInfo			Display description object
   111 @param aRotation		Initial rotation
   112 @param aHwnd			Associated window handle
   113 @param aFrameBuffers	Array of one or more pointers to frame buffers
   114 @param aResolution		Initial resolution
   115 @param aTwips           Size in twips
   116 @return	KErrNone if successful, or a system-wide error otherwise.
   117 */
   118 TInt DDisplayChannel::Initialize(RDisplayChannel::TDisplayInfo& aInfo, 
   119 		                         RDisplayChannel::TDisplayRotation aRotation,
   120 		                         HWND aHwnd, RPointerArray<TAny>& aFrameBuffers, 
   121 		                         RPointerArray<TBufferAddressA>& aChunks,
   122 								 TScreenBuffer& aDsaBuffer,
   123 		                         TSize aResolution, 
   124 		                         TSize aTwips,
   125 		                         const RDisplayChannel::TPixelFormat aPixelFormatArray[],
   126 								 const TInt aPixelFormatArraySize,
   127 								 const RDisplayChannel::TBufferFormat& aBufferFormat)
   128 
   129 	{
   130 	__ASSERT_DEBUG(aInfo.iBitsPerPixel >= 12 && aInfo.iBitsPerPixel <= 32, Panic(EDisplayPanicInvalidBitDepth));
   131 	__ASSERT_DEBUG(aInfo.iRefreshRateHz > 0, Panic(EDisplayPanicInvalidRefreshRate));
   132 	__ASSERT_DEBUG(aInfo.iAvailableRotations & aRotation, Panic(EDisplayPanicInvalidRotation));
   133 	__ASSERT_DEBUG(aInfo.iNormal.iWidth == aInfo.iFlipped.iHeight, Panic(EDisplayPanicInvalidDimensions));
   134 	__ASSERT_DEBUG(aInfo.iNormal.iHeight == aInfo.iFlipped.iWidth, Panic(EDisplayPanicInvalidDimensions));
   135 	__ASSERT_DEBUG(aRotation == RDisplayChannel::ERotationNormal ||
   136 					aRotation == RDisplayChannel::ERotation90CW ||
   137 					aRotation == RDisplayChannel::ERotation180 ||
   138 					aRotation == RDisplayChannel::ERotation270CW, Panic(EDisplayPanicInvalidRotation));
   139 	__ASSERT_DEBUG(aFrameBuffers.Count() > 0, Panic(EDisplayPanicInvalidFrameBuffers));
   140 	__ASSERT_DEBUG(aHwnd, Panic(EDisplayPanicInvalidWindowHandle));
   141 
   142 	ValidateSpecificInfo((aInfo.iBitsPerPixel > 16) ? 4 : 2, aInfo.iNormal);
   143 	ValidateSpecificInfo((aInfo.iBitsPerPixel > 16) ? 4 : 2, aInfo.iFlipped);
   144 
   145 	// aFrameBuffers includes the legacy buffer at index 0.
   146 	iNumCompositionBuffers = aFrameBuffers.Count() - 1;
   147 	iTotalBuffers = KFirstCompositionBuffer + iNumCompositionBuffers;
   148 	iBuffer = (TBufferInfo*)Kern::AllocZ(iTotalBuffers * sizeof(TBufferInfo));
   149 	iChunks = (TBufferAddressA*)Kern::AllocZ(iTotalBuffers * sizeof(TBufferAddressA));
   150 	if (!iBuffer)
   151 		{
   152 		return KErrNoMemory;
   153 		}
   154 
   155 	aInfo.iNumCompositionBuffers = iNumCompositionBuffers;
   156 	for (TUint index = 0; index < iNumCompositionBuffers; index++)
   157 		{
   158 		iBuffer[index + KFirstCompositionBuffer].iAddress = aFrameBuffers[index + 1];
   159 		iChunks[index + KFirstCompositionBuffer].iChunk = aChunks[index + 1]->iChunk;
   160 		}
   161 		
   162 	iChannelInfo = aInfo;
   163 	
   164 	iDisplayRotation = iCurrentRotation = aRotation;
   165 	iDisplayResolution = iCurrentResolution = aResolution;
   166 	iCurrentTwips = aTwips;
   167 	iHwnd = aHwnd;
   168 	
   169 	// Ensure the VSync DFC is on the same queue as the message handling.
   170 	iVSyncTicks = NKern::TimerTicks(1000 / aInfo.iRefreshRateHz);
   171     iVSync.OneShot(iVSyncTicks);
   172 
   173 	if (aDsaBuffer.iMemChunks.Count() != 0)
   174 		{	
   175 		iBuffer[KLegacyBuffer].iAddress = aDsaBuffer.iFrameBuffers[0];
   176 		}
   177 	else
   178 		{
   179 		iBuffer[KLegacyBuffer].iAddress = NULL;
   180 		}
   181     
   182 	iPixelFormatArray = aPixelFormatArray;
   183 	iPixelFormatArraySize = aPixelFormatArraySize;
   184 
   185 	// copy the initial buffer format
   186 	iInitialBufferFormat = aBufferFormat;
   187 	iDisplayBufferFormat = iInitialBufferFormat;
   188 	iCurrentBufferFormat = iDisplayBufferFormat;
   189 	return KErrNone;
   190 	}
   191 
   192 
   193 /**
   194 Set the address of the legacy buffer. 
   195  
   196 @param aAddress			Pointer to the legacy buffer. 
   197 */
   198 void DDisplayChannel::SetLegacyBuffer(void *aAddress)
   199 	{ 
   200 	iBuffer[KLegacyBuffer].iAddress = aAddress;
   201 	}
   202 
   203 
   204 
   205 /**
   206 Handle a message on this display for the logical channel.
   207 
   208 @param aMsg	The message to process. The iValue member of this distinguishes the
   209 		message type:
   210 		iValue == ECloseMsg, channel close message
   211 		iValue == KMaxTInt, a 'DoCancel' message
   212 		iValue >= 0, a 'DoControl' message with function number equal to iValue
   213 		iValue < 0, a 'DoRequest' message with function number equal to ~iValue
   214 */
   215 void DDisplayChannel::HandleMsg(TMessageBase* aMsg)
   216 	{
   217 	iMsg = (TThreadMessage*)aMsg;
   218 	TInt id = iMsg->iValue;
   219 	TInt r = KErrNone;
   220 
   221     if (id == (TInt)ECloseMsg)
   222        {
   223        iVSync.Cancel();
   224 	   iWaitForPostRequest.Complete(KErrCancel);
   225 	   iWaitForDisplayConnect.Complete(KErrCancel);
   226        if (iBuffer)
   227 	       	{
   228     		// Unhook display channel from the GUI code if initialized.
   229     		if (iBuffer[KLegacyBuffer].iAddress)
   230 	       		{
   231     		      	Kern::HalFunction(EHalGroupEmulator, EEmulatorHalSetDisplayChannel,
   232 	   					(TAny*)iScreenNumber, NULL);
   233         	   		PostMessage(iHwnd, WMU_SET_DISPLAY_BUFFER, 0, 0);
   234 		      	    InvalidateRect(iHwnd, NULL, FALSE);
   235     			}
   236 
   237 	       	RDisplayChannel::TBufferId index = iTotalBuffers;
   238 
   239     		while (index-- > 0)
   240 	       		{
   241 		          	iBuffer[index].iRequest.Complete(KErrCancel);
   242 
   243         			if (IsUserBuffer(index))
   244 		          		{
   245         				// Close chunk
   246 		          		if (iBuffer[index].iChunk)
   247         					{
   248 		              			NKern::ThreadEnterCS();
   249             					Kern::ChunkClose(iBuffer[index].iChunk);
   250             					NKern::ThreadLeaveCS();
   251         					}
   252 				        }
   253 			     }
   254 
   255             }
   256 			iMsg->Complete(KErrNone, EFalse);
   257 			return;
   258         }
   259 
   260 	if (id < 0)
   261 		{
   262 		DoRequest(~id);
   263 		r = KErrNone;
   264 		}
   265 	else
   266 		{
   267 		r = (id == KMaxTInt) ? DoCancel(iMsg->Int0()) : DoControl(id);
   268 		}
   269 
   270 	iMsg->Complete(r, (id != ECloseMsg));
   271 	}
   272 
   273 
   274 /**
   275 Process synchronous 'control' requests. Parameters are in the first two
   276 arguments of iMsg.
   277 */
   278 TInt DDisplayChannel::DoControl(TInt aFunction)
   279 	{
   280 	DD_TRACE(Kern::Printf(">DDisplayChannel::DoControl fn=%d\n", aFunction);)
   281 
   282 	TInt r = KErrNotSupported;
   283 	TPckgBuf<RDisplayChannel::TDisplayInfo> pkg(iChannelInfo);
   284 	switch(aFunction)
   285 		{
   286 		case RDisplayChannel::ECtrlGetDisplayInfo:
   287 			// a1: TDisplayInfo* info [out]
   288 			Kern::KUDesPut(*(TDes8*)iMsg->Ptr0(), pkg); ///*&iChannelInfo*/);
   289 			r = KErrNone;
   290 			break;
   291 
   292 		case RDisplayChannel::ECtrlOpen:
   293 			// Everything is done in Construct
   294 			r = KErrNone;
   295 			break;
   296 
   297 		case RDisplayChannel::ECtrlClose:
   298 			// Nothing to do?
   299 			r = KErrNone;
   300 			break;
   301 
   302 		case RDisplayChannel::ECtrlPostCompositionBuffer:
   303 			// a1: const TRegionFix<KMaxRectangles>* region [in]
   304 			// a2: TPostCount* post count [out]
   305 			r = PostCompositionBuffer(iMsg->Ptr0(), (RDisplayChannel::TPostCount*)iMsg->Ptr1());
   306 			break;
   307 
   308 		case RDisplayChannel::ECtrlPostLegacyBuffer:
   309 			// a1: const TRegionFix<KMaxRectangles>* region [in]
   310 			// a2: TPostCount* post count [out]
   311 			r = PostLegacyBuffer(iMsg->Ptr0(), (RDisplayChannel::TPostCount*)iMsg->Ptr1());
   312 			break;
   313 
   314 		case RDisplayChannel::ECtrlRegisterUserBuffer:
   315 			// a1: { TInt Chunk handle, TInt offset }* [in]
   316 			// a2: TInt* buffer ID [out]
   317 			{
   318 			__ASSERT_DEBUG(iMsg->Ptr0(), Panic(EDisplayPanicNullArgument));
   319 			TInt arg[2];
   320 			kumemget(arg, iMsg->Ptr0(), sizeof(arg));
   321 			r = RegisterUserBuffer(arg[0], arg[1], (RDisplayChannel::TBufferId*)iMsg->Ptr1());
   322 			}
   323 			break;
   324 
   325 		case RDisplayChannel::ECtrlDeregisterUserBuffer:
   326 			// a1: TBufferId* buffer ID [in]
   327 			r = DeregisterUserBuffer((RDisplayChannel::TBufferId*)iMsg->Ptr0());
   328 			break;
   329 
   330 		case RDisplayChannel::ECtrlSetRotation:
   331 			// a1: TDisplayRotation* new rotation [in]
   332 			// a2: TBool* display config has changed [out]
   333 			r = SetRotation((RDisplayChannel::TDisplayRotation*)iMsg->Ptr0(), (TBool*)iMsg->Ptr1());
   334 			break;
   335 
   336 		case RDisplayChannel::ECtrlCurrentRotation:
   337 			// a1: TDisplayRotation* current rotation [out]
   338 			r = SafePut(iMsg->Ptr0(), &iCurrentRotation, sizeof(iCurrentRotation));
   339 			break;
   340 
   341 		case ECloseMsg:
   342 			r = KErrNone;
   343 			break;
   344 
   345 	    case RDisplayChannel::ECtrlGetCompositionBufferInfo:
   346     	    {
   347     	    TInt arg[2];
   348     	    TInt index = *((TInt*)(iMsg->Ptr0()));
   349             r = Kern::MakeHandleAndOpen(iMsg->Client(), iChunks[index + KFirstCompositionBuffer].iChunk);
   350             if(r >= 0)
   351                 {
   352 	            arg[0] = r;
   353 	            arg[1] = 0;
   354 				SafePut(iMsg->Ptr1(),&arg,(sizeof(TInt)*2));
   355                 r = KErrNone;
   356                 }
   357              }
   358     	    break;
   359     	 // added to v1.0
   360 	    case RDisplayChannel::ECtrlVersion:
   361 			r = SafePut(iMsg->Ptr0(), &iVersion, sizeof(iVersion));
   362 	    	break;
   363     	//v1_1
   364 	    case RDisplayChannel::ECtrlNumberOfResolutions:
   365 	    	{
   366 	    	r = NumberOfResolutions();
   367 	    	}
   368 	    	break;
   369 	    case RDisplayChannel::ECtrlGetResolutions:
   370 	    	{
   371 	    	r = GetResolutions();
   372 	    	if(r == KErrCorrupt) //Resolution list changed during GetResolutions
   373 	    		{//second go
   374 	    		r = GetResolutions();
   375 	    		}
   376 	    	}
   377 	    	break;
   378 	    case RDisplayChannel::ECtrlSetResolution:
   379 	    	{
   380 	    	r = SetResolution((TSize*)iMsg->Ptr0());
   381 	    	}
   382 	    	break;
   383 	    case RDisplayChannel::ECtrlGetResolution:
   384 	    	{
   385 	    	r = GetResolution((TSize*)iMsg->Ptr0());
   386 	    	}
   387 	    	break;
   388 	    case RDisplayChannel::ECtrlGetTwips:
   389 	    	{
   390 	    	r = GetTwips((TSize*)iMsg->Ptr0());
   391 	    	}
   392 	    	break;
   393 	    case RDisplayChannel::ECtrlNumberOfPixelFormats:
   394 			r = iPixelFormatArraySize;
   395 	    	break;
   396 	    case RDisplayChannel::ECtrlGetPixelFormats:
   397 	    	r = GetPixelFormats();
   398 	    	break;
   399 	    case RDisplayChannel::ECtrlSetBufferFormat:
   400 	    	r = SetBufferFormat((RDisplayChannel::TBufferFormat*)iMsg->Ptr0());
   401 	    	break;
   402 	    case RDisplayChannel::ECtrlGetBufferFormat:
   403 			r = SafePut(iMsg->Ptr0(), &iCurrentBufferFormat, sizeof(iCurrentBufferFormat));
   404 	    	break;
   405 	    case RDisplayChannel::ECtrlNextPlaneOffset:
   406 	    	// we support, for moment only packed pixel formats
   407 	    	r = NextPlaneOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(), NULL);
   408 	    	break;
   409 	    case RDisplayChannel::ECtrlNextLineOffset:
   410 	    	// use the internal current resolution and current rotation
   411 	    	r = NextLineOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(), NULL);
   412 	    	break;
   413 	    case RDisplayChannel::ECtrlNextPlaneOffsetExtended:
   414 	    	// we support, for moment only packed pixel formats
   415 	    	r = NextPlaneOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(),
   416 	    			            (RDisplayChannel::TBufferFormatContext*)iMsg->Ptr1());
   417 	    	break;
   418 	    case RDisplayChannel::ECtrlNextLineOffsetExtended:
   419 	    	r = NextLineOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(),
   420 	    			           (RDisplayChannel::TBufferFormatContext*)iMsg->Ptr1());
   421 	    	break;
   422 		}
   423 	DD_TRACE(Kern::Printf("<DDisplayChannel::DoControl result=%d\n",r);)
   424 	return r;
   425 	}
   426 
   427 TInt DDisplayChannel::GetIndexForSize(const TSize& aSize,TInt& aSpinnerOut)
   428 	{
   429 	TInt numberOfResolutions = 0;
   430 	TInt spinner1 = 0;
   431 	TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, &spinner1, iScreenNumber);
   432 	if(r < KErrNone)
   433 		return r;
   434 	TVideoInfoV01 info;
   435 	TPckg<TVideoInfoV01> infoPckg(info);
   436 
   437 	for (TInt res=0;res<numberOfResolutions;res++)
   438 		{
   439 		//pass info package to be filled in, also sending the config to read, and the screen within that
   440 		Kern::HalFunction(EHalGroupDisplay, EDisplayHalSpecificScreenInfo, (TAny*)&res, (TAny*)&infoPckg, iScreenNumber);
   441 		if (info.iSizeInPixels.iWidth==aSize.iWidth && info.iSizeInPixels.iHeight==aSize.iHeight)
   442 			{
   443 			r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, &aSpinnerOut, iScreenNumber);
   444 			if(r < KErrNone)
   445 				return r;
   446 			if (aSpinnerOut!=spinner1)
   447 				{
   448 				return KErrCorrupt;
   449 				}
   450 			else
   451 				{
   452 				return res;
   453 				}
   454 			}
   455 		}
   456 	return KErrArgument;
   457 	}
   458 
   459 /**
   460 Process asynchronous requests. TRequestStatus is at iMsg->Ptr0(), and the other
   461 two parameters are in iMsg->Ptr1() and iMsg->Ptr2().
   462 */
   463 void DDisplayChannel::DoRequest(TInt aFunction)
   464 	{
   465 	DD_TRACE(Kern::Printf(">DDisplayChannel::DoRequest fn=%d\n", aFunction);)
   466 
   467 	TInt r = KErrNotSupported;
   468 
   469 	switch(aFunction)
   470 		{
   471 		case RDisplayChannel::EReqGetCompositionBuffer:
   472 			// a1: TAny** buffer address [out]
   473 			r = GetCompositionBuffer(static_cast<TAny**>(iMsg->Ptr1()));
   474 			break;
   475 
   476 		case RDisplayChannel::EReqPostUserBuffer:
   477 			// a1: { TBufferId* buffer ID, const TRegionFix<KMaxRectangles>* region }* [in]
   478 			// a2: TPostCount* post count [out]
   479 			{
   480 			TAny* arg[2];
   481 			__ASSERT_DEBUG(iMsg->Ptr1(), Panic(EDisplayPanicNullArgument));
   482 			kumemget(arg, iMsg->Ptr1(), sizeof(arg));
   483 			r = PostUserBuffer(reinterpret_cast<RDisplayChannel::TBufferId*>(arg[0]), arg[1],
   484 					reinterpret_cast<RDisplayChannel::TPostCount*>(iMsg->Ptr2()));
   485 			}
   486 			break;
   487 
   488 		case RDisplayChannel::EReqWaitForPost:
   489 			// a1: TInt* post to wait for [in]
   490 			r = WaitForPost(static_cast<RDisplayChannel::TPostCount*>(iMsg->Ptr1()));
   491 			break;
   492 	    	//v1_1
   493 		case RDisplayChannel::EReqWaitForDisplayConnect:
   494 			r = WaitForDisplayConnect();
   495 			break;
   496 		}
   497 
   498 	DD_TRACE(Kern::Printf("<DDisplayChannel::DoRequest result=%d\n",r);)
   499 
   500 	if (r != KRequestPending)
   501 		{
   502 		TRequestStatus* status = reinterpret_cast<TRequestStatus*>(iMsg->Ptr0());
   503 		Kern::RequestComplete(iMsg->Client(), status, r);
   504 		}
   505 	}
   506 
   507 
   508 /**
   509 Process asynchronous request cancellations
   510 */
   511 TInt DDisplayChannel::DoCancel(TInt aRequestMask)
   512 	{
   513 	DD_TRACE(Kern::Printf(">DDisplayChannel::DoCancel mask=%x\n", aRequestMask);)
   514 
   515 	if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelGetCompositionBuffer))
   516 		{
   517 		if (IsCompositionBuffer(iGetBuffer))
   518 			{
   519 			iBuffer[iGetBuffer].iRequest.Complete(KErrCancel);
   520 			}
   521 		}
   522 
   523 	if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelPostUserBuffer))
   524 		{
   525 		if (IsUserBuffer(iPostedBuffer))
   526 			{
   527 			iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
   528 			}
   529 		}
   530 
   531 	if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelWaitForPost))
   532 		{
   533 		iWaitForPostRequest.Complete(KErrCancel);
   534 		}
   535 	if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelWaitForDisplayConnect))
   536 		{
   537 		iWaitForDisplayConnect.Complete(KErrCancel);
   538 		}
   539 
   540 	DD_TRACE(Kern::Printf("<DDisplayChannel::DoCancel\n",r);)
   541 	return KErrNone;
   542 	}
   543 
   544 
   545 /**
   546 Get the number of resolutions on this screen
   547 @return Number of resolutions if successful, otherwise a system wide error code.
   548 */
   549 TInt DDisplayChannel::NumberOfResolutions()
   550 	{
   551 	TInt numberOfResolutions = 0;
   552 	TInt error = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, NULL, iScreenNumber);
   553 	if (error != KErrNone)
   554 		{
   555 		return error;
   556 		}
   557 	return numberOfResolutions;
   558 	}
   559 
   560 
   561 /**
   562 Safely write from kernel to user memory.
   563 @param aDst	Pointer to destination, user memory.
   564 @param aSrc	Pointer to source, kernel memory.
   565 @param aBytes	Number of bytes to write.
   566 @return KErrNone if successful, KErrArgument if either pointer is NULL.
   567 */
   568 TInt DDisplayChannel::SafePut(TAny* aDst, TAny* aSrc, TInt aBytes)
   569 	{
   570 	if (!aDst || !aSrc)
   571 		{
   572 		return KErrArgument;
   573 		}
   574 
   575 	kumemput(aDst, aSrc, aBytes);
   576 	return KErrNone;
   577 	}
   578 
   579 
   580 /**
   581 Driver panic.
   582 @param	aPanic	The cause of the panic.
   583 */
   584 void DDisplayChannel::Panic(TDisplayPanic aPanic)
   585 	{
   586 	Kern::Fault("DISPLAY", aPanic);
   587 	}
   588 
   589 
   590 /**
   591 Client panic.
   592 @param	aPanic	The cause of the panic.
   593 */
   594 void DDisplayChannel::ClientPanic(RDisplayChannel::TPanic aPanic)
   595 	{
   596 	_LIT(KLitDisplayChannel, "DISPLAYCHANNEL");
   597 	Kern::ThreadKill(iClient, EExitPanic, aPanic, KLitDisplayChannel);
   598 	}
   599 
   600 
   601 /**
   602 VSync is emulated by using a nanokernel timer to call this function at the
   603 frame rate.
   604 */
   605 void DDisplayChannel::VSyncTimerFn(TAny* aDisplayChannel)
   606 	{
   607 	reinterpret_cast<DDisplayChannel*>(aDisplayChannel)->DoVSyncTimer();
   608 	}
   609 
   610 /**
   611 Instance function called on the timer thread. Queues the VSyncDfc to run on its
   612 thread.
   613 */
   614 void DDisplayChannel::DoVSyncTimer(void)
   615 	{
   616 	iVSyncDfc.Add();
   617 	iVSync.Again(iVSyncTicks);
   618 	}
   619 
   620 
   621 /**
   622 DFC function to post the current buffer to the display.
   623 @param aDisplayImpl	The display object to be posted.
   624 */
   625 void DDisplayChannel::VSyncDfcFn(TAny* aDisplayChannel)
   626 	{
   627 	reinterpret_cast<DDisplayChannel*>(aDisplayChannel)->DoVSync();
   628 	}
   629 
   630 
   631 /**
   632 Post the current buffer to the display. Signal waiting threads under various
   633 conditions. This is run off the same DFC queue as message handling, so there is
   634 no need to protect the fields.
   635 */
   636 void DDisplayChannel::DoVSync(void)
   637 	{
   638 	if(iWaitForDisplayConnect.iStatus)
   639 		{
   640 		TInt currentSpinner;
   641 		Kern::HalFunction(EHalGroupDisplay, EDisplayHalGetStateSpinner, &currentSpinner, NULL, iScreenNumber);
   642 		//display state changed
   643 		if(currentSpinner != iDisplayStateSpinner)
   644 			iWaitForDisplayConnect.Complete(KErrNone);
   645 		}
   646 		
   647 	if (IsValidBuffer(iPostedBuffer))
   648 		{
   649 		// Complete any outstanding request for the buffer which was displayed.
   650 		// This either signifies the user or composition buffer becoming
   651 		// available 
   652 		if (iDisplayBuffer != iPostedBuffer)
   653 			{
   654 			iBuffer[iDisplayBuffer].iRequest.Complete(KErrNone);
   655 			}
   656 
   657 		iDisplayBuffer = (RDisplayChannel::TBufferId)iPostedBuffer;
   658 		iPostedBuffer = (RDisplayChannel::TBufferId)KBufferNotSet;
   659 
   660 		// Update the pixel pointer used when painting the client window		
   661 		PostMessage(iHwnd, WMU_SET_DISPLAY_BUFFER, 0,
   662 				(LPARAM)iBuffer[iDisplayBuffer].iAddress);
   663 
   664 		// check if the buffer format is modified
   665 	if ((iDisplayBufferFormat.iSize.iHeight != iNewBufferFormat.iSize.iHeight) || 
   666 		(iDisplayBufferFormat.iSize.iWidth != iNewBufferFormat.iSize.iWidth) ||
   667 		(iDisplayBufferFormat.iPixelFormat != iNewBufferFormat.iPixelFormat))
   668 		{
   669 		// We post in one messages everything, but we got to pack the size
   670 		// speculate that the maximum width and height can be represented in 16 bit
   671 		TUint aggregateSize = ((TUint)iNewBufferFormat.iSize.iHeight << 16) & 0xffff0000; 
   672 		aggregateSize += (TUint)iNewBufferFormat.iSize.iWidth & 0x0000ffff;
   673 		PostMessage(iHwnd, 
   674 				    WMU_SET_BUFFER_FORMAT, 
   675 				    aggregateSize, 
   676 				    iNewBufferFormat.iPixelFormat);
   677 		iDisplayBufferFormat = iNewBufferFormat;
   678 		}
   679 	
   680 		if (iDisplayRotation != iNewRotation)
   681 			{
   682 			iDisplayRotation = iNewRotation;
   683 
   684 			TUint flip;
   685 			switch (iDisplayRotation)
   686 				{
   687 				case RDisplayChannel::ERotation90CW:
   688 					flip = EEmulatorFlipLeft;
   689 					break;
   690 				case RDisplayChannel::ERotation180:
   691 					flip = EEmulatorFlipInvert;
   692 					break;
   693 				case RDisplayChannel::ERotation270CW:
   694 					flip = EEmulatorFlipRight;
   695 					break;
   696 				default:	// Normal
   697 					flip = EEmulatorFlipRestore;
   698 					break;
   699 				}
   700 			PostMessage(iHwnd, WM_FLIP_MESSAGE, flip, NULL);
   701 
   702 			iPostedRectCount = 0;	// Force full invalidation
   703 			}
   704 
   705 		if (iDisplayResolution.iWidth != iNewResolution.iWidth ||
   706 				iDisplayResolution.iHeight != iNewResolution.iHeight)
   707 			{
   708 			iDisplayResolution = iNewResolution;
   709 			PostMessage(iHwnd, WMU_SET_DISPLAY_SIZE, 
   710 					iDisplayResolution.iWidth, iDisplayResolution.iHeight);
   711 			}
   712 	
   713 		
   714 		// Invalidate the window contents where necessary
   715 		TInt count = iPostedRectCount;
   716 		if (count)
   717 			{
   718 			// Order of invalidation is immaterial
   719 			while (count--)
   720 				{
   721 				InvalidateRect(iHwnd, &iPostedRect[count], FALSE);
   722 				}
   723 
   724 			iPostedRectCount = 0;
   725 			}
   726 		else
   727 			{
   728 			InvalidateRect(iHwnd, NULL, FALSE);
   729 			}
   730 
   731 		// Use differences to allow for wraparound
   732 		if ((TInt)(iWaitForPost - iLastPostCount) > 0 && (TInt)(iPostCount - iWaitForPost) >= 0)
   733 			{
   734 			// Post waited for is now being displayed or was dropped
   735 			iWaitForPostRequest.Complete(KErrNone);
   736 			}
   737 		iLastPostCount = iPostCount;
   738 		}
   739 	}
   740 
   741 
   742 /**
   743 Set the status object for this request and the thread to complete it on, if not
   744 already set.
   745 @param aStatus	The new request status.
   746 @param aThread	The thread on which to complete.
   747 @return EFalse if the status is already set, or ETrue if the status has now been
   748 set.
   749 */
   750 TBool DDisplayChannel::TRequest::SetStatus(TThreadMessage& aMsg)
   751 	{
   752 	if (iStatus)
   753 		{
   754 		__ASSERT_DEBUG(iThread, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicNullThreadOnSet));
   755 		return EFalse;	// In use
   756 		}
   757 
   758 	__ASSERT_DEBUG(!iThread, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicThreadAlreadySet));
   759 	DThread* thread = aMsg.Client();
   760 	TInt r = thread->Open();
   761 	__ASSERT_DEBUG( r == KErrNone, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicThreadOpenFailed));
   762 	(TAny)r;
   763 	iThread = thread;
   764 	iStatus = reinterpret_cast<TRequestStatus*>(aMsg.Ptr0());
   765 	return ETrue;
   766 	}
   767 
   768 
   769 /**
   770 Complete the request with the given result. If the status has not been set, or
   771 has already been completed, this does nothing.
   772 @param aResult	The result of the asynchronous request.
   773 */
   774 void DDisplayChannel::TRequest::Complete(TInt aResult)
   775 	{
   776 	if (iStatus)
   777 		{
   778     	__ASSERT_DEBUG(iThread, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicNullThreadOnComplete));
   779 		Kern::RequestComplete(iThread, iStatus, aResult);
   780 		Kern::SafeClose((DObject*&)iThread, NULL);
   781 		}
   782 	}
   783 
   784 
   785 /**
   786 Post the current composition buffer to the display on the next frame tick.
   787 @param aRegion	NULL if the entire buffer has changed, or a user pointer to up
   788 to TDisplayInfo::KMaxRectagles areas that have changed.
   789 @param aPostCount	User pointer to an integer to receive the new post count.
   790 @return KErrNone, or a system-wide error code
   791 */
   792 TInt DDisplayChannel::PostCompositionBuffer(TAny* aRegion, RDisplayChannel::TPostCount* aPostCount)
   793 	{
   794 	if (!IsCompositionBuffer(iGetBuffer))
   795 		{
   796 		return KErrNotSupported;
   797 		}
   798 
   799 	if (iWaitForPost == iPostCount)
   800 		{
   801 		// Complete wait for post (dropped)
   802 		iWaitForPostRequest.Complete(KErrNone);
   803 		}
   804 
   805 	if (IsUserBuffer(iPostedBuffer))
   806 		{
   807 		// Complete the user post request (not displayed)
   808 		iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
   809 		}
   810 
   811 	iPostedBuffer = iGetBuffer;
   812 	iGetBuffer = NextCompositionBuffer(iGetBuffer);
   813 
   814 	if (iNumCompositionBuffers > 2 && iGetBuffer == iDisplayBuffer)
   815 		{
   816 		// With more than two buffers, there must always be one available with
   817 		// no waiting required, so find it.
   818 		iGetBuffer = NextCompositionBuffer(iGetBuffer);
   819 		}
   820 
   821 	// Get the region
   822 	if (aRegion)
   823 		{
   824 		// Set iPostedRect(Count) from aRegion.
   825 		Panic(EDisplayPanicNotYetImplemented);
   826 		}
   827 
   828 	// What to do about wrapping?
   829 	iPostCount++;
   830 	iNewRotation = iCurrentRotation;
   831 	iNewResolution = iCurrentResolution;
   832 	iNewBufferFormat = iCurrentBufferFormat;
   833 	SafePut(aPostCount, &iPostCount, sizeof(iPostCount));
   834 
   835 	return KErrNone;
   836 	}
   837 
   838 
   839 /**
   840 Post the legacy buffer to the display on the next frame tick.
   841 @param aRegion	NULL if the entire buffer has changed, or a user pointer to up
   842 to TDisplayInfo::KMaxRectagles areas that have changed.
   843 @param aPostCount	User pointer to an integer to receive the new post count.
   844 @return KErrNone, or a system-wide error code
   845 */
   846 TInt DDisplayChannel::PostLegacyBuffer(TAny* aRegion, RDisplayChannel::TPostCount* aPostCount)
   847 	{
   848 	if (iWaitForPost == iPostCount)
   849 		{
   850 		// Complete wait for post (dropped)
   851 		iWaitForPostRequest.Complete(KErrNone);
   852 		}
   853 
   854 	if (IsUserBuffer(iPostedBuffer))
   855 		{
   856 		iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
   857 		}
   858 
   859 	// iBuffer should NOT be NULL here!
   860 	__ASSERT_ALWAYS(iBuffer[KLegacyBuffer].iAddress, Panic(EDisplayPanicNoLegacyBuffer));
   861 	iPostedBuffer = KLegacyBuffer;
   862 
   863 	// Get the region into iRegion
   864 	if (aRegion)
   865 		{
   866 		// Set iPostedRect(Count) from aRegion.
   867 		Panic(EDisplayPanicNotYetImplemented);
   868 		}
   869 
   870 	iPostCount++;
   871 	iNewRotation = iCurrentRotation;
   872 	iNewResolution = iCurrentResolution;
   873 	iNewBufferFormat = iCurrentBufferFormat;
   874 	SafePut(aPostCount, &iPostCount, sizeof(iPostCount));
   875 
   876 	return KErrNone;
   877 	}
   878 
   879 
   880 /**
   881 Asynchronously request the current composition buffer. Completes immediately
   882 if not already being displayed, or an error occurs.
   883 @param aStatus	The request status to be completed.
   884 @param aAddress	The user pointer to the location to put the address.
   885 */
   886 TInt DDisplayChannel::GetCompositionBuffer(TAny** aAddress)
   887 	{
   888 	if (!IsCompositionBuffer(iGetBuffer))
   889 		{
   890 		// No composition buffers available for use.
   891 		return KErrNotSupported;
   892 		}
   893 
   894 	// The address won't change, so may as well set it now.
   895 	TUint idx = iGetBuffer - KFirstCompositionBuffer;
   896 	if (SafePut(aAddress, &idx, sizeof(TUint)) != KErrNone)
   897 		{
   898 		return KErrArgument;
   899 		}
   900 
   901 	if (iNumCompositionBuffers > 1 && iGetBuffer == iDisplayBuffer)
   902 		{
   903 		// Multi-buffer case, and buffer is currently being displayed
   904 
   905 		if (iBuffer[iGetBuffer].iRequest.SetStatus(*iMsg))
   906 			{
   907 			return KRequestPending;
   908 			}
   909 
   910 		// Already set
   911 		return KErrInUse;
   912 		}
   913 
   914 	return KErrNone;
   915 	}
   916 
   917 
   918 /**
   919 Post a user buffer to the display on the next frame tick.
   920 @param aBufferId	The ID of the user buffer to post.
   921 @param aRegion	NULL if the entire buffer has changed, or a user pointer to up
   922 to TDisplayInfo::KMaxRectagles areas that have changed.
   923 @return KErrNone, or a system-wide error code
   924 */
   925 TInt DDisplayChannel::PostUserBuffer(RDisplayChannel::TBufferId* aBufferId, TAny* aRegion, RDisplayChannel::TPostCount* aPostCount)
   926 	{
   927 	RDisplayChannel::TBufferId bufferId;
   928 	bufferId = reinterpret_cast <RDisplayChannel::TBufferId> (aBufferId);
   929 
   930 	if (!IsUserBuffer(bufferId))
   931 		{
   932 		// Not a user buffer.
   933 		return KErrArgument;
   934 		}
   935 
   936 	if (!iBuffer[bufferId].iChunk)
   937 		{
   938 		// User buffer not initialised.
   939 		return KErrArgument;
   940 		}
   941 
   942 	if (iWaitForPost == iPostCount)
   943 		{
   944 		// Complete wait for post (dropped)
   945 		iWaitForPostRequest.Complete(KErrNone);
   946 		}
   947 
   948 	if (IsUserBuffer(iPostedBuffer))
   949 		{
   950 		// Complete the user post request (not displayed)
   951 		iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
   952 		}
   953 
   954 	if (bufferId == iDisplayBuffer)	//pathological case
   955 		{
   956 		// Complete the current display buffer as we are superceding it with the same one
   957 		iBuffer[bufferId].iRequest.Complete(KErrNone);
   958 		}
   959 
   960 	// Only one buffer can be posted at any time, and if it were this user
   961 	// buffer, the request will have just been completed, so this shouldn't fail.
   962 	TBool isSet = iBuffer[bufferId].iRequest.SetStatus(*iMsg);
   963 
   964 	__ASSERT_DEBUG(isSet, Panic(EDisplayPanicInUse));
   965 	(TAny)isSet;
   966 	iPostedBuffer = bufferId;
   967 
   968 	// Get the region
   969 	if (aRegion)
   970 		{
   971 		// Set iPostedRect(Count) from aRegion.
   972 		Panic(EDisplayPanicNotYetImplemented);
   973 		}
   974 
   975 	iPostCount++;
   976 	iNewRotation = iCurrentRotation;
   977 	iNewResolution = iCurrentResolution;
   978 	iNewBufferFormat = iCurrentBufferFormat;
   979 	SafePut(aPostCount, &iPostCount, sizeof(iPostCount));
   980 
   981 	return KRequestPending;
   982 	}
   983 
   984 /**
   985 Asynchronous request notification when the given post count is reached (or
   986 passed).
   987 @param aStatus	The request status to be completed.
   988 @param aPostCount	The count to wait for.
   989 */
   990 TInt DDisplayChannel::WaitForPost(RDisplayChannel::TPostCount* aPostCount)
   991 	{
   992 	TInt postCount;
   993 
   994 	kumemget(&postCount, aPostCount, sizeof(RDisplayChannel::TPostCount));
   995 
   996 	if ((TInt)(iWaitForPost - iLastPostCount) > 0 && (TInt)(iPostCount - iWaitForPost) >= 0)
   997 		{
   998 		// Set up the request to be completed when the post occurs
   999 		if (iWaitForPostRequest.SetStatus(*iMsg))
  1000 			{
  1001 			iWaitForPost = postCount;
  1002 			return KRequestPending;
  1003 			}
  1004 
  1005 		// Already waiting for a post
  1006 		return KErrInUse;
  1007 		}
  1008 
  1009 	// Requested post already displayed/dropped
  1010 	return KErrNone;
  1011 	}
  1012 
  1013 /**
  1014 Asynchronous request notification when the display connection state changes.
  1015 This occurs when the display is disconnected, connected with no list, or a list of modes becomes available or is updated.
  1016 */
  1017 TInt DDisplayChannel::WaitForDisplayConnect()
  1018 	{
  1019 	
  1020 	Kern::HalFunction(EHalGroupDisplay, EDisplayHalGetStateSpinner, &iDisplayStateSpinner, NULL, iScreenNumber);
  1021 	
  1022 	if (iWaitForDisplayConnect.SetStatus(*iMsg))
  1023 		{
  1024 		return KRequestPending;
  1025 		}
  1026 
  1027 	// Already waiting for a post
  1028 	return KErrInUse;
  1029 	}
  1030 
  1031 
  1032 /**
  1033 Set the rotation of the screen on the next frame. If the buffer contents will
  1034 not be valid, the flag set. The validity of the buffer is down to whether the
  1035 width and height change.
  1036 
  1037 @param aNewRotation	Address in user space of the new rotation setting.
  1038 @param aDisplayConfigChanged	Address in user space of where to put whether the
  1039 orientation specific info to use has changed following the rotation setting.
  1040 @return KErrNone, or KErrArgument if an argument was invalid.
  1041 */
  1042 TInt DDisplayChannel::SetRotation(RDisplayChannel::TDisplayRotation* aNewRotation,
  1043 		TBool* aDisplayConfigChanged)
  1044 	{
  1045 	RDisplayChannel::TDisplayRotation newRotation;
  1046 
  1047 	__ASSERT_DEBUG(aNewRotation, Panic(EDisplayPanicNullArgument));
  1048 
  1049 	kumemget(&newRotation, aNewRotation, sizeof(newRotation));
  1050 
  1051 	if (((TInt)newRotation - 1) & newRotation)
  1052 		{
  1053 		// More than one bit is set, which is not valid
  1054 		return KErrArgument;
  1055 		}
  1056 
  1057 	if ((iChannelInfo.iAvailableRotations & newRotation) == 0)
  1058 		{
  1059 		// Rotation is not supported
  1060 		return KErrArgument;
  1061 		}
  1062 
  1063 	TBool displayConfigChanged = (IsFlipped(newRotation) != IsFlipped(iCurrentRotation));
  1064 	iCurrentRotation = newRotation;
  1065 
  1066 	SafePut(aDisplayConfigChanged, &displayConfigChanged, sizeof(TBool));
  1067 
  1068 	return KErrNone;
  1069 	}
  1070 
  1071 
  1072 /**
  1073 Register a user buffer. Assign an ID for it (if available) and open the chunk to
  1074 get the address.
  1075 @param aChunkHandle	The chunk handle.
  1076 @param aOffset		The offset from the chunk base address to the start of the
  1077 buffer.
  1078 @param aBufferId	The address in user space of where to put the buffer ID.
  1079 */
  1080 TInt DDisplayChannel::RegisterUserBuffer(TInt aChunkHandle, TInt aOffset,
  1081 		RDisplayChannel::TBufferId* aBufferId)
  1082 	{
  1083 	if (!aBufferId)
  1084 		{
  1085 		return KErrArgument;
  1086 		}
  1087 
  1088 	NKern::ThreadEnterCS();
  1089 	DChunk* chunk = Kern::OpenSharedChunk(iMsg->Client(), aChunkHandle,
  1090 			EFalse);
  1091 	NKern::ThreadLeaveCS();
  1092 	if (!chunk)
  1093 		{
  1094 		return KErrBadHandle;
  1095 		}
  1096 
  1097 	TLinAddr kernelAddress;
  1098 
  1099 	const TInt bufferSize = (iDisplayResolution.iWidth * iDisplayResolution.iHeight);
  1100 	TInt r = Kern::ChunkAddress(chunk,aOffset,bufferSize,kernelAddress);
  1101 	if(r!=KErrNone)
  1102 		{
  1103 		NKern::ThreadEnterCS();
  1104 		Kern::ChunkClose(chunk);
  1105 		NKern::ThreadLeaveCS();
  1106 		return r;
  1107 		}
  1108 
  1109 	// Search for an empty slot
  1110 	for (TInt index = KFirstUserBuffer; index < (KFirstUserBuffer + RDisplayChannel::TDisplayInfo::KMaxUserBuffers); index++)
  1111 		{
  1112 		if (!iBuffer[index].iChunk)
  1113 			{
  1114 			// Found one, so fill in the details and return the index as the ID.
  1115 			iBuffer[index].iChunk = chunk;
  1116 			iBuffer[index].iAddress = (TAny*)(kernelAddress);
  1117 			kumemput(aBufferId, &index, sizeof(RDisplayChannel::TBufferId));
  1118 			return KErrNone;
  1119 			}
  1120 		}
  1121 
  1122 	// No slots available.
  1123 	NKern::ThreadEnterCS();
  1124 	Kern::ChunkClose(chunk);
  1125 	NKern::ThreadLeaveCS();
  1126 	return KErrTooBig;
  1127 	}
  1128 
  1129 
  1130 /**
  1131 Deregister a user buffer.
  1132 @param aBufferId	The buffer ID.
  1133 */
  1134 TInt DDisplayChannel::DeregisterUserBuffer(RDisplayChannel::TBufferId* aBufferId)
  1135 	{
  1136 	RDisplayChannel::TBufferId bufferId;
  1137 	
  1138 	__ASSERT_DEBUG(aBufferId, Panic(EDisplayPanicNullArgument));
  1139 	kumemget(&bufferId, aBufferId, sizeof(RDisplayChannel::TBufferId));
  1140 
  1141 	if (!IsUserBuffer(bufferId))
  1142 		{
  1143 		// Not a valid ID
  1144 		return KErrArgument;
  1145 		}
  1146 
  1147 	TBufferInfo* buffer = &iBuffer[bufferId];
  1148 	if (!buffer->iChunk)
  1149 		{
  1150 		// Not registered
  1151 		return KErrArgument;
  1152 		}
  1153 
  1154 	if (iDisplayBuffer == bufferId)
  1155 		{
  1156 		return KErrInUse;
  1157 		}
  1158 
  1159 	if (iPostedBuffer == bufferId)
  1160 		{
  1161 		// Was queued to be posted
  1162 		iPostedBuffer = (RDisplayChannel::TBufferId)KBufferNotSet;
  1163 		iPostedRectCount = 0;
  1164 		}
  1165 
  1166 	// Cancel any outstanding request on the buffer and clear out the fields.
  1167 	buffer->iRequest.Complete(KErrCancel);
  1168 	NKern::ThreadEnterCS();
  1169 	Kern::ChunkClose(buffer->iChunk);
  1170 	NKern::ThreadLeaveCS();
  1171 	buffer->iChunk = NULL;
  1172 	buffer->iAddress = NULL;
  1173 
  1174 	return KErrNone;
  1175 	}
  1176 
  1177 /**
  1178 Get all resolutions available for this screen and insert to a descriptor
  1179 @return KErrNone if successful, otherwise a system wide error code.
  1180 */
  1181 TInt DDisplayChannel::GetResolutions()
  1182 	{
  1183 	TInt r;
  1184 	__ASSERT_DEBUG(iMsg->Ptr0(), Panic(EDisplayPanicNullArgument));
  1185 	__ASSERT_DEBUG(iMsg->Ptr1(), Panic(EDisplayPanicNullArgument));
  1186 	//get the number of resolutions (as above)
  1187 	TInt numberOfResolutions = 0;
  1188 	TInt refStateSpinner, curStateSpinner;
  1189 	//Get the number of resolutions as well as the display state spinner at this point
  1190 	r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, &refStateSpinner, iScreenNumber);
  1191 	if(r < KErrNone)
  1192 		{
  1193 		return r;
  1194 		}
  1195 		    	
  1196 	TInt length;
  1197 	TInt maxLength;
  1198 	Kern::KUDesInfo(*(const TDesC*)iMsg->Ptr0(),length,maxLength);
  1199 		    	
  1200 	if ((maxLength/static_cast<TInt>(sizeof(RDisplayChannel::TResolution))) < numberOfResolutions)
  1201 		{
  1202 		return KErrOverflow;
  1203 		}
  1204 		    	
  1205 	TVideoInfoV01 info;
  1206 	TPckg<TVideoInfoV01> infoPckg(info);
  1207 	RDisplayChannel::TResolution resolution = {{0,0},{0,0},RDisplayChannel::ERotationAll};
  1208 	TPtr8 tempDes(NULL,0);
  1209 
  1210 	TInt i;
  1211 	for (i=0;i<numberOfResolutions;i++)
  1212 		{
  1213 		//before filling the package, the display state needs to be checked for consistency
  1214 		Kern::HalFunction(EHalGroupDisplay, EDisplayHalGetStateSpinner, &curStateSpinner, NULL, iScreenNumber);
  1215 		    			    		
  1216 		if(curStateSpinner != refStateSpinner)
  1217 			{ //display state has changed, the resolution list we trying to get becomes corrupted
  1218 			Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(),(i)*sizeof(RDisplayChannel::TResolution));
  1219 			return KErrCorrupt;
  1220 			}
  1221 
  1222 		//pass info package to be filled in, also sending the config to read, and the screen within that
  1223 		Kern::HalFunction(EHalGroupDisplay, EDisplayHalSpecificScreenInfo, &i, &infoPckg, iScreenNumber);
  1224 		//save resolution
  1225 		resolution.iPixelSize = info.iSizeInPixels;
  1226 		resolution.iTwipsSize = info.iSizeInTwips;
  1227 		//copy resolution
  1228   		tempDes.Set((TUint8*)&resolution,sizeof(RDisplayChannel::TResolution),sizeof(RDisplayChannel::TResolution));
  1229    		r = Kern::ThreadDesWrite(iMsg->Client(),(TDes8*)iMsg->Ptr0(),tempDes,i*sizeof(RDisplayChannel::TResolution),iMsg->Client());
  1230 		    		
  1231    		if (r<KErrNone)
  1232    			{
  1233    			Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(),(i)*sizeof(RDisplayChannel::TResolution));
  1234    			return r;
  1235    			}
  1236    		}
  1237 	Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(),(i)*sizeof(RDisplayChannel::TResolution));
  1238    	SafePut(iMsg->Ptr1(), &numberOfResolutions, sizeof(numberOfResolutions));
  1239    	return KErrNone;
  1240 	}
  1241 
  1242 
  1243 
  1244 TInt DDisplayChannel::SetResolution(TSize* aSize)
  1245 	{
  1246 	if (!aSize)
  1247 		{
  1248 		ClientPanic(RDisplayChannel::ENullArgument);
  1249 		return KErrArgument;
  1250 		}
  1251 
  1252 	TSize size;
  1253 	kumemget32(&size, aSize, sizeof(size));
  1254 	if (size.iWidth < 0 || size.iHeight < 0)
  1255 		{
  1256 		ClientPanic(RDisplayChannel::EInvalidResolution);
  1257 		return KErrArgument;
  1258 		}
  1259 	
  1260 	if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData, 
  1261 			__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
  1262 		{
  1263 		return KErrPermissionDenied;
  1264 		}
  1265 
  1266 	// Validate size. Return KErrArgument on failure.
  1267 	//Get the number of resolutions
  1268 	TInt numberOfResolutions;
  1269 	TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, NULL, iScreenNumber);
  1270 	if(r < KErrNone)
  1271 		{
  1272 		return r;
  1273 		}
  1274 	TVideoInfoV01 info;
  1275 	TPckg<TVideoInfoV01> infoPckg(info);
  1276 	for (TInt i = 0; i < numberOfResolutions; i++)
  1277 		{
  1278 		//pass info package to be filled in, also sending the config to read, and the screen within that
  1279 		Kern::HalFunction(EHalGroupDisplay, EDisplayHalSpecificScreenInfo, &i, &infoPckg, iScreenNumber);
  1280 		
  1281 		if (info.iSizeInPixels.iWidth == size.iWidth &&
  1282 				info.iSizeInPixels.iHeight == size.iHeight)
  1283 			{	//matched resolution
  1284 			iCurrentResolution = size;
  1285 			iCurrentTwips = info.iSizeInTwips;
  1286 			
  1287 			if (iCurrentResolution.iHeight > iNewBufferFormat.iSize.iHeight ||
  1288 				iCurrentResolution.iWidth > iNewBufferFormat.iSize.iWidth)
  1289 				{
  1290 				// going back to initial settings and, we hope, 
  1291 				// the buffers could still be displayed correctly, but we have no guarantee
  1292 				iCurrentBufferFormat = iInitialBufferFormat;
  1293 				}
  1294 			return KErrNone;
  1295 			}
  1296    		}
  1297 	return KErrArgument;	//if reached here, it did not match aSize to any config resolution
  1298 	}
  1299 
  1300 TInt DDisplayChannel::GetResolution(TSize* aSize)
  1301 	{
  1302 	TInt numberOfResolutions;
  1303 	TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions,
  1304 			&numberOfResolutions, NULL, iScreenNumber);
  1305 
  1306 	if (r == KErrNone)
  1307 		{
  1308 		if (numberOfResolutions > 0)
  1309 			{
  1310 		   	SafePut(aSize, &iCurrentResolution, sizeof(iCurrentResolution));
  1311 			}
  1312 		else
  1313 			{
  1314 			TSize resolution = {0,0};
  1315 		   	SafePut(aSize, &resolution, sizeof(resolution));
  1316 			}
  1317 		}
  1318 	return r;
  1319 	}
  1320 
  1321 TInt DDisplayChannel::GetTwips(TSize* aSize)
  1322 	{
  1323 	TInt numberOfResolutions;
  1324 	TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions,
  1325 			&numberOfResolutions, NULL, iScreenNumber);
  1326 
  1327 	if (r == KErrNone)
  1328 		{
  1329 		if (numberOfResolutions > 0)
  1330 			{
  1331 		   	SafePut(aSize, &iCurrentTwips, sizeof(iCurrentTwips));
  1332 			}
  1333 		else
  1334 			{
  1335 			TSize twips = {0,0};
  1336 		   	SafePut(aSize, &twips, sizeof(twips));
  1337 			}
  1338 		}
  1339 	return r;
  1340 	}
  1341 /**
  1342 Get all the pixel formats available and insert them to a descriptor
  1343 @return KErrNone if successful, otherwise a system wide error code.
  1344 */
  1345 TInt DDisplayChannel::GetPixelFormats()
  1346 	{
  1347 	TInt r;
  1348 	__ASSERT_DEBUG(iMsg->Ptr0(), Panic(EDisplayPanicNullArgument));
  1349 	__ASSERT_DEBUG(iMsg->Ptr1(), Panic(EDisplayPanicNullArgument));
  1350 	//get the number of resolutions (as above)
  1351 	TPtr8 pixelFormatDes(NULL,0);
  1352 	TInt length = ((TInt)sizeof(RDisplayChannel::TPixelFormat)) * iPixelFormatArraySize;
  1353 	pixelFormatDes.Set((TUint8*)iPixelFormatArray, length, length);
  1354 	r = Kern::ThreadDesWrite(iMsg->Client(),(TDes8*)iMsg->Ptr0(), pixelFormatDes, 0, iMsg->Client());
  1355 	if (r == KErrNone)
  1356 		{
  1357 		Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(), length);
  1358 		SafePut(iMsg->Ptr1(), &iPixelFormatArraySize, sizeof(iPixelFormatArraySize));
  1359 		}
  1360 	return r;
  1361 	}
  1362 
  1363 
  1364 TInt DDisplayChannel::SetBufferFormat(RDisplayChannel::TBufferFormat* aBufferFormat)
  1365 	{
  1366 	if (!aBufferFormat)
  1367 		{
  1368 		ClientPanic(RDisplayChannel::ENullArgument);
  1369 		return KErrArgument;
  1370 		}
  1371 
  1372 	if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData, 
  1373 			__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
  1374 		{
  1375 		return KErrPermissionDenied;
  1376 		}
  1377 
  1378 	RDisplayChannel::TBufferFormat bufferFormat;
  1379 	kumemget32(&bufferFormat, aBufferFormat, sizeof(RDisplayChannel::TBufferFormat));
  1380 	
  1381 	// Validate Size
  1382 	if (iCurrentResolution.iHeight > bufferFormat.iSize.iHeight ||
  1383 		iCurrentResolution.iWidth > bufferFormat.iSize.iWidth ||
  1384 		bufferFormat.iSize.iHeight > KMaxBufferSizeHeightAndWidth ||
  1385 		bufferFormat.iSize.iWidth > KMaxBufferSizeHeightAndWidth)
  1386 		{
  1387 		//return error on failure
  1388 		return KErrArgument;
  1389 		}
  1390 	
  1391 	// check we received one of the supported formats.
  1392 	for (TInt i = 0; i < iPixelFormatArraySize; i++)
  1393 		{
  1394 		if (bufferFormat.iPixelFormat == iPixelFormatArray[i])
  1395 			{
  1396 			// the arguments are all validated at this point, update the current format
  1397 			iCurrentBufferFormat = bufferFormat;
  1398 			return KErrNone;
  1399 			}
  1400 		}
  1401 	
  1402 		//return error on failure
  1403 		return KErrArgument;
  1404 	}
  1405 
  1406 TInt DDisplayChannel::ValidateBufferFormat(const RDisplayChannel::TBufferFormat& aBufferFormat,
  1407 									 	   const RDisplayChannel::TResolution& aResolution)
  1408 	{
  1409 	// Validate the size reported in buffer format against the given resolution
  1410 	if (aResolution.iPixelSize.iHeight > aBufferFormat.iSize.iHeight ||
  1411 		aResolution.iPixelSize.iWidth > aBufferFormat.iSize.iWidth ||
  1412 		aBufferFormat.iSize.iHeight > KMaxBufferSizeHeightAndWidth ||
  1413 		aBufferFormat.iSize.iWidth > KMaxBufferSizeHeightAndWidth)
  1414 		{
  1415 		//return error on failure
  1416 		return KErrArgument;
  1417 		}
  1418 	
  1419 	// check we received one of the supported formats.
  1420 	for (TInt i = 0; i < iPixelFormatArraySize; i++)
  1421 		{
  1422 		if (aBufferFormat.iPixelFormat == iPixelFormatArray[i])
  1423 			{
  1424 			return KErrNone;
  1425 			}
  1426 		}
  1427 		
  1428 	return KErrArgument;
  1429 	}
  1430 
  1431 TInt DDisplayChannel::NextPlaneOffset(RDisplayChannel::TBufferFormat* aBufferFormat, 
  1432 		            				 RDisplayChannel::TBufferFormatContext* aContext)
  1433 	{
  1434 	if (!aBufferFormat)
  1435 		{
  1436 		ClientPanic(RDisplayChannel::ENullArgument);
  1437 		return KErrArgument;
  1438 		}
  1439 
  1440 	if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData, 
  1441 			__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
  1442 		{
  1443 		return KErrPermissionDenied;
  1444 		}
  1445 
  1446 	RDisplayChannel::TBufferFormat bufferFormat;
  1447 	kumemget32(&bufferFormat, aBufferFormat, sizeof(bufferFormat));
  1448 	
  1449 	RDisplayChannel::TResolution resolution;
  1450 	RDisplayChannel::TDisplayRotation rotation;
  1451 	
  1452 	if (aContext)
  1453 		{
  1454 		RDisplayChannel::TBufferFormatContext context;
  1455 		kumemget32(&context, aContext, sizeof(context));
  1456 		resolution = context.iResolution;
  1457 		rotation = context.iRotation;
  1458 		}
  1459 	else
  1460 		{
  1461 		resolution.iPixelSize = iCurrentResolution;
  1462 		rotation = iCurrentRotation;
  1463 		}
  1464 	
  1465 		TInt err = ValidateBufferFormat(bufferFormat, resolution);
  1466 		
  1467 		if (err != KErrNone)
  1468 			{
  1469 			return err;
  1470 			}
  1471 		//it assumes no planar pixel formats are supported by this driver implementation
  1472 		return 0;
  1473 	}
  1474 
  1475 TInt DDisplayChannel::NextLineOffset(RDisplayChannel::TBufferFormat* aBufferFormat, 
  1476 		            				 RDisplayChannel::TBufferFormatContext* aContext)
  1477 	{
  1478 	if (!aBufferFormat)
  1479 		{
  1480 		ClientPanic(RDisplayChannel::ENullArgument);
  1481 		return KErrArgument;
  1482 		}
  1483 
  1484 	if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData, 
  1485 			__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
  1486 		{
  1487 		return KErrPermissionDenied;
  1488 		}
  1489 
  1490 	RDisplayChannel::TBufferFormat bufferFormat;
  1491 	kumemget32(&bufferFormat, aBufferFormat, sizeof(bufferFormat));
  1492 	
  1493 	RDisplayChannel::TResolution resolution;
  1494 	RDisplayChannel::TDisplayRotation rotation;
  1495 	
  1496 	if (aContext)
  1497 		{
  1498 		RDisplayChannel::TBufferFormatContext context;
  1499 		kumemget32(&context, aContext, sizeof(context));
  1500 		resolution = context.iResolution;
  1501 		rotation = context.iRotation;
  1502 		}
  1503 	else
  1504 		{
  1505 		resolution.iPixelSize = iCurrentResolution;
  1506 		rotation = iCurrentRotation;
  1507 		}
  1508 
  1509 	TInt err = ValidateBufferFormat(bufferFormat, resolution);
  1510 	
  1511 	if (err != KErrNone)
  1512 		{
  1513 		return err;
  1514 		}
  1515 	
  1516 	TInt bpp = 0;
  1517 	//validating the pixel format and getting the pixel size in bits
  1518 	switch (bufferFormat.iPixelFormat)
  1519 		{
  1520 		case EUidPixelFormatXRGB_4444:	// RGB4444
  1521 		case EUidPixelFormatARGB_4444:
  1522 		case EUidPixelFormatRGB_565:	// RGB565
  1523 			bpp = 16;
  1524 			break;
  1525 		case EUidPixelFormatXRGB_8888:	// Really 32bpp, but top 8 unused
  1526 		case EUidPixelFormatARGB_8888:
  1527 		case EUidPixelFormatARGB_8888_PRE:
  1528 			bpp = 32;
  1529 			break;
  1530 		default:
  1531 			// We got an error, it seems. The pixel format is not supported 
  1532 			// Let's panic because the pixel format has just been validated
  1533 			Panic(EDisplayPanicInvalidBitDepth);
  1534 			break;
  1535 		}
  1536 		
  1537 	TInt widthInPixel = 0;	// pixels
  1538 		
  1539 	// let's take in consideration the given rotation
  1540 	switch (rotation)
  1541 		{
  1542 		case RDisplayChannel::ERotation90CW:
  1543 		case RDisplayChannel::ERotation270CW:
  1544 			widthInPixel = bufferFormat.iSize.iHeight;
  1545 			break;
  1546 		default:	// Normal
  1547 			widthInPixel = bufferFormat.iSize.iWidth;
  1548 			break;
  1549 		}
  1550 	
  1551 	// we have to round up to 32 bits word. This is a Ms Windows limitation 
  1552 	TInt stride = _ALIGN_UP((widthInPixel * bpp), 32) >> 3;
  1553 	return stride;
  1554 	}