1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/graphicshwdrivers/surfacemgr/src/extension.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1699 @@
1.4 +// Copyright (c) 2006-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 <graphics/surface.h>
1.22 +#include <graphics/surfacetypes.h>
1.23 +#include <graphics/surfacemanager.h>
1.24 +#include "surfacemanager_dev.h"
1.25 +#include <kernel/cache.h>
1.26 +
1.27 +/**
1.28 +Convert the surface Id to an index of the array
1.29 +based on the least significant 4 bits of the first word of the ID
1.30 +@param aSurfaceId Const reference to the surface Id
1.31 +@internalTechnology
1.32 +*/
1.33 +static TInt SurfaceIdToIndex(const TSurfaceId& aSurfaceId)
1.34 + {
1.35 + return static_cast<TInt>(aSurfaceId.iInternal[0]&(KMaxLists-1));
1.36 + }
1.37 +
1.38 +/**
1.39 +Removes an item from a linked list
1.40 +@param aList Pointer to the head of a linked list of type T
1.41 +@param aOwner Pointer to the object to be removed
1.42 +@internalTechnology
1.43 +*/
1.44 +template<class T>
1.45 +static void UnlinkListItem(T** aList, const T* aItem)
1.46 + {
1.47 + TRACE(Kern::Printf("SM UnlinkListItem list %08x object %08x \n", aList, aItem);)
1.48 +
1.49 + __ASSERT_DEBUG(aItem != NULL, Kern::Fault("Surface Manager", __LINE__));
1.50 + __ASSERT_DEBUG(*aList != NULL, Kern::Fault("Surface Manager", __LINE__));
1.51 +
1.52 + if (*aList == aItem) //one we want is at the head of the list
1.53 + {
1.54 + *aList = aItem->iNext;
1.55 + return;
1.56 + }
1.57 +
1.58 + T* p = *aList;
1.59 + T* q = (*aList)->iNext;
1.60 + while (q)
1.61 + {
1.62 + if (q == aItem)
1.63 + {
1.64 + p->iNext = q->iNext;
1.65 + return;
1.66 + }
1.67 + p = q;
1.68 + q = q->iNext;
1.69 + }
1.70 + }
1.71 +
1.72 +
1.73 +
1.74 +
1.75 +/**
1.76 +Returns a pointer to the surface owner object for the specified process, for this surface.
1.77 +@param aProcess Pointer to the process object
1.78 +@return pointer to the surface owner object if found, else NULL
1.79 +@internalTechnology
1.80 +*/
1.81 +
1.82 +TProcessListItem* TSurface::ProcessOwnerInfo(const DProcess* aProcess)
1.83 + {
1.84 + TProcessListItem* so = iOwners;
1.85 + while(so)
1.86 + {
1.87 + if (aProcess == so->iOwningProcess)
1.88 + {
1.89 + break;
1.90 + }
1.91 + so = so->iNext;
1.92 + }
1.93 + return so;
1.94 + }
1.95 +
1.96 +/**
1.97 +Creates a shared chunk surface.
1.98 +@param aParams Package buffer containing the surface creation parameters.
1.99 +@param aId Will be set to the surface id of the newly created surface.
1.100 +@return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
1.101 +otherwise one of the other system wide error codes.
1.102 +@see RSurfaceManager::TSurfaceCreationAttributes
1.103 +@internalTechnology
1.104 +*/
1.105 +
1.106 +TInt DSurfaceManager::CreateSurface(const TDesC8* aParams, TSurfaceId* aId)
1.107 + {
1.108 +
1.109 + RSurfaceManager::TSurfaceCreationAttributesBuf buf;
1.110 + RSurfaceManager::TSurfaceCreationAttributes& attribs = buf();
1.111 +
1.112 + Kern::KUDesGet(buf, *aParams); //fetch input parameters
1.113 + if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) )
1.114 + {
1.115 + return KErrArgument;
1.116 + }
1.117 +
1.118 + RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface];
1.119 + if( (attribs.iHintCount>0) && attribs.iSurfaceHints)
1.120 + {
1.121 + kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
1.122 + attribs.iSurfaceHints = tempSurfaceHints;
1.123 + }
1.124 + else
1.125 + {
1.126 + attribs.iSurfaceHints=NULL;
1.127 + }
1.128 +
1.129 + //validate input parameters and calculate chunk size
1.130 + TInt roundedBufferSize = attribs.iOffsetBetweenBuffers;
1.131 + TUint dummyActualSize = 0;
1.132 +
1.133 + TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, dummyActualSize, ETrue);
1.134 + if (chunkSize == 0)
1.135 + {
1.136 + return KErrArgument;
1.137 + }
1.138 +
1.139 + TSurfaceId sid;
1.140 + TInt r = KErrNone;
1.141 + TSurface* surface = NULL;
1.142 + do //in the unlikely event that we generate a duplicate surface id, try again.
1.143 + {
1.144 + GenerateSurfaceId(sid);
1.145 +
1.146 + NKern::FMWait(&iMutex);
1.147 + surface = FindSurfaceById(sid);
1.148 + NKern::FMSignal(&iMutex);
1.149 + }
1.150 + while (surface);
1.151 +
1.152 + //create a shared chunk for the surface memory
1.153 + TChunkCreateInfo info;
1.154 + info.iType = TChunkCreateInfo::ESharedKernelMultiple; //multi process mappable
1.155 + info.iMaxSize = chunkSize;
1.156 + info.iOwnsMemory = ETrue;
1.157 +
1.158 +//iMapAttr is valid only for hardware devices and will not make any effect in wins
1.159 +#ifndef __WINS__
1.160 + info.iMapAttr = (attribs.iCacheAttrib == RSurfaceManager::ECached) ? EMapAttrCachedMax : EMapAttrL1Uncached;
1.161 +#else
1.162 + info.iMapAttr = 0;
1.163 +#endif
1.164 +
1.165 + TLinAddr kernAddr;
1.166 + TUint32 mapAttr;
1.167 +
1.168 + NKern::ThreadEnterCS();
1.169 + DChunk* chunk;
1.170 + r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr);
1.171 + if (KErrNone != r)
1.172 + {
1.173 + NKern::ThreadLeaveCS();
1.174 + return r;
1.175 + }
1.176 +
1.177 + //commit the memory
1.178 + TUint32 paddr;
1.179 + if (attribs.iContiguous)
1.180 + {
1.181 + r = Kern::ChunkCommitContiguous(chunk, 0, chunkSize, paddr);
1.182 + }
1.183 + else
1.184 + {
1.185 + r = Kern::ChunkCommit(chunk, 0, chunkSize);
1.186 + }
1.187 +
1.188 + if (KErrNone != r)
1.189 + {
1.190 + //problem committing the memory,
1.191 + //destroy the chunk and cleanup
1.192 + Kern::ChunkClose(chunk);
1.193 + NKern::ThreadLeaveCS();
1.194 + return r;
1.195 + }
1.196 +
1.197 + //create a surface structure for the new surface
1.198 + surface = new TSurface;
1.199 + TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);)
1.200 + if (!surface)
1.201 + {
1.202 + //destroy the chunk and cleanup, out of memory
1.203 + Kern::ChunkClose(chunk);
1.204 + NKern::ThreadLeaveCS();
1.205 + return KErrNoMemory;
1.206 + }
1.207 +
1.208 + surface->iId = sid;
1.209 + surface->iSize = attribs.iSize;
1.210 + surface->iBuffers = attribs.iBuffers;
1.211 + surface->iPixelFormat = attribs.iPixelFormat;
1.212 + surface->iStride = attribs.iStride;
1.213 + surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer;
1.214 + surface->iAlignment = attribs.iAlignment;
1.215 + surface->iContiguous = attribs.iContiguous;
1.216 + surface->iChunk = chunk;
1.217 + surface->iOffsetBetweenBuffers = roundedBufferSize;
1.218 + surface->iCacheAttrib = attribs.iCacheAttrib;
1.219 + surface->iMappable = attribs.iMappable;
1.220 + if(attribs.iHintCount>0)
1.221 + {
1.222 + memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
1.223 + }
1.224 + memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair));
1.225 +
1.226 + //create a surface owner for this surface
1.227 + TProcessListItem* owner = new TProcessListItem;
1.228 + TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);)
1.229 +
1.230 + if (!owner)
1.231 + {
1.232 + //destroy the chunk and cleanup, out of memory
1.233 + Kern::ChunkClose(chunk);
1.234 + delete(surface);
1.235 + TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);)
1.236 + NKern::ThreadLeaveCS();
1.237 + return KErrNoMemory;
1.238 + }
1.239 +
1.240 + owner->iCount = 1; //mark it as open in this process
1.241 + owner->iOwningProcess = &Kern::CurrentProcess();
1.242 + owner->iNext = NULL;
1.243 +
1.244 + surface->iOwners = owner; //only 1 owner at creation time
1.245 +
1.246 + //at this point we have a fully constructed TSurface
1.247 +
1.248 + //add surface to head of surfaces list
1.249 + NKern::FMWait(&iMutex);
1.250 + //Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index
1.251 + //add the new surface to the beginning of the list
1.252 + TInt index = SurfaceIdToIndex(sid);
1.253 + surface->iNext = iSurfacesIndex[index];
1.254 + iSurfacesIndex[index] = surface;
1.255 +
1.256 + NKern::FMSignal(&iMutex);
1.257 + NKern::ThreadLeaveCS();
1.258 +
1.259 + //write surface id back to user side
1.260 + kumemput(aId, &sid, sizeof (TSurfaceId));
1.261 + return KErrNone;
1.262 + }
1.263 +
1.264 +
1.265 +/**
1.266 +Validate that a chunk contains physical memory for the used areas.
1.267 +
1.268 +This function should be called in Critical Section in order to be completed even if the thread
1.269 +or process is killed and so be able to free the memory allocated (TUint32[pageList])
1.270 +
1.271 +@param aChunk Chunk that the user supplied.
1.272 +@param aAttribs Surface Creation Attributes.
1.273 +@param aBuffersize Calculated size of each buffer.
1.274 +@param aMapAttr Filled in with the mapping attributes of the memory.
1.275 +@param aIsContiguous Lets the caller know if the surface is physically contiguous or not.
1.276 +@return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
1.277 +KErrBadHandle if aChunkHandle is of an invalid shared chunk memory,
1.278 +otherwise one of the other system wide error codes.
1.279 +@see RSurfaceManager::TSurfaceCreationAttributes
1.280 +@internalTechnology
1.281 +*/
1.282 +TInt DSurfaceManager::ValidatePhysicalMemory(DChunk* aChunk, const RSurfaceManager::TSurfaceCreationAttributes& aAttribs,
1.283 + TUint aBuffersize, TUint32& aMapAttr, TBool &aIsContiguous)
1.284 + {
1.285 + TLinAddr kernAddr;
1.286 + TUint32 physAddr;
1.287 +
1.288 + //Get the physical address for a region in a shared chunk
1.289 + TInt pageSize = Kern::RoundToPageSize(1);
1.290 + TInt pageList = 1 + (aChunk->iSize + pageSize - 2) / pageSize;
1.291 + TUint32* physAddr2 = new TUint32[pageList];
1.292 + if(!physAddr2)
1.293 + {
1.294 + return KErrNoMemory;
1.295 + }
1.296 +
1.297 + // Unless proven otherwise, the memory is not contiguous.
1.298 + aIsContiguous = EFalse;
1.299 + TInt r = Kern::ChunkPhysicalAddress(aChunk, 0, aChunk->iSize, kernAddr, aMapAttr, physAddr, physAddr2);
1.300 + if (KErrNone == r)
1.301 + {
1.302 + aIsContiguous = ETrue;
1.303 + }
1.304 +
1.305 +
1.306 + TRACE(Kern::Printf("SM CreateSurface ChunkPhysicalAddress r %d chunk %08x chunk size %d", r, aChunk, aChunk->iSize);)
1.307 + TRACE(Kern::Printf("SM CreateSurface kernAddr %08x", kernAddr);)
1.308 + TRACE(Kern::Printf("SM CreateSurface mapAttr %08x", aMapAttr);)
1.309 + TRACE(Kern::Printf("SM CreateSurface physAddr %08x", physAddr);)
1.310 + TRACE(Kern::Printf("SM CreateSurface physAddr2 %08x", physAddr2);)
1.311 +
1.312 + if(r < KErrNone)
1.313 + {
1.314 + // Error means that there isn't memory in the whole chunk - so check the
1.315 + // relevant areas - it is allowed to have gaps between the buffers, but not
1.316 + // within the actual regions that are used for buffers.
1.317 +
1.318 + // So, we first check the area before first buffer up to "offsettofirstbuffer", which all should be valid
1.319 + if (aAttribs.iOffsetToFirstBuffer != 0)
1.320 + {
1.321 + r = Kern::ChunkPhysicalAddress(aChunk, 0, aAttribs.iOffsetToFirstBuffer,
1.322 + kernAddr, aMapAttr, physAddr, physAddr2);
1.323 + }
1.324 + else
1.325 + {
1.326 + r = KErrNone;
1.327 + }
1.328 +
1.329 + // If that's a pass, loop through and check the actual buffers (leave loop if it fails).
1.330 + for(TInt i = 0; i < aAttribs.iBuffers && KErrNone <= r; i++)
1.331 + {
1.332 + r = Kern::ChunkPhysicalAddress(aChunk,
1.333 + aAttribs.iOffsetToFirstBuffer + aAttribs.iOffsetBetweenBuffers * i,
1.334 + aBuffersize, kernAddr, aMapAttr, physAddr, physAddr2);
1.335 + }
1.336 + }
1.337 +
1.338 + // Fix up weird ChunkPhysicalAddress behaviour - it returns 1 to indicate that memory is non-contiguous.
1.339 + if (1 == r)
1.340 + {
1.341 + r = KErrNone;
1.342 + }
1.343 +
1.344 + delete[] physAddr2;
1.345 + return r;
1.346 + }
1.347 +
1.348 +
1.349 +/**
1.350 +Creates a surface in an existing shared chunk.
1.351 +@param aParam Package buf containing the surface creation parameters and id to be set to the surface id of the newly created surface.
1.352 +@param aChunkHandle Existing valid shared chunk handle.
1.353 +@return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
1.354 +KErrBadHandle if aChunkHandle is of an invalid shared chunk memory,
1.355 +otherwise one of the other system wide error codes.
1.356 +@see RSurfaceManager::TSurfaceCreationAttributes
1.357 +@internalTechnology
1.358 +*/
1.359 +TInt DSurfaceManager::CreateSurface(RSurfaceManagerDriver::TDeviceParam* aParam, TInt aChunkHandle)
1.360 + {
1.361 + RSurfaceManager::TSurfaceCreationAttributesBuf buf;
1.362 + RSurfaceManager::TSurfaceCreationAttributes& attribs = buf();
1.363 +
1.364 + //Get the input parameters
1.365 + RSurfaceManagerDriver::TDeviceParam param;
1.366 + kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
1.367 + Kern::KUDesGet(buf, *(reinterpret_cast<const TDesC8*>(param.iBuffer)));
1.368 + if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) )
1.369 + {
1.370 + return KErrArgument;
1.371 + }
1.372 +
1.373 + RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface];
1.374 + if( (attribs.iHintCount>0) && attribs.iSurfaceHints)
1.375 + {
1.376 + kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
1.377 + attribs.iSurfaceHints = tempSurfaceHints;
1.378 + }
1.379 + else
1.380 + {
1.381 + attribs.iSurfaceHints=NULL;
1.382 + }
1.383 +
1.384 + //validate input parameters and calc size
1.385 + TInt roundedBufferSize = attribs.iOffsetBetweenBuffers;
1.386 + TUint actualBufferSize = 0;
1.387 + TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, actualBufferSize);
1.388 + if (chunkSize == 0)
1.389 + {
1.390 + return KErrArgument;
1.391 + }
1.392 +
1.393 + NKern::ThreadEnterCS();
1.394 +
1.395 + //Open an existing shared chunk
1.396 + DChunk* chunk = Kern::OpenSharedChunk(NULL, aChunkHandle, EFalse);
1.397 + if(chunk == NULL)
1.398 + {
1.399 + NKern::ThreadLeaveCS();
1.400 + return KErrBadHandle;
1.401 + }
1.402 +
1.403 + //Check for chunk type as kernel multiple
1.404 + if(chunk->iChunkType != ESharedKernelMultiple)
1.405 + {
1.406 + Kern::ChunkClose(chunk);
1.407 + NKern::ThreadLeaveCS();
1.408 + return KErrBadHandle;
1.409 + }
1.410 +
1.411 + //Check for enough chunk size to create surface for requested attributes
1.412 + if (chunk->iSize < attribs.iOffsetToFirstBuffer + attribs.iBuffers * actualBufferSize)
1.413 + {
1.414 + Kern::ChunkClose(chunk);
1.415 + NKern::ThreadLeaveCS();
1.416 + return KErrArgument;
1.417 + }
1.418 +
1.419 + TSurfaceId sid;
1.420 + TSurface* surface = NULL;
1.421 + do //in the unlikely event that we generate a duplicate surface id, try again.
1.422 + {
1.423 + GenerateSurfaceId(sid);
1.424 +
1.425 + NKern::FMWait(&iMutex);
1.426 + surface = FindSurfaceById(sid);
1.427 + NKern::FMSignal(&iMutex);
1.428 + }
1.429 + while (surface);
1.430 +
1.431 + //create a surface structure for the new surface
1.432 + surface = new TSurface;
1.433 + TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);)
1.434 + if (!surface)
1.435 + {
1.436 + //destroy the chunk and cleanup, out of memory
1.437 + Kern::ChunkClose(chunk);
1.438 + NKern::ThreadLeaveCS();
1.439 + return KErrNoMemory;
1.440 + }
1.441 +
1.442 + TUint32 mapAttr = 0;
1.443 + TBool isContiguous;
1.444 + TInt r = ValidatePhysicalMemory(chunk, attribs, actualBufferSize, mapAttr, isContiguous);
1.445 + if (r != KErrNone)
1.446 + {
1.447 + //destroy the surface and close the chunk
1.448 + delete(surface);
1.449 + Kern::ChunkClose(chunk);
1.450 + NKern::ThreadLeaveCS();
1.451 + if (r != KErrNoMemory)
1.452 + {
1.453 + r = KErrArgument;
1.454 + }
1.455 + return r;
1.456 + }
1.457 +
1.458 + surface->iId = sid;
1.459 + surface->iSize = attribs.iSize;
1.460 + surface->iBuffers = attribs.iBuffers;
1.461 + surface->iPixelFormat = attribs.iPixelFormat;
1.462 + surface->iStride = attribs.iStride;
1.463 + surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer;
1.464 + surface->iAlignment = attribs.iAlignment;
1.465 + surface->iContiguous = isContiguous;
1.466 + surface->iChunk = chunk;
1.467 + surface->iOffsetBetweenBuffers = (attribs.iOffsetBetweenBuffers) ? attribs.iOffsetBetweenBuffers : roundedBufferSize;
1.468 + surface->iMappable = attribs.iMappable;
1.469 +#ifndef __WINS__ //Creation attribute field will not considered for iCacheAttrib
1.470 + TUint32 level1Info = mapAttr & EMapAttrL1CacheMask;
1.471 + TUint32 level2Info = mapAttr & EMapAttrL2CacheMask;
1.472 + TBool chunkIsNotcached = ((level2Info == EMapAttrL2Uncached) &&
1.473 + ((level1Info == EMapAttrFullyBlocking) || (level1Info == EMapAttrBufferedNC) ||
1.474 + (level1Info == EMapAttrBufferedC) || (level1Info == EMapAttrL1Uncached)));
1.475 + surface->iCacheAttrib = (chunkIsNotcached) ? RSurfaceManager::ENotCached : RSurfaceManager::ECached;
1.476 +#else
1.477 + surface->iCacheAttrib = RSurfaceManager::ENotCached;
1.478 +#endif
1.479 +
1.480 + if(attribs.iHintCount>0)
1.481 + {
1.482 + memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
1.483 + }
1.484 + memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair));
1.485 +
1.486 + //create a surface owner for this surface
1.487 + TProcessListItem* owner = new TProcessListItem;
1.488 + TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);)
1.489 +
1.490 + if (!owner)
1.491 + {
1.492 + //destroy the chunk and cleanup, out of memory
1.493 + Kern::ChunkClose(chunk);
1.494 + delete(surface);
1.495 + TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);)
1.496 + NKern::ThreadLeaveCS();
1.497 + return KErrNoMemory;
1.498 + }
1.499 +
1.500 + owner->iCount = 1; //mark it as open in this process
1.501 + owner->iOwningProcess = &Kern::CurrentProcess();
1.502 + owner->iNext = NULL;
1.503 +
1.504 + surface->iOwners = owner; //only 1 owner at creation time
1.505 +
1.506 + NKern::FMWait(&iMutex);
1.507 + //at this point we have a fully constructed TSurface
1.508 + //add surface to head of surfaces list
1.509 +
1.510 + //Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index
1.511 + //add the new surface to the beginning of the list
1.512 + TInt index = SurfaceIdToIndex(sid);
1.513 + surface->iNext = iSurfacesIndex[index];
1.514 + iSurfacesIndex[index] = surface;
1.515 + NKern::FMSignal(&iMutex);
1.516 + NKern::ThreadLeaveCS();
1.517 +
1.518 + //write surface id back to user side
1.519 + kumemput(reinterpret_cast<TSurfaceId*>(param.iSurfaceId), &sid, sizeof (TSurfaceId));
1.520 + return KErrNone;
1.521 + }
1.522 +
1.523 +
1.524 +/**
1.525 +Opens a surface. If the current process already is in the owners list, its usage count is
1.526 +incremented. If this is an open from a different process, a new surface owner object is added
1.527 +to the surface's list of owners and its usage count is set to 1.
1.528 +@param aId The surface id of the surface to be opened.
1.529 +@return KErrNone if successful, otherwise a system error code
1.530 +@internalTechnology
1.531 +*/
1.532 +TInt DSurfaceManager::OpenSurface(const TSurfaceId* aId)
1.533 + {
1.534 + TSurfaceId sid;
1.535 + //fetch surface id from user memory
1.536 + kumemget(&sid, aId, sizeof (TSurfaceId));
1.537 + NKern::ThreadEnterCS();
1.538 + TProcessListItem* owner = new TProcessListItem; //speculative creation
1.539 + TRACE(Kern::Printf("SM A %08x TProcessListItem OpenSurface", owner);)
1.540 +
1.541 + NKern::FMWait(&iMutex);
1.542 + //look it up
1.543 + TSurface* surface = FindSurfaceById(sid);
1.544 + if (!surface)
1.545 + {
1.546 + NKern::FMSignal(&iMutex);
1.547 + delete owner; //free the memory just allocated
1.548 + TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);)
1.549 + NKern::ThreadLeaveCS();
1.550 + return KErrArgument;
1.551 + }
1.552 +
1.553 + //find the owner
1.554 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.555 + if (so)
1.556 + {
1.557 + //already an owner so inc the ref count
1.558 + ++so->iCount;
1.559 + }
1.560 + else
1.561 + {
1.562 + //new process trying to open it
1.563 + if (!owner)
1.564 + {
1.565 + //the creation of the owner information object failed, out of memory
1.566 + NKern::FMSignal(&iMutex);
1.567 + NKern::ThreadLeaveCS();
1.568 + return KErrNoMemory;
1.569 + }
1.570 +
1.571 + owner->iCount = 1; //mark it open in this process
1.572 + owner->iOwningProcess = &Kern::CurrentProcess();
1.573 +
1.574 + //add the owner to the list of owners
1.575 + owner->iNext = surface->iOwners;
1.576 + surface->iOwners = owner;
1.577 + owner = NULL;
1.578 + }
1.579 + NKern::FMSignal(&iMutex);
1.580 + delete owner; //free if not used.
1.581 + TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);)
1.582 + NKern::ThreadLeaveCS();
1.583 + return KErrNone;
1.584 + }
1.585 +
1.586 +
1.587 +
1.588 +/**
1.589 +Closes a surface. Decrements the usage count in the surface owner object
1.590 +if the usage count is then zero, removes this surface owner from the surface.
1.591 +If this results in a surface with no owners, the surface is deleted and the
1.592 +surface shared chunk is closed.
1.593 +@param aId The id of the surface to be closed
1.594 +@return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface,
1.595 +KErrAccessDenied if the surface is not open in the current process, otherwise a system wide
1.596 +error code.
1.597 +@internalTechnology
1.598 +*/
1.599 +TInt DSurfaceManager::CloseSurface(const TSurfaceId* aId)
1.600 + {
1.601 +
1.602 + TSurfaceId sid;
1.603 + kumemget(&sid, aId, sizeof (TSurfaceId)); //fetch surface id from user memory
1.604 + //look it up
1.605 + NKern::ThreadEnterCS();
1.606 + NKern::FMWait(&iMutex);
1.607 + TSurface* surface = FindSurfaceById(sid);
1.608 + if (!surface)
1.609 + {
1.610 + NKern::FMSignal(&iMutex);
1.611 + NKern::ThreadLeaveCS();
1.612 + return KErrArgument;
1.613 + }
1.614 +
1.615 + //find the owner
1.616 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.617 + if (!so)
1.618 + {
1.619 + NKern::FMSignal(&iMutex);
1.620 + NKern::ThreadLeaveCS();
1.621 + return KErrAccessDenied;
1.622 + }
1.623 +
1.624 + //current process is a surface owner so decrement the open count
1.625 + TSurface* surfaceToDelete = NULL;
1.626 + TProcessListItem* ownerToDelete = NULL;
1.627 + DChunk* chunkToClose = NULL;
1.628 + if (--so->iCount == 0)
1.629 + {
1.630 + //if count is now zero remove the owner
1.631 + //surface->RemoveOwner(so);
1.632 + UnlinkListItem(&surface->iOwners, so);
1.633 + ownerToDelete = so;
1.634 +
1.635 + //check to see if the surface has any owners
1.636 + if (!surface->iOwners)
1.637 + {
1.638 + //no more owners of the surface
1.639 + chunkToClose = surface->iChunk;
1.640 +
1.641 + //remove the surface from the list
1.642 + UnlinkListItem(&(iSurfacesIndex[SurfaceIdToIndex(surface->iId)]), surface);
1.643 + surfaceToDelete = surface;
1.644 + }
1.645 + }
1.646 +
1.647 + NKern::FMSignal(&iMutex);
1.648 +
1.649 + if (chunkToClose)
1.650 + {
1.651 + //surface has no more owners so close the chunk
1.652 + Kern::ChunkClose(chunkToClose);
1.653 + }
1.654 +
1.655 + delete surfaceToDelete;
1.656 + TRACE(Kern::Printf("SM D %08x TSurface CloseSurface",surfaceToDelete);)
1.657 + delete ownerToDelete;
1.658 + TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurface",ownerToDelete);)
1.659 + NKern::ThreadLeaveCS();
1.660 +
1.661 + return KErrNone;
1.662 + }
1.663 +
1.664 +
1.665 +/**
1.666 +Maps the surface memory into the process of the calling thread. This will fail if
1.667 +the surface is not open in this process, or if the handle to the chunk cannot be created.
1.668 +@param aId The id of the surface to be mapped in.
1.669 +@return KErrNone if successful, KErrArgument if the surface ID does not refer to a
1.670 +surface, KErrAccessDenied if the surface is not open in the current process,
1.671 +KErrNotSupported if the surface is not mappable, KErrOverflow if the chunk limit has been
1.672 +exceeded in the moving memory model, otherwise a system wide error code.
1.673 +@internalTechnology
1.674 +*/
1.675 +TInt DSurfaceManager::MapSurface(const TSurfaceId* aId)
1.676 + {
1.677 + TSurfaceId sid;
1.678 + kumemget(&sid, aId, sizeof (TSurfaceId)); //fetch surface id from user memory
1.679 +
1.680 + //look it up
1.681 + NKern::ThreadEnterCS();
1.682 + NKern::FMWait(&iMutex);
1.683 + TSurface* surface = FindSurfaceById(sid);
1.684 + if (!surface)
1.685 + {
1.686 + NKern::FMSignal(&iMutex);
1.687 + NKern::ThreadLeaveCS();
1.688 + return KErrArgument; //surface id is not valid or in the list of surfaces
1.689 + }
1.690 + if(!surface->iMappable)
1.691 + {
1.692 + NKern::FMSignal(&iMutex);
1.693 + NKern::ThreadLeaveCS();
1.694 + return KErrNotSupported;
1.695 + }
1.696 +
1.697 + //find the owner
1.698 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.699 + if (!so)
1.700 + {
1.701 + NKern::FMSignal(&iMutex);
1.702 + NKern::ThreadLeaveCS();
1.703 + return KErrAccessDenied; //can't map it in, it's not open in this process
1.704 + }
1.705 +
1.706 + DChunk* chunk = surface->iChunk;
1.707 + TInt r = chunk->Open();
1.708 + NKern::FMSignal(&iMutex);
1.709 + TRACE(Kern::Printf("SM MapSurface chunk open r %d\n",r);)
1.710 +
1.711 + if (r == KErrGeneral)
1.712 + {
1.713 + NKern::ThreadLeaveCS();
1.714 + return KErrAccessDenied;
1.715 + }
1.716 +
1.717 + //if we are here, got the surface and we are the owner.
1.718 + //if we are the owner we must have it open at least once
1.719 +
1.720 + r = Kern::MakeHandleAndOpen(NULL, chunk);
1.721 + chunk->Close(NULL);
1.722 + TRACE(Kern::Printf("SM MapSurface handle open r: %d\n",r);)
1.723 +
1.724 + NKern::ThreadLeaveCS();
1.725 +
1.726 + return r;
1.727 + }
1.728 +
1.729 +
1.730 +/**
1.731 +Record a new connection to the driver.
1.732 +Adds an element to the reference counted list of connected processes if the connection
1.733 +is from a new process, otherwise it increments the reference count.
1.734 +@param aProcess The process which has opened a driver channel.
1.735 +@internalTechnology
1.736 +*/
1.737 +TInt DSurfaceManager::AddConnection(const DProcess* aProcess)
1.738 + {
1.739 + TRACE(Kern::Printf("SM AddConnection process %08x\n", aProcess);)
1.740 + NKern::ThreadEnterCS();
1.741 + TProcessListItem* connectedProcess = new TProcessListItem; //speculative creation
1.742 + TRACE(Kern::Printf("SM A %08x TProcessListItem AddConnection", connectedProcess);)
1.743 + NKern::FMWait(&iMutex);
1.744 + TProcessListItem* p = FindConnectedProcess(aProcess);
1.745 + if (p) //already connected, found the process
1.746 + {
1.747 + ++p->iCount;
1.748 + }
1.749 + else
1.750 + {
1.751 + //add a new connected process
1.752 + if (!connectedProcess)
1.753 + {
1.754 + //the creation of the owner information object failed, out of memory
1.755 + NKern::FMSignal(&iMutex);
1.756 + NKern::ThreadLeaveCS();
1.757 + return KErrNoMemory;
1.758 + }
1.759 + connectedProcess->iOwningProcess = (DProcess*)aProcess;
1.760 + connectedProcess->iCount=1;
1.761 +
1.762 + connectedProcess->iNext = iConnectedProcesses;
1.763 + iConnectedProcesses = connectedProcess;
1.764 + connectedProcess = NULL;
1.765 + }
1.766 + NKern::FMSignal(&iMutex);
1.767 + delete connectedProcess;
1.768 + TRACE(Kern::Printf("SM D %08x TProcessListItem AddConnection", connectedProcess);)
1.769 + NKern::ThreadLeaveCS();
1.770 + return KErrNone;
1.771 + }
1.772 +
1.773 +
1.774 +
1.775 +/**
1.776 +Called when the driver channel is closed.
1.777 +Decrements the reference count for the connected process, if the last connection
1.778 +for this process is closed (reference count reaches 0) it removes the process from the list.
1.779 +@param aProcess The process which has closed the driver channel.
1.780 +@internalTechnology
1.781 +*/
1.782 +void DSurfaceManager::RemoveConnection(const DProcess* aProcess)
1.783 + {
1.784 + TRACE(Kern::Printf("SM RemoveConnection process %08x\n", aProcess);)
1.785 + NKern::ThreadEnterCS();
1.786 + NKern::FMWait(&iMutex);
1.787 + TProcessListItem* p =FindConnectedProcess(aProcess);
1.788 + TProcessListItem* toDelete = NULL;
1.789 + if (p) //already connected, found the process
1.790 + {
1.791 + if (--p->iCount == 0) //last connection in process has disconnected
1.792 + {
1.793 + //remove the process from the list and cleanup
1.794 + UnlinkListItem(&iConnectedProcesses, p);
1.795 + toDelete = p;
1.796 + }
1.797 + }
1.798 + NKern::FMSignal(&iMutex);
1.799 + delete toDelete;
1.800 + TRACE(Kern::Printf("SM D %08x TProcessListItem RemoveConnection ", toDelete);)
1.801 +
1.802 +
1.803 + if (toDelete) // if a process has closed its last channel, remove process from the surface owners.
1.804 + {
1.805 + CloseSurfaceHandlesForProcess(aProcess);
1.806 + }
1.807 +
1.808 + NKern::ThreadLeaveCS();
1.809 + }
1.810 +
1.811 +
1.812 +
1.813 +
1.814 +/**
1.815 +Closes all the surfaces belonging to the process which has just terminated.
1.816 +If this is the only owner of a surface, delete the surface.
1.817 +@param aProcess The process which has terminated.
1.818 +@pre must be called in critical section
1.819 +@internalTechnology
1.820 +*/
1.821 +void DSurfaceManager::CloseSurfaceHandlesForProcess(const DProcess* aProcess)
1.822 + {
1.823 +
1.824 + NKern::FMWait(&iMutex);
1.825 +
1.826 + TSurface* p = NULL;
1.827 + TSurface* surfacesTodelete = NULL;
1.828 + TProcessListItem* ownersTodelete = NULL;
1.829 + TProcessListItem* so;
1.830 + // There are 16 doubly linked lists managed by Surface Manager
1.831 + for (TInt index = 0; index < KMaxLists; index++)
1.832 + {
1.833 + p = iSurfacesIndex[index];
1.834 + while(p)
1.835 + {
1.836 + //see if the process which has just died is an owner of any surfaces
1.837 + TSurface* surface = p;
1.838 + p=p->iNext;
1.839 + so = surface->ProcessOwnerInfo(aProcess);
1.840 + if (so)
1.841 + {
1.842 + UnlinkListItem(&surface->iOwners, so);
1.843 + so->iNext = ownersTodelete; //add the owner to the list of owner objects to remove
1.844 + ownersTodelete = so;
1.845 +
1.846 + if (!surface->iOwners) //if the surface hasn't any owners
1.847 + {
1.848 + //remove the surface from the list
1.849 + UnlinkListItem(&iSurfacesIndex[index], surface);
1.850 + surface->iNext = surfacesTodelete; //add the surface to the list of surfaces to remove
1.851 + surfacesTodelete = surface;
1.852 + }
1.853 + }
1.854 + }
1.855 + }
1.856 + NKern::FMSignal(&iMutex);
1.857 +
1.858 + while(surfacesTodelete)
1.859 + {
1.860 + p = surfacesTodelete->iNext;
1.861 + Kern::ChunkClose(surfacesTodelete->iChunk);
1.862 + TRACE(Kern::Printf("SM Close chunk %08x CloseSurfaceHandlesForProcess",surfacesTodelete->iChunk);)
1.863 + delete surfacesTodelete;
1.864 + TRACE(Kern::Printf("SM D %08x TSurface CloseSurfaceHandlesForProcess",surfacesTodelete);)
1.865 + surfacesTodelete = p;
1.866 + }
1.867 +
1.868 + while(ownersTodelete)
1.869 + {
1.870 + so = ownersTodelete->iNext;
1.871 + delete ownersTodelete;
1.872 + TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurfaceHandlesForProcess",ownersTodelete);)
1.873 + ownersTodelete = so;
1.874 + }
1.875 + }
1.876 +
1.877 +
1.878 +/**
1.879 +Returns the metadata information about the specified surface.
1.880 +@param aId The id of the surface.
1.881 +@param aInfo Pointer to user side descriptor to receive the information.
1.882 +@return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface,
1.883 +KErrAccessDenied if the surface is not open in the current process, otherwise a system wide
1.884 +error code.
1.885 +@internalTechnology
1.886 +*/
1.887 +TInt DSurfaceManager::SurfaceInfo(const TSurfaceId* aId, TDes8* aInfo)
1.888 + {
1.889 + TSurfaceId sid;
1.890 + //fetch surface id from user memory
1.891 + kumemget(&sid, aId, sizeof (TSurfaceId));
1.892 +
1.893 + RSurfaceManager::TInfoBuf buf;
1.894 + RSurfaceManager::TSurfaceInfoV01& info = buf();
1.895 +
1.896 + NKern::FMWait(&iMutex);
1.897 + //look it up
1.898 + TSurface* surface = FindSurfaceById(sid);
1.899 + if (!surface)
1.900 + {
1.901 + NKern::FMSignal(&iMutex);
1.902 + return KErrArgument;
1.903 + }
1.904 +
1.905 + //find the owner
1.906 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.907 + if (!so)
1.908 + {
1.909 + NKern::FMSignal(&iMutex);
1.910 + return KErrAccessDenied; //can do this, not open
1.911 + }
1.912 +
1.913 + //at this point, we have a surface, we are the owner and it's mapped in
1.914 + info.iSize = surface->iSize; // Visible width/height in pixels
1.915 + info.iBuffers = surface->iBuffers; // Number of Buffers
1.916 + info.iPixelFormat = surface->iPixelFormat; // pixel format
1.917 + info.iStride = surface->iStride; // Number of bytes between start of one line and start of next
1.918 + info.iContiguous = surface->iContiguous; // is it physically contiguous
1.919 + info.iCacheAttrib = surface->iCacheAttrib; // Underlying chunk is CPU cached or not
1.920 + info.iMappable = surface->iMappable; // Is the surface Mappable
1.921 + NKern::FMSignal(&iMutex);
1.922 +
1.923 + //copy it back to user side
1.924 + Kern::InfoCopy(*aInfo, buf);
1.925 + return KErrNone;
1.926 + }
1.927 +
1.928 +
1.929 +
1.930 +/**
1.931 +Generates a unique surface id
1.932 +@param aId Surface id reference to receive the generated id.
1.933 +@internalTechnology
1.934 +*/
1.935 +void DSurfaceManager::GenerateSurfaceId(TSurfaceId& aId)
1.936 + {
1.937 + TSurfaceId id;
1.938 +
1.939 + for (TInt x = 0; x < 4; ++x)
1.940 + {
1.941 + id.iInternal[x] = Kern::Random();
1.942 + };
1.943 +
1.944 + //package up the handle,
1.945 + //set the type identifier
1.946 + id.iInternal[3] &= 0x00FFFFFF;
1.947 + id.iInternal[3] |= TSurfaceTypes::ESurfaceManagerSurface << 24;
1.948 + aId = id;
1.949 + TRACE(Kern::Printf("SM GenerateSurfaceId id = %u %u %u %u\n",id.iInternal[0],id.iInternal[1],id.iInternal[2],id.iInternal[3]);)
1.950 + };
1.951 +
1.952 +
1.953 +
1.954 +/**
1.955 +Validates the surface creation attributes and calculates the size of the chunk required.
1.956 +@param aAttribs The surface creation attributes used to specify the surface requirements.
1.957 +@param aOffset Set to the offset between buffers on successfull return.
1.958 +@param aNewChunk If this is true, surface is created in a new chunk otherwise the surface is created in an existing chunk
1.959 +@return The size of chunk required. A size of 0 indicates a problem.
1.960 +*/
1.961 +TInt DSurfaceManager::ValidateAndCalculateChunkSize(RSurfaceManager::TSurfaceCreationAttributes& aAttribs,
1.962 + TInt& aOffset, TUint &aActualBufferSize, const TBool aNewChunk)
1.963 + {
1.964 +/*
1.965 + TRACE(Kern::Printf("SM width = %d height = %d\n", aAttribs.iSize.iWidth, aAttribs.iSize.iHeight);)
1.966 + TRACE(Kern::Printf("SM buffers = %d\n", aAttribs.iBuffers);)
1.967 + TRACE(Kern::Printf("SM format = %d\n", aAttribs.iPixelFormat);)
1.968 + TRACE(Kern::Printf("SM stride = %d\n", aAttribs.iStride);)
1.969 + TRACE(Kern::Printf("SM offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);)
1.970 + TRACE(Kern::Printf("SM offset between buffer = %d\n", aOffset);)
1.971 + TRACE(Kern::Printf("SM alignment = %d\n", aAttribs.iAlignment);)
1.972 + TRACE(Kern::Printf("SM contiguous = %d\n\n", aAttribs.iContiguous);)
1.973 + TRACE(Kern::Printf("SM cacheAttrib = %d\n\n", aAttribs.iCacheAttrib);)
1.974 +*/
1.975 + //check for negative values
1.976 + if(aAttribs.iOffsetToFirstBuffer < 0 || aOffset < 0 )
1.977 + {
1.978 + TRACE(Kern::Printf("SM Validate offset for negative value");)
1.979 + return 0;
1.980 + }
1.981 +
1.982 + //check aligment is sensible
1.983 + TInt alignmentMask = 0;
1.984 + switch(aAttribs.iAlignment)
1.985 + {
1.986 + case 1:
1.987 + case 2:
1.988 + case 4:
1.989 + case 8:
1.990 + case 16:
1.991 + case 32:
1.992 + alignmentMask = 31;
1.993 + break;
1.994 + case 64:
1.995 + alignmentMask = 63;
1.996 + break;
1.997 + case RSurfaceManager::EPageAligned:
1.998 + break;
1.999 + default:
1.1000 + TRACE(Kern::Printf("SM Validate alignment");)
1.1001 + return 0;
1.1002 + }
1.1003 +
1.1004 + //check alignment issues.
1.1005 + if(aAttribs.iAlignment != RSurfaceManager::EPageAligned)
1.1006 + {
1.1007 + if(aNewChunk)
1.1008 + {
1.1009 + if(aAttribs.iCacheAttrib == RSurfaceManager::ECached) // Surface is CPU cached, so the alignment will be based on either 32 or 64 byte
1.1010 + {
1.1011 + //offset to first buffer needs to fit alignment
1.1012 + aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignmentMask & ~alignmentMask;
1.1013 + //alignment with respect to offsetbetweenbuffers
1.1014 + aOffset = aOffset + alignmentMask & ~alignmentMask;
1.1015 + }
1.1016 + else // Surface is NOT CPU cached, so the alignment will be based on surface attribute alignment
1.1017 + {
1.1018 + TUint alignMask = aAttribs.iAlignment-1;
1.1019 + //offset to first buffer needs to fit alignment
1.1020 + aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignMask & ~alignMask;
1.1021 + //alignment with respect to offsetbetweenbuffers
1.1022 + aOffset = aOffset + alignMask & ~alignMask;
1.1023 + }
1.1024 + }
1.1025 + else // existing chunk
1.1026 + {
1.1027 + TUint alignMask = aAttribs.iAlignment-1;
1.1028 + //check alignment issues. offset to first buffer needs to fit alignment
1.1029 + if (aAttribs.iOffsetToFirstBuffer & alignMask)
1.1030 + {
1.1031 + TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");)
1.1032 + return 0;
1.1033 + }
1.1034 +
1.1035 + //check alignment for offsetbetweenbuffers. offset between buffer needs to fit alignment for existing chunks
1.1036 + if (aOffset & alignMask)
1.1037 + {
1.1038 + TRACE(Kern::Printf("SM Validate offset between buffers misaligned");)
1.1039 + return 0;
1.1040 + }
1.1041 + }
1.1042 + }
1.1043 + else //page aligned
1.1044 + {
1.1045 + if(aNewChunk)// if its a new chunks and doesn't match exact alignment then do the rounding
1.1046 + {
1.1047 + TUint32 pageSize = Kern::RoundToPageSize(1);
1.1048 + //offset to first buffer needs to fit alignment
1.1049 + aAttribs.iOffsetToFirstBuffer = (aAttribs.iOffsetToFirstBuffer + (pageSize - 1)) & ~(pageSize - 1);
1.1050 + //alignment with respect to offsetbetweenbuffers
1.1051 + aOffset = (aOffset + (pageSize - 1)) & ~((pageSize - 1));
1.1052 + }
1.1053 + else // for existing chunks don't do any rounding operation
1.1054 + {
1.1055 + TUint32 pageSize = Kern::RoundToPageSize(1);
1.1056 + TUint alignmask = aAttribs.iOffsetToFirstBuffer & (pageSize - 1);
1.1057 + if (alignmask)
1.1058 + {
1.1059 + TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");)
1.1060 + return 0;
1.1061 + }
1.1062 +
1.1063 + alignmask = aOffset & (pageSize - 1);
1.1064 + if (alignmask)
1.1065 + {
1.1066 + TRACE(Kern::Printf("SM Validate offset between buffers misaligned");)
1.1067 + return 0;
1.1068 + }
1.1069 + }
1.1070 + }
1.1071 +
1.1072 + //check width and height
1.1073 + if(aAttribs.iSize.iWidth <= 0 || aAttribs.iSize.iHeight <= 0)
1.1074 + {
1.1075 + TRACE(Kern::Printf("SM Validate width/height");)
1.1076 + return 0;
1.1077 + }
1.1078 +
1.1079 +
1.1080 + //check there is at least 1 buffer
1.1081 + if (aAttribs.iBuffers <= 0)
1.1082 + {
1.1083 + TRACE(Kern::Printf("SM Validate buffers");)
1.1084 + return 0;
1.1085 + }
1.1086 +
1.1087 + //Sort the array and also check for duplication
1.1088 + if (!SortHints(aAttribs.iSurfaceHints,aAttribs.iHintCount))
1.1089 + {
1.1090 + TRACE(Kern::Printf("SM Validate Duplicate hint key");)
1.1091 + return 0;
1.1092 + }
1.1093 +
1.1094 + TUint size = 0;
1.1095 + //calculate buffer size and round it to alignment or to page size
1.1096 + TInt64 bufferSize = aAttribs.iStride;
1.1097 + bufferSize *= aAttribs.iSize.iHeight;
1.1098 +
1.1099 + if (I64HIGH(bufferSize) > 0) //too big
1.1100 + {
1.1101 + TRACE(Kern::Printf("SM Validate chunk buffer size is out of range");)
1.1102 + return 0;
1.1103 + }
1.1104 +
1.1105 + TUint bsize = I64LOW(bufferSize);
1.1106 + if (bsize > KMaxTInt)
1.1107 + {
1.1108 + TRACE(Kern::Printf("SM Validate buffer size is out of range for TInt");)
1.1109 + return 0;
1.1110 + }
1.1111 +
1.1112 + if(aAttribs.iAlignment == RSurfaceManager::EPageAligned)
1.1113 + {
1.1114 + bsize = Kern::RoundToPageSize(bsize); //page alignment
1.1115 + }
1.1116 + else if(aAttribs.iCacheAttrib == RSurfaceManager::ECached)
1.1117 + {
1.1118 + bsize = bsize + alignmentMask & ~alignmentMask; //CPU cached byte alignment, for minimum of the specified alignment(32 or 64)
1.1119 + }
1.1120 + else
1.1121 + {
1.1122 + bsize = bsize + (aAttribs.iAlignment-1) & ~(aAttribs.iAlignment-1); //NON CPU cached byte alignment for 1, 2, 4, 8, 16, 32 and 64
1.1123 + }
1.1124 +
1.1125 + bufferSize = bsize;
1.1126 + // Remember the actual size.
1.1127 + aActualBufferSize = bsize;
1.1128 +
1.1129 + //if offset between buffers is zero, then assign the calculated value as offset between buffers
1.1130 + if(aOffset == 0)
1.1131 + {
1.1132 + //buffer size rounded to alignment as offset between buffers
1.1133 + aOffset = I64INT(bufferSize);
1.1134 + }
1.1135 + else if(aOffset < I64INT(bufferSize))
1.1136 + {
1.1137 + TRACE(Kern::Printf("SM Offset between the buffer is less than the required size");)
1.1138 + return 0;
1.1139 + }
1.1140 + else
1.1141 + {
1.1142 + //use the buffer size specified
1.1143 + bufferSize = aOffset;
1.1144 + }
1.1145 +
1.1146 +
1.1147 + TInt64 totalSize = aAttribs.iOffsetToFirstBuffer + (aAttribs.iBuffers * bufferSize);
1.1148 +
1.1149 + if (I64HIGH(totalSize) > 0) //too big
1.1150 + {
1.1151 + TRACE(Kern::Printf("SM Validate chunk size is out of range for RoundToPageSize");)
1.1152 + return 0;
1.1153 + }
1.1154 +
1.1155 + size = I64LOW(totalSize);
1.1156 + if (size > KMaxTInt)
1.1157 + {
1.1158 + TRACE(Kern::Printf("SM Validate size is out of range for TInt");)
1.1159 + return 0;
1.1160 + }
1.1161 +
1.1162 + size = Kern::RoundToPageSize(size);
1.1163 +
1.1164 + //check the size isn't greater than will fit in a TInt
1.1165 + if (size > KMaxTInt)
1.1166 + {
1.1167 + TRACE(Kern::Printf("SM Rounded size is out of range for TInt");)
1.1168 + return 0;
1.1169 + }
1.1170 +
1.1171 + TRACE(Kern::Printf("SM After validate - offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);)
1.1172 + TRACE(Kern::Printf("SM After validate - offset between buffer = %d\n", aOffset);)
1.1173 + TRACE(Kern::Printf("SM CalculateChunkSize size = %d\n", size);)
1.1174 + return size;
1.1175 + }
1.1176 +
1.1177 +
1.1178 +/**
1.1179 +Find the surface in the list.
1.1180 +@param aId The surface id of the surface to find in the surface list
1.1181 +@return pointer to the surface object
1.1182 +@internalTechnology
1.1183 +*/
1.1184 +TSurface* DSurfaceManager::FindSurfaceById(const TSurfaceId& aId)
1.1185 + {
1.1186 + TSurface *p = iSurfacesIndex[SurfaceIdToIndex(aId)];
1.1187 + while (p)
1.1188 + {
1.1189 + if (aId == p->iId)
1.1190 + {
1.1191 + //found it
1.1192 + return p;
1.1193 + }
1.1194 +
1.1195 + p = p->iNext;
1.1196 + }
1.1197 + return NULL;
1.1198 + }
1.1199 +
1.1200 +
1.1201 +/**
1.1202 +Find the index of the hint key from the surface list using binary search.
1.1203 +@param aHintsArray Pointer to the first element in the array of surface hints
1.1204 +@param aKey The surface hint key uid value to search in the surface list
1.1205 +@return index of the hint pair key in the surface list, KErrNotFound if key not found
1.1206 +@internalTechnology
1.1207 +*/
1.1208 +TInt DSurfaceManager::FindHintKey(const RSurfaceManager::THintPair* aHintsArray, TUint32 aKey) const
1.1209 + {
1.1210 + __ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__));
1.1211 +
1.1212 + TInt bottom = 0;
1.1213 + TInt top = KMaxHintsPerSurface - 1;
1.1214 + TInt mid;
1.1215 + while (bottom <= top)
1.1216 + {
1.1217 + mid = (bottom + top) / 2;
1.1218 + if((TUint) aHintsArray[mid].iKey.iUid == aKey)
1.1219 + {
1.1220 + return mid;
1.1221 + }
1.1222 + else if ((TUint)aHintsArray[mid].iKey.iUid < aKey)
1.1223 + {
1.1224 + top = mid - 1;
1.1225 + }
1.1226 + else
1.1227 + {
1.1228 + bottom = mid + 1;
1.1229 + }
1.1230 + }
1.1231 + return KErrNotFound; //Hint key not found
1.1232 + }
1.1233 +
1.1234 +TProcessListItem* DSurfaceManager::FindConnectedProcess(const DProcess* aProcess)
1.1235 + {
1.1236 + TProcessListItem * p = iConnectedProcesses;
1.1237 + while (p)
1.1238 + {
1.1239 + if (aProcess == p->iOwningProcess)
1.1240 + {
1.1241 + //found it
1.1242 + return p;
1.1243 + }
1.1244 +
1.1245 + p = p->iNext;
1.1246 + }
1.1247 + return NULL;
1.1248 + }
1.1249 +
1.1250 +/**
1.1251 +Searches for a right place to insert the new hint pair in a sorted array.
1.1252 +@param aHintsArray Pointer to the first element in the sorted array
1.1253 +@param aKey The surface hint key uid value to search in the surface list
1.1254 +@pre, there is at least one empty place in the array
1.1255 +@return KErrNone if a new hint pair key inserted in the surface list, KErrAlreadyExists if duplicated
1.1256 +@internalTechnology
1.1257 +*/
1.1258 +TInt DSurfaceManager::InsertHintKey(RSurfaceManager::THintPair* aHintsArray, const RSurfaceManager::THintPair& aHintPair) const
1.1259 + {
1.1260 + __ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__));
1.1261 + __ASSERT_DEBUG(aHintsArray[KMaxHintsPerSurface-1].iKey.iUid == NULL, Kern::Fault("Surface Manager", __LINE__));
1.1262 +
1.1263 + TInt pos = 0;
1.1264 + if (aHintsArray[pos].iKey.iUid != 0)
1.1265 + {
1.1266 + while((TUint)aHintsArray[pos].iKey.iUid>(TUint)aHintPair.iKey.iUid && pos < KMaxHintsPerSurface-1)
1.1267 + {// find the right place to insert
1.1268 + ++pos;
1.1269 + }
1.1270 +
1.1271 + if((TUint)aHintsArray[pos].iKey.iUid==(TUint)aHintPair.iKey.iUid)
1.1272 + {
1.1273 + //Duplicate key
1.1274 + return KErrAlreadyExists;
1.1275 + }
1.1276 + else
1.1277 + {
1.1278 + // Shift right
1.1279 + memmove(aHintsArray+pos+1, aHintsArray+pos, (KMaxHintsPerSurface-pos-1)*sizeof(RSurfaceManager::THintPair));
1.1280 + }
1.1281 + }
1.1282 + aHintsArray[pos] = aHintPair;
1.1283 + return KErrNone;
1.1284 + }
1.1285 +
1.1286 +/**
1.1287 +Sort the surface hint array in descending order.
1.1288 +@param aHintsArray The surface hintpair in the surface list
1.1289 +@param aNumberOfHints The number of hints
1.1290 +@return ETrue if sorting is finished or it is an empty array, EFalse if key duplicated
1.1291 +@internalTechnology
1.1292 +*/
1.1293 +TBool DSurfaceManager::SortHints(RSurfaceManager::THintPair* aHintsArray, TInt aNumberOfHints) const
1.1294 + {
1.1295 + TInt in = 0;
1.1296 + TInt out = 0;
1.1297 + RSurfaceManager::THintPair temp;
1.1298 + if(!aHintsArray)
1.1299 + {
1.1300 + return ETrue;
1.1301 + }
1.1302 + for(out = 0; out < aNumberOfHints; ++out)
1.1303 + {
1.1304 + if(aHintsArray[out].iKey.iUid != 0)
1.1305 + {
1.1306 + temp = aHintsArray[out];
1.1307 + in = out; // start shifting at out
1.1308 + while(in > 0 && (TUint)aHintsArray[in-1].iKey.iUid <= (TUint)temp.iKey.iUid)
1.1309 + {
1.1310 + if ((TUint)aHintsArray[in-1].iKey.iUid == (TUint)temp.iKey.iUid)
1.1311 + {
1.1312 + return EFalse; //duplicate hint keys are not allowed
1.1313 + }
1.1314 + aHintsArray[in] = aHintsArray[in-1]; // shift item to the right
1.1315 + --in; // go left one position
1.1316 + }
1.1317 + aHintsArray[in] = temp; // insert marked item
1.1318 + }
1.1319 + }
1.1320 + return ETrue;
1.1321 + }
1.1322 +
1.1323 +
1.1324 +/**
1.1325 +Ensures the memory is updated consistently before/after triggering non CPU hardware access.
1.1326 +@param aParam The suface id and buffer number (0 based).
1.1327 +@param aOperation The type of the synchronize operation.
1.1328 +@return KErrNone if successful, KErrArgument if the surface ID is invalid or
1.1329 +buffer number is invalid, KErrAccessDenied if the surface is not open in this
1.1330 +process, otherwise a system wide error code.
1.1331 +@see RSurfaceManager::TSyncOperation
1.1332 +@internalTechnology
1.1333 +*/
1.1334 +TInt DSurfaceManager::SynchronizeCache(RSurfaceManagerDriver::TDeviceParam* aParam, RSurfaceManager::TSyncOperation aOperation)
1.1335 + {
1.1336 + //Parse the parameters
1.1337 + RSurfaceManagerDriver::TDeviceParam param;
1.1338 + kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
1.1339 + TSurfaceId sid;
1.1340 + kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId));
1.1341 + TInt buffer = (TInt)param.iBuffer;
1.1342 +
1.1343 + NKern::ThreadEnterCS();
1.1344 + NKern::FMWait(&iMutex);
1.1345 + //look it up
1.1346 + TSurface* surface = FindSurfaceById(sid);
1.1347 + if (!surface)
1.1348 + {
1.1349 + NKern::FMSignal(&iMutex);
1.1350 + NKern::ThreadLeaveCS();
1.1351 + return KErrArgument;
1.1352 + }
1.1353 +
1.1354 + //find the owner
1.1355 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.1356 + if (!so)
1.1357 + {
1.1358 + NKern::FMSignal(&iMutex);
1.1359 + NKern::ThreadLeaveCS();
1.1360 + return KErrAccessDenied;
1.1361 + }
1.1362 +
1.1363 + // surfaces have to have at least one buffer
1.1364 + __ASSERT_DEBUG(surface->iBuffers > 0, Kern::Fault("Surface Manager", __LINE__));
1.1365 +
1.1366 + //Validate the buffer number is within range
1.1367 + if((buffer >= surface->iBuffers) || (buffer < 0))
1.1368 + {
1.1369 + NKern::FMSignal(&iMutex);
1.1370 + NKern::ThreadLeaveCS();
1.1371 + return KErrArgument;
1.1372 + }
1.1373 +
1.1374 + DChunk* chunk = surface->iChunk;
1.1375 + TInt offsetBetweenBuffers = surface->iOffsetBetweenBuffers;
1.1376 + NKern::FMSignal(&iMutex);
1.1377 +
1.1378 + TUint32 kernAddr;
1.1379 + TUint32 mapAttr;
1.1380 + TUint32 physAddr;
1.1381 + TInt pageList = chunk->iSize / Kern::RoundToPageSize(1) + 1;
1.1382 + TUint32* physAddr2 = new TUint32[pageList];
1.1383 + if(!physAddr2)
1.1384 + {
1.1385 + NKern::ThreadLeaveCS();
1.1386 + return KErrNoMemory;
1.1387 + }
1.1388 +
1.1389 + TRACE(Kern::Printf("SM %08x DChunk SynchronizeCache", chunk);)
1.1390 +
1.1391 + //Retrieve the kernel address and mapping attribute from the chunk
1.1392 + TInt err = Kern::ChunkPhysicalAddress(chunk, surface->iOffsetToFirstBuffer + (buffer * offsetBetweenBuffers), offsetBetweenBuffers, kernAddr, mapAttr, physAddr, physAddr2);
1.1393 + delete[] physAddr2;
1.1394 + if(err >= KErrNone)
1.1395 + {
1.1396 + TRACE(Kern::Printf("SM %08x kernAddr SynchronizeCache", kernAddr);)
1.1397 + TRACE(Kern::Printf("SM %08x mapAttr SynchronizeCache", mapAttr);)
1.1398 + err = KErrNone;
1.1399 +
1.1400 + // Do the sync operation
1.1401 + switch(aOperation)
1.1402 + {
1.1403 + case RSurfaceManager::ESyncBeforeNonCPURead:
1.1404 + Cache::SyncMemoryBeforeDmaWrite(kernAddr, offsetBetweenBuffers, mapAttr);
1.1405 + break;
1.1406 + case RSurfaceManager::ESyncBeforeNonCPUWrite:
1.1407 + Cache::SyncMemoryBeforeDmaRead(kernAddr, offsetBetweenBuffers, mapAttr);
1.1408 + break;
1.1409 + case RSurfaceManager::ESyncAfterNonCPUWrite:
1.1410 + Cache::SyncMemoryAfterDmaRead(kernAddr, offsetBetweenBuffers);
1.1411 + break;
1.1412 + default:
1.1413 + err = KErrArgument;
1.1414 + break;
1.1415 + }
1.1416 + }
1.1417 + NKern::ThreadLeaveCS();
1.1418 +
1.1419 + return err;
1.1420 + }
1.1421 +
1.1422 +
1.1423 +/**
1.1424 +Get the surface hint value for the given surface ID and hint pair key.
1.1425 +@param aSurfaceId The surface identifier originally returned when the surface was created.
1.1426 +@param aHintPair The hint value for the requested hint pair key.
1.1427 +@return KErrNone if successful, KErrArgument if the surface ID is invalid or
1.1428 +invalid hint pair key used, KErrAccessDenied if the surface is not open in the
1.1429 +current process, otherwise a system wide error code.
1.1430 +@internalTechnology
1.1431 +*/
1.1432 +TInt DSurfaceManager::GetSurfaceHint(const TSurfaceId* aSurfaceId, RSurfaceManager::THintPair* aHintPair)
1.1433 + {
1.1434 + RSurfaceManager::THintPair hintPair;
1.1435 + kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
1.1436 +
1.1437 + if (hintPair.iKey.iUid == 0)
1.1438 + {
1.1439 + TRACE(Kern::Printf("SM GetSurfaceHint Hint key is invalid");)
1.1440 + return KErrArgument; //Invalid Hint key
1.1441 + }
1.1442 +
1.1443 + TSurfaceId sid;
1.1444 + //fetch surface id from user memory
1.1445 + kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
1.1446 +
1.1447 + NKern::FMWait(&iMutex);
1.1448 + //look it up
1.1449 + TSurface* surface = FindSurfaceById(sid);
1.1450 + if (!surface)
1.1451 + {
1.1452 + NKern::FMSignal(&iMutex);
1.1453 + return KErrArgument;
1.1454 + }
1.1455 +
1.1456 + //find the owner
1.1457 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.1458 + if (!so)
1.1459 + {
1.1460 + NKern::FMSignal(&iMutex);
1.1461 + return KErrAccessDenied;
1.1462 + }
1.1463 +
1.1464 + //at this point, we have a surface, we have to find the hint value based on the hint pair key
1.1465 + TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid);
1.1466 +
1.1467 + if (index == KErrNotFound)
1.1468 + {
1.1469 + TRACE(Kern::Printf("SM GetSurfaceHint Hint key not found");)
1.1470 + NKern::FMSignal(&iMutex);
1.1471 + return KErrArgument; //Hint key not found
1.1472 + }
1.1473 +
1.1474 + RSurfaceManager::THintPair hint = surface->iSurfaceHints[index];
1.1475 + NKern::FMSignal(&iMutex);
1.1476 +
1.1477 + TRACE(Kern::Printf("SM GetSurfaceHint Hint value %d", hint.iValue);)
1.1478 + //write it back to user side
1.1479 + kumemput(aHintPair, &hint, sizeof(RSurfaceManager::THintPair));
1.1480 + return KErrNone;
1.1481 + }
1.1482 +
1.1483 +
1.1484 +/**
1.1485 +Set the surface hint value for an existing surface hint key of the surface Id.
1.1486 +@param aSurfaceId The surface identifier originally returned when the surface was created.
1.1487 +@param aHintPair The value of the hint pair to set.
1.1488 +@return KErrNone if successful, KErrArgument if the surface ID is invalid or if invalid
1.1489 +hint key used, KErrAccessDenied if the hint pair is immutable or the surface is not open
1.1490 +in the current process, otherwise a system wide error code.
1.1491 +@internalTechnology
1.1492 +*/
1.1493 +TInt DSurfaceManager::SetSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair)
1.1494 + {
1.1495 + RSurfaceManager::THintPair hintPair;
1.1496 + kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
1.1497 +
1.1498 + //Check for valid hint key
1.1499 + if (!hintPair.iKey.iUid)
1.1500 + {
1.1501 + TRACE(Kern::Printf("SM SetSurfaceHint Hint key is invalid");)
1.1502 + return KErrArgument; //Invalid Hint key
1.1503 + }
1.1504 +
1.1505 + TSurfaceId sid;
1.1506 + //fetch surface id from user memory
1.1507 + kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
1.1508 +
1.1509 + NKern::ThreadEnterCS();
1.1510 + NKern::FMWait(&iMutex);
1.1511 + //look it up
1.1512 + TSurface* surface = FindSurfaceById(sid);
1.1513 + if (!surface)
1.1514 + {
1.1515 + NKern::FMSignal(&iMutex);
1.1516 + NKern::ThreadLeaveCS();
1.1517 + return KErrArgument;
1.1518 + }
1.1519 +
1.1520 + //find the owner
1.1521 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.1522 + if (!so)
1.1523 + {
1.1524 + NKern::FMSignal(&iMutex);
1.1525 + NKern::ThreadLeaveCS();
1.1526 + return KErrAccessDenied;
1.1527 + }
1.1528 +
1.1529 + //at this point, we have a surface, we have to find the hint value based on the hint pair key
1.1530 + TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid);
1.1531 + if (index == KErrNotFound)
1.1532 + {
1.1533 + TRACE(Kern::Printf("SM SetSurfaceHint Hint key not found or invalid");)
1.1534 + NKern::FMSignal(&iMutex);
1.1535 + NKern::ThreadLeaveCS();
1.1536 + return KErrArgument; //Hint key not found or invalid
1.1537 + }
1.1538 +
1.1539 + //Check for mutability
1.1540 + if(!surface->iSurfaceHints[index].iMutable)
1.1541 + {
1.1542 + TRACE(Kern::Printf("SM SetSurfaceHint Hint is immutable");)
1.1543 + NKern::FMSignal(&iMutex);
1.1544 + NKern::ThreadLeaveCS();
1.1545 + return KErrAccessDenied; //Hint pair is immutable
1.1546 + }
1.1547 + TRACE(Kern::Printf("SM SetSurfaceHint Hint key found and updated its value %d for the surface %08x \n", aHintPair->iValue, &sid);)
1.1548 +
1.1549 + //set the hint pair value now
1.1550 + memcpy(&surface->iSurfaceHints[index], &hintPair, sizeof(RSurfaceManager::THintPair));
1.1551 + NKern::FMSignal(&iMutex);
1.1552 + NKern::ThreadLeaveCS();
1.1553 +
1.1554 + return KErrNone;
1.1555 + }
1.1556 +
1.1557 +/**
1.1558 +Add a new surface hint value for the surface Id.
1.1559 +@param aSurfaceId The surface identifier originally returned when the surface was created.
1.1560 +@param aHintPair The value of the hint pair to Add.
1.1561 +@return Returns KErrNone if successful, KErrArgument if the surface ID is invalid or the
1.1562 +hint pair has invalid key UID, KErrAccessDenied if the surface is not open in the current
1.1563 +process, KErrAlreadyExists if duplicate hint key used, KErrOverflow if no space to add new
1.1564 +pair, otherwise a system wide error code.
1.1565 +@internalTechnology
1.1566 +*/
1.1567 +TInt DSurfaceManager::AddSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair)
1.1568 + {
1.1569 + RSurfaceManager::THintPair hintPair;
1.1570 + kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
1.1571 +
1.1572 + //Check for valid hint key
1.1573 + if (hintPair.iKey.iUid == 0)
1.1574 + {
1.1575 + TRACE(Kern::Printf("SM AddSurfaceHint Hint key is invalid");)
1.1576 + return KErrArgument; //Invalid Hint key
1.1577 + }
1.1578 +
1.1579 + TSurfaceId sid;
1.1580 + //fetch surface id from user memory
1.1581 + kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
1.1582 +
1.1583 + NKern::ThreadEnterCS();
1.1584 + NKern::FMWait(&iMutex);
1.1585 + //look it up
1.1586 + TSurface* surface = FindSurfaceById(sid);
1.1587 + if (!surface)
1.1588 + {
1.1589 + NKern::FMSignal(&iMutex);
1.1590 + NKern::ThreadLeaveCS();
1.1591 + return KErrArgument;
1.1592 + }
1.1593 +
1.1594 + //find the owner
1.1595 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.1596 + if (!so)
1.1597 + {
1.1598 + NKern::FMSignal(&iMutex);
1.1599 + NKern::ThreadLeaveCS();
1.1600 + return KErrAccessDenied;
1.1601 + }
1.1602 +
1.1603 +
1.1604 + //Check for empty hint pair
1.1605 + if(surface->iSurfaceHints[KMaxHintsPerSurface - 1].iKey.iUid != 0)//at least end of sorted hint array should be 0 to add a new hint
1.1606 + {
1.1607 + TRACE(Kern::Printf("SM AddSurfaceHint there is no room to add the hint");)
1.1608 + NKern::FMSignal(&iMutex);
1.1609 + NKern::ThreadLeaveCS();
1.1610 + return KErrOverflow; //No room for new hint
1.1611 + }
1.1612 + //We found room for a new hint pair, so insert it in the array
1.1613 + // Meanwhile, we check for duplication, if it is, return KErrAlreadyExists
1.1614 + TInt err = InsertHintKey(surface->iSurfaceHints,hintPair);
1.1615 + NKern::FMSignal(&iMutex);
1.1616 + TRACE(Kern::Printf("SM AddSurfaceHint Added new key ");)
1.1617 + NKern::ThreadLeaveCS();
1.1618 + return err;
1.1619 + }
1.1620 +
1.1621 +/**
1.1622 +Get the offset of the specified buffer from the base address of the underlying
1.1623 +chunk.
1.1624 +
1.1625 +To obtain the address of the buffer, the offset returned must be added onto the
1.1626 +base address of the RChunk returned in a call to MapSurface(). Note that
1.1627 +buffer offsets are immutable during the lifetime of the surface.
1.1628 +@param aParam The input parameters including the surface ID and buffer index.
1.1629 +@pre The surface is open in the calling process.
1.1630 +@return KErrNone if successful, KErrArgument if aSurfaceId or aBuffer are invalid,
1.1631 +KErrAccessDenied if the surface is not open in the current process, KErrNotSupported if
1.1632 +the surface is not mappable, otherwise a system wide error code.
1.1633 +*/
1.1634 +TInt DSurfaceManager::GetBufferOffset(RSurfaceManagerDriver::TDeviceParam* aParam,TUint* aOffset)
1.1635 + {
1.1636 + //Get the input parameters
1.1637 + RSurfaceManagerDriver::TDeviceParam param;
1.1638 + kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
1.1639 + TSurfaceId sid;
1.1640 + //fetch surface id from user memory
1.1641 + kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId));
1.1642 + //(TAny*)iBuffer holds the buffer number in its value
1.1643 + TInt bufferNumber = (TInt) param.iBuffer;
1.1644 +
1.1645 + TSurface* surface = NULL;
1.1646 + NKern::FMWait(&iMutex);
1.1647 + surface = FindSurfaceById(sid);
1.1648 + if(NULL == surface || (bufferNumber >= surface->iBuffers))
1.1649 + {
1.1650 + NKern::FMSignal(&iMutex);
1.1651 + return KErrArgument;
1.1652 + }
1.1653 + if(!surface->iMappable)
1.1654 + {
1.1655 + NKern::FMSignal(&iMutex);
1.1656 + return KErrNotSupported;
1.1657 + }
1.1658 + //find the owner
1.1659 + TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1.1660 + if (!so)
1.1661 + {
1.1662 + NKern::FMSignal(&iMutex);
1.1663 + return KErrAccessDenied;
1.1664 + }
1.1665 + TInt bufferOffset = surface->iOffsetToFirstBuffer + bufferNumber*surface->iOffsetBetweenBuffers;
1.1666 + NKern::FMSignal(&iMutex);
1.1667 +
1.1668 + kumemput(aOffset, &bufferOffset, sizeof (TInt));
1.1669 + return KErrNone;
1.1670 + }
1.1671 +
1.1672 +/**
1.1673 +Returns information specific to the Surface Manager implementation.
1.1674 +@param aAttrib: Attribute to retrieve
1.1675 +@param aValue : Output parameter where we write the value for the specified attribute
1.1676 +@return KErrNone if successful or KErrArgument if the attribute UID is not recognized
1.1677 +@internalTechnology
1.1678 +*/
1.1679 +TInt DSurfaceManager::GetSurfaceManagerAttrib(RSurfaceManager::TSurfaceManagerAttrib* aAttrib,TInt* aValue)
1.1680 + {
1.1681 + RSurfaceManager::TSurfaceManagerAttrib attrib;
1.1682 + kumemget(&attrib, aAttrib, sizeof(RSurfaceManager::TSurfaceManagerAttrib));
1.1683 +
1.1684 + TInt out=KErrNone;
1.1685 + TInt value;
1.1686 + switch (attrib)
1.1687 + {
1.1688 + case RSurfaceManager::EMaxNumberOfHints:
1.1689 + value=KMaxHintsPerSurface;
1.1690 + break;
1.1691 +
1.1692 + default:
1.1693 + out=KErrArgument;
1.1694 + break;
1.1695 + };
1.1696 +
1.1697 + if (out==KErrNone)
1.1698 + {
1.1699 + kumemput(aValue, &value, sizeof (TInt));
1.1700 + }
1.1701 + return out;
1.1702 + }