First public contribution.
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 #include <kernel/kern_priv.h>
18 #include <graphics/surface.h>
19 #include <graphics/surfacetypes.h>
20 #include <graphics/surfacemanager.h>
21 #include "surfacemanager_dev.h"
22 #include <kernel/cache.h>
25 Convert the surface Id to an index of the array
26 based on the least significant 4 bits of the first word of the ID
27 @param aSurfaceId Const reference to the surface Id
30 static TInt SurfaceIdToIndex(const TSurfaceId& aSurfaceId)
32 return static_cast<TInt>(aSurfaceId.iInternal[0]&(KMaxLists-1));
36 Removes an item from a linked list
37 @param aList Pointer to the head of a linked list of type T
38 @param aOwner Pointer to the object to be removed
42 static void UnlinkListItem(T** aList, const T* aItem)
44 TRACE(Kern::Printf("SM UnlinkListItem list %08x object %08x \n", aList, aItem);)
46 __ASSERT_DEBUG(aItem != NULL, Kern::Fault("Surface Manager", __LINE__));
47 __ASSERT_DEBUG(*aList != NULL, Kern::Fault("Surface Manager", __LINE__));
49 if (*aList == aItem) //one we want is at the head of the list
51 *aList = aItem->iNext;
56 T* q = (*aList)->iNext;
73 Returns a pointer to the surface owner object for the specified process, for this surface.
74 @param aProcess Pointer to the process object
75 @return pointer to the surface owner object if found, else NULL
79 TProcessListItem* TSurface::ProcessOwnerInfo(const DProcess* aProcess)
81 TProcessListItem* so = iOwners;
84 if (aProcess == so->iOwningProcess)
94 Creates a shared chunk surface.
95 @param aParams Package buffer containing the surface creation parameters.
96 @param aId Will be set to the surface id of the newly created surface.
97 @return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
98 otherwise one of the other system wide error codes.
99 @see RSurfaceManager::TSurfaceCreationAttributes
103 TInt DSurfaceManager::CreateSurface(const TDesC8* aParams, TSurfaceId* aId)
106 RSurfaceManager::TSurfaceCreationAttributesBuf buf;
107 RSurfaceManager::TSurfaceCreationAttributes& attribs = buf();
109 Kern::KUDesGet(buf, *aParams); //fetch input parameters
110 if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) )
115 RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface];
116 if( (attribs.iHintCount>0) && attribs.iSurfaceHints)
118 kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
119 attribs.iSurfaceHints = tempSurfaceHints;
123 attribs.iSurfaceHints=NULL;
126 //validate input parameters and calculate chunk size
127 TInt roundedBufferSize = attribs.iOffsetBetweenBuffers;
128 TUint dummyActualSize = 0;
130 TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, dummyActualSize, ETrue);
138 TSurface* surface = NULL;
139 do //in the unlikely event that we generate a duplicate surface id, try again.
141 GenerateSurfaceId(sid);
143 NKern::FMWait(&iMutex);
144 surface = FindSurfaceById(sid);
145 NKern::FMSignal(&iMutex);
149 //create a shared chunk for the surface memory
150 TChunkCreateInfo info;
151 info.iType = TChunkCreateInfo::ESharedKernelMultiple; //multi process mappable
152 info.iMaxSize = chunkSize;
153 info.iOwnsMemory = ETrue;
155 //iMapAttr is valid only for hardware devices and will not make any effect in wins
157 info.iMapAttr = (attribs.iCacheAttrib == RSurfaceManager::ECached) ? EMapAttrCachedMax : EMapAttrL1Uncached;
165 NKern::ThreadEnterCS();
167 r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr);
170 NKern::ThreadLeaveCS();
176 if (attribs.iContiguous)
178 r = Kern::ChunkCommitContiguous(chunk, 0, chunkSize, paddr);
182 r = Kern::ChunkCommit(chunk, 0, chunkSize);
187 //problem committing the memory,
188 //destroy the chunk and cleanup
189 Kern::ChunkClose(chunk);
190 NKern::ThreadLeaveCS();
194 //create a surface structure for the new surface
195 surface = new TSurface;
196 TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);)
199 //destroy the chunk and cleanup, out of memory
200 Kern::ChunkClose(chunk);
201 NKern::ThreadLeaveCS();
206 surface->iSize = attribs.iSize;
207 surface->iBuffers = attribs.iBuffers;
208 surface->iPixelFormat = attribs.iPixelFormat;
209 surface->iStride = attribs.iStride;
210 surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer;
211 surface->iAlignment = attribs.iAlignment;
212 surface->iContiguous = attribs.iContiguous;
213 surface->iChunk = chunk;
214 surface->iOffsetBetweenBuffers = roundedBufferSize;
215 surface->iCacheAttrib = attribs.iCacheAttrib;
216 surface->iMappable = attribs.iMappable;
217 if(attribs.iHintCount>0)
219 memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
221 memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair));
223 //create a surface owner for this surface
224 TProcessListItem* owner = new TProcessListItem;
225 TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);)
229 //destroy the chunk and cleanup, out of memory
230 Kern::ChunkClose(chunk);
232 TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);)
233 NKern::ThreadLeaveCS();
237 owner->iCount = 1; //mark it as open in this process
238 owner->iOwningProcess = &Kern::CurrentProcess();
241 surface->iOwners = owner; //only 1 owner at creation time
243 //at this point we have a fully constructed TSurface
245 //add surface to head of surfaces list
246 NKern::FMWait(&iMutex);
247 //Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index
248 //add the new surface to the beginning of the list
249 TInt index = SurfaceIdToIndex(sid);
250 surface->iNext = iSurfacesIndex[index];
251 iSurfacesIndex[index] = surface;
253 NKern::FMSignal(&iMutex);
254 NKern::ThreadLeaveCS();
256 //write surface id back to user side
257 kumemput(aId, &sid, sizeof (TSurfaceId));
263 Validate that a chunk contains physical memory for the used areas.
265 This function should be called in Critical Section in order to be completed even if the thread
266 or process is killed and so be able to free the memory allocated (TUint32[pageList])
268 @param aChunk Chunk that the user supplied.
269 @param aAttribs Surface Creation Attributes.
270 @param aBuffersize Calculated size of each buffer.
271 @param aMapAttr Filled in with the mapping attributes of the memory.
272 @param aIsContiguous Lets the caller know if the surface is physically contiguous or not.
273 @return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
274 KErrBadHandle if aChunkHandle is of an invalid shared chunk memory,
275 otherwise one of the other system wide error codes.
276 @see RSurfaceManager::TSurfaceCreationAttributes
279 TInt DSurfaceManager::ValidatePhysicalMemory(DChunk* aChunk, const RSurfaceManager::TSurfaceCreationAttributes& aAttribs,
280 TUint aBuffersize, TUint32& aMapAttr, TBool &aIsContiguous)
285 //Get the physical address for a region in a shared chunk
286 TInt pageSize = Kern::RoundToPageSize(1);
287 TInt pageList = 1 + (aChunk->iSize + pageSize - 2) / pageSize;
288 TUint32* physAddr2 = new TUint32[pageList];
294 // Unless proven otherwise, the memory is not contiguous.
295 aIsContiguous = EFalse;
296 TInt r = Kern::ChunkPhysicalAddress(aChunk, 0, aChunk->iSize, kernAddr, aMapAttr, physAddr, physAddr2);
299 aIsContiguous = ETrue;
303 TRACE(Kern::Printf("SM CreateSurface ChunkPhysicalAddress r %d chunk %08x chunk size %d", r, aChunk, aChunk->iSize);)
304 TRACE(Kern::Printf("SM CreateSurface kernAddr %08x", kernAddr);)
305 TRACE(Kern::Printf("SM CreateSurface mapAttr %08x", aMapAttr);)
306 TRACE(Kern::Printf("SM CreateSurface physAddr %08x", physAddr);)
307 TRACE(Kern::Printf("SM CreateSurface physAddr2 %08x", physAddr2);)
311 // Error means that there isn't memory in the whole chunk - so check the
312 // relevant areas - it is allowed to have gaps between the buffers, but not
313 // within the actual regions that are used for buffers.
315 // So, we first check the area before first buffer up to "offsettofirstbuffer", which all should be valid
316 if (aAttribs.iOffsetToFirstBuffer != 0)
318 r = Kern::ChunkPhysicalAddress(aChunk, 0, aAttribs.iOffsetToFirstBuffer,
319 kernAddr, aMapAttr, physAddr, physAddr2);
326 // If that's a pass, loop through and check the actual buffers (leave loop if it fails).
327 for(TInt i = 0; i < aAttribs.iBuffers && KErrNone <= r; i++)
329 r = Kern::ChunkPhysicalAddress(aChunk,
330 aAttribs.iOffsetToFirstBuffer + aAttribs.iOffsetBetweenBuffers * i,
331 aBuffersize, kernAddr, aMapAttr, physAddr, physAddr2);
335 // Fix up weird ChunkPhysicalAddress behaviour - it returns 1 to indicate that memory is non-contiguous.
347 Creates a surface in an existing shared chunk.
348 @param aParam Package buf containing the surface creation parameters and id to be set to the surface id of the newly created surface.
349 @param aChunkHandle Existing valid shared chunk handle.
350 @return KErrNone if successful, KErrArgument if the creation attributes were incorrect,
351 KErrBadHandle if aChunkHandle is of an invalid shared chunk memory,
352 otherwise one of the other system wide error codes.
353 @see RSurfaceManager::TSurfaceCreationAttributes
356 TInt DSurfaceManager::CreateSurface(RSurfaceManagerDriver::TDeviceParam* aParam, TInt aChunkHandle)
358 RSurfaceManager::TSurfaceCreationAttributesBuf buf;
359 RSurfaceManager::TSurfaceCreationAttributes& attribs = buf();
361 //Get the input parameters
362 RSurfaceManagerDriver::TDeviceParam param;
363 kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
364 Kern::KUDesGet(buf, *(reinterpret_cast<const TDesC8*>(param.iBuffer)));
365 if( (attribs.iHintCount > KMaxHintsPerSurface) || (attribs.iHintCount<0) )
370 RSurfaceManager::THintPair tempSurfaceHints[KMaxHintsPerSurface];
371 if( (attribs.iHintCount>0) && attribs.iSurfaceHints)
373 kumemget(tempSurfaceHints, attribs.iSurfaceHints, attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
374 attribs.iSurfaceHints = tempSurfaceHints;
378 attribs.iSurfaceHints=NULL;
381 //validate input parameters and calc size
382 TInt roundedBufferSize = attribs.iOffsetBetweenBuffers;
383 TUint actualBufferSize = 0;
384 TInt chunkSize = ValidateAndCalculateChunkSize(attribs, roundedBufferSize, actualBufferSize);
390 NKern::ThreadEnterCS();
392 //Open an existing shared chunk
393 DChunk* chunk = Kern::OpenSharedChunk(NULL, aChunkHandle, EFalse);
396 NKern::ThreadLeaveCS();
397 return KErrBadHandle;
400 //Check for chunk type as kernel multiple
401 if(chunk->iChunkType != ESharedKernelMultiple)
403 Kern::ChunkClose(chunk);
404 NKern::ThreadLeaveCS();
405 return KErrBadHandle;
408 //Check for enough chunk size to create surface for requested attributes
409 if (chunk->iSize < attribs.iOffsetToFirstBuffer + attribs.iBuffers * actualBufferSize)
411 Kern::ChunkClose(chunk);
412 NKern::ThreadLeaveCS();
417 TSurface* surface = NULL;
418 do //in the unlikely event that we generate a duplicate surface id, try again.
420 GenerateSurfaceId(sid);
422 NKern::FMWait(&iMutex);
423 surface = FindSurfaceById(sid);
424 NKern::FMSignal(&iMutex);
428 //create a surface structure for the new surface
429 surface = new TSurface;
430 TRACE(Kern::Printf("SM A %08x TSurface CreateSurface",surface);)
433 //destroy the chunk and cleanup, out of memory
434 Kern::ChunkClose(chunk);
435 NKern::ThreadLeaveCS();
441 TInt r = ValidatePhysicalMemory(chunk, attribs, actualBufferSize, mapAttr, isContiguous);
444 //destroy the surface and close the chunk
446 Kern::ChunkClose(chunk);
447 NKern::ThreadLeaveCS();
448 if (r != KErrNoMemory)
456 surface->iSize = attribs.iSize;
457 surface->iBuffers = attribs.iBuffers;
458 surface->iPixelFormat = attribs.iPixelFormat;
459 surface->iStride = attribs.iStride;
460 surface->iOffsetToFirstBuffer = attribs.iOffsetToFirstBuffer;
461 surface->iAlignment = attribs.iAlignment;
462 surface->iContiguous = isContiguous;
463 surface->iChunk = chunk;
464 surface->iOffsetBetweenBuffers = (attribs.iOffsetBetweenBuffers) ? attribs.iOffsetBetweenBuffers : roundedBufferSize;
465 surface->iMappable = attribs.iMappable;
466 #ifndef __WINS__ //Creation attribute field will not considered for iCacheAttrib
467 TUint32 level1Info = mapAttr & EMapAttrL1CacheMask;
468 TUint32 level2Info = mapAttr & EMapAttrL2CacheMask;
469 TBool chunkIsNotcached = ((level2Info == EMapAttrL2Uncached) &&
470 ((level1Info == EMapAttrFullyBlocking) || (level1Info == EMapAttrBufferedNC) ||
471 (level1Info == EMapAttrBufferedC) || (level1Info == EMapAttrL1Uncached)));
472 surface->iCacheAttrib = (chunkIsNotcached) ? RSurfaceManager::ENotCached : RSurfaceManager::ECached;
474 surface->iCacheAttrib = RSurfaceManager::ENotCached;
477 if(attribs.iHintCount>0)
479 memcpy(surface->iSurfaceHints,tempSurfaceHints,attribs.iHintCount*sizeof(RSurfaceManager::THintPair));
481 memclr(surface->iSurfaceHints+attribs.iHintCount, (KMaxHintsPerSurface-attribs.iHintCount)*sizeof(RSurfaceManager::THintPair));
483 //create a surface owner for this surface
484 TProcessListItem* owner = new TProcessListItem;
485 TRACE(Kern::Printf("SM A %08x TProcessListItem CreateSurface",owner);)
489 //destroy the chunk and cleanup, out of memory
490 Kern::ChunkClose(chunk);
492 TRACE(Kern::Printf("SM D %08x TSurface CreateSurface",surface);)
493 NKern::ThreadLeaveCS();
497 owner->iCount = 1; //mark it as open in this process
498 owner->iOwningProcess = &Kern::CurrentProcess();
501 surface->iOwners = owner; //only 1 owner at creation time
503 NKern::FMWait(&iMutex);
504 //at this point we have a fully constructed TSurface
505 //add surface to head of surfaces list
507 //Mask off the bottom log2(KMaxLists) bits of the first word of the surfaceID as an index
508 //add the new surface to the beginning of the list
509 TInt index = SurfaceIdToIndex(sid);
510 surface->iNext = iSurfacesIndex[index];
511 iSurfacesIndex[index] = surface;
512 NKern::FMSignal(&iMutex);
513 NKern::ThreadLeaveCS();
515 //write surface id back to user side
516 kumemput(reinterpret_cast<TSurfaceId*>(param.iSurfaceId), &sid, sizeof (TSurfaceId));
522 Opens a surface. If the current process already is in the owners list, its usage count is
523 incremented. If this is an open from a different process, a new surface owner object is added
524 to the surface's list of owners and its usage count is set to 1.
525 @param aId The surface id of the surface to be opened.
526 @return KErrNone if successful, otherwise a system error code
529 TInt DSurfaceManager::OpenSurface(const TSurfaceId* aId)
532 //fetch surface id from user memory
533 kumemget(&sid, aId, sizeof (TSurfaceId));
534 NKern::ThreadEnterCS();
535 TProcessListItem* owner = new TProcessListItem; //speculative creation
536 TRACE(Kern::Printf("SM A %08x TProcessListItem OpenSurface", owner);)
538 NKern::FMWait(&iMutex);
540 TSurface* surface = FindSurfaceById(sid);
543 NKern::FMSignal(&iMutex);
544 delete owner; //free the memory just allocated
545 TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);)
546 NKern::ThreadLeaveCS();
551 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
554 //already an owner so inc the ref count
559 //new process trying to open it
562 //the creation of the owner information object failed, out of memory
563 NKern::FMSignal(&iMutex);
564 NKern::ThreadLeaveCS();
568 owner->iCount = 1; //mark it open in this process
569 owner->iOwningProcess = &Kern::CurrentProcess();
571 //add the owner to the list of owners
572 owner->iNext = surface->iOwners;
573 surface->iOwners = owner;
576 NKern::FMSignal(&iMutex);
577 delete owner; //free if not used.
578 TRACE(Kern::Printf("SM D %08x TProcessListItem OpenSurface", owner);)
579 NKern::ThreadLeaveCS();
586 Closes a surface. Decrements the usage count in the surface owner object
587 if the usage count is then zero, removes this surface owner from the surface.
588 If this results in a surface with no owners, the surface is deleted and the
589 surface shared chunk is closed.
590 @param aId The id of the surface to be closed
591 @return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface,
592 KErrAccessDenied if the surface is not open in the current process, otherwise a system wide
596 TInt DSurfaceManager::CloseSurface(const TSurfaceId* aId)
600 kumemget(&sid, aId, sizeof (TSurfaceId)); //fetch surface id from user memory
602 NKern::ThreadEnterCS();
603 NKern::FMWait(&iMutex);
604 TSurface* surface = FindSurfaceById(sid);
607 NKern::FMSignal(&iMutex);
608 NKern::ThreadLeaveCS();
613 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
616 NKern::FMSignal(&iMutex);
617 NKern::ThreadLeaveCS();
618 return KErrAccessDenied;
621 //current process is a surface owner so decrement the open count
622 TSurface* surfaceToDelete = NULL;
623 TProcessListItem* ownerToDelete = NULL;
624 DChunk* chunkToClose = NULL;
625 if (--so->iCount == 0)
627 //if count is now zero remove the owner
628 //surface->RemoveOwner(so);
629 UnlinkListItem(&surface->iOwners, so);
632 //check to see if the surface has any owners
633 if (!surface->iOwners)
635 //no more owners of the surface
636 chunkToClose = surface->iChunk;
638 //remove the surface from the list
639 UnlinkListItem(&(iSurfacesIndex[SurfaceIdToIndex(surface->iId)]), surface);
640 surfaceToDelete = surface;
644 NKern::FMSignal(&iMutex);
648 //surface has no more owners so close the chunk
649 Kern::ChunkClose(chunkToClose);
652 delete surfaceToDelete;
653 TRACE(Kern::Printf("SM D %08x TSurface CloseSurface",surfaceToDelete);)
654 delete ownerToDelete;
655 TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurface",ownerToDelete);)
656 NKern::ThreadLeaveCS();
663 Maps the surface memory into the process of the calling thread. This will fail if
664 the surface is not open in this process, or if the handle to the chunk cannot be created.
665 @param aId The id of the surface to be mapped in.
666 @return KErrNone if successful, KErrArgument if the surface ID does not refer to a
667 surface, KErrAccessDenied if the surface is not open in the current process,
668 KErrNotSupported if the surface is not mappable, KErrOverflow if the chunk limit has been
669 exceeded in the moving memory model, otherwise a system wide error code.
672 TInt DSurfaceManager::MapSurface(const TSurfaceId* aId)
675 kumemget(&sid, aId, sizeof (TSurfaceId)); //fetch surface id from user memory
678 NKern::ThreadEnterCS();
679 NKern::FMWait(&iMutex);
680 TSurface* surface = FindSurfaceById(sid);
683 NKern::FMSignal(&iMutex);
684 NKern::ThreadLeaveCS();
685 return KErrArgument; //surface id is not valid or in the list of surfaces
687 if(!surface->iMappable)
689 NKern::FMSignal(&iMutex);
690 NKern::ThreadLeaveCS();
691 return KErrNotSupported;
695 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
698 NKern::FMSignal(&iMutex);
699 NKern::ThreadLeaveCS();
700 return KErrAccessDenied; //can't map it in, it's not open in this process
703 DChunk* chunk = surface->iChunk;
704 TInt r = chunk->Open();
705 NKern::FMSignal(&iMutex);
706 TRACE(Kern::Printf("SM MapSurface chunk open r %d\n",r);)
708 if (r == KErrGeneral)
710 NKern::ThreadLeaveCS();
711 return KErrAccessDenied;
714 //if we are here, got the surface and we are the owner.
715 //if we are the owner we must have it open at least once
717 r = Kern::MakeHandleAndOpen(NULL, chunk);
719 TRACE(Kern::Printf("SM MapSurface handle open r: %d\n",r);)
721 NKern::ThreadLeaveCS();
728 Record a new connection to the driver.
729 Adds an element to the reference counted list of connected processes if the connection
730 is from a new process, otherwise it increments the reference count.
731 @param aProcess The process which has opened a driver channel.
734 TInt DSurfaceManager::AddConnection(const DProcess* aProcess)
736 TRACE(Kern::Printf("SM AddConnection process %08x\n", aProcess);)
737 NKern::ThreadEnterCS();
738 TProcessListItem* connectedProcess = new TProcessListItem; //speculative creation
739 TRACE(Kern::Printf("SM A %08x TProcessListItem AddConnection", connectedProcess);)
740 NKern::FMWait(&iMutex);
741 TProcessListItem* p = FindConnectedProcess(aProcess);
742 if (p) //already connected, found the process
748 //add a new connected process
749 if (!connectedProcess)
751 //the creation of the owner information object failed, out of memory
752 NKern::FMSignal(&iMutex);
753 NKern::ThreadLeaveCS();
756 connectedProcess->iOwningProcess = (DProcess*)aProcess;
757 connectedProcess->iCount=1;
759 connectedProcess->iNext = iConnectedProcesses;
760 iConnectedProcesses = connectedProcess;
761 connectedProcess = NULL;
763 NKern::FMSignal(&iMutex);
764 delete connectedProcess;
765 TRACE(Kern::Printf("SM D %08x TProcessListItem AddConnection", connectedProcess);)
766 NKern::ThreadLeaveCS();
773 Called when the driver channel is closed.
774 Decrements the reference count for the connected process, if the last connection
775 for this process is closed (reference count reaches 0) it removes the process from the list.
776 @param aProcess The process which has closed the driver channel.
779 void DSurfaceManager::RemoveConnection(const DProcess* aProcess)
781 TRACE(Kern::Printf("SM RemoveConnection process %08x\n", aProcess);)
782 NKern::ThreadEnterCS();
783 NKern::FMWait(&iMutex);
784 TProcessListItem* p =FindConnectedProcess(aProcess);
785 TProcessListItem* toDelete = NULL;
786 if (p) //already connected, found the process
788 if (--p->iCount == 0) //last connection in process has disconnected
790 //remove the process from the list and cleanup
791 UnlinkListItem(&iConnectedProcesses, p);
795 NKern::FMSignal(&iMutex);
797 TRACE(Kern::Printf("SM D %08x TProcessListItem RemoveConnection ", toDelete);)
800 if (toDelete) // if a process has closed its last channel, remove process from the surface owners.
802 CloseSurfaceHandlesForProcess(aProcess);
805 NKern::ThreadLeaveCS();
812 Closes all the surfaces belonging to the process which has just terminated.
813 If this is the only owner of a surface, delete the surface.
814 @param aProcess The process which has terminated.
815 @pre must be called in critical section
818 void DSurfaceManager::CloseSurfaceHandlesForProcess(const DProcess* aProcess)
821 NKern::FMWait(&iMutex);
824 TSurface* surfacesTodelete = NULL;
825 TProcessListItem* ownersTodelete = NULL;
826 TProcessListItem* so;
827 // There are 16 doubly linked lists managed by Surface Manager
828 for (TInt index = 0; index < KMaxLists; index++)
830 p = iSurfacesIndex[index];
833 //see if the process which has just died is an owner of any surfaces
834 TSurface* surface = p;
836 so = surface->ProcessOwnerInfo(aProcess);
839 UnlinkListItem(&surface->iOwners, so);
840 so->iNext = ownersTodelete; //add the owner to the list of owner objects to remove
843 if (!surface->iOwners) //if the surface hasn't any owners
845 //remove the surface from the list
846 UnlinkListItem(&iSurfacesIndex[index], surface);
847 surface->iNext = surfacesTodelete; //add the surface to the list of surfaces to remove
848 surfacesTodelete = surface;
853 NKern::FMSignal(&iMutex);
855 while(surfacesTodelete)
857 p = surfacesTodelete->iNext;
858 Kern::ChunkClose(surfacesTodelete->iChunk);
859 TRACE(Kern::Printf("SM Close chunk %08x CloseSurfaceHandlesForProcess",surfacesTodelete->iChunk);)
860 delete surfacesTodelete;
861 TRACE(Kern::Printf("SM D %08x TSurface CloseSurfaceHandlesForProcess",surfacesTodelete);)
862 surfacesTodelete = p;
865 while(ownersTodelete)
867 so = ownersTodelete->iNext;
868 delete ownersTodelete;
869 TRACE(Kern::Printf("SM D %08x TProcessListItem CloseSurfaceHandlesForProcess",ownersTodelete);)
876 Returns the metadata information about the specified surface.
877 @param aId The id of the surface.
878 @param aInfo Pointer to user side descriptor to receive the information.
879 @return KErrNone if successful, KErrArgument if the surface ID does not refer to a surface,
880 KErrAccessDenied if the surface is not open in the current process, otherwise a system wide
884 TInt DSurfaceManager::SurfaceInfo(const TSurfaceId* aId, TDes8* aInfo)
887 //fetch surface id from user memory
888 kumemget(&sid, aId, sizeof (TSurfaceId));
890 RSurfaceManager::TInfoBuf buf;
891 RSurfaceManager::TSurfaceInfoV01& info = buf();
893 NKern::FMWait(&iMutex);
895 TSurface* surface = FindSurfaceById(sid);
898 NKern::FMSignal(&iMutex);
903 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
906 NKern::FMSignal(&iMutex);
907 return KErrAccessDenied; //can do this, not open
910 //at this point, we have a surface, we are the owner and it's mapped in
911 info.iSize = surface->iSize; // Visible width/height in pixels
912 info.iBuffers = surface->iBuffers; // Number of Buffers
913 info.iPixelFormat = surface->iPixelFormat; // pixel format
914 info.iStride = surface->iStride; // Number of bytes between start of one line and start of next
915 info.iContiguous = surface->iContiguous; // is it physically contiguous
916 info.iCacheAttrib = surface->iCacheAttrib; // Underlying chunk is CPU cached or not
917 info.iMappable = surface->iMappable; // Is the surface Mappable
918 NKern::FMSignal(&iMutex);
920 //copy it back to user side
921 Kern::InfoCopy(*aInfo, buf);
928 Generates a unique surface id
929 @param aId Surface id reference to receive the generated id.
932 void DSurfaceManager::GenerateSurfaceId(TSurfaceId& aId)
936 for (TInt x = 0; x < 4; ++x)
938 id.iInternal[x] = Kern::Random();
941 //package up the handle,
942 //set the type identifier
943 id.iInternal[3] &= 0x00FFFFFF;
944 id.iInternal[3] |= TSurfaceTypes::ESurfaceManagerSurface << 24;
946 TRACE(Kern::Printf("SM GenerateSurfaceId id = %u %u %u %u\n",id.iInternal[0],id.iInternal[1],id.iInternal[2],id.iInternal[3]);)
952 Validates the surface creation attributes and calculates the size of the chunk required.
953 @param aAttribs The surface creation attributes used to specify the surface requirements.
954 @param aOffset Set to the offset between buffers on successfull return.
955 @param aNewChunk If this is true, surface is created in a new chunk otherwise the surface is created in an existing chunk
956 @return The size of chunk required. A size of 0 indicates a problem.
958 TInt DSurfaceManager::ValidateAndCalculateChunkSize(RSurfaceManager::TSurfaceCreationAttributes& aAttribs,
959 TInt& aOffset, TUint &aActualBufferSize, const TBool aNewChunk)
962 TRACE(Kern::Printf("SM width = %d height = %d\n", aAttribs.iSize.iWidth, aAttribs.iSize.iHeight);)
963 TRACE(Kern::Printf("SM buffers = %d\n", aAttribs.iBuffers);)
964 TRACE(Kern::Printf("SM format = %d\n", aAttribs.iPixelFormat);)
965 TRACE(Kern::Printf("SM stride = %d\n", aAttribs.iStride);)
966 TRACE(Kern::Printf("SM offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);)
967 TRACE(Kern::Printf("SM offset between buffer = %d\n", aOffset);)
968 TRACE(Kern::Printf("SM alignment = %d\n", aAttribs.iAlignment);)
969 TRACE(Kern::Printf("SM contiguous = %d\n\n", aAttribs.iContiguous);)
970 TRACE(Kern::Printf("SM cacheAttrib = %d\n\n", aAttribs.iCacheAttrib);)
972 //check for negative values
973 if(aAttribs.iOffsetToFirstBuffer < 0 || aOffset < 0 )
975 TRACE(Kern::Printf("SM Validate offset for negative value");)
979 //check aligment is sensible
980 TInt alignmentMask = 0;
981 switch(aAttribs.iAlignment)
994 case RSurfaceManager::EPageAligned:
997 TRACE(Kern::Printf("SM Validate alignment");)
1001 //check alignment issues.
1002 if(aAttribs.iAlignment != RSurfaceManager::EPageAligned)
1006 if(aAttribs.iCacheAttrib == RSurfaceManager::ECached) // Surface is CPU cached, so the alignment will be based on either 32 or 64 byte
1008 //offset to first buffer needs to fit alignment
1009 aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignmentMask & ~alignmentMask;
1010 //alignment with respect to offsetbetweenbuffers
1011 aOffset = aOffset + alignmentMask & ~alignmentMask;
1013 else // Surface is NOT CPU cached, so the alignment will be based on surface attribute alignment
1015 TUint alignMask = aAttribs.iAlignment-1;
1016 //offset to first buffer needs to fit alignment
1017 aAttribs.iOffsetToFirstBuffer = aAttribs.iOffsetToFirstBuffer + alignMask & ~alignMask;
1018 //alignment with respect to offsetbetweenbuffers
1019 aOffset = aOffset + alignMask & ~alignMask;
1022 else // existing chunk
1024 TUint alignMask = aAttribs.iAlignment-1;
1025 //check alignment issues. offset to first buffer needs to fit alignment
1026 if (aAttribs.iOffsetToFirstBuffer & alignMask)
1028 TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");)
1032 //check alignment for offsetbetweenbuffers. offset between buffer needs to fit alignment for existing chunks
1033 if (aOffset & alignMask)
1035 TRACE(Kern::Printf("SM Validate offset between buffers misaligned");)
1042 if(aNewChunk)// if its a new chunks and doesn't match exact alignment then do the rounding
1044 TUint32 pageSize = Kern::RoundToPageSize(1);
1045 //offset to first buffer needs to fit alignment
1046 aAttribs.iOffsetToFirstBuffer = (aAttribs.iOffsetToFirstBuffer + (pageSize - 1)) & ~(pageSize - 1);
1047 //alignment with respect to offsetbetweenbuffers
1048 aOffset = (aOffset + (pageSize - 1)) & ~((pageSize - 1));
1050 else // for existing chunks don't do any rounding operation
1052 TUint32 pageSize = Kern::RoundToPageSize(1);
1053 TUint alignmask = aAttribs.iOffsetToFirstBuffer & (pageSize - 1);
1056 TRACE(Kern::Printf("SM Validate offset to first pixel misaligned");)
1060 alignmask = aOffset & (pageSize - 1);
1063 TRACE(Kern::Printf("SM Validate offset between buffers misaligned");)
1069 //check width and height
1070 if(aAttribs.iSize.iWidth <= 0 || aAttribs.iSize.iHeight <= 0)
1072 TRACE(Kern::Printf("SM Validate width/height");)
1077 //check there is at least 1 buffer
1078 if (aAttribs.iBuffers <= 0)
1080 TRACE(Kern::Printf("SM Validate buffers");)
1084 //Sort the array and also check for duplication
1085 if (!SortHints(aAttribs.iSurfaceHints,aAttribs.iHintCount))
1087 TRACE(Kern::Printf("SM Validate Duplicate hint key");)
1092 //calculate buffer size and round it to alignment or to page size
1093 TInt64 bufferSize = aAttribs.iStride;
1094 bufferSize *= aAttribs.iSize.iHeight;
1096 if (I64HIGH(bufferSize) > 0) //too big
1098 TRACE(Kern::Printf("SM Validate chunk buffer size is out of range");)
1102 TUint bsize = I64LOW(bufferSize);
1103 if (bsize > KMaxTInt)
1105 TRACE(Kern::Printf("SM Validate buffer size is out of range for TInt");)
1109 if(aAttribs.iAlignment == RSurfaceManager::EPageAligned)
1111 bsize = Kern::RoundToPageSize(bsize); //page alignment
1113 else if(aAttribs.iCacheAttrib == RSurfaceManager::ECached)
1115 bsize = bsize + alignmentMask & ~alignmentMask; //CPU cached byte alignment, for minimum of the specified alignment(32 or 64)
1119 bsize = bsize + (aAttribs.iAlignment-1) & ~(aAttribs.iAlignment-1); //NON CPU cached byte alignment for 1, 2, 4, 8, 16, 32 and 64
1123 // Remember the actual size.
1124 aActualBufferSize = bsize;
1126 //if offset between buffers is zero, then assign the calculated value as offset between buffers
1129 //buffer size rounded to alignment as offset between buffers
1130 aOffset = I64INT(bufferSize);
1132 else if(aOffset < I64INT(bufferSize))
1134 TRACE(Kern::Printf("SM Offset between the buffer is less than the required size");)
1139 //use the buffer size specified
1140 bufferSize = aOffset;
1144 TInt64 totalSize = aAttribs.iOffsetToFirstBuffer + (aAttribs.iBuffers * bufferSize);
1146 if (I64HIGH(totalSize) > 0) //too big
1148 TRACE(Kern::Printf("SM Validate chunk size is out of range for RoundToPageSize");)
1152 size = I64LOW(totalSize);
1153 if (size > KMaxTInt)
1155 TRACE(Kern::Printf("SM Validate size is out of range for TInt");)
1159 size = Kern::RoundToPageSize(size);
1161 //check the size isn't greater than will fit in a TInt
1162 if (size > KMaxTInt)
1164 TRACE(Kern::Printf("SM Rounded size is out of range for TInt");)
1168 TRACE(Kern::Printf("SM After validate - offset to first buffer = %d\n", aAttribs.iOffsetToFirstBuffer);)
1169 TRACE(Kern::Printf("SM After validate - offset between buffer = %d\n", aOffset);)
1170 TRACE(Kern::Printf("SM CalculateChunkSize size = %d\n", size);)
1176 Find the surface in the list.
1177 @param aId The surface id of the surface to find in the surface list
1178 @return pointer to the surface object
1181 TSurface* DSurfaceManager::FindSurfaceById(const TSurfaceId& aId)
1183 TSurface *p = iSurfacesIndex[SurfaceIdToIndex(aId)];
1199 Find the index of the hint key from the surface list using binary search.
1200 @param aHintsArray Pointer to the first element in the array of surface hints
1201 @param aKey The surface hint key uid value to search in the surface list
1202 @return index of the hint pair key in the surface list, KErrNotFound if key not found
1205 TInt DSurfaceManager::FindHintKey(const RSurfaceManager::THintPair* aHintsArray, TUint32 aKey) const
1207 __ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__));
1210 TInt top = KMaxHintsPerSurface - 1;
1212 while (bottom <= top)
1214 mid = (bottom + top) / 2;
1215 if((TUint) aHintsArray[mid].iKey.iUid == aKey)
1219 else if ((TUint)aHintsArray[mid].iKey.iUid < aKey)
1228 return KErrNotFound; //Hint key not found
1231 TProcessListItem* DSurfaceManager::FindConnectedProcess(const DProcess* aProcess)
1233 TProcessListItem * p = iConnectedProcesses;
1236 if (aProcess == p->iOwningProcess)
1248 Searches for a right place to insert the new hint pair in a sorted array.
1249 @param aHintsArray Pointer to the first element in the sorted array
1250 @param aKey The surface hint key uid value to search in the surface list
1251 @pre, there is at least one empty place in the array
1252 @return KErrNone if a new hint pair key inserted in the surface list, KErrAlreadyExists if duplicated
1255 TInt DSurfaceManager::InsertHintKey(RSurfaceManager::THintPair* aHintsArray, const RSurfaceManager::THintPair& aHintPair) const
1257 __ASSERT_DEBUG(aHintsArray != NULL, Kern::Fault("Surface Manager", __LINE__));
1258 __ASSERT_DEBUG(aHintsArray[KMaxHintsPerSurface-1].iKey.iUid == NULL, Kern::Fault("Surface Manager", __LINE__));
1261 if (aHintsArray[pos].iKey.iUid != 0)
1263 while((TUint)aHintsArray[pos].iKey.iUid>(TUint)aHintPair.iKey.iUid && pos < KMaxHintsPerSurface-1)
1264 {// find the right place to insert
1268 if((TUint)aHintsArray[pos].iKey.iUid==(TUint)aHintPair.iKey.iUid)
1271 return KErrAlreadyExists;
1276 memmove(aHintsArray+pos+1, aHintsArray+pos, (KMaxHintsPerSurface-pos-1)*sizeof(RSurfaceManager::THintPair));
1279 aHintsArray[pos] = aHintPair;
1284 Sort the surface hint array in descending order.
1285 @param aHintsArray The surface hintpair in the surface list
1286 @param aNumberOfHints The number of hints
1287 @return ETrue if sorting is finished or it is an empty array, EFalse if key duplicated
1290 TBool DSurfaceManager::SortHints(RSurfaceManager::THintPair* aHintsArray, TInt aNumberOfHints) const
1294 RSurfaceManager::THintPair temp;
1299 for(out = 0; out < aNumberOfHints; ++out)
1301 if(aHintsArray[out].iKey.iUid != 0)
1303 temp = aHintsArray[out];
1304 in = out; // start shifting at out
1305 while(in > 0 && (TUint)aHintsArray[in-1].iKey.iUid <= (TUint)temp.iKey.iUid)
1307 if ((TUint)aHintsArray[in-1].iKey.iUid == (TUint)temp.iKey.iUid)
1309 return EFalse; //duplicate hint keys are not allowed
1311 aHintsArray[in] = aHintsArray[in-1]; // shift item to the right
1312 --in; // go left one position
1314 aHintsArray[in] = temp; // insert marked item
1322 Ensures the memory is updated consistently before/after triggering non CPU hardware access.
1323 @param aParam The suface id and buffer number (0 based).
1324 @param aOperation The type of the synchronize operation.
1325 @return KErrNone if successful, KErrArgument if the surface ID is invalid or
1326 buffer number is invalid, KErrAccessDenied if the surface is not open in this
1327 process, otherwise a system wide error code.
1328 @see RSurfaceManager::TSyncOperation
1331 TInt DSurfaceManager::SynchronizeCache(RSurfaceManagerDriver::TDeviceParam* aParam, RSurfaceManager::TSyncOperation aOperation)
1333 //Parse the parameters
1334 RSurfaceManagerDriver::TDeviceParam param;
1335 kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
1337 kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId));
1338 TInt buffer = (TInt)param.iBuffer;
1340 NKern::ThreadEnterCS();
1341 NKern::FMWait(&iMutex);
1343 TSurface* surface = FindSurfaceById(sid);
1346 NKern::FMSignal(&iMutex);
1347 NKern::ThreadLeaveCS();
1348 return KErrArgument;
1352 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1355 NKern::FMSignal(&iMutex);
1356 NKern::ThreadLeaveCS();
1357 return KErrAccessDenied;
1360 // surfaces have to have at least one buffer
1361 __ASSERT_DEBUG(surface->iBuffers > 0, Kern::Fault("Surface Manager", __LINE__));
1363 //Validate the buffer number is within range
1364 if((buffer >= surface->iBuffers) || (buffer < 0))
1366 NKern::FMSignal(&iMutex);
1367 NKern::ThreadLeaveCS();
1368 return KErrArgument;
1371 DChunk* chunk = surface->iChunk;
1372 TInt offsetBetweenBuffers = surface->iOffsetBetweenBuffers;
1373 NKern::FMSignal(&iMutex);
1378 TInt pageList = chunk->iSize / Kern::RoundToPageSize(1) + 1;
1379 TUint32* physAddr2 = new TUint32[pageList];
1382 NKern::ThreadLeaveCS();
1383 return KErrNoMemory;
1386 TRACE(Kern::Printf("SM %08x DChunk SynchronizeCache", chunk);)
1388 //Retrieve the kernel address and mapping attribute from the chunk
1389 TInt err = Kern::ChunkPhysicalAddress(chunk, surface->iOffsetToFirstBuffer + (buffer * offsetBetweenBuffers), offsetBetweenBuffers, kernAddr, mapAttr, physAddr, physAddr2);
1393 TRACE(Kern::Printf("SM %08x kernAddr SynchronizeCache", kernAddr);)
1394 TRACE(Kern::Printf("SM %08x mapAttr SynchronizeCache", mapAttr);)
1397 // Do the sync operation
1400 case RSurfaceManager::ESyncBeforeNonCPURead:
1401 Cache::SyncMemoryBeforeDmaWrite(kernAddr, offsetBetweenBuffers, mapAttr);
1403 case RSurfaceManager::ESyncBeforeNonCPUWrite:
1404 Cache::SyncMemoryBeforeDmaRead(kernAddr, offsetBetweenBuffers, mapAttr);
1406 case RSurfaceManager::ESyncAfterNonCPUWrite:
1407 Cache::SyncMemoryAfterDmaRead(kernAddr, offsetBetweenBuffers);
1414 NKern::ThreadLeaveCS();
1421 Get the surface hint value for the given surface ID and hint pair key.
1422 @param aSurfaceId The surface identifier originally returned when the surface was created.
1423 @param aHintPair The hint value for the requested hint pair key.
1424 @return KErrNone if successful, KErrArgument if the surface ID is invalid or
1425 invalid hint pair key used, KErrAccessDenied if the surface is not open in the
1426 current process, otherwise a system wide error code.
1429 TInt DSurfaceManager::GetSurfaceHint(const TSurfaceId* aSurfaceId, RSurfaceManager::THintPair* aHintPair)
1431 RSurfaceManager::THintPair hintPair;
1432 kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
1434 if (hintPair.iKey.iUid == 0)
1436 TRACE(Kern::Printf("SM GetSurfaceHint Hint key is invalid");)
1437 return KErrArgument; //Invalid Hint key
1441 //fetch surface id from user memory
1442 kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
1444 NKern::FMWait(&iMutex);
1446 TSurface* surface = FindSurfaceById(sid);
1449 NKern::FMSignal(&iMutex);
1450 return KErrArgument;
1454 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1457 NKern::FMSignal(&iMutex);
1458 return KErrAccessDenied;
1461 //at this point, we have a surface, we have to find the hint value based on the hint pair key
1462 TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid);
1464 if (index == KErrNotFound)
1466 TRACE(Kern::Printf("SM GetSurfaceHint Hint key not found");)
1467 NKern::FMSignal(&iMutex);
1468 return KErrArgument; //Hint key not found
1471 RSurfaceManager::THintPair hint = surface->iSurfaceHints[index];
1472 NKern::FMSignal(&iMutex);
1474 TRACE(Kern::Printf("SM GetSurfaceHint Hint value %d", hint.iValue);)
1475 //write it back to user side
1476 kumemput(aHintPair, &hint, sizeof(RSurfaceManager::THintPair));
1482 Set the surface hint value for an existing surface hint key of the surface Id.
1483 @param aSurfaceId The surface identifier originally returned when the surface was created.
1484 @param aHintPair The value of the hint pair to set.
1485 @return KErrNone if successful, KErrArgument if the surface ID is invalid or if invalid
1486 hint key used, KErrAccessDenied if the hint pair is immutable or the surface is not open
1487 in the current process, otherwise a system wide error code.
1490 TInt DSurfaceManager::SetSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair)
1492 RSurfaceManager::THintPair hintPair;
1493 kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
1495 //Check for valid hint key
1496 if (!hintPair.iKey.iUid)
1498 TRACE(Kern::Printf("SM SetSurfaceHint Hint key is invalid");)
1499 return KErrArgument; //Invalid Hint key
1503 //fetch surface id from user memory
1504 kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
1506 NKern::ThreadEnterCS();
1507 NKern::FMWait(&iMutex);
1509 TSurface* surface = FindSurfaceById(sid);
1512 NKern::FMSignal(&iMutex);
1513 NKern::ThreadLeaveCS();
1514 return KErrArgument;
1518 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1521 NKern::FMSignal(&iMutex);
1522 NKern::ThreadLeaveCS();
1523 return KErrAccessDenied;
1526 //at this point, we have a surface, we have to find the hint value based on the hint pair key
1527 TInt index = FindHintKey(surface->iSurfaceHints, hintPair.iKey.iUid);
1528 if (index == KErrNotFound)
1530 TRACE(Kern::Printf("SM SetSurfaceHint Hint key not found or invalid");)
1531 NKern::FMSignal(&iMutex);
1532 NKern::ThreadLeaveCS();
1533 return KErrArgument; //Hint key not found or invalid
1536 //Check for mutability
1537 if(!surface->iSurfaceHints[index].iMutable)
1539 TRACE(Kern::Printf("SM SetSurfaceHint Hint is immutable");)
1540 NKern::FMSignal(&iMutex);
1541 NKern::ThreadLeaveCS();
1542 return KErrAccessDenied; //Hint pair is immutable
1544 TRACE(Kern::Printf("SM SetSurfaceHint Hint key found and updated its value %d for the surface %08x \n", aHintPair->iValue, &sid);)
1546 //set the hint pair value now
1547 memcpy(&surface->iSurfaceHints[index], &hintPair, sizeof(RSurfaceManager::THintPair));
1548 NKern::FMSignal(&iMutex);
1549 NKern::ThreadLeaveCS();
1555 Add a new surface hint value for the surface Id.
1556 @param aSurfaceId The surface identifier originally returned when the surface was created.
1557 @param aHintPair The value of the hint pair to Add.
1558 @return Returns KErrNone if successful, KErrArgument if the surface ID is invalid or the
1559 hint pair has invalid key UID, KErrAccessDenied if the surface is not open in the current
1560 process, KErrAlreadyExists if duplicate hint key used, KErrOverflow if no space to add new
1561 pair, otherwise a system wide error code.
1564 TInt DSurfaceManager::AddSurfaceHint(const TSurfaceId* aSurfaceId, const RSurfaceManager::THintPair* aHintPair)
1566 RSurfaceManager::THintPair hintPair;
1567 kumemget(&hintPair, aHintPair, sizeof(RSurfaceManager::THintPair));
1569 //Check for valid hint key
1570 if (hintPair.iKey.iUid == 0)
1572 TRACE(Kern::Printf("SM AddSurfaceHint Hint key is invalid");)
1573 return KErrArgument; //Invalid Hint key
1577 //fetch surface id from user memory
1578 kumemget(&sid, aSurfaceId, sizeof (TSurfaceId));
1580 NKern::ThreadEnterCS();
1581 NKern::FMWait(&iMutex);
1583 TSurface* surface = FindSurfaceById(sid);
1586 NKern::FMSignal(&iMutex);
1587 NKern::ThreadLeaveCS();
1588 return KErrArgument;
1592 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1595 NKern::FMSignal(&iMutex);
1596 NKern::ThreadLeaveCS();
1597 return KErrAccessDenied;
1601 //Check for empty hint pair
1602 if(surface->iSurfaceHints[KMaxHintsPerSurface - 1].iKey.iUid != 0)//at least end of sorted hint array should be 0 to add a new hint
1604 TRACE(Kern::Printf("SM AddSurfaceHint there is no room to add the hint");)
1605 NKern::FMSignal(&iMutex);
1606 NKern::ThreadLeaveCS();
1607 return KErrOverflow; //No room for new hint
1609 //We found room for a new hint pair, so insert it in the array
1610 // Meanwhile, we check for duplication, if it is, return KErrAlreadyExists
1611 TInt err = InsertHintKey(surface->iSurfaceHints,hintPair);
1612 NKern::FMSignal(&iMutex);
1613 TRACE(Kern::Printf("SM AddSurfaceHint Added new key ");)
1614 NKern::ThreadLeaveCS();
1619 Get the offset of the specified buffer from the base address of the underlying
1622 To obtain the address of the buffer, the offset returned must be added onto the
1623 base address of the RChunk returned in a call to MapSurface(). Note that
1624 buffer offsets are immutable during the lifetime of the surface.
1625 @param aParam The input parameters including the surface ID and buffer index.
1626 @pre The surface is open in the calling process.
1627 @return KErrNone if successful, KErrArgument if aSurfaceId or aBuffer are invalid,
1628 KErrAccessDenied if the surface is not open in the current process, KErrNotSupported if
1629 the surface is not mappable, otherwise a system wide error code.
1631 TInt DSurfaceManager::GetBufferOffset(RSurfaceManagerDriver::TDeviceParam* aParam,TUint* aOffset)
1633 //Get the input parameters
1634 RSurfaceManagerDriver::TDeviceParam param;
1635 kumemget(¶m, aParam, sizeof(RSurfaceManagerDriver::TDeviceParam));
1637 //fetch surface id from user memory
1638 kumemget(&sid, param.iSurfaceId, sizeof(TSurfaceId));
1639 //(TAny*)iBuffer holds the buffer number in its value
1640 TInt bufferNumber = (TInt) param.iBuffer;
1642 TSurface* surface = NULL;
1643 NKern::FMWait(&iMutex);
1644 surface = FindSurfaceById(sid);
1645 if(NULL == surface || (bufferNumber >= surface->iBuffers))
1647 NKern::FMSignal(&iMutex);
1648 return KErrArgument;
1650 if(!surface->iMappable)
1652 NKern::FMSignal(&iMutex);
1653 return KErrNotSupported;
1656 TProcessListItem* so = surface->ProcessOwnerInfo(&Kern::CurrentProcess());
1659 NKern::FMSignal(&iMutex);
1660 return KErrAccessDenied;
1662 TInt bufferOffset = surface->iOffsetToFirstBuffer + bufferNumber*surface->iOffsetBetweenBuffers;
1663 NKern::FMSignal(&iMutex);
1665 kumemput(aOffset, &bufferOffset, sizeof (TInt));
1670 Returns information specific to the Surface Manager implementation.
1671 @param aAttrib: Attribute to retrieve
1672 @param aValue : Output parameter where we write the value for the specified attribute
1673 @return KErrNone if successful or KErrArgument if the attribute UID is not recognized
1676 TInt DSurfaceManager::GetSurfaceManagerAttrib(RSurfaceManager::TSurfaceManagerAttrib* aAttrib,TInt* aValue)
1678 RSurfaceManager::TSurfaceManagerAttrib attrib;
1679 kumemget(&attrib, aAttrib, sizeof(RSurfaceManager::TSurfaceManagerAttrib));
1685 case RSurfaceManager::EMaxNumberOfHints:
1686 value=KMaxHintsPerSurface;
1696 kumemput(aValue, &value, sizeof (TInt));