diff -r 000000000000 -r a41df078684a kerneltest/e32test/examples/camera1/camera1_ldd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/examples/camera1/camera1_ldd.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,1137 @@ +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// its implementation. +// +// + +/** + @file An example camera device driver which uses Shared Chunks in + @publishedPartner + @prototype 9.1 +*/ + +#include +#include +#include "camera1.h" +#include "camera1_dev.h" + +#if 0 // Set true for tracing +#define TRACE(x) x +#else +#define TRACE(x) +#endif + +// +// DCamera1Factory +// + +/** + Standard export function for LDDs. This creates a DLogicalDevice derived object, + in this case, our DCamera1Factory +*/ +DECLARE_STANDARD_LDD() + { + return new DCamera1Factory; + } + +/** + Constructor +*/ +DCamera1Factory::DCamera1Factory() + { + // Set version number for this device + iVersion=RCamera1::VersionRequired(); + // Indicate that do support units or a PDD + iParseMask=0; + } + +/** + Second stage constructor for DCamera1Factory. + This must at least set a name for the driver object. + + @return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DCamera1Factory::Install() + { + return SetName(&RCamera1::Name()); + } + +/** + Destructor +*/ +DCamera1Factory::~DCamera1Factory() + { + } + +/** + Return the drivers capabilities. + Called in the response to an RDevice::GetCaps() request. + + @param aDes User-side descriptor to write capabilities information into +*/ +void DCamera1Factory::GetCaps(TDes8& aDes) const + { + // Create a capabilities object + RCamera1::TCaps caps; + caps.iVersion = iVersion; + // Write it back to user memory + Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps)); + } + +/** + Called by the kernel's device driver framework to create a Logical Channel. + This is called in the context of the user thread (client) which requested the creation of a Logical Channel + (E.g. through a call to RBusLogicalChannel::DoCreate) + The thread is in a critical section. + + @param aChannel Set to point to the created Logical Channel + + @return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DCamera1Factory::Create(DLogicalChannelBase*& aChannel) + { + aChannel=new DCamera1Channel; + if(!aChannel) + return KErrNoMemory; + + return KErrNone; + } + +// +// Logical Channel +// + +/** + Default configuration for driver (640x480 pixels of 32bits captured at 15 frames/sec) +*/ +static const RCamera1::TConfig DefaultConfig = {{640,480},4,15}; + +/** + Constructor +*/ +DCamera1Channel::DCamera1Channel() + : iDfcQ(Kern::TimerDfcQ()), // This test uses the timer DFC queue for DFCs + iStateChangeDfc(StateChangeDfcTrampoline,this,1), // DFC is priority '1' + iConfig(DefaultConfig), + iCaptureTimer(CaptureDfcTrampoline,this) + { + } + +/** + Second stage constructor called by the kernel's device driver framework. + This is called in the context of the user thread (client) which requested the creation of a Logical Channel + (E.g. through a call to RBusLogicalChannel::DoCreate) + The thread is in a critical section. + + @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate + @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate + @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate + + @return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DCamera1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) + { + // Check client has EMultimediaDD capability + if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by CAPTURE1"))) + return KErrPermissionDenied; + + // Check version + if (!Kern::QueryVersionSupported(RCamera1::VersionRequired(),aVer)) + return KErrNotSupported; + + // Setup DFCs + iStateChangeDfc.SetDfcQ(iDfcQ); + + // Done + return Kern::MutexCreate(iStateChangeMutex,KNullDesC,KMutexOrdGeneral7); + } + +/** + Destructor +*/ +DCamera1Channel::~DCamera1Channel() + { + DoCancel(RCamera1::EAllRequests); + EndCapture(); + iStateChangeDfc.Cancel(); + if(iStateChangeMutex) + iStateChangeMutex->Close(0); + if(iCaptureBuffers) + iCaptureBuffers->Close(); + } + +/** + Process a request on this logical channel. + + @param aReqNo Request number: + ==KMaxTInt, a 'DoCancel' message + >=0, a 'DoControl' message with function number equal to iValue + <0, a 'DoRequest' message with function number equal to ~iValue + @param a1 First argument. For DoRequest requests this is a pointer to the TRequestStatus. + @param a2 Second argument. For DoRequest this is a pointer to the 2 actual TAny* arguments. + + @return Result. Ignored by device driver framework for DoRequest requests. +*/ +TInt DCamera1Channel::Request(TInt aReqNo, TAny* a1, TAny* a2) + { + // Decode the message type and dispatch it to the relevent handler function... + if ((TUint)aReqNo<(TUint)KMaxTInt) + return DoControl(aReqNo,a1,a2); + if(aReqNo==KMaxTInt) + return DoCancel((TInt)a1); + return DoRequest(aReqNo,a1,a2); + } + +/** + Process synchronous 'control' requests +*/ +TInt DCamera1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2) + { + TRACE(Kern::Printf(">DCamera1Channel::DoControl fn=%d\n",aFunction);) + + (void)a2; // a2 not used in this example + + TInt r = KErrNotSupported; + switch (aFunction) + { + case RCamera1::EGetConfig: + r = GetConfig((TDes8*)a1); + break; + + case RCamera1::ESetConfig: + r = SetConfig((const TDesC8*)a1); + break; + + case RCamera1::EStartCapture: + r = StartCapture(); + break; + + case RCamera1::EEndCapture: + r = EndCapture(); + break; + + case RCamera1::EReleaseImage: + r = ImageRelease((TInt)a1); + break; + + case RCamera1::ECaptureImage: + CaptureImage((TRequestStatus*)a1,(TInt)a2); + break; + } + + TRACE(Kern::Printf("DCamera1Channel::DoRequest req=%d\n",aNotReqNo);) + + // Get arguments + TAny* a[2]; + kumemget32(a,a2,sizeof(a)); + TRequestStatus* status=(TRequestStatus*)a1; + TInt reqNo = ~aNotReqNo; + + // Do the request + TInt r; + switch(reqNo) + { + case RCamera1::ECaptureImage: + // Not used because we do 'ECaptureImage' as a DoControl rather than + // a DoRequest for performance reasons + + default: + r = KErrNotSupported; + break; + } + + // Complete request if there was an error + if (r!=KErrNone) + Kern::RequestComplete(&Kern::CurrentThread(),status,r); + + TRACE(Kern::Printf("DCamera1Channel::DoCancel mask=%08x\n",aMask);) + + if(aMask&(1<4) + return KErrArgument; + + if(config.iFrameRate<0) + return KErrArgument; + if(config.iNumImageBuffers<1) + return KErrArgument; + + TInt imageSize; + DCaptureBuffers* buffers; + TInt r; + + // Need to be in critical section whilst holding a DMutex + NKern::ThreadEnterCS(); + + // Claim state change mutex. Note, the return value is ignored because a Wait + // can only fail if the mutex is destroyed whilst waiting for it, this can't + // happen in our driver. + Kern::MutexWait(*iStateChangeMutex); + + // Check we aren't in the middle of capturing images + if(iCapturing) + { + r = KErrInUse; + goto done; + } + + // Change the config + iConfig = config; + iCaptureRateTicks = config.iFrameRate ? 1000000/config.iFrameRate/NKern::TickPeriod() : KMaxTInt; + if(iCaptureRateTicks<1) + iCaptureRateTicks = 1; + + // Claim ownership of old buffers + NKern::FMWait(&iCaptureMutex); + buffers = iCaptureBuffers; + iCaptureBuffers = NULL; + NKern::FMSignal(&iCaptureMutex); + + // Delete old buffers + if(buffers) + buffers->Close(); + + // Contruct new buffer object + imageSize = iConfig.iImageSize.iWidth*iConfig.iImageSize.iHeight*iConfig.iImageBytesPerPixel; + buffers = DCaptureBuffers::New(2+iConfig.iNumImageBuffers,imageSize); + if(!buffers) + { + r = KErrNoMemory; + goto done; + } + + // Use the new buffers if another thread didn't create them first + NKern::FMWait(&iCaptureMutex); + iCaptureBuffers = buffers; + NKern::FMSignal(&iCaptureMutex); + + // Create handle for chunk + r = Kern::MakeHandleAndOpen(NULL, iCaptureBuffers->iChunk); + +done: + // Release state change mutex + Kern::MutexSignal(*iStateChangeMutex); + + NKern::ThreadLeaveCS(); + + return r; + } + +// +// Methods for processing start/end capture +// + +/** + Start image capturing +*/ +TInt DCamera1Channel::StartCapture() + { + // Need to be in critical section whilst holding a DMutex + NKern::ThreadEnterCS(); + + // Claim state change mutex. Note, the return value is ignored because a Wait + // can only fail if the mutex is destroyed whilst waiting for it, this can't + // happen in our driver. + Kern::MutexWait(*iStateChangeMutex); + + NKern::FMWait(&iCaptureMutex); + + TInt r; + if(!iCaptureBuffers) + r = KErrNotReady; // SetConfig not yet been called + else if(iCapturing) + r = KErrInUse; // StartCapture has already been called + else + { + // Initialise image buffer state for capturing images + iCaptureBuffers->Reset(); + + // Flag capturing started + iCapturing = ETrue; + r = KErrNone; + } + + NKern::FMSignal(&iCaptureMutex); + + // Get state change DFC to initialise camera hardware for capture + if(r==KErrNone) + StateChange(ETrue); + + // Release state change mutex + Kern::MutexSignal(*iStateChangeMutex); + + NKern::ThreadLeaveCS(); + + return r; + } + +/** + End image capturing +*/ +TInt DCamera1Channel::EndCapture() + { + // Need to be in critical section whilst holding a DMutex + NKern::ThreadEnterCS(); + + // Claim state change mutex. Note, the return value is ignored because a Wait + // can only fail if the mutex is destroyed whilst waiting for it, this can't + // happen in our driver. + Kern::MutexWait(*iStateChangeMutex); + + if(iCapturing) + { + // Get state change DFC to reset camera hardware + StateChange(EFalse); + + // Flag capture ended + NKern::FMWait(&iCaptureMutex); + iCapturing = EFalse; + NKern::FMSignal(&iCaptureMutex); + + // Cancel any pending caoture request + CaptureImageCancel(); + } + + // Release state change mutex + Kern::MutexSignal(*iStateChangeMutex); + + NKern::ThreadLeaveCS(); + + return KErrNone; + } + +/** + Performs state change on Start/EndCapture by calling state change DFC + Call with iStateChangeMutex held. + + @param aNewState True to start image capture, false to stop image capture. +*/ +void DCamera1Channel::StateChange(TBool aNewState) + { + iNewState = aNewState; + NKern::FSSetOwner(&iStateChangeSemaphore,NULL); + iStateChangeDfc.Enque(); + NKern::FSWait(&iStateChangeSemaphore); + } + +/** + DFC callback called when Start/EndCapture requests are made. +*/ +void DCamera1Channel::StateChangeDfcTrampoline(TAny* aSelf) + { + // Just call non-static method + ((DCamera1Channel*)aSelf)->StateChangeDfc(); + } + +/** + DFC callback called when Start/EndCapture requests are made. +*/ +void DCamera1Channel::StateChangeDfc() + { + TRACE(Kern::Printf(">DCamera1Channel::StateChangeDfc\n");) + + // Call relevent state change function + if(iNewState) + DoStartCapture(); + else + DoEndCapture(); + + // Signal completion + NKern::FSSignal(&iStateChangeSemaphore); + + TRACE(Kern::Printf("ImageForClient(); + if(buffer) + { + // Return offset of buffer to client + r = buffer->iChunkOffset; + } + else + { + // Image not found... + if(!iCaptureBuffers->iFreeBuffers[0]) + r = KErrOverflow; // Out of buffers + else + { + // Wait for new image to become available + iCaptureRequestStatus = aRequestStatus; + requestThread->Open(); // can't fail because this is the current thread + iCaptureRequestThread = requestThread; + r = KErrNone; + } + } + } + + NKern::FMSignal(&iCaptureMutex); + +done: + // Complete request if there was an error + if (r!=KErrNone) + Kern::RequestComplete(requestThread,aRequestStatus,r); + } + +/** + Signal Capture Image request completed +*/ +void DCamera1Channel::CaptureImageCancel() + { + // Need to be in critical section so we don't die whilst owning the capture image request + NKern::ThreadEnterCS(); + + // Claim the capture image request + NKern::FMWait(&iCaptureMutex); + DThread* thread = iCaptureRequestThread;; + TRequestStatus* status = iCaptureRequestStatus; + iCaptureRequestStatus = NULL; + NKern::FMSignal(&iCaptureMutex); + + // Signal completion + if(status) + { + Kern::RequestComplete(thread,status,KErrCancel); + thread->Close(0); + } + + NKern::ThreadLeaveCS(); + } + +/** + DFC callback called when after a new image has been captured + In this example code this is called by +*/ +void DCamera1Channel::CaptureDfcTrampoline(TAny* aSelf) + { + // Just call non-static method + ((DCamera1Channel*)aSelf)->CaptureDfc(); + } + +/** + DFC callback called when a new image has been captured +*/ +void DCamera1Channel::CaptureDfc() + { + TRACE(Kern::Printf(">DCamera1Channel::CaptureDfc\n");) + + NKern::FMWait(&iCaptureMutex); + + // Update image buffers state + iCaptureBuffers->ImageCaptured(); + + // Did client request an image and is one available? + DImageBuffer* clientBuffer; + if(iCaptureRequestStatus && (clientBuffer=iCaptureBuffers->ImageForClient())!=NULL ) + { + // Claim the client request + DThread* thread = iCaptureRequestThread; + TRequestStatus* status = iCaptureRequestStatus; + iCaptureRequestStatus = NULL; + + NKern::FMSignal(&iCaptureMutex); + + // We now own the client request but we don't have to worry about + // being in a critical section because we are running in a DFC thread + // which can't be killed + + // Complete client request with the chunk offset for a captured image + // (We use AsyncClose() here because we are running in a high priority DFC and + // don't want to take the penalty for possibly deleting a thread in this context.) + Kern::RequestComplete(thread,status,clientBuffer->iChunkOffset); + thread->AsyncClose(); + } + else + NKern::FMSignal(&iCaptureMutex); + + // Get camera hardware to capture next image + DoNextCapture(); + + TRACE(Kern::Printf("Open(); + buffer = buffers->InUseImage(aChunkOffset); + } + NKern::FMSignal(&iCaptureMutex); + + TInt r; + if(!buffer) + r = KErrNotFound; // Buffer not found + else + { + // Purge the CPU cache for the buffer. + // Note, we don't do this whilst holding iCaptureMutex because it can + // take a long time. + // Also, it doesn't mater that e aren't holding the mutex because: + // 1. The buffer can't be delete because we have a reference count on iCaptureBuffers + // 2. Reentrancy of the Purge method is safe + buffers->Purge(buffer); + + // Release buffer (move it to the free list) + NKern::FMWait(&iCaptureMutex); + r = buffers->ImageRelease(aChunkOffset) ? KErrNone : KErrArgument; + NKern::FMSignal(&iCaptureMutex); + } + + // Close reference on buffers + if(buffers) + buffers->Close(); + + NKern::ThreadLeaveCS(); + + return r; + } + +// +// DCaptureBuffers +// + +/** + Construct a new set of buffers + + @param aNumBuffers Number of buffers + @param aBufferSize Size of each buffer in bytes + + @return Pointer to the created DCaptureBuffers or NULL if the system ran out of memory +*/ +DCaptureBuffers* DCaptureBuffers::New(TInt aNumBuffers,TInt aBufferSize) + { + DCaptureBuffers* buffers = new DCaptureBuffers; + if(buffers) + { + TInt r = buffers->Create(aNumBuffers,aBufferSize); + if(r==KErrNone) + return buffers; + delete buffers; + // An error other than 'no memory' must be a programming error in the driver + __NK_ASSERT_ALWAYS(r==KErrNoMemory); + } + return NULL; + } + +/** + Construct with access count of one +*/ +DCaptureBuffers::DCaptureBuffers() + : iAccessCount(1) + { + } + +/** + Create all buffers and lists +*/ +TInt DCaptureBuffers::Create(TInt aNumBuffers,TInt aBufferSize) + { + // Allocate buffer lists + DImageBuffer** lists = (DImageBuffer**)Kern::AllocZ(3*aNumBuffers*sizeof(DImageBuffer*)); + if(!lists) + return KErrNoMemory; + iBufferLists = lists; + iFreeBuffers = lists; + iCompletedBuffers = lists+aNumBuffers; + iInUseBuffers = lists+2*aNumBuffers; + + // Calculate sizes + aBufferSize = Kern::RoundToPageSize(aBufferSize); + TInt pageSize = Kern::RoundToPageSize(1); + TUint64 chunkSize = TUint64(aBufferSize+pageSize)*aNumBuffers+pageSize; + if(chunkSize>(TUint64)KMaxTInt) + return KErrNoMemory; // Need more than 2GB of memory! + + // Create chunk + TChunkCreateInfo info; + info.iType = TChunkCreateInfo::ESharedKernelMultiple; + info.iMaxSize = (TInt)chunkSize; +#ifndef __WINS__ + info.iMapAttr = EMapAttrCachedMax; +#else + info.iMapAttr = 0; +#endif + info.iOwnsMemory = ETrue; + TInt r = Kern::ChunkCreate(info,iChunk,iChunkBase,iChunkMapAttr); + if(r!=KErrNone) + return r; + + // Construct array of buffers + iNumBuffers = aNumBuffers; + iImageBuffer = new DImageBuffer[aNumBuffers]; + if(!iImageBuffer) + return KErrNoMemory; + + // Create each buffer + TInt offset = pageSize; + while(aNumBuffers) + { + r = iImageBuffer[--aNumBuffers].Create(iChunk,offset,aBufferSize); + if(r!=KErrNone) + return r; + offset += aBufferSize+pageSize; + } + + return KErrNone; + } + +/** + Destructor +*/ +DCaptureBuffers::~DCaptureBuffers() + { + if(iChunk) + Kern::ChunkClose(iChunk); + delete [] iImageBuffer; + Kern::Free(iBufferLists); + } + +/** + Increment access count of buffers +*/ +void DCaptureBuffers::Open() + { + __e32_atomic_tas_ord32(&iAccessCount, 1, 1, 0); + } + +/** + Decrement access count of buffers. + Deleting them if the count is decremented to zero. +*/ +void DCaptureBuffers::Close() + { + __ASSERT_NO_FAST_MUTEX; + __ASSERT_CRITICAL; + if(__e32_atomic_tas_ord32(&iAccessCount, 1, -1, 0) == 1) + AsyncDelete(); + } + +/** + Reset all image buffer lists to reflect the state at the start of image capture process +*/ +void DCaptureBuffers::Reset() + { + // Purge cache for all buffers in use by client. + DImageBuffer** list = iInUseBuffers; + DImageBuffer* buffer; + while((buffer=*list++)!=NULL) + Purge(buffer); + + // Get pointers to first buffer + buffer = iImageBuffer; + + // Set buffers for current and next images + iCurrentBuffer = buffer++; + iNextBuffer = buffer++; + + // Add all other buffers to the free list + DImageBuffer** free = iFreeBuffers; + DImageBuffer* bufferLimit = iImageBuffer+iNumBuffers; + while(bufferiChunkOffset,aBuffer->iSize,iChunkMapAttr); + } + +/** + Remove an image buffer to the start of the given image list. + @return A pointer to the image buffer or NULL if the list was empty +*/ +DImageBuffer* DCaptureBuffers::Remove(DImageBuffer** aList) + { + DImageBuffer* buffer=aList[0]; + if(buffer) + { + DImageBuffer* b; + do + { + b=aList[1]; + *aList++ = b; + } + while(b); + } + return buffer; + } + +/** + Add an image buffer to the end of the given image list. +*/ +DImageBuffer* DCaptureBuffers::Add(DImageBuffer** aList, DImageBuffer* aBuffer) + { + while(*aList) aList++; + *aList = aBuffer; + return aBuffer; + } + +/** + Update buffer lists after an image has been captured. + @return A pointer to the catptured image buffer +*/ +DImageBuffer* DCaptureBuffers::ImageCaptured() + { + // Add captured image to completed list + DImageBuffer* buffer = iCurrentBuffer; + DCaptureBuffers::Add(iCompletedBuffers,buffer); + + // Make queued buffer the current one + iCurrentBuffer = iNextBuffer; + + // Queue a new buffer + iNextBuffer = DCaptureBuffers::Remove(iFreeBuffers); + if(!iNextBuffer) + iNextBuffer = DCaptureBuffers::Remove(iCompletedBuffers); + + TRACE(Kern::Printf("DCaptureBuffers::ImageCaptured buf=%08x\n",buffer->iChunkOffset);) + + return buffer; + } + +/** + Get the next image from the completed capture list and make it 'in use' by the client + + @return A pointer to the next completed image buffer +*/ +DImageBuffer* DCaptureBuffers::ImageForClient() + { + DImageBuffer* buffer=Remove(iCompletedBuffers); + if(buffer) + DCaptureBuffers::Add(iInUseBuffers,buffer); + + TRACE(Kern::Printf("DCaptureBuffers::ImageForClient buf=%08x\n",buffer ? buffer->iChunkOffset : -1);) + + return buffer; + } + +/** + Release (move to free list) the 'in use' image specified by the given chunk offset. + + @param aChunkOffset The chunk offset corresponding to the buffer to be freed + + @return The freed image buffer, or NULL if no 'in use' buffer had the specified chunk offset. +*/ +DImageBuffer* DCaptureBuffers::ImageRelease(TInt aChunkOffset) + { + // Scan 'in use' list for the image buffer + DImageBuffer** list = iInUseBuffers; + DImageBuffer* buffer; + while((buffer=*list++)!=NULL && buffer->iChunkOffset!=aChunkOffset) + {}; + + // Move buffer to the free list (if found) + if(buffer) + buffer = Add(iFreeBuffers,Remove(list-1)); + + TRACE(Kern::Printf("DCaptureBuffers::ImageRelease buf=%08x\n",buffer ? buffer->iChunkOffset : -1);) + + return buffer; + } + +/** + Find the 'in use' image specified by the given chunk offset + + @param aChunkOffset The chunk offset corresponding to the buffer to be freed + + @return The image buffer, or NULL if no 'in use' buffer had the specified chunk offset +*/ +DImageBuffer* DCaptureBuffers::InUseImage(TInt aChunkOffset) + { + // Scan 'in use' list for the image buffer + DImageBuffer** list = iInUseBuffers; + DImageBuffer* buffer; + while((buffer=*list++)!=NULL && buffer->iChunkOffset!=aChunkOffset) + {}; + + return buffer; + } + +// +// DImageBuffer +// + +/** + Constructor clears all member data +*/ +DImageBuffer::DImageBuffer() + { + memclr(this,sizeof(*this)); + } + +/** + Commit memory for this buffer. + + @param aChunk The chunk into which the memory is to be commited + @param aOffset The offset within aChunk for the start of the comitted memory. + Must be a multiple of the MMU page size. + @param aSize The number of bytes of memory to commit. + Must be a multiple of the MMU page size. + + @return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt DImageBuffer::Create(DChunk* aChunk, TInt aOffset, TInt aSize) + { + TInt r; + + // Initialise data + iChunkOffset = aOffset; + iSize = aSize; + + // Try for physically contiguous memory first + r = Kern::ChunkCommitContiguous(aChunk,aOffset,aSize,iPhysicalAddress); + if(r==KErrNone) + return r; + + // failed to get contiguous memory... + + // Mark physical address invalid + iPhysicalAddress = KPhysAddrInvalid; + + // Commit discontiguous memory + r = Kern::ChunkCommit(aChunk,aOffset,aSize); + if(r!=KErrNone) + return r; + + // Allocate array for list of physical pages + iPhysicalPages = new TPhysAddr[aSize/Kern::RoundToPageSize(1)]; + if(!iPhysicalPages) + return KErrNoMemory; + + // Get physical addresses of pages in buffer + TUint32 kernAddr; + TUint32 mapAttr; + TPhysAddr physAddr; + r = Kern::ChunkPhysicalAddress(aChunk,aOffset,aSize,kernAddr,mapAttr,physAddr,iPhysicalPages); + // r = 0 or 1 on success. (1 meaning the physical pages are not-contiguous) + if(r>=0) + r = KErrNone; + return r; + } + +/** + Destructor +*/ +DImageBuffer::~DImageBuffer() + { + delete [] iPhysicalPages; + } + +// +// Program camera hardware +// + +/** + Initialise camera hardware to start capturing images + First buffer to fill is iCaptureBuffers->iCurrentBuffer. + Next buffer to fill will be iCaptureBuffers->iNextBuffer. +*/ +void DCamera1Channel::DoStartCapture() + { + // For this example test... + + TRACE(Kern::Printf("DCamera1Channel::DoStartCapture buf=%08x cnt=%04d\n",iCaptureBuffers->iCurrentBuffer->iChunkOffset,iCaptureCounter);) + + // Initialise frame counter + iCaptureCounter = 0; + + // Put frame counter into current image buffer. (This is the 'image' data we capture). + *(TInt*)(iCaptureBuffers->iChunkBase+iCaptureBuffers->iCurrentBuffer->iChunkOffset) = iCaptureCounter++; + + // Start the timer + TInt r=iCaptureTimer.OneShot(iCaptureRateTicks,ETrue); + __NK_ASSERT_ALWAYS(r==KErrNone); + } + +/** + Reset camera hardware to stop capturing images +*/ +void DCamera1Channel::DoEndCapture() + { + // For this example test... + + TRACE(Kern::Printf("DCamera1Channel::DoEndCapture\n");) + + // Cancel the timer + iCaptureTimer.Cancel(); + } + +/** + Setup camera hardware to capture next image + Next buffer to fill will be iCaptureBuffers->iNextBuffer; + + @param aLastImage The last image just captured. I.e. the completed capture which caused + this method to be called +*/ +void DCamera1Channel::DoNextCapture() + { + // For this example test... + + TRACE(Kern::Printf("DCamera1Channel::DoNextCapture cur=%08x cnt=%04d nxt=%08x\n",iCaptureBuffers->iCurrentBuffer->iChunkOffset,iCaptureCounter,iCaptureBuffers->iNextBuffer->iChunkOffset);) + + // Put frame counter into current image buffer. (This is the 'image' data we capture). + *(TInt*)(iCaptureBuffers->iChunkBase+iCaptureBuffers->iCurrentBuffer->iChunkOffset) = iCaptureCounter++; + + // Restart the timer + TInt r = iCaptureTimer.Again(iCaptureRateTicks); + if(r==KErrArgument) + { + // Timer would have already expired. + // + // In a real device driver this is analogous to iCurrentBuffer already being filled + // and the DMA queue being emptied. I.e. we have missed some frames. + // + // For this test... + + TRACE(Kern::Printf("DCamera1Channel::DoNextCapture frame dropped cnt=%04d\n",iCaptureCounter);) + + // Skip a frame count + ++iCaptureCounter; + + // Restart timer + r = iCaptureTimer.OneShot(iCaptureRateTicks,ETrue); + } + __NK_ASSERT_ALWAYS(r==KErrNone); + } +