baseport/syborg/webcamera/webcamera_ldd.cpp
author Shimizu Satoshi <s_shimizu@isb.co.jp>
Mon, 18 Oct 2010 19:39:25 +0900
changeset 124 606eafc6d6a8
parent 52 0dfaca43d90e
permissions -rw-r--r--
Obtain an image of Webcamera from QEMU and add the Bitmap change display function.

/*
* Copyright (c) 2010 ISB.
* 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:
* ISB - initial contribution.
*
* Contributors:
*
* Description: USB driver for test
*
*/

#include <kern_priv.h>
#include "webcamera_ldd.h"

#define DP(format...) Kern::Printf(format)

_LIT(KDriver1PanicCategory,"WebcameraDevice");

/**
Create Logic device.
 */
DECLARE_STANDARD_LDD()
	{
	DP("DECLARE_STANDARD_LDD()");
	return new DWebcameraLogicalDevice;
	}

/**
Constructor
*/
DWebcameraLogicalDevice::DWebcameraLogicalDevice()
	{
	DP("DWebcameraLogicalDevice()");
	// Set version number for this device
	iVersion = RWebcameraDevice::VersionRequired();
	// Indicate that we work with a PDD
	iParseMask = KDeviceAllowPhysicalDevice;
	}

/**
Destructor
*/
DWebcameraLogicalDevice::~DWebcameraLogicalDevice()
	{
	}

/**
Second stage constructor for DDriver1Factory.
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 DWebcameraLogicalDevice::Install()
	{
	DP("DWebcameraLogicalDevice::Install()");

	return SetName(&RWebcameraDevice::Name());
	}

/**
Return the drivers capabilities.
Called in the response to an RDevice::GetCaps() request.

@param aDes User-side descriptor to write capabilities information into
*/
void DWebcameraLogicalDevice::GetCaps(TDes8& aDes) const
	{
	// Create a capabilities object
	RWebcameraDevice::TCaps caps;
	caps.iVersion = iVersion;
	// Write it back to user memory
	Kern::InfoCopy(aDes, (TUint8*)&caps, sizeof(caps));
	}

/**
Called by the kernel's device driver framework to create a Logical Channel.
This is called in the context of the user thread (client) which requested the creation of a Logical Channel
(E.g. through a call to RBusLogicalChannel::DoCreate)
The thread is in a critical section.

@param aChannel Set to point to the created Logical Channel
@return KErrNone if successful, otherwise one of the other system wide error codes.
*/
TInt DWebcameraLogicalDevice::Create(DLogicalChannelBase*& aChannel)
	{
	DP("DWebcameraLogicalDevice::Create() start");
	aChannel = new DWebcameraLogicalChannel;
	if (!aChannel)
		{
		return KErrNoMemory;
		}
	DP("DWebcameraLogicalDevice::Create() end");
	return KErrNone;
	}

/**
Constructor
*/
DWebcameraLogicalChannel::DWebcameraLogicalChannel()
	: iReceiveDataDfc(GetFlameDfc, this, 1)
	, iCaptureDfc(CaptureDfc, this, 1)
	{
	DP("DWebcameraLogicalChannel::DWebcameraLogicalChannel() start");

	// Get pointer to client threads DThread object
	iClient = &Kern::CurrentThread();
	// Open a reference on client thread so it's control block can't dissapear until
	// this driver has finished with it.
	((DObject*)iClient)->Open();
	iWebCameraState = RWebcameraDevice::EPowerOff;

	DP("DWebcameraLogicalChannel::DWebcameraLogicalChannel() end");
	}

/**
Destructor
*/
DWebcameraLogicalChannel::~DWebcameraLogicalChannel()
	{
	DP("DWebcameraLogicalChannel::~DWebcameraLogicalChannel() start");
	// Cancel all processing that we may be doing
	DoCancel(RWebcameraDevice::EAllRequests);
	// Close sharedchunks
	CloseSharedChunks();
	// Close our reference on the client thread
	Kern::SafeClose((DObject*&)iClient, NULL);

	delete iConvert;

	// Buffer Free.
	Kern::Free(iHeaderPtr);
	Kern::Free(iDataPtr);
	Kern::Free(iBmpBuf);
	DP("DWebcameraLogicalChannel::~DWebcameraLogicalChannel() end");
	}

