graphicshwdrivers/surfacemgr/src/extension.cpp
branchbug235_bringup_0
changeset 147 af143508cc47
parent 146 4d1fe4a7ce83
child 148 706129140cfc
equal deleted inserted replaced
146:4d1fe4a7ce83 147:af143508cc47
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 
       
    17 #include <kernel/kern_priv.h>
       
    18 #include <graphics/surface.h>
       
    19 #include <graphics/surfacetypes.h>
       
    20 #include <graphics/surfacemanager.h>
       
    21 #include "surfacemanager_dev.h"
       
    22 #include <kernel/cache.h>
       
    23 
       
    24 /**
       
    25 Convert the surface Id to an index of the array 
       
    26 based on the least significant 4 bits of the first word of the ID
       
    27 @param	aSurfaceId  Const reference to the surface Id
       
    28 @internalTechnology
       
    29 */
       
    30 static TInt SurfaceIdToIndex(const TSurfaceId& aSurfaceId)
       
    31 	{
       
    32 	return static_cast<TInt>(aSurfaceId.iInternal[0]&(KMaxLists-1));
       
    33 	}
       
    34 
       
    35 /**
       
    36 Removes an item from a linked list
       
    37 @param	aList  Pointer to the head of a linked list of type T
       
    38 @param	aOwner  Pointer to the object to be removed
       
    39 @internalTechnology
       
    40 */
       
    41 template<class T>
       
    42 static void UnlinkListItem(T** aList, const T* aItem)
       
    43 	{
       
    44 	TRACE(Kern::Printf("SM UnlinkListItem list %08x  object %08x \n", aList, aItem);)
       
    45 	
       
    46 	__ASSERT_DEBUG(aItem != NULL, Kern::Fault("Surface Manager", __LINE__));
       
    47 	__ASSERT_DEBUG(*aList != NULL, Kern::Fault("Surface Manager", __LINE__));
       
    48 
       
    49 	if (*aList == aItem)	//one we want is at the head of the list
       
    50 		{
       
    51 		*aList = aItem->iNext;
       
    52 		return;
       
    53 		}
       
    54 	
       
    55 	T* p = *aList;
       
    56 	T* q = (*aList)->iNext;
       
    57 	while (q)
       
    58 		{
       
    59 		if (q == aItem)
       
    60 			{
       
    61 			p->iNext = q->iNext;
       
    62 			return;
       
    63 			}
       
    64 		p = q;
       
    65 		q = q->iNext;
       
    66 		}
       
    67 	}
       
    68 
       
    69 
       
    70 
       
    71 
       
    72 /**
       
    73 Returns a pointer to the surface owner object for the specified process, for this surface.
       
    74 @param	aProcess  Pointer to the process object
       
    75 @return pointer to the surface owner object if found, else NULL
       
    76 @internalTechnology
       
    77 */
       
    78 
       
    79 TProcessListItem* TSurface::ProcessOwnerInfo(const DProcess* aProcess)
       
    80 	{
       
    81 	TProcessListItem* so = iOwners;
       
    82 	while(so)
       
    83 		{
       
    84 		if (aProcess == so->iOwningProcess)
       
    85 			{
       
    86 			break;
       
    87 			}
       
    88 		so = so->iNext;
       
    89 		}
       
    90 	return so;
       
    91 	}
       
    92 
       
    93 /**
       
    94 Creates a shared chunk surface.
       
    95 @param aParams  Package buffer containing the surface creation parameters.  
       
    96 @param aId  Will be set to the surface id of the newly created surface.
       
    97 @return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
       
    98 otherwise one of the other system wide error codes.
       
    99 @see RSurfaceManager::TSurfaceCreationAttributes
       
   100 @internalTechnology
       
   101 */
       
   102 
       
   103 TInt DSurfaceManager::CreateSurface(const TDesC8* aParams, TSurfaceId* aId)
       
   104 	{
       
   105 
       
   106 	RSurfaceManager::TSurfaceCreationAttributesBuf buf;
       
   107 	RSurfaceManager::TSurfaceCreationAttributes& attribs = buf();
       
   108 	
       
   109 	Kern::KUDesGet(buf, *aParams);		//fetch input parameters
       
   110 	if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) )
       
   111 		{
       
   112 		return KErrArgument;
       
   113 		}	
       
   114 	
       
   115 	RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface];
       
   116 	if( (attribs.iHintCount>0) && attribs.iSurfaceHints)
       
   117 		{
       
   118 		kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair));		
       
   119 		attribs.iSurfaceHints = tempSurfaceHints;
       
   120 		}
       
   121 	else
       
   122 		{
       
   123 		attribs.iSurfaceHints=NULL;
       
   124 		}
       
   125 
       
   126 	//validate input parameters and calculate chunk size
       
   127 	TInt roundedBufferSize = attribs.iOffsetBetweenBuffers;
       
   128 	TUint dummyActualSize = 0;	
       
   129 	
       
   130 	TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, dummyActualSize, ETrue);
       
   131 	if (chunkSize == 0)
       
   132 		{
       
   133 		return KErrArgument;
       
   134 		}	
       
   135 
       
   136 	TSurfaceId sid;
       
   137 	TInt r = KErrNone;
       
   138 	TSurface* surface = NULL;
       
   139 	do		//in the unlikely event that we generate a duplicate surface id, try again.
       
   140 		{
       
   141 		GenerateSurfaceId(sid);
       
   142 
       
   143 		NKern::FMWait(&iMutex);
       
   144 		surface = FindSurfaceById(sid);
       
   145 		NKern::FMSignal(&iMutex);
       
   146 		}
       
   147 	while (surface);
       
   148 	
       
   149 	//create a shared chunk for the surface memory
       
   150 	TChunkCreateInfo info;
       
   151 	info.iType = TChunkCreateInfo::ESharedKernelMultiple;	//multi process mappable
       
   152 	info.iMaxSize = chunkSize;
       
   153 	info.iOwnsMemory = ETrue;
       
   154 
       
   155 //iMapAttr is valid only for hardware devices and will not make any effect in wins	
       
   156 #ifndef __WINS__
       
   157 	info.iMapAttr = (attribs.iCacheAttrib == RSurfaceManager::ECached) ? EMapAttrCachedMax : EMapAttrL1Uncached;
       
   158 #else
       
   159 	info.iMapAttr = 0;
       
   160 #endif
       
   161 
       
   162 	TLinAddr kernAddr;
       
   163 	TUint32 mapAttr;	
       
   164 	
       
   165 	NKern::ThreadEnterCS();
       
   166 	DChunk* chunk;
       
   167 	r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr);
       
   168 	if (KErrNone != r)
       
   169 		{
       
   170 		NKern::ThreadLeaveCS();
       
   171 		return r;
       
   172 		}
       
   173 
       
   174 	//commit the memory
       
   175 	TUint32 paddr;
       
   176 	if (attribs.iContiguous)
       
   177 		{
       
   178 		r = Kern::ChunkCommitContiguous(chunk, 0, chunkSize, paddr);
       
   179 		}
       
   180 	else
       
   181 		{
       
   182 		r = Kern::ChunkCommit(chunk, 0, chunkSize);
       
   183 		}
       
   184 
       
   185 	if (KErrNone != r)
       
   186 		{
       
   187 		//problem committing the memory,
       
   188 		//destroy the chunk and cleanup
       
   189 		Kern::ChunkClose(chunk);
       
   190 		NKern::ThreadLeaveCS();
       
   191 		return r;
       
   192 		}
       
   193 
       
   194 	//create a surface structure for the new surface
       
   195 	surface = new TSurface;
       
   196 	TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);)
       
   197 	if (!surface)
       
   198 		{
       
   199 		//destroy the chunk and cleanup, out of memory
       
   200 		Kern::ChunkClose(chunk);
       
   201 		NKern::ThreadLeaveCS();
       
   202 		return KErrNoMemory;
       
   203 		}
       
   204 
       
   205 	surface->iId = sid;
       
   206 	surface->iSize = attribs.iSize;
       
   207 	surface->iBuffers = attribs.iBuffers;
       
   208 	surface->iPixelFormat = attribs.iPixelFormat;
       
   209 	surface->iStride = attribs.iStride;
       
   210 	surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer;
       
   211 	surface->iAlignment = attribs.iAlignment;
       
   212 	surface->iContiguous = attribs.iContiguous;
       
   213 	surface->iChunk = chunk;
       
   214 	surface->iOffsetBetweenBuffers = roundedBufferSize;
       
   215 	surface->iCacheAttrib = attribs.iCacheAttrib;
       
   216 	surface->iMappable = attribs.iMappable;
       
   217 	if(attribs.iHintCount>0)
       
   218 		{
       
   219 		memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
       
   220 		}
       
   221 	memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair));
       
   222 	
       
   223 	//create a surface owner for this surface
       
   224 	TProcessListItem* owner = new TProcessListItem;
       
   225 	TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);)
       
   226 
       
   227 	if (!owner)
       
   228 		{
       
   229 		//destroy the chunk and cleanup, out of memory
       
   230 		Kern::ChunkClose(chunk);
       
   231 		delete(surface);
       
   232 		TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);)
       
   233 		NKern::ThreadLeaveCS();
       
   234 		return KErrNoMemory;
       
   235 		}
       
   236 	
       
   237 	owner->iCount = 1;		//mark it as open in this process
       
   238 	owner->iOwningProcess =  &Kern::CurrentProcess();
       
   239 	owner->iNext = NULL;
       
   240 		
       
   241 	surface->iOwners = owner;	//only 1 owner at creation time
       
   242 
       
   243 	//at this point we have a fully constructed TSurface
       
   244 
       
   245 	//add surface to head of surfaces list
       
   246 	NKern::FMWait(&iMutex);
       
   247 	//Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index
       
   248 	//add the new surface to the beginning of the list 
       
   249 	TInt index = SurfaceIdToIndex(sid);
       
   250 	surface->iNext = iSurfacesIndex[index];
       
   251 	iSurfacesIndex[index] = surface;
       
   252 
       
   253 	NKern::FMSignal(&iMutex);		
       
   254 	NKern::ThreadLeaveCS();
       
   255 	
       
   256 	//write surface id back to user side
       
   257 	kumemput(aId, &sid, sizeof (TSurfaceId));
       
   258 	return KErrNone;
       
   259 	}
       
   260 
       
   261 
       
   262 /**
       
   263 Validate that a chunk contains physical memory for the used areas.
       
   264 
       
   265 This function should be called in Critical Section in order to be completed even if the thread 
       
   266 or process is killed and so be able to free the memory allocated  (TUint32[pageList])
       
   267 
       
   268 @param aChunk  Chunk that the user supplied.   
       
   269 @param aAttribs  Surface Creation Attributes.
       
   270 @param aBuffersize  Calculated size of each buffer.
       
   271 @param aMapAttr  Filled in with the mapping attributes of the memory.
       
   272 @param aIsContiguous  Lets the caller know if the surface is physically contiguous or not. 
       
   273 @return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
       
   274 KErrBadHandle if aChunkHandle is of an invalid shared chunk memory,
       
   275 otherwise one of the other system wide error codes.
       
   276 @see RSurfaceManager::TSurfaceCreationAttributes
       
   277 @internalTechnology
       
   278 */
       
   279 TInt DSurfaceManager::ValidatePhysicalMemory(DChunk* aChunk, const RSurfaceManager::TSurfaceCreationAttributes& aAttribs, 
       
   280 								   TUint aBuffersize, TUint32& aMapAttr, TBool &aIsContiguous) 
       
   281 	{
       
   282 	TLinAddr kernAddr;
       
   283 	TUint32 physAddr;
       
   284 
       
   285 	//Get the physical address for a region in a shared chunk
       
   286 	TInt pageSize = Kern::RoundToPageSize(1);
       
   287 	TInt pageList = 1 + (aChunk->iSize + pageSize - 2) / pageSize;
       
   288 	TUint32* physAddr2 = new TUint32[pageList];
       
   289 	if(!physAddr2)
       
   290 		{
       
   291 		return KErrNoMemory;
       
   292 		}
       
   293 	
       
   294 	// Unless proven otherwise, the memory is not contiguous. 
       
   295 	aIsContiguous = EFalse;
       
   296 	TInt r = Kern::ChunkPhysicalAddress(aChunk, 0, aChunk->iSize, kernAddr, aMapAttr, physAddr, physAddr2);
       
   297 	if (KErrNone == r)
       
   298 		{
       
   299 		aIsContiguous = ETrue;
       
   300 		}
       
   301 	
       
   302 	
       
   303 	TRACE(Kern::Printf("SM CreateSurface ChunkPhysicalAddress r %d chunk %08x chunk size %d", r, aChunk, aChunk->iSize);)
       
   304 	TRACE(Kern::Printf("SM CreateSurface kernAddr %08x", kernAddr);)
       
   305 	TRACE(Kern::Printf("SM CreateSurface mapAttr %08x", aMapAttr);)
       
   306 	TRACE(Kern::Printf("SM CreateSurface physAddr %08x", physAddr);)
       
   307 	TRACE(Kern::Printf("SM CreateSurface physAddr2 %08x", physAddr2);)
       
   308 	
       
   309 	if(r < KErrNone)
       
   310 		{
       
   311 		// Error means that there isn't memory in the whole chunk - so check the
       
   312 		// relevant areas - it is allowed to have gaps between the buffers, but not 
       
   313 		// within the actual regions that are used for buffers. 
       
   314 		
       
   315 		// So, we first check the area before first buffer up to "offsettofirstbuffer", which all should be valid
       
   316 		if (aAttribs.iOffsetToFirstBuffer != 0)
       
   317 			{
       
   318 			r = Kern::ChunkPhysicalAddress(aChunk, 0, aAttribs.iOffsetToFirstBuffer, 
       
   319 					kernAddr, aMapAttr, physAddr, physAddr2);
       
   320 			}
       
   321 		else
       
   322 			{
       
   323 			r = KErrNone;
       
   324 			}
       
   325 		
       
   326 		// If that's a pass, loop through and check the actual buffers (leave loop if it fails).
       
   327 		for(TInt i = 0; i < aAttribs.iBuffers && KErrNone <= r; i++)
       
   328 			{
       
   329 			r = Kern::ChunkPhysicalAddress(aChunk, 
       
   330 					aAttribs.iOffsetToFirstBuffer + aAttribs.iOffsetBetweenBuffers * i, 
       
   331 					aBuffersize, kernAddr, aMapAttr, physAddr, physAddr2);
       
   332 			}
       
   333 		}
       
   334 
       
   335 	// Fix up weird ChunkPhysicalAddress behaviour - it returns 1 to indicate that memory is non-contiguous. 
       
   336 	if (1 == r)
       
   337 		{
       
   338 		r = KErrNone;
       
   339 		}
       
   340 
       
   341 	delete[] physAddr2;
       
   342 	return r;
       
   343 	}
       
   344 
       
   345 
       
   346 /**
       
   347 Creates a surface in an existing shared chunk.
       
   348 @param aParam  Package buf containing the surface creation parameters and id to be set to the surface id of the newly created surface.  
       
   349 @param aChunkHandle  Existing valid shared chunk handle.
       
   350 @return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
       
   351 KErrBadHandle if aChunkHandle is of an invalid shared chunk memory,
       
   352 otherwise one of the other system wide error codes.
       
   353 @see RSurfaceManager::TSurfaceCreationAttributes
       
   354 @internalTechnology
       
   355 */
       
   356 TInt DSurfaceManager::CreateSurface(RSurfaceManagerDriver::TDeviceParam* aParam, TInt aChunkHandle)
       
   357 	{
       
   358 	RSurfaceManager::TSurfaceCreationAttributesBuf buf;
       
   359 	RSurfaceManager::TSurfaceCreationAttributes& attribs = buf();
       
   360 
       
   361 	//Get the input parameters
       
   362 	RSurfaceManagerDriver::TDeviceParam param;
       
   363 	kumemget(&param, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
       
   364 	Kern::KUDesGet(buf, *(reinterpret_cast<const TDesC8*>(param.iBuffer)));
       
   365 	if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) )
       
   366 		{
       
   367 		return KErrArgument;
       
   368 		}	
       
   369 	
       
   370 	RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface];
       
   371 	if( (attribs.iHintCount>0) && attribs.iSurfaceHints)
       
   372 		{
       
   373 		kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair));		
       
   374 		attribs.iSurfaceHints = tempSurfaceHints;
       
   375 		}
       
   376 	else
       
   377 		{
       
   378 		attribs.iSurfaceHints=NULL;
       
   379 		}
       
   380 		
       
   381 	//validate input parameters and calc size
       
   382 	TInt roundedBufferSize = attribs.iOffsetBetweenBuffers;
       
   383 	TUint actualBufferSize = 0;
       
   384 	TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, actualBufferSize);
       
   385 	if (chunkSize == 0)
       
   386 		{
       
   387 		return KErrArgument;
       
   388 		}
       
   389 	
       
   390 	NKern::ThreadEnterCS();
       
   391 	
       
   392 	//Open an existing shared chunk
       
   393 	DChunk* chunk = Kern::OpenSharedChunk(NULL, aChunkHandle, EFalse);
       
   394 	if(chunk == NULL)
       
   395 		{
       
   396 		NKern::ThreadLeaveCS();
       
   397 		return KErrBadHandle;
       
   398 		}
       
   399 	
       
   400 	//Check for chunk type as kernel multiple
       
   401 	if(chunk->iChunkType != ESharedKernelMultiple)
       
   402 		{
       
   403 		Kern::ChunkClose(chunk);
       
   404 		NKern::ThreadLeaveCS();
       
   405 		return KErrBadHandle;
       
   406 		}
       
   407 	
       
   408 	//Check for enough chunk size to create surface for requested attributes
       
   409 	if (chunk->iSize < attribs.iOffsetToFirstBuffer + attribs.iBuffers * actualBufferSize)
       
   410 		{
       
   411 		Kern::ChunkClose(chunk);
       
   412 		NKern::ThreadLeaveCS();
       
   413 		return KErrArgument;
       
   414 		}
       
   415 
       
   416 	TSurfaceId sid;
       
   417 	TSurface* surface = NULL;
       
   418 	do		//in the unlikely event that we generate a duplicate surface id, try again.
       
   419 		{
       
   420 		GenerateSurfaceId(sid);
       
   421 
       
   422 		NKern::FMWait(&iMutex);
       
   423 		surface = FindSurfaceById(sid);
       
   424 		NKern::FMSignal(&iMutex);
       
   425 		}
       
   426 	while (surface);
       
   427 
       
   428 	//create a surface structure for the new surface
       
   429 	surface = new TSurface;
       
   430 	TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);)
       
   431 	if (!surface)
       
   432 		{
       
   433 		//destroy the chunk and cleanup, out of memory
       
   434 		Kern::ChunkClose(chunk);
       
   435 		NKern::ThreadLeaveCS();
       
   436 		return KErrNoMemory;
       
   437 		}
       
   438 
       
   439 	TUint32 mapAttr = 0;
       
   440 	TBool isContiguous;
       
   441 	TInt r = ValidatePhysicalMemory(chunk, attribs, actualBufferSize, mapAttr, isContiguous);
       
   442 	if (r != KErrNone)
       
   443 		{
       
   444 		//destroy the surface and close the chunk
       
   445 		delete(surface);
       
   446 		Kern::ChunkClose(chunk);
       
   447 		NKern::ThreadLeaveCS();
       
   448 		if (r != KErrNoMemory)
       
   449 			{
       
   450 			r = KErrArgument;
       
   451 			}
       
   452 		return r;
       
   453 		}
       
   454 	
       
   455 	surface->iId = sid;
       
   456 	surface->iSize = attribs.iSize;
       
   457 	surface->iBuffers = attribs.iBuffers;
       
   458 	surface->iPixelFormat = attribs.iPixelFormat;
       
   459 	surface->iStride = attribs.iStride;
       
   460 	surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer;
       
   461 	surface->iAlignment = attribs.iAlignment;
       
   462 	surface->iContiguous = isContiguous;
       
   463 	surface->iChunk = chunk;
       
   464 	surface->iOffsetBetweenBuffers = (attribs.iOffsetBetweenBuffers) ? attribs.iOffsetBetweenBuffers : roundedBufferSize;
       
   465 	surface->iMappable = attribs.iMappable;
       
   466 #ifndef __WINS__	//Creation attribute field will not considered for iCacheAttrib
       
   467 	TUint32 level1Info = mapAttr & EMapAttrL1CacheMask;
       
   468 	TUint32 level2Info = mapAttr & EMapAttrL2CacheMask;
       
   469 	TBool chunkIsNotcached =  ((level2Info == EMapAttrL2Uncached) && 
       
   470 	    ((level1Info == EMapAttrFullyBlocking) || (level1Info == EMapAttrBufferedNC) ||
       
   471 	     (level1Info == EMapAttrBufferedC) || (level1Info == EMapAttrL1Uncached)));
       
   472 	surface->iCacheAttrib = (chunkIsNotcached) ? RSurfaceManager::ENotCached : RSurfaceManager::ECached;
       
   473 #else
       
   474 	surface->iCacheAttrib = RSurfaceManager::ENotCached;	
       
   475 #endif
       
   476 	
       
   477 	if(attribs.iHintCount>0)
       
   478 		{
       
   479 		memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
       
   480 		}
       
   481 	memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair));
       
   482 
       
   483 	//create a surface owner for this surface
       
   484 	TProcessListItem* owner = new TProcessListItem;
       
   485 	TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);)
       
   486 
       
   487 	if (!owner)
       
   488 		{
       
   489 		//destroy the chunk and cleanup, out of memory
       
   490 		Kern::ChunkClose(chunk);
       
   491 		delete(surface);
       
   492 		TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);)
       
   493 		NKern::ThreadLeaveCS();
       
   494 		return KErrNoMemory;
       
   495 		}
       
   496 	
       
   497 	owner->iCount = 1;		//mark it as open in this process
       
   498 	owner->iOwningProcess =  &Kern::CurrentProcess();
       
   499 	owner->iNext = NULL;
       
   500 		
       
   501 	surface->iOwners = owner;	//only 1 owner at creation time
       
   502 
       
   503 	NKern::FMWait(&iMutex);
       
   504 	//at this point we have a fully constructed TSurface
       
   505 	//add surface to head of surfaces list
       
   506 
       
   507 	//Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index
       
   508 	//add the new surface to the beginning of the list 
       
   509 	TInt index = SurfaceIdToIndex(sid);
       
   510 	surface->iNext = iSurfacesIndex[index];
       
   511 	iSurfacesIndex[index] = surface;
       
   512 	NKern::FMSignal(&iMutex);		
       
   513 	NKern::ThreadLeaveCS();
       
   514 	
       
   515 	//write surface id back to user side
       
   516 	kumemput(reinterpret_cast<TSurfaceId*>(param.iSurfaceId), &sid, sizeof (TSurfaceId));
       
   517 	return KErrNone;
       
   518 	}
       
   519 
       
   520 
       
   521 /**
       
   522 Opens a surface.  If the current process already is in the owners list, its usage count is
       
   523 incremented.  If this is an open from a different process, a new surface owner object is added
       
   524 to the surface's list of owners and its usage count is set to 1.
       
   525 @param aId  The surface id of the surface to be opened.
       
   526 @return KErrNone if successful, otherwise a system error code
       
   527 @internalTechnology
       
   528 */
       
   529 TInt DSurfaceManager::OpenSurface(const TSurfaceId* aId)
       
   530 	{
       
   531 	TSurfaceId sid;
       
   532 	//fetch surface id from user memory
       
   533 	kumemget(&sid, aId, sizeof (TSurfaceId));
       
   534 	NKern::ThreadEnterCS();
       
   535 	TProcessListItem* owner = new TProcessListItem;  //speculative creation
       
   536 	TRACE(Kern::Printf("SM A %08x TProcessListItem OpenSurface", owner);)
       
   537 	
       
   538 	NKern::FMWait(&iMutex);
       
   539 	//look it up
       
   540 	TSurface* surface = FindSurfaceById(sid);
       
   541 	if (!surface)	
       
   542 		{
       
   543 		NKern::FMSignal(&iMutex);
       
   544 		delete owner;		//free the memory just allocated
       
   545 		TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);)
       
   546 		NKern::ThreadLeaveCS();
       
   547 		return KErrArgument;
       
   548 		}
       
   549 
       
   550 	//find the owner
       
   551 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
   552 	if (so)
       
   553 		{
       
   554 		//already an owner so inc the ref count
       
   555 		++so->iCount;
       
   556 		}
       
   557 	else
       
   558 		{
       
   559 		//new process trying to open it
       
   560 		if (!owner)
       
   561 			{
       
   562 			//the creation of the owner information object failed, out of memory
       
   563 			NKern::FMSignal(&iMutex);
       
   564 			NKern::ThreadLeaveCS();
       
   565 			return KErrNoMemory;
       
   566 			}
       
   567 			
       
   568 		owner->iCount = 1;		//mark it open in this process
       
   569 		owner->iOwningProcess =  &Kern::CurrentProcess();
       
   570 		
       
   571 		//add the owner to the list of owners
       
   572 		owner->iNext = surface->iOwners;
       
   573 		surface->iOwners = owner;
       
   574 		owner = NULL;
       
   575 		}
       
   576 	NKern::FMSignal(&iMutex);
       
   577 	delete owner;		//free if not used.
       
   578 	TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);)
       
   579 	NKern::ThreadLeaveCS();
       
   580 	return KErrNone;
       
   581 	}
       
   582 
       
   583 
       
   584 
       
   585 /**
       
   586 Closes a surface.  Decrements the usage count in the surface owner object
       
   587 if the usage count is then zero, removes this surface owner from the surface.
       
   588 If this results in a surface with no owners, the surface is deleted and the 
       
   589 surface shared chunk is closed.
       
   590 @param aId  The id of the surface to be closed
       
   591 @return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface,
       
   592 KErrAccessDenied if the surface is not open in the current process, otherwise a system wide
       
   593 error code.
       
   594 @internalTechnology
       
   595 */
       
   596 TInt DSurfaceManager::CloseSurface(const TSurfaceId* aId)
       
   597 	{
       
   598 
       
   599 	TSurfaceId sid;
       
   600 	kumemget(&sid, aId, sizeof (TSurfaceId));	//fetch surface id from user memory
       
   601 	//look it up
       
   602 	NKern::ThreadEnterCS();
       
   603 	NKern::FMWait(&iMutex);
       
   604 	TSurface* surface = FindSurfaceById(sid);
       
   605 	if (!surface)	
       
   606 		{
       
   607 		NKern::FMSignal(&iMutex);
       
   608 		NKern::ThreadLeaveCS();
       
   609 		return KErrArgument;
       
   610 		}
       
   611 
       
   612 	//find the owner
       
   613 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
   614 	if (!so)
       
   615 		{
       
   616 		NKern::FMSignal(&iMutex);
       
   617 		NKern::ThreadLeaveCS();
       
   618 		return KErrAccessDenied;
       
   619 		}
       
   620 
       
   621 	//current process is a surface owner so decrement the open count
       
   622 	TSurface* surfaceToDelete = NULL;
       
   623 	TProcessListItem* ownerToDelete = NULL;
       
   624 	DChunk* chunkToClose = NULL;
       
   625 	if (--so->iCount == 0)
       
   626 		{
       
   627 		//if count is now zero remove the owner
       
   628 		//surface->RemoveOwner(so);
       
   629 		UnlinkListItem(&surface->iOwners, so);
       
   630 		ownerToDelete = so;
       
   631 
       
   632 		//check to see if the surface has any owners
       
   633 		if (!surface->iOwners)
       
   634 			{
       
   635 			//no more owners of the surface
       
   636 			chunkToClose = surface->iChunk;
       
   637 
       
   638 			//remove the surface from the list
       
   639 			UnlinkListItem(&(iSurfacesIndex[SurfaceIdToIndex(surface->iId)]), surface);
       
   640 			surfaceToDelete = surface;
       
   641 			}
       
   642 		}
       
   643 	
       
   644 	NKern::FMSignal(&iMutex);
       
   645 
       
   646 	if (chunkToClose)
       
   647 		{
       
   648 		//surface has no more owners so close the chunk
       
   649 		Kern::ChunkClose(chunkToClose);
       
   650 		}
       
   651 
       
   652 	delete surfaceToDelete;
       
   653 	TRACE(Kern::Printf("SM D %08x TSurface CloseSurface",surfaceToDelete);)
       
   654 	delete ownerToDelete;
       
   655 	TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurface",ownerToDelete);)
       
   656 	NKern::ThreadLeaveCS();
       
   657 
       
   658 	return KErrNone;
       
   659 	}
       
   660 
       
   661 
       
   662 /**
       
   663 Maps the surface memory into the process of the calling thread. This will fail if
       
   664 the surface is not open in this process, or if the handle to the chunk cannot be created.
       
   665 @param aId  The id of the surface to be mapped in.
       
   666 @return KErrNone if successful, KErrArgument if the surface ID does not refer to a
       
   667 surface, KErrAccessDenied if the surface is not open in the current process,
       
   668 KErrNotSupported if the surface is not mappable, KErrOverflow if the chunk limit has been
       
   669 exceeded in the moving memory model, otherwise a system wide error code.
       
   670 @internalTechnology
       
   671 */
       
   672 TInt DSurfaceManager::MapSurface(const TSurfaceId* aId)
       
   673 	{
       
   674 	TSurfaceId sid;
       
   675 	kumemget(&sid, aId, sizeof (TSurfaceId));	//fetch surface id from user memory
       
   676 
       
   677 	//look it up
       
   678 	NKern::ThreadEnterCS();
       
   679 	NKern::FMWait(&iMutex);
       
   680 	TSurface* surface = FindSurfaceById(sid);
       
   681 	if (!surface)	
       
   682 		{
       
   683 		NKern::FMSignal(&iMutex);
       
   684 		NKern::ThreadLeaveCS();
       
   685 		return KErrArgument;	//surface id is not valid or in the list of surfaces
       
   686 		}
       
   687 	if(!surface->iMappable)
       
   688 		{
       
   689 		NKern::FMSignal(&iMutex);
       
   690 		NKern::ThreadLeaveCS();		
       
   691 		return KErrNotSupported;
       
   692 		}
       
   693 
       
   694 	//find the owner
       
   695 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
   696 	if (!so)
       
   697 		{
       
   698 		NKern::FMSignal(&iMutex);
       
   699 		NKern::ThreadLeaveCS();
       
   700 		return KErrAccessDenied;	//can't map it in, it's not open in this process
       
   701 		}
       
   702 
       
   703 	DChunk* chunk = surface->iChunk;
       
   704 	TInt r = chunk->Open();
       
   705 	NKern::FMSignal(&iMutex);
       
   706 	TRACE(Kern::Printf("SM MapSurface chunk open r %d\n",r);)
       
   707 
       
   708 	if (r == KErrGeneral)
       
   709 		{
       
   710 		NKern::ThreadLeaveCS();
       
   711 		return KErrAccessDenied;
       
   712 		}
       
   713 
       
   714 	//if we are here, got the surface and we are the owner.
       
   715 	//if we are the owner we must have it open at least once
       
   716 
       
   717 	r = Kern::MakeHandleAndOpen(NULL, chunk);
       
   718 	chunk->Close(NULL);
       
   719 	TRACE(Kern::Printf("SM MapSurface handle open r: %d\n",r);)
       
   720 
       
   721 	NKern::ThreadLeaveCS();
       
   722 
       
   723 	return r;
       
   724 	}
       
   725 
       
   726 
       
   727 /**
       
   728 Record a new connection to the driver.
       
   729 Adds an element to the reference counted list of connected processes if the connection
       
   730 is from a new process, otherwise it increments the reference count.
       
   731 @param aProcess  The process which has opened a driver channel.
       
   732 @internalTechnology
       
   733 */
       
   734 TInt DSurfaceManager::AddConnection(const DProcess* aProcess)
       
   735 	{
       
   736 	TRACE(Kern::Printf("SM AddConnection process %08x\n", aProcess);)
       
   737 	NKern::ThreadEnterCS();
       
   738 	TProcessListItem* connectedProcess = new TProcessListItem;  //speculative creation
       
   739 	TRACE(Kern::Printf("SM A %08x TProcessListItem AddConnection", connectedProcess);)
       
   740 	NKern::FMWait(&iMutex);
       
   741 	TProcessListItem* p = FindConnectedProcess(aProcess);
       
   742 	if (p)	//already connected, found the process
       
   743 		{
       
   744 		++p->iCount;
       
   745 		}
       
   746 	else
       
   747 		{
       
   748 		//add a new connected process
       
   749 		if (!connectedProcess)
       
   750 			{
       
   751 			//the creation of the owner information object failed, out of memory
       
   752 			NKern::FMSignal(&iMutex);
       
   753 			NKern::ThreadLeaveCS();
       
   754 			return KErrNoMemory;
       
   755 			}
       
   756 		connectedProcess->iOwningProcess = (DProcess*)aProcess;
       
   757 		connectedProcess->iCount=1;
       
   758 		
       
   759 		connectedProcess->iNext = iConnectedProcesses;
       
   760 		iConnectedProcesses = connectedProcess;
       
   761 		connectedProcess = NULL;
       
   762 		}
       
   763 	NKern::FMSignal(&iMutex);
       
   764 	delete connectedProcess;
       
   765 	TRACE(Kern::Printf("SM D %08x TProcessListItem AddConnection", connectedProcess);)
       
   766 	NKern::ThreadLeaveCS();
       
   767 	return KErrNone;
       
   768 	}
       
   769 	
       
   770 	
       
   771 	
       
   772 /**
       
   773 Called when the driver channel is closed.
       
   774 Decrements the reference count for the connected process, if the last connection
       
   775 for this process is closed (reference count reaches 0) it removes the process from the list.
       
   776 @param aProcess  The process which has closed the driver channel.
       
   777 @internalTechnology
       
   778 */
       
   779 void DSurfaceManager::RemoveConnection(const DProcess* aProcess)
       
   780 	{
       
   781 	TRACE(Kern::Printf("SM RemoveConnection process %08x\n", aProcess);)
       
   782 	NKern::ThreadEnterCS();
       
   783 	NKern::FMWait(&iMutex);
       
   784 	TProcessListItem* p =FindConnectedProcess(aProcess);
       
   785 	TProcessListItem* toDelete = NULL;
       
   786 	if (p)	//already connected, found the process
       
   787 		{
       
   788 		if (--p->iCount == 0) //last connection in process has disconnected
       
   789 			{
       
   790 			//remove the process from the list and cleanup
       
   791 			UnlinkListItem(&iConnectedProcesses, p);
       
   792 			toDelete = p;
       
   793 			}
       
   794 		}
       
   795 	NKern::FMSignal(&iMutex);
       
   796 	delete toDelete;
       
   797 	TRACE(Kern::Printf("SM D %08x TProcessListItem RemoveConnection ", toDelete);)
       
   798 	
       
   799 	
       
   800 	if (toDelete)	// if a process has closed its last channel, remove process from the surface owners.
       
   801 		{
       
   802 		CloseSurfaceHandlesForProcess(aProcess);
       
   803 		}
       
   804 
       
   805 	NKern::ThreadLeaveCS();
       
   806 	}
       
   807 	
       
   808 
       
   809 
       
   810 
       
   811 /**
       
   812 Closes all the surfaces belonging to the process which has just terminated.
       
   813 If this is the only owner of a surface, delete the surface.
       
   814 @param aProcess  The process which has terminated.
       
   815 @pre must be called in critical section
       
   816 @internalTechnology
       
   817 */
       
   818 void DSurfaceManager::CloseSurfaceHandlesForProcess(const DProcess* aProcess)
       
   819 	{
       
   820 
       
   821 	NKern::FMWait(&iMutex);
       
   822 
       
   823 	TSurface* p = NULL;
       
   824 	TSurface* surfacesTodelete = NULL;
       
   825 	TProcessListItem* ownersTodelete = NULL;
       
   826 	TProcessListItem* so;
       
   827 	// There are 16 doubly linked lists managed by Surface Manager
       
   828 	for (TInt index = 0; index < KMaxLists; index++)
       
   829 		{
       
   830 		p = iSurfacesIndex[index];
       
   831 		while(p)
       
   832 			{
       
   833 			//see if the process which has just died is an owner of any surfaces
       
   834 			TSurface* surface = p;
       
   835 			p=p->iNext;
       
   836 			so = surface->ProcessOwnerInfo(aProcess);
       
   837 			if (so)
       
   838 				{
       
   839 				UnlinkListItem(&surface->iOwners, so);
       
   840 				so->iNext = ownersTodelete;	//add the owner to the list of owner objects to remove
       
   841 				ownersTodelete = so;
       
   842 
       
   843 				if (!surface->iOwners)	//if the surface hasn't any owners
       
   844 					{
       
   845 					//remove the surface from the list
       
   846 					UnlinkListItem(&iSurfacesIndex[index], surface);
       
   847 					surface->iNext = surfacesTodelete;	//add the surface to the list of surfaces to remove
       
   848 					surfacesTodelete = surface;
       
   849 					}
       
   850 				}
       
   851 			}
       
   852 		}
       
   853 	NKern::FMSignal(&iMutex);
       
   854 
       
   855 	while(surfacesTodelete)
       
   856 		{
       
   857 		p = surfacesTodelete->iNext;
       
   858 		Kern::ChunkClose(surfacesTodelete->iChunk);
       
   859 		TRACE(Kern::Printf("SM Close chunk %08x CloseSurfaceHandlesForProcess",surfacesTodelete->iChunk);)
       
   860 		delete surfacesTodelete;
       
   861 		TRACE(Kern::Printf("SM D %08x TSurface CloseSurfaceHandlesForProcess",surfacesTodelete);)
       
   862 		surfacesTodelete = p;
       
   863 		}
       
   864 
       
   865 	while(ownersTodelete)
       
   866 		{
       
   867 		so = ownersTodelete->iNext;
       
   868 		delete ownersTodelete;
       
   869 		TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurfaceHandlesForProcess",ownersTodelete);)
       
   870 		ownersTodelete = so;
       
   871 		}
       
   872 	}
       
   873 
       
   874 	
       
   875 /**
       
   876 Returns the metadata information about the specified surface.
       
   877 @param aId  The id of the surface.
       
   878 @param aInfo  Pointer to user side descriptor to receive the information.
       
   879 @return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface,
       
   880 KErrAccessDenied if the surface is not open in the current process, otherwise a system wide
       
   881 error code.
       
   882 @internalTechnology
       
   883 */	
       
   884 TInt DSurfaceManager::SurfaceInfo(const TSurfaceId* aId, TDes8* aInfo)
       
   885 	{
       
   886 	TSurfaceId sid;
       
   887 	//fetch surface id from user memory
       
   888 	kumemget(&sid, aId, sizeof (TSurfaceId));
       
   889 
       
   890 	RSurfaceManager::TInfoBuf buf;
       
   891 	RSurfaceManager::TSurfaceInfoV01& info = buf();
       
   892 
       
   893 	NKern::FMWait(&iMutex);
       
   894 	//look it up
       
   895 	TSurface* surface = FindSurfaceById(sid);
       
   896 	if (!surface)	
       
   897 		{
       
   898 		NKern::FMSignal(&iMutex);
       
   899 		return KErrArgument;
       
   900 		}
       
   901 	
       
   902 	//find the owner
       
   903 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
   904 	if (!so)
       
   905 		{
       
   906 		NKern::FMSignal(&iMutex);
       
   907 		return KErrAccessDenied;	//can do this, not open
       
   908 		}
       
   909 	
       
   910 	//at this point, we have a surface, we are the owner and it's mapped in
       
   911 	info.iSize = surface->iSize; 									// Visible width/height in pixels
       
   912 	info.iBuffers = surface->iBuffers;								// Number of Buffers
       
   913 	info.iPixelFormat = surface->iPixelFormat;	      				// pixel format
       
   914 	info.iStride = surface->iStride;								// Number of bytes between start of one line and start of next
       
   915 	info.iContiguous = surface->iContiguous;						// is it physically contiguous
       
   916 	info.iCacheAttrib = surface->iCacheAttrib;						// Underlying chunk is CPU cached or not
       
   917 	info.iMappable = surface->iMappable;							// Is the surface Mappable
       
   918 	NKern::FMSignal(&iMutex);
       
   919 	
       
   920 	//copy it back to user side
       
   921 	Kern::InfoCopy(*aInfo, buf);
       
   922 	return KErrNone;
       
   923 	}
       
   924 
       
   925 
       
   926 
       
   927 /**
       
   928 Generates a unique surface id
       
   929 @param aId  Surface id reference to receive the generated id.
       
   930 @internalTechnology
       
   931 */	
       
   932 void DSurfaceManager::GenerateSurfaceId(TSurfaceId& aId)
       
   933 	{
       
   934 	TSurfaceId id;
       
   935 	
       
   936 	for (TInt x = 0; x < 4; ++x)
       
   937 		{
       
   938 		id.iInternal[x] = Kern::Random();
       
   939 		};
       
   940 	
       
   941 	//package up the handle,
       
   942 	//set the type identifier
       
   943 	id.iInternal[3] &= 0x00FFFFFF;
       
   944 	id.iInternal[3] |= TSurfaceTypes::ESurfaceManagerSurface << 24;
       
   945 	aId = id;
       
   946 	TRACE(Kern::Printf("SM GenerateSurfaceId id = %u %u %u %u\n",id.iInternal[0],id.iInternal[1],id.iInternal[2],id.iInternal[3]);)
       
   947 	};
       
   948 	
       
   949 
       
   950 
       
   951 /**
       
   952 Validates the surface creation attributes and calculates the size of the chunk required.
       
   953 @param aAttribs  The surface creation attributes used to specify the surface requirements.
       
   954 @param aOffset  Set to the offset between buffers on successfull return.
       
   955 @param aNewChunk  If this is true, surface is created in a new chunk otherwise the surface is created in an existing chunk
       
   956 @return The size of chunk required.  A size of 0 indicates a problem.
       
   957 */	
       
   958 TInt DSurfaceManager::ValidateAndCalculateChunkSize(RSurfaceManager::TSurfaceCreationAttributes& aAttribs, 
       
   959 			TInt& aOffset, TUint &aActualBufferSize, const TBool aNewChunk)
       
   960 	{
       
   961 /*	
       
   962 	TRACE(Kern::Printf("SM width = %d  height = %d\n", aAttribs.iSize.iWidth, aAttribs.iSize.iHeight);)
       
   963 	TRACE(Kern::Printf("SM buffers = %d\n", aAttribs.iBuffers);)
       
   964 	TRACE(Kern::Printf("SM format = %d\n", aAttribs.iPixelFormat);)
       
   965 	TRACE(Kern::Printf("SM stride = %d\n", aAttribs.iStride);)
       
   966 	TRACE(Kern::Printf("SM offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);)
       
   967 	TRACE(Kern::Printf("SM offset between buffer = %d\n", aOffset);)
       
   968 	TRACE(Kern::Printf("SM alignment = %d\n", aAttribs.iAlignment);)
       
   969 	TRACE(Kern::Printf("SM contiguous = %d\n\n", aAttribs.iContiguous);)
       
   970 	TRACE(Kern::Printf("SM cacheAttrib = %d\n\n", aAttribs.iCacheAttrib);)
       
   971 */
       
   972 	//check for negative values
       
   973 	if(aAttribs.iOffsetToFirstBuffer < 0 || aOffset < 0 )
       
   974 		{
       
   975 		TRACE(Kern::Printf("SM Validate offset for negative value");)
       
   976 		return 0;
       
   977 		}
       
   978 
       
   979 	//check aligment is sensible
       
   980 	TInt alignmentMask = 0;
       
   981 	switch(aAttribs.iAlignment)
       
   982 		{
       
   983 		case 1:	
       
   984 		case 2:	
       
   985 		case 4: 
       
   986 		case 8: 
       
   987 		case 16: 
       
   988 		case 32: 
       
   989 			alignmentMask = 31; 
       
   990 			break;
       
   991 		case 64: 
       
   992 			alignmentMask = 63; 
       
   993 			break;
       
   994 		case RSurfaceManager::EPageAligned:
       
   995 			break;
       
   996 		default:
       
   997 			TRACE(Kern::Printf("SM Validate alignment");)
       
   998 			return 0;
       
   999 		}
       
  1000 	
       
  1001 	//check alignment issues.
       
  1002 	if(aAttribs.iAlignment != RSurfaceManager::EPageAligned)
       
  1003 		{
       
  1004 		if(aNewChunk)	
       
  1005 			{
       
  1006 			if(aAttribs.iCacheAttrib == RSurfaceManager::ECached)	// Surface is CPU cached, so the alignment will be based on either 32 or 64 byte 
       
  1007 				{
       
  1008 				//offset to first buffer needs to fit alignment
       
  1009 				aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignmentMask & ~alignmentMask;
       
  1010 				//alignment with respect to offsetbetweenbuffers
       
  1011 				aOffset = aOffset + alignmentMask & ~alignmentMask;
       
  1012 				}
       
  1013 			else	// Surface is NOT CPU cached, so the alignment will be based on surface attribute alignment
       
  1014 				{
       
  1015 				TUint alignMask = aAttribs.iAlignment-1;
       
  1016 				//offset to first buffer needs to fit alignment
       
  1017 				aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignMask & ~alignMask;
       
  1018 				//alignment with respect to offsetbetweenbuffers
       
  1019 				aOffset = aOffset + alignMask & ~alignMask;
       
  1020 				}
       
  1021 			}
       
  1022 		else	// existing chunk
       
  1023 			{
       
  1024 			TUint alignMask = aAttribs.iAlignment-1;
       
  1025 			//check alignment issues.  offset to first buffer needs to fit alignment
       
  1026 			if (aAttribs.iOffsetToFirstBuffer & alignMask)
       
  1027 				{
       
  1028 				TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");)
       
  1029 				return 0;
       
  1030 				}
       
  1031 
       
  1032 			//check alignment for offsetbetweenbuffers.  offset between buffer needs to fit alignment for existing chunks
       
  1033 			if (aOffset & alignMask)
       
  1034 				{
       
  1035 				TRACE(Kern::Printf("SM Validate offset between buffers misaligned");)
       
  1036 				return 0;
       
  1037 				}
       
  1038 			}
       
  1039 		}
       
  1040 	else	//page aligned
       
  1041 		{
       
  1042 		if(aNewChunk)// if its a new chunks and doesn't match exact alignment then do the rounding
       
  1043 			{
       
  1044 			TUint32 pageSize = Kern::RoundToPageSize(1);
       
  1045 			//offset to first buffer needs to fit alignment
       
  1046 			aAttribs.iOffsetToFirstBuffer = (aAttribs.iOffsetToFirstBuffer + (pageSize - 1)) & ~(pageSize - 1);
       
  1047 			//alignment with respect to offsetbetweenbuffers
       
  1048 			aOffset = (aOffset + (pageSize - 1)) & ~((pageSize - 1));
       
  1049 			}
       
  1050 		else	// for existing chunks don't do any rounding operation
       
  1051 			{
       
  1052 			TUint32 pageSize = Kern::RoundToPageSize(1);
       
  1053 			TUint alignmask = aAttribs.iOffsetToFirstBuffer & (pageSize - 1);
       
  1054 			if (alignmask)
       
  1055 				{
       
  1056 				TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");)
       
  1057 				return 0;
       
  1058 				}
       
  1059 			
       
  1060 			alignmask = aOffset & (pageSize - 1);
       
  1061 			if (alignmask)
       
  1062 				{
       
  1063 				TRACE(Kern::Printf("SM Validate offset between buffers misaligned");)
       
  1064 				return 0;
       
  1065 				}
       
  1066 			}
       
  1067 		}
       
  1068 
       
  1069 	//check width and height
       
  1070 	if(aAttribs.iSize.iWidth <= 0 || aAttribs.iSize.iHeight <= 0)
       
  1071 		{
       
  1072 		TRACE(Kern::Printf("SM Validate width/height");)
       
  1073 		return 0;
       
  1074 		}
       
  1075 	
       
  1076 	
       
  1077 	//check there is at least 1 buffer
       
  1078 	if (aAttribs.iBuffers <= 0)
       
  1079 		{
       
  1080 		TRACE(Kern::Printf("SM Validate buffers");)
       
  1081 		return 0;
       
  1082 		}
       
  1083 
       
  1084 	//Sort the array and also check for duplication
       
  1085 	if (!SortHints(aAttribs.iSurfaceHints,aAttribs.iHintCount)) 
       
  1086 		{
       
  1087 		TRACE(Kern::Printf("SM Validate Duplicate hint key");)
       
  1088 		return 0;
       
  1089 		}
       
  1090 
       
  1091 	TUint size = 0;
       
  1092 	//calculate buffer size and round it to alignment or to page size
       
  1093 	TInt64 bufferSize = aAttribs.iStride;
       
  1094 	bufferSize  *= aAttribs.iSize.iHeight;
       
  1095 
       
  1096 	if (I64HIGH(bufferSize) > 0) //too big
       
  1097 		{
       
  1098 		TRACE(Kern::Printf("SM Validate chunk buffer size is out of range");)
       
  1099 		return 0;
       
  1100 		}
       
  1101 	
       
  1102 	TUint bsize = I64LOW(bufferSize);
       
  1103 	if (bsize > KMaxTInt)
       
  1104 		{
       
  1105 		TRACE(Kern::Printf("SM Validate buffer size is out of range for TInt");)
       
  1106 		return 0;
       
  1107 		}
       
  1108 
       
  1109 	if(aAttribs.iAlignment == RSurfaceManager::EPageAligned)
       
  1110 		{
       
  1111 		bsize = Kern::RoundToPageSize(bsize);	//page alignment
       
  1112 		}
       
  1113 	else if(aAttribs.iCacheAttrib == RSurfaceManager::ECached)
       
  1114 		{
       
  1115 		bsize = bsize + alignmentMask & ~alignmentMask;	//CPU cached byte alignment, for minimum of the specified alignment(32 or 64)
       
  1116 		}
       
  1117 	else
       
  1118 		{
       
  1119 		bsize = bsize + (aAttribs.iAlignment-1) & ~(aAttribs.iAlignment-1);	//NON CPU cached byte alignment for 1, 2, 4, 8, 16, 32 and 64
       
  1120 		}
       
  1121 	
       
  1122 	bufferSize = bsize;
       
  1123 	// Remember the actual size. 
       
  1124 	aActualBufferSize = bsize;
       
  1125 
       
  1126 	//if offset between buffers is zero, then assign the calculated value as offset between buffers
       
  1127 	if(aOffset == 0)
       
  1128 		{
       
  1129 		//buffer size rounded to alignment as offset between buffers
       
  1130 		aOffset = I64INT(bufferSize);
       
  1131 		}
       
  1132 	else if(aOffset < I64INT(bufferSize))
       
  1133 		{
       
  1134 		TRACE(Kern::Printf("SM Offset between the buffer is less than the required size");)
       
  1135 		return 0;
       
  1136 		}
       
  1137 	else
       
  1138 		{
       
  1139 		//use the buffer size specified
       
  1140 		bufferSize = aOffset;
       
  1141 		}
       
  1142 	
       
  1143 	
       
  1144 	TInt64 totalSize = aAttribs.iOffsetToFirstBuffer + (aAttribs.iBuffers * bufferSize);
       
  1145 	
       
  1146 	if (I64HIGH(totalSize) > 0) //too big
       
  1147 		{
       
  1148 		TRACE(Kern::Printf("SM Validate chunk size is out of range for RoundToPageSize");)
       
  1149 		return 0;
       
  1150 		}
       
  1151 		
       
  1152 	size = I64LOW(totalSize);
       
  1153 	if (size > KMaxTInt)
       
  1154 		{
       
  1155 		TRACE(Kern::Printf("SM Validate size is out of range for TInt");)
       
  1156 		return 0;
       
  1157 		}
       
  1158 
       
  1159 	size = Kern::RoundToPageSize(size);
       
  1160 
       
  1161 	//check the size isn't greater than will fit in a TInt
       
  1162 	if (size > KMaxTInt)
       
  1163 		{
       
  1164 		TRACE(Kern::Printf("SM Rounded size is out of range for TInt");)
       
  1165 		return 0;
       
  1166 		}
       
  1167 	
       
  1168 	TRACE(Kern::Printf("SM After validate - offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);)
       
  1169 	TRACE(Kern::Printf("SM After validate - offset between buffer = %d\n", aOffset);)
       
  1170 	TRACE(Kern::Printf("SM CalculateChunkSize size = %d\n", size);)
       
  1171 	return size;
       
  1172 	}
       
  1173 
       
  1174 
       
  1175 /**
       
  1176 Find the surface in the list.   
       
  1177 @param aId  The surface id of the surface to find in the surface list
       
  1178 @return pointer to the surface object
       
  1179 @internalTechnology
       
  1180 */
       
  1181 TSurface* DSurfaceManager::FindSurfaceById(const TSurfaceId& aId)
       
  1182 	{
       
  1183 	TSurface *p = iSurfacesIndex[SurfaceIdToIndex(aId)];
       
  1184 	while (p)
       
  1185 		{
       
  1186 		if (aId == p->iId)
       
  1187 			{
       
  1188 			//found it
       
  1189 			return p;
       
  1190 			}
       
  1191 	
       
  1192 		p = p->iNext;
       
  1193 		}
       
  1194 	return NULL;
       
  1195 	}
       
  1196 
       
  1197 
       
  1198 /**
       
  1199 Find the index of the hint key from the surface list using binary search.   
       
  1200 @param aHintsArray  Pointer to the first element in the array of surface hints
       
  1201 @param aKey  The surface hint key uid value to search in the surface list
       
  1202 @return index of the hint pair key in the surface list, KErrNotFound if key not found
       
  1203 @internalTechnology
       
  1204 */
       
  1205 TInt DSurfaceManager::FindHintKey(const RSurfaceManager::THintPair* aHintsArray, TUint32 aKey) const
       
  1206 	{
       
  1207 	__ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__));
       
  1208 
       
  1209 	TInt bottom = 0;
       
  1210 	TInt top = KMaxHintsPerSurface - 1;
       
  1211 	TInt mid;
       
  1212 	while (bottom <= top)
       
  1213 		{
       
  1214 	    mid = (bottom + top) / 2;
       
  1215 	    if((TUint) aHintsArray[mid].iKey.iUid == aKey)
       
  1216 	    	{
       
  1217 	    	return mid;
       
  1218 	    	} 
       
  1219 	    else if ((TUint)aHintsArray[mid].iKey.iUid < aKey) 
       
  1220 	    	{
       
  1221 	    	top = mid - 1;
       
  1222 	    	}
       
  1223 	    else
       
  1224 	    	{
       
  1225 	    	bottom = mid + 1;
       
  1226 	    	}
       
  1227 	  }
       
  1228 	return KErrNotFound;	//Hint key not found
       
  1229     }
       
  1230 
       
  1231 TProcessListItem* DSurfaceManager::FindConnectedProcess(const DProcess* aProcess)
       
  1232 	{
       
  1233 	TProcessListItem * p = iConnectedProcesses;
       
  1234 	while (p)
       
  1235 		{
       
  1236 		if (aProcess == p->iOwningProcess)
       
  1237 			{
       
  1238 			//found it
       
  1239 			return p;
       
  1240 			}
       
  1241 		
       
  1242 		p = p->iNext;
       
  1243 		}
       
  1244 	return NULL;
       
  1245 	}
       
  1246 
       
  1247 /**
       
  1248 Searches for a right place to insert the new hint pair in a sorted array.
       
  1249 @param aHintsArray  Pointer to the first element in the sorted array
       
  1250 @param aKey  The surface hint key uid value to search in the surface list
       
  1251 @pre, there is at least one empty place in the array
       
  1252 @return KErrNone if a new hint pair key inserted in the surface list, KErrAlreadyExists if duplicated
       
  1253 @internalTechnology
       
  1254 */
       
  1255 TInt DSurfaceManager::InsertHintKey(RSurfaceManager::THintPair* aHintsArray, const RSurfaceManager::THintPair& aHintPair) const
       
  1256 	{
       
  1257 	__ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__));
       
  1258 	__ASSERT_DEBUG(aHintsArray[KMaxHintsPerSurface-1].iKey.iUid == NULL, Kern::Fault("Surface Manager", __LINE__));
       
  1259 
       
  1260 	TInt pos = 0;
       
  1261 	if (aHintsArray[pos].iKey.iUid != 0)
       
  1262 		{
       
  1263 		while((TUint)aHintsArray[pos].iKey.iUid>(TUint)aHintPair.iKey.iUid && pos < KMaxHintsPerSurface-1)
       
  1264 			{// find the right place to insert
       
  1265 			++pos;
       
  1266 			}
       
  1267 	
       
  1268 		if((TUint)aHintsArray[pos].iKey.iUid==(TUint)aHintPair.iKey.iUid)
       
  1269 			{
       
  1270 			//Duplicate key 
       
  1271 			return KErrAlreadyExists;
       
  1272 			}
       
  1273 		else
       
  1274 			{
       
  1275 			// Shift right
       
  1276 			memmove(aHintsArray+pos+1, aHintsArray+pos, (KMaxHintsPerSurface-pos-1)*sizeof(RSurfaceManager::THintPair));		
       
  1277 			}	
       
  1278 		}
       
  1279 	aHintsArray[pos] = aHintPair;
       
  1280 	return KErrNone;
       
  1281 	}
       
  1282 
       
  1283 /**
       
  1284 Sort the surface hint array in descending order.
       
  1285 @param aHintsArray  The surface hintpair in the surface list
       
  1286 @param aNumberOfHints The number of hints
       
  1287 @return ETrue if sorting is finished or it is an empty array, EFalse if key duplicated
       
  1288 @internalTechnology
       
  1289 */
       
  1290 TBool DSurfaceManager::SortHints(RSurfaceManager::THintPair* aHintsArray, TInt aNumberOfHints) const
       
  1291 	{
       
  1292 	TInt in = 0;
       
  1293 	TInt out = 0;
       
  1294 	RSurfaceManager::THintPair temp;
       
  1295 	if(!aHintsArray)
       
  1296 		{
       
  1297 		return ETrue;
       
  1298 		}
       
  1299 	for(out = 0; out < aNumberOfHints; ++out) 
       
  1300 		{
       
  1301 		if(aHintsArray[out].iKey.iUid != 0)
       
  1302 			{
       
  1303 			temp = aHintsArray[out];   
       
  1304 			in = out;          // start shifting at out
       
  1305 			while(in > 0 && (TUint)aHintsArray[in-1].iKey.iUid <= (TUint)temp.iKey.iUid)
       
  1306 				{
       
  1307 				if ((TUint)aHintsArray[in-1].iKey.iUid == (TUint)temp.iKey.iUid)
       
  1308 					{
       
  1309 					return EFalse;		//duplicate hint keys are not allowed
       
  1310 					}
       
  1311 				aHintsArray[in] = aHintsArray[in-1];     // shift item to the right
       
  1312 				--in;          // go left one position
       
  1313 				}
       
  1314 			aHintsArray[in] = temp;        // insert marked item
       
  1315 			}
       
  1316 		}
       
  1317 	return ETrue;
       
  1318 	}
       
  1319 
       
  1320 
       
  1321 /**
       
  1322 Ensures the memory is updated consistently before/after triggering non CPU hardware access. 
       
  1323 @param aParam  The suface id and buffer number (0 based).
       
  1324 @param aOperation  The type of the synchronize operation. 
       
  1325 @return KErrNone if successful, KErrArgument if the surface ID is invalid or
       
  1326 buffer number is invalid, KErrAccessDenied if the surface is not open in this
       
  1327 process, otherwise a system wide error code.
       
  1328 @see RSurfaceManager::TSyncOperation
       
  1329 @internalTechnology
       
  1330 */	
       
  1331 TInt DSurfaceManager::SynchronizeCache(RSurfaceManagerDriver::TDeviceParam* aParam, RSurfaceManager::TSyncOperation aOperation)
       
  1332 	{
       
  1333 	//Parse the parameters
       
  1334 	RSurfaceManagerDriver::TDeviceParam param;
       
  1335 	kumemget(&param, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
       
  1336 	TSurfaceId sid;
       
  1337 	kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId));
       
  1338 	TInt buffer = (TInt)param.iBuffer;
       
  1339 	
       
  1340 	NKern::ThreadEnterCS();
       
  1341 	NKern::FMWait(&iMutex);
       
  1342 	//look it up
       
  1343 	TSurface* surface = FindSurfaceById(sid);
       
  1344 	if (!surface)	
       
  1345 		{
       
  1346 		NKern::FMSignal(&iMutex);
       
  1347 		NKern::ThreadLeaveCS();
       
  1348 		return KErrArgument;
       
  1349 		}
       
  1350 	
       
  1351 	//find the owner
       
  1352 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
  1353 	if (!so)
       
  1354 		{
       
  1355 		NKern::FMSignal(&iMutex);
       
  1356 		NKern::ThreadLeaveCS();
       
  1357 		return KErrAccessDenied;
       
  1358 		}
       
  1359 
       
  1360 	// surfaces have to have at least one buffer
       
  1361 	__ASSERT_DEBUG(surface->iBuffers > 0, Kern::Fault("Surface Manager", __LINE__));
       
  1362 	
       
  1363 	//Validate the buffer number is within range
       
  1364 	if((buffer >= surface->iBuffers) || (buffer < 0))
       
  1365 		{
       
  1366 		NKern::FMSignal(&iMutex);
       
  1367 		NKern::ThreadLeaveCS();
       
  1368 		return KErrArgument;
       
  1369 		}
       
  1370 
       
  1371 	DChunk* chunk = surface->iChunk;
       
  1372 	TInt offsetBetweenBuffers = surface->iOffsetBetweenBuffers;
       
  1373 	NKern::FMSignal(&iMutex);
       
  1374 
       
  1375 	TUint32 kernAddr;
       
  1376 	TUint32 mapAttr;
       
  1377 	TUint32 physAddr;
       
  1378 	TInt pageList = chunk->iSize / Kern::RoundToPageSize(1) + 1;
       
  1379 	TUint32* physAddr2 = new TUint32[pageList];
       
  1380 	if(!physAddr2)
       
  1381 		{
       
  1382 		NKern::ThreadLeaveCS();
       
  1383 		return KErrNoMemory;
       
  1384 		}
       
  1385 	
       
  1386 	TRACE(Kern::Printf("SM %08x DChunk SynchronizeCache", chunk);)
       
  1387 	
       
  1388 	//Retrieve the kernel address and mapping attribute from the chunk
       
  1389 	TInt err = Kern::ChunkPhysicalAddress(chunk, surface->iOffsetToFirstBuffer + (buffer * offsetBetweenBuffers), offsetBetweenBuffers, kernAddr, mapAttr, physAddr, physAddr2);
       
  1390 	delete[] physAddr2;
       
  1391 	if(err >= KErrNone)
       
  1392 		{
       
  1393 		TRACE(Kern::Printf("SM %08x kernAddr SynchronizeCache", kernAddr);)
       
  1394 		TRACE(Kern::Printf("SM %08x mapAttr SynchronizeCache", mapAttr);)
       
  1395 		err = KErrNone;
       
  1396 
       
  1397 		// Do the sync operation
       
  1398 		switch(aOperation)
       
  1399 			{
       
  1400 			case RSurfaceManager::ESyncBeforeNonCPURead:
       
  1401 				Cache::SyncMemoryBeforeDmaWrite(kernAddr, offsetBetweenBuffers, mapAttr);
       
  1402 				break;
       
  1403 			case RSurfaceManager::ESyncBeforeNonCPUWrite:
       
  1404 				Cache::SyncMemoryBeforeDmaRead(kernAddr, offsetBetweenBuffers, mapAttr);
       
  1405 				break;
       
  1406 			case RSurfaceManager::ESyncAfterNonCPUWrite:
       
  1407 				Cache::SyncMemoryAfterDmaRead(kernAddr, offsetBetweenBuffers);
       
  1408 				break;
       
  1409 			default: 
       
  1410 				err = KErrArgument;
       
  1411 				break;
       
  1412 			}			
       
  1413 		}
       
  1414 	NKern::ThreadLeaveCS();
       
  1415 
       
  1416 	return err;
       
  1417 	}
       
  1418 
       
  1419 
       
  1420 /**
       
  1421 Get the surface hint value for the given surface ID and hint pair key.
       
  1422 @param aSurfaceId  The surface identifier originally returned when the surface was created.
       
  1423 @param aHintPair  The hint value for the requested hint pair key.
       
  1424 @return KErrNone if successful, KErrArgument if the surface ID is invalid or
       
  1425 invalid hint pair key used, KErrAccessDenied if the surface is not open in the
       
  1426 current process, otherwise a system wide error code.
       
  1427 @internalTechnology
       
  1428 */ 
       
  1429 TInt DSurfaceManager::GetSurfaceHint(const TSurfaceId* aSurfaceId, RSurfaceManager::THintPair* aHintPair)
       
  1430 	{
       
  1431 	RSurfaceManager::THintPair hintPair;
       
  1432 	kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
       
  1433 
       
  1434 	if (hintPair.iKey.iUid == 0)
       
  1435 		{
       
  1436 		TRACE(Kern::Printf("SM GetSurfaceHint Hint key is invalid");)
       
  1437 		return KErrArgument;	//Invalid Hint key
       
  1438 		}
       
  1439 	
       
  1440 	TSurfaceId sid;
       
  1441 	//fetch surface id from user memory
       
  1442 	kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
       
  1443 
       
  1444 	NKern::FMWait(&iMutex);
       
  1445 	//look it up
       
  1446 	TSurface* surface = FindSurfaceById(sid);
       
  1447 	if (!surface)	
       
  1448 		{
       
  1449 		NKern::FMSignal(&iMutex);
       
  1450 		return KErrArgument;
       
  1451 		}
       
  1452 	
       
  1453 	//find the owner
       
  1454 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
  1455 	if (!so)
       
  1456 		{
       
  1457 		NKern::FMSignal(&iMutex);
       
  1458 		return KErrAccessDenied;
       
  1459 		}
       
  1460 	
       
  1461 	//at this point, we have a surface, we have to find the hint value based on the hint pair key
       
  1462 	TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid);
       
  1463 
       
  1464 	if (index == KErrNotFound)
       
  1465 		{
       
  1466 		TRACE(Kern::Printf("SM GetSurfaceHint Hint key not found");)
       
  1467 		NKern::FMSignal(&iMutex);
       
  1468 		return KErrArgument;	//Hint key not found
       
  1469 		}
       
  1470 
       
  1471 	RSurfaceManager::THintPair hint = surface->iSurfaceHints[index];
       
  1472 	NKern::FMSignal(&iMutex);
       
  1473 		
       
  1474 	TRACE(Kern::Printf("SM GetSurfaceHint Hint value %d", hint.iValue);)
       
  1475 	//write it back to user side
       
  1476 	kumemput(aHintPair, &hint, sizeof(RSurfaceManager::THintPair));
       
  1477 	return KErrNone;
       
  1478 	}
       
  1479 
       
  1480 
       
  1481 /**
       
  1482 Set the surface hint value for an existing surface hint key of the surface Id.
       
  1483 @param aSurfaceId  The surface identifier originally returned when the surface was created.
       
  1484 @param aHintPair  The value of the hint pair to set.
       
  1485 @return KErrNone if successful, KErrArgument if the surface ID is invalid or if invalid
       
  1486 hint key used, KErrAccessDenied if the hint pair is immutable or the surface is not open
       
  1487 in the current process, otherwise a system wide error code.
       
  1488 @internalTechnology
       
  1489 */ 
       
  1490 TInt DSurfaceManager::SetSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair)
       
  1491 	{
       
  1492 	RSurfaceManager::THintPair hintPair;
       
  1493 	kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
       
  1494 
       
  1495 	//Check for valid hint key
       
  1496 	if (!hintPair.iKey.iUid)
       
  1497 		{
       
  1498 		TRACE(Kern::Printf("SM SetSurfaceHint Hint key is invalid");)
       
  1499 		return KErrArgument;	//Invalid Hint key
       
  1500 		}
       
  1501 	
       
  1502 	TSurfaceId sid;
       
  1503 	//fetch surface id from user memory
       
  1504 	kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
       
  1505 
       
  1506 	NKern::ThreadEnterCS();
       
  1507 	NKern::FMWait(&iMutex);
       
  1508 	//look it up
       
  1509 	TSurface* surface = FindSurfaceById(sid);
       
  1510 	if (!surface)	
       
  1511 		{
       
  1512 		NKern::FMSignal(&iMutex);
       
  1513 		NKern::ThreadLeaveCS();
       
  1514 		return KErrArgument;
       
  1515 		}
       
  1516 	
       
  1517 	//find the owner
       
  1518 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
  1519 	if (!so)
       
  1520 		{
       
  1521 		NKern::FMSignal(&iMutex);
       
  1522 		NKern::ThreadLeaveCS();
       
  1523 		return KErrAccessDenied;
       
  1524 		}
       
  1525 	
       
  1526 	//at this point, we have a surface, we have to find the hint value based on the hint pair key
       
  1527 	TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid);
       
  1528 	if (index == KErrNotFound)
       
  1529 		{
       
  1530 		TRACE(Kern::Printf("SM SetSurfaceHint Hint key not found or invalid");)
       
  1531 		NKern::FMSignal(&iMutex);
       
  1532 		NKern::ThreadLeaveCS();
       
  1533 		return KErrArgument;	//Hint key not found or invalid
       
  1534 		}
       
  1535 	
       
  1536 	//Check for mutability
       
  1537 	if(!surface->iSurfaceHints[index].iMutable)
       
  1538 		{
       
  1539 		TRACE(Kern::Printf("SM SetSurfaceHint Hint is immutable");)
       
  1540 		NKern::FMSignal(&iMutex);
       
  1541 		NKern::ThreadLeaveCS();
       
  1542 		return KErrAccessDenied;	//Hint pair is immutable
       
  1543 		}
       
  1544 	TRACE(Kern::Printf("SM SetSurfaceHint Hint key found and updated its value %d for the surface %08x \n", aHintPair->iValue, &sid);)
       
  1545 	
       
  1546 	//set the hint pair value now
       
  1547 	memcpy(&surface->iSurfaceHints[index], &hintPair, sizeof(RSurfaceManager::THintPair));
       
  1548 	NKern::FMSignal(&iMutex);
       
  1549 	NKern::ThreadLeaveCS();
       
  1550 
       
  1551 	return KErrNone;
       
  1552 	}
       
  1553 
       
  1554 /**
       
  1555 Add a new surface hint value for the surface Id.
       
  1556 @param aSurfaceId  The surface identifier originally returned when the surface was created.
       
  1557 @param aHintPair  The value of the hint pair to Add.
       
  1558 @return Returns KErrNone if successful, KErrArgument if the surface ID is invalid or the
       
  1559 hint pair has invalid key UID, KErrAccessDenied if the surface is not open in the current
       
  1560 process, KErrAlreadyExists if duplicate hint key used, KErrOverflow if no space to add new
       
  1561 pair, otherwise a system wide error code.
       
  1562 @internalTechnology
       
  1563 */ 
       
  1564 TInt DSurfaceManager::AddSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair)
       
  1565 	{
       
  1566 	RSurfaceManager::THintPair hintPair;
       
  1567 	kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
       
  1568 
       
  1569 	//Check for valid hint key
       
  1570 	if (hintPair.iKey.iUid == 0)
       
  1571 		{
       
  1572 		TRACE(Kern::Printf("SM AddSurfaceHint Hint key is invalid");)
       
  1573 		return KErrArgument;	//Invalid Hint key
       
  1574 		}
       
  1575 	
       
  1576 	TSurfaceId sid;
       
  1577 	//fetch surface id from user memory
       
  1578 	kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
       
  1579 
       
  1580 	NKern::ThreadEnterCS();
       
  1581 	NKern::FMWait(&iMutex);
       
  1582 	//look it up
       
  1583 	TSurface* surface = FindSurfaceById(sid);
       
  1584 	if (!surface)	
       
  1585 		{
       
  1586 		NKern::FMSignal(&iMutex);
       
  1587 		NKern::ThreadLeaveCS();
       
  1588 		return KErrArgument;
       
  1589 		}
       
  1590 	
       
  1591 	//find the owner
       
  1592 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
  1593 	if (!so)
       
  1594 		{
       
  1595 		NKern::FMSignal(&iMutex);
       
  1596 		NKern::ThreadLeaveCS();
       
  1597 		return KErrAccessDenied;
       
  1598 		}
       
  1599 	
       
  1600 
       
  1601 	//Check for empty hint pair
       
  1602 	if(surface->iSurfaceHints[KMaxHintsPerSurface - 1].iKey.iUid != 0)//at least end of sorted hint array should be 0 to add a new hint
       
  1603 		{
       
  1604 		TRACE(Kern::Printf("SM AddSurfaceHint there is no room to add the hint");)
       
  1605 		NKern::FMSignal(&iMutex);
       
  1606 		NKern::ThreadLeaveCS();
       
  1607 		return KErrOverflow;	//No room for new hint
       
  1608 		}
       
  1609 	//We found room for a new hint pair, so insert it in the array
       
  1610 	// Meanwhile, we check for duplication, if it is, return KErrAlreadyExists
       
  1611 	TInt err = InsertHintKey(surface->iSurfaceHints,hintPair);
       
  1612 	NKern::FMSignal(&iMutex);
       
  1613 	TRACE(Kern::Printf("SM AddSurfaceHint Added new key ");)
       
  1614 	NKern::ThreadLeaveCS();
       
  1615 	return err;
       
  1616 	}
       
  1617 
       
  1618 /**
       
  1619 Get the offset of the specified buffer from the base address of the underlying
       
  1620 chunk.
       
  1621 
       
  1622 To obtain the address of the buffer, the offset returned must be added onto the
       
  1623 base address of the RChunk returned in a call to MapSurface(). Note that
       
  1624 buffer offsets are immutable during the lifetime of the surface.
       
  1625 @param aParam The input parameters including the surface ID and buffer index.
       
  1626 @pre The surface is open in the calling process.
       
  1627 @return KErrNone if successful, KErrArgument if aSurfaceId or aBuffer are invalid,
       
  1628 KErrAccessDenied if the surface is not open in the current process, KErrNotSupported if
       
  1629 the surface is not mappable, otherwise a system wide error code.
       
  1630 */
       
  1631 TInt DSurfaceManager::GetBufferOffset(RSurfaceManagerDriver::TDeviceParam* aParam,TUint* aOffset)
       
  1632 	{
       
  1633 	//Get the input parameters
       
  1634 	RSurfaceManagerDriver::TDeviceParam param;
       
  1635 	kumemget(&param, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
       
  1636 	TSurfaceId sid;
       
  1637 	//fetch surface id from user memory
       
  1638 	kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId));
       
  1639 	//(TAny*)iBuffer holds the buffer number in its value
       
  1640 	TInt bufferNumber = (TInt) param.iBuffer;
       
  1641 	
       
  1642 	TSurface* surface = NULL;
       
  1643 	NKern::FMWait(&iMutex);
       
  1644 	surface = FindSurfaceById(sid);
       
  1645 	if(NULL == surface || (bufferNumber >= surface->iBuffers))
       
  1646 		{
       
  1647 		NKern::FMSignal(&iMutex);
       
  1648 		return KErrArgument;
       
  1649 		}
       
  1650 	if(!surface->iMappable)
       
  1651 		{
       
  1652 		NKern::FMSignal(&iMutex);
       
  1653 		return KErrNotSupported;
       
  1654 		}
       
  1655 	//find the owner
       
  1656 	TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
       
  1657 	if (!so)
       
  1658 		{
       
  1659 		NKern::FMSignal(&iMutex);
       
  1660 		return KErrAccessDenied;		
       
  1661 		}
       
  1662 	TInt bufferOffset = surface->iOffsetToFirstBuffer + bufferNumber*surface->iOffsetBetweenBuffers;
       
  1663 	NKern::FMSignal(&iMutex);
       
  1664 	
       
  1665 	kumemput(aOffset, &bufferOffset, sizeof (TInt));
       
  1666 	return KErrNone;
       
  1667 	}
       
  1668 
       
  1669 /**
       
  1670 Returns information specific to the Surface Manager implementation.
       
  1671 @param aAttrib: Attribute to retrieve
       
  1672 @param aValue : Output parameter where we write the value for the specified attribute
       
  1673 @return KErrNone if successful or KErrArgument if the attribute UID is not recognized
       
  1674 @internalTechnology
       
  1675 */
       
  1676 TInt DSurfaceManager::GetSurfaceManagerAttrib(RSurfaceManager::TSurfaceManagerAttrib* aAttrib,TInt* aValue)
       
  1677 	{
       
  1678 	RSurfaceManager::TSurfaceManagerAttrib attrib;
       
  1679 	kumemget(&attrib, aAttrib, sizeof(RSurfaceManager::TSurfaceManagerAttrib));
       
  1680 	
       
  1681 	TInt out=KErrNone;
       
  1682 	TInt value;
       
  1683 	switch (attrib)
       
  1684 		{
       
  1685 		case RSurfaceManager::EMaxNumberOfHints:
       
  1686 			value=KMaxHintsPerSurface;
       
  1687 			break;		
       
  1688 		
       
  1689 		default:
       
  1690 			out=KErrArgument;
       
  1691 			break;			
       
  1692 		};
       
  1693 	
       
  1694 	if (out==KErrNone)
       
  1695 		{
       
  1696 		kumemput(aValue, &value, sizeof (TInt));
       
  1697 		}	
       
  1698 	return out;
       
  1699 	}