--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/camerasc/cameraldd.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,2223 @@
+// Copyright (c) 2008-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:
+// e32/drivers/camerasc/cameraldd.cpp
+//
+//
+
+#include <drivers/camerasc.h>
+#include <kernel/kern_priv.h>
+#include <kernel/cache.h>
+
+//#define __KTRACE_CAM(s) s;
+#define __KTRACE_CAM(s)
+
+#define DISCARD_COMPLETED_TO_AVOID_OVERFLOW
+
+static const char KCameraLddPanic[]="CameraSc LDD";
+
+/**
+Standard export function for LDDs. This creates a DLogicalDevice derived object,
+in this case, DSoundScLddFactory.
+*/
+DECLARE_STANDARD_LDD()
+ {
+ return new DCameraScLddFactory;
+ }
+
+/**
+Constructor for the camera driver factory class.
+*/
+DCameraScLddFactory::DCameraScLddFactory()
+ {
+// iUnitsOpenMask=0;
+
+ __KTRACE_CAM(Kern::Printf(">DCameraScLddFactory::DCameraScLddFactory"));
+
+ // Set version number for this device.
+ iVersion=RDevCameraSc::VersionRequired();
+
+ // Indicate that units / PDD are supported.
+ iParseMask=KDeviceAllowUnit|KDeviceAllowPhysicalDevice;
+
+ // Leave the units decision to the PDD
+ iUnitsMask=0xffffffff;
+ }
+
+/**
+Second stage constructor for the camera driver factory class.
+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 DCameraScLddFactory::Install()
+ {
+ return(SetName(&KDevCameraScName));
+ }
+
+/**
+Return the 'capabilities' of the camera driver in general.
+Called in the response to an RDevice::GetCaps() request.
+@param aDes A user-side descriptor to write the capabilities information into.
+*/
+void DCameraScLddFactory::GetCaps(TDes8 &aDes) const
+ {
+ // Create a capabilities object
+ TCapsDevCameraV01 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 client thread which requested the creation of a logical
+channel - through a call to RBusLogicalChannel::DoCreate().
+The thread is in a critical section.
+@param aChannel Set by this function to point to the created logical channel.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCameraScLddFactory::Create(DLogicalChannelBase*& aChannel)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLddFactory::Create"));
+
+ aChannel=new DCameraScLdd;
+ if (!aChannel)
+ return(KErrNoMemory);
+
+ return(KErrNone);
+ }
+
+/**
+Check whether a channel has is currently open on the specified unit.
+@param aUnit The number of the unit to be checked.
+@return ETrue if a channel is open on the specified channel, EFalse otherwise.
+@pre The unit info. mutex must be held.
+*/
+TBool DCameraScLddFactory::IsUnitOpen(TInt aUnit)
+ {
+ return(iUnitsOpenMask&(1<<aUnit));
+ }
+
+/**
+Attempt to change the state of the channel open status for a particular channel.
+@param aUnit The number of the unit to be updated.
+@param aIsOpenSetting The required new state for the channel open status: either ETrue to set the status to open or
+ EFalse to set the status to closed.
+@return KErrNone if the status was updated successfully;
+ KErrInUse if an attempt has been made to set the channnel status to open while it is already open.
+*/
+TInt DCameraScLddFactory::SetUnitOpen(TInt aUnit,TBool aIsOpenSetting)
+ {
+ NKern::FMWait(&iUnitInfoMutex); // Acquire the unit info. mutex.
+
+ // Fail a request to open an channel that is already open
+ if (aIsOpenSetting && IsUnitOpen(aUnit))
+ {
+ NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
+ return(KErrInUse);
+ }
+
+ // Update the open status as requested
+ if (aIsOpenSetting)
+ iUnitsOpenMask|=(1<<aUnit);
+ else
+ iUnitsOpenMask&=~(1<<aUnit);
+
+ NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
+ return(KErrNone);
+ }
+
+/**
+Constructor for the camera driver logical channel.
+*/
+DCameraScLdd::DCameraScLdd()
+ : iRequestQueue(&iMutex),
+ iRestartDfc(DCameraScLdd::RestartDfc,this,5),
+ iPowerDownDfc(DCameraScLdd::PowerDownDfc,this,3),
+ iPowerUpDfc(DCameraScLdd::PowerUpDfc,this,3)
+ {
+ iState=EOpen;
+// iCaptureMode=ECaptureModeImage;
+// iFrameHeight=0;
+// iFrameWidth=0;
+// iBufManager=NULL;
+// iPowerHandler=NULL;
+// iImageGatherCount=0;
+
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DCameraScLdd"));
+
+ iUnit=-1; // Invalid unit number
+
+ // Get pointer to client thread's DThread object
+ iOwningThread=&Kern::CurrentThread();
+
+ // Open a reference on client thread so it's control block can't dissapear until
+ // this driver has finished with it. Note, this call to Open() can't fail since
+ // it is the thread we are currently running in
+ iOwningThread->Open();
+ }
+
+/**
+Destructor for the camera driver logical channel.
+This is called in the context of the client thread once a 'ECloseMsg' message has been
+sent to the device driver DFC thread.
+*/
+DCameraScLdd::~DCameraScLdd()
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::~DCameraScLdd"));
+
+ TInt captureMode;
+
+ // Remove and delete the power handler.
+ if (iPowerHandler)
+ {
+ iPowerHandler->Remove();
+ delete iPowerHandler;
+ }
+
+ if (iCaptureModeConfig)
+ {
+ // Delete any buffers and shared chunk we created.
+ for (captureMode=0; captureMode < ECamCaptureModeMax; captureMode++)
+ {
+ if (iCaptureModeConfig[captureMode].iBufManager)
+ delete iCaptureModeConfig[captureMode].iBufManager;
+ }
+
+ // Delete the buffer config. info. structure.
+ for (captureMode=0; captureMode < ECamCaptureModeMax; captureMode++)
+ {
+ if (iCaptureModeConfig[captureMode].iBufConfig)
+ Kern::Free(iCaptureModeConfig[captureMode].iBufConfig);
+ }
+
+ if (iCaptureModeConfig)
+ delete[] iCaptureModeConfig;
+ }
+ // Close our reference on the client thread
+ Kern::SafeClose((DObject*&)iOwningThread,NULL);
+
+ // Clear the 'units open mask' in the LDD factory.
+ if (iUnit>=0)
+ ((DCameraScLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse);
+ }
+
+/**
+Second stage constructor for the camera driver - called by the kernel's device driver framework.
+This is called in the context of the client thread 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. This is checked by the PDD and not used here.
+@param aInfo The info argument supplied by the client. Always NULL in this case.
+@param aVer The version argument supplied by the client.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCameraScLdd::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& aVer)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DoCreate"));
+
+ // Check the client has EMultimediaDD capability.
+ if (!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by ECAMERA.LDD (Camera driver)")))
+ return(KErrPermissionDenied);
+
+ // Check that the camera driver version specified by the client is compatible.
+ if (!Kern::QueryVersionSupported(RDevCameraSc::VersionRequired(),aVer))
+ return(KErrNotSupported);
+
+ // Check that a channel hasn't already been opened on this unit.
+ TInt r=((DCameraScLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory.
+ if (r!=KErrNone)
+ return(r);
+ iUnit=aUnit;
+
+ // Create the power handler
+ iPowerHandler=new DCameraScPowerHandler(this);
+ if (!iPowerHandler)
+ return(KErrNoMemory);
+ iPowerHandler->Add();
+
+ // Create the pending capture request list
+ r=iRequestQueue.Create(iOwningThread);
+ if (r!=KErrNone)
+ return(r);
+
+ // Initialise the PDD
+ ((DCameraScPdd*)iPdd)->iLdd=this;
+
+ // Setup the default camera config
+ iCaptureMode=ECamCaptureModeImage;
+
+ iCaptureModeConfig = new TCaptureModeConfig[ECamCaptureModeMax];
+ if(!iCaptureModeConfig)
+ return KErrNoMemory;
+ TInt capsSize = Pdd()->CapsSize();
+ TInt captureMode;
+ TAny* capsBuf;
+ capsBuf = Kern::Alloc(capsSize);
+ if(!capsBuf)
+ return KErrNoMemory;
+
+ // Query the driver for its capabilities and set a default pixel format
+ // and frame size for each available capture mode.
+ TPtr8 capsPtr( (TUint8*)capsBuf, capsSize, capsSize );
+ Pdd()->Caps(capsPtr);
+
+ TCameraCapsV02* caps = (TCameraCapsV02*) capsPtr.Ptr();
+ SDevCamPixelFormat* pixelFormat = (SDevCamPixelFormat*) (caps + 1);
+ SDevCamFrameSize* frameSize;
+ TAny* frameSizeCapsBuf=0;
+ TPtr8 frameSizeCapsPtr(0,0,0);
+
+ // Set the cache to hold the default dynamic attribute values.
+ iBrightnessValue = caps->iDynamicRange[ECamAttributeBrightness].iDefault;
+ iContrastValue = caps->iDynamicRange[ECamAttributeContrast].iDefault;
+ iColorEffectValue = caps->iDynamicRange[ECamAttributeColorEffect].iDefault;
+
+ for (captureMode=0; captureMode < ECamCaptureModeMax; captureMode++)
+ {
+ if ((captureMode==ECamCaptureModeImage) && (caps->iNumImagePixelFormats==0))
+ continue;
+
+ if ((captureMode==ECamCaptureModeVideo) && (caps->iNumVideoPixelFormats==0))
+ continue;
+
+ if ((captureMode==ECamCaptureModeViewFinder) && (caps->iNumViewFinderPixelFormats==0))
+ continue;
+
+ iCaptureModeConfig[captureMode].iCamConfig.iPixelFormat=*pixelFormat;
+ frameSizeCapsBuf = Kern::Alloc(pixelFormat->iNumFrameSizes*sizeof(SDevCamFrameSize));
+ new (&frameSizeCapsPtr) TPtr8((TUint8*)frameSizeCapsBuf, pixelFormat->iNumFrameSizes*sizeof(SDevCamFrameSize), pixelFormat->iNumFrameSizes*sizeof(SDevCamFrameSize));
+ r=Pdd()->FrameSizeCaps((TDevCamCaptureMode)captureMode, pixelFormat->iPixelFormat, frameSizeCapsPtr);
+ if(r!=KErrNone)
+ {
+ Kern::Free(frameSizeCapsBuf);
+ return r;
+ }
+ frameSize=(SDevCamFrameSize*) frameSizeCapsPtr.Ptr();
+ iCaptureModeConfig[captureMode].iCamConfig.iFrameSize = *frameSize;
+ iCaptureModeConfig[captureMode].iCamConfig.iFrameRate = frameSize->iMinFrameRate;
+ Kern::Free(frameSizeCapsBuf);
+
+ iCaptureModeConfig[captureMode].iCamConfig.iFlashMode = ECamFlashNone;
+ iCaptureModeConfig[captureMode].iCamConfig.iExposureMode = ECamExposureAuto;
+ iCaptureModeConfig[captureMode].iCamConfig.iWhiteBalanceMode = ECamWBAuto;
+ iCaptureModeConfig[captureMode].iCamConfig.iZoom = 0;
+ iCaptureModeConfig[captureMode].iCamConfig.iPixelWidthInBytes = 0;
+ }
+ Kern::Free(capsBuf);
+ // Setup the default buffer config.
+ r=ReAllocBufferConfigInfo(0); // Zeros the structure
+ if (r!=KErrNone)
+ return(r);
+ for (captureMode=0; captureMode < ECamCaptureModeMax; captureMode++)
+ {
+ iCaptureModeConfig[captureMode].iBufConfig->iNumBuffers=KDefaultNumClientBuffers;
+ }
+
+ // Set up the correct DFC queue and enable the reception of client messages.
+ TDfcQue* dfcq=((DCameraScPdd*)iPdd)->DfcQ(aUnit);
+ SetDfcQ(dfcq);
+ iRestartDfc.SetDfcQ(dfcq);
+ iPowerDownDfc.SetDfcQ(dfcq);
+ iPowerUpDfc.SetDfcQ(dfcq);
+ iMsgQ.Receive();
+
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::DoCreate"));
+
+ return(KErrNone);
+ }
+
+/**
+Shutdown the camera device.
+Terminate all device activity and power down the hardware.
+*/
+void DCameraScLdd::Shutdown()
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::Shutdown"));
+
+ iState=EOpen;
+
+ // Power down the hardware
+ Pdd()->PowerDown();
+
+ // Cancel any requests that we may be handling
+ DoCancel(RDevCameraSc::EAllRequests);
+
+ // Make sure DFCs are not queued.
+ iRestartDfc.Cancel();
+ iPowerDownDfc.Cancel();
+ iPowerUpDfc.Cancel();
+ }
+
+/**
+Notification to the driver that a handle to it has been requested by a user thread.
+The use of a camera driver channel is restricted here to a single thread (that has
+EMultimediaDD capability).
+@param aThread A pointer to thread which is requesting the handle.
+@param aType Whether the requested handle is thread or process relative.
+@return KErrNone, if the request is for a thread relative handle - originating from
+ the same the thread that created the channel object;
+ KErrAccessDenied, otherwise.
+*/
+TInt DCameraScLdd::RequestUserHandle(DThread* aThread, TOwnerType aType)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::RequestUserHandle"));
+
+ // Ensure that each channel can only be used by a single thread.
+ if (aType!=EOwnerThread || aThread!=iOwningThread)
+ return(KErrAccessDenied);
+ return(KErrNone);
+ }
+
+/**
+Process a request on this logical channel
+Called in the context of the client thread.
+@param aReqNo The request number:
+ ==KMaxTInt: a 'DoCancel' message;
+ >=0: a 'DoControl' message with function number equal to value.
+ <0: a 'DoRequest' message with function number equal to ~value.
+@param a1 The first request argument. For DoRequest(), this is a pointer to the TRequestStatus.
+@param a2 The second request argument. For DoRequest(), this is a pointer to the 2 actual TAny* arguments.
+@return The result of the request. This is ignored by device driver framework for DoRequest().
+*/
+TInt DCameraScLdd::Request(TInt aReqNo, TAny* a1, TAny* a2)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::Request(%d)",aReqNo));
+ TInt r;
+ if (aReqNo<RDevCameraSc::EMsgControlMax && aReqNo>(~RDevCameraSc::EMsgRequestMax))
+ {
+ // Implement in the context of the kernel thread - prepare and issue a kernel message.
+ r=DLogicalChannel::Request(aReqNo,a1,a2);
+ }
+ else
+ {
+ // Implement in the context of the client thread.
+ // Decode the message type and dispatch it to the relevent handler function.
+ if ((TUint)aReqNo<(TUint)KMaxTInt)
+ r=DoControl(aReqNo,a1,a2); // DoControl - process the request.
+
+ else if (aReqNo==KMaxTInt)
+ {
+ r=DoCancel((TInt)a1); // DoCancel - cancel the request.
+ }
+
+ else
+ {
+ // DoRequest
+ TInt func=~aReqNo;
+
+ // NotifyNewImage() during image capture mode is another case which must be handled in the kernel thread.
+ if (iCaptureMode==ECamCaptureModeImage && func==RDevCameraSc::ERequestNotifyNewImage)
+ r=DLogicalChannel::Request(aReqNo,a1,a2);
+ else
+ {
+ // Read the arguments from the client thread and process the request.
+ TAny* a[2];
+ kumemget32(a,a2,sizeof(a));
+ TRequestStatus* status=(TRequestStatus*)a1;
+ r=DoRequest(func,status,a[0],a[1]);
+
+ // Complete request if there was an error
+ if (r!=KErrNone)
+ Kern::RequestComplete(iOwningThread,status,r);
+ r=KErrNone;
+ }
+ }
+ }
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::Request - %d",r));
+ return(r);
+ }
+
+/**
+Process a message for this logical channel.
+This function is called in the context of the DFC thread.
+@param aMsg The message to process.
+ The iValue member of this distinguishes the message type:
+ iValue==ECloseMsg, channel close message.
+ iValue==KMaxTInt, a 'DoCancel' message.
+ iValue>=0, a 'DoControl' message with function number equal to iValue.
+ iValue<0, a 'DoRequest' message with function number equal to ~iValue.
+*/
+void DCameraScLdd::HandleMsg(TMessageBase* aMsg)
+ {
+ TThreadMessage& m=*(TThreadMessage*)aMsg;
+ TInt id=m.iValue;
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::HandleMsg(%d)",id));
+
+ // Decode the message type and dispatch it to the relevent handler function.
+ if (id==(TInt)ECloseMsg)
+ {
+ // Channel close.
+ Shutdown();
+ m.Complete(KErrNone,EFalse);
+ return;
+ }
+ else if (id<0) // The only DoRequest handled in the kernel thread is NotifyNewImage(ECamCaptureModeImage).
+ {
+ // DoRequest
+ TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+ TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
+ if (r!=KErrNone)
+ Kern::RequestComplete(iOwningThread,pS,r);
+ m.Complete(KErrNone,ETrue);
+ }
+ else
+ {
+ // Must be DoControl (Cancel is handled in the client thread).
+ TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+ m.Complete(r,ETrue);
+ }
+ }
+
+/**
+Process a synchronous 'DoControl' request.
+This function is called in the context of the DFC thread.
+@param aFunction The request number.
+@param a1 The first request argument.
+@param a2 The second request argument.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCameraScLdd::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DoControl(%d)",aFunction));
+
+ TInt r=KErrNotSupported;
+ switch (aFunction)
+ {
+ case RDevCameraSc::EControlCaps:
+ {
+ r = GetSensorCaps(a1);
+ break;
+ }
+ case RDevCameraSc::EControlSetCaptureMode:
+ {
+ // Change the capture mode.
+ r=SetCaptureMode((TInt)a1);
+ break;
+ }
+ case RDevCameraSc::EControlSetCamConfig:
+ {
+ // Set the new camera configuration.
+ NKern::ThreadEnterCS();
+ r=SetCamConfig((TInt)a1, (const TDesC8*)a2);
+ NKern::ThreadLeaveCS();
+ break;
+ }
+ case RDevCameraSc::EControlGetCamConfig:
+ {
+ // Write the config to the client.
+ TPtrC8 ptr((const TUint8*)&iCaptureModeConfig[(TInt)a1].iCamConfig,sizeof(iCaptureModeConfig[(TInt)a1].iCamConfig));
+ Kern::InfoCopy(*((TDes8*)a2),ptr);
+ r=KErrNone;
+ break;
+ }
+ case RDevCameraSc::EControlGetBufferConfig:
+ if (iCaptureModeConfig[(TInt)a1].iBufConfig)
+ {
+ // Write the buffer config to the client.
+ TPtrC8 ptr((const TUint8*)&(*iCaptureModeConfig[(TInt)a1].iBufConfig),iCaptureModeConfig[(TInt)a1].iBufConfigSize);
+ Kern::InfoCopy(*((TDes8*)a2),ptr);
+ r=KErrNone;
+ }
+ break;
+ case RDevCameraSc::EControlSetBufConfigChunkCreate:
+ // Need to be in critical section while deleting an exisiting config and creating a new one
+ NKern::ThreadEnterCS();
+ r=SetBufConfig((TInt)a1,(TInt)a2);
+ NKern::ThreadLeaveCS();
+ break;
+ case RDevCameraSc::EControlSetBufConfigChunkOpen:
+ SSetBufConfigChunkOpenInfo info;
+ r=Kern::ThreadRawRead(iOwningThread,a2,&info,sizeof(info));
+ if (r==KErrNone)
+ {
+ // Need to be in critical section while deleting an exisiting config and creating a new one
+ NKern::ThreadEnterCS();
+ r=SetBufConfig((TInt)a1,info.iBufferConfigBuf,info.iChunkHandle);
+ NKern::ThreadLeaveCS();
+ }
+ break;
+ case RDevCameraSc::EControlChunkClose:
+ r=ChunkClose((TInt)a1);
+ break;
+ case RDevCameraSc::EControlStart:
+ r=Start();
+ break;
+ case RDevCameraSc::EControlStop:
+ if (iState==ECapturing)
+ {
+ r=Pdd()->Stop();
+ DoCancel(1<<RDevCameraSc::ERequestNotifyNewImage);
+ if (r==KErrNone)
+ iState=EConfigured;
+ }
+ else
+ {
+ r=KErrGeneral;
+ }
+ break;
+ case RDevCameraSc::EControlReleaseBuffer:
+ r=ReleaseBuffer((TInt)a1);
+ break;
+ case RDevCameraSc::EControlNotifyNewImageSpecificCancel:
+ {
+ NKern::FMWait(&iMutex); // Acquire the buffer/request list mutex.
+ iRequestQueue.Cancel((TRequestStatus*)a1);
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ r=KErrNone;
+ break;
+ }
+
+ case RDevCameraSc::EControlBufferIdToOffset:
+ {
+ // a1 has pointer to buffer for search criteria
+ // a2 has pointer to offset for result
+ TDevCamBufferModeAndId info;
+ TPtr8 inDesc((TUint8*)(&info), sizeof(info));
+
+ r = Kern::ThreadDesRead(iOwningThread,a1,inDesc,0);
+ if (r == KErrNone)
+ {
+ TInt id = info.iId;
+ TDevCamCaptureMode captureMode = info.iCaptureMode;
+
+ r = KErrNotFound;
+ DBufferManager* mgr = iCaptureModeConfig[captureMode].iBufManager;
+ if (mgr)
+ {
+ if (mgr->iImageBuffer[id].iId == id)
+ {
+ kumemput32(a2, &mgr->iImageBuffer[id].iChunkOffset, sizeof(TInt));
+ r = KErrNone;
+ }
+ }
+ }
+
+ break;
+ }
+ case RDevCameraSc::EControlCapsSize:
+ {
+ r = Pdd()->CapsSize();
+ break;
+ }
+ case RDevCameraSc::EControlFrameSizeCaps:
+ {
+ r = GetFrameSizeCaps(a1, a2);
+ break;
+ }
+
+ case RDevCameraSc::EControlSetDynamicAttribute:
+ {
+ NKern::ThreadEnterCS();
+ r = SetDynamicAttribute((TInt)a1, (TUint)a2);
+ NKern::ThreadLeaveCS();
+ break;
+ }
+
+ case RDevCameraSc::EControlGetDynamicAttribute:
+ {
+ TInt attribute = (TInt)(a1);
+ TUint value = 0;
+
+ r = GetDynamicAttribute(attribute, value);
+ if (r == KErrNone)
+ {
+ kumemput32(a2, &value, sizeof(TUint));
+ }
+
+ break;
+ }
+
+ }
+ return(r);
+ }
+
+/**
+Process an asynchronous 'DoRequest' request.
+This function is called in the context of the DFC thread.
+@param aFunction The request number.
+@param aStatus A pointer to the TRequestStatus.
+@param a1 The first request argument.
+@param a2 The second request argument.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCameraScLdd::DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* /*a1*/, TAny* /*a2*/)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DoRequest(%d)",aFunction));
+
+ TInt r=KErrNotSupported;
+ switch (aFunction)
+ {
+ case RDevCameraSc::ERequestNotifyNewImage:
+ r=NotifyNewImage(aStatus);
+ break;
+ }
+
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::DoRequest - %d",r));
+ return(r);
+ }
+
+/**
+Process the cancelling of asynchronous requests.
+This function is called in the context of the DFC thread.
+@param aMask A mask indicating which requests need to be cancelled.
+@return The result of the cancel. Either KErrNone if successful, otherwise one of the other
+ system wide error codes.
+*/
+TInt DCameraScLdd::DoCancel(TUint aMask)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DoCancel(%08x)",aMask));
+
+ if (aMask&(1<<RDevCameraSc::ERequestNotifyNewImage))
+ {
+ NKern::FMWait(&iMutex); // Acquire the buffer/request list mutex.
+ iRequestQueue.CancelAll();
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ }
+ return(KErrNone);
+ }
+
+/**
+@pre The thread must be in a critical section.
+*/
+TInt DCameraScLdd::ReAllocBufferConfigInfo(TInt aNumBuffers)
+ {
+ for (TInt captureMode=0; captureMode < ECamCaptureModeMax; captureMode++)
+ {
+ if (iCaptureModeConfig[captureMode].iBufConfig)
+ {
+ Kern::Free(iCaptureModeConfig[captureMode].iBufConfig);
+ iCaptureModeConfig[captureMode].iBufConfig=NULL;
+ }
+
+ iCaptureModeConfig[captureMode].iBufConfigSize=aNumBuffers*(sizeof(SBufSpecList)); // Size of the three integers that hold the offset to the start of each buffer and the buffer id.
+ iCaptureModeConfig[captureMode].iBufConfigSize+=sizeof(TSharedChunkBufConfigBase);
+ iCaptureModeConfig[captureMode].iBufConfig=(TCameraSharedChunkBufConfig*)Kern::AllocZ(iCaptureModeConfig[captureMode].iBufConfigSize);
+ if (!iCaptureModeConfig[captureMode].iBufConfig)
+ return(KErrNoMemory);
+ }
+ return(KErrNone);
+ }
+
+/**
+Reallocate memory for the new buffer configuration.
+@param aNumBuffers The number of buffers.
+@pre The thread must be in a critical section.
+*/
+TInt DCameraScLdd::ReAllocBufferConfigInfo(TInt aCaptureMode, TInt aNumBuffers)
+ {
+ if (iCaptureModeConfig[aCaptureMode].iBufConfig)
+ {
+ Kern::Free(iCaptureModeConfig[aCaptureMode].iBufConfig);
+ iCaptureModeConfig[aCaptureMode].iBufConfig=NULL;
+ }
+
+ iCaptureModeConfig[aCaptureMode].iBufConfigSize=aNumBuffers*(sizeof(SBufSpecList)); // Size of the three integers that hold the offset to the start of each buffer and the buffer id.
+ iCaptureModeConfig[aCaptureMode].iBufConfigSize+=sizeof(TSharedChunkBufConfigBase);
+ iCaptureModeConfig[aCaptureMode].iBufConfig=(TCameraSharedChunkBufConfig*)Kern::AllocZ(iCaptureModeConfig[aCaptureMode].iBufConfigSize);
+ if (!iCaptureModeConfig[aCaptureMode].iBufConfig)
+ return(KErrNoMemory);
+
+ return(KErrNone);
+ }
+
+/**
+@return A handle to the shared chunk for the owning thread (a value >0), if successful;
+ otherwise one of the other system wide error codes, (a value <0).
+@param aCamConfigBuf The supplied camera configuration.
+@pre The thread must be in a critical section.
+*/
+TInt DCameraScLdd::SetCamConfig(TInt aCaptureMode, const TDesC8* aCamConfigBuf)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::SetCamConfig()"));
+
+ // Set the configuration of the sensor
+ TInt r=DoSetConfig(aCaptureMode, aCamConfigBuf);
+ return(r);
+ }
+
+/**
+Allows changing of the dynamic settings.
+Checks locally the validity of the arguments passed so as to increase performance by not
+forcing a context switch.
+
+If the setting has been accepted by the sensor the new value is cached by the LDD so further
+querying does not involve another context switch.
+
+@param aAttribute An enum identifying the dynamic attribute to change.
+@param aValue The attributes value.
+@return KErrNone if successful, KErrNotSupported if not supported, KErrArgument if aValue out of range.
+ Otherwise, one of the system wide error codes.
+@pre The thread must be in a critical section.
+*/
+TInt DCameraScLdd::SetDynamicAttribute(TInt aAttribute, TUint aValue)
+ {
+ TUint* attrCachePtr = NULL;
+ TInt err = KErrNotSupported;
+
+ switch (aAttribute)
+ {
+ case ECamAttributeBrightness:
+ err = Pdd()->SetBrightness(aValue);
+ attrCachePtr = &iBrightnessValue;
+ break;
+
+ case ECamAttributeContrast:
+ err = Pdd()->SetContrast(aValue);
+ attrCachePtr = &iContrastValue;
+ break;
+
+ case ECamAttributeColorEffect:
+ err = Pdd()->SetColorEffect(aValue);
+ attrCachePtr = &iColorEffectValue;
+ break;
+
+ default:
+ return err;
+ }
+
+ if (err == KErrNone)
+ {
+ // Cache the set value.
+ __ASSERT_DEBUG(attrCachePtr, Kern::Fault(KCameraLddPanic, __LINE__));
+ *attrCachePtr = aValue;
+ }
+
+ return err;
+ }
+
+
+/**
+Allows querying of a dynamic setting.
+The value is read from the cached LDD values.
+
+@param aAttribute An enum identifying the dynamic attribute to change.
+@param aValue A reference to a variable that will receive the attribute value.
+@return KErrNone if successful, KErrNotFound if aAttribute is an unsupported
+ setting. The parameter aValue is not changed if this function fails.
+*/
+TInt DCameraScLdd::GetDynamicAttribute(TInt aAttribute, TUint& aValue)
+ {
+ switch (aAttribute)
+ {
+ case ECamAttributeBrightness:
+ aValue = iBrightnessValue;
+ break;
+
+ case ECamAttributeContrast:
+ aValue = iContrastValue;
+ break;
+
+ case ECamAttributeColorEffect:
+ aValue = iColorEffectValue;
+ break;
+
+ default:
+ return KErrNotFound;
+ }
+
+ return KErrNone;
+ }
+
+
+/**
+Updates the buffer configuration of the camera for the specified capture mode.
+@return A handle to the shared chunk for the owning thread (a value >0), if successful;
+ otherwise one of the other system wide error codes, (a value <0).
+*/
+TInt DCameraScLdd::SetBufConfig(TInt aCaptureMode, TInt aNumBuffers)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::SetBufConfig(CaptureMode=%d,NumBuffers=%d)",aCaptureMode,aNumBuffers));
+
+ // Free any memory and chunk already allocated
+ TInt r=ChunkClose(aCaptureMode);
+ if (r!=KErrNone)
+ return(r);
+
+ // Allocate a new shared chunk and create the specified number of buffers within it.
+ TInt buffersize=((iCaptureModeConfig[aCaptureMode].iCamConfig.iFrameSize.iWidth*iCaptureModeConfig[aCaptureMode].iCamConfig.iFrameSize.iHeight) * iCaptureModeConfig[aCaptureMode].iCamConfig.iPixelWidthInBytes);
+ __KTRACE_CAM(Kern::Printf(">>DCameraScLdd::SetBufConfig - iFrameSize:%d, iPixelWidthInBytes:%d => bufferSize:%d",(iCaptureModeConfig[aCaptureMode].iCamConfig.iFrameSize.iWidth*iCaptureModeConfig[aCaptureMode].iCamConfig.iFrameSize.iHeight),iCaptureModeConfig[aCaptureMode].iCamConfig.iPixelWidthInBytes,buffersize));
+ iCaptureModeConfig[aCaptureMode].iBufManager=new DBufferManager(this);
+ if (!iCaptureModeConfig[aCaptureMode].iBufManager)
+ return(KErrNoMemory);
+ r=iCaptureModeConfig[aCaptureMode].iBufManager->Create(aNumBuffers,buffersize);
+ if (r!=KErrNone)
+ return(r);
+
+ // Update the LDD's chunk/buffer geometry info.
+ r=ReAllocBufferConfigInfo(aCaptureMode, aNumBuffers);
+ if (r!=KErrNone)
+ return(r);
+ iCaptureModeConfig[aCaptureMode].iBufManager->GetBufConfig(*iCaptureModeConfig[aCaptureMode].iBufConfig);
+
+ // Create handle to the shared chunk for the owning thread.
+ r=Kern::MakeHandleAndOpen(iOwningThread,iCaptureModeConfig[aCaptureMode].iBufManager->iChunk);
+ if (r>0)
+ {
+ // And save the the chunk and handle for later. Normally the chunk handle will be closed when the chunk
+ // is closed, but if the chunk is re-allocated then it will need to be closed before re-allocation.
+ iCaptureModeConfig[aCaptureMode].iChunkHandle=r;
+ }
+
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::SetBufConfig - %d",r));
+ return(r);
+ }
+
+/**
+Updates the buffer configuration of the camera, which has been supplied by the user, for the specified capture mode.
+@param aCaptureMode The capture mode for which the setting of the buffer configuration is made.
+@param aBufferConfigBuf A buffer that holds the buffer configuration for the camera.
+@param aChunkHandle A handle for the shared chunk supplied by the client.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+@pre The thread must be in a critical section.
+*/
+TInt DCameraScLdd::SetBufConfig(TInt aCaptureMode,const TDesC8* aBufferConfigBuf,TInt aChunkHandle)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::SetConfig(Handle-%d)",aChunkHandle));
+
+ // Read the buffer config structure from the client.
+ TInt numBuffers;
+ TPtr8 ptr((TUint8*)&numBuffers,sizeof(numBuffers));
+ TInt r=Kern::ThreadDesRead(iOwningThread,aBufferConfigBuf,ptr,0);
+ if (r!=KErrNone)
+ return(r);
+ // Calculate the minimum length of the descriptor.
+ TInt minDesLen=(numBuffers*sizeof(SBufSpecList))+sizeof(TSharedChunkBufConfigBase);
+ r=Kern::ThreadGetDesLength(iOwningThread,aBufferConfigBuf);
+ if (r<minDesLen)
+ return(KErrArgument);
+ r=ReAllocBufferConfigInfo(aCaptureMode, numBuffers);
+ if (r!=KErrNone)
+ return(r);
+ ptr.Set((TUint8*)iCaptureModeConfig[aCaptureMode].iBufConfig,0,iCaptureModeConfig[aCaptureMode].iBufConfigSize);
+ r=Kern::ThreadDesRead(iOwningThread,aBufferConfigBuf,ptr,0);
+ if (r!=KErrNone)
+ return(r);
+
+ // Free any memory and chunk already allocated
+ r=ChunkClose(aCaptureMode);
+ if (r!=KErrNone)
+ return(r);
+
+ // Open the shared chunk supplied and create buffer objects for the committed buffers within it.
+ iCaptureModeConfig[aCaptureMode].iBufManager=new DBufferManager(this);
+ if (!iCaptureModeConfig[aCaptureMode].iBufManager)
+ return(KErrNoMemory);
+ r=iCaptureModeConfig[aCaptureMode].iBufManager->Create(*iCaptureModeConfig[aCaptureMode].iBufConfig,aChunkHandle,iOwningThread);
+ if (r!=KErrNone)
+ return(r);
+
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::SetConfig - %d",KErrNone));
+ return(r);
+ }
+
+/**
+Frees the buffer manager associated with a chunk, and closes the chunk itself. The chunk being closed,
+and its associated DBufferManager instance should have been allocated by the device driver. However,
+this is not a requirement.
+@param aCaptureMode The capture mode for which to free the buffer manager and chunk.
+@return KErrNone if successful.
+ KErrInUse if an attempt has been made to free the memory and chunk while they are in use.
+ Otherwise one of the other system-wide error codes.
+*/
+TInt DCameraScLdd::ChunkClose(TInt aCaptureMode)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::ChunkClose(Capture Mode-%d)",aCaptureMode));
+
+ if(iCaptureMode == aCaptureMode)
+ {
+ if (iState==ECapturing)
+ return(KErrInUse);
+ }
+
+ // Delete any existing buffers
+ if (iCaptureModeConfig[aCaptureMode].iBufManager)
+ {
+ delete iCaptureModeConfig[aCaptureMode].iBufManager;
+ iCaptureModeConfig[aCaptureMode].iBufManager=NULL;
+ }
+
+ // If a handle to the shared chunk was created, close it, using the handle of the thread on which
+ // it was created, in case a different thread is now calling us
+ if (iCaptureModeConfig[aCaptureMode].iChunkHandle>0)
+ {
+ Kern::CloseHandle(iOwningThread,iCaptureModeConfig[aCaptureMode].iChunkHandle);
+ iCaptureModeConfig[aCaptureMode].iChunkHandle=0;
+ }
+
+ return(KErrNone);
+ }
+
+/**
+Set the current capture mode and submits the camera configuration to the PDD, passing it as a descriptor
+to support future changes to the config structure.
+
+@param aCaptureMode The capture mode that the camera switches to.
+@return KErrNone if successful;
+ otherwise one of the other system-wide error codes.
+*/
+TInt DCameraScLdd::SetCaptureMode(TInt aCaptureMode)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::SetCaptureMode(Mode-%d)",aCaptureMode));
+
+ TInt r=KErrNone;
+ if(aCaptureMode >= ECamCaptureModeMax || aCaptureMode < 0)
+ {
+ r=KErrNotFound;
+ return(r);
+ }
+
+ if (!iCaptureModeConfig[aCaptureMode].iBufManager)
+ {
+ r=KErrNotReady;
+ return(r);
+ }
+
+ iCaptureMode=(TDevCamCaptureMode)aCaptureMode; // The capture mode has already been checked for its validity.
+
+ __KTRACE_CAM(Kern::Printf("DCameraScLdd::SetCaptureMode: iFrameSize:%dx%d)",iCaptureModeConfig[iCaptureMode].iCamConfig.iFrameSize.iWidth, iCaptureModeConfig[iCaptureMode].iCamConfig.iFrameSize.iHeight));
+
+ // Call the PDD to change the hardware configuration according to the new capture mode.
+ // Pass it as a descriptor - to support future changes to the config structure.
+ TPtr8 ptr((TUint8*)&iCaptureModeConfig[iCaptureMode].iCamConfig,sizeof(iCaptureModeConfig[iCaptureMode].iCamConfig),sizeof(iCaptureModeConfig[iCaptureMode].iCamConfig));
+ r=Pdd()->SetConfig(ptr);
+ if (r!=KErrNone)
+ return(r);
+ return KErrNone;
+ }
+
+
+/**
+Process a start image capture request from the client - in the capture mode supplied.
+If this is a free running mode then the PDD is called straight away to commence capturing frames. In one shot mode the driver postpones the capturing
+of frames until a NotifyNewImage() request is received.
+@return KErrNone if successful; whether capture mode was actually started or deferred until NotifyNewImage();
+ KErrNotReady if SetConfig() has not been previously called;
+ otherwise one of the other system-wide error codes.
+*/
+TInt DCameraScLdd::Start()
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::Start(Current Mode-%d)",iCaptureMode));
+
+ if (iState==ECapturing)
+ return(KErrInUse);
+ TInt r=KErrNone;
+
+ // Only continue if the mode being started has been configured
+ if (iCaptureModeConfig[iCaptureMode].iBufManager)
+ iState=EConfigured;
+
+ if (iState==EOpen)
+ r=KErrNotReady;
+ else if (iState==EConfigured)
+ {
+ iCaptureModeConfig[iCaptureMode].iBufManager->Reset();
+ if (iCaptureMode!=ECamCaptureModeImage)
+ r=DoStart();
+ if (r==KErrNone)
+ iState=ECapturing;
+ }
+ else
+ r=KErrGeneral;
+ return(r);
+ }
+
+/**
+Start the PDD capturing images.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCameraScLdd::DoStart()
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DoStart()"));
+
+ DBufferManager* bufManager=iCaptureModeConfig[iCaptureMode].iBufManager;
+ TLinAddr linAddr=(bufManager->iChunkBase)+(bufManager->iCurrentBuffer->iChunkOffset);
+ TPhysAddr physAddr=bufManager->iCurrentBuffer->iPhysicalAddress;
+ TInt r=Pdd()->Start(iCaptureMode,linAddr,physAddr);
+
+/*
+ * James Cooper: Uncommenting this code will cause the ASSERT_DEBUG in SetImageCaptured() to fail
+ * if (r==KErrNone && bufManager->iNextBuffer)
+ {
+ linAddr=(bufManager->iChunkBase)+(bufManager->iNextBuffer->iChunkOffset);
+ physAddr=bufManager->iNextBuffer->iPhysicalAddress;
+ r=Pdd()->CaptureNextImage(linAddr,physAddr);
+ }
+*/
+ return(r);
+ }
+
+/**
+Process a notify a new image request from the client.
+If there is an image already available then the request is completed straight away, otherwise it is added to the capture request queue.
+@param aStatus The request status to be signalled when the request is complete. If the request is successful then this is set
+ to the offset within the shared chunk where the record data resides. Alternatively, if an error occurs,
+ it will be set to one of the system wide error values.
+@return KErrNone if successful - whether the request was completed or simply queued;
+ KErrNotReady if Start() hasn't been previousely called;
+ KErrInUse: if the client needs to free up buffers before further requests can be accepted;
+ KErrGeneral: if the client has more requests queued than there are buffers;
+ otherwise one of the other system wide error codes.
+*/
+TInt DCameraScLdd::NotifyNewImage(TRequestStatus* aStatus)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::NotifyNewImage(%x) - iState(%d)",aStatus,iState));
+ DBufferManager* bufManager=iCaptureModeConfig[iCaptureMode].iBufManager;
+ TInt r;
+ if (iState!=ECapturing || !bufManager)
+ return(KErrNotReady);
+
+ NKern::FMWait(&iMutex); // Acquire the buffer/request list mutex.
+ if (iCaptureMode!=ECamCaptureModeImage)
+ {
+ // We're operating in one of the free running modes, see if an image is already available.
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::NotifyNewImage - Getting image for client"));
+ TImageBuffer* buf=bufManager->GetImageForClient(EFalse);
+ if (buf)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::NotifyNewImage - There is an image available already"));
+ // There is an image available already - complete the request.
+ r=buf->iResult;
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ if (r==KErrNone)
+ {
+ // Only complete if successful here. Errors will be completed on returning from this method.
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::NotifyNewImage(iId:%d)",buf->iId));
+ Kern::RequestComplete(iOwningThread,aStatus,(buf->iId));
+ }
+ return(r);
+ }
+
+ // The buffer 'completed' list is empty. If the 'in-use' list contains all the buffers apart from the one being filled
+ // then let the client know they need to free some buffers.
+ if (bufManager->iFreeBufferQ.IsEmpty() && !bufManager->iNextBuffer)
+ {
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ return(KErrInUse);
+ }
+ }
+ else
+ {
+ // We're operating in one shot image capture mode. Check if the client needs to free up some buffers
+ // before we can accept the request.
+ if (bufManager->iCompletedBufferQ.IsEmpty() && bufManager->iFreeBufferQ.IsEmpty() && !bufManager->iNextBuffer)
+ {
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ return(KErrInUse);
+ }
+
+ // Enough buffers are available so we can start capturing data. First
+ // check that there isn't already a capture request in progress.
+ if (iRequestQueue.IsEmpty())
+ {
+ // No previous request in progress so start the PDD.
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ r=DoStart();
+ if (r!=KErrNone)
+ return(r);
+ NKern::FMWait(&iMutex); // Acquire the buffer/request list mutex again.
+ }
+ }
+
+ // Save the request in the pending queue and return. The request will be completed from the PDD and the DFC thread when
+ // an image is available.
+ r=iRequestQueue.Add(aStatus);
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ return(r);
+ }
+
+/**
+Process a release buffer request from the client.
+@param aChunkOffset The chunk offset corresponding to the buffer to be freed.
+@return KErrNone if successful;
+ KErrNotFound if no 'in use' buffer had the specified chunk offset;
+ KErrNotReady if the driver hasn't been configured for the current capture mode.
+*/
+TInt DCameraScLdd::ReleaseBuffer(TInt aBufferId)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::ReleaseBuffer(%d)",aBufferId));
+ if(!iCaptureModeConfig[iCaptureMode].iBufManager)
+ return KErrNotReady;
+ DBufferManager* bufManager=iCaptureModeConfig[iCaptureMode].iBufManager;
+ TInt chunkOffset = 0;
+
+ TInt r=KErrNone;
+ /* The driver is left in an ECapturing state after capturing frames. However, it can be left in an
+ EConfigured state as a result of Stop() being called. Stop() cancels all pending capture requests and
+ leaves the driver in a state in which it can be restarted without needing reconfiguring. */
+ if (iState!=EOpen && bufManager)
+ {
+ chunkOffset = bufManager->iImageBuffer[aBufferId].iChunkOffset;
+ TImageBuffer* buf=NULL;
+ NKern::FMWait(&iMutex); // Acquire the buffer/request list mutex.
+ buf=bufManager->FindInUseImage(chunkOffset);
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ if (buf)
+ {
+ // The buffer specified by the client has been found in the 'in-use' list.
+ bufManager->Purge(buf);
+ }
+ else
+ r=KErrNotFound;
+
+ if (r==KErrNone)
+ {
+ NKern::FMWait(&iMutex); // Acquire the buffer/request list mutex.
+ // Release it from the 'in-use list into the 'free' list.
+ r=bufManager->ReleaseImage(chunkOffset);
+ if (r>0)
+ {
+ // The buffer needs to be queued straight away - so signal this to the PDD
+ TLinAddr linAddr=(bufManager->iChunkBase)+(bufManager->iNextBuffer->iChunkOffset);
+ TPhysAddr physAddr=bufManager->iNextBuffer->iPhysicalAddress;
+ buf=bufManager->iNextBuffer;
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ r=Pdd()->CaptureNextImage(linAddr,physAddr);
+ if (r==KErrNotReady)
+ r=KErrNone;
+ }
+ else
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ }
+ }
+ else
+ r=KErrNotReady;
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::ReleaseBuffer() - r(%d)",r));
+ return(r);
+ }
+
+/**
+Called from the PDD in the DFC thread each time it finishes capturing an image frame.
+This will complete a pending capture request and update buffer lists.
+@param aCaptureMode The capture mode of the image captured. @see TDevCamCaptureMode.
+@param aResult The result of the image capture request being completed.
+@param aLinAddr If this function returns KErrNone then on return, this holds the linear address of the start of the next buffer
+ to use for image capture.
+@param aPhysAddr If this function returns KErrNone then on return, this holds the physical address that corresponds to the
+ linear address: aLinAddr.
+@return KErrNone if capturing should continue - with holding information on the next buffer to use for image capture.
+ KErrNotReady if capturing should continue - but with no further buffer available for image capture just yet.
+ KErrAbort if image capturing should now be terminated.
+*/
+TInt DCameraScLdd::ImageCaptureCallback(TDevCamCaptureMode /*aCaptureMode*/,TInt aResult,TLinAddr* aLinAddr,TPhysAddr* aPhysAddr)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::ImageCaptureCallback"));
+
+ DBufferManager* bufManager=iCaptureModeConfig[iCaptureMode].iBufManager;
+ // Update the buffer list and get the next buffer for capture.
+ NKern::FMWait(&iMutex); // Acquire the buffer/request list mutex.
+ TImageBuffer* nextBuffer=bufManager->SetImageCaptured(aResult); // Puts the captured image's buffer in the completed buffer queue.
+
+ // Check if there is a capture request pending.
+ if (!iRequestQueue.IsEmpty())
+ {
+ // A capture request is pending.
+ TBool removeLast=((iCaptureMode==ECamCaptureModeImage) ? (TBool) ETrue : (TBool) EFalse);
+ TImageBuffer* buf=bufManager->GetImageForClient(removeLast); // Retrieved the captured image from the buffer in the completed buffer queue.
+ if (buf)
+ {
+ // Update the request pending list and complete the request.
+ TRequestStatus* rs=iRequestQueue.Remove();
+ TInt reason=(buf->iResult==KErrNone) ? buf->iId : buf->iResult;
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ buf->SyncMemoryAfterDmaRead();
+ Kern::RequestComplete(iOwningThread,rs,reason); // Complete the request.
+ }
+ else
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+ }
+ else
+ NKern::FMSignal(&iMutex); // Release the buffer/request list mutex.
+
+ // Now work out what instruction to give to the PDD
+ TInt r=KErrNone;
+ if (iCaptureMode==ECamCaptureModeImage)
+ {
+ // Image capture mode. If we've just completed a one shot request, see if there is yet another one pending.
+ if (!iRequestQueue.IsEmpty())
+ {
+ // Another request is pending so let the PDD carry on.
+ // If an error occured we need to first stop and re-start image capture
+ if (aResult!=KErrNone)
+ {
+ iRestartDfc.Enque(); // Queue a DFC to re-start the PDD later.
+ r=KErrAbort;
+ }
+ }
+ else
+ {
+ r=KErrAbort; // End of image gather mode so stop the PDD.
+ }
+ }
+ else
+ {
+ // One of the free running modes. If an error occured we need to first stop and re-start image capture
+ if (aResult!=KErrNone)
+ {
+ iRestartDfc.Enque(); // Queue a DFC to re-start the PDD later.
+ r=KErrAbort;
+ }
+ }
+
+ // If capture should continue, check if there is a further buffer available to use for image capture.
+ if (r==KErrNone)
+ {
+ if (nextBuffer)
+ {
+ *aLinAddr=(bufManager->iChunkBase)+(nextBuffer->iChunkOffset);
+ *aPhysAddr=nextBuffer->iPhysicalAddress;
+ }
+ else
+ r=KErrNotReady;
+ }
+ return(r);
+ }
+
+/**
+Stores the camera configuration passed in from the user after checking and validating it.
+@param aCaptureMode The capture mode for which the setting of the camera configuration is made.
+@param aCamConfigBuf A buffer that contains the camera configuration.
+@return KErrNone if successful
+ KErrInUse if the camera is capturing an image
+ KErrArgument if the camera configuration passed in is invalid
+ otherwise a system wide error code.
+*/
+TInt DCameraScLdd::DoSetConfig(TInt aCaptureMode, const TDesC8* aCamConfigBuf)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DoSetConfig(CaptureMode=%d)",aCaptureMode));
+
+ if(iCaptureMode == aCaptureMode)
+ {
+ if (iState==ECapturing)
+ return(KErrInUse);
+ }
+
+ // Read the config structure from the client
+ TCameraConfigV02 config;
+ TPtr8 ptr((TUint8*)&config,sizeof(config));
+ TInt r=Kern::ThreadDesRead(iOwningThread,aCamConfigBuf,ptr,0);
+ if (r!=KErrNone)
+ return(r);
+
+ // Check that it is compatible with this camera device
+ r=ValidateConfig(aCaptureMode, config);
+ if (r!=KErrNone)
+ {
+ if (r == KErrNotFound)
+ r = KErrArgument;
+ return(r);
+ }
+
+ // We're about to replace any previous configuration - so set the
+ // status back to un-configured. A new buffer configuration must be calculated as a result of that.
+ //iState=EOpen;
+
+ // Save the new configuration.
+ iCaptureModeConfig[aCaptureMode].iCamConfig=config;
+ iCaptureModeConfig[aCaptureMode].iFrameHeight=iCaptureModeConfig[aCaptureMode].iCamConfig.iFrameSize.iHeight;
+ iCaptureModeConfig[aCaptureMode].iFrameWidth=iCaptureModeConfig[aCaptureMode].iCamConfig.iFrameSize.iWidth;
+
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::DoSetConfig - %d",KErrNone));
+ return(r);
+ }
+
+/**
+Validates the configuration that is about to be used with the driver.
+@param aCaptureMode The capture mode that the configuration is for.
+@param aConfig The buffer that contains the camera configuration, as passed in from the user.
+@return KErrNotFound if the configuration is not supported by the camera sensor.
+ KErrNotSupported if the driver does not support aCaptureMode
+ KErrNone if successful.
+*/
+TInt DCameraScLdd::ValidateConfig(TInt aCaptureMode, TCameraConfigV02& aConfig)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::ValidateConfig"));
+
+ TInt capsSize = Pdd()->CapsSize();
+ NKern::ThreadEnterCS();
+ TAny* capsBuf = Kern::Alloc(capsSize);
+ if(!capsBuf)
+ {
+ NKern::ThreadLeaveCS();
+ return KErrNoMemory;
+ }
+
+ TPtr8 capsPtr( (TUint8*)capsBuf, capsSize, capsSize );
+ Pdd()->Caps(capsPtr);
+ NKern::ThreadLeaveCS();
+
+ TCameraCapsV02* camCaps = (TCameraCapsV02*) capsPtr.Ptr();
+
+ TInt r;
+ if(aCaptureMode==ECamCaptureModeImage && camCaps->iNumImagePixelFormats)
+ {
+ r=DoValidateConfig(camCaps, aCaptureMode, aConfig);
+ }
+ else if(aCaptureMode==ECamCaptureModeVideo && camCaps->iNumVideoPixelFormats)
+ {
+ r=DoValidateConfig(camCaps, aCaptureMode, aConfig);
+ }
+ else if(aCaptureMode==ECamCaptureModeViewFinder && camCaps->iNumViewFinderPixelFormats)
+ {
+ r=DoValidateConfig(camCaps, aCaptureMode, aConfig);
+ }
+ else
+ r=KErrNotSupported;
+
+ if(r==KErrNone)
+ {
+ // Calculate the pixel width (in bytes) for the format specified
+ aConfig.iPixelWidthInBytes=aConfig.iPixelFormat.iPixelWidthInBytes;
+ }
+
+ NKern::ThreadEnterCS();
+ Kern::Free(capsBuf);
+ NKern::ThreadLeaveCS();
+
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::ValidateConfig - %d",r));
+ return(r);
+ }
+
+/**
+Validates the configuration that is about to be used with the driver by checking it against what the camera sensor supports.
+@param aCamCaps The buffer that contains the capabilities of the camera driver.
+@param aCaptureMode The capture mode that the configuration is for.
+@param aConfig The buffer that contains the camera configuration, as passed in from the user.
+@return KErrNotFound if the configuration is not supported by the camera sensor
+ KErrNone if successful
+ or one of the system wide error values.
+*/
+TInt DCameraScLdd::DoValidateConfig(TCameraCapsV02* aCamCaps, TInt& aCaptureMode, TCameraConfigV02& aConfig)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::DoValidateConfig"));
+ TAny* frameSizeCapsBuf;
+ TInt frameSizeCapsSize;
+ SFrameSizeCapsInfo info;
+ SDevCamFrameSize* frameSize;
+ TUint i;
+ TUint l;
+ SDevCamPixelFormat* pixelFormat;
+ TUint start;
+ TUint end;
+ TInt r;
+ pixelFormat = (SDevCamPixelFormat*) (aCamCaps + 1);
+ if(aCaptureMode==ECamCaptureModeImage)
+ {
+ start=0;
+ end=aCamCaps->iNumImagePixelFormats;
+ }
+ else if(aCaptureMode==ECamCaptureModeVideo)
+ {
+ start=aCamCaps->iNumImagePixelFormats;
+ end=aCamCaps->iNumImagePixelFormats + aCamCaps->iNumVideoPixelFormats;
+ pixelFormat += aCamCaps->iNumImagePixelFormats;
+ }
+ else if(aCaptureMode==ECamCaptureModeViewFinder)
+ {
+ start=aCamCaps->iNumImagePixelFormats+aCamCaps->iNumVideoPixelFormats;
+ end=aCamCaps->iNumImagePixelFormats + aCamCaps->iNumVideoPixelFormats + aCamCaps->iNumViewFinderPixelFormats;
+ pixelFormat += aCamCaps->iNumImagePixelFormats;
+ pixelFormat += aCamCaps->iNumVideoPixelFormats;
+ }
+ else
+ return KErrNotSupported;
+
+ for (i=start; i<end; i++)
+ {
+ if(aConfig.iPixelFormat.iPixelFormat==pixelFormat->iPixelFormat)
+ {
+ info.iUidPixelFormat = pixelFormat->iPixelFormat;
+ info.iCaptureMode = (TDevCamCaptureMode) aCaptureMode;
+ frameSizeCapsSize = pixelFormat->iNumFrameSizes*sizeof(SDevCamFrameSize);
+ NKern::ThreadEnterCS();
+ frameSizeCapsBuf = Kern::Alloc(frameSizeCapsSize);
+ NKern::ThreadLeaveCS();
+ if (!frameSizeCapsBuf)
+ {
+ return KErrNoMemory;
+ }
+ TPtr8 frameSizeCapsPtr( (TUint8*)frameSizeCapsBuf, frameSizeCapsSize, frameSizeCapsSize );
+ if ((r = Pdd()->FrameSizeCaps(info.iCaptureMode, info.iUidPixelFormat, frameSizeCapsPtr)) == KErrNone)
+ {
+ frameSize = (SDevCamFrameSize*) frameSizeCapsPtr.Ptr();
+ for(l=0; l<pixelFormat->iNumFrameSizes; l++ )
+ {
+ if (aConfig.iFrameSize.iWidth == frameSize->iWidth &&
+ aConfig.iFrameSize.iHeight == frameSize->iHeight &&
+ aConfig.iFrameRate >= frameSize->iMinFrameRate &&
+ aConfig.iFrameRate <= frameSize->iMaxFrameRate)
+ {
+ NKern::ThreadEnterCS();
+ Kern::Free(frameSizeCapsBuf);
+ NKern::ThreadLeaveCS();
+ __KTRACE_CAM(Kern::Printf("<DCameraScLdd::DoValidateConfig"));
+ return KErrNone;
+ }
+ frameSize++;
+ }
+ NKern::ThreadEnterCS();
+ Kern::Free(frameSizeCapsBuf);
+ NKern::ThreadLeaveCS();
+ return KErrNotFound;
+ }
+ else
+ {
+ NKern::ThreadEnterCS();
+ Kern::Free(frameSizeCapsBuf);
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+ }
+ pixelFormat++;
+ }
+ return KErrNotFound;
+ }
+
+/**
+The DFC used to re-start the PDD following a data capture error.
+@param aChannel A pointer to the camera driver logical channel object.
+*/
+void DCameraScLdd::RestartDfc(TAny* aChannel)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::RestartDfc"));
+
+ DCameraScLdd& drv=*(DCameraScLdd*)aChannel;
+
+ if (!drv.iCaptureModeConfig[drv.iCaptureMode].iBufManager->iCurrentBuffer)
+ drv.iCaptureModeConfig[drv.iCaptureMode].iBufManager->iCurrentBuffer=drv.iCaptureModeConfig[drv.iCaptureMode].iBufManager->NextAvailableForCapture();
+ __ASSERT_ALWAYS(drv.iCaptureModeConfig[drv.iCaptureMode].iBufManager->iCurrentBuffer,Kern::Fault(KCameraLddPanic,__LINE__));
+
+ if (!drv.iCaptureModeConfig[drv.iCaptureMode].iBufManager->iNextBuffer)
+ drv.iCaptureModeConfig[drv.iCaptureMode].iBufManager->iNextBuffer=drv.iCaptureModeConfig[drv.iCaptureMode].iBufManager->NextAvailableForCapture();
+
+ drv.DoStart();
+ }
+
+/**
+The DFC used to handle power down requests from the power manager before a transition into system
+shutdown/standby.
+@param aChannel A pointer to the camera driver logical channel object.
+*/
+void DCameraScLdd::PowerDownDfc(TAny* aChannel)
+ {
+ DCameraScLdd& drv=*(DCameraScLdd*)aChannel;
+ drv.Shutdown();
+ drv.iPowerHandler->PowerDownDone();
+ }
+
+/**
+The DFC used to handle power up requests from the power manager following a transition out of system standby.
+@param aChannel A pointer to the camera driver logical channel object.
+*/
+void DCameraScLdd::PowerUpDfc(TAny* aChannel)
+ {
+ DCameraScLdd& drv=*(DCameraScLdd*)aChannel;
+ drv.iPowerHandler->PowerUpDone();
+ }
+
+void DCameraScLdd::PanicClientThread(TInt aReason)
+ {
+ Kern::ThreadKill(iOwningThread, EExitPanic, aReason, KDevCameraScName);
+ }
+
+/**
+Retrieves the capabilities of the camera sensor.
+@param aBuffer A pointer to a descriptor passed in by the user.
+*/
+TInt DCameraScLdd::GetSensorCaps(TAny* aBuffer)
+ {
+ // Return the capabilities for this device. Read this from the PDD and
+ // then write it to the client
+ TInt capsSize = Pdd()->CapsSize();
+ TInt bufferSize;
+ TInt maxBufferSize;
+ Kern::KUDesInfo(*((TDes8*)aBuffer), bufferSize, maxBufferSize);
+ if(capsSize>maxBufferSize)
+ {
+ return KErrArgument;
+ }
+ NKern::ThreadEnterCS();
+ TAny* capsBuf = Kern::Alloc(capsSize);
+ if(!capsBuf)
+ {
+ NKern::ThreadLeaveCS();
+ return KErrNoMemory;
+ }
+
+ TPtr8 capsPtr( (TUint8*)capsBuf, capsSize, capsSize );
+ Pdd()->Caps(capsPtr);
+ NKern::ThreadLeaveCS();
+ Kern::InfoCopy(*((TDes8*)aBuffer), capsPtr.Ptr(), capsSize);
+ NKern::ThreadEnterCS();
+ Kern::Free((TAny*)capsBuf);
+ NKern::ThreadLeaveCS();
+ return KErrNone;
+ }
+
+/**
+Retrieves the frame sizes supported for a given pixel format.
+@param aBuffer A pointer to descriptor passed in by the user.
+@param aFrameSizeCapsInfo A structure that holds information regarding the requested capabilities.
+*/
+TInt DCameraScLdd::GetFrameSizeCaps(TAny* aBuffer, TAny* aFrameSizeCapsInfo)
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScLdd::GetFrameSizeCaps()"));
+ TInt frameSizeCapsMaxSize;
+ TInt frameSizeCapsSize;
+ Kern::KUDesInfo(*((TDes8*)aBuffer),frameSizeCapsSize,frameSizeCapsMaxSize);
+ SFrameSizeCapsInfo info;
+ kumemget((TAny*)&info,aFrameSizeCapsInfo,sizeof(info));
+ NKern::ThreadEnterCS();
+ // Allocate memory on the heap for the frame size structure.
+ TAny* frameSizeCapsBuf = Kern::Alloc(frameSizeCapsMaxSize);
+ if (!frameSizeCapsBuf)
+ {
+ NKern::ThreadLeaveCS();
+ return KErrNoMemory;
+ }
+ TPtr8 frameSizeCapsPtr( (TUint8*)frameSizeCapsBuf, frameSizeCapsMaxSize, frameSizeCapsMaxSize );
+ // Request the frame sizes from the Pdd.
+ TInt r=Pdd()->FrameSizeCaps(info.iCaptureMode, info.iUidPixelFormat, frameSizeCapsPtr);
+ NKern::ThreadLeaveCS();
+ if (r!=KErrNone)
+ {
+ NKern::ThreadEnterCS();
+ Kern::Free((TAny*)frameSizeCapsBuf);
+ NKern::ThreadLeaveCS();
+ return r;
+ }
+ Kern::InfoCopy(*((TDes8*)aBuffer),frameSizeCapsPtr.Ptr(), frameSizeCapsMaxSize);
+ NKern::ThreadEnterCS();
+ Kern::Free((TAny*)frameSizeCapsBuf);
+ NKern::ThreadLeaveCS();
+ return KErrNone;
+ }
+
+
+/**
+Constructor for the buffer manager.
+*/
+DBufferManager::DBufferManager(DCameraScLdd* aLdd)
+ : iLdd(aLdd)
+ {
+// iChunk=NULL;
+// iNumBuffers=0;
+// iImageBuffer=NULL;
+ }
+
+/**
+Destructor for the buffer manager.
+@pre The thread must be in a critical section.
+*/
+DBufferManager::~DBufferManager()
+ {
+ if (iChunk)
+ Kern::ChunkClose(iChunk);
+ delete[] iImageBuffer;
+ }
+
+/**
+Second stage constructor for the buffer manager. This version creates a shared chunk and a buffer object for each
+buffer specified within this. Then it commits memory within the chunk for each of these buffers. This also involves the
+creation of a set of buffer lists to manage the buffers.
+@param aNumBuffers The number of buffers required in the shared chunk.
+@param aBufferSize The size of each buffer required in the shared chunk.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+@pre The thread must be in a critical section.
+*/
+TInt DBufferManager::Create(TInt aNumBuffers,TInt aBufferSize)
+ {
+ __KTRACE_CAM(Kern::Printf(">DBufferManager::Create(Bufs-%d,Sz-%d)",aNumBuffers,aBufferSize));
+
+ TInt r=CreateBufferLists(aNumBuffers);
+ if (r!=KErrNone)
+ return(r);
+
+ // Calculate the size of the chunk required for the buffer configuration specified.
+ aBufferSize=Kern::RoundToPageSize(aBufferSize);
+ TInt pageSize=Kern::RoundToPageSize(1);
+ // Leave space for guard pages around each buffer. There is a guard page in between each buffer but
+ // NO guard page before the first buffer or after the last buffer
+ TUint64 chunkSize=TUint64(aBufferSize+pageSize)*aNumBuffers-pageSize;
+ if (chunkSize>(TUint64)KMaxTInt)
+ return(KErrNoMemory); // Need more than 2GB of memory!
+
+ // Create the shared chunk. The PDD supplies most of the chunk create info - but not the maximum size.
+ TChunkCreateInfo info;
+ info.iMaxSize=(TInt)chunkSize;
+ iLdd->Pdd()->GetChunkCreateInfo(info); // Call down to the PDD for the rest.
+
+ r = Kern::ChunkCreate(info,iChunk,iChunkBase,iChunkMapAttr);
+ if (r!=KErrNone)
+ return(r);
+
+ // Commit memory in the chunk for each buffer.
+ TInt offset=0;
+ TBool isContiguous;
+ for (TInt i=0; i<aNumBuffers ; i++)
+ {
+ r=CommitMemoryForBuffer(offset,aBufferSize,isContiguous);
+ if (r!=KErrNone)
+ return(r);
+ r=iImageBuffer[i].Create(iChunk,offset,aBufferSize,i,isContiguous);
+ iImageBuffer[i].iId=i;
+ if (r!=KErrNone)
+ return(r);
+ offset += (aBufferSize+pageSize);
+ }
+
+ return(KErrNone);
+ }
+
+/**
+Second stage constructor for the buffer manager. This version opens an existing shared chunk using a client supplied
+handle. It then creates a buffer object for each buffer that exists within the chunk as well as creating a set of buffer
+lists to manage the buffers.
+@param aBufConfig The shared chunk buffer configuration object - specifying the geometry of the buffer configuration
+within the shared chunk supplied.
+@param aChunkHandle A handle for the shared chunk supplied by the client.
+@param anOwningThread The thread in which the given handle is valid.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+@pre The thread must be in a critical section.
+*/
+TInt DBufferManager::Create(TCameraSharedChunkBufConfig& aBufConfig,TInt aChunkHandle,DThread* anOwningThread)
+ {
+ __KTRACE_CAM(Kern::Printf(">DBufferManager::Create(Handle-%d)",aChunkHandle));
+
+ // Validate the buffer configuration information
+ if (!aBufConfig.iFlags&KScFlagBufOffsetListInUse)
+ return(KErrArgument);
+
+ TInt numBuffers=aBufConfig.iNumBuffers;
+ TInt r=CreateBufferLists(numBuffers);
+ if (r!=KErrNone)
+ return(r);
+
+ DChunk* chunk;
+ chunk=Kern::OpenSharedChunk(anOwningThread,aChunkHandle,ETrue);
+ if (!chunk)
+ return(KErrBadHandle);
+ iChunk=chunk;
+
+ // Read the physical address for the 1st buffer in order to determine the kernel address and the map attributes.
+ TInt bufferSizeInBytes=aBufConfig.iBufferSizeInBytes;
+
+ SBufSpecList* bufferSpec=&aBufConfig.iSpec;
+
+ TInt offset=bufferSpec[0].iBufferOffset;
+
+ TPhysAddr physAddr;
+ r=Kern::ChunkPhysicalAddress(iChunk,offset,bufferSizeInBytes,iChunkBase,iChunkMapAttr,physAddr,NULL);
+ if (r!=KErrNone)
+ return(r);
+
+ // Store the supplied buffer info. into each buffer object.
+
+ for (TInt i=0; i<numBuffers; i++)
+ {
+ offset=bufferSpec[i].iBufferOffset;
+ // Assume it isn't contiguous here - Create() will detect and do the right thing if it is contiguous.
+ r=iImageBuffer[i].Create(iChunk,offset,bufferSizeInBytes,i,EFalse);
+ iImageBuffer[i].iId=i;
+ if (r!=KErrNone)
+ return(r);
+ }
+ __KTRACE_CAM(Kern::Printf("<DBufferManager::Create - %d",KErrNone));
+ return(KErrNone);
+ }
+
+/**
+Copies the contents of the Buffer Manager's configuration into aBufConfig
+@param aBufConfig The buffer that the data is copied into.
+*/
+void DBufferManager::GetBufConfig(TCameraSharedChunkBufConfig& aBufConfig)
+ {
+ __KTRACE_CAM(Kern::Printf(">DBufferManager::GetBufConfig"));
+ TInt numBuffers=iNumBuffers;
+ if (numBuffers<=0)
+ return;
+
+ SBufSpecList* bufferSpec=&aBufConfig.iSpec;
+
+ while (numBuffers--)
+ {
+ bufferSpec[numBuffers].iBufferOffset=iImageBuffer[numBuffers].iChunkOffset;
+ bufferSpec[numBuffers].iBufferId=iImageBuffer[numBuffers].iId;
+ }
+
+ aBufConfig.iNumBuffers=iNumBuffers;
+ aBufConfig.iBufferSizeInBytes=iImageBuffer[0].iSize; // They're all the same size - so read from the 1st one.
+ aBufConfig.iFlags|=KScFlagBufOffsetListInUse;
+ return;
+ }
+
+/**
+Allocate an array of buffer objects, - one for each buffer contained within the shared chunk.
+@param aNumBuffers The number of buffer objects required.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+@pre The thread must be in a critical section.
+*/
+TInt DBufferManager::CreateBufferLists(TInt aNumBuffers)
+ {
+ __KTRACE_CAM(Kern::Printf(">DBufferManager::CreateBufferLists(Bufs-%d)",aNumBuffers));
+
+ // Construct the array of buffers.
+ iNumBuffers=aNumBuffers;
+ iImageBuffer=new TImageBuffer[aNumBuffers];
+ if (!iImageBuffer)
+ return(KErrNoMemory);
+ return(KErrNone);
+ }
+
+TInt DBufferManager::CommitMemoryForBuffer(TInt aChunkOffset,TInt aSize,TBool& aIsContiguous)
+ {
+ __KTRACE_CAM(Kern::Printf(">DBufferManager::CommitMemoryForBuffer(Offset-%x,Sz-%d)",aChunkOffset,aSize));
+
+ // Try for physically contiguous memory first.
+ TPhysAddr physicalAddress;
+ TInt r=Kern::ChunkCommitContiguous(iChunk,aChunkOffset,aSize,physicalAddress);
+ if (r==KErrNone)
+ {
+ aIsContiguous=ETrue;
+ return(r);
+ }
+
+ // Commit memory that isn't contiguous instead.
+ aIsContiguous=EFalse;
+ r=Kern::ChunkCommit(iChunk,aChunkOffset,aSize);
+ return(r);
+ }
+
+/**
+Reset all image buffer lists to reflect the state at the start of the image capture process.
+@pre The buffer/request queue mutex must be held.
+*/
+void DBufferManager::Reset()
+ {
+ __KTRACE_CAM(Kern::Printf(">DBufferManager::Reset"));
+
+ TImageBuffer* pBuf;
+
+ // Before reseting buffer lists, purge the cache for all cached buffers currently in use by client.
+ pBuf=(TImageBuffer*)iInUseBufferQ.First();
+ SDblQueLink* anchor=&iInUseBufferQ.iA;
+ while (pBuf!=anchor)
+ {
+ Purge(pBuf);
+ pBuf=(TImageBuffer*)pBuf->iNext;
+ }
+
+ // Start by reseting all the lists.
+ iFreeBufferQ.iA.iNext=iFreeBufferQ.iA.iPrev=&iFreeBufferQ.iA;
+ iCompletedBufferQ.iA.iNext=iCompletedBufferQ.iA.iPrev=&iCompletedBufferQ.iA;
+ iInUseBufferQ.iA.iNext=iInUseBufferQ.iA.iPrev=&iInUseBufferQ.iA;
+
+ // Set the pointers to the current and the next record buffers.
+ pBuf=iImageBuffer; // This is the first buffer
+ iCurrentBuffer=pBuf++;
+ iNextBuffer = pBuf++;
+
+ // Add all other buffers to the free list.
+ TImageBuffer* bufferLimit=iImageBuffer+iNumBuffers;
+ while(pBuf<bufferLimit)
+ iFreeBufferQ.Add(pBuf++);
+ }
+
+/**
+Purge the cache for a cached image buffer.
+@param aBuffer The buffer to be purged.
+*/
+void DBufferManager::Purge(TImageBuffer* aBuffer)
+ {
+ aBuffer->SyncMemoryBeforeDmaRead();
+ }
+
+/**
+Update buffer lists after an image has been captured.
+@param aResult The result of the image capture operation that has just completed.
+@return A pointer to the next image buffer for capture - or NULL if none are available.
+@pre The buffer/request queue mutex must be held.
+*/
+TImageBuffer* DBufferManager::SetImageCaptured(TInt aResult)
+ {
+ // Take a copy of the buffer with the image just captured.
+ __ASSERT_DEBUG(iCurrentBuffer,Kern::Fault(KCameraLddPanic,__LINE__));
+ TImageBuffer* cur=iCurrentBuffer;
+
+ // Make the queued buffer the current one.
+ iCurrentBuffer=iNextBuffer;
+
+ // Now we need to identify the next image buffer to queue.
+ iNextBuffer=NextAvailableForCapture();
+
+ // Now add the buffer with the image just captured to the 'completed' list.
+ if (cur)
+ {
+ cur->iResult=aResult; // Store the result of the capture operation in the image buffer object.
+ iCompletedBufferQ.Add(cur);
+ }
+
+ __KTRACE_CAM(Kern::Printf("<DBufferManager::SetImageCaptured(buf=%08x)-%d",cur->iChunkOffset,aResult));
+ return(iNextBuffer);
+ }
+
+/**
+Remove from the buffer lists the next buffer that is available to queue for transfer.
+@return A pointer to the next image buffer for capture - or NULL if none are available.
+@pre The buffer/request queue mutex must be held.
+*/
+TImageBuffer* DBufferManager::NextAvailableForCapture()
+ {
+ // We need to identify the next image buffer to queue. Try to get one from the 'free' list.
+ TImageBuffer* buffer=(TImageBuffer*)iFreeBufferQ.GetFirst();
+#ifdef DISCARD_COMPLETED_TO_AVOID_OVERFLOW
+ // If there are none left on the 'free' list then take one from the completed list.
+ if (!buffer)
+ buffer=(TImageBuffer*)iCompletedBufferQ.GetFirst();
+#endif
+ return(buffer);
+ }
+
+/**
+Get the next image from the 'completed' capture list. If there is no error associated with the buffer,
+make it 'in use' by the client. Otherwise, return the buffer to the free list.
+@param aRemoveLast If true, the buffer is removed from the tail of the completed capture list, otherwise
+ it is removed from the head of this list.
+@return A pointer to the next completed image buffer - or NULL if there is no buffer available.
+@pre The buffer/request queue mutex must be held.
+*/
+TImageBuffer* DBufferManager::GetImageForClient(TBool aRemoveLast)
+ {
+ __KTRACE_CAM(Kern::Printf("<DBufferManager::GetImageForClient"));
+ TImageBuffer* buffer=NULL;
+ if (!iCompletedBufferQ.IsEmpty())
+ {
+ buffer = (aRemoveLast) ? (TImageBuffer*)iCompletedBufferQ.Last() : (TImageBuffer*)iCompletedBufferQ.First();
+ buffer->Deque();
+
+ if (buffer->iResult==KErrNone)
+ iInUseBufferQ.Add(buffer);
+ else
+ iFreeBufferQ.Add(buffer);
+ }
+ 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.
+@return KErrNone if buffer moved to the free list;
+ 1 if the buffer needs to be queued straight away
+ KErrArgument if no 'in use' buffer had the specified chunk offset;
+@pre The buffer/request queue mutex must be held.
+*/
+TInt DBufferManager::ReleaseImage(TInt aChunkOffset)
+ {
+ __KTRACE_CAM(Kern::Printf(">DBufferManager::ReleaseImage(chunkOffset=%08x)",aChunkOffset));
+ TInt r=KErrArgument;
+
+ // Scan 'in use' list for the image buffer
+ TImageBuffer* pBuf;
+ pBuf=(TImageBuffer*)iInUseBufferQ.First();
+ SDblQueLink* anchor=&iInUseBufferQ.iA;
+ while (pBuf!=anchor && pBuf->iChunkOffset!=aChunkOffset)
+ pBuf=(TImageBuffer*)pBuf->iNext;
+
+ if (pBuf!=anchor)
+ {
+ // Buffer found in 'in-use' list.
+ if (!iNextBuffer)
+ {
+ // We need to signal the pdd to queue this buffer straight away.
+ iNextBuffer=(TImageBuffer*)pBuf->Deque();
+ r=1;
+ }
+ else
+ {
+ // Move buffer to the free list.
+ iFreeBufferQ.Add(pBuf->Deque());
+ r=KErrNone;
+ }
+ }
+
+ __KTRACE_CAM(Kern::Printf("<DBufferManager::ReleaseImage(buf=%08x)",((pBuf!=anchor) ? pBuf->iChunkOffset : -1)));
+ return(r);
+ }
+
+/**
+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
+@pre The buffer/request queue mutex must be held.
+*/
+TImageBuffer* DBufferManager::FindInUseImage(TInt aChunkOffset)
+ {
+ // Scan 'in use' list for the image buffer
+ TImageBuffer* pBuf;
+ pBuf=(TImageBuffer*)iInUseBufferQ.First();
+ SDblQueLink* anchor=&iInUseBufferQ.iA;
+ while (pBuf!=anchor && pBuf->iChunkOffset!=aChunkOffset)
+ pBuf=(TImageBuffer*)pBuf->iNext;
+
+ return((pBuf!=anchor)?pBuf:NULL);
+ }
+
+/**
+Constructor for the image buffer class.
+Clears all member data
+*/
+TImageBuffer::TImageBuffer()
+ {
+ memclr(this,sizeof(*this));
+ }
+
+/**
+Destructor for the image buffer class.
+*/
+TImageBuffer::~TImageBuffer()
+ {
+ delete[] iPhysicalPages;
+ }
+
+/**
+Second stage constructor for the image buffer class - get information on the memory
+allocated to 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 commited.
+ Must be a multiple of the MMU page size.
+@return KErrNone if successful, otherwise one of the other system wide error codes.
+@pre The thread must be in a critical section.
+*/
+TInt TImageBuffer::Create(DChunk* aChunk,TInt aOffset,TInt aSize, TInt aId, TBool aIsContiguous)
+ {
+ __KTRACE_CAM(Kern::Printf(">TImageBuffer::Create(Off-%x,Sz-%d,Contig-%d)",aOffset,aSize,aIsContiguous));
+
+ // Save info. on the chunk the buffer is in, and the offset and size of the buffer.
+ iChunk=aChunk;
+ iChunkOffset=aOffset;
+ iId=aId;
+ iSize=aSize;
+
+ TInt r=KErrNone;
+ iPhysicalPages=NULL;
+ if (!aIsContiguous)
+ {
+ // Allocate an array for a list of the physical pages.
+ iPhysicalPages = new TPhysAddr[aSize/Kern::RoundToPageSize(1)+2];
+ if (!iPhysicalPages)
+ r=KErrNoMemory;
+ }
+
+ if (r==KErrNone)
+ {
+ // Get the physical addresses of the pages in the buffer.
+ TUint32 mapAttr;
+ r=Kern::ChunkPhysicalAddress(aChunk,aOffset,aSize,iLinearAddress,mapAttr,iPhysicalAddress,iPhysicalPages);
+ // r = 0 or 1 on success. (1 meaning the physical pages are not contiguous).
+ if (r==1)
+ {
+ // The physical pages are not contiguous.
+ iPhysicalAddress=KPhysAddrInvalid; // Mark the physical address as invalid.
+ r=(aIsContiguous) ? KErrGeneral : KErrNone;
+ }
+ if (r==0)
+ {
+ delete[] iPhysicalPages; // We shouldn't retain this info. if the physical pages are contiguous.
+ iPhysicalPages=NULL;
+ }
+ }
+ __KTRACE_CAM(Kern::Printf("<TImageBuffer::Create - %d",r));
+ return(r);
+ }
+
+/**
+Prepares a cacheable buffer for use by the DMA engine, before an image capture.
+*/
+void TImageBuffer::SyncMemoryBeforeDmaRead()
+ {
+#ifndef __WINS__
+ if (iChunk->iMapAttr&EMapAttrCachedMax)
+ {
+ Cache::SyncMemoryBeforeDmaRead(iLinearAddress,iSize);
+ }
+#endif
+ }
+
+/**
+Prepare a cacheable buffer for use by the CPU, after an image capture using DMA.
+*/
+void TImageBuffer::SyncMemoryAfterDmaRead()
+ {
+#ifndef __WINS__
+ if (iChunk->iMapAttr&EMapAttrCachedMax)
+ {
+ Cache::SyncMemoryAfterDmaRead(iLinearAddress,iSize);
+ }
+#endif
+ }
+
+/**
+Constructor for the capture request queue.
+*/
+TCameraScRequestQueue::TCameraScRequestQueue(NFastMutex* aMutexPtr)
+ : iMutexPtr(aMutexPtr)
+ {
+ iOwningThread=NULL;
+ memclr(&iRequest[0],sizeof(TCameraScRequest*)*KMaxCamScRequestsPending);
+ }
+
+/**
+Destructor for the capture request queue.
+*/
+TCameraScRequestQueue::~TCameraScRequestQueue()
+ {
+ for (TInt i=0 ; i<KMaxCamScRequestsPending ; i++)
+ delete iRequest[i];
+ }
+
+/**
+Second stage constructor for the capture request queue.
+@param anOwningThread A pointer to the owning client thread.
+@return KErrNone if successful;
+ KErrNoMemory if unable to allocate memory for the capture request queue.
+@pre The thread must be in a critical section.
+*/
+TInt TCameraScRequestQueue::Create(DThread* anOwningThread)
+ {
+ iOwningThread=anOwningThread;
+
+ // Create the set of available request objects and add them to the unused request queue.
+ for (TInt i=0 ; i<KMaxCamScRequestsPending ; i++)
+ {
+ iRequest[i]=new TCameraScRequest;
+ if (!iRequest[i])
+ return(KErrNoMemory);
+ iUnusedRequestQ.Add(iRequest[i]);
+ }
+
+ return(KErrNone);
+ }
+
+/**
+Store a request status pointer onto the tail of the capture request queue.
+@param aStatus The request status pointer to be stored.
+@return KErrNone if successful;
+ KErrGeneral if the limit on the number of pending capture request (KMaxCamScRequestsPending) would be exceeded.
+@pre The buffer/request queue mutex must be held.
+*/
+TInt TCameraScRequestQueue::Add(TRequestStatus* aStatus)
+ {
+ TCameraScRequest* req=(TCameraScRequest*)iUnusedRequestQ.GetFirst();
+ if (!req)
+ return(KErrGeneral); // Must have exceeded KMaxCamScRequestsPending
+
+ req->iStatus=aStatus;
+ iPendRequestQ.Add(req);
+ return(KErrNone);
+ }
+
+/**
+Retrieve the next request status pointer from the head of the capture request queue.
+@return The request status pointer removed or NULL if the list is empty.
+@pre The buffer/request queue mutex must be held.
+*/
+TRequestStatus* TCameraScRequestQueue::Remove()
+ {
+ TRequestStatus* status=NULL;
+ TCameraScRequest* req=(TCameraScRequest*)iPendRequestQ.GetFirst();
+ if (req)
+ {
+ status=req->iStatus;
+ iUnusedRequestQ.Add(req);
+ }
+ return(status);
+ }
+
+/**
+Remove a specifc request status pointer from the the capture request queue, completing it with a 'KErrCancel' completion reason.
+@param aStatus The request status pointer to be completed.
+@pre The buffer/request queue mutex must be held.
+*/
+void TCameraScRequestQueue::Cancel(TRequestStatus* aStatus)
+ {
+ // Find the entry concerned
+ TCameraScRequest* req=(TCameraScRequest*)iPendRequestQ.First();
+ SDblQueLink* anchor=&iPendRequestQ.iA;
+ while (req!=anchor && req->iStatus!=aStatus)
+ req=(TCameraScRequest*)req->iNext;
+ if (req==anchor)
+ return;
+
+ // Remove and cancel it.
+ req->Deque();
+ iUnusedRequestQ.Add(req);
+ NKern::FMSignal(iMutexPtr); // Release the request list mutex while we complete the request. This is safe.
+ Kern::RequestComplete(iOwningThread,req->iStatus,KErrCancel);
+ NKern::FMWait(iMutexPtr); // Re-acquire the request list mutex.
+ }
+
+/**
+Remove each request status pointer from the the capture request queue, completing each with a 'KErrCancel' completion reason.
+@pre The buffer/request queue mutex must be held.
+*/
+void TCameraScRequestQueue::CancelAll()
+ {
+
+ TRequestStatus* status;
+ while ((status=Remove())!=NULL)
+ {
+ NKern::FMSignal(iMutexPtr); // Release the request list mutex while we complete the request. This is safe.
+ Kern::RequestComplete(iOwningThread,status,KErrCancel);
+ NKern::FMWait(iMutexPtr); // Re-acquire the request list mutex.
+ }
+ }
+
+/**
+Constructor for the camera driver power handler class.
+@param aChannel A pointer to the camera driver logical channel which owns this power handler.
+*/
+DCameraScPowerHandler::DCameraScPowerHandler(DCameraScLdd* aChannel)
+: DPowerHandler(KDevCameraScName),
+ iChannel(aChannel)
+ {
+ }
+
+/**
+A request from the power manager for the power down of the camera device.
+This is called during a transition of the phone into standby or power off.
+@param aState The target power state; can be EPwStandby or EPwOff only.
+*/
+void DCameraScPowerHandler::PowerDown(TPowerState aPowerState)
+ {
+ (void)aPowerState;
+ __KTRACE_CAM(Kern::Printf(">DCameraScPowerHandler::PowerDown(State-%d)",aPowerState));
+
+ // Power-down involves hardware access so queue a DFC to perform this from the driver thread.
+ iChannel->iPowerDownDfc.Enque();
+ }
+
+/**
+A request from the power manager for the power up of the camera device.
+This is called during a transition of the phone out of standby.
+*/
+void DCameraScPowerHandler::PowerUp()
+ {
+ __KTRACE_CAM(Kern::Printf(">DCameraScPowerHandler::PowerUp"));
+
+ // Power-up involves hardware access so queue a DFC to perform this from the driver thread.
+ iChannel->iPowerUpDfc.Enque();
+ }