First public contribution.
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
 
     2 // All rights reserved.
 
     3 // This component and the accompanying materials are made available
 
     4 // under the terms of the License "Eclipse Public License v1.0"
 
     5 // which accompanies this distribution, and is available
 
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
 
     8 // Initial Contributors:
 
     9 // Nokia Corporation - initial contribution.
 
    17  @file Example Logical Device Driver
 
    22 #include <kernel/kern_priv.h>
 
    24 #include "driver1_dev.h"
 
    26 _LIT(KDriver1PanicCategory,"Driver1");
 
    34   Standard export function for LDDs. This creates a DLogicalDevice derived object,
 
    35   in this case, our DDriver1Factory
 
    37 DECLARE_STANDARD_LDD()
 
    39 	return new DDriver1Factory;
 
    45 DDriver1Factory::DDriver1Factory()
 
    47 	// Set version number for this device
 
    48 	iVersion=RDriver1::VersionRequired();
 
    49 	// Indicate that we work with a PDD
 
    50 	iParseMask=KDeviceAllowPhysicalDevice;
 
    55   Second stage constructor for DDriver1Factory.
 
    56   This must at least set a name for the driver object.
 
    58   @return KErrNone if successful, otherwise one of the other system wide error codes.
 
    60 TInt DDriver1Factory::Install()
 
    62 	return SetName(&RDriver1::Name());
 
    69 DDriver1Factory::~DDriver1Factory()
 
    75   Return the drivers capabilities.
 
    76   Called in the response to an RDevice::GetCaps() request.
 
    78   @param aDes User-side descriptor to write capabilities information into
 
    80 void DDriver1Factory::GetCaps(TDes8& aDes) const
 
    82 	// Create a capabilities object
 
    84 	caps.iVersion = iVersion;
 
    85 	// Write it back to user memory
 
    86 	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
 
    90   Called by the kernel's device driver framework to create a Logical Channel.
 
    91   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
 
    92   (E.g. through a call to RBusLogicalChannel::DoCreate)
 
    93   The thread is in a critical section.
 
    95   @param aChannel Set to point to the created Logical Channel
 
    97   @return KErrNone if successful, otherwise one of the other system wide error codes.
 
    99 TInt DDriver1Factory::Create(DLogicalChannelBase*& aChannel)
 
   101 	aChannel=new DDriver1Channel;
 
   115 DDriver1Channel::DDriver1Channel()
 
   116 	:	iSendDataDfc(SendDataDfc, this, 1),        // DFC is priority '1'
 
   117 		iReceiveDataDfc(ReceiveDataDfc, this, 1)   // DFC is priority '1'
 
   119 	// Get pointer to client threads DThread object
 
   120 	iClient=&Kern::CurrentThread();
 
   122 	// Open a reference on client thread so it's control block can't dissapear until
 
   123 	// this driver has finished with it.
 
   124 	// Note, this call to Open can't fail since its the thread we are currently running in
 
   129   Second stage constructor called by the kernel's device driver framework.
 
   130   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
 
   131   (E.g. through a call to RBusLogicalChannel::DoCreate)
 
   132   The thread is in a critical section.
 
   134   @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
 
   135   @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
 
   136   @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
 
   138   @return KErrNone if successful, otherwise one of the other system wide error codes.
 
   140 TInt DDriver1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
 
   142 	// Check Platform Security capabilities of client thread (if required).
 
   144 	// Here we handle the simple case where:
 
   145 	// 1. The device driver can only have one client thread
 
   146 	// 2. The security policy is the binary all-or-nothing policy.
 
   147 	//    E.g. "If you have the right capability you can do anything with the driver
 
   148 	//    and if you don't have the capability you can't do anything"
 
   150 	// If only some functionality of the driver is restricted, then the security check should
 
   151 	// go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
 
   152 	// shouldn't be used because the 'current thread' isn't the client.
 
   154 	// In this example we do a check here for ECapability_None (which always passes)...
 
   155 	if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
 
   156 		return KErrPermissionDenied;
 
   159 	if (!Kern::QueryVersionSupported(RDriver1::VersionRequired(),aVer))
 
   160 		return KErrNotSupported;
 
   162 	// Setup LDD for receiving client messages
 
   163 	SetDfcQ(((DDevice1PddFactory*)iPhysicalDevice)->iDfcQ);
 
   166 	// Associate DFCs with the same queue we set above to receive client messages on
 
   167 	iSendDataDfc.SetDfcQ(iDfcQ);
 
   168 	iReceiveDataDfc.SetDfcQ(iDfcQ);
 
   170 	// Give PDD a pointer to this channel
 
   180 DDriver1Channel::~DDriver1Channel()
 
   182 	// Cancel all processing that we may be doing
 
   183 	DoCancel(RDriver1::EAllRequests);
 
   184 	// Close our reference on the client thread
 
   185 	Kern::SafeClose((DObject*&)iClient,NULL);
 
   189   Called when a user thread requests a handle to this channel.
 
   191 TInt DDriver1Channel::RequestUserHandle(DThread* aThread, TOwnerType aType)
 
   193 	// Make sure that only our client can get a handle
 
   194 	if (aType!=EOwnerThread || aThread!=iClient)
 
   195 		return KErrAccessDenied;
 
   200   Process a message for this logical channel.
 
   201   This function is called in the context of a DFC thread.
 
   203   @param aMessage The message to process.
 
   204 	              The iValue member of this distinguishes the message type:
 
   205 	              iValue==ECloseMsg, channel close message
 
   206 	              iValue==KMaxTInt, a 'DoCancel' message
 
   207 	              iValue>=0, a 'DoControl' message with function number equal to iValue
 
   208 	              iValue<0, a 'DoRequest' message with function number equal to ~iValue
 
   210 void DDriver1Channel::HandleMsg(TMessageBase* aMsg)
 
   212 	TThreadMessage& m=*(TThreadMessage*)aMsg;
 
   217 	// Decode the message type and dispatch it to the relevent handler function...
 
   219 	if (id==(TInt)ECloseMsg)
 
   222 		DoCancel(RDriver1::EAllRequests);
 
   223 		m.Complete(KErrNone, EFalse);
 
   231 		m.Complete(KErrNone,ETrue);
 
   238 		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
 
   239 		TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
 
   241 			Kern::RequestComplete(iClient,pS,r);
 
   242 		m.Complete(KErrNone,ETrue);
 
   247 		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
 
   253   Process synchronous 'control' requests
 
   255 TInt DDriver1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
 
   257 	(void)a2;   // a2 not used in this example
 
   263 		case RDriver1::EGetConfig:
 
   264 			r = GetConfig((TDes8*)a1);
 
   267 		case RDriver1::ESetConfig:
 
   268 			r = SetConfig((const TDesC8*)a1);
 
   272 			r = KErrNotSupported;
 
   280   Process asynchronous requests.
 
   282 TInt DDriver1Channel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
 
   284 	(void)a2;   // a2 not used in this example
 
   290 		case RDriver1::ESendData:
 
   291 			r=SendData(aStatus,(const TDesC8*)a1);
 
   294 		case RDriver1::EReceiveData:
 
   295 			// Example Platform Security capability check which tests the
 
   296 			// client for ECapability_None (which always passes)...
 
   297 			if(iClient->HasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
 
   298 				r=ReceiveData(aStatus,(TDes8*)a1);
 
   300 				r=KErrPermissionDenied;
 
   304 			r = KErrNotSupported;
 
   312   Process cancelling of asynchronous requests.
 
   314 void DDriver1Channel::DoCancel(TUint aMask)
 
   316 	if(aMask&(1<<RDriver1::ESendData))
 
   318 	if(aMask&(1<<RDriver1::EReceiveData))
 
   323 // Methods for processing configuration control messages
 
   327   Process a GetConfig control message. This writes the current driver configuration to a
 
   328   RDriver1::TConfigBuf supplied by the client.
 
   330 TInt DDriver1Channel::GetConfig(TDes8* aConfigBuf)
 
   332 	// Create a structure giving the current configuration
 
   333 	RDriver1::TConfig config;
 
   334 	CurrentConfig(config);
 
   336 	// Write the config to the client
 
   337 	TPtrC8 ptr((const TUint8*)&config,sizeof(config));
 
   338 	return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL);
 
   342   Process a SetConfig control message. This sets the driver configuration using a
 
   343   RDriver1::TConfigBuf supplied by the client.
 
   345 TInt DDriver1Channel::SetConfig(const TDesC8* aConfigBuf)
 
   347 	// Don't allow configuration changes whilst we're busy
 
   348 	if(iSendDataStatus || iReceiveDataStatus)
 
   351 	// Create a config structure.
 
   352 	RDriver1::TConfig config;
 
   353 	CurrentConfig(config);
 
   355 	// Note: We have filled config with the current settings, this is to allow
 
   356 	// backwards compatibility when a client gives us an old (and shorter) version
 
   357 	// of the config structure.
 
   359 	// Read the config structure from client
 
   360 	TPtr8 ptr((TUint8*)&config,sizeof(config));
 
   361 	TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
 
   365 	// Use config data to setup the driver. Checking that parameters which aren't settable
 
   366 	// either contain the correct values or are zero (meaning 'default')
 
   367 	if(config.iPddBufferSize && config.iPddBufferSize!=Pdd()->BufferSize())
 
   370 	if(config.iMaxSendDataSize && config.iMaxSendDataSize!=iSendDataBuffer.MaxSize())
 
   373 	if(config.iMaxReceiveDataSize && config.iMaxReceiveDataSize!=iReceiveDataBuffer.MaxSize())
 
   376 	r=Pdd()->SetSpeed(config.iSpeed);
 
   384   Fill a TConfig with the drivers current configuration.
 
   386 void DDriver1Channel::CurrentConfig(RDriver1::TConfig& aConfig)
 
   388 	aConfig.iSpeed = Pdd()->Speed();
 
   389 	aConfig.iPddBufferSize = Pdd()->BufferSize();
 
   390 	aConfig.iMaxSendDataSize = iSendDataBuffer.MaxSize();
 
   391 	aConfig.iMaxReceiveDataSize = iReceiveDataBuffer.MaxSize();
 
   395 // Methods for processing 'SendData'
 
   399   Start processing a SendData request.
 
   401 TInt DDriver1Channel::SendData(TRequestStatus* aStatus,const TDesC8* aData)
 
   403 	// Check that a 'SendData' isn't already in progress
 
   406 		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
 
   410 	// Read data from client into our buffer
 
   411 	TInt r=Kern::ThreadDesRead(iClient,aData,iSendDataBuffer,0);
 
   415 	// Give data to PDD so that it can do the work
 
   416 	r=Pdd()->SendData(iSendDataBuffer);
 
   420 	// Save the client request status and return
 
   421 	iSendDataStatus = aStatus;
 
   426   Cancel a SendData request.
 
   428 void DDriver1Channel::SendDataCancel()
 
   432 		// Tell PDD to stop processing the request
 
   433 		Pdd()->SendDataCancel();
 
   435 		iSendDataDfc.Cancel();
 
   436 		// Complete clients request
 
   437 		Kern::RequestComplete(iClient,iSendDataStatus,KErrCancel);
 
   442   Called by PDD from ISR to indicate that a SendData operation has completed.
 
   444 void DDriver1Channel::SendDataComplete(TInt aResult)
 
   447 	iSendDataResult = aResult;
 
   453   DFC callback which gets triggered after the PDD has signalled that SendData completed.
 
   454   This just casts aPtr and calls DoSendDataComplete().
 
   456 void DDriver1Channel::SendDataDfc(TAny* aPtr)
 
   458 	((DDriver1Channel*)aPtr)->DoSendDataComplete();
 
   462   Called from a DFC after the PDD has signalled that SendData completed.
 
   464 void DDriver1Channel::DoSendDataComplete()
 
   466 	TInt result = iSendDataResult;
 
   467 	// Complete clients request
 
   468 	Kern::RequestComplete(iClient,iSendDataStatus,result);
 
   472 // Methods for processing 'ReceiveData'
 
   476   Start processing a ReceiveData request.
 
   478 TInt DDriver1Channel::ReceiveData(TRequestStatus* aStatus,TDes8* aPtr)
 
   480 	// Check that a 'ReceiveData' isn't already in progress
 
   481 	if(iReceiveDataStatus)
 
   483 		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
 
   488 	TInt r=Pdd()->ReceiveData(iReceiveDataBuffer);
 
   492 	// Save the client request status and descriptor before returning
 
   493 	iReceiveDataStatus = aStatus;
 
   494 	iReceiveDataDescriptor = aPtr;
 
   499   Cancel a ReceiveData request.
 
   501 void DDriver1Channel::ReceiveDataCancel()
 
   503 	if(iReceiveDataStatus)
 
   505 		// Tell PDD to stop processing the request
 
   506 		Pdd()->ReceiveDataCancel();
 
   508 		iReceiveDataDfc.Cancel();
 
   509 		// Finished with client descriptor, so NULL it to help detect coding errors
 
   510 		iReceiveDataDescriptor = NULL;
 
   511 		// Complete clients request
 
   512 		Kern::RequestComplete(iClient,iReceiveDataStatus,KErrCancel);
 
   517   Called by PDD from ISR to indicate that a ReceiveData operation has completed.
 
   519 void DDriver1Channel::ReceiveDataComplete(TInt aResult)
 
   522 	iReceiveDataResult = aResult;
 
   524 	iReceiveDataDfc.Add();
 
   528   DFC Callback which gets triggered after the PDD has signalled that ReceiveData completed.
 
   529   This just casts aPtr and calls DoReceiveDataComplete().
 
   531 void DDriver1Channel::ReceiveDataDfc(TAny* aPtr)
 
   533 	((DDriver1Channel*)aPtr)->DoReceiveDataComplete();
 
   537   Called from a DFC after the PDD has signalled that ReceiveData completed.
 
   539 void DDriver1Channel::DoReceiveDataComplete()
 
   541 	// Write data to client from our buffer
 
   542 	TInt result=Kern::ThreadDesWrite(iClient,iReceiveDataDescriptor,iReceiveDataBuffer,0);
 
   544 	// Finished with client descriptor, so NULL it to help detect coding errors
 
   545 	iReceiveDataDescriptor = NULL;
 
   547 	// Use result code from PDD if it was an error
 
   548 	if(iReceiveDataResult!=KErrNone)
 
   549 		result = iReceiveDataResult;
 
   551 	// Complete clients request
 
   552 	Kern::RequestComplete(iClient,iReceiveDataStatus,result);