os/kernelhwsrv/kerneltest/e32test/examples/driver1/driver1_ldd.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 /**
    17  @file Example Logical Device Driver
    18  @publishedPartner
    19  @released
    20 */
    21 
    22 #include <kernel/kern_priv.h>
    23 #include "driver1.h"
    24 #include "driver1_dev.h"
    25 
    26 _LIT(KDriver1PanicCategory,"Driver1");
    27 
    28 
    29 //
    30 // DDriver1Factory
    31 //
    32 
    33 /**
    34   Standard export function for LDDs. This creates a DLogicalDevice derived object,
    35   in this case, our DDriver1Factory
    36 */
    37 DECLARE_STANDARD_LDD()
    38 	{
    39 	return new DDriver1Factory;
    40 	}
    41 
    42 /**
    43   Constructor
    44 */
    45 DDriver1Factory::DDriver1Factory()
    46 	{
    47 	// Set version number for this device
    48 	iVersion=RDriver1::VersionRequired();
    49 	// Indicate that we work with a PDD
    50 	iParseMask=KDeviceAllowPhysicalDevice;
    51 	}
    52 
    53 
    54 /**
    55   Second stage constructor for DDriver1Factory.
    56   This must at least set a name for the driver object.
    57 
    58   @return KErrNone if successful, otherwise one of the other system wide error codes.
    59 */
    60 TInt DDriver1Factory::Install()
    61 	{
    62 	return SetName(&RDriver1::Name());
    63 	}
    64 
    65 
    66 /**
    67      Destructor
    68    */
    69 DDriver1Factory::~DDriver1Factory()
    70    	{
    71    	}
    72 
    73 
    74 /**
    75   Return the drivers capabilities.
    76   Called in the response to an RDevice::GetCaps() request.
    77 
    78   @param aDes User-side descriptor to write capabilities information into
    79 */
    80 void DDriver1Factory::GetCaps(TDes8& aDes) const
    81 	{
    82 	// Create a capabilities object
    83 	RDriver1::TCaps caps;
    84 	caps.iVersion = iVersion;
    85 	// Write it back to user memory
    86 	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
    87 	}
    88 
    89 /**
    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.
    94 
    95   @param aChannel Set to point to the created Logical Channel
    96 
    97   @return KErrNone if successful, otherwise one of the other system wide error codes.
    98 */
    99 TInt DDriver1Factory::Create(DLogicalChannelBase*& aChannel)
   100 	{
   101 	aChannel=new DDriver1Channel;
   102 	if(!aChannel)
   103 		return KErrNoMemory;
   104 
   105 	return KErrNone;
   106 	}
   107 
   108 //
   109 // Logical Channel
   110 //
   111 
   112 /**
   113   Constructor
   114 */
   115 DDriver1Channel::DDriver1Channel()
   116 	:	iSendDataDfc(SendDataDfc, this, 1),        // DFC is priority '1'
   117 		iReceiveDataDfc(ReceiveDataDfc, this, 1)   // DFC is priority '1'
   118 	{
   119 	// Get pointer to client threads DThread object
   120 	iClient=&Kern::CurrentThread();
   121 
   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
   125 	iClient->Open();
   126 	}
   127 
   128 /**
   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.
   133 
   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
   137 
   138   @return KErrNone if successful, otherwise one of the other system wide error codes.
   139 */
   140 TInt DDriver1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
   141 	{
   142 	// Check Platform Security capabilities of client thread (if required).
   143 	//
   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"
   149 	// 
   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.
   153 	//
   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;
   157 
   158 	// Check version
   159 	if (!Kern::QueryVersionSupported(RDriver1::VersionRequired(),aVer))
   160 		return KErrNotSupported;
   161 
   162 	// Setup LDD for receiving client messages
   163 	SetDfcQ(((DDevice1PddFactory*)iPhysicalDevice)->iDfcQ);
   164 	iMsgQ.Receive();
   165 
   166 	// Associate DFCs with the same queue we set above to receive client messages on
   167 	iSendDataDfc.SetDfcQ(iDfcQ);
   168 	iReceiveDataDfc.SetDfcQ(iDfcQ);
   169 
   170 	// Give PDD a pointer to this channel
   171 	Pdd()->iLdd=this;
   172 
   173 	// Done
   174 	return KErrNone;
   175 	}
   176 
   177 /**
   178   Destructor
   179 */
   180 DDriver1Channel::~DDriver1Channel()
   181 	{
   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);
   186 	}
   187 
   188 /**
   189   Called when a user thread requests a handle to this channel.
   190 */
   191 TInt DDriver1Channel::RequestUserHandle(DThread* aThread, TOwnerType aType)
   192 	{
   193 	// Make sure that only our client can get a handle
   194 	if (aType!=EOwnerThread || aThread!=iClient)
   195 		return KErrAccessDenied;
   196 	return KErrNone;
   197 	}
   198 
   199 /**
   200   Process a message for this logical channel.
   201   This function is called in the context of a DFC thread.
   202 
   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
   209 */
   210 void DDriver1Channel::HandleMsg(TMessageBase* aMsg)
   211 	{
   212 	TThreadMessage& m=*(TThreadMessage*)aMsg;
   213 
   214 	// Get message type
   215 	TInt id=m.iValue;
   216 
   217 	// Decode the message type and dispatch it to the relevent handler function...
   218 
   219 	if (id==(TInt)ECloseMsg)
   220 		{
   221 		// Channel Close
   222 		DoCancel(RDriver1::EAllRequests);
   223 		m.Complete(KErrNone, EFalse);
   224 		return;
   225 		}
   226 
   227 	if (id==KMaxTInt)
   228 		{
   229 		// DoCancel
   230 		DoCancel(m.Int0());
   231 		m.Complete(KErrNone,ETrue);
   232 		return;
   233 		}
   234 
   235 	if (id<0)
   236 		{
   237 		// DoRequest
   238 		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
   239 		TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
   240 		if (r!=KErrNone)
   241 			Kern::RequestComplete(iClient,pS,r);
   242 		m.Complete(KErrNone,ETrue);
   243 		}
   244 	else
   245 		{
   246 		// DoControl
   247 		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
   248 		m.Complete(r,ETrue);
   249 		}
   250 	}
   251 
   252 /**
   253   Process synchronous 'control' requests
   254 */
   255 TInt DDriver1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
   256 	{
   257 	(void)a2;   // a2 not used in this example
   258 
   259 	TInt r;
   260 
   261 	switch (aFunction)
   262 		{
   263 		case RDriver1::EGetConfig:
   264 			r = GetConfig((TDes8*)a1);
   265 			break;
   266 
   267 		case RDriver1::ESetConfig:
   268 			r = SetConfig((const TDesC8*)a1);
   269 			break;
   270 
   271 		default:
   272 			r = KErrNotSupported;
   273 			break;
   274 		}
   275 
   276 	return r;
   277 	}
   278 
   279 /**
   280   Process asynchronous requests.
   281 */
   282 TInt DDriver1Channel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
   283 	{
   284 	(void)a2;   // a2 not used in this example
   285 
   286 	TInt r;
   287 
   288 	switch(aReqNo)
   289 		{
   290 		case RDriver1::ESendData:
   291 			r=SendData(aStatus,(const TDesC8*)a1);
   292 			break;
   293 
   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);
   299 			else
   300 				r=KErrPermissionDenied;
   301 			break;
   302 
   303 		default:
   304 			r = KErrNotSupported;
   305 			break;
   306 		}
   307 
   308 	return r;
   309 	}
   310 
   311 /**
   312   Process cancelling of asynchronous requests.
   313 */
   314 void DDriver1Channel::DoCancel(TUint aMask)
   315 	{
   316 	if(aMask&(1<<RDriver1::ESendData))
   317 		SendDataCancel();
   318 	if(aMask&(1<<RDriver1::EReceiveData))
   319 		ReceiveDataCancel();
   320 	}
   321 
   322 //
   323 // Methods for processing configuration control messages
   324 //
   325 
   326 /**
   327   Process a GetConfig control message. This writes the current driver configuration to a
   328   RDriver1::TConfigBuf supplied by the client.
   329 */
   330 TInt DDriver1Channel::GetConfig(TDes8* aConfigBuf)
   331 	{
   332 	// Create a structure giving the current configuration
   333 	RDriver1::TConfig config;
   334 	CurrentConfig(config);
   335 
   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);
   339 	}
   340 
   341 /**
   342   Process a SetConfig control message. This sets the driver configuration using a
   343   RDriver1::TConfigBuf supplied by the client.
   344 */
   345 TInt DDriver1Channel::SetConfig(const TDesC8* aConfigBuf)
   346 	{
   347 	// Don't allow configuration changes whilst we're busy
   348 	if(iSendDataStatus || iReceiveDataStatus)
   349 		return KErrInUse;
   350 
   351 	// Create a config structure.
   352 	RDriver1::TConfig config;
   353 	CurrentConfig(config);
   354 
   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.
   358 
   359 	// Read the config structure from client
   360 	TPtr8 ptr((TUint8*)&config,sizeof(config));
   361 	TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
   362 	if(r!=KErrNone)
   363 		return r;
   364 
   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())
   368 		return KErrArgument;
   369 
   370 	if(config.iMaxSendDataSize && config.iMaxSendDataSize!=iSendDataBuffer.MaxSize())
   371 		return KErrArgument;
   372 
   373 	if(config.iMaxReceiveDataSize && config.iMaxReceiveDataSize!=iReceiveDataBuffer.MaxSize())
   374 		return KErrArgument;
   375 
   376 	r=Pdd()->SetSpeed(config.iSpeed);
   377 	if(r!=KErrNone)
   378 		return r;
   379 
   380 	return r;
   381 	}
   382 
   383 /**
   384   Fill a TConfig with the drivers current configuration.
   385 */
   386 void DDriver1Channel::CurrentConfig(RDriver1::TConfig& aConfig)
   387 	{
   388 	aConfig.iSpeed = Pdd()->Speed();
   389 	aConfig.iPddBufferSize = Pdd()->BufferSize();
   390 	aConfig.iMaxSendDataSize = iSendDataBuffer.MaxSize();
   391 	aConfig.iMaxReceiveDataSize = iReceiveDataBuffer.MaxSize();
   392 	}
   393 
   394 //
   395 // Methods for processing 'SendData'
   396 //
   397 
   398 /**
   399   Start processing a SendData request.
   400 */
   401 TInt DDriver1Channel::SendData(TRequestStatus* aStatus,const TDesC8* aData)
   402 	{
   403 	// Check that a 'SendData' isn't already in progress
   404 	if(iSendDataStatus)
   405 		{
   406 		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
   407 		return KErrInUse;
   408 		}
   409 
   410 	// Read data from client into our buffer
   411 	TInt r=Kern::ThreadDesRead(iClient,aData,iSendDataBuffer,0);
   412 	if(r!=KErrNone)
   413 		return r;
   414 
   415 	// Give data to PDD so that it can do the work
   416 	r=Pdd()->SendData(iSendDataBuffer);
   417 	if(r!=KErrNone)
   418 		return r;
   419 
   420 	// Save the client request status and return
   421 	iSendDataStatus = aStatus;
   422 	return KErrNone;
   423 	}
   424 
   425 /**
   426   Cancel a SendData request.
   427 */
   428 void DDriver1Channel::SendDataCancel()
   429 	{
   430 	if(iSendDataStatus)
   431 		{
   432 		// Tell PDD to stop processing the request
   433 		Pdd()->SendDataCancel();
   434 		// Cancel DFC
   435 		iSendDataDfc.Cancel();
   436 		// Complete clients request
   437 		Kern::RequestComplete(iClient,iSendDataStatus,KErrCancel);
   438 		}
   439 	}
   440 
   441 /**
   442   Called by PDD from ISR to indicate that a SendData operation has completed.
   443 */
   444 void DDriver1Channel::SendDataComplete(TInt aResult)
   445 	{
   446 	// Save result code
   447 	iSendDataResult = aResult;
   448 	// Queue DFC
   449 	iSendDataDfc.Add();
   450 	}
   451 
   452 /**
   453   DFC callback which gets triggered after the PDD has signalled that SendData completed.
   454   This just casts aPtr and calls DoSendDataComplete().
   455 */
   456 void DDriver1Channel::SendDataDfc(TAny* aPtr)
   457 	{
   458 	((DDriver1Channel*)aPtr)->DoSendDataComplete();
   459 	}
   460 
   461 /**
   462   Called from a DFC after the PDD has signalled that SendData completed.
   463 */
   464 void DDriver1Channel::DoSendDataComplete()
   465 	{
   466 	TInt result = iSendDataResult;
   467 	// Complete clients request
   468 	Kern::RequestComplete(iClient,iSendDataStatus,result);
   469 	}
   470 
   471 //
   472 // Methods for processing 'ReceiveData'
   473 //
   474 
   475 /**
   476   Start processing a ReceiveData request.
   477 */
   478 TInt DDriver1Channel::ReceiveData(TRequestStatus* aStatus,TDes8* aPtr)
   479 	{
   480 	// Check that a 'ReceiveData' isn't already in progress
   481 	if(iReceiveDataStatus)
   482 		{
   483 		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
   484 		return KErrInUse;
   485 		}
   486 
   487 	// Ask PDD for data
   488 	TInt r=Pdd()->ReceiveData(iReceiveDataBuffer);
   489 	if(r!=KErrNone)
   490 		return r;
   491 
   492 	// Save the client request status and descriptor before returning
   493 	iReceiveDataStatus = aStatus;
   494 	iReceiveDataDescriptor = aPtr;
   495 	return KErrNone;
   496 	}
   497 
   498 /**
   499   Cancel a ReceiveData request.
   500 */
   501 void DDriver1Channel::ReceiveDataCancel()
   502 	{
   503 	if(iReceiveDataStatus)
   504 		{
   505 		// Tell PDD to stop processing the request
   506 		Pdd()->ReceiveDataCancel();
   507 		// Cancel DFC
   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);
   513 		}
   514 	}
   515 
   516 /**
   517   Called by PDD from ISR to indicate that a ReceiveData operation has completed.
   518 */
   519 void DDriver1Channel::ReceiveDataComplete(TInt aResult)
   520 	{
   521 	// Save result code
   522 	iReceiveDataResult = aResult;
   523 	// Queue DFC
   524 	iReceiveDataDfc.Add();
   525 	}
   526 
   527 /**
   528   DFC Callback which gets triggered after the PDD has signalled that ReceiveData completed.
   529   This just casts aPtr and calls DoReceiveDataComplete().
   530 */
   531 void DDriver1Channel::ReceiveDataDfc(TAny* aPtr)
   532 	{
   533 	((DDriver1Channel*)aPtr)->DoReceiveDataComplete();
   534 	}
   535 
   536 /**
   537   Called from a DFC after the PDD has signalled that ReceiveData completed.
   538 */
   539 void DDriver1Channel::DoReceiveDataComplete()
   540 	{
   541 	// Write data to client from our buffer
   542 	TInt result=Kern::ThreadDesWrite(iClient,iReceiveDataDescriptor,iReceiveDataBuffer,0);
   543 
   544 	// Finished with client descriptor, so NULL it to help detect coding errors
   545 	iReceiveDataDescriptor = NULL;
   546 
   547 	// Use result code from PDD if it was an error
   548 	if(iReceiveDataResult!=KErrNone)
   549 		result = iReceiveDataResult;
   550 
   551 	// Complete clients request
   552 	Kern::RequestComplete(iClient,iReceiveDataStatus,result);
   553 	}
   554