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