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