bsptemplate/asspandvariant/template_variant/camerasc/camerasc.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 27 May 2010 14:17:14 +0300
changeset 139 95f71bcdcdb7
parent 31 56f325a607ea
child 258 880ff05ad710
permissions -rw-r--r--
Revision: 201021 Kit: 2010121

// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of 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:
// template\template_variant\camerasc\camerasc.cpp
// Implementation of the template shared chunk camera physical device driver (PDD).
// This file is part of the Template Base port
// 
//
#include "camerasc_plat.h"

_LIT(KCameraScPddName, "CameraSc.TE");
_LIT(KCameraScDfcQueueName, "CameraSc.TE.DfcQ");

/**
Standard export function for PDD factories.  This creates a DPhysicalDevice derived object, in this case,
DTemplateCameraScPddFactory.
*/
DECLARE_STANDARD_PDD()
	{
	return new DTemplateCameraScPddFactory;
	}

/**
Constructor for the shared chunk camera PDD factory class.
*/
DTemplateCameraScPddFactory::DTemplateCameraScPddFactory()
	{
	// We currently support only unit 0
	iUnitsMask = 0x01;

	// Set the version number for this device.  This is used to allow code to specify that it requires a
	// minimum version of the device in order to operate.  If the version requested is less than this then
	// the device is safe to be used
	iVersion = RDevCameraSc::VersionRequired();
	}

/**
Destructor for the shared chunk camera PDD factory class.
*/
DTemplateCameraScPddFactory::~DTemplateCameraScPddFactory()
	{
	}

/**
Second stage constructor for the shared chunk camera PDD factory class.  This must at least set a name for
the driver object.
@return KErrNone if successful, otherwise one of the system wide error codes.
*/
TInt DTemplateCameraScPddFactory::Install()
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPddFactory::Install()"));

	TInt r;

	// Create a DFC queue so that handling of both camera hardware callbacks and requests made to the LDD from
	// user mode can be processed in the same thread, to avoid the use of semaphores
	if ((r = Kern::DynamicDfcQCreate(iDfcQ, 26, KCameraScDfcQueueName)) == KErrNone)
		{
		// All PDD factories must have a unique name
		r = SetName(&KCameraScPddName);
		}

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPddFactory::Install() => Returning %d", r));

	return r;
	}

/**
Returns the PDD's capabilities.  This is not used by the Symbian OS device driver framework
or by the LDD but is here as some LDDs will make use of it.
@param aDes	A descriptor into which to write capability information.
*/
void DTemplateCameraScPddFactory::GetCaps(TDes8& /*aDes*/) const
	{
	}

/**
Called by the kernel's device driver framework to check if this PDD is suitable for use
with 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 aUnit	The unit argument supplied by the client to RBusLogicalChannel::DoCreate()
				This is used to determine which sensor to use.
@param aInfo	The info argument supplied by the client to RBusLogicalChannel::DoCreate().
@param aVer		The version number of the logical channel which will use this physical channel.
@return KErrNone if successful, otherwise one of the system wide error codes.
*/
TInt DTemplateCameraScPddFactory::Validate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& aVer)
	{
	// Check that the version requested is less than or equal to the version of this PDD
	if (!Kern::QueryVersionSupported(RDevCameraSc::VersionRequired(), aVer))
		{
		return KErrNotSupported;
		}

	// Check that the unit number specifies the available sensor
	if ((aUnit < 0) || (aUnit > 0))
		{
		return KErrNotSupported;
		}

	return KErrNone;
	}

/**
Called by the kernel's device driver framework to create a physical channel object.  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 physical channel object.
@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 number of the logical channel which will use this physical channel.
@return KErrNone if successful, otherwise one of the other system wide error codes.
*/
TInt DTemplateCameraScPddFactory::Create(DBase*& aChannel, TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/)
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPddFactory::Create()"));

	// Create an instance of the PDD channel object that will work with the Template sensor
	DTemplateCameraScPdd* pD = new DTemplateCameraScPdd;

	aChannel = pD;
	TInt r = KErrNoMemory;

	if (pD)
		{
		r = pD->DoCreate(this, aUnit);
		}

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPddFactory::Create() => Returning %d", r));

	return r;
	}

/**
Called by SetUnitOpen() to see if a particular unit is open.  When called, the
iUnitInfoMutex fast mutex will be taken, ensuring safe access to iUnitsOpenMask.
@param aUnit	The unit number to be checked for being open.
@return ETrue if the unit specified by aUnit is already open, otherwise EFalse.
*/
TBool DTemplateCameraScPddFactory::IsUnitOpen(TInt aUnit)
	{
	return (iUnitsOpenMask & (1 << aUnit));
	}