/**
Called when a user thread requests a handle to this channel.
*/
TInt DWebcameraLogicalChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
	{
	// Make sure that only our client can get a handle
	if (aType != EOwnerThread || aThread != iClient)
		{
		return KErrAccessDenied;
		}
	return KErrNone;
	}

/**
Second stage constructor called by the kernel's device driver framework.
This is called in the context of the user thread (client) which requested the creation of a Logical Channel
(E.g. through a call to RBusLogicalChannel::DoCreate)
The thread is in a critical section.

@param aUnit The unit argument supplied by the client
@param aInfo The info argument supplied by the client
@param aVer The version argument supplied by the client

@return KErrNone if successful, otherwise one of the other system wide error codes.
*/
TInt DWebcameraLogicalChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
	{
	DP("DWebcameraLogicalChannel::DoCreate() start");
	if (!Kern::CurrentThreadHasCapability(ECapability_None, __PLATSEC_DIAGNOSTIC_STRING("Checked by Webcamera")))
		{
		return KErrPermissionDenied;
		}
	// Check version
	if (!Kern::QueryVersionSupported(RWebcameraDevice::VersionRequired(), aVer))
		{
		return KErrNotSupported;
		}
	// Setup LDD for receiving client messages
	SetDfcQ(Kern::DfcQue0());
	iMsgQ.Receive();
	//Associate DFCs with the same queue we set above to receive client messages on
	iReceiveDataDfc.SetDfcQ(iDfcQ);
	iCaptureDfc.SetDfcQ(iDfcQ);
	//Give PDD a pointer to this channel
	Pdd()->iLdd = this;	
	// Create shared chunk.
	TInt rtn = CreatSharedChunks();
	if (rtn)
		{
		return rtn;
		}

	DP("DWebcameraLogicalChannel::DoCreate() end");
	return KErrNone;
	}

/**
Process a message for this logical channel.
This function is called in the context of a DFC thread.

@param aMessage	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 DWebcameraLogicalChannel::HandleMsg(TMessageBase* aMsg)
	{
	DP("DWebcameraLogicalChannel::HandleMsg() start");
	TThreadMessage& m = *(TThreadMessage*)aMsg;

	// Get message type
	TInt id = m.iValue;
	DP("id=%d",id);

	// Decode the message type and dispatch it to the relevent handler function...
	if (id == (TInt)ECloseMsg)
		{
		DoCancel(RWebcameraDevice::EAllRequests);
		m.Complete(KErrNone, EFalse);
		return;
		}

	if (m.Client() != iClient)
		{
		Kern::ThreadKill(m.Client(),
						 EExitPanic,
						 ERequestFromWrongThread,
						 KDriver1PanicCategory);
		m.Complete(KErrNone, ETrue);
		return;
		}

	if (id == KMaxTInt)
		{
		DoCancel(m.Int0());
		m.Complete(KErrNone, ETrue);
		return;
		}

	if (id < 0)
		{
		// DoRequest
		TRequestStatus* pS = (TRequestStatus*)m.Ptr0();
		TInt rtn = DoRequest(~id, pS, m.Ptr1(), aMsg);

		if (rtn != KErrNone)
			{
			Kern::RequestComplete(iClient, pS, rtn);
			}
		m.Complete(KErrNone, ETrue);
		}
	else
		{
		// DoControl
		TInt rtn = DoControl(id, m.Ptr0(), aMsg);
		m.Complete(rtn, ETrue);
		}
	DP("DWebcameraLogicalChannel::HandleMsg() end");
	}

/**
Process synchronous 'control' requests
*/
TInt DWebcameraLogicalChannel::DoControl(TInt aFunction, TAny* a1, TAny* /*a2*/)
	{
	DP("DWebcameraLogicalChannel::DoControl() start");
	TInt rtn;
	rtn = KErrNone;

	switch (aFunction)
		{
		case RWebcameraDevice::EGetConfig:
//			rtn = GetConfig((TDes8*)a1);
			rtn = KErrNone;
			break;
        case RWebcameraDevice::ESetConfig:
//			rtn = SetConfig((const TDesC8*)a1);
			break;
		case RWebcameraDevice::EOpenSharedChunck:
			rtn=OpenSharedChunks((RWebcameraDevice::TChunkInfo*)a1);
			break;
		case RWebcameraDevice::EInitViewFinder:
			rtn = Pdd()->InitViewFinder();
			iDataPtr = Kern::Alloc(BUFSIZE);
			iBmpBuf = (TUint8*)Kern::Alloc(BITMAPBUFSIZE);
			break;
		default:
			rtn = KErrNotSupported;
			break;
		}
	DP("DWebcameraLogicalChannel::DoControl() end");
	return rtn;
	}

