os/kernelhwsrv/kerneltest/e32test/examples/driver1/driver1_pdd.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/examples/driver1/driver1_pdd.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,297 @@
     1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +/**
    1.20 + @file Example Pysical Device Driver
    1.21 + @publishedPartner
    1.22 + @released
    1.23 +*/
    1.24 +
    1.25 +#include <kernel/kern_priv.h>
    1.26 +#include "driver1.h"
    1.27 +#include "driver1_dev.h"
    1.28 +
    1.29 +// Name for PDD, must match LDD name with a '.' and distinguishing name appended
    1.30 +_LIT(KDriver1PddName,"DRIVER1.template");
    1.31 +
    1.32 +
    1.33 +class DDriver1Device : public DDriver1
    1.34 +	{
    1.35 +public:
    1.36 +	DDriver1Device(DDevice1PddFactory* aFactory);
    1.37 +	~DDriver1Device();
    1.38 +	TInt DoCreate();
    1.39 +	// Inherited from DDriver1. These called by the LDD.
    1.40 +	virtual TInt BufferSize() const;
    1.41 +	virtual TInt Speed() const;
    1.42 +	virtual TInt SetSpeed(TInt aSpeed);
    1.43 +	virtual TInt SendData(const TDesC8& aData);
    1.44 +	virtual void SendDataCancel();
    1.45 +	virtual TInt ReceiveData(TDes8& aBuffer);
    1.46 +	virtual void ReceiveDataCancel();
    1.47 +private:
    1.48 +	static void SendDataTimerCallback(TAny* aPtr);
    1.49 +	void SendDataCallback();
    1.50 +	static void ReceiveDataTimerCallback(TAny* aPtr);
    1.51 +	void ReceiveDataCallback();
    1.52 +private:
    1.53 +	DDevice1PddFactory* iFactory;
    1.54 +	TInt iSpeed;
    1.55 +	NTimer iSendDataTimer;
    1.56 +	NTimer iReceiveDataTimer;
    1.57 +	TBuf8<256> iBuffer;
    1.58 +	TDes8* iReceiveBuffer;
    1.59 +	};
    1.60 +
    1.61 +
    1.62 +
    1.63 +//
    1.64 +// DDevice1PddFactory
    1.65 +//
    1.66 +
    1.67 +const TInt KDriver1ThreadPriority = 27;
    1.68 +_LIT(KDriver1Thread,"Driver1Thread");
    1.69 +
    1.70 +/**
    1.71 +  Standard export function for PDDs. This creates a DPhysicalDevice derived object,
    1.72 +  in this case, our DDevice1PddFactory
    1.73 +*/
    1.74 +DECLARE_STANDARD_PDD()
    1.75 +	{
    1.76 +	return new DDevice1PddFactory;
    1.77 +	}
    1.78 +
    1.79 +DDevice1PddFactory::DDevice1PddFactory()
    1.80 +	{
    1.81 +	// Set version number for this device
    1.82 +	iVersion=RDriver1::VersionRequired();
    1.83 +	}
    1.84 +
    1.85 +/**
    1.86 +  Second stage constructor for DPhysicalDevice derived objects.
    1.87 +  This must at least set a name for the driver object.
    1.88 +
    1.89 +  @return KErrNone or standard error code.
    1.90 +*/
    1.91 +TInt DDevice1PddFactory::Install()
    1.92 +	{
    1.93 +	// Allocate a kernel thread to run the DFC 
    1.94 +	TInt r = Kern::DynamicDfcQCreate(iDfcQ, KDriver1ThreadPriority, KDriver1Thread);
    1.95 +	if (r == KErrNone)
    1.96 +		{ 
    1.97 +		r = SetName(&KDriver1PddName);
    1.98 +		} 	
    1.99 +	return r;
   1.100 +	}
   1.101 +
   1.102 +/**
   1.103 +  Returns the drivers capabilities. This is not used by the Symbian OS device driver framework
   1.104 +  but may be useful for the LDD to use.
   1.105 +
   1.106 +  @param aDes Descriptor to write capabilities information into
   1.107 +*/
   1.108 +void DDevice1PddFactory::GetCaps(TDes8& aDes) const
   1.109 +	{
   1.110 +	// Create a capabilities object
   1.111 +	DDriver1::TCaps caps;
   1.112 +	caps.iVersion = iVersion;
   1.113 +	// Zero the buffer
   1.114 +	TInt maxLen = aDes.MaxLength();
   1.115 +	aDes.FillZ(maxLen);
   1.116 +	// Copy cpabilities
   1.117 +	TInt size=sizeof(caps);
   1.118 +	if(size>maxLen)
   1.119 +		size=maxLen;
   1.120 +	aDes.Copy((TUint8*)&caps,size);
   1.121 +	}
   1.122 +
   1.123 +/**
   1.124 +  Called by the kernel's device driver framework to create a Physical Channel.
   1.125 +  This is called in the context of the user thread (client) which requested the creation of a Logical Channel
   1.126 +  (E.g. through a call to RBusLogicalChannel::DoCreate)
   1.127 +  The thread is in a critical section.
   1.128 +
   1.129 +  @param aChannel Set to point to the created Physical Channel
   1.130 +  @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
   1.131 +  @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
   1.132 +  @param aVer The version number of the Logical Channel which will use this Physical Channel 
   1.133 +
   1.134 +  @return KErrNone or standard error code.
   1.135 +*/
   1.136 +TInt DDevice1PddFactory::Create(DBase*& aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
   1.137 +	{
   1.138 +	// Ignore the parameters we aren't interested in...
   1.139 +	(void)aUnit;
   1.140 +	(void)aInfo;
   1.141 +	(void)aVer;
   1.142 +
   1.143 +	// Create a new physical channel
   1.144 +	DDriver1Device* device=new DDriver1Device(this);
   1.145 +	aChannel=device;
   1.146 +	if (!device)
   1.147 +		return KErrNoMemory;
   1.148 +	return device->DoCreate();
   1.149 +	}
   1.150 +
   1.151 +/**
   1.152 +  Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.
   1.153 +  This is called in the context of the user thread (client) which requested the creation of a Logical Channel
   1.154 +  (E.g. through a call to RBusLogicalChannel::DoCreate)
   1.155 +  The thread is in a critical section.
   1.156 +
   1.157 +  @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
   1.158 +  @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
   1.159 +  @param aVer The version number of the Logical Channel which will use this Physical Channel 
   1.160 +
   1.161 +  @return KErrNone or standard error code.
   1.162 +*/
   1.163 +TInt DDevice1PddFactory::Validate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
   1.164 +	{
   1.165 +	// Check version numbers
   1.166 +	if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(EMinimumLddMajorVersion,EMinimumLddMinorVersion,EMinimumLddBuild))))
   1.167 +		return KErrNotSupported;
   1.168 +
   1.169 +	// We don't support units
   1.170 +    if (aUnit != -1)
   1.171 +        return KErrNotSupported;
   1.172 +
   1.173 +	// Ignore extra info, (this could be used for validation purposes)
   1.174 +	// Note, aInof is a pointer to a descriptor in user memory, therefore safe methods should
   1.175 +	// be used for reading its contents. E.g. using Kern::KUDesGet()
   1.176 +	(void)aInfo;
   1.177 +
   1.178 +	// OK
   1.179 +	return KErrNone;
   1.180 +	}
   1.181 +
   1.182 +/**
   1.183 +  Destructor
   1.184 +*/
   1.185 +DDevice1PddFactory::~DDevice1PddFactory()
   1.186 +	{
   1.187 +	if (iDfcQ)
   1.188 +		iDfcQ->Destroy();
   1.189 +	}
   1.190 +
   1.191 +//
   1.192 +// DDriver1Device
   1.193 +//
   1.194 +
   1.195 +DDriver1Device::DDriver1Device(DDevice1PddFactory* aFactory)
   1.196 +	:	iFactory(aFactory),
   1.197 +		iSpeed(100000),  // 100000us (100ms) per byte
   1.198 +		iSendDataTimer(SendDataTimerCallback,this),
   1.199 +		iReceiveDataTimer(ReceiveDataTimerCallback,this)
   1.200 +	{
   1.201 +	}
   1.202 +
   1.203 +DDriver1Device::~DDriver1Device()
   1.204 +	{
   1.205 +	// Driver no longer using hardware resources
   1.206 +	__e32_atomic_add_ord32(&iFactory->iHardwareInUse, TUint32(-1));
   1.207 +	}
   1.208 +
   1.209 +TInt DDriver1Device::DoCreate()
   1.210 +	{
   1.211 +	// Claim the hardware resources by incrementing iHardwareInUse.
   1.212 +	// Must do this before any other failure can happen in this function so that
   1.213 +	// the destructor can safely decrement iHardwareInUse.
   1.214 +	//
   1.215 +	// This method of ensuring hardware is only in use by one driver at a time
   1.216 +	// wouldn't be needed if the driver claimed real hardware resources which
   1.217 +	// could only be used once. E.g. binding to an interrupt.
   1.218 +	if (__e32_atomic_add_ord32(&iFactory->iHardwareInUse, 1))
   1.219 +		return KErrInUse;
   1.220 +
   1.221 +	// Other setup goes here
   1.222 +
   1.223 +	return KErrNone;
   1.224 +	}
   1.225 +
   1.226 +TInt DDriver1Device::BufferSize() const
   1.227 +	{
   1.228 +	return iBuffer.MaxSize();
   1.229 +	}
   1.230 +
   1.231 +TInt DDriver1Device::Speed() const
   1.232 +	{
   1.233 +	return iSpeed;
   1.234 +	}
   1.235 +
   1.236 +TInt DDriver1Device::SetSpeed(TInt aSpeed)
   1.237 +	{
   1.238 +	if(aSpeed<=0)
   1.239 +		return KErrArgument;
   1.240 +	iSpeed = aSpeed;
   1.241 +	return KErrNone;
   1.242 +	}
   1.243 +
   1.244 +TInt DDriver1Device::SendData(const TDesC8& aData)
   1.245 +	{
   1.246 +	// Save the last part of the data to 'send', we will pretend to 'receive' this later
   1.247 +	iBuffer=aData.Right(iBuffer.MaxSize());
   1.248 +	// Pretend to send the data by waiting for iSpeed micro-seconds per byte...
   1.249 +	iSendDataTimer.OneShot(aData.Size()*iSpeed/NKern::TickPeriod());
   1.250 +
   1.251 +	return KErrNone;
   1.252 +	}
   1.253 +
   1.254 +void DDriver1Device::SendDataCancel()
   1.255 +	{
   1.256 +	// Stop the timer we were using to pretend we were processing the send
   1.257 +	iSendDataTimer.Cancel();
   1.258 +	}
   1.259 +
   1.260 +void DDriver1Device::SendDataTimerCallback(TAny* aPtr)
   1.261 +	{
   1.262 +	// Just forward callback to non-static callback function
   1.263 +	((DDriver1Device*)aPtr)->SendDataCallback();
   1.264 +	}
   1.265 +
   1.266 +void DDriver1Device::SendDataCallback()
   1.267 +	{
   1.268 +	// Tell LDD we've done
   1.269 +	iLdd->SendDataComplete(KErrNone);
   1.270 +	}
   1.271 +
   1.272 +TInt DDriver1Device::ReceiveData(TDes8& aBuffer)
   1.273 +	{
   1.274 +	// Save a pointer to the buffer we need to put the 'recevied' data in
   1.275 +	iReceiveBuffer=&aBuffer;
   1.276 +	// Pretend to receive the data by waiting for iSpeed micro-seconds per byte...
   1.277 +	iReceiveDataTimer.OneShot(iBuffer.Size()*iSpeed/NKern::TickPeriod());
   1.278 +
   1.279 +	return KErrNone;
   1.280 +	}
   1.281 +
   1.282 +void DDriver1Device::ReceiveDataCancel()
   1.283 +	{
   1.284 +	// Stop the timer we were using to pretend we were processing the receive
   1.285 +	iReceiveDataTimer.Cancel();
   1.286 +	}
   1.287 +
   1.288 +void DDriver1Device::ReceiveDataTimerCallback(TAny* aPtr)
   1.289 +	{
   1.290 +	// Just forward callback to non-static callback function
   1.291 +	((DDriver1Device*)aPtr)->ReceiveDataCallback();
   1.292 +	}
   1.293 +
   1.294 +void DDriver1Device::ReceiveDataCallback()
   1.295 +	{
   1.296 +	// Pretend the data we have received is that saved in iBuffer when we last did a send
   1.297 +	*iReceiveBuffer=iBuffer;
   1.298 +	// Tell LDD we've done
   1.299 +	iLdd->ReceiveDataComplete(KErrNone);
   1.300 +	}