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;
}