/**
Process asynchronous requests.
*/
TInt DWebcameraLogicalChannel::DoRequest(TInt aReqNo,
											TRequestStatus* aStatus,
											TAny* a1,
											TAny* /*a2*/)
	{
	TInt rtn;
	iRequesting = ETrue;
	rtn = KErrNone;

	switch (aReqNo)
		{
		case RWebcameraDevice::EStart:
			iReceiveDataStatus = aStatus;
			iReceiving = ETrue;
			iWebCameraState = RWebcameraDevice::EStart;
			iReceiveDataDfc.Add();
			// Example Platform Security capability check which tests the
			// client for ECapability_None (which always passes)...
			if (iRequesting == EFalse)
				{
				iReceiving = EFalse;
				Kern::RequestComplete(iClient,
									  iReceiveDataStatus,
									  iReceiveDataResult);
				}
			else
				{
				iReceiveDataDescriptor = (TInt*)a1;
				}
			break;
		case RWebcameraDevice::ECapture:
			iCaptureStatus = aStatus;
			iWebCameraState = RWebcameraDevice::ECapture;
			iCaptureDfc.Add();
			if (iRequesting == EFalse)
				{
				Kern::RequestComplete(iClient, iCaptureStatus, iCaptureResult);
				}
			else
				{
		        iCaptureDescriptor=(TInt*)a1;
				}
			break;
		case RWebcameraDevice::EPowerOn:
			if (iPowerOn == EFalse)
				{
				iPowerOn = ETrue;
				iWebCameraState = RWebcameraDevice::EPowerOn;
				iHeaderPtr = Kern::Alloc(sizeof(TWebcameraUVC));
				rtn = Pdd()->PowerOn(iHeaderPtr);
				Kern::RequestComplete(iClient, aStatus, rtn);
				}
			else
				{
				Kern::RequestComplete(iClient, aStatus, KErrAlreadyExists);
				}
			break;
		case RWebcameraDevice::EPowerOff:
			Pdd()->Disconnect();
			iPowerOn = EFalse;
			iReceiving = EFalse;
			iReceiveDataDfc.Cancel();
			iCaptureDfc.Cancel();
			iWebCameraState = RWebcameraDevice::EPowerOff;
			Kern::RequestComplete(iClient, aStatus, rtn);
			break;
		default:
			rtn = KErrNotSupported;
			Kern::RequestComplete(iClient, aStatus, rtn);
			break;
		}
	iRequesting = EFalse;
	return rtn;
	}

/**
Process cancelling of asynchronous requests.
*/
void DWebcameraLogicalChannel::DoCancel(TUint aMask)
	{
	DP("DWebcameraLogicalChannel::DoCancel() start");
	DP("aMask=%d",aMask);
	if (aMask & (1 << RWebcameraDevice::EStart))
		{
		DP("RWebcameraDevice::EStart=%d",RWebcameraDevice::EStart);
		if (iReceiveDataStatus)
			{
			DP("iReceiveDataStatus=%d",iReceiveDataStatus);
			Pdd()->Stop(DWebcameraDriverBase::USB_cancel);
			iReceiving = EFalse;
			iReceiveDataDfc.Cancel();
			Kern::RequestComplete(iClient, iReceiveDataStatus, KErrCancel);
			}
		}
	if (aMask&(1<<RWebcameraDevice::ECapture))
		{
		DP("RWebcameraDevice::ECapture=%d",RWebcameraDevice::ECapture);
		if (iCaptureStatus)
			{
			iCaptureDfc.Cancel();
			Kern::RequestComplete(iClient, iCaptureStatus, KErrCancel);
			}
		}
	DP("DWebcameraLogicalChannel::DoCancel() end");
	}

