kerneltest/e32test/examples/driver1/driver1_pdd.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 136 743008598095
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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 <kernel/kern_priv.h>
#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);
	}