/**
Attempt to change the state of the unit open state for a particular unit.
@param aUnit	The unit number to be set to open or closed state.
@param aIsOpen	The required new state for the unit;  either ETrue to set the state
				to open or EFalse to set the state to closed.
@return KErrNone if the state was updated successfully, otherwise KErrInUse if an attempt
		was made to set the unit status to open while it is already open.
*/
TInt DTemplateCameraScPddFactory::SetUnitOpen(TInt aUnit, TBool aIsOpen)
	{
	// Wait until it is safe to access the unit state mask
	NKern::FMWait(&iUnitInfoMutex);

	// Fail a request to open a unit that is already open
	if (aIsOpen && IsUnitOpen(aUnit))
		{
		__KTRACE_CAM(Kern::Printf("+ DTemplateCameraScPddFactory::SetUnitOpen() => Unit %d is already in use", aUnit));

		// Release the unit state mask mutex
		NKern::FMSignal(&iUnitInfoMutex);

		return KErrInUse;
		}

	// Set or clear the unit's open status bit as required
	if (aIsOpen)
		{
		iUnitsOpenMask |= (1 << aUnit);
		}
	else
		{
		iUnitsOpenMask &= ~(1 << aUnit);
		}

	// Release the unit state mask mutex
	NKern::FMSignal(&iUnitInfoMutex);

	return KErrNone;
	}

/**
Constructor for the shared chunk camera PDD class.
*/
DTemplateCameraScPdd::DTemplateCameraScPdd()
	{
	// Set the unit number to -1 to indicate that this channel has never been registered
	// with the PDD factory
	iUnit = -1;

	// The channel has been created but not yet configured */
	iState = EUnconfigured;
	}

/**
Destructor for the shared chunk camera PDD class.  This is called in the context of the client thread
once an 'ECloseMsg' message has been sent to the device driver DFC thread.
*/
DTemplateCameraScPdd::~DTemplateCameraScPdd()
	{
	delete [] iCapsBuffer;
	delete iSensor;

	// Indicate that a physical channel is no longer open on this unit
	if (iUnit >= 0)
		{
		iPhysicalDevice->SetUnitOpen(iUnit, EFalse);
		}
	}

/**
Second stage constructor for the H4 camera PDD.
@param aPhysicalDevice	A pointer to the factory class that is creating this PDD
@param aUnit			The unit argument supplied by the client to RBusLogicalChannel::DoCreate().
@return KErrNone if successful, otherwise one of the other system wide error codes.
*/
TInt DTemplateCameraScPdd::DoCreate(DTemplateCameraScPddFactory* aPhysicalDevice, TInt aUnit)
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPdd::DoCreate()"));

	TInt r;

	iPhysicalDevice = aPhysicalDevice;

	// Check that a physical channel hasn't already been opened on this unit
	if ((r = iPhysicalDevice->SetUnitOpen(aUnit, ETrue)) == KErrNone)
		{
		iUnit = aUnit;

		// Create an abstracted sensor interface
		if ((iSensor = new DTemplateSensorIf(*this, DfcQ(aUnit))) != NULL)
			{
			if ((r = iSensor->DoCreate()) == KErrNone)
				{
				// Setup the capabilities of this device for later reference
				if ((r = iSensor->GetCaps(iCaps)) > 0)
					{
					// And save the size as returned from the sensor
					iCapsSize = r;

					// Although iCaps now points to a TCameraCapsV02 structure, it is actually a variable
					// sized structure that was allocated as an array of TUint8 so save it to a TUint8
					// ptr so that it can be deleted properly
					iCapsBuffer = (TUint8*) iCaps;

					// Enable the clocks needed by the camera subsystem and power up the sensor
					r = iSensor->RequestPower();

					// Some sensors power themselves up automatically in their DoCreate() function,
					// so take this into account here
					if (r == KErrAlreadyExists)
						{
						r = KErrNone;
						}
					}
				}
			}
		else
			{
			r = KErrNoMemory;
			}
		}

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPdd::DoCreate() => Returning %d", r));

	return r;
	}

/**
An appropriate DFC queue to use for processing client requests (that is, those that won't be processed
in the context of the client thread), and also for processing image completion requests from the sensor
will have been setup by the PDD factory.  Anything needing to run in this same DFC thread can access the
queue via this function.
@param	aUnit	The unit number for which to get the DFC queue.
@return	The DFC queue to be used.
*/
TDfcQue* DTemplateCameraScPdd::DfcQ(TInt /*aUnit*/)
	{
	return iPhysicalDevice->iDfcQ;
	}

