baseport/syborg/webcamera/webcamera_ldd.cpp
author Masaki Hosaka <hosaka@isb.co.jp>
Wed, 24 Mar 2010 13:46:59 +0900
changeset 52 0dfaca43d90e
permissions -rw-r--r--
Added web camera drivers and QEMU plug-in for obtaining and transferring dummy data.

/*
* 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"
#include <webcamera_driver.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;
	return KErrNone;
	DP("DWebcameraLogicalDevice::Create() end");
	}

/**
  Constructor
*/
DWebcameraLogicalChannel::DWebcameraLogicalChannel()
	: iReceiveDataDfc(GetOneFlameDfc, 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();
	
	DP("DWebcameraLogicalChannel::DWebcameraLogicalChannel() end");
	}

/**
  Destructor
*/
DWebcameraLogicalChannel::~DWebcameraLogicalChannel()
	{
	DP("DWebcameraLogicalChannel::~DWebcameraLogicalChannel() start");
    // Cancel all processing that we may be doing
	DoCancel(RWebcameraDevice::EAllRequests);	
	if (iComm)
		{
		delete iComm;
		}
    if (iChunk)
        {
        Epoc::FreePhysicalRam(iPhysAddr, iSize);
        }
    // Close our reference on the client thread
	Kern::SafeClose((DObject*&)iClient,NULL);
	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;

	//allocate Memory
	iSize=Kern::RoundToPageSize(BUFSIZE);
	TInt rtn=Epoc::AllocPhysicalRam(iSize, iPhysAddr);
	if (rtn != KErrNone)
		{
		return rtn;
		}
	rtn=DPlatChunkHw::New(iChunk, iPhysAddr, iSize,EMapAttrUserRw|EMapAttrBufferedC);
	if (rtn != KErrNone)
		{
		if (iPhysAddr)
			{
			Epoc::FreePhysicalRam(iPhysAddr, iSize);
			}
		return rtn;
		}
	iLAdr = reinterpret_cast<TUint8*>(iChunk->LinearAddress());
	
	iComm=HBuf8::New(BUFSIZE);
	if (!iComm)
		{
		return KErrNotSupported;
		}
	iReceiveDataBuffer=iComm;
	iCaptureBuffer=iComm;

	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;
	TThreadMessage& m=*(TThreadMessage*)a2;
	TRequestStatus* pS=(TRequestStatus*)m.Ptr0();

	switch (aFunction)
		{
		case RWebcameraDevice::EGetConfig:
//			rtn = GetConfig((TDes8*)a1);
			rtn = KErrNone;
			if ( rtn != KErrNone )
				{
				Kern::RequestComplete(iClient,pS,rtn);
				}
			break;
        case RWebcameraDevice::ESetConfig:
 //       	rtn = SetConfig((const TDesC8*)a1);
            break;
            
		default:
			rtn = KErrNotSupported;
			Kern::RequestComplete(iClient,pS,rtn);
			break;
		}
	DP("DWebcameraLogicalChannel::DoControl() end");
	return rtn;

	}

/**
  Process asynchronous requests.
*/
TInt DWebcameraLogicalChannel::DoRequest(TInt aReqNo,
											TRequestStatus* aStatus,
											TAny* a1,
											TAny* a2)
	{
	DP("DWebcameraLogicalChannel::DoRequest() start");
	TInt rtn;
	TThreadMessage& m=*(TThreadMessage*)a2;

	iRequesting =ETrue;
	rtn = KErrNone;
    DP("aReqNo=%d",aReqNo);
	switch(aReqNo)
		{
		case RWebcameraDevice::EStart:
   			DP("EStart=%d",RWebcameraDevice::EStart);
			iReceiveDataStatus = aStatus;
			iReceiving = ETrue ;
			iReceiveDataBuffer->FillZ(iCaptureBuffer->MaxLength());
			iReceiveDataBuffer->Zero();
			DP("iReceiveDataBuffer Len=%d",iReceiveDataBuffer->MaxLength());
			DP("iReceiveDataBuffer Len=%d",iReceiveDataBuffer->Length());
			rtn = Pdd()->StartViewerFinder(iPhysAddr,iSize);
			if ( rtn != KErrNone ) 
				{
	   			DP("rtn=%d",rtn);
				iReceiving = EFalse ;
				Kern::RequestComplete(iClient,aStatus,rtn);
				}
			else
				{
	   			DP("rtn=%d",rtn);
				// Example Platform Security capability check which tests the
				// client for ECapability_None (which always passes)...
				if ( iRequesting == EFalse )
					{
		   			DP("iRequesting=EFalse");
					iReceiving = EFalse ;
					Kern::RequestComplete(iClient,
										  iReceiveDataStatus,
										  iReceiveDataResult);
					}
				else
					{
					DP("iRequesting=ETrue");
					iReceiveDataDescriptor=(TDes8*)a1;
					}
				}
			break;
		case RWebcameraDevice::ECapture:
			iCaptureing = ETrue ;
			iCaptureStatus = aStatus;
			iCaptureBuffer->FillZ(iCaptureBuffer->MaxLength());
			iCaptureBuffer->Zero();
		    DP("iCaptureBuffer Len=%d",iCaptureBuffer->MaxLength());
		    DP("iCaptureBuffer Len=%d",iCaptureBuffer->Length());
			rtn = Pdd()->StartCapture(iPhysAddr,iSize);
			DP("rtn=%d",rtn);
			if ( rtn != KErrNone ) 
				{
				iCaptureing = EFalse ;
				Kern::RequestComplete(iClient,aStatus,rtn);
				}
			else
				{
				if ( iRequesting == EFalse )
					{
				    DP("iRequesting=EFalse");
					iReceiving = EFalse ;
					Kern::RequestComplete(iClient,iCaptureStatus,iCaptureResult);
					}
				else
					{
			        DP("Capture iRequesting=ETrue");
				    iCaptureDescriptor=(TDes8*)a1;
					}
				}
			break;
		default:
			rtn=KErrNotSupported;
			Kern::RequestComplete(iClient,aStatus,rtn);
			break;
		}
	iRequesting = EFalse;

	DP("DWebcameraLogicalChannel::DoRequest() end");
	return rtn;

	}

