diff -r 4d1fe4a7ce83 -r af143508cc47 graphicshwdrivers/surfacemgr/src/extension.cpp --- a/graphicshwdrivers/surfacemgr/src/extension.cpp Fri Aug 13 15:11:40 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1699 +0,0 @@ -// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// - - -#include -#include -#include -#include -#include "surfacemanager_dev.h" -#include - -/** -Convert the surface Id to an index of the array -based on the least significant 4 bits of the first word of the ID -@param aSurfaceId Const reference to the surface Id -@internalTechnology -*/ -static TInt SurfaceIdToIndex(const TSurfaceId& aSurfaceId) - { - return static_cast(aSurfaceId.iInternal[0]&(KMaxLists-1)); - } - -/** -Removes an item from a linked list -@param aList Pointer to the head of a linked list of type T -@param aOwner Pointer to the object to be removed -@internalTechnology -*/ -template -static void UnlinkListItem(T** aList, const T* aItem) - { - TRACE(Kern::Printf("SM UnlinkListItem list %08x object %08x \n", aList, aItem);) - - __ASSERT_DEBUG(aItem != NULL, Kern::Fault("Surface Manager", __LINE__)); - __ASSERT_DEBUG(*aList != NULL, Kern::Fault("Surface Manager", __LINE__)); - - if (*aList == aItem) //one we want is at the head of the list - { - *aList = aItem->iNext; - return; - } - - T* p = *aList; - T* q = (*aList)->iNext; - while (q) - { - if (q == aItem) - { - p->iNext = q->iNext; - return; - } - p = q; - q = q->iNext; - } - } - - - - -/** -Returns a pointer to the surface owner object for the specified process, for this surface. -@param aProcess Pointer to the process object -@return pointer to the surface owner object if found, else NULL -@internalTechnology -*/ - -TProcessListItem* TSurface::ProcessOwnerInfo(const DProcess* aProcess) - { - TProcessListItem* so = iOwners; - while(so) - { - if (aProcess == so->iOwningProcess) - { - break; - } - so = so->iNext; - } - return so; - } - -/** -Creates a shared chunk surface. -@param aParams Package buffer containing the surface creation parameters. -@param aId Will be set to the surface id of the newly created surface. -@return KErrNone if successful, KErrArgument if the creation attributes were incorrect, -otherwise one of the other system wide error codes. -@see RSurfaceManager::TSurfaceCreationAttributes -@internalTechnology -*/ - -TInt DSurfaceManager::CreateSurface(const TDesC8* aParams, TSurfaceId* aId) - { - - RSurfaceManager::TSurfaceCreationAttributesBuf buf; - RSurfaceManager::TSurfaceCreationAttributes& attribs = buf(); - - Kern::KUDesGet(buf, *aParams); //fetch input parameters - if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) ) - { - return KErrArgument; - } - - RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface]; - if( (attribs.iHintCount>0) && attribs.iSurfaceHints) - { - kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair)); - attribs.iSurfaceHints = tempSurfaceHints; - } - else - { - attribs.iSurfaceHints=NULL; - } - - //validate input parameters and calculate chunk size - TInt roundedBufferSize = attribs.iOffsetBetweenBuffers; - TUint dummyActualSize = 0; - - TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, dummyActualSize, ETrue); - if (chunkSize == 0) - { - return KErrArgument; - } - - TSurfaceId sid; - TInt r = KErrNone; - TSurface* surface = NULL; - do //in the unlikely event that we generate a duplicate surface id, try again. - { - GenerateSurfaceId(sid); - - NKern::FMWait(&iMutex); - surface = FindSurfaceById(sid); - NKern::FMSignal(&iMutex); - } - while (surface); - - //create a shared chunk for the surface memory - TChunkCreateInfo info; - info.iType = TChunkCreateInfo::ESharedKernelMultiple; //multi process mappable - info.iMaxSize = chunkSize; - info.iOwnsMemory = ETrue; - -//iMapAttr is valid only for hardware devices and will not make any effect in wins -#ifndef __WINS__ - info.iMapAttr = (attribs.iCacheAttrib == RSurfaceManager::ECached) ? EMapAttrCachedMax : EMapAttrL1Uncached; -#else - info.iMapAttr = 0; -#endif - - TLinAddr kernAddr; - TUint32 mapAttr; - - NKern::ThreadEnterCS(); - DChunk* chunk; - r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr); - if (KErrNone != r) - { - NKern::ThreadLeaveCS(); - return r; - } - - //commit the memory - TUint32 paddr; - if (attribs.iContiguous) - { - r = Kern::ChunkCommitContiguous(chunk, 0, chunkSize, paddr); - } - else - { - r = Kern::ChunkCommit(chunk, 0, chunkSize); - } - - if (KErrNone != r) - { - //problem committing the memory, - //destroy the chunk and cleanup - Kern::ChunkClose(chunk); - NKern::ThreadLeaveCS(); - return r; - } - - //create a surface structure for the new surface - surface = new TSurface; - TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);) - if (!surface) - { - //destroy the chunk and cleanup, out of memory - Kern::ChunkClose(chunk); - NKern::ThreadLeaveCS(); - return KErrNoMemory; - } - - surface->iId = sid; - surface->iSize = attribs.iSize; - surface->iBuffers = attribs.iBuffers; - surface->iPixelFormat = attribs.iPixelFormat; - surface->iStride = attribs.iStride; - surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer; - surface->iAlignment = attribs.iAlignment; - surface->iContiguous = attribs.iContiguous; - surface->iChunk = chunk; - surface->iOffsetBetweenBuffers = roundedBufferSize; - surface->iCacheAttrib = attribs.iCacheAttrib; - surface->iMappable = attribs.iMappable; - if(attribs.iHintCount>0) - { - memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair)); - } - memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair)); - - //create a surface owner for this surface - TProcessListItem* owner = new TProcessListItem; - TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);) - - if (!owner) - { - //destroy the chunk and cleanup, out of memory - Kern::ChunkClose(chunk); - delete(surface); - TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);) - NKern::ThreadLeaveCS(); - return KErrNoMemory; - } - - owner->iCount = 1; //mark it as open in this process - owner->iOwningProcess = &Kern::CurrentProcess(); - owner->iNext = NULL; - - surface->iOwners = owner; //only 1 owner at creation time - - //at this point we have a fully constructed TSurface - - //add surface to head of surfaces list - NKern::FMWait(&iMutex); - //Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index - //add the new surface to the beginning of the list - TInt index = SurfaceIdToIndex(sid); - surface->iNext = iSurfacesIndex[index]; - iSurfacesIndex[index] = surface; - - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - - //write surface id back to user side - kumemput(aId, &sid, sizeof (TSurfaceId)); - return KErrNone; - } - - -/** -Validate that a chunk contains physical memory for the used areas. - -This function should be called in Critical Section in order to be completed even if the thread -or process is killed and so be able to free the memory allocated (TUint32[pageList]) - -@param aChunk Chunk that the user supplied. -@param aAttribs Surface Creation Attributes. -@param aBuffersize Calculated size of each buffer. -@param aMapAttr Filled in with the mapping attributes of the memory. -@param aIsContiguous Lets the caller know if the surface is physically contiguous or not. -@return KErrNone if successful, KErrArgument if the creation attributes were incorrect, -KErrBadHandle if aChunkHandle is of an invalid shared chunk memory, -otherwise one of the other system wide error codes. -@see RSurfaceManager::TSurfaceCreationAttributes -@internalTechnology -*/ -TInt DSurfaceManager::ValidatePhysicalMemory(DChunk* aChunk, const RSurfaceManager::TSurfaceCreationAttributes& aAttribs, - TUint aBuffersize, TUint32& aMapAttr, TBool &aIsContiguous) - { - TLinAddr kernAddr; - TUint32 physAddr; - - //Get the physical address for a region in a shared chunk - TInt pageSize = Kern::RoundToPageSize(1); - TInt pageList = 1 + (aChunk->iSize + pageSize - 2) / pageSize; - TUint32* physAddr2 = new TUint32[pageList]; - if(!physAddr2) - { - return KErrNoMemory; - } - - // Unless proven otherwise, the memory is not contiguous. - aIsContiguous = EFalse; - TInt r = Kern::ChunkPhysicalAddress(aChunk, 0, aChunk->iSize, kernAddr, aMapAttr, physAddr, physAddr2); - if (KErrNone == r) - { - aIsContiguous = ETrue; - } - - - TRACE(Kern::Printf("SM CreateSurface ChunkPhysicalAddress r %d chunk %08x chunk size %d", r, aChunk, aChunk->iSize);) - TRACE(Kern::Printf("SM CreateSurface kernAddr %08x", kernAddr);) - TRACE(Kern::Printf("SM CreateSurface mapAttr %08x", aMapAttr);) - TRACE(Kern::Printf("SM CreateSurface physAddr %08x", physAddr);) - TRACE(Kern::Printf("SM CreateSurface physAddr2 %08x", physAddr2);) - - if(r < KErrNone) - { - // Error means that there isn't memory in the whole chunk - so check the - // relevant areas - it is allowed to have gaps between the buffers, but not - // within the actual regions that are used for buffers. - - // So, we first check the area before first buffer up to "offsettofirstbuffer", which all should be valid - if (aAttribs.iOffsetToFirstBuffer != 0) - { - r = Kern::ChunkPhysicalAddress(aChunk, 0, aAttribs.iOffsetToFirstBuffer, - kernAddr, aMapAttr, physAddr, physAddr2); - } - else - { - r = KErrNone; - } - - // If that's a pass, loop through and check the actual buffers (leave loop if it fails). - for(TInt i = 0; i < aAttribs.iBuffers && KErrNone <= r; i++) - { - r = Kern::ChunkPhysicalAddress(aChunk, - aAttribs.iOffsetToFirstBuffer + aAttribs.iOffsetBetweenBuffers * i, - aBuffersize, kernAddr, aMapAttr, physAddr, physAddr2); - } - } - - // Fix up weird ChunkPhysicalAddress behaviour - it returns 1 to indicate that memory is non-contiguous. - if (1 == r) - { - r = KErrNone; - } - - delete[] physAddr2; - return r; - } - - -/** -Creates a surface in an existing shared chunk. -@param aParam Package buf containing the surface creation parameters and id to be set to the surface id of the newly created surface. -@param aChunkHandle Existing valid shared chunk handle. -@return KErrNone if successful, KErrArgument if the creation attributes were incorrect, -KErrBadHandle if aChunkHandle is of an invalid shared chunk memory, -otherwise one of the other system wide error codes. -@see RSurfaceManager::TSurfaceCreationAttributes -@internalTechnology -*/ -TInt DSurfaceManager::CreateSurface(RSurfaceManagerDriver::TDeviceParam* aParam, TInt aChunkHandle) - { - RSurfaceManager::TSurfaceCreationAttributesBuf buf; - RSurfaceManager::TSurfaceCreationAttributes& attribs = buf(); - - //Get the input parameters - RSurfaceManagerDriver::TDeviceParam param; - kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam)); - Kern::KUDesGet(buf, *(reinterpret_cast(param.iBuffer))); - if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) ) - { - return KErrArgument; - } - - RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface]; - if( (attribs.iHintCount>0) && attribs.iSurfaceHints) - { - kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair)); - attribs.iSurfaceHints = tempSurfaceHints; - } - else - { - attribs.iSurfaceHints=NULL; - } - - //validate input parameters and calc size - TInt roundedBufferSize = attribs.iOffsetBetweenBuffers; - TUint actualBufferSize = 0; - TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, actualBufferSize); - if (chunkSize == 0) - { - return KErrArgument; - } - - NKern::ThreadEnterCS(); - - //Open an existing shared chunk - DChunk* chunk = Kern::OpenSharedChunk(NULL, aChunkHandle, EFalse); - if(chunk == NULL) - { - NKern::ThreadLeaveCS(); - return KErrBadHandle; - } - - //Check for chunk type as kernel multiple - if(chunk->iChunkType != ESharedKernelMultiple) - { - Kern::ChunkClose(chunk); - NKern::ThreadLeaveCS(); - return KErrBadHandle; - } - - //Check for enough chunk size to create surface for requested attributes - if (chunk->iSize < attribs.iOffsetToFirstBuffer + attribs.iBuffers * actualBufferSize) - { - Kern::ChunkClose(chunk); - NKern::ThreadLeaveCS(); - return KErrArgument; - } - - TSurfaceId sid; - TSurface* surface = NULL; - do //in the unlikely event that we generate a duplicate surface id, try again. - { - GenerateSurfaceId(sid); - - NKern::FMWait(&iMutex); - surface = FindSurfaceById(sid); - NKern::FMSignal(&iMutex); - } - while (surface); - - //create a surface structure for the new surface - surface = new TSurface; - TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);) - if (!surface) - { - //destroy the chunk and cleanup, out of memory - Kern::ChunkClose(chunk); - NKern::ThreadLeaveCS(); - return KErrNoMemory; - } - - TUint32 mapAttr = 0; - TBool isContiguous; - TInt r = ValidatePhysicalMemory(chunk, attribs, actualBufferSize, mapAttr, isContiguous); - if (r != KErrNone) - { - //destroy the surface and close the chunk - delete(surface); - Kern::ChunkClose(chunk); - NKern::ThreadLeaveCS(); - if (r != KErrNoMemory) - { - r = KErrArgument; - } - return r; - } - - surface->iId = sid; - surface->iSize = attribs.iSize; - surface->iBuffers = attribs.iBuffers; - surface->iPixelFormat = attribs.iPixelFormat; - surface->iStride = attribs.iStride; - surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer; - surface->iAlignment = attribs.iAlignment; - surface->iContiguous = isContiguous; - surface->iChunk = chunk; - surface->iOffsetBetweenBuffers = (attribs.iOffsetBetweenBuffers) ? attribs.iOffsetBetweenBuffers : roundedBufferSize; - surface->iMappable = attribs.iMappable; -#ifndef __WINS__ //Creation attribute field will not considered for iCacheAttrib - TUint32 level1Info = mapAttr & EMapAttrL1CacheMask; - TUint32 level2Info = mapAttr & EMapAttrL2CacheMask; - TBool chunkIsNotcached = ((level2Info == EMapAttrL2Uncached) && - ((level1Info == EMapAttrFullyBlocking) || (level1Info == EMapAttrBufferedNC) || - (level1Info == EMapAttrBufferedC) || (level1Info == EMapAttrL1Uncached))); - surface->iCacheAttrib = (chunkIsNotcached) ? RSurfaceManager::ENotCached : RSurfaceManager::ECached; -#else - surface->iCacheAttrib = RSurfaceManager::ENotCached; -#endif - - if(attribs.iHintCount>0) - { - memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair)); - } - memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair)); - - //create a surface owner for this surface - TProcessListItem* owner = new TProcessListItem; - TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);) - - if (!owner) - { - //destroy the chunk and cleanup, out of memory - Kern::ChunkClose(chunk); - delete(surface); - TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);) - NKern::ThreadLeaveCS(); - return KErrNoMemory; - } - - owner->iCount = 1; //mark it as open in this process - owner->iOwningProcess = &Kern::CurrentProcess(); - owner->iNext = NULL; - - surface->iOwners = owner; //only 1 owner at creation time - - NKern::FMWait(&iMutex); - //at this point we have a fully constructed TSurface - //add surface to head of surfaces list - - //Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index - //add the new surface to the beginning of the list - TInt index = SurfaceIdToIndex(sid); - surface->iNext = iSurfacesIndex[index]; - iSurfacesIndex[index] = surface; - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - - //write surface id back to user side - kumemput(reinterpret_cast(param.iSurfaceId), &sid, sizeof (TSurfaceId)); - return KErrNone; - } - - -/** -Opens a surface. If the current process already is in the owners list, its usage count is -incremented. If this is an open from a different process, a new surface owner object is added -to the surface's list of owners and its usage count is set to 1. -@param aId The surface id of the surface to be opened. -@return KErrNone if successful, otherwise a system error code -@internalTechnology -*/ -TInt DSurfaceManager::OpenSurface(const TSurfaceId* aId) - { - TSurfaceId sid; - //fetch surface id from user memory - kumemget(&sid, aId, sizeof (TSurfaceId)); - NKern::ThreadEnterCS(); - TProcessListItem* owner = new TProcessListItem; //speculative creation - TRACE(Kern::Printf("SM A %08x TProcessListItem OpenSurface", owner);) - - NKern::FMWait(&iMutex); - //look it up - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - delete owner; //free the memory just allocated - TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);) - NKern::ThreadLeaveCS(); - return KErrArgument; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (so) - { - //already an owner so inc the ref count - ++so->iCount; - } - else - { - //new process trying to open it - if (!owner) - { - //the creation of the owner information object failed, out of memory - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrNoMemory; - } - - owner->iCount = 1; //mark it open in this process - owner->iOwningProcess = &Kern::CurrentProcess(); - - //add the owner to the list of owners - owner->iNext = surface->iOwners; - surface->iOwners = owner; - owner = NULL; - } - NKern::FMSignal(&iMutex); - delete owner; //free if not used. - TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);) - NKern::ThreadLeaveCS(); - return KErrNone; - } - - - -/** -Closes a surface. Decrements the usage count in the surface owner object -if the usage count is then zero, removes this surface owner from the surface. -If this results in a surface with no owners, the surface is deleted and the -surface shared chunk is closed. -@param aId The id of the surface to be closed -@return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface, -KErrAccessDenied if the surface is not open in the current process, otherwise a system wide -error code. -@internalTechnology -*/ -TInt DSurfaceManager::CloseSurface(const TSurfaceId* aId) - { - - TSurfaceId sid; - kumemget(&sid, aId, sizeof (TSurfaceId)); //fetch surface id from user memory - //look it up - NKern::ThreadEnterCS(); - NKern::FMWait(&iMutex); - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrArgument; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrAccessDenied; - } - - //current process is a surface owner so decrement the open count - TSurface* surfaceToDelete = NULL; - TProcessListItem* ownerToDelete = NULL; - DChunk* chunkToClose = NULL; - if (--so->iCount == 0) - { - //if count is now zero remove the owner - //surface->RemoveOwner(so); - UnlinkListItem(&surface->iOwners, so); - ownerToDelete = so; - - //check to see if the surface has any owners - if (!surface->iOwners) - { - //no more owners of the surface - chunkToClose = surface->iChunk; - - //remove the surface from the list - UnlinkListItem(&(iSurfacesIndex[SurfaceIdToIndex(surface->iId)]), surface); - surfaceToDelete = surface; - } - } - - NKern::FMSignal(&iMutex); - - if (chunkToClose) - { - //surface has no more owners so close the chunk - Kern::ChunkClose(chunkToClose); - } - - delete surfaceToDelete; - TRACE(Kern::Printf("SM D %08x TSurface CloseSurface",surfaceToDelete);) - delete ownerToDelete; - TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurface",ownerToDelete);) - NKern::ThreadLeaveCS(); - - return KErrNone; - } - - -/** -Maps the surface memory into the process of the calling thread. This will fail if -the surface is not open in this process, or if the handle to the chunk cannot be created. -@param aId The id of the surface to be mapped in. -@return KErrNone if successful, KErrArgument if the surface ID does not refer to a -surface, KErrAccessDenied if the surface is not open in the current process, -KErrNotSupported if the surface is not mappable, KErrOverflow if the chunk limit has been -exceeded in the moving memory model, otherwise a system wide error code. -@internalTechnology -*/ -TInt DSurfaceManager::MapSurface(const TSurfaceId* aId) - { - TSurfaceId sid; - kumemget(&sid, aId, sizeof (TSurfaceId)); //fetch surface id from user memory - - //look it up - NKern::ThreadEnterCS(); - NKern::FMWait(&iMutex); - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrArgument; //surface id is not valid or in the list of surfaces - } - if(!surface->iMappable) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrNotSupported; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrAccessDenied; //can't map it in, it's not open in this process - } - - DChunk* chunk = surface->iChunk; - TInt r = chunk->Open(); - NKern::FMSignal(&iMutex); - TRACE(Kern::Printf("SM MapSurface chunk open r %d\n",r);) - - if (r == KErrGeneral) - { - NKern::ThreadLeaveCS(); - return KErrAccessDenied; - } - - //if we are here, got the surface and we are the owner. - //if we are the owner we must have it open at least once - - r = Kern::MakeHandleAndOpen(NULL, chunk); - chunk->Close(NULL); - TRACE(Kern::Printf("SM MapSurface handle open r: %d\n",r);) - - NKern::ThreadLeaveCS(); - - return r; - } - - -/** -Record a new connection to the driver. -Adds an element to the reference counted list of connected processes if the connection -is from a new process, otherwise it increments the reference count. -@param aProcess The process which has opened a driver channel. -@internalTechnology -*/ -TInt DSurfaceManager::AddConnection(const DProcess* aProcess) - { - TRACE(Kern::Printf("SM AddConnection process %08x\n", aProcess);) - NKern::ThreadEnterCS(); - TProcessListItem* connectedProcess = new TProcessListItem; //speculative creation - TRACE(Kern::Printf("SM A %08x TProcessListItem AddConnection", connectedProcess);) - NKern::FMWait(&iMutex); - TProcessListItem* p = FindConnectedProcess(aProcess); - if (p) //already connected, found the process - { - ++p->iCount; - } - else - { - //add a new connected process - if (!connectedProcess) - { - //the creation of the owner information object failed, out of memory - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrNoMemory; - } - connectedProcess->iOwningProcess = (DProcess*)aProcess; - connectedProcess->iCount=1; - - connectedProcess->iNext = iConnectedProcesses; - iConnectedProcesses = connectedProcess; - connectedProcess = NULL; - } - NKern::FMSignal(&iMutex); - delete connectedProcess; - TRACE(Kern::Printf("SM D %08x TProcessListItem AddConnection", connectedProcess);) - NKern::ThreadLeaveCS(); - return KErrNone; - } - - - -/** -Called when the driver channel is closed. -Decrements the reference count for the connected process, if the last connection -for this process is closed (reference count reaches 0) it removes the process from the list. -@param aProcess The process which has closed the driver channel. -@internalTechnology -*/ -void DSurfaceManager::RemoveConnection(const DProcess* aProcess) - { - TRACE(Kern::Printf("SM RemoveConnection process %08x\n", aProcess);) - NKern::ThreadEnterCS(); - NKern::FMWait(&iMutex); - TProcessListItem* p =FindConnectedProcess(aProcess); - TProcessListItem* toDelete = NULL; - if (p) //already connected, found the process - { - if (--p->iCount == 0) //last connection in process has disconnected - { - //remove the process from the list and cleanup - UnlinkListItem(&iConnectedProcesses, p); - toDelete = p; - } - } - NKern::FMSignal(&iMutex); - delete toDelete; - TRACE(Kern::Printf("SM D %08x TProcessListItem RemoveConnection ", toDelete);) - - - if (toDelete) // if a process has closed its last channel, remove process from the surface owners. - { - CloseSurfaceHandlesForProcess(aProcess); - } - - NKern::ThreadLeaveCS(); - } - - - - -/** -Closes all the surfaces belonging to the process which has just terminated. -If this is the only owner of a surface, delete the surface. -@param aProcess The process which has terminated. -@pre must be called in critical section -@internalTechnology -*/ -void DSurfaceManager::CloseSurfaceHandlesForProcess(const DProcess* aProcess) - { - - NKern::FMWait(&iMutex); - - TSurface* p = NULL; - TSurface* surfacesTodelete = NULL; - TProcessListItem* ownersTodelete = NULL; - TProcessListItem* so; - // There are 16 doubly linked lists managed by Surface Manager - for (TInt index = 0; index < KMaxLists; index++) - { - p = iSurfacesIndex[index]; - while(p) - { - //see if the process which has just died is an owner of any surfaces - TSurface* surface = p; - p=p->iNext; - so = surface->ProcessOwnerInfo(aProcess); - if (so) - { - UnlinkListItem(&surface->iOwners, so); - so->iNext = ownersTodelete; //add the owner to the list of owner objects to remove - ownersTodelete = so; - - if (!surface->iOwners) //if the surface hasn't any owners - { - //remove the surface from the list - UnlinkListItem(&iSurfacesIndex[index], surface); - surface->iNext = surfacesTodelete; //add the surface to the list of surfaces to remove - surfacesTodelete = surface; - } - } - } - } - NKern::FMSignal(&iMutex); - - while(surfacesTodelete) - { - p = surfacesTodelete->iNext; - Kern::ChunkClose(surfacesTodelete->iChunk); - TRACE(Kern::Printf("SM Close chunk %08x CloseSurfaceHandlesForProcess",surfacesTodelete->iChunk);) - delete surfacesTodelete; - TRACE(Kern::Printf("SM D %08x TSurface CloseSurfaceHandlesForProcess",surfacesTodelete);) - surfacesTodelete = p; - } - - while(ownersTodelete) - { - so = ownersTodelete->iNext; - delete ownersTodelete; - TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurfaceHandlesForProcess",ownersTodelete);) - ownersTodelete = so; - } - } - - -/** -Returns the metadata information about the specified surface. -@param aId The id of the surface. -@param aInfo Pointer to user side descriptor to receive the information. -@return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface, -KErrAccessDenied if the surface is not open in the current process, otherwise a system wide -error code. -@internalTechnology -*/ -TInt DSurfaceManager::SurfaceInfo(const TSurfaceId* aId, TDes8* aInfo) - { - TSurfaceId sid; - //fetch surface id from user memory - kumemget(&sid, aId, sizeof (TSurfaceId)); - - RSurfaceManager::TInfoBuf buf; - RSurfaceManager::TSurfaceInfoV01& info = buf(); - - NKern::FMWait(&iMutex); - //look it up - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - return KErrArgument; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - return KErrAccessDenied; //can do this, not open - } - - //at this point, we have a surface, we are the owner and it's mapped in - info.iSize = surface->iSize; // Visible width/height in pixels - info.iBuffers = surface->iBuffers; // Number of Buffers - info.iPixelFormat = surface->iPixelFormat; // pixel format - info.iStride = surface->iStride; // Number of bytes between start of one line and start of next - info.iContiguous = surface->iContiguous; // is it physically contiguous - info.iCacheAttrib = surface->iCacheAttrib; // Underlying chunk is CPU cached or not - info.iMappable = surface->iMappable; // Is the surface Mappable - NKern::FMSignal(&iMutex); - - //copy it back to user side - Kern::InfoCopy(*aInfo, buf); - return KErrNone; - } - - - -/** -Generates a unique surface id -@param aId Surface id reference to receive the generated id. -@internalTechnology -*/ -void DSurfaceManager::GenerateSurfaceId(TSurfaceId& aId) - { - TSurfaceId id; - - for (TInt x = 0; x < 4; ++x) - { - id.iInternal[x] = Kern::Random(); - }; - - //package up the handle, - //set the type identifier - id.iInternal[3] &= 0x00FFFFFF; - id.iInternal[3] |= TSurfaceTypes::ESurfaceManagerSurface << 24; - aId = id; - TRACE(Kern::Printf("SM GenerateSurfaceId id = %u %u %u %u\n",id.iInternal[0],id.iInternal[1],id.iInternal[2],id.iInternal[3]);) - }; - - - -/** -Validates the surface creation attributes and calculates the size of the chunk required. -@param aAttribs The surface creation attributes used to specify the surface requirements. -@param aOffset Set to the offset between buffers on successfull return. -@param aNewChunk If this is true, surface is created in a new chunk otherwise the surface is created in an existing chunk -@return The size of chunk required. A size of 0 indicates a problem. -*/ -TInt DSurfaceManager::ValidateAndCalculateChunkSize(RSurfaceManager::TSurfaceCreationAttributes& aAttribs, - TInt& aOffset, TUint &aActualBufferSize, const TBool aNewChunk) - { -/* - TRACE(Kern::Printf("SM width = %d height = %d\n", aAttribs.iSize.iWidth, aAttribs.iSize.iHeight);) - TRACE(Kern::Printf("SM buffers = %d\n", aAttribs.iBuffers);) - TRACE(Kern::Printf("SM format = %d\n", aAttribs.iPixelFormat);) - TRACE(Kern::Printf("SM stride = %d\n", aAttribs.iStride);) - TRACE(Kern::Printf("SM offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);) - TRACE(Kern::Printf("SM offset between buffer = %d\n", aOffset);) - TRACE(Kern::Printf("SM alignment = %d\n", aAttribs.iAlignment);) - TRACE(Kern::Printf("SM contiguous = %d\n\n", aAttribs.iContiguous);) - TRACE(Kern::Printf("SM cacheAttrib = %d\n\n", aAttribs.iCacheAttrib);) -*/ - //check for negative values - if(aAttribs.iOffsetToFirstBuffer < 0 || aOffset < 0 ) - { - TRACE(Kern::Printf("SM Validate offset for negative value");) - return 0; - } - - //check aligment is sensible - TInt alignmentMask = 0; - switch(aAttribs.iAlignment) - { - case 1: - case 2: - case 4: - case 8: - case 16: - case 32: - alignmentMask = 31; - break; - case 64: - alignmentMask = 63; - break; - case RSurfaceManager::EPageAligned: - break; - default: - TRACE(Kern::Printf("SM Validate alignment");) - return 0; - } - - //check alignment issues. - if(aAttribs.iAlignment != RSurfaceManager::EPageAligned) - { - if(aNewChunk) - { - if(aAttribs.iCacheAttrib == RSurfaceManager::ECached) // Surface is CPU cached, so the alignment will be based on either 32 or 64 byte - { - //offset to first buffer needs to fit alignment - aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignmentMask & ~alignmentMask; - //alignment with respect to offsetbetweenbuffers - aOffset = aOffset + alignmentMask & ~alignmentMask; - } - else // Surface is NOT CPU cached, so the alignment will be based on surface attribute alignment - { - TUint alignMask = aAttribs.iAlignment-1; - //offset to first buffer needs to fit alignment - aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignMask & ~alignMask; - //alignment with respect to offsetbetweenbuffers - aOffset = aOffset + alignMask & ~alignMask; - } - } - else // existing chunk - { - TUint alignMask = aAttribs.iAlignment-1; - //check alignment issues. offset to first buffer needs to fit alignment - if (aAttribs.iOffsetToFirstBuffer & alignMask) - { - TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");) - return 0; - } - - //check alignment for offsetbetweenbuffers. offset between buffer needs to fit alignment for existing chunks - if (aOffset & alignMask) - { - TRACE(Kern::Printf("SM Validate offset between buffers misaligned");) - return 0; - } - } - } - else //page aligned - { - if(aNewChunk)// if its a new chunks and doesn't match exact alignment then do the rounding - { - TUint32 pageSize = Kern::RoundToPageSize(1); - //offset to first buffer needs to fit alignment - aAttribs.iOffsetToFirstBuffer = (aAttribs.iOffsetToFirstBuffer + (pageSize - 1)) & ~(pageSize - 1); - //alignment with respect to offsetbetweenbuffers - aOffset = (aOffset + (pageSize - 1)) & ~((pageSize - 1)); - } - else // for existing chunks don't do any rounding operation - { - TUint32 pageSize = Kern::RoundToPageSize(1); - TUint alignmask = aAttribs.iOffsetToFirstBuffer & (pageSize - 1); - if (alignmask) - { - TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");) - return 0; - } - - alignmask = aOffset & (pageSize - 1); - if (alignmask) - { - TRACE(Kern::Printf("SM Validate offset between buffers misaligned");) - return 0; - } - } - } - - //check width and height - if(aAttribs.iSize.iWidth <= 0 || aAttribs.iSize.iHeight <= 0) - { - TRACE(Kern::Printf("SM Validate width/height");) - return 0; - } - - - //check there is at least 1 buffer - if (aAttribs.iBuffers <= 0) - { - TRACE(Kern::Printf("SM Validate buffers");) - return 0; - } - - //Sort the array and also check for duplication - if (!SortHints(aAttribs.iSurfaceHints,aAttribs.iHintCount)) - { - TRACE(Kern::Printf("SM Validate Duplicate hint key");) - return 0; - } - - TUint size = 0; - //calculate buffer size and round it to alignment or to page size - TInt64 bufferSize = aAttribs.iStride; - bufferSize *= aAttribs.iSize.iHeight; - - if (I64HIGH(bufferSize) > 0) //too big - { - TRACE(Kern::Printf("SM Validate chunk buffer size is out of range");) - return 0; - } - - TUint bsize = I64LOW(bufferSize); - if (bsize > KMaxTInt) - { - TRACE(Kern::Printf("SM Validate buffer size is out of range for TInt");) - return 0; - } - - if(aAttribs.iAlignment == RSurfaceManager::EPageAligned) - { - bsize = Kern::RoundToPageSize(bsize); //page alignment - } - else if(aAttribs.iCacheAttrib == RSurfaceManager::ECached) - { - bsize = bsize + alignmentMask & ~alignmentMask; //CPU cached byte alignment, for minimum of the specified alignment(32 or 64) - } - else - { - bsize = bsize + (aAttribs.iAlignment-1) & ~(aAttribs.iAlignment-1); //NON CPU cached byte alignment for 1, 2, 4, 8, 16, 32 and 64 - } - - bufferSize = bsize; - // Remember the actual size. - aActualBufferSize = bsize; - - //if offset between buffers is zero, then assign the calculated value as offset between buffers - if(aOffset == 0) - { - //buffer size rounded to alignment as offset between buffers - aOffset = I64INT(bufferSize); - } - else if(aOffset < I64INT(bufferSize)) - { - TRACE(Kern::Printf("SM Offset between the buffer is less than the required size");) - return 0; - } - else - { - //use the buffer size specified - bufferSize = aOffset; - } - - - TInt64 totalSize = aAttribs.iOffsetToFirstBuffer + (aAttribs.iBuffers * bufferSize); - - if (I64HIGH(totalSize) > 0) //too big - { - TRACE(Kern::Printf("SM Validate chunk size is out of range for RoundToPageSize");) - return 0; - } - - size = I64LOW(totalSize); - if (size > KMaxTInt) - { - TRACE(Kern::Printf("SM Validate size is out of range for TInt");) - return 0; - } - - size = Kern::RoundToPageSize(size); - - //check the size isn't greater than will fit in a TInt - if (size > KMaxTInt) - { - TRACE(Kern::Printf("SM Rounded size is out of range for TInt");) - return 0; - } - - TRACE(Kern::Printf("SM After validate - offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);) - TRACE(Kern::Printf("SM After validate - offset between buffer = %d\n", aOffset);) - TRACE(Kern::Printf("SM CalculateChunkSize size = %d\n", size);) - return size; - } - - -/** -Find the surface in the list. -@param aId The surface id of the surface to find in the surface list -@return pointer to the surface object -@internalTechnology -*/ -TSurface* DSurfaceManager::FindSurfaceById(const TSurfaceId& aId) - { - TSurface *p = iSurfacesIndex[SurfaceIdToIndex(aId)]; - while (p) - { - if (aId == p->iId) - { - //found it - return p; - } - - p = p->iNext; - } - return NULL; - } - - -/** -Find the index of the hint key from the surface list using binary search. -@param aHintsArray Pointer to the first element in the array of surface hints -@param aKey The surface hint key uid value to search in the surface list -@return index of the hint pair key in the surface list, KErrNotFound if key not found -@internalTechnology -*/ -TInt DSurfaceManager::FindHintKey(const RSurfaceManager::THintPair* aHintsArray, TUint32 aKey) const - { - __ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__)); - - TInt bottom = 0; - TInt top = KMaxHintsPerSurface - 1; - TInt mid; - while (bottom <= top) - { - mid = (bottom + top) / 2; - if((TUint) aHintsArray[mid].iKey.iUid == aKey) - { - return mid; - } - else if ((TUint)aHintsArray[mid].iKey.iUid < aKey) - { - top = mid - 1; - } - else - { - bottom = mid + 1; - } - } - return KErrNotFound; //Hint key not found - } - -TProcessListItem* DSurfaceManager::FindConnectedProcess(const DProcess* aProcess) - { - TProcessListItem * p = iConnectedProcesses; - while (p) - { - if (aProcess == p->iOwningProcess) - { - //found it - return p; - } - - p = p->iNext; - } - return NULL; - } - -/** -Searches for a right place to insert the new hint pair in a sorted array. -@param aHintsArray Pointer to the first element in the sorted array -@param aKey The surface hint key uid value to search in the surface list -@pre, there is at least one empty place in the array -@return KErrNone if a new hint pair key inserted in the surface list, KErrAlreadyExists if duplicated -@internalTechnology -*/ -TInt DSurfaceManager::InsertHintKey(RSurfaceManager::THintPair* aHintsArray, const RSurfaceManager::THintPair& aHintPair) const - { - __ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__)); - __ASSERT_DEBUG(aHintsArray[KMaxHintsPerSurface-1].iKey.iUid == NULL, Kern::Fault("Surface Manager", __LINE__)); - - TInt pos = 0; - if (aHintsArray[pos].iKey.iUid != 0) - { - while((TUint)aHintsArray[pos].iKey.iUid>(TUint)aHintPair.iKey.iUid && pos < KMaxHintsPerSurface-1) - {// find the right place to insert - ++pos; - } - - if((TUint)aHintsArray[pos].iKey.iUid==(TUint)aHintPair.iKey.iUid) - { - //Duplicate key - return KErrAlreadyExists; - } - else - { - // Shift right - memmove(aHintsArray+pos+1, aHintsArray+pos, (KMaxHintsPerSurface-pos-1)*sizeof(RSurfaceManager::THintPair)); - } - } - aHintsArray[pos] = aHintPair; - return KErrNone; - } - -/** -Sort the surface hint array in descending order. -@param aHintsArray The surface hintpair in the surface list -@param aNumberOfHints The number of hints -@return ETrue if sorting is finished or it is an empty array, EFalse if key duplicated -@internalTechnology -*/ -TBool DSurfaceManager::SortHints(RSurfaceManager::THintPair* aHintsArray, TInt aNumberOfHints) const - { - TInt in = 0; - TInt out = 0; - RSurfaceManager::THintPair temp; - if(!aHintsArray) - { - return ETrue; - } - for(out = 0; out < aNumberOfHints; ++out) - { - if(aHintsArray[out].iKey.iUid != 0) - { - temp = aHintsArray[out]; - in = out; // start shifting at out - while(in > 0 && (TUint)aHintsArray[in-1].iKey.iUid <= (TUint)temp.iKey.iUid) - { - if ((TUint)aHintsArray[in-1].iKey.iUid == (TUint)temp.iKey.iUid) - { - return EFalse; //duplicate hint keys are not allowed - } - aHintsArray[in] = aHintsArray[in-1]; // shift item to the right - --in; // go left one position - } - aHintsArray[in] = temp; // insert marked item - } - } - return ETrue; - } - - -/** -Ensures the memory is updated consistently before/after triggering non CPU hardware access. -@param aParam The suface id and buffer number (0 based). -@param aOperation The type of the synchronize operation. -@return KErrNone if successful, KErrArgument if the surface ID is invalid or -buffer number is invalid, KErrAccessDenied if the surface is not open in this -process, otherwise a system wide error code. -@see RSurfaceManager::TSyncOperation -@internalTechnology -*/ -TInt DSurfaceManager::SynchronizeCache(RSurfaceManagerDriver::TDeviceParam* aParam, RSurfaceManager::TSyncOperation aOperation) - { - //Parse the parameters - RSurfaceManagerDriver::TDeviceParam param; - kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam)); - TSurfaceId sid; - kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId)); - TInt buffer = (TInt)param.iBuffer; - - NKern::ThreadEnterCS(); - NKern::FMWait(&iMutex); - //look it up - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrArgument; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrAccessDenied; - } - - // surfaces have to have at least one buffer - __ASSERT_DEBUG(surface->iBuffers > 0, Kern::Fault("Surface Manager", __LINE__)); - - //Validate the buffer number is within range - if((buffer >= surface->iBuffers) || (buffer < 0)) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrArgument; - } - - DChunk* chunk = surface->iChunk; - TInt offsetBetweenBuffers = surface->iOffsetBetweenBuffers; - NKern::FMSignal(&iMutex); - - TUint32 kernAddr; - TUint32 mapAttr; - TUint32 physAddr; - TInt pageList = chunk->iSize / Kern::RoundToPageSize(1) + 1; - TUint32* physAddr2 = new TUint32[pageList]; - if(!physAddr2) - { - NKern::ThreadLeaveCS(); - return KErrNoMemory; - } - - TRACE(Kern::Printf("SM %08x DChunk SynchronizeCache", chunk);) - - //Retrieve the kernel address and mapping attribute from the chunk - TInt err = Kern::ChunkPhysicalAddress(chunk, surface->iOffsetToFirstBuffer + (buffer * offsetBetweenBuffers), offsetBetweenBuffers, kernAddr, mapAttr, physAddr, physAddr2); - delete[] physAddr2; - if(err >= KErrNone) - { - TRACE(Kern::Printf("SM %08x kernAddr SynchronizeCache", kernAddr);) - TRACE(Kern::Printf("SM %08x mapAttr SynchronizeCache", mapAttr);) - err = KErrNone; - - // Do the sync operation - switch(aOperation) - { - case RSurfaceManager::ESyncBeforeNonCPURead: - Cache::SyncMemoryBeforeDmaWrite(kernAddr, offsetBetweenBuffers, mapAttr); - break; - case RSurfaceManager::ESyncBeforeNonCPUWrite: - Cache::SyncMemoryBeforeDmaRead(kernAddr, offsetBetweenBuffers, mapAttr); - break; - case RSurfaceManager::ESyncAfterNonCPUWrite: - Cache::SyncMemoryAfterDmaRead(kernAddr, offsetBetweenBuffers); - break; - default: - err = KErrArgument; - break; - } - } - NKern::ThreadLeaveCS(); - - return err; - } - - -/** -Get the surface hint value for the given surface ID and hint pair key. -@param aSurfaceId The surface identifier originally returned when the surface was created. -@param aHintPair The hint value for the requested hint pair key. -@return KErrNone if successful, KErrArgument if the surface ID is invalid or -invalid hint pair key used, KErrAccessDenied if the surface is not open in the -current process, otherwise a system wide error code. -@internalTechnology -*/ -TInt DSurfaceManager::GetSurfaceHint(const TSurfaceId* aSurfaceId, RSurfaceManager::THintPair* aHintPair) - { - RSurfaceManager::THintPair hintPair; - kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair)); - - if (hintPair.iKey.iUid == 0) - { - TRACE(Kern::Printf("SM GetSurfaceHint Hint key is invalid");) - return KErrArgument; //Invalid Hint key - } - - TSurfaceId sid; - //fetch surface id from user memory - kumemget(&sid, aSurfaceId, sizeof (TSurfaceId)); - - NKern::FMWait(&iMutex); - //look it up - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - return KErrArgument; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - return KErrAccessDenied; - } - - //at this point, we have a surface, we have to find the hint value based on the hint pair key - TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid); - - if (index == KErrNotFound) - { - TRACE(Kern::Printf("SM GetSurfaceHint Hint key not found");) - NKern::FMSignal(&iMutex); - return KErrArgument; //Hint key not found - } - - RSurfaceManager::THintPair hint = surface->iSurfaceHints[index]; - NKern::FMSignal(&iMutex); - - TRACE(Kern::Printf("SM GetSurfaceHint Hint value %d", hint.iValue);) - //write it back to user side - kumemput(aHintPair, &hint, sizeof(RSurfaceManager::THintPair)); - return KErrNone; - } - - -/** -Set the surface hint value for an existing surface hint key of the surface Id. -@param aSurfaceId The surface identifier originally returned when the surface was created. -@param aHintPair The value of the hint pair to set. -@return KErrNone if successful, KErrArgument if the surface ID is invalid or if invalid -hint key used, KErrAccessDenied if the hint pair is immutable or the surface is not open -in the current process, otherwise a system wide error code. -@internalTechnology -*/ -TInt DSurfaceManager::SetSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair) - { - RSurfaceManager::THintPair hintPair; - kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair)); - - //Check for valid hint key - if (!hintPair.iKey.iUid) - { - TRACE(Kern::Printf("SM SetSurfaceHint Hint key is invalid");) - return KErrArgument; //Invalid Hint key - } - - TSurfaceId sid; - //fetch surface id from user memory - kumemget(&sid, aSurfaceId, sizeof (TSurfaceId)); - - NKern::ThreadEnterCS(); - NKern::FMWait(&iMutex); - //look it up - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrArgument; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrAccessDenied; - } - - //at this point, we have a surface, we have to find the hint value based on the hint pair key - TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid); - if (index == KErrNotFound) - { - TRACE(Kern::Printf("SM SetSurfaceHint Hint key not found or invalid");) - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrArgument; //Hint key not found or invalid - } - - //Check for mutability - if(!surface->iSurfaceHints[index].iMutable) - { - TRACE(Kern::Printf("SM SetSurfaceHint Hint is immutable");) - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrAccessDenied; //Hint pair is immutable - } - TRACE(Kern::Printf("SM SetSurfaceHint Hint key found and updated its value %d for the surface %08x \n", aHintPair->iValue, &sid);) - - //set the hint pair value now - memcpy(&surface->iSurfaceHints[index], &hintPair, sizeof(RSurfaceManager::THintPair)); - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - - return KErrNone; - } - -/** -Add a new surface hint value for the surface Id. -@param aSurfaceId The surface identifier originally returned when the surface was created. -@param aHintPair The value of the hint pair to Add. -@return Returns KErrNone if successful, KErrArgument if the surface ID is invalid or the -hint pair has invalid key UID, KErrAccessDenied if the surface is not open in the current -process, KErrAlreadyExists if duplicate hint key used, KErrOverflow if no space to add new -pair, otherwise a system wide error code. -@internalTechnology -*/ -TInt DSurfaceManager::AddSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair) - { - RSurfaceManager::THintPair hintPair; - kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair)); - - //Check for valid hint key - if (hintPair.iKey.iUid == 0) - { - TRACE(Kern::Printf("SM AddSurfaceHint Hint key is invalid");) - return KErrArgument; //Invalid Hint key - } - - TSurfaceId sid; - //fetch surface id from user memory - kumemget(&sid, aSurfaceId, sizeof (TSurfaceId)); - - NKern::ThreadEnterCS(); - NKern::FMWait(&iMutex); - //look it up - TSurface* surface = FindSurfaceById(sid); - if (!surface) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrArgument; - } - - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrAccessDenied; - } - - - //Check for empty hint pair - if(surface->iSurfaceHints[KMaxHintsPerSurface - 1].iKey.iUid != 0)//at least end of sorted hint array should be 0 to add a new hint - { - TRACE(Kern::Printf("SM AddSurfaceHint there is no room to add the hint");) - NKern::FMSignal(&iMutex); - NKern::ThreadLeaveCS(); - return KErrOverflow; //No room for new hint - } - //We found room for a new hint pair, so insert it in the array - // Meanwhile, we check for duplication, if it is, return KErrAlreadyExists - TInt err = InsertHintKey(surface->iSurfaceHints,hintPair); - NKern::FMSignal(&iMutex); - TRACE(Kern::Printf("SM AddSurfaceHint Added new key ");) - NKern::ThreadLeaveCS(); - return err; - } - -/** -Get the offset of the specified buffer from the base address of the underlying -chunk. - -To obtain the address of the buffer, the offset returned must be added onto the -base address of the RChunk returned in a call to MapSurface(). Note that -buffer offsets are immutable during the lifetime of the surface. -@param aParam The input parameters including the surface ID and buffer index. -@pre The surface is open in the calling process. -@return KErrNone if successful, KErrArgument if aSurfaceId or aBuffer are invalid, -KErrAccessDenied if the surface is not open in the current process, KErrNotSupported if -the surface is not mappable, otherwise a system wide error code. -*/ -TInt DSurfaceManager::GetBufferOffset(RSurfaceManagerDriver::TDeviceParam* aParam,TUint* aOffset) - { - //Get the input parameters - RSurfaceManagerDriver::TDeviceParam param; - kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam)); - TSurfaceId sid; - //fetch surface id from user memory - kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId)); - //(TAny*)iBuffer holds the buffer number in its value - TInt bufferNumber = (TInt) param.iBuffer; - - TSurface* surface = NULL; - NKern::FMWait(&iMutex); - surface = FindSurfaceById(sid); - if(NULL == surface || (bufferNumber >= surface->iBuffers)) - { - NKern::FMSignal(&iMutex); - return KErrArgument; - } - if(!surface->iMappable) - { - NKern::FMSignal(&iMutex); - return KErrNotSupported; - } - //find the owner - TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess()); - if (!so) - { - NKern::FMSignal(&iMutex); - return KErrAccessDenied; - } - TInt bufferOffset = surface->iOffsetToFirstBuffer + bufferNumber*surface->iOffsetBetweenBuffers; - NKern::FMSignal(&iMutex); - - kumemput(aOffset, &bufferOffset, sizeof (TInt)); - return KErrNone; - } - -/** -Returns information specific to the Surface Manager implementation. -@param aAttrib: Attribute to retrieve -@param aValue : Output parameter where we write the value for the specified attribute -@return KErrNone if successful or KErrArgument if the attribute UID is not recognized -@internalTechnology -*/ -TInt DSurfaceManager::GetSurfaceManagerAttrib(RSurfaceManager::TSurfaceManagerAttrib* aAttrib,TInt* aValue) - { - RSurfaceManager::TSurfaceManagerAttrib attrib; - kumemget(&attrib, aAttrib, sizeof(RSurfaceManager::TSurfaceManagerAttrib)); - - TInt out=KErrNone; - TInt value; - switch (attrib) - { - case RSurfaceManager::EMaxNumberOfHints: - value=KMaxHintsPerSurface; - break; - - default: - out=KErrArgument; - break; - }; - - if (out==KErrNone) - { - kumemput(aValue, &value, sizeof (TInt)); - } - return out; - }