/**
Called by the LDD in order to query the capabilities of the PDD.
@param	aCapsBuf	A reference to a descriptor owned by the LDD, containing a TCameraCapsV02 structure
					for the capabilities.
*/
void DTemplateCameraScPdd::Caps(TDes8& aCapsBuf) const
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPdd::Caps()"));

	// The iCaps structure will already have been created by a call to iSensor->SetCaps() in DoCreate().
	// Simply copy it into the supplied TPckgBuf, taking into account the fact that the TCameraCapsV02
	// buffer is of a variable size *and* may be smaller or larger than the iCaps structure
	TPtrC8 ptr((const TUint8*) iCaps, iCapsSize);
	aCapsBuf.FillZ(aCapsBuf.MaxLength());
	aCapsBuf = ptr.Left(Min(ptr.Length(), aCapsBuf.MaxLength()));

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPdd::Caps()"));
	}

/**
Called by the LDD to setup a new image configuration, including such things as image size, framerate
and pixel format.
@param	aConfigBuf	A reference to a TPckgBuf containing a TCameraConfigV02 configuration structure.
@return KErrNone if successful, otherwise one of the system wide error codes.
*/
TInt DTemplateCameraScPdd::SetConfig(const TDesC8& aConfigBuf)
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPdd::SetConfig()"));

	TInt r;

	// It is only legal to call this if image capture is not already underway, so check for this
	// before doing anything
	if (iState <= EConfigured)
		{
		// Read the new configuration from the LDD into a local copy of the configuration structure,
		// taking into account for compatibility that the TPckgBuf may be smaller or larger than the
		// TCameraConfigV02 structure
		TCameraConfigV02 config;
		TPtr8 ptr((TUint8*) &config, sizeof(config));
		Kern::InfoCopy(ptr, aConfigBuf);

		// Save the new configuration for later and let the sensor also know about it
		iConfig = config;
		iSensor->SetConfig(config);

		// Signal success and set the channel to the configured state
		r = KErrNone;
		iState = EConfigured;
		}
	else
		{
		r = KErrInUse;
		}

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPdd::SetConfig() => Returning %d", r));

	return r;
	}

/**
Begins capture into the address pointed to by aLinAddr and aPhysAddr.  Both of these addresses point to
the same buffer;  The address used by the sensor is hardware dependent.
@param	aCaptureMode	Whether to capture in video, viewfinder or single image mode.
@param	aLinAddr		The virtual address of the buffer into which to capture the image.
@param	aPhysAddr		The physical address of the buffer into which to capture the image.
@return	KErrNone if successful, otherwise one of the other system wide error codes.
@pre	SetConfig() must first have been called.
*/
TInt DTemplateCameraScPdd::Start(TDevCamCaptureMode aCaptureMode, TLinAddr aLinAddr, TPhysAddr aPhysAddr)
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPdd::Start() => Configuring sensor for %d x %d capture", iConfig.iFrameSize.iWidth, iConfig.iFrameSize.iHeight));

	// Ensure the precondition is met
	__ASSERT_DEBUG((iState == EConfigured), Kern::Fault("camerasc", ENotConfigured));

	// Save the capture mode for use when we call back into the LDD with the captured image
	iCaptureMode = aCaptureMode;

	// And start the sensor running
	TInt r = iSensor->Start(aCaptureMode, aLinAddr, aPhysAddr);

	// If everything was ok, set the channel to the capturing state
	if (r == KErrNone)
		{
		iState = ECapturing;
		}

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPdd::Start() => Returning %d", r));

	return r;
	}

/**
Sets the address of the buffer info which the next image will be captured.  Called by the LDD for successive
images that are requested after the initial call to Start().
@param	aLinAddr		The virtual address of the buffer into which to capture the image.
@param	aPhysAddr		The physical address of the buffer into which to capture the image.
@return	KErrNone if successful, otherwise one of the other system wide error codes.
*/
TInt DTemplateCameraScPdd::CaptureNextImage(TLinAddr aLinAddr, TPhysAddr aPhysAddr)
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPdd::CaptureNextImage()"));

	// Pass the call directly to the sensor abstraction
	TInt r = iSensor->CaptureNextImage(aLinAddr, aPhysAddr);

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPdd::CaptureNextImage()=> Returning %d", r));

	return(r);
	}

/**
Stops any image capturing that is currently underway.  It is safe to call this without having called Start().
@return	KErrNone if successful, otherwise one of the other system wide error codes.
*/
TInt DTemplateCameraScPdd::Stop()
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPdd::Stop()"));

	// Pass the call directly to the sensor abstraction
	iSensor->Stop();

	// Det the channel back to the configured state as it is now safe to call Start() again
	iState = EConfigured;

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPdd::Stop()"));

	return KErrNone;
	}

