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