/**
Called by PDD from ISR to indicate that a ReceiveData operation has completed.
*/
void DWebcameraLogicalChannel::GetOneFlameComplete(TInt aDataSize)
	{
	iSaveSize = iSize - aDataSize;
	// Queue DFC
	iWebCameraState = RWebcameraDevice::ETransferData;
	iReceiveDataDfc.Add();
	//set size of received data
	if (iSaveSize > 0)
		{
		iReceiveDataResult = KErrNone;
		}
	else
		{
		iReceiveDataResult = KErrUnknown; //TODO:define of error
		}
	}

void DWebcameraLogicalChannel::DoStartViewFinder()
	{
	TInt rtn = Pdd()->StartViewerFinder(iDataPtr, BUFSIZE);
	if (rtn != KErrNone)
		{
		DP("rtn=%d",rtn);
		iReceiving = EFalse;
		Kern::RequestComplete(iClient, iReceiveDataStatus, rtn);
		}
	}
/**
DFC Callback which gets triggered after the PDD has signalled that getting oneflame completed.
This just casts aPtr and calls DoGetOneFlameComplete().
*/
void DWebcameraLogicalChannel::GetFlameDfc(TAny* aPtr)
	{
	switch (((DWebcameraLogicalChannel*)aPtr)->iWebCameraState)
		{
	case RWebcameraDevice::EStart:
		((DWebcameraLogicalChannel*)aPtr)->DoStartViewFinder();
		break;
	case RWebcameraDevice::ETransferData:
		((DWebcameraLogicalChannel*)aPtr)->DoGetOneFlameComplete();
		break;
	default:
		break;
		}
	}
/**
DFC Callback
gets Capture image completed.
This just casts aPtr and calls DoCaptureComplete().
*/
void DWebcameraLogicalChannel::CaptureDfc(TAny* aPtr)
	{
	DP("DWebcameraLogicalChannel::CaptureDfc() start");
	((DWebcameraLogicalChannel*)aPtr)->DoCaptureComplete();
	DP("DWebcameraLogicalChannel::CaptureDfc() end");
	}

/**
Called from a DFC after the PDD has signalled that getting oneflame completed.
*/
void DWebcameraLogicalChannel::DoGetOneFlameComplete()
	{
	if (!iConvert)
		{
		iConvert = new DWebCameraConvert((TWebcameraUVC*)iHeaderPtr);
		}

	iConvert->ConvertData((TUint8*)iDataPtr, iBmpBuf);
	kumemget((TAny*)(iChunkLinAddr), iBmpBuf, iSaveSize);

	TInt result = Kern::ThreadRawWrite(iClient, iReceiveDataDescriptor, &iSaveSize,sizeof(TInt), 0);

	// Finished with client descriptor, so NULL it to help detect coding errors
	iReceiveDataDescriptor = NULL;

	// Use result code from PDD if it was an error
	if(iReceiveDataResult != KErrNone)
		{
		result = iReceiveDataResult;
		}
	// Complete clients request
	Kern::RequestComplete(iClient, iReceiveDataStatus, result);
	}

/**
Called from a DFC after the PDD has signalled that getting Capture image completed.
*/
void DWebcameraLogicalChannel::DoCaptureComplete()
	{
	DP("DWebcameraLogicalChannel::DoCaptureComplete() start");

	TInt result = Kern::ThreadRawWrite(iClient, iCaptureDescriptor, &iSaveSize, sizeof(TInt), 0);

	// Finished with client descriptor, so NULL it to help detect coding errors
	iCaptureDescriptor = NULL;

	// Use result code from PDD if it was an error
	if(iCaptureResult != KErrNone)
		{
		result = iCaptureResult;
		}
	// Complete clients request
	Kern::RequestComplete(iClient, iCaptureStatus, result);
	DP("DWebcameraLogicalChannel::DoCaptureComplete() end");
	}

