diff -r 000000000000 -r a41df078684a kerneltest/e32test/examples/driver1/driver1_pdd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/examples/driver1/driver1_pdd.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,297 @@ +// Copyright (c) 2003-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: +// + +/** + @file Example Pysical Device Driver + @publishedPartner + @released +*/ + +#include +#include "driver1.h" +#include "driver1_dev.h" + +// Name for PDD, must match LDD name with a '.' and distinguishing name appended +_LIT(KDriver1PddName,"DRIVER1.template"); + + +class DDriver1Device : public DDriver1 + { +public: + DDriver1Device(DDevice1PddFactory* aFactory); + ~DDriver1Device(); + TInt DoCreate(); + // Inherited from DDriver1. These called by the LDD. + virtual TInt BufferSize() const; + virtual TInt Speed() const; + virtual TInt SetSpeed(TInt aSpeed); + virtual TInt SendData(const TDesC8& aData); + virtual void SendDataCancel(); + virtual TInt ReceiveData(TDes8& aBuffer); + virtual void ReceiveDataCancel(); +private: + static void SendDataTimerCallback(TAny* aPtr); + void SendDataCallback(); + static void ReceiveDataTimerCallback(TAny* aPtr); + void ReceiveDataCallback(); +private: + DDevice1PddFactory* iFactory; + TInt iSpeed; + NTimer iSendDataTimer; + NTimer iReceiveDataTimer; + TBuf8<256> iBuffer; + TDes8* iReceiveBuffer; + }; + + + +// +// DDevice1PddFactory +// + +const TInt KDriver1ThreadPriority = 27; +_LIT(KDriver1Thread,"Driver1Thread"); + +/** + Standard export function for PDDs. This creates a DPhysicalDevice derived object, + in this case, our DDevice1PddFactory +*/ +DECLARE_STANDARD_PDD() + { + return new DDevice1PddFactory; + } + +DDevice1PddFactory::DDevice1PddFactory() + { + // Set version number for this device + iVersion=RDriver1::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 DDevice1PddFactory::Install() + { + // Allocate a kernel thread to run the DFC + TInt r = Kern::DynamicDfcQCreate(iDfcQ, KDriver1ThreadPriority, KDriver1Thread); + if (r == KErrNone) + { + r = SetName(&KDriver1PddName); + } + 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 DDevice1PddFactory::GetCaps(TDes8& aDes) const + { + // Create a capabilities object + DDriver1::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 DDevice1PddFactory::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 + DDriver1Device* device=new DDriver1Device(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 DDevice1PddFactory::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; + } + +/** + Destructor +*/ +DDevice1PddFactory::~DDevice1PddFactory() + { + if (iDfcQ) + iDfcQ->Destroy(); + } + +// +// DDriver1Device +// + +DDriver1Device::DDriver1Device(DDevice1PddFactory* aFactory) + : iFactory(aFactory), + iSpeed(100000), // 100000us (100ms) per byte + iSendDataTimer(SendDataTimerCallback,this), + iReceiveDataTimer(ReceiveDataTimerCallback,this) + { + } + +DDriver1Device::~DDriver1Device() + { + // Driver no longer using hardware resources + __e32_atomic_add_ord32(&iFactory->iHardwareInUse, TUint32(-1)); + } + +TInt DDriver1Device::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 (__e32_atomic_add_ord32(&iFactory->iHardwareInUse, 1)) + return KErrInUse; + + // Other setup goes here + + return KErrNone; + } + +TInt DDriver1Device::BufferSize() const + { + return iBuffer.MaxSize(); + } + +TInt DDriver1Device::Speed() const + { + return iSpeed; + } + +TInt DDriver1Device::SetSpeed(TInt aSpeed) + { + if(aSpeed<=0) + return KErrArgument; + iSpeed = aSpeed; + return KErrNone; + } + +TInt DDriver1Device::SendData(const TDesC8& aData) + { + // Save the last part of the data to 'send', we will pretend to 'receive' this later + iBuffer=aData.Right(iBuffer.MaxSize()); + // Pretend to send the data by waiting for iSpeed micro-seconds per byte... + iSendDataTimer.OneShot(aData.Size()*iSpeed/NKern::TickPeriod()); + + return KErrNone; + } + +void DDriver1Device::SendDataCancel() + { + // Stop the timer we were using to pretend we were processing the send + iSendDataTimer.Cancel(); + } + +void DDriver1Device::SendDataTimerCallback(TAny* aPtr) + { + // Just forward callback to non-static callback function + ((DDriver1Device*)aPtr)->SendDataCallback(); + } + +void DDriver1Device::SendDataCallback() + { + // Tell LDD we've done + iLdd->SendDataComplete(KErrNone); + } + +TInt DDriver1Device::ReceiveData(TDes8& aBuffer) + { + // Save a pointer to the buffer we need to put the 'recevied' data in + iReceiveBuffer=&aBuffer; + // Pretend to receive the data by waiting for iSpeed micro-seconds per byte... + iReceiveDataTimer.OneShot(iBuffer.Size()*iSpeed/NKern::TickPeriod()); + + return KErrNone; + } + +void DDriver1Device::ReceiveDataCancel() + { + // Stop the timer we were using to pretend we were processing the receive + iReceiveDataTimer.Cancel(); + } + +void DDriver1Device::ReceiveDataTimerCallback(TAny* aPtr) + { + // Just forward callback to non-static callback function + ((DDriver1Device*)aPtr)->ReceiveDataCallback(); + } + +void DDriver1Device::ReceiveDataCallback() + { + // Pretend the data we have received is that saved in iBuffer when we last did a send + *iReceiveBuffer=iBuffer; + // Tell LDD we've done + iLdd->ReceiveDataComplete(KErrNone); + }