diff -r 000000000000 -r dfb7c4ff071f commsfwutils/commsbufs/reference/loopback_driver/pdd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwutils/commsbufs/reference/loopback_driver/pdd.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,387 @@ +// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// + +#include + +#ifdef SYMBIAN_OLD_EXPORT_LOCATION +#include +#else +//this header is not exported, needs to be a user include +#include "legacy_loopback_driver.h" +#endif + +#include "device.h" + +// Name for PDD, must match LDD name with a '.' and distinguishing name appended +_LIT(KLegacyLoopbackPddName,"legacy_loopback.pdd"); + + +typedef TBuf8 TMTUBuffer; + +class TQueue + { +public: + TMTUBuffer* HeadBuffer() {return &iQueue[iQueueHead];} + TMTUBuffer* TailBuffer() {return &iQueue[iQueueTail];} + + TBool IsEmpty() const {return iLength == 0;} + TBool IsFull() const {return iLength == KLoopbackQueueLen;} + TInt MaxLength() const {return KLoopbackQueueLen;} + TInt Length() const {return iLength;} + + void Pop() + { + __ASSERT_ALWAYS(iLength > 0, Kern::Fault("comms loopback", KErrOverflow)); + iQueueHead++; + if(iQueueHead == KLoopbackQueueLen) + { + iQueueHead = 0; + } + iLength--; + } + + void Push() + { + __ASSERT_ALWAYS(iLength < KLoopbackQueueLen, Kern::Fault("comms loopback", KErrOverflow)); + iQueueTail++; + if(iQueueTail == KLoopbackQueueLen) + { + iQueueTail = 0; + } + iLength++; + } + + TQueue() : iQueueHead(0), iQueueTail(0), iLength(0) {} + +private: + TMTUBuffer iQueue[KLoopbackQueueLen]; + TInt iQueueHead; + TInt iQueueTail; + TInt iLength; + }; + + +class DESockLoopbackDevice : public DESockLoopback + { +public: + DESockLoopbackDevice(DESockLoopbackPddFactory* aFactory); + ~DESockLoopbackDevice(); + TInt DoCreate(); + // Inherited from DESockLoopback. These called by the LDD. + virtual TInt BufferSize() const; + virtual TInt Speed() const; + virtual TInt SetSpeed(TInt aSpeed); + virtual TInt RequestDataSend(); + virtual void SendDataCancel(); + virtual TInt RequestDataReceipt(); + virtual void ReceiveDataCancel(); + virtual TDes8& SendBuffer(); + virtual TDesC8& ReceiveBuffer(); + virtual TBool ReceivedQueueLen(); + virtual void AdvanceReceiveQueue(); + +private: + void SendDataCallback(); + void ReceiveDataCallback(); + + static void DataRecvCallback(TAny* aSelf); + void DoDataRecvCallback(); +private: + DESockLoopbackPddFactory* iFactory; + TInt iSpeed; + + TQueue iSendQueue; + TQueue iReceiveQueue; + + TBool iPendingRead; + TDfc iRecvDataDfc; + }; + + + +const TInt KESockLoopbackThreadPriority = 27; +_LIT(KESockLoopbackThread,"ESockLoopbackThread"); + +/** + Standard export function for PDDs. This creates a DPhysicalDevice derived object, + in this case, our DESockLoopbackPddFactory +*/ +DECLARE_STANDARD_PDD() + { + return new DESockLoopbackPddFactory; + } + +DESockLoopbackPddFactory::DESockLoopbackPddFactory() + { + // Set version number for this device + iVersion=RLegacyLoopbackDriver::VersionRequired(); + } + +/** + Second stage constructor for DPhysicalDevice derived objects. + This must at least set a name for the driver object. + + @return KErrNone or standard error code. +*/ +TInt DESockLoopbackPddFactory::Install() + { + // Allocate a kernel thread to run the DFC + TInt r = Kern::DynamicDfcQCreate(iDfcQ, KESockLoopbackThreadPriority, KESockLoopbackThread); + if (r == KErrNone) + { + r = SetName(&KLegacyLoopbackPddName); + } + return r; + } + +/** + Returns the drivers capabilities. This is not used by the Symbian OS device driver framework + but may be useful for the LDD to use. + + @param aDes Descriptor to write capabilities information into +*/ +void DESockLoopbackPddFactory::GetCaps(TDes8& aDes) const + { + // Create a capabilities object + DESockLoopback::TCaps caps; + caps.iVersion = iVersion; + // Zero the buffer + TInt maxLen = aDes.MaxLength(); + aDes.FillZ(maxLen); + // Copy cpabilities + TInt size=sizeof(caps); + if(size>maxLen) + size=maxLen; + aDes.Copy((TUint8*)&caps,size); + } + +/** + Called by the kernel's device driver framework to create a Physical 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 Physical Channel + @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 or standard error code. +*/ +TInt DESockLoopbackPddFactory::Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer) + { + // Ignore the parameters we aren't interested in... + (void)aUnit; + (void)aInfo; + (void)aVer; + + // Create a new physical channel + DESockLoopbackDevice* device=new DESockLoopbackDevice(this); + aChannel=device; + if (!device) + return KErrNoMemory; + return device->DoCreate(); + } + +/** + 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 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 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 or standard error code. +*/ +TInt DESockLoopbackPddFactory::Validate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer) + { + // Check version numbers + if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(EMinimumLddMajorVersion,EMinimumLddMinorVersion,EMinimumLddBuild)))) + return KErrNotSupported; + + // We don't support units + if (aUnit != -1) + return KErrNotSupported; + + // Ignore extra info, (this could be used for validation purposes) + // Note, aInof is a pointer to a descriptor in user memory, therefore safe methods should + // be used for reading its contents. E.g. using Kern::KUDesGet() + (void)aInfo; + + // OK + return KErrNone; + } + +DESockLoopbackPddFactory::~DESockLoopbackPddFactory() + { + if (iDfcQ) + iDfcQ->Destroy(); + } + +DESockLoopbackDevice::DESockLoopbackDevice(DESockLoopbackPddFactory* aFactory) + : iFactory(aFactory), + iSpeed(100000), // 100000us (100ms) per byte + iSendQueue(), + iReceiveQueue(), + iRecvDataDfc(DataRecvCallback, this, aFactory->iDfcQ, 1) + + { + } + +DESockLoopbackDevice::~DESockLoopbackDevice() + { + // Driver no longer using hardware resources + NKern::LockedDec(iFactory->iHardwareInUse); + } + +TInt DESockLoopbackDevice::DoCreate() + { + // Claim the hardware resources by incrementing iHardwareInUse. + // Must do this before any other failure can happen in this function so that + // the destructor can safely decrement iHardwareInUse. + // + // This method of ensuring hardware is only in use by one driver at a time + // wouldn't be needed if the driver claimed real hardware resources which + // could only be used once. E.g. binding to an interrupt. + if(NKern::LockedInc(iFactory->iHardwareInUse)) + return KErrInUse; + + // Other setup goes here + + return KErrNone; + } + +TInt DESockLoopbackDevice::BufferSize() const + { + return iSendQueue.MaxLength(); + } + +TInt DESockLoopbackDevice::Speed() const + { + return iSpeed; + } + +TInt DESockLoopbackDevice::SetSpeed(TInt aSpeed) + { + if(aSpeed<=0) + return KErrArgument; + iSpeed = aSpeed; + return KErrNone; + } + +TInt DESockLoopbackDevice::RequestDataSend() + { + // Push our send buffer in to the queue + iSendQueue.Push(); + + // Trigger reception + NKern::Lock(); + SendDataCallback(); + NKern::Unlock(); + + return KErrNone; + } + +void DESockLoopbackDevice::SendDataCancel() + { + } + +void DESockLoopbackDevice::SendDataCallback() + { + // Tell self new data is coming + iRecvDataDfc.Add(); + + // Tell LDD we've done sending + iLdd->SendDataComplete(KErrNone); + } + +TInt DESockLoopbackDevice::RequestDataReceipt() + { + iPendingRead = ETrue; + if(!(iReceiveQueue.IsEmpty() && iSendQueue.IsEmpty())) + { + NKern::Lock(); + ReceiveDataCallback(); + NKern::Unlock(); + } + return KErrNone; + } + +void DESockLoopbackDevice::ReceiveDataCancel() + { + } + +void DESockLoopbackDevice::ReceiveDataCallback() + { + // Copy buffer from send queue (it's like our receive hardware) to receive queue + if(!iReceiveQueue.IsFull() && !iSendQueue.IsEmpty()) + { + // Copy the buffer from one queue to the other and patch up descriptor + TDes8* srcDesc = iSendQueue.HeadBuffer(); + TDes8* destDesc = iReceiveQueue.TailBuffer(); + + const TUint8* srcPtr = srcDesc->Ptr(); + const TUint8* destPtr = destDesc->Ptr(); + + TInt length = srcDesc->Length(); + + memcpy((void*)destPtr, (void*)srcPtr, length); + + destDesc->SetLength(length); + + // Bump the receive queue now that we have loaded it + iReceiveQueue.Push(); + + // Drop our incoming buffer + iSendQueue.Pop(); + + // If there is a pending read request then we can now satisfy it + if(iPendingRead) + { + iPendingRead = FALSE; + + // Tell LDD we're done + iLdd->ReceiveDataComplete(KErrNone); + } + } + } + +TDes8& DESockLoopbackDevice::SendBuffer() + { + return *iSendQueue.TailBuffer(); + } + +TDesC8& DESockLoopbackDevice::ReceiveBuffer() + { + return *iReceiveQueue.HeadBuffer(); + } + +void DESockLoopbackDevice::AdvanceReceiveQueue() + { + iReceiveQueue.Pop(); + } + +TInt DESockLoopbackDevice::ReceivedQueueLen() + { + return iReceiveQueue.Length(); + } + + +void DESockLoopbackDevice::DataRecvCallback(TAny* aSelf) + { + ((DESockLoopbackDevice*)aSelf)->ReceiveDataCallback(); + }