/**
Process a GetConfig control message. This writes the current driver configuration to a
RWebcameraDevice::TConfigBuf supplied by the client.
*/
TInt DWebcameraLogicalChannel::GetConfig(TDes8* aConfigBuf)
	{
	//unsupported
	return KErrNotSupported;
	}

/**
Process a SetConfig control message. This sets the driver configuration using a
RWebcameraDevice::TConfigBuf supplied by the client.
*/
TInt DWebcameraLogicalChannel::SetConfig(const TDesC8* aConfigBuf)
	{
	//unsupported
	return KErrNotSupported;
	}

/**
Fill a TConfig with the drivers current configuration.
*/
/*void DWebcameraLogicalChannel::CurrentConfig(RWebcameraDevice::TConfig& aConfig)
	{
	//unsupported
	}
*/

TInt DWebcameraLogicalChannel::CreatSharedChunks()
	{
	DP("DWebcameraLogicalChannel::CreatSharedChunks() start");

	iChunk=NULL;

	NKern::ThreadEnterCS();

	iSize = Kern::RoundToPageSize(BITMAPBUFSIZE);

	TChunkCreateInfo info;
	info.iType			= TChunkCreateInfo::ESharedKernelMultiple;
	info.iMaxSize		= iSize;
	info.iMapAttr		= EMapAttrFullyBlocking;
	info.iOwnsMemory	= ETrue;
	info.iDestroyedDfc	= NULL;
	TInt r = Kern::ChunkCreate(info, iChunk, iChunkLinAddr, iChunkMappingAttr);
	if (r != KErrNone)
		{
		NKern::ThreadLeaveCS();
		return r;
		}
	iPhysAddr = 0x0;
	r = Kern::ChunkCommitContiguous(iChunk, 0, iSize, iPhysAddr);

	if (r != KErrNone)
		{
		Kern::ChunkClose(iChunk);
		NKern::ThreadLeaveCS();
		return r;
		}
	NKern::ThreadLeaveCS();

	DP("DWebcameraLogicalChannel::CreatSharedChunks() end");
	return KErrNone;
	}

TInt DWebcameraLogicalChannel::OpenSharedChunks(RWebcameraDevice::TChunkInfo* aChunkInfo)
	{
	DP("DWebcameraLogicalChannel::OpenSharedChunks() start");
	RWebcameraDevice::TChunkInfo chunkInfo;
	NKern::ThreadEnterCS();
	// Make handle to chunifo for current thread
	TInt r = Kern::MakeHandleAndOpen(iClient, iChunk);
	if (r >= 0) 
		{
		chunkInfo.iChunkHandle = r;
		r = KErrNone;
		}

	NKern::ThreadLeaveCS();

	if (r != KErrNone)
		{
		memclr(&chunkInfo,sizeof(chunkInfo));
		}
	TInt result = Kern::ThreadRawWrite(iClient, aChunkInfo, &chunkInfo, sizeof(chunkInfo), 0);

	DP("DWebcameraLogicalChannel::OpenSharedChunks() end");
	return r;
	}

void DWebcameraLogicalChannel::ChunkDestroyed()
	{
	DP("DWebcameraLogicalChannel::ChunkDestroyed() start");
	//unsupported
	DP("DWebcameraLogicalChannel::ChunkDestroyed() end");
	}

void DWebcameraLogicalChannel::CloseSharedChunks()
	{
	DP("DWebcameraLogicalChannel::CloseSharedChunks() start");
	if (iChunk)
		{
		Kern::ChunkClose(iChunk);
		}
	DP("DWebcameraLogicalChannel::CloseSharedChunks() end");
	}

/**
Get the point to Physical channel.
 */
DWebcameraDriverBase* DWebcameraLogicalChannel::Pdd()
	{
	DP("DWebcameraLogicalChannel::Pdd() start");
	return (DWebcameraDriverBase*)iPdd;
	}