/**
  Process cancelling of asynchronous requests.
*/
void DWebcameraLogicalChannel::DoCancel(TUint aMask)
	{
	DP("DWebcameraLogicalChannel::DoCancel() start");
	TInt rtn;
	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)
			{
			Pdd()->Stop(DWebcameraDriverBase::USB_cancel);
			iReceiving = EFalse ;
			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)
    {
	DP("DWebcameraLogicalChannel::GetOneFlameComplete() start");
	DP("datasize=%d",aDataSize);
	iSaveSize=iSize - aDataSize;
    // Queue DFC
    iReceiveDataDfc.Add();
    //set size of received data
    if (iSaveSize > 0)
    	{
	    iReceiveDataResult = KErrNone;
    	}
    else
    	{
		iReceiveDataResult = KErrUnknown;//TODO:define of error
    	}
	DP("DWebcameraLogicalChannel::GetOneFlameComplete() end");
    }

/**
  Called by PDD from ISR to indicate that a get capture image operation has completed.
*/
void DWebcameraLogicalChannel::CaptureComplete(TInt aDataSize)
    {
	DP("DWebcameraLogicalChannel::CaptureComplete() start");
	DP("datasize=%d",aDataSize);
	iSaveSize=iSize - aDataSize;
    // Queue DFC
	iCaptureDfc.Add();
    //set size of received data
    if (iSaveSize > 0)
    	{
		iCaptureResult = KErrNone;
    	}
    else
    	{
        iCaptureResult = KErrUnknown;//TODO:define of error
    	}
	DP("DWebcameraLogicalChannel::CaptureComplete() end");
    }

/**
  DFC Callback which gets triggered after the PDD has signalled that getting oneflame completed.
  This just casts aPtr and calls DoGetOneFlameComplete().
*/
void DWebcameraLogicalChannel::GetOneFlameDfc(TAny* aPtr)
    {
	DP("DWebcameraLogicalChannel::GetOneFlameDfc() start");
    ((DWebcameraLogicalChannel*)aPtr)->DoGetOneFlameComplete();
	DP("DWebcameraLogicalChannel::GetOneFlameDfc() end");
    }

/**
  DFC Callback which gets triggered after the PDD has signalled that getting 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()
    {
	DP("DWebcameraLogicalChannel::DoGetOneFlameComplete() start");
	iReceiveDataBuffer->Copy(iLAdr,iSaveSize);
    DP("iReceiveDataBuffer Len=%d",iReceiveDataBuffer->Length());
	// Write data to client from our buffer
    TInt result=Kern::ThreadDesWrite(iClient,iReceiveDataDescriptor,*iReceiveDataBuffer,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);
	DP("DWebcameraLogicalChannel::DoGetOneFlameComplete() end");
    }

/**
  Called from a DFC after the PDD has signalled that getting Capture image completed.
*/
void DWebcameraLogicalChannel::DoCaptureComplete()
    {
	DP("DWebcameraLogicalChannel::DoCaptureComplete() start");
	iCaptureBuffer->Copy(iLAdr,iSaveSize);
    DP("iCaptureBuffer Len=%d",iCaptureBuffer->Length());
	// Write data to client from our buffer
   TInt result=Kern::ThreadDesWrite(iClient,iCaptureDescriptor,*iCaptureBuffer,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
    }

/**
  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
    }

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

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