1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/boardsupport/emulator/emulatorbsp/specific/display_chan.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1554 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +
1.20 +#include <kernel/kern_priv.h>
1.21 +#include <kernel/kernel.h>
1.22 +#include <winsdef.h>
1.23 +#include <emulator.h>
1.24 +#include <pixelformats.h>
1.25 +#include "gui.h"
1.26 +#include "display_chan.h"
1.27 +
1.28 +#define WIN32_LEAN_AND_MEAN
1.29 +#pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
1.30 +#include <windows.h>
1.31 +#pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
1.32 +
1.33 +#ifndef DD_TRACE
1.34 +#ifdef DD_TRACE_ENABLED
1.35 +#define DD_TRACE(X) X
1.36 +#else
1.37 +#define DD_TRACE(X)
1.38 +#endif
1.39 +#endif
1.40 +
1.41 +
1.42 +
1.43 +DDisplayChannel::DDisplayChannel() :
1.44 + iVSync(&DDisplayChannel::VSyncTimerFn, this),
1.45 + iVSyncDfc(&DDisplayChannel::VSyncDfcFn, this, Kern::DfcQue0(), KDfcPriority),
1.46 + iPostedBuffer((TUint)KBufferNotSet),
1.47 + iGetBuffer((TUint)KFirstCompositionBuffer),
1.48 + iDisplayStateSpinner(0),
1.49 + iVersion(KDisplayChMajorVersionNumber,
1.50 + KDisplayChMinorVersionNumber,
1.51 + KDisplayChBuildVersionNumber)
1.52 + {
1.53 + DD_TRACE(Kern::Printf("DDisplayChannel Creation");)
1.54 + }
1.55 +
1.56 +
1.57 +DDisplayChannel::~DDisplayChannel()
1.58 + {
1.59 + DD_TRACE(Kern::Printf("DDisplayChannel Destruction");)
1.60 + //clean up.
1.61 +
1.62 + NKern::ThreadEnterCS();
1.63 + Kern::Free(iBuffer);
1.64 + NKern::ThreadLeaveCS();
1.65 +
1.66 + }
1.67 +
1.68 +
1.69 +/**
1.70 + Second stage constructor called by the kernel's device driver framework.
1.71 + This is called in the context of the user thread (client) which requested the creation of a Logical Channel
1.72 + (E.g. through a call to RBusLogicalChannel::DoCreate)
1.73 + The thread is in a critical section.
1.74 +
1.75 + @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
1.76 + @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
1.77 + @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
1.78 +
1.79 + @return KErrNone if successful, otherwise one of the other system wide error codes.
1.80 +*/
1.81 +TInt DDisplayChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& aVer)
1.82 + {
1.83 + // Check version
1.84 + if (!Kern::QueryVersionSupported(iDevice->iVersion, aVer))
1.85 + {
1.86 + return KErrNotSupported;
1.87 + }
1.88 +
1.89 + iScreenNumber = aUnit; /*aUnit?*/
1.90 + SetDfcQ(Kern::DfcQue0());
1.91 + iMsgQ.Receive();
1.92 +
1.93 + // Ask the GUI code to initialize the rest of the object.
1.94 + return Kern::HalFunction(EHalGroupEmulator, EEmulatorHalSetDisplayChannel,
1.95 + (TAny*)iScreenNumber, this);
1.96 + }
1.97 +
1.98 +
1.99 +void DDisplayChannel::ValidateSpecificInfo(TInt aBytesPerPixel, RDisplayChannel::TOrientationSpecificInfo& aInfo)
1.100 + {
1.101 + __ASSERT_DEBUG(aInfo.iWidth > 0 && aInfo.iHeight > 0, Panic(EDisplayPanicInvalidDimensions));
1.102 + __ASSERT_DEBUG(aInfo.iOffsetBetweenLines > 0, Panic(EDisplayPanicInvalidStride));
1.103 + __ASSERT_DEBUG(aInfo.iWidth * aBytesPerPixel <= (TUint)aInfo.iOffsetBetweenLines, Panic(EDisplayPanicInvalidStride));
1.104 +
1.105 + //this is just to stop compiler complaining..
1.106 + (TAny)aBytesPerPixel;
1.107 + (TAny)aInfo;
1.108 + }
1.109 +
1.110 +/**
1.111 +Finish creating the display channel object.
1.112 +
1.113 +@param aInfo Display description object
1.114 +@param aRotation Initial rotation
1.115 +@param aHwnd Associated window handle
1.116 +@param aFrameBuffers Array of one or more pointers to frame buffers
1.117 +@param aResolution Initial resolution
1.118 +@param aTwips Size in twips
1.119 +@return KErrNone if successful, or a system-wide error otherwise.
1.120 +*/
1.121 +TInt DDisplayChannel::Initialize(RDisplayChannel::TDisplayInfo& aInfo,
1.122 + RDisplayChannel::TDisplayRotation aRotation,
1.123 + HWND aHwnd, RPointerArray<TAny>& aFrameBuffers,
1.124 + RPointerArray<TBufferAddressA>& aChunks,
1.125 + TScreenBuffer& aDsaBuffer,
1.126 + TSize aResolution,
1.127 + TSize aTwips,
1.128 + const RDisplayChannel::TPixelFormat aPixelFormatArray[],
1.129 + const TInt aPixelFormatArraySize,
1.130 + const RDisplayChannel::TBufferFormat& aBufferFormat)
1.131 +
1.132 + {
1.133 + __ASSERT_DEBUG(aInfo.iBitsPerPixel >= 12 && aInfo.iBitsPerPixel <= 32, Panic(EDisplayPanicInvalidBitDepth));
1.134 + __ASSERT_DEBUG(aInfo.iRefreshRateHz > 0, Panic(EDisplayPanicInvalidRefreshRate));
1.135 + __ASSERT_DEBUG(aInfo.iAvailableRotations & aRotation, Panic(EDisplayPanicInvalidRotation));
1.136 + __ASSERT_DEBUG(aInfo.iNormal.iWidth == aInfo.iFlipped.iHeight, Panic(EDisplayPanicInvalidDimensions));
1.137 + __ASSERT_DEBUG(aInfo.iNormal.iHeight == aInfo.iFlipped.iWidth, Panic(EDisplayPanicInvalidDimensions));
1.138 + __ASSERT_DEBUG(aRotation == RDisplayChannel::ERotationNormal ||
1.139 + aRotation == RDisplayChannel::ERotation90CW ||
1.140 + aRotation == RDisplayChannel::ERotation180 ||
1.141 + aRotation == RDisplayChannel::ERotation270CW, Panic(EDisplayPanicInvalidRotation));
1.142 + __ASSERT_DEBUG(aFrameBuffers.Count() > 0, Panic(EDisplayPanicInvalidFrameBuffers));
1.143 + __ASSERT_DEBUG(aHwnd, Panic(EDisplayPanicInvalidWindowHandle));
1.144 +
1.145 + ValidateSpecificInfo((aInfo.iBitsPerPixel > 16) ? 4 : 2, aInfo.iNormal);
1.146 + ValidateSpecificInfo((aInfo.iBitsPerPixel > 16) ? 4 : 2, aInfo.iFlipped);
1.147 +
1.148 + // aFrameBuffers includes the legacy buffer at index 0.
1.149 + iNumCompositionBuffers = aFrameBuffers.Count() - 1;
1.150 + iTotalBuffers = KFirstCompositionBuffer + iNumCompositionBuffers;
1.151 + iBuffer = (TBufferInfo*)Kern::AllocZ(iTotalBuffers * sizeof(TBufferInfo));
1.152 + iChunks = (TBufferAddressA*)Kern::AllocZ(iTotalBuffers * sizeof(TBufferAddressA));
1.153 + if (!iBuffer)
1.154 + {
1.155 + return KErrNoMemory;
1.156 + }
1.157 +
1.158 + aInfo.iNumCompositionBuffers = iNumCompositionBuffers;
1.159 + for (TUint index = 0; index < iNumCompositionBuffers; index++)
1.160 + {
1.161 + iBuffer[index + KFirstCompositionBuffer].iAddress = aFrameBuffers[index + 1];
1.162 + iChunks[index + KFirstCompositionBuffer].iChunk = aChunks[index + 1]->iChunk;
1.163 + }
1.164 +
1.165 + iChannelInfo = aInfo;
1.166 +
1.167 + iDisplayRotation = iCurrentRotation = aRotation;
1.168 + iDisplayResolution = iCurrentResolution = aResolution;
1.169 + iCurrentTwips = aTwips;
1.170 + iHwnd = aHwnd;
1.171 +
1.172 + // Ensure the VSync DFC is on the same queue as the message handling.
1.173 + iVSyncTicks = NKern::TimerTicks(1000 / aInfo.iRefreshRateHz);
1.174 + iVSync.OneShot(iVSyncTicks);
1.175 +
1.176 + if (aDsaBuffer.iMemChunks.Count() != 0)
1.177 + {
1.178 + iBuffer[KLegacyBuffer].iAddress = aDsaBuffer.iFrameBuffers[0];
1.179 + }
1.180 + else
1.181 + {
1.182 + iBuffer[KLegacyBuffer].iAddress = NULL;
1.183 + }
1.184 +
1.185 + iPixelFormatArray = aPixelFormatArray;
1.186 + iPixelFormatArraySize = aPixelFormatArraySize;
1.187 +
1.188 + // copy the initial buffer format
1.189 + iInitialBufferFormat = aBufferFormat;
1.190 + iDisplayBufferFormat = iInitialBufferFormat;
1.191 + iCurrentBufferFormat = iDisplayBufferFormat;
1.192 + return KErrNone;
1.193 + }
1.194 +
1.195 +
1.196 +/**
1.197 +Set the address of the legacy buffer.
1.198 +
1.199 +@param aAddress Pointer to the legacy buffer.
1.200 +*/
1.201 +void DDisplayChannel::SetLegacyBuffer(void *aAddress)
1.202 + {
1.203 + iBuffer[KLegacyBuffer].iAddress = aAddress;
1.204 + }
1.205 +
1.206 +
1.207 +
1.208 +/**
1.209 +Handle a message on this display for the logical channel.
1.210 +
1.211 +@param aMsg The message to process. The iValue member of this distinguishes the
1.212 + message type:
1.213 + iValue == ECloseMsg, channel close message
1.214 + iValue == KMaxTInt, a 'DoCancel' message
1.215 + iValue >= 0, a 'DoControl' message with function number equal to iValue
1.216 + iValue < 0, a 'DoRequest' message with function number equal to ~iValue
1.217 +*/
1.218 +void DDisplayChannel::HandleMsg(TMessageBase* aMsg)
1.219 + {
1.220 + iMsg = (TThreadMessage*)aMsg;
1.221 + TInt id = iMsg->iValue;
1.222 + TInt r = KErrNone;
1.223 +
1.224 + if (id == (TInt)ECloseMsg)
1.225 + {
1.226 + iVSync.Cancel();
1.227 + iWaitForPostRequest.Complete(KErrCancel);
1.228 + iWaitForDisplayConnect.Complete(KErrCancel);
1.229 + if (iBuffer)
1.230 + {
1.231 + // Unhook display channel from the GUI code if initialized.
1.232 + if (iBuffer[KLegacyBuffer].iAddress)
1.233 + {
1.234 + Kern::HalFunction(EHalGroupEmulator, EEmulatorHalSetDisplayChannel,
1.235 + (TAny*)iScreenNumber, NULL);
1.236 + PostMessage(iHwnd, WMU_SET_DISPLAY_BUFFER, 0, 0);
1.237 + InvalidateRect(iHwnd, NULL, FALSE);
1.238 + }
1.239 +
1.240 + RDisplayChannel::TBufferId index = iTotalBuffers;
1.241 +
1.242 + while (index-- > 0)
1.243 + {
1.244 + iBuffer[index].iRequest.Complete(KErrCancel);
1.245 +
1.246 + if (IsUserBuffer(index))
1.247 + {
1.248 + // Close chunk
1.249 + if (iBuffer[index].iChunk)
1.250 + {
1.251 + NKern::ThreadEnterCS();
1.252 + Kern::ChunkClose(iBuffer[index].iChunk);
1.253 + NKern::ThreadLeaveCS();
1.254 + }
1.255 + }
1.256 + }
1.257 +
1.258 + }
1.259 + iMsg->Complete(KErrNone, EFalse);
1.260 + return;
1.261 + }
1.262 +
1.263 + if (id < 0)
1.264 + {
1.265 + DoRequest(~id);
1.266 + r = KErrNone;
1.267 + }
1.268 + else
1.269 + {
1.270 + r = (id == KMaxTInt) ? DoCancel(iMsg->Int0()) : DoControl(id);
1.271 + }
1.272 +
1.273 + iMsg->Complete(r, (id != ECloseMsg));
1.274 + }
1.275 +
1.276 +
1.277 +/**
1.278 +Process synchronous 'control' requests. Parameters are in the first two
1.279 +arguments of iMsg.
1.280 +*/
1.281 +TInt DDisplayChannel::DoControl(TInt aFunction)
1.282 + {
1.283 + DD_TRACE(Kern::Printf(">DDisplayChannel::DoControl fn=%d\n", aFunction);)
1.284 +
1.285 + TInt r = KErrNotSupported;
1.286 + TPckgBuf<RDisplayChannel::TDisplayInfo> pkg(iChannelInfo);
1.287 + switch(aFunction)
1.288 + {
1.289 + case RDisplayChannel::ECtrlGetDisplayInfo:
1.290 + // a1: TDisplayInfo* info [out]
1.291 + Kern::KUDesPut(*(TDes8*)iMsg->Ptr0(), pkg); ///*&iChannelInfo*/);
1.292 + r = KErrNone;
1.293 + break;
1.294 +
1.295 + case RDisplayChannel::ECtrlOpen:
1.296 + // Everything is done in Construct
1.297 + r = KErrNone;
1.298 + break;
1.299 +
1.300 + case RDisplayChannel::ECtrlClose:
1.301 + // Nothing to do?
1.302 + r = KErrNone;
1.303 + break;
1.304 +
1.305 + case RDisplayChannel::ECtrlPostCompositionBuffer:
1.306 + // a1: const TRegionFix<KMaxRectangles>* region [in]
1.307 + // a2: TPostCount* post count [out]
1.308 + r = PostCompositionBuffer(iMsg->Ptr0(), (RDisplayChannel::TPostCount*)iMsg->Ptr1());
1.309 + break;
1.310 +
1.311 + case RDisplayChannel::ECtrlPostLegacyBuffer:
1.312 + // a1: const TRegionFix<KMaxRectangles>* region [in]
1.313 + // a2: TPostCount* post count [out]
1.314 + r = PostLegacyBuffer(iMsg->Ptr0(), (RDisplayChannel::TPostCount*)iMsg->Ptr1());
1.315 + break;
1.316 +
1.317 + case RDisplayChannel::ECtrlRegisterUserBuffer:
1.318 + // a1: { TInt Chunk handle, TInt offset }* [in]
1.319 + // a2: TInt* buffer ID [out]
1.320 + {
1.321 + __ASSERT_DEBUG(iMsg->Ptr0(), Panic(EDisplayPanicNullArgument));
1.322 + TInt arg[2];
1.323 + kumemget(arg, iMsg->Ptr0(), sizeof(arg));
1.324 + r = RegisterUserBuffer(arg[0], arg[1], (RDisplayChannel::TBufferId*)iMsg->Ptr1());
1.325 + }
1.326 + break;
1.327 +
1.328 + case RDisplayChannel::ECtrlDeregisterUserBuffer:
1.329 + // a1: TBufferId* buffer ID [in]
1.330 + r = DeregisterUserBuffer((RDisplayChannel::TBufferId*)iMsg->Ptr0());
1.331 + break;
1.332 +
1.333 + case RDisplayChannel::ECtrlSetRotation:
1.334 + // a1: TDisplayRotation* new rotation [in]
1.335 + // a2: TBool* display config has changed [out]
1.336 + r = SetRotation((RDisplayChannel::TDisplayRotation*)iMsg->Ptr0(), (TBool*)iMsg->Ptr1());
1.337 + break;
1.338 +
1.339 + case RDisplayChannel::ECtrlCurrentRotation:
1.340 + // a1: TDisplayRotation* current rotation [out]
1.341 + r = SafePut(iMsg->Ptr0(), &iCurrentRotation, sizeof(iCurrentRotation));
1.342 + break;
1.343 +
1.344 + case ECloseMsg:
1.345 + r = KErrNone;
1.346 + break;
1.347 +
1.348 + case RDisplayChannel::ECtrlGetCompositionBufferInfo:
1.349 + {
1.350 + TInt arg[2];
1.351 + TInt index = *((TInt*)(iMsg->Ptr0()));
1.352 + r = Kern::MakeHandleAndOpen(iMsg->Client(), iChunks[index + KFirstCompositionBuffer].iChunk);
1.353 + if(r >= 0)
1.354 + {
1.355 + arg[0] = r;
1.356 + arg[1] = 0;
1.357 + SafePut(iMsg->Ptr1(),&arg,(sizeof(TInt)*2));
1.358 + r = KErrNone;
1.359 + }
1.360 + }
1.361 + break;
1.362 + // added to v1.0
1.363 + case RDisplayChannel::ECtrlVersion:
1.364 + r = SafePut(iMsg->Ptr0(), &iVersion, sizeof(iVersion));
1.365 + break;
1.366 + //v1_1
1.367 + case RDisplayChannel::ECtrlNumberOfResolutions:
1.368 + {
1.369 + r = NumberOfResolutions();
1.370 + }
1.371 + break;
1.372 + case RDisplayChannel::ECtrlGetResolutions:
1.373 + {
1.374 + r = GetResolutions();
1.375 + if(r == KErrCorrupt) //Resolution list changed during GetResolutions
1.376 + {//second go
1.377 + r = GetResolutions();
1.378 + }
1.379 + }
1.380 + break;
1.381 + case RDisplayChannel::ECtrlSetResolution:
1.382 + {
1.383 + r = SetResolution((TSize*)iMsg->Ptr0());
1.384 + }
1.385 + break;
1.386 + case RDisplayChannel::ECtrlGetResolution:
1.387 + {
1.388 + r = GetResolution((TSize*)iMsg->Ptr0());
1.389 + }
1.390 + break;
1.391 + case RDisplayChannel::ECtrlGetTwips:
1.392 + {
1.393 + r = GetTwips((TSize*)iMsg->Ptr0());
1.394 + }
1.395 + break;
1.396 + case RDisplayChannel::ECtrlNumberOfPixelFormats:
1.397 + r = iPixelFormatArraySize;
1.398 + break;
1.399 + case RDisplayChannel::ECtrlGetPixelFormats:
1.400 + r = GetPixelFormats();
1.401 + break;
1.402 + case RDisplayChannel::ECtrlSetBufferFormat:
1.403 + r = SetBufferFormat((RDisplayChannel::TBufferFormat*)iMsg->Ptr0());
1.404 + break;
1.405 + case RDisplayChannel::ECtrlGetBufferFormat:
1.406 + r = SafePut(iMsg->Ptr0(), &iCurrentBufferFormat, sizeof(iCurrentBufferFormat));
1.407 + break;
1.408 + case RDisplayChannel::ECtrlNextPlaneOffset:
1.409 + // we support, for moment only packed pixel formats
1.410 + r = NextPlaneOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(), NULL);
1.411 + break;
1.412 + case RDisplayChannel::ECtrlNextLineOffset:
1.413 + // use the internal current resolution and current rotation
1.414 + r = NextLineOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(), NULL);
1.415 + break;
1.416 + case RDisplayChannel::ECtrlNextPlaneOffsetExtended:
1.417 + // we support, for moment only packed pixel formats
1.418 + r = NextPlaneOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(),
1.419 + (RDisplayChannel::TBufferFormatContext*)iMsg->Ptr1());
1.420 + break;
1.421 + case RDisplayChannel::ECtrlNextLineOffsetExtended:
1.422 + r = NextLineOffset((RDisplayChannel::TBufferFormat*)iMsg->Ptr0(),
1.423 + (RDisplayChannel::TBufferFormatContext*)iMsg->Ptr1());
1.424 + break;
1.425 + }
1.426 + DD_TRACE(Kern::Printf("<DDisplayChannel::DoControl result=%d\n",r);)
1.427 + return r;
1.428 + }
1.429 +
1.430 +TInt DDisplayChannel::GetIndexForSize(const TSize& aSize,TInt& aSpinnerOut)
1.431 + {
1.432 + TInt numberOfResolutions = 0;
1.433 + TInt spinner1 = 0;
1.434 + TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, &spinner1, iScreenNumber);
1.435 + if(r < KErrNone)
1.436 + return r;
1.437 + TVideoInfoV01 info;
1.438 + TPckg<TVideoInfoV01> infoPckg(info);
1.439 +
1.440 + for (TInt res=0;res<numberOfResolutions;res++)
1.441 + {
1.442 + //pass info package to be filled in, also sending the config to read, and the screen within that
1.443 + Kern::HalFunction(EHalGroupDisplay, EDisplayHalSpecificScreenInfo, (TAny*)&res, (TAny*)&infoPckg, iScreenNumber);
1.444 + if (info.iSizeInPixels.iWidth==aSize.iWidth && info.iSizeInPixels.iHeight==aSize.iHeight)
1.445 + {
1.446 + r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, &aSpinnerOut, iScreenNumber);
1.447 + if(r < KErrNone)
1.448 + return r;
1.449 + if (aSpinnerOut!=spinner1)
1.450 + {
1.451 + return KErrCorrupt;
1.452 + }
1.453 + else
1.454 + {
1.455 + return res;
1.456 + }
1.457 + }
1.458 + }
1.459 + return KErrArgument;
1.460 + }
1.461 +
1.462 +/**
1.463 +Process asynchronous requests. TRequestStatus is at iMsg->Ptr0(), and the other
1.464 +two parameters are in iMsg->Ptr1() and iMsg->Ptr2().
1.465 +*/
1.466 +void DDisplayChannel::DoRequest(TInt aFunction)
1.467 + {
1.468 + DD_TRACE(Kern::Printf(">DDisplayChannel::DoRequest fn=%d\n", aFunction);)
1.469 +
1.470 + TInt r = KErrNotSupported;
1.471 +
1.472 + switch(aFunction)
1.473 + {
1.474 + case RDisplayChannel::EReqGetCompositionBuffer:
1.475 + // a1: TAny** buffer address [out]
1.476 + r = GetCompositionBuffer(static_cast<TAny**>(iMsg->Ptr1()));
1.477 + break;
1.478 +
1.479 + case RDisplayChannel::EReqPostUserBuffer:
1.480 + // a1: { TBufferId* buffer ID, const TRegionFix<KMaxRectangles>* region }* [in]
1.481 + // a2: TPostCount* post count [out]
1.482 + {
1.483 + TAny* arg[2];
1.484 + __ASSERT_DEBUG(iMsg->Ptr1(), Panic(EDisplayPanicNullArgument));
1.485 + kumemget(arg, iMsg->Ptr1(), sizeof(arg));
1.486 + r = PostUserBuffer(reinterpret_cast<RDisplayChannel::TBufferId*>(arg[0]), arg[1],
1.487 + reinterpret_cast<RDisplayChannel::TPostCount*>(iMsg->Ptr2()));
1.488 + }
1.489 + break;
1.490 +
1.491 + case RDisplayChannel::EReqWaitForPost:
1.492 + // a1: TInt* post to wait for [in]
1.493 + r = WaitForPost(static_cast<RDisplayChannel::TPostCount*>(iMsg->Ptr1()));
1.494 + break;
1.495 + //v1_1
1.496 + case RDisplayChannel::EReqWaitForDisplayConnect:
1.497 + r = WaitForDisplayConnect();
1.498 + break;
1.499 + }
1.500 +
1.501 + DD_TRACE(Kern::Printf("<DDisplayChannel::DoRequest result=%d\n",r);)
1.502 +
1.503 + if (r != KRequestPending)
1.504 + {
1.505 + TRequestStatus* status = reinterpret_cast<TRequestStatus*>(iMsg->Ptr0());
1.506 + Kern::RequestComplete(iMsg->Client(), status, r);
1.507 + }
1.508 + }
1.509 +
1.510 +
1.511 +/**
1.512 +Process asynchronous request cancellations
1.513 +*/
1.514 +TInt DDisplayChannel::DoCancel(TInt aRequestMask)
1.515 + {
1.516 + DD_TRACE(Kern::Printf(">DDisplayChannel::DoCancel mask=%x\n", aRequestMask);)
1.517 +
1.518 + if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelGetCompositionBuffer))
1.519 + {
1.520 + if (IsCompositionBuffer(iGetBuffer))
1.521 + {
1.522 + iBuffer[iGetBuffer].iRequest.Complete(KErrCancel);
1.523 + }
1.524 + }
1.525 +
1.526 + if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelPostUserBuffer))
1.527 + {
1.528 + if (IsUserBuffer(iPostedBuffer))
1.529 + {
1.530 + iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
1.531 + }
1.532 + }
1.533 +
1.534 + if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelWaitForPost))
1.535 + {
1.536 + iWaitForPostRequest.Complete(KErrCancel);
1.537 + }
1.538 + if (aRequestMask & (1 << RDisplayChannel::ECtrlCancelWaitForDisplayConnect))
1.539 + {
1.540 + iWaitForDisplayConnect.Complete(KErrCancel);
1.541 + }
1.542 +
1.543 + DD_TRACE(Kern::Printf("<DDisplayChannel::DoCancel\n",r);)
1.544 + return KErrNone;
1.545 + }
1.546 +
1.547 +
1.548 +/**
1.549 +Get the number of resolutions on this screen
1.550 +@return Number of resolutions if successful, otherwise a system wide error code.
1.551 +*/
1.552 +TInt DDisplayChannel::NumberOfResolutions()
1.553 + {
1.554 + TInt numberOfResolutions = 0;
1.555 + TInt error = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, NULL, iScreenNumber);
1.556 + if (error != KErrNone)
1.557 + {
1.558 + return error;
1.559 + }
1.560 + return numberOfResolutions;
1.561 + }
1.562 +
1.563 +
1.564 +/**
1.565 +Safely write from kernel to user memory.
1.566 +@param aDst Pointer to destination, user memory.
1.567 +@param aSrc Pointer to source, kernel memory.
1.568 +@param aBytes Number of bytes to write.
1.569 +@return KErrNone if successful, KErrArgument if either pointer is NULL.
1.570 +*/
1.571 +TInt DDisplayChannel::SafePut(TAny* aDst, TAny* aSrc, TInt aBytes)
1.572 + {
1.573 + if (!aDst || !aSrc)
1.574 + {
1.575 + return KErrArgument;
1.576 + }
1.577 +
1.578 + kumemput(aDst, aSrc, aBytes);
1.579 + return KErrNone;
1.580 + }
1.581 +
1.582 +
1.583 +/**
1.584 +Driver panic.
1.585 +@param aPanic The cause of the panic.
1.586 +*/
1.587 +void DDisplayChannel::Panic(TDisplayPanic aPanic)
1.588 + {
1.589 + Kern::Fault("DISPLAY", aPanic);
1.590 + }
1.591 +
1.592 +
1.593 +/**
1.594 +Client panic.
1.595 +@param aPanic The cause of the panic.
1.596 +*/
1.597 +void DDisplayChannel::ClientPanic(RDisplayChannel::TPanic aPanic)
1.598 + {
1.599 + _LIT(KLitDisplayChannel, "DISPLAYCHANNEL");
1.600 + Kern::ThreadKill(iClient, EExitPanic, aPanic, KLitDisplayChannel);
1.601 + }
1.602 +
1.603 +
1.604 +/**
1.605 +VSync is emulated by using a nanokernel timer to call this function at the
1.606 +frame rate.
1.607 +*/
1.608 +void DDisplayChannel::VSyncTimerFn(TAny* aDisplayChannel)
1.609 + {
1.610 + reinterpret_cast<DDisplayChannel*>(aDisplayChannel)->DoVSyncTimer();
1.611 + }
1.612 +
1.613 +/**
1.614 +Instance function called on the timer thread. Queues the VSyncDfc to run on its
1.615 +thread.
1.616 +*/
1.617 +void DDisplayChannel::DoVSyncTimer(void)
1.618 + {
1.619 + iVSyncDfc.Add();
1.620 + iVSync.Again(iVSyncTicks);
1.621 + }
1.622 +
1.623 +
1.624 +/**
1.625 +DFC function to post the current buffer to the display.
1.626 +@param aDisplayImpl The display object to be posted.
1.627 +*/
1.628 +void DDisplayChannel::VSyncDfcFn(TAny* aDisplayChannel)
1.629 + {
1.630 + reinterpret_cast<DDisplayChannel*>(aDisplayChannel)->DoVSync();
1.631 + }
1.632 +
1.633 +
1.634 +/**
1.635 +Post the current buffer to the display. Signal waiting threads under various
1.636 +conditions. This is run off the same DFC queue as message handling, so there is
1.637 +no need to protect the fields.
1.638 +*/
1.639 +void DDisplayChannel::DoVSync(void)
1.640 + {
1.641 + if(iWaitForDisplayConnect.iStatus)
1.642 + {
1.643 + TInt currentSpinner;
1.644 + Kern::HalFunction(EHalGroupDisplay, EDisplayHalGetStateSpinner, ¤tSpinner, NULL, iScreenNumber);
1.645 + //display state changed
1.646 + if(currentSpinner != iDisplayStateSpinner)
1.647 + iWaitForDisplayConnect.Complete(KErrNone);
1.648 + }
1.649 +
1.650 + if (IsValidBuffer(iPostedBuffer))
1.651 + {
1.652 + // Complete any outstanding request for the buffer which was displayed.
1.653 + // This either signifies the user or composition buffer becoming
1.654 + // available
1.655 + if (iDisplayBuffer != iPostedBuffer)
1.656 + {
1.657 + iBuffer[iDisplayBuffer].iRequest.Complete(KErrNone);
1.658 + }
1.659 +
1.660 + iDisplayBuffer = (RDisplayChannel::TBufferId)iPostedBuffer;
1.661 + iPostedBuffer = (RDisplayChannel::TBufferId)KBufferNotSet;
1.662 +
1.663 + // Update the pixel pointer used when painting the client window
1.664 + PostMessage(iHwnd, WMU_SET_DISPLAY_BUFFER, 0,
1.665 + (LPARAM)iBuffer[iDisplayBuffer].iAddress);
1.666 +
1.667 + // check if the buffer format is modified
1.668 + if ((iDisplayBufferFormat.iSize.iHeight != iNewBufferFormat.iSize.iHeight) ||
1.669 + (iDisplayBufferFormat.iSize.iWidth != iNewBufferFormat.iSize.iWidth) ||
1.670 + (iDisplayBufferFormat.iPixelFormat != iNewBufferFormat.iPixelFormat))
1.671 + {
1.672 + // We post in one messages everything, but we got to pack the size
1.673 + // speculate that the maximum width and height can be represented in 16 bit
1.674 + TUint aggregateSize = ((TUint)iNewBufferFormat.iSize.iHeight << 16) & 0xffff0000;
1.675 + aggregateSize += (TUint)iNewBufferFormat.iSize.iWidth & 0x0000ffff;
1.676 + PostMessage(iHwnd,
1.677 + WMU_SET_BUFFER_FORMAT,
1.678 + aggregateSize,
1.679 + iNewBufferFormat.iPixelFormat);
1.680 + iDisplayBufferFormat = iNewBufferFormat;
1.681 + }
1.682 +
1.683 + if (iDisplayRotation != iNewRotation)
1.684 + {
1.685 + iDisplayRotation = iNewRotation;
1.686 +
1.687 + TUint flip;
1.688 + switch (iDisplayRotation)
1.689 + {
1.690 + case RDisplayChannel::ERotation90CW:
1.691 + flip = EEmulatorFlipLeft;
1.692 + break;
1.693 + case RDisplayChannel::ERotation180:
1.694 + flip = EEmulatorFlipInvert;
1.695 + break;
1.696 + case RDisplayChannel::ERotation270CW:
1.697 + flip = EEmulatorFlipRight;
1.698 + break;
1.699 + default: // Normal
1.700 + flip = EEmulatorFlipRestore;
1.701 + break;
1.702 + }
1.703 + PostMessage(iHwnd, WM_FLIP_MESSAGE, flip, NULL);
1.704 +
1.705 + iPostedRectCount = 0; // Force full invalidation
1.706 + }
1.707 +
1.708 + if (iDisplayResolution.iWidth != iNewResolution.iWidth ||
1.709 + iDisplayResolution.iHeight != iNewResolution.iHeight)
1.710 + {
1.711 + iDisplayResolution = iNewResolution;
1.712 + PostMessage(iHwnd, WMU_SET_DISPLAY_SIZE,
1.713 + iDisplayResolution.iWidth, iDisplayResolution.iHeight);
1.714 + }
1.715 +
1.716 +
1.717 + // Invalidate the window contents where necessary
1.718 + TInt count = iPostedRectCount;
1.719 + if (count)
1.720 + {
1.721 + // Order of invalidation is immaterial
1.722 + while (count--)
1.723 + {
1.724 + InvalidateRect(iHwnd, &iPostedRect[count], FALSE);
1.725 + }
1.726 +
1.727 + iPostedRectCount = 0;
1.728 + }
1.729 + else
1.730 + {
1.731 + InvalidateRect(iHwnd, NULL, FALSE);
1.732 + }
1.733 +
1.734 + // Use differences to allow for wraparound
1.735 + if ((TInt)(iWaitForPost - iLastPostCount) > 0 && (TInt)(iPostCount - iWaitForPost) >= 0)
1.736 + {
1.737 + // Post waited for is now being displayed or was dropped
1.738 + iWaitForPostRequest.Complete(KErrNone);
1.739 + }
1.740 + iLastPostCount = iPostCount;
1.741 + }
1.742 + }
1.743 +
1.744 +
1.745 +/**
1.746 +Set the status object for this request and the thread to complete it on, if not
1.747 +already set.
1.748 +@param aStatus The new request status.
1.749 +@param aThread The thread on which to complete.
1.750 +@return EFalse if the status is already set, or ETrue if the status has now been
1.751 +set.
1.752 +*/
1.753 +TBool DDisplayChannel::TRequest::SetStatus(TThreadMessage& aMsg)
1.754 + {
1.755 + if (iStatus)
1.756 + {
1.757 + __ASSERT_DEBUG(iThread, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicNullThreadOnSet));
1.758 + return EFalse; // In use
1.759 + }
1.760 +
1.761 + __ASSERT_DEBUG(!iThread, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicThreadAlreadySet));
1.762 + DThread* thread = aMsg.Client();
1.763 + TInt r = thread->Open();
1.764 + __ASSERT_DEBUG( r == KErrNone, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicThreadOpenFailed));
1.765 + (TAny)r;
1.766 + iThread = thread;
1.767 + iStatus = reinterpret_cast<TRequestStatus*>(aMsg.Ptr0());
1.768 + return ETrue;
1.769 + }
1.770 +
1.771 +
1.772 +/**
1.773 +Complete the request with the given result. If the status has not been set, or
1.774 +has already been completed, this does nothing.
1.775 +@param aResult The result of the asynchronous request.
1.776 +*/
1.777 +void DDisplayChannel::TRequest::Complete(TInt aResult)
1.778 + {
1.779 + if (iStatus)
1.780 + {
1.781 + __ASSERT_DEBUG(iThread, Kern::PanicCurrentThread(RDisplayChannel::Name(), EDisplayPanicNullThreadOnComplete));
1.782 + Kern::RequestComplete(iThread, iStatus, aResult);
1.783 + Kern::SafeClose((DObject*&)iThread, NULL);
1.784 + }
1.785 + }
1.786 +
1.787 +
1.788 +/**
1.789 +Post the current composition buffer to the display on the next frame tick.
1.790 +@param aRegion NULL if the entire buffer has changed, or a user pointer to up
1.791 +to TDisplayInfo::KMaxRectagles areas that have changed.
1.792 +@param aPostCount User pointer to an integer to receive the new post count.
1.793 +@return KErrNone, or a system-wide error code
1.794 +*/
1.795 +TInt DDisplayChannel::PostCompositionBuffer(TAny* aRegion, RDisplayChannel::TPostCount* aPostCount)
1.796 + {
1.797 + if (!IsCompositionBuffer(iGetBuffer))
1.798 + {
1.799 + return KErrNotSupported;
1.800 + }
1.801 +
1.802 + if (iWaitForPost == iPostCount)
1.803 + {
1.804 + // Complete wait for post (dropped)
1.805 + iWaitForPostRequest.Complete(KErrNone);
1.806 + }
1.807 +
1.808 + if (IsUserBuffer(iPostedBuffer))
1.809 + {
1.810 + // Complete the user post request (not displayed)
1.811 + iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
1.812 + }
1.813 +
1.814 + iPostedBuffer = iGetBuffer;
1.815 + iGetBuffer = NextCompositionBuffer(iGetBuffer);
1.816 +
1.817 + if (iNumCompositionBuffers > 2 && iGetBuffer == iDisplayBuffer)
1.818 + {
1.819 + // With more than two buffers, there must always be one available with
1.820 + // no waiting required, so find it.
1.821 + iGetBuffer = NextCompositionBuffer(iGetBuffer);
1.822 + }
1.823 +
1.824 + // Get the region
1.825 + if (aRegion)
1.826 + {
1.827 + // Set iPostedRect(Count) from aRegion.
1.828 + Panic(EDisplayPanicNotYetImplemented);
1.829 + }
1.830 +
1.831 + // What to do about wrapping?
1.832 + iPostCount++;
1.833 + iNewRotation = iCurrentRotation;
1.834 + iNewResolution = iCurrentResolution;
1.835 + iNewBufferFormat = iCurrentBufferFormat;
1.836 + SafePut(aPostCount, &iPostCount, sizeof(iPostCount));
1.837 +
1.838 + return KErrNone;
1.839 + }
1.840 +
1.841 +
1.842 +/**
1.843 +Post the legacy buffer to the display on the next frame tick.
1.844 +@param aRegion NULL if the entire buffer has changed, or a user pointer to up
1.845 +to TDisplayInfo::KMaxRectagles areas that have changed.
1.846 +@param aPostCount User pointer to an integer to receive the new post count.
1.847 +@return KErrNone, or a system-wide error code
1.848 +*/
1.849 +TInt DDisplayChannel::PostLegacyBuffer(TAny* aRegion, RDisplayChannel::TPostCount* aPostCount)
1.850 + {
1.851 + if (iWaitForPost == iPostCount)
1.852 + {
1.853 + // Complete wait for post (dropped)
1.854 + iWaitForPostRequest.Complete(KErrNone);
1.855 + }
1.856 +
1.857 + if (IsUserBuffer(iPostedBuffer))
1.858 + {
1.859 + iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
1.860 + }
1.861 +
1.862 + // iBuffer should NOT be NULL here!
1.863 + __ASSERT_ALWAYS(iBuffer[KLegacyBuffer].iAddress, Panic(EDisplayPanicNoLegacyBuffer));
1.864 + iPostedBuffer = KLegacyBuffer;
1.865 +
1.866 + // Get the region into iRegion
1.867 + if (aRegion)
1.868 + {
1.869 + // Set iPostedRect(Count) from aRegion.
1.870 + Panic(EDisplayPanicNotYetImplemented);
1.871 + }
1.872 +
1.873 + iPostCount++;
1.874 + iNewRotation = iCurrentRotation;
1.875 + iNewResolution = iCurrentResolution;
1.876 + iNewBufferFormat = iCurrentBufferFormat;
1.877 + SafePut(aPostCount, &iPostCount, sizeof(iPostCount));
1.878 +
1.879 + return KErrNone;
1.880 + }
1.881 +
1.882 +
1.883 +/**
1.884 +Asynchronously request the current composition buffer. Completes immediately
1.885 +if not already being displayed, or an error occurs.
1.886 +@param aStatus The request status to be completed.
1.887 +@param aAddress The user pointer to the location to put the address.
1.888 +*/
1.889 +TInt DDisplayChannel::GetCompositionBuffer(TAny** aAddress)
1.890 + {
1.891 + if (!IsCompositionBuffer(iGetBuffer))
1.892 + {
1.893 + // No composition buffers available for use.
1.894 + return KErrNotSupported;
1.895 + }
1.896 +
1.897 + // The address won't change, so may as well set it now.
1.898 + TUint idx = iGetBuffer - KFirstCompositionBuffer;
1.899 + if (SafePut(aAddress, &idx, sizeof(TUint)) != KErrNone)
1.900 + {
1.901 + return KErrArgument;
1.902 + }
1.903 +
1.904 + if (iNumCompositionBuffers > 1 && iGetBuffer == iDisplayBuffer)
1.905 + {
1.906 + // Multi-buffer case, and buffer is currently being displayed
1.907 +
1.908 + if (iBuffer[iGetBuffer].iRequest.SetStatus(*iMsg))
1.909 + {
1.910 + return KRequestPending;
1.911 + }
1.912 +
1.913 + // Already set
1.914 + return KErrInUse;
1.915 + }
1.916 +
1.917 + return KErrNone;
1.918 + }
1.919 +
1.920 +
1.921 +/**
1.922 +Post a user buffer to the display on the next frame tick.
1.923 +@param aBufferId The ID of the user buffer to post.
1.924 +@param aRegion NULL if the entire buffer has changed, or a user pointer to up
1.925 +to TDisplayInfo::KMaxRectagles areas that have changed.
1.926 +@return KErrNone, or a system-wide error code
1.927 +*/
1.928 +TInt DDisplayChannel::PostUserBuffer(RDisplayChannel::TBufferId* aBufferId, TAny* aRegion, RDisplayChannel::TPostCount* aPostCount)
1.929 + {
1.930 + RDisplayChannel::TBufferId bufferId;
1.931 + bufferId = reinterpret_cast <RDisplayChannel::TBufferId> (aBufferId);
1.932 +
1.933 + if (!IsUserBuffer(bufferId))
1.934 + {
1.935 + // Not a user buffer.
1.936 + return KErrArgument;
1.937 + }
1.938 +
1.939 + if (!iBuffer[bufferId].iChunk)
1.940 + {
1.941 + // User buffer not initialised.
1.942 + return KErrArgument;
1.943 + }
1.944 +
1.945 + if (iWaitForPost == iPostCount)
1.946 + {
1.947 + // Complete wait for post (dropped)
1.948 + iWaitForPostRequest.Complete(KErrNone);
1.949 + }
1.950 +
1.951 + if (IsUserBuffer(iPostedBuffer))
1.952 + {
1.953 + // Complete the user post request (not displayed)
1.954 + iBuffer[iPostedBuffer].iRequest.Complete(KErrCancel);
1.955 + }
1.956 +
1.957 + if (bufferId == iDisplayBuffer) //pathological case
1.958 + {
1.959 + // Complete the current display buffer as we are superceding it with the same one
1.960 + iBuffer[bufferId].iRequest.Complete(KErrNone);
1.961 + }
1.962 +
1.963 + // Only one buffer can be posted at any time, and if it were this user
1.964 + // buffer, the request will have just been completed, so this shouldn't fail.
1.965 + TBool isSet = iBuffer[bufferId].iRequest.SetStatus(*iMsg);
1.966 +
1.967 + __ASSERT_DEBUG(isSet, Panic(EDisplayPanicInUse));
1.968 + (TAny)isSet;
1.969 + iPostedBuffer = bufferId;
1.970 +
1.971 + // Get the region
1.972 + if (aRegion)
1.973 + {
1.974 + // Set iPostedRect(Count) from aRegion.
1.975 + Panic(EDisplayPanicNotYetImplemented);
1.976 + }
1.977 +
1.978 + iPostCount++;
1.979 + iNewRotation = iCurrentRotation;
1.980 + iNewResolution = iCurrentResolution;
1.981 + iNewBufferFormat = iCurrentBufferFormat;
1.982 + SafePut(aPostCount, &iPostCount, sizeof(iPostCount));
1.983 +
1.984 + return KRequestPending;
1.985 + }
1.986 +
1.987 +/**
1.988 +Asynchronous request notification when the given post count is reached (or
1.989 +passed).
1.990 +@param aStatus The request status to be completed.
1.991 +@param aPostCount The count to wait for.
1.992 +*/
1.993 +TInt DDisplayChannel::WaitForPost(RDisplayChannel::TPostCount* aPostCount)
1.994 + {
1.995 + TInt postCount;
1.996 +
1.997 + kumemget(&postCount, aPostCount, sizeof(RDisplayChannel::TPostCount));
1.998 +
1.999 + if ((TInt)(iWaitForPost - iLastPostCount) > 0 && (TInt)(iPostCount - iWaitForPost) >= 0)
1.1000 + {
1.1001 + // Set up the request to be completed when the post occurs
1.1002 + if (iWaitForPostRequest.SetStatus(*iMsg))
1.1003 + {
1.1004 + iWaitForPost = postCount;
1.1005 + return KRequestPending;
1.1006 + }
1.1007 +
1.1008 + // Already waiting for a post
1.1009 + return KErrInUse;
1.1010 + }
1.1011 +
1.1012 + // Requested post already displayed/dropped
1.1013 + return KErrNone;
1.1014 + }
1.1015 +
1.1016 +/**
1.1017 +Asynchronous request notification when the display connection state changes.
1.1018 +This occurs when the display is disconnected, connected with no list, or a list of modes becomes available or is updated.
1.1019 +*/
1.1020 +TInt DDisplayChannel::WaitForDisplayConnect()
1.1021 + {
1.1022 +
1.1023 + Kern::HalFunction(EHalGroupDisplay, EDisplayHalGetStateSpinner, &iDisplayStateSpinner, NULL, iScreenNumber);
1.1024 +
1.1025 + if (iWaitForDisplayConnect.SetStatus(*iMsg))
1.1026 + {
1.1027 + return KRequestPending;
1.1028 + }
1.1029 +
1.1030 + // Already waiting for a post
1.1031 + return KErrInUse;
1.1032 + }
1.1033 +
1.1034 +
1.1035 +/**
1.1036 +Set the rotation of the screen on the next frame. If the buffer contents will
1.1037 +not be valid, the flag set. The validity of the buffer is down to whether the
1.1038 +width and height change.
1.1039 +
1.1040 +@param aNewRotation Address in user space of the new rotation setting.
1.1041 +@param aDisplayConfigChanged Address in user space of where to put whether the
1.1042 +orientation specific info to use has changed following the rotation setting.
1.1043 +@return KErrNone, or KErrArgument if an argument was invalid.
1.1044 +*/
1.1045 +TInt DDisplayChannel::SetRotation(RDisplayChannel::TDisplayRotation* aNewRotation,
1.1046 + TBool* aDisplayConfigChanged)
1.1047 + {
1.1048 + RDisplayChannel::TDisplayRotation newRotation;
1.1049 +
1.1050 + __ASSERT_DEBUG(aNewRotation, Panic(EDisplayPanicNullArgument));
1.1051 +
1.1052 + kumemget(&newRotation, aNewRotation, sizeof(newRotation));
1.1053 +
1.1054 + if (((TInt)newRotation - 1) & newRotation)
1.1055 + {
1.1056 + // More than one bit is set, which is not valid
1.1057 + return KErrArgument;
1.1058 + }
1.1059 +
1.1060 + if ((iChannelInfo.iAvailableRotations & newRotation) == 0)
1.1061 + {
1.1062 + // Rotation is not supported
1.1063 + return KErrArgument;
1.1064 + }
1.1065 +
1.1066 + TBool displayConfigChanged = (IsFlipped(newRotation) != IsFlipped(iCurrentRotation));
1.1067 + iCurrentRotation = newRotation;
1.1068 +
1.1069 + SafePut(aDisplayConfigChanged, &displayConfigChanged, sizeof(TBool));
1.1070 +
1.1071 + return KErrNone;
1.1072 + }
1.1073 +
1.1074 +
1.1075 +/**
1.1076 +Register a user buffer. Assign an ID for it (if available) and open the chunk to
1.1077 +get the address.
1.1078 +@param aChunkHandle The chunk handle.
1.1079 +@param aOffset The offset from the chunk base address to the start of the
1.1080 +buffer.
1.1081 +@param aBufferId The address in user space of where to put the buffer ID.
1.1082 +*/
1.1083 +TInt DDisplayChannel::RegisterUserBuffer(TInt aChunkHandle, TInt aOffset,
1.1084 + RDisplayChannel::TBufferId* aBufferId)
1.1085 + {
1.1086 + if (!aBufferId)
1.1087 + {
1.1088 + return KErrArgument;
1.1089 + }
1.1090 +
1.1091 + NKern::ThreadEnterCS();
1.1092 + DChunk* chunk = Kern::OpenSharedChunk(iMsg->Client(), aChunkHandle,
1.1093 + EFalse);
1.1094 + NKern::ThreadLeaveCS();
1.1095 + if (!chunk)
1.1096 + {
1.1097 + return KErrBadHandle;
1.1098 + }
1.1099 +
1.1100 + TLinAddr kernelAddress;
1.1101 +
1.1102 + const TInt bufferSize = (iDisplayResolution.iWidth * iDisplayResolution.iHeight);
1.1103 + TInt r = Kern::ChunkAddress(chunk,aOffset,bufferSize,kernelAddress);
1.1104 + if(r!=KErrNone)
1.1105 + {
1.1106 + NKern::ThreadEnterCS();
1.1107 + Kern::ChunkClose(chunk);
1.1108 + NKern::ThreadLeaveCS();
1.1109 + return r;
1.1110 + }
1.1111 +
1.1112 + // Search for an empty slot
1.1113 + for (TInt index = KFirstUserBuffer; index < (KFirstUserBuffer + RDisplayChannel::TDisplayInfo::KMaxUserBuffers); index++)
1.1114 + {
1.1115 + if (!iBuffer[index].iChunk)
1.1116 + {
1.1117 + // Found one, so fill in the details and return the index as the ID.
1.1118 + iBuffer[index].iChunk = chunk;
1.1119 + iBuffer[index].iAddress = (TAny*)(kernelAddress);
1.1120 + kumemput(aBufferId, &index, sizeof(RDisplayChannel::TBufferId));
1.1121 + return KErrNone;
1.1122 + }
1.1123 + }
1.1124 +
1.1125 + // No slots available.
1.1126 + NKern::ThreadEnterCS();
1.1127 + Kern::ChunkClose(chunk);
1.1128 + NKern::ThreadLeaveCS();
1.1129 + return KErrTooBig;
1.1130 + }
1.1131 +
1.1132 +
1.1133 +/**
1.1134 +Deregister a user buffer.
1.1135 +@param aBufferId The buffer ID.
1.1136 +*/
1.1137 +TInt DDisplayChannel::DeregisterUserBuffer(RDisplayChannel::TBufferId* aBufferId)
1.1138 + {
1.1139 + RDisplayChannel::TBufferId bufferId;
1.1140 +
1.1141 + __ASSERT_DEBUG(aBufferId, Panic(EDisplayPanicNullArgument));
1.1142 + kumemget(&bufferId, aBufferId, sizeof(RDisplayChannel::TBufferId));
1.1143 +
1.1144 + if (!IsUserBuffer(bufferId))
1.1145 + {
1.1146 + // Not a valid ID
1.1147 + return KErrArgument;
1.1148 + }
1.1149 +
1.1150 + TBufferInfo* buffer = &iBuffer[bufferId];
1.1151 + if (!buffer->iChunk)
1.1152 + {
1.1153 + // Not registered
1.1154 + return KErrArgument;
1.1155 + }
1.1156 +
1.1157 + if (iDisplayBuffer == bufferId)
1.1158 + {
1.1159 + return KErrInUse;
1.1160 + }
1.1161 +
1.1162 + if (iPostedBuffer == bufferId)
1.1163 + {
1.1164 + // Was queued to be posted
1.1165 + iPostedBuffer = (RDisplayChannel::TBufferId)KBufferNotSet;
1.1166 + iPostedRectCount = 0;
1.1167 + }
1.1168 +
1.1169 + // Cancel any outstanding request on the buffer and clear out the fields.
1.1170 + buffer->iRequest.Complete(KErrCancel);
1.1171 + NKern::ThreadEnterCS();
1.1172 + Kern::ChunkClose(buffer->iChunk);
1.1173 + NKern::ThreadLeaveCS();
1.1174 + buffer->iChunk = NULL;
1.1175 + buffer->iAddress = NULL;
1.1176 +
1.1177 + return KErrNone;
1.1178 + }
1.1179 +
1.1180 +/**
1.1181 +Get all resolutions available for this screen and insert to a descriptor
1.1182 +@return KErrNone if successful, otherwise a system wide error code.
1.1183 +*/
1.1184 +TInt DDisplayChannel::GetResolutions()
1.1185 + {
1.1186 + TInt r;
1.1187 + __ASSERT_DEBUG(iMsg->Ptr0(), Panic(EDisplayPanicNullArgument));
1.1188 + __ASSERT_DEBUG(iMsg->Ptr1(), Panic(EDisplayPanicNullArgument));
1.1189 + //get the number of resolutions (as above)
1.1190 + TInt numberOfResolutions = 0;
1.1191 + TInt refStateSpinner, curStateSpinner;
1.1192 + //Get the number of resolutions as well as the display state spinner at this point
1.1193 + r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, &refStateSpinner, iScreenNumber);
1.1194 + if(r < KErrNone)
1.1195 + {
1.1196 + return r;
1.1197 + }
1.1198 +
1.1199 + TInt length;
1.1200 + TInt maxLength;
1.1201 + Kern::KUDesInfo(*(const TDesC*)iMsg->Ptr0(),length,maxLength);
1.1202 +
1.1203 + if ((maxLength/static_cast<TInt>(sizeof(RDisplayChannel::TResolution))) < numberOfResolutions)
1.1204 + {
1.1205 + return KErrOverflow;
1.1206 + }
1.1207 +
1.1208 + TVideoInfoV01 info;
1.1209 + TPckg<TVideoInfoV01> infoPckg(info);
1.1210 + RDisplayChannel::TResolution resolution = {{0,0},{0,0},RDisplayChannel::ERotationAll};
1.1211 + TPtr8 tempDes(NULL,0);
1.1212 +
1.1213 + TInt i;
1.1214 + for (i=0;i<numberOfResolutions;i++)
1.1215 + {
1.1216 + //before filling the package, the display state needs to be checked for consistency
1.1217 + Kern::HalFunction(EHalGroupDisplay, EDisplayHalGetStateSpinner, &curStateSpinner, NULL, iScreenNumber);
1.1218 +
1.1219 + if(curStateSpinner != refStateSpinner)
1.1220 + { //display state has changed, the resolution list we trying to get becomes corrupted
1.1221 + Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(),(i)*sizeof(RDisplayChannel::TResolution));
1.1222 + return KErrCorrupt;
1.1223 + }
1.1224 +
1.1225 + //pass info package to be filled in, also sending the config to read, and the screen within that
1.1226 + Kern::HalFunction(EHalGroupDisplay, EDisplayHalSpecificScreenInfo, &i, &infoPckg, iScreenNumber);
1.1227 + //save resolution
1.1228 + resolution.iPixelSize = info.iSizeInPixels;
1.1229 + resolution.iTwipsSize = info.iSizeInTwips;
1.1230 + //copy resolution
1.1231 + tempDes.Set((TUint8*)&resolution,sizeof(RDisplayChannel::TResolution),sizeof(RDisplayChannel::TResolution));
1.1232 + r = Kern::ThreadDesWrite(iMsg->Client(),(TDes8*)iMsg->Ptr0(),tempDes,i*sizeof(RDisplayChannel::TResolution),iMsg->Client());
1.1233 +
1.1234 + if (r<KErrNone)
1.1235 + {
1.1236 + Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(),(i)*sizeof(RDisplayChannel::TResolution));
1.1237 + return r;
1.1238 + }
1.1239 + }
1.1240 + Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(),(i)*sizeof(RDisplayChannel::TResolution));
1.1241 + SafePut(iMsg->Ptr1(), &numberOfResolutions, sizeof(numberOfResolutions));
1.1242 + return KErrNone;
1.1243 + }
1.1244 +
1.1245 +
1.1246 +
1.1247 +TInt DDisplayChannel::SetResolution(TSize* aSize)
1.1248 + {
1.1249 + if (!aSize)
1.1250 + {
1.1251 + ClientPanic(RDisplayChannel::ENullArgument);
1.1252 + return KErrArgument;
1.1253 + }
1.1254 +
1.1255 + TSize size;
1.1256 + kumemget32(&size, aSize, sizeof(size));
1.1257 + if (size.iWidth < 0 || size.iHeight < 0)
1.1258 + {
1.1259 + ClientPanic(RDisplayChannel::EInvalidResolution);
1.1260 + return KErrArgument;
1.1261 + }
1.1262 +
1.1263 + if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,
1.1264 + __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
1.1265 + {
1.1266 + return KErrPermissionDenied;
1.1267 + }
1.1268 +
1.1269 + // Validate size. Return KErrArgument on failure.
1.1270 + //Get the number of resolutions
1.1271 + TInt numberOfResolutions;
1.1272 + TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions, &numberOfResolutions, NULL, iScreenNumber);
1.1273 + if(r < KErrNone)
1.1274 + {
1.1275 + return r;
1.1276 + }
1.1277 + TVideoInfoV01 info;
1.1278 + TPckg<TVideoInfoV01> infoPckg(info);
1.1279 + for (TInt i = 0; i < numberOfResolutions; i++)
1.1280 + {
1.1281 + //pass info package to be filled in, also sending the config to read, and the screen within that
1.1282 + Kern::HalFunction(EHalGroupDisplay, EDisplayHalSpecificScreenInfo, &i, &infoPckg, iScreenNumber);
1.1283 +
1.1284 + if (info.iSizeInPixels.iWidth == size.iWidth &&
1.1285 + info.iSizeInPixels.iHeight == size.iHeight)
1.1286 + { //matched resolution
1.1287 + iCurrentResolution = size;
1.1288 + iCurrentTwips = info.iSizeInTwips;
1.1289 +
1.1290 + if (iCurrentResolution.iHeight > iNewBufferFormat.iSize.iHeight ||
1.1291 + iCurrentResolution.iWidth > iNewBufferFormat.iSize.iWidth)
1.1292 + {
1.1293 + // going back to initial settings and, we hope,
1.1294 + // the buffers could still be displayed correctly, but we have no guarantee
1.1295 + iCurrentBufferFormat = iInitialBufferFormat;
1.1296 + }
1.1297 + return KErrNone;
1.1298 + }
1.1299 + }
1.1300 + return KErrArgument; //if reached here, it did not match aSize to any config resolution
1.1301 + }
1.1302 +
1.1303 +TInt DDisplayChannel::GetResolution(TSize* aSize)
1.1304 + {
1.1305 + TInt numberOfResolutions;
1.1306 + TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions,
1.1307 + &numberOfResolutions, NULL, iScreenNumber);
1.1308 +
1.1309 + if (r == KErrNone)
1.1310 + {
1.1311 + if (numberOfResolutions > 0)
1.1312 + {
1.1313 + SafePut(aSize, &iCurrentResolution, sizeof(iCurrentResolution));
1.1314 + }
1.1315 + else
1.1316 + {
1.1317 + TSize resolution = {0,0};
1.1318 + SafePut(aSize, &resolution, sizeof(resolution));
1.1319 + }
1.1320 + }
1.1321 + return r;
1.1322 + }
1.1323 +
1.1324 +TInt DDisplayChannel::GetTwips(TSize* aSize)
1.1325 + {
1.1326 + TInt numberOfResolutions;
1.1327 + TInt r = Kern::HalFunction(EHalGroupDisplay, EDisplayHalNumberOfResolutions,
1.1328 + &numberOfResolutions, NULL, iScreenNumber);
1.1329 +
1.1330 + if (r == KErrNone)
1.1331 + {
1.1332 + if (numberOfResolutions > 0)
1.1333 + {
1.1334 + SafePut(aSize, &iCurrentTwips, sizeof(iCurrentTwips));
1.1335 + }
1.1336 + else
1.1337 + {
1.1338 + TSize twips = {0,0};
1.1339 + SafePut(aSize, &twips, sizeof(twips));
1.1340 + }
1.1341 + }
1.1342 + return r;
1.1343 + }
1.1344 +/**
1.1345 +Get all the pixel formats available and insert them to a descriptor
1.1346 +@return KErrNone if successful, otherwise a system wide error code.
1.1347 +*/
1.1348 +TInt DDisplayChannel::GetPixelFormats()
1.1349 + {
1.1350 + TInt r;
1.1351 + __ASSERT_DEBUG(iMsg->Ptr0(), Panic(EDisplayPanicNullArgument));
1.1352 + __ASSERT_DEBUG(iMsg->Ptr1(), Panic(EDisplayPanicNullArgument));
1.1353 + //get the number of resolutions (as above)
1.1354 + TPtr8 pixelFormatDes(NULL,0);
1.1355 + TInt length = ((TInt)sizeof(RDisplayChannel::TPixelFormat)) * iPixelFormatArraySize;
1.1356 + pixelFormatDes.Set((TUint8*)iPixelFormatArray, length, length);
1.1357 + r = Kern::ThreadDesWrite(iMsg->Client(),(TDes8*)iMsg->Ptr0(), pixelFormatDes, 0, iMsg->Client());
1.1358 + if (r == KErrNone)
1.1359 + {
1.1360 + Kern::KUDesSetLength(*(TDes8*)iMsg->Ptr0(), length);
1.1361 + SafePut(iMsg->Ptr1(), &iPixelFormatArraySize, sizeof(iPixelFormatArraySize));
1.1362 + }
1.1363 + return r;
1.1364 + }
1.1365 +
1.1366 +
1.1367 +TInt DDisplayChannel::SetBufferFormat(RDisplayChannel::TBufferFormat* aBufferFormat)
1.1368 + {
1.1369 + if (!aBufferFormat)
1.1370 + {
1.1371 + ClientPanic(RDisplayChannel::ENullArgument);
1.1372 + return KErrArgument;
1.1373 + }
1.1374 +
1.1375 + if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,
1.1376 + __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
1.1377 + {
1.1378 + return KErrPermissionDenied;
1.1379 + }
1.1380 +
1.1381 + RDisplayChannel::TBufferFormat bufferFormat;
1.1382 + kumemget32(&bufferFormat, aBufferFormat, sizeof(RDisplayChannel::TBufferFormat));
1.1383 +
1.1384 + // Validate Size
1.1385 + if (iCurrentResolution.iHeight > bufferFormat.iSize.iHeight ||
1.1386 + iCurrentResolution.iWidth > bufferFormat.iSize.iWidth ||
1.1387 + bufferFormat.iSize.iHeight > KMaxBufferSizeHeightAndWidth ||
1.1388 + bufferFormat.iSize.iWidth > KMaxBufferSizeHeightAndWidth)
1.1389 + {
1.1390 + //return error on failure
1.1391 + return KErrArgument;
1.1392 + }
1.1393 +
1.1394 + // check we received one of the supported formats.
1.1395 + for (TInt i = 0; i < iPixelFormatArraySize; i++)
1.1396 + {
1.1397 + if (bufferFormat.iPixelFormat == iPixelFormatArray[i])
1.1398 + {
1.1399 + // the arguments are all validated at this point, update the current format
1.1400 + iCurrentBufferFormat = bufferFormat;
1.1401 + return KErrNone;
1.1402 + }
1.1403 + }
1.1404 +
1.1405 + //return error on failure
1.1406 + return KErrArgument;
1.1407 + }
1.1408 +
1.1409 +TInt DDisplayChannel::ValidateBufferFormat(const RDisplayChannel::TBufferFormat& aBufferFormat,
1.1410 + const RDisplayChannel::TResolution& aResolution)
1.1411 + {
1.1412 + // Validate the size reported in buffer format against the given resolution
1.1413 + if (aResolution.iPixelSize.iHeight > aBufferFormat.iSize.iHeight ||
1.1414 + aResolution.iPixelSize.iWidth > aBufferFormat.iSize.iWidth ||
1.1415 + aBufferFormat.iSize.iHeight > KMaxBufferSizeHeightAndWidth ||
1.1416 + aBufferFormat.iSize.iWidth > KMaxBufferSizeHeightAndWidth)
1.1417 + {
1.1418 + //return error on failure
1.1419 + return KErrArgument;
1.1420 + }
1.1421 +
1.1422 + // check we received one of the supported formats.
1.1423 + for (TInt i = 0; i < iPixelFormatArraySize; i++)
1.1424 + {
1.1425 + if (aBufferFormat.iPixelFormat == iPixelFormatArray[i])
1.1426 + {
1.1427 + return KErrNone;
1.1428 + }
1.1429 + }
1.1430 +
1.1431 + return KErrArgument;
1.1432 + }
1.1433 +
1.1434 +TInt DDisplayChannel::NextPlaneOffset(RDisplayChannel::TBufferFormat* aBufferFormat,
1.1435 + RDisplayChannel::TBufferFormatContext* aContext)
1.1436 + {
1.1437 + if (!aBufferFormat)
1.1438 + {
1.1439 + ClientPanic(RDisplayChannel::ENullArgument);
1.1440 + return KErrArgument;
1.1441 + }
1.1442 +
1.1443 + if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,
1.1444 + __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
1.1445 + {
1.1446 + return KErrPermissionDenied;
1.1447 + }
1.1448 +
1.1449 + RDisplayChannel::TBufferFormat bufferFormat;
1.1450 + kumemget32(&bufferFormat, aBufferFormat, sizeof(bufferFormat));
1.1451 +
1.1452 + RDisplayChannel::TResolution resolution;
1.1453 + RDisplayChannel::TDisplayRotation rotation;
1.1454 +
1.1455 + if (aContext)
1.1456 + {
1.1457 + RDisplayChannel::TBufferFormatContext context;
1.1458 + kumemget32(&context, aContext, sizeof(context));
1.1459 + resolution = context.iResolution;
1.1460 + rotation = context.iRotation;
1.1461 + }
1.1462 + else
1.1463 + {
1.1464 + resolution.iPixelSize = iCurrentResolution;
1.1465 + rotation = iCurrentRotation;
1.1466 + }
1.1467 +
1.1468 + TInt err = ValidateBufferFormat(bufferFormat, resolution);
1.1469 +
1.1470 + if (err != KErrNone)
1.1471 + {
1.1472 + return err;
1.1473 + }
1.1474 + //it assumes no planar pixel formats are supported by this driver implementation
1.1475 + return 0;
1.1476 + }
1.1477 +
1.1478 +TInt DDisplayChannel::NextLineOffset(RDisplayChannel::TBufferFormat* aBufferFormat,
1.1479 + RDisplayChannel::TBufferFormatContext* aContext)
1.1480 + {
1.1481 + if (!aBufferFormat)
1.1482 + {
1.1483 + ClientPanic(RDisplayChannel::ENullArgument);
1.1484 + return KErrArgument;
1.1485 + }
1.1486 +
1.1487 + if (!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,
1.1488 + __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY0.LDD (display channel driver)")))
1.1489 + {
1.1490 + return KErrPermissionDenied;
1.1491 + }
1.1492 +
1.1493 + RDisplayChannel::TBufferFormat bufferFormat;
1.1494 + kumemget32(&bufferFormat, aBufferFormat, sizeof(bufferFormat));
1.1495 +
1.1496 + RDisplayChannel::TResolution resolution;
1.1497 + RDisplayChannel::TDisplayRotation rotation;
1.1498 +
1.1499 + if (aContext)
1.1500 + {
1.1501 + RDisplayChannel::TBufferFormatContext context;
1.1502 + kumemget32(&context, aContext, sizeof(context));
1.1503 + resolution = context.iResolution;
1.1504 + rotation = context.iRotation;
1.1505 + }
1.1506 + else
1.1507 + {
1.1508 + resolution.iPixelSize = iCurrentResolution;
1.1509 + rotation = iCurrentRotation;
1.1510 + }
1.1511 +
1.1512 + TInt err = ValidateBufferFormat(bufferFormat, resolution);
1.1513 +
1.1514 + if (err != KErrNone)
1.1515 + {
1.1516 + return err;
1.1517 + }
1.1518 +
1.1519 + TInt bpp = 0;
1.1520 + //validating the pixel format and getting the pixel size in bits
1.1521 + switch (bufferFormat.iPixelFormat)
1.1522 + {
1.1523 + case EUidPixelFormatXRGB_4444: // RGB4444
1.1524 + case EUidPixelFormatARGB_4444:
1.1525 + case EUidPixelFormatRGB_565: // RGB565
1.1526 + bpp = 16;
1.1527 + break;
1.1528 + case EUidPixelFormatXRGB_8888: // Really 32bpp, but top 8 unused
1.1529 + case EUidPixelFormatARGB_8888:
1.1530 + case EUidPixelFormatARGB_8888_PRE:
1.1531 + bpp = 32;
1.1532 + break;
1.1533 + default:
1.1534 + // We got an error, it seems. The pixel format is not supported
1.1535 + // Let's panic because the pixel format has just been validated
1.1536 + Panic(EDisplayPanicInvalidBitDepth);
1.1537 + break;
1.1538 + }
1.1539 +
1.1540 + TInt widthInPixel = 0; // pixels
1.1541 +
1.1542 + // let's take in consideration the given rotation
1.1543 + switch (rotation)
1.1544 + {
1.1545 + case RDisplayChannel::ERotation90CW:
1.1546 + case RDisplayChannel::ERotation270CW:
1.1547 + widthInPixel = bufferFormat.iSize.iHeight;
1.1548 + break;
1.1549 + default: // Normal
1.1550 + widthInPixel = bufferFormat.iSize.iWidth;
1.1551 + break;
1.1552 + }
1.1553 +
1.1554 + // we have to round up to 32 bits word. This is a Ms Windows limitation
1.1555 + TInt stride = _ALIGN_UP((widthInPixel * bpp), 32) >> 3;
1.1556 + return stride;
1.1557 + }