1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/examples/driver1/driver1_ldd.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,554 @@
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 Logical 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 +_LIT(KDriver1PanicCategory,"Driver1");
1.30 +
1.31 +
1.32 +//
1.33 +// DDriver1Factory
1.34 +//
1.35 +
1.36 +/**
1.37 + Standard export function for LDDs. This creates a DLogicalDevice derived object,
1.38 + in this case, our DDriver1Factory
1.39 +*/
1.40 +DECLARE_STANDARD_LDD()
1.41 + {
1.42 + return new DDriver1Factory;
1.43 + }
1.44 +
1.45 +/**
1.46 + Constructor
1.47 +*/
1.48 +DDriver1Factory::DDriver1Factory()
1.49 + {
1.50 + // Set version number for this device
1.51 + iVersion=RDriver1::VersionRequired();
1.52 + // Indicate that we work with a PDD
1.53 + iParseMask=KDeviceAllowPhysicalDevice;
1.54 + }
1.55 +
1.56 +
1.57 +/**
1.58 + Second stage constructor for DDriver1Factory.
1.59 + This must at least set a name for the driver object.
1.60 +
1.61 + @return KErrNone if successful, otherwise one of the other system wide error codes.
1.62 +*/
1.63 +TInt DDriver1Factory::Install()
1.64 + {
1.65 + return SetName(&RDriver1::Name());
1.66 + }
1.67 +
1.68 +
1.69 +/**
1.70 + Destructor
1.71 + */
1.72 +DDriver1Factory::~DDriver1Factory()
1.73 + {
1.74 + }
1.75 +
1.76 +
1.77 +/**
1.78 + Return the drivers capabilities.
1.79 + Called in the response to an RDevice::GetCaps() request.
1.80 +
1.81 + @param aDes User-side descriptor to write capabilities information into
1.82 +*/
1.83 +void DDriver1Factory::GetCaps(TDes8& aDes) const
1.84 + {
1.85 + // Create a capabilities object
1.86 + RDriver1::TCaps caps;
1.87 + caps.iVersion = iVersion;
1.88 + // Write it back to user memory
1.89 + Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
1.90 + }
1.91 +
1.92 +/**
1.93 + Called by the kernel's device driver framework to create a Logical Channel.
1.94 + This is called in the context of the user thread (client) which requested the creation of a Logical Channel
1.95 + (E.g. through a call to RBusLogicalChannel::DoCreate)
1.96 + The thread is in a critical section.
1.97 +
1.98 + @param aChannel Set to point to the created Logical Channel
1.99 +
1.100 + @return KErrNone if successful, otherwise one of the other system wide error codes.
1.101 +*/
1.102 +TInt DDriver1Factory::Create(DLogicalChannelBase*& aChannel)
1.103 + {
1.104 + aChannel=new DDriver1Channel;
1.105 + if(!aChannel)
1.106 + return KErrNoMemory;
1.107 +
1.108 + return KErrNone;
1.109 + }
1.110 +
1.111 +//
1.112 +// Logical Channel
1.113 +//
1.114 +
1.115 +/**
1.116 + Constructor
1.117 +*/
1.118 +DDriver1Channel::DDriver1Channel()
1.119 + : iSendDataDfc(SendDataDfc, this, 1), // DFC is priority '1'
1.120 + iReceiveDataDfc(ReceiveDataDfc, this, 1) // DFC is priority '1'
1.121 + {
1.122 + // Get pointer to client threads DThread object
1.123 + iClient=&Kern::CurrentThread();
1.124 +
1.125 + // Open a reference on client thread so it's control block can't dissapear until
1.126 + // this driver has finished with it.
1.127 + // Note, this call to Open can't fail since its the thread we are currently running in
1.128 + iClient->Open();
1.129 + }
1.130 +
1.131 +/**
1.132 + Second stage constructor called by the kernel's device driver framework.
1.133 + This is called in the context of the user thread (client) which requested the creation of a Logical Channel
1.134 + (E.g. through a call to RBusLogicalChannel::DoCreate)
1.135 + The thread is in a critical section.
1.136 +
1.137 + @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
1.138 + @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
1.139 + @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
1.140 +
1.141 + @return KErrNone if successful, otherwise one of the other system wide error codes.
1.142 +*/
1.143 +TInt DDriver1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
1.144 + {
1.145 + // Check Platform Security capabilities of client thread (if required).
1.146 + //
1.147 + // Here we handle the simple case where:
1.148 + // 1. The device driver can only have one client thread
1.149 + // 2. The security policy is the binary all-or-nothing policy.
1.150 + // E.g. "If you have the right capability you can do anything with the driver
1.151 + // and if you don't have the capability you can't do anything"
1.152 + //
1.153 + // If only some functionality of the driver is restricted, then the security check should
1.154 + // go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
1.155 + // shouldn't be used because the 'current thread' isn't the client.
1.156 + //
1.157 + // In this example we do a check here for ECapability_None (which always passes)...
1.158 + if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
1.159 + return KErrPermissionDenied;
1.160 +
1.161 + // Check version
1.162 + if (!Kern::QueryVersionSupported(RDriver1::VersionRequired(),aVer))
1.163 + return KErrNotSupported;
1.164 +
1.165 + // Setup LDD for receiving client messages
1.166 + SetDfcQ(((DDevice1PddFactory*)iPhysicalDevice)->iDfcQ);
1.167 + iMsgQ.Receive();
1.168 +
1.169 + // Associate DFCs with the same queue we set above to receive client messages on
1.170 + iSendDataDfc.SetDfcQ(iDfcQ);
1.171 + iReceiveDataDfc.SetDfcQ(iDfcQ);
1.172 +
1.173 + // Give PDD a pointer to this channel
1.174 + Pdd()->iLdd=this;
1.175 +
1.176 + // Done
1.177 + return KErrNone;
1.178 + }
1.179 +
1.180 +/**
1.181 + Destructor
1.182 +*/
1.183 +DDriver1Channel::~DDriver1Channel()
1.184 + {
1.185 + // Cancel all processing that we may be doing
1.186 + DoCancel(RDriver1::EAllRequests);
1.187 + // Close our reference on the client thread
1.188 + Kern::SafeClose((DObject*&)iClient,NULL);
1.189 + }
1.190 +
1.191 +/**
1.192 + Called when a user thread requests a handle to this channel.
1.193 +*/
1.194 +TInt DDriver1Channel::RequestUserHandle(DThread* aThread, TOwnerType aType)
1.195 + {
1.196 + // Make sure that only our client can get a handle
1.197 + if (aType!=EOwnerThread || aThread!=iClient)
1.198 + return KErrAccessDenied;
1.199 + return KErrNone;
1.200 + }
1.201 +
1.202 +/**
1.203 + Process a message for this logical channel.
1.204 + This function is called in the context of a DFC thread.
1.205 +
1.206 + @param aMessage The message to process.
1.207 + The iValue member of this distinguishes the message type:
1.208 + iValue==ECloseMsg, channel close message
1.209 + iValue==KMaxTInt, a 'DoCancel' message
1.210 + iValue>=0, a 'DoControl' message with function number equal to iValue
1.211 + iValue<0, a 'DoRequest' message with function number equal to ~iValue
1.212 +*/
1.213 +void DDriver1Channel::HandleMsg(TMessageBase* aMsg)
1.214 + {
1.215 + TThreadMessage& m=*(TThreadMessage*)aMsg;
1.216 +
1.217 + // Get message type
1.218 + TInt id=m.iValue;
1.219 +
1.220 + // Decode the message type and dispatch it to the relevent handler function...
1.221 +
1.222 + if (id==(TInt)ECloseMsg)
1.223 + {
1.224 + // Channel Close
1.225 + DoCancel(RDriver1::EAllRequests);
1.226 + m.Complete(KErrNone, EFalse);
1.227 + return;
1.228 + }
1.229 +
1.230 + if (id==KMaxTInt)
1.231 + {
1.232 + // DoCancel
1.233 + DoCancel(m.Int0());
1.234 + m.Complete(KErrNone,ETrue);
1.235 + return;
1.236 + }
1.237 +
1.238 + if (id<0)
1.239 + {
1.240 + // DoRequest
1.241 + TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
1.242 + TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
1.243 + if (r!=KErrNone)
1.244 + Kern::RequestComplete(iClient,pS,r);
1.245 + m.Complete(KErrNone,ETrue);
1.246 + }
1.247 + else
1.248 + {
1.249 + // DoControl
1.250 + TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
1.251 + m.Complete(r,ETrue);
1.252 + }
1.253 + }
1.254 +
1.255 +/**
1.256 + Process synchronous 'control' requests
1.257 +*/
1.258 +TInt DDriver1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
1.259 + {
1.260 + (void)a2; // a2 not used in this example
1.261 +
1.262 + TInt r;
1.263 +
1.264 + switch (aFunction)
1.265 + {
1.266 + case RDriver1::EGetConfig:
1.267 + r = GetConfig((TDes8*)a1);
1.268 + break;
1.269 +
1.270 + case RDriver1::ESetConfig:
1.271 + r = SetConfig((const TDesC8*)a1);
1.272 + break;
1.273 +
1.274 + default:
1.275 + r = KErrNotSupported;
1.276 + break;
1.277 + }
1.278 +
1.279 + return r;
1.280 + }
1.281 +
1.282 +/**
1.283 + Process asynchronous requests.
1.284 +*/
1.285 +TInt DDriver1Channel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
1.286 + {
1.287 + (void)a2; // a2 not used in this example
1.288 +
1.289 + TInt r;
1.290 +
1.291 + switch(aReqNo)
1.292 + {
1.293 + case RDriver1::ESendData:
1.294 + r=SendData(aStatus,(const TDesC8*)a1);
1.295 + break;
1.296 +
1.297 + case RDriver1::EReceiveData:
1.298 + // Example Platform Security capability check which tests the
1.299 + // client for ECapability_None (which always passes)...
1.300 + if(iClient->HasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
1.301 + r=ReceiveData(aStatus,(TDes8*)a1);
1.302 + else
1.303 + r=KErrPermissionDenied;
1.304 + break;
1.305 +
1.306 + default:
1.307 + r = KErrNotSupported;
1.308 + break;
1.309 + }
1.310 +
1.311 + return r;
1.312 + }
1.313 +
1.314 +/**
1.315 + Process cancelling of asynchronous requests.
1.316 +*/
1.317 +void DDriver1Channel::DoCancel(TUint aMask)
1.318 + {
1.319 + if(aMask&(1<<RDriver1::ESendData))
1.320 + SendDataCancel();
1.321 + if(aMask&(1<<RDriver1::EReceiveData))
1.322 + ReceiveDataCancel();
1.323 + }
1.324 +
1.325 +//
1.326 +// Methods for processing configuration control messages
1.327 +//
1.328 +
1.329 +/**
1.330 + Process a GetConfig control message. This writes the current driver configuration to a
1.331 + RDriver1::TConfigBuf supplied by the client.
1.332 +*/
1.333 +TInt DDriver1Channel::GetConfig(TDes8* aConfigBuf)
1.334 + {
1.335 + // Create a structure giving the current configuration
1.336 + RDriver1::TConfig config;
1.337 + CurrentConfig(config);
1.338 +
1.339 + // Write the config to the client
1.340 + TPtrC8 ptr((const TUint8*)&config,sizeof(config));
1.341 + return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL);
1.342 + }
1.343 +
1.344 +/**
1.345 + Process a SetConfig control message. This sets the driver configuration using a
1.346 + RDriver1::TConfigBuf supplied by the client.
1.347 +*/
1.348 +TInt DDriver1Channel::SetConfig(const TDesC8* aConfigBuf)
1.349 + {
1.350 + // Don't allow configuration changes whilst we're busy
1.351 + if(iSendDataStatus || iReceiveDataStatus)
1.352 + return KErrInUse;
1.353 +
1.354 + // Create a config structure.
1.355 + RDriver1::TConfig config;
1.356 + CurrentConfig(config);
1.357 +
1.358 + // Note: We have filled config with the current settings, this is to allow
1.359 + // backwards compatibility when a client gives us an old (and shorter) version
1.360 + // of the config structure.
1.361 +
1.362 + // Read the config structure from client
1.363 + TPtr8 ptr((TUint8*)&config,sizeof(config));
1.364 + TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
1.365 + if(r!=KErrNone)
1.366 + return r;
1.367 +
1.368 + // Use config data to setup the driver. Checking that parameters which aren't settable
1.369 + // either contain the correct values or are zero (meaning 'default')
1.370 + if(config.iPddBufferSize && config.iPddBufferSize!=Pdd()->BufferSize())
1.371 + return KErrArgument;
1.372 +
1.373 + if(config.iMaxSendDataSize && config.iMaxSendDataSize!=iSendDataBuffer.MaxSize())
1.374 + return KErrArgument;
1.375 +
1.376 + if(config.iMaxReceiveDataSize && config.iMaxReceiveDataSize!=iReceiveDataBuffer.MaxSize())
1.377 + return KErrArgument;
1.378 +
1.379 + r=Pdd()->SetSpeed(config.iSpeed);
1.380 + if(r!=KErrNone)
1.381 + return r;
1.382 +
1.383 + return r;
1.384 + }
1.385 +
1.386 +/**
1.387 + Fill a TConfig with the drivers current configuration.
1.388 +*/
1.389 +void DDriver1Channel::CurrentConfig(RDriver1::TConfig& aConfig)
1.390 + {
1.391 + aConfig.iSpeed = Pdd()->Speed();
1.392 + aConfig.iPddBufferSize = Pdd()->BufferSize();
1.393 + aConfig.iMaxSendDataSize = iSendDataBuffer.MaxSize();
1.394 + aConfig.iMaxReceiveDataSize = iReceiveDataBuffer.MaxSize();
1.395 + }
1.396 +
1.397 +//
1.398 +// Methods for processing 'SendData'
1.399 +//
1.400 +
1.401 +/**
1.402 + Start processing a SendData request.
1.403 +*/
1.404 +TInt DDriver1Channel::SendData(TRequestStatus* aStatus,const TDesC8* aData)
1.405 + {
1.406 + // Check that a 'SendData' isn't already in progress
1.407 + if(iSendDataStatus)
1.408 + {
1.409 + Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
1.410 + return KErrInUse;
1.411 + }
1.412 +
1.413 + // Read data from client into our buffer
1.414 + TInt r=Kern::ThreadDesRead(iClient,aData,iSendDataBuffer,0);
1.415 + if(r!=KErrNone)
1.416 + return r;
1.417 +
1.418 + // Give data to PDD so that it can do the work
1.419 + r=Pdd()->SendData(iSendDataBuffer);
1.420 + if(r!=KErrNone)
1.421 + return r;
1.422 +
1.423 + // Save the client request status and return
1.424 + iSendDataStatus = aStatus;
1.425 + return KErrNone;
1.426 + }
1.427 +
1.428 +/**
1.429 + Cancel a SendData request.
1.430 +*/
1.431 +void DDriver1Channel::SendDataCancel()
1.432 + {
1.433 + if(iSendDataStatus)
1.434 + {
1.435 + // Tell PDD to stop processing the request
1.436 + Pdd()->SendDataCancel();
1.437 + // Cancel DFC
1.438 + iSendDataDfc.Cancel();
1.439 + // Complete clients request
1.440 + Kern::RequestComplete(iClient,iSendDataStatus,KErrCancel);
1.441 + }
1.442 + }
1.443 +
1.444 +/**
1.445 + Called by PDD from ISR to indicate that a SendData operation has completed.
1.446 +*/
1.447 +void DDriver1Channel::SendDataComplete(TInt aResult)
1.448 + {
1.449 + // Save result code
1.450 + iSendDataResult = aResult;
1.451 + // Queue DFC
1.452 + iSendDataDfc.Add();
1.453 + }
1.454 +
1.455 +/**
1.456 + DFC callback which gets triggered after the PDD has signalled that SendData completed.
1.457 + This just casts aPtr and calls DoSendDataComplete().
1.458 +*/
1.459 +void DDriver1Channel::SendDataDfc(TAny* aPtr)
1.460 + {
1.461 + ((DDriver1Channel*)aPtr)->DoSendDataComplete();
1.462 + }
1.463 +
1.464 +/**
1.465 + Called from a DFC after the PDD has signalled that SendData completed.
1.466 +*/
1.467 +void DDriver1Channel::DoSendDataComplete()
1.468 + {
1.469 + TInt result = iSendDataResult;
1.470 + // Complete clients request
1.471 + Kern::RequestComplete(iClient,iSendDataStatus,result);
1.472 + }
1.473 +
1.474 +//
1.475 +// Methods for processing 'ReceiveData'
1.476 +//
1.477 +
1.478 +/**
1.479 + Start processing a ReceiveData request.
1.480 +*/
1.481 +TInt DDriver1Channel::ReceiveData(TRequestStatus* aStatus,TDes8* aPtr)
1.482 + {
1.483 + // Check that a 'ReceiveData' isn't already in progress
1.484 + if(iReceiveDataStatus)
1.485 + {
1.486 + Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
1.487 + return KErrInUse;
1.488 + }
1.489 +
1.490 + // Ask PDD for data
1.491 + TInt r=Pdd()->ReceiveData(iReceiveDataBuffer);
1.492 + if(r!=KErrNone)
1.493 + return r;
1.494 +
1.495 + // Save the client request status and descriptor before returning
1.496 + iReceiveDataStatus = aStatus;
1.497 + iReceiveDataDescriptor = aPtr;
1.498 + return KErrNone;
1.499 + }
1.500 +
1.501 +/**
1.502 + Cancel a ReceiveData request.
1.503 +*/
1.504 +void DDriver1Channel::ReceiveDataCancel()
1.505 + {
1.506 + if(iReceiveDataStatus)
1.507 + {
1.508 + // Tell PDD to stop processing the request
1.509 + Pdd()->ReceiveDataCancel();
1.510 + // Cancel DFC
1.511 + iReceiveDataDfc.Cancel();
1.512 + // Finished with client descriptor, so NULL it to help detect coding errors
1.513 + iReceiveDataDescriptor = NULL;
1.514 + // Complete clients request
1.515 + Kern::RequestComplete(iClient,iReceiveDataStatus,KErrCancel);
1.516 + }
1.517 + }
1.518 +
1.519 +/**
1.520 + Called by PDD from ISR to indicate that a ReceiveData operation has completed.
1.521 +*/
1.522 +void DDriver1Channel::ReceiveDataComplete(TInt aResult)
1.523 + {
1.524 + // Save result code
1.525 + iReceiveDataResult = aResult;
1.526 + // Queue DFC
1.527 + iReceiveDataDfc.Add();
1.528 + }
1.529 +
1.530 +/**
1.531 + DFC Callback which gets triggered after the PDD has signalled that ReceiveData completed.
1.532 + This just casts aPtr and calls DoReceiveDataComplete().
1.533 +*/
1.534 +void DDriver1Channel::ReceiveDataDfc(TAny* aPtr)
1.535 + {
1.536 + ((DDriver1Channel*)aPtr)->DoReceiveDataComplete();
1.537 + }
1.538 +
1.539 +/**
1.540 + Called from a DFC after the PDD has signalled that ReceiveData completed.
1.541 +*/
1.542 +void DDriver1Channel::DoReceiveDataComplete()
1.543 + {
1.544 + // Write data to client from our buffer
1.545 + TInt result=Kern::ThreadDesWrite(iClient,iReceiveDataDescriptor,iReceiveDataBuffer,0);
1.546 +
1.547 + // Finished with client descriptor, so NULL it to help detect coding errors
1.548 + iReceiveDataDescriptor = NULL;
1.549 +
1.550 + // Use result code from PDD if it was an error
1.551 + if(iReceiveDataResult!=KErrNone)
1.552 + result = iReceiveDataResult;
1.553 +
1.554 + // Complete clients request
1.555 + Kern::RequestComplete(iClient,iReceiveDataStatus,result);
1.556 + }
1.557 +