/**
Power down the camera device.  This is called by the LDD when the driver channel is being closed or
when the system is being powered down.  This is always called in the context of the DFC thread.
*/
void DTemplateCameraScPdd::PowerDown()
	{

#ifdef _DEBUG

	// Power off the camera
	TInt r = iSensor->RelinquishPower();

	// Not being able to power down indicates a serious programming error
	__ASSERT_DEBUG((r == KErrNone), Kern::Fault("camerasc", ECannotPowerDown));

#else // ! _DEBUG

	// Power off the camera
	iSensor->RelinquishPower();

#endif // ! _DEBUG

	}

/**
Return the shared chunk creation information to be used by this device.
@param	aChunkCreateInfo	A structure to be filled with the settings required for this device.
*/
void DTemplateCameraScPdd::GetChunkCreateInfo(TChunkCreateInfo& aChunkCreateInfo)
	{
	// Can be opened by any number of user side processes
	aChunkCreateInfo.iType = TChunkCreateInfo::ESharedKernelMultiple;
	// Use both L1 and L2 cache if available.  LDD will take care of pre and post DMA cache handling
#ifdef __WINS__
	aChunkCreateInfo.iMapAttr = 0xFF000;
#else
	aChunkCreateInfo.iMapAttr = EMapAttrCachedMax;
#endif
	// Chunk owns the memory which will be freed when the chunk is destroyed
	aChunkCreateInfo.iOwnsMemory = ETrue;
	// Don't queue the chunk's destruction on an DFC
	aChunkCreateInfo.iDestroyedDfc = NULL;
	}

/**
Returns the size of the variable sized capabilities structure in bytes.  The buffer passed into
DTemplateCameraScPdd::GetCaps() must be at least this large to hold the fixed portion of the TCameraCapsV02
structure, as well as the array of SDevCamPixelFormat structures that follows it.
@return	The size in bytes of the variable sized capabilities structure.
*/
TInt DTemplateCameraScPdd::CapsSize()
	{
	return iCapsSize;
	}

/**
Obtains information regarding the frame sizes and frame rates supported for a given combination of capture mode
and pixel format.
@param	aCaptureMode		The capture mode for which to obtain the information.
@param	aUidPixelFormat		The pixel format for which to obtain the information.
@param	aFrameSizeCapsBuf	A reference to an array of packaged SDevCamFrameSize structures, owned by the LDD, into
							which to place the information.
@@return	KErrNone if successful, else one of the other system wide error codes.
*/
TInt DTemplateCameraScPdd::FrameSizeCaps(TDevCamCaptureMode aCaptureMode, TUidPixelFormat aUidPixelFormat, TDes8& aFrameSizeCapsBuf)
	{
	return iSensor->FrameSizeCaps(aCaptureMode, aUidPixelFormat, aFrameSizeCapsBuf);
	}

/**
Called by the sensor abstraction when an image is available.
@param	aResult	KErrNone if successful, otherwise one of the system wide error codes.
@param	aLinAddr		The virtual address of the buffer into which to capture the image.
@param	aPhysAddr		The physical address of the buffer into which to capture the image.
*/
TInt DTemplateCameraScPdd::NotifyImageCaptureEvent(TInt aResult, TLinAddr& aLinAddr, TPhysAddr& aPhysAddr)
	{
	__KTRACE_CAM(Kern::Printf("> DTemplateCameraScPdd::NotifyImageCaptureEvent() => aResult = %d", aResult));

	// Inform the LDD that a new image has been received
	TInt r = iLdd->ImageCaptureCallback(iCaptureMode, aResult, &aLinAddr, &aPhysAddr);

	// If the LDD has returned KErrAbort then something has gone wrong, and if it has returned KErrNotReady
	// then it has no more frames available, so call Stop()
	if (r != KErrNone)
		{
		Stop();
		}

	__KTRACE_CAM(Kern::Printf("< DTemplateCameraScPdd::NotifyImageCaptureEvent() => Returning %d", r));

	return r;
	}

TInt DTemplateCameraScPdd::SetBrightness(TUint /*aBrightness*/)
	{
	return KErrNone;
	}

TInt DTemplateCameraScPdd::SetContrast(TUint /*aContrast*/)
	{
	return KErrNone;
	}

TInt DTemplateCameraScPdd::SetColorEffect(TUint /*aColorEffect*/)
	{
	return KErrNone;
	}