commsfwutils/commsbufs/reference/zerocopy_loopback_driver/ldd.cpp
changeset 0 dfb7c4ff071f
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 1999-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 "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 #include <kernel/kern_priv.h>
       
    17 
       
    18 #ifdef SYMBIAN_OLD_EXPORT_LOCATION
       
    19 #include <comms-infras/zerocopy_loopback_driver.h>
       
    20 #else
       
    21 //this header is not exported, needs to be a user include
       
    22 #include "zerocopy_loopback_driver.h"
       
    23 #endif
       
    24 
       
    25 #include "device.h"
       
    26 #include <comms-infras/commsbufpond.h>
       
    27 
       
    28 
       
    29 _LIT(KZeroCopyLoopbackPanicCategory,"ZeroCopyLoopback");
       
    30 
       
    31 
       
    32 /**
       
    33   Standard export function for LDDs. This creates a DLogicalDevice derived object,
       
    34   in this case, our DZeroCopyLoopbackFactory
       
    35 */
       
    36 DECLARE_STANDARD_LDD()
       
    37 	{
       
    38 	return new DZeroCopyLoopbackFactory;
       
    39 	}
       
    40 
       
    41 /**
       
    42   Constructor
       
    43 */
       
    44 DZeroCopyLoopbackFactory::DZeroCopyLoopbackFactory()
       
    45 	{
       
    46 	// Set version number for this device
       
    47 	iVersion=RZeroCopyLoopbackDriver::VersionRequired();
       
    48 	// Indicate that we work with a PDD
       
    49 	iParseMask=KDeviceAllowPhysicalDevice;
       
    50 	}
       
    51 
       
    52 
       
    53 /**
       
    54   Second stage constructor for DZeroCopyLoopbackFactory.
       
    55   This must at least set a name for the driver object.
       
    56 
       
    57   @return KErrNone if successful, otherwise one of the other system wide error codes.
       
    58 */
       
    59 TInt DZeroCopyLoopbackFactory::Install()
       
    60 	{
       
    61 	return SetName(&RZeroCopyLoopbackDriver::Name());
       
    62 	}
       
    63 
       
    64 DZeroCopyLoopbackFactory::~DZeroCopyLoopbackFactory()
       
    65    	{
       
    66    	}
       
    67 
       
    68 /**
       
    69   Return the drivers capabilities.
       
    70   Called in the response to an RDevice::GetCaps() request.
       
    71 
       
    72   @param aDes User-side descriptor to write capabilities information into
       
    73 */
       
    74 void DZeroCopyLoopbackFactory::GetCaps(TDes8& aDes) const
       
    75 	{
       
    76 	// Create a capabilities object
       
    77 	RZeroCopyLoopbackDriver::TCaps caps;
       
    78 	caps.iVersion = iVersion;
       
    79 	// Write it back to user memory
       
    80 	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
       
    81 	}
       
    82 
       
    83 /**
       
    84   Called by the kernel's device driver framework to create a Logical Channel.
       
    85   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
       
    86   (E.g. through a call to RBusLogicalChannel::DoCreate)
       
    87   The thread is in a critical section.
       
    88 
       
    89   @param aChannel Set to point to the created Logical Channel
       
    90 
       
    91   @return KErrNone if successful, otherwise one of the other system wide error codes.
       
    92 */
       
    93 TInt DZeroCopyLoopbackFactory::Create(DLogicalChannelBase*& aChannel)
       
    94 	{
       
    95 	aChannel=new DZeroCopyLoopbackChannel;
       
    96 	if(!aChannel)
       
    97 		return KErrNoMemory;
       
    98 
       
    99 	return KErrNone;
       
   100 	}
       
   101 
       
   102 DZeroCopyLoopbackChannel::DZeroCopyLoopbackChannel()
       
   103 	:	iSendDataDfc(SendDataDfc, this, 1),        // DFC is priority '1'
       
   104 		iReceiveDataDfc(ReceiveDataDfc, this, 1)   // DFC is priority '1'
       
   105 	{
       
   106 	// Get pointer to client threads DThread object
       
   107 	iClient=&Kern::CurrentThread();
       
   108 
       
   109 	// Open a reference on client thread so it's control block can't dissapear until
       
   110 	// this driver has finished with it.
       
   111 	// Note, this call to Open can't fail since its the thread we are currently running in
       
   112 	iClient->Open();
       
   113 	memclr(&iDebugProbes, sizeof(iDebugProbes));
       
   114 	Kern::Printf("clearing probe points\n");
       
   115 	}
       
   116 
       
   117 /**
       
   118   Second stage constructor called by the kernel's device driver framework.
       
   119   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
       
   120   (E.g. through a call to RBusLogicalChannel::DoCreate)
       
   121   The thread is in a critical section.
       
   122 
       
   123   @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
       
   124   @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
       
   125   @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
       
   126 
       
   127   @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   128 */
       
   129 TInt DZeroCopyLoopbackChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
       
   130 	{
       
   131 	// Check Platform Security capabilities of client thread (if required).
       
   132 	//
       
   133 	// Here we handle the simple case where:
       
   134 	// 1. The device driver can only have one client thread
       
   135 	// 2. The security policy is the binary all-or-nothing policy.
       
   136 	//    E.g. "If you have the right capability you can do anything with the driver
       
   137 	//    and if you don't have the capability you can't do anything"
       
   138 	// 
       
   139 	// If only some functionality of the driver is restricted, then the security check should
       
   140 	// go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
       
   141 	// shouldn't be used because the 'current thread' isn't the client.
       
   142 	//
       
   143 	// In this example we do a check here for ECapability_None (which always passes)...
       
   144 	if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by zerocopy loopback")))
       
   145 		return KErrPermissionDenied;
       
   146 
       
   147 	// Check version
       
   148 	if (!Kern::QueryVersionSupported(RZeroCopyLoopbackDriver::VersionRequired(),aVer))
       
   149 		return KErrNotSupported;
       
   150 
       
   151 	// Setup LDD for receiving client messages
       
   152 	SetDfcQ(((DZeroCopyLoopbackPddFactory*)iPhysicalDevice)->iDfcQ);
       
   153 	iMsgQ.Receive();
       
   154 
       
   155 	// Associate DFCs with the same queue we set above to receive client messages on
       
   156 	iSendDataDfc.SetDfcQ(iDfcQ);
       
   157 	iReceiveDataDfc.SetDfcQ(iDfcQ);
       
   158 
       
   159 	iPond = DCommsPond::New();
       
   160 	if(!iPond)
       
   161 		{
       
   162 		return KErrNoMemory;
       
   163 		}
       
   164 	
       
   165 	// Give PDD a pointer to this channel
       
   166 	Pdd()->iLdd = this;
       
   167 
       
   168 	// Done
       
   169 	return KErrNone;
       
   170 	}
       
   171 
       
   172 #define PRINT_PROBE_POINTS(name) \
       
   173 	{\
       
   174 	Kern::Printf("probe list:%s\n\t", name); \
       
   175 	for(TInt i = 0; i < (sizeof(iDebugProbes) / sizeof(TInt)); i++)\
       
   176 		{ \
       
   177 		Kern::Printf("%d:%d, ", i, iDebugProbes[i]); \
       
   178 		} \
       
   179 	Kern::Printf("\n\n"); \
       
   180 	}
       
   181 
       
   182 #define PROBE_LDD(index) (iDebugProbes[index]++)
       
   183 #define PROBE_LDD_STATIC(index, obj) (((obj)->iDebugProbes[index])++)
       
   184 
       
   185 DZeroCopyLoopbackChannel::~DZeroCopyLoopbackChannel()
       
   186 	{
       
   187 	// Cancel all processing that we may be doing
       
   188 	DoCancel(RZeroCopyLoopbackDriver::EAllRequests);
       
   189 	
       
   190 	delete iPond;
       
   191 	
       
   192 	// Close our reference on the client thread
       
   193 	Kern::SafeClose((DObject*&)iClient,NULL);
       
   194 	}
       
   195 
       
   196 /**
       
   197   Called when a user thread requests a handle to this channel.
       
   198 */
       
   199 TInt DZeroCopyLoopbackChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
       
   200 	{
       
   201 	// Make sure that only our client can get a handle
       
   202 	if (aType!=EOwnerThread || aThread!=iClient)
       
   203 		return KErrAccessDenied;
       
   204 	return KErrNone;
       
   205 	}
       
   206 
       
   207 /**
       
   208   Process a message for this logical channel.
       
   209   This function is called in the context of a DFC thread.
       
   210 
       
   211   @param aMessage The message to process.
       
   212 	              The iValue member of this distinguishes the message type:
       
   213 	              iValue==ECloseMsg, channel close message
       
   214 	              iValue==KMaxTInt, a 'DoCancel' message
       
   215 	              iValue>=0, a 'DoControl' message with function number equal to iValue
       
   216 	              iValue<0, a 'DoRequest' message with function number equal to ~iValue
       
   217 */
       
   218 void DZeroCopyLoopbackChannel::HandleMsg(TMessageBase* aMsg)
       
   219 	{
       
   220 	TThreadMessage& m=*(TThreadMessage*)aMsg;
       
   221 
       
   222 	// Get message type
       
   223 	TInt id=m.iValue;
       
   224 
       
   225 	// Decode the message type and dispatch it to the relevent handler function...
       
   226 
       
   227 	if (id==(TInt)ECloseMsg)
       
   228 		{
       
   229 		// Channel Close
       
   230 		PRINT_PROBE_POINTS("ldd");
       
   231 		DoCancel(RZeroCopyLoopbackDriver::EAllRequests);
       
   232 		m.Complete(KErrNone, EFalse);
       
   233 		return;
       
   234 		}
       
   235 
       
   236 	if (id==KMaxTInt)
       
   237 		{
       
   238 		// DoCancel
       
   239 		DoCancel(m.Int0());
       
   240 		m.Complete(KErrNone,ETrue);
       
   241 		return;
       
   242 		}
       
   243 
       
   244 	if (id<0)
       
   245 		{
       
   246 		// DoRequest
       
   247 		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
       
   248 		TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
       
   249 		if (r!=KErrNone)
       
   250 			{
       
   251 			Kern::RequestComplete(iClient,pS,r);
       
   252 			}
       
   253 		m.Complete(KErrNone,ETrue);
       
   254 		}
       
   255 	else
       
   256 		{
       
   257 		// DoControl
       
   258 		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
       
   259 		m.Complete(r,ETrue);
       
   260 		}
       
   261 	}
       
   262 
       
   263 /**
       
   264   Process synchronous 'control' requests
       
   265 */
       
   266 TInt DZeroCopyLoopbackChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
       
   267 	{
       
   268 	(void)a2;   // a2 not used in this example
       
   269 
       
   270 	TInt r;
       
   271 
       
   272 	switch (aFunction)
       
   273 		{
       
   274 		case RZeroCopyLoopbackDriver::EGetConfig:
       
   275 			r = GetConfig((TDes8*)a1);
       
   276 			break;
       
   277 
       
   278 		case RZeroCopyLoopbackDriver::ESetConfig:
       
   279 			r = SetConfig((const TDesC8*)a1);
       
   280 			break;
       
   281 
       
   282 		case RZeroCopyLoopbackDriver::ELoadPond:
       
   283 			r = LoadPond((TPondTransferBuf*)a1);
       
   284 			break;
       
   285 		
       
   286 		case RZeroCopyLoopbackDriver::EUnloadPond:
       
   287 			r = UnloadPond();
       
   288 			break;
       
   289 		
       
   290 		default:
       
   291 			r = KErrNotSupported;
       
   292 			break;
       
   293 		}
       
   294 
       
   295 	return r;
       
   296 	}
       
   297 
       
   298 /**
       
   299   Process asynchronous requests.
       
   300 */
       
   301 TInt DZeroCopyLoopbackChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
       
   302 	{
       
   303 	(void)a2;   // a2 not used in this example
       
   304 
       
   305 	TInt r;
       
   306 
       
   307 	switch(aReqNo)
       
   308 		{
       
   309 		case RZeroCopyLoopbackDriver::ESendData_ByZeroCopy:
       
   310 			r = SendData(aStatus, (TInt)a1);
       
   311 			break;
       
   312 
       
   313 		case RZeroCopyLoopbackDriver::EReceiveData_ByZeroCopy:
       
   314 			// Example Platform Security capability check which tests the
       
   315 			// client for ECapability_None (which always passes)...
       
   316 			if(iClient->HasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by zerocopy loopback")))
       
   317 				r = ReceiveData(aStatus, (TInt*)a1);
       
   318 			else
       
   319 				r = KErrPermissionDenied;
       
   320 			break;
       
   321 
       
   322 		default:
       
   323 			r = KErrNotSupported;
       
   324 			break;
       
   325 		}
       
   326 
       
   327 	return r;
       
   328 	}
       
   329 
       
   330 /**
       
   331   Process cancelling of asynchronous requests.
       
   332 */
       
   333 void DZeroCopyLoopbackChannel::DoCancel(TUint aMask)
       
   334 	{
       
   335 	if(aMask&(1<<RZeroCopyLoopbackDriver::ESendData))
       
   336 		SendDataCancel();
       
   337 	if(aMask&(1<<RZeroCopyLoopbackDriver::EReceiveData))
       
   338 		ReceiveDataCancel();
       
   339 	}
       
   340 
       
   341 /**
       
   342   Process a GetConfig control message. This writes the current driver configuration to a
       
   343   RZeroCopyLoopbackDriver::TConfigBuf supplied by the client.
       
   344 */
       
   345 TInt DZeroCopyLoopbackChannel::GetConfig(TDes8* aConfigBuf)
       
   346 	{
       
   347 	// Create a structure giving the current configuration
       
   348 	RZeroCopyLoopbackDriver::TConfig config;
       
   349 	CurrentConfig(config);
       
   350 
       
   351 	// Write the config to the client
       
   352 	TPtrC8 ptr((const TUint8*)&config,sizeof(config));
       
   353 	return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL);
       
   354 	}
       
   355 
       
   356 /**
       
   357   Process a SetConfig control message. This sets the driver configuration using a
       
   358   RZeroCopyLoopbackDriver::TConfigBuf supplied by the client.
       
   359 */
       
   360 TInt DZeroCopyLoopbackChannel::SetConfig(const TDesC8* aConfigBuf)
       
   361 	{
       
   362 	// Don't allow configuration changes whilst we're busy
       
   363 	if(iSendDataStatus || iReceiveDataStatus)
       
   364 		return KErrInUse;
       
   365 
       
   366 	// Create a config structure.
       
   367 	RZeroCopyLoopbackDriver::TConfig config;
       
   368 	CurrentConfig(config);
       
   369 
       
   370 	// Note: We have filled config with the current settings, this is to allow
       
   371 	// backwards compatibility when a client gives us an old (and shorter) version
       
   372 	// of the config structure.
       
   373 
       
   374 	// Read the config structure from client
       
   375 	TPtr8 ptr((TUint8*)&config,sizeof(config));
       
   376 	TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
       
   377 	if(r!=KErrNone)
       
   378 		return r;
       
   379 
       
   380 	// Use config data to setup the driver. Checking that parameters which aren't settable
       
   381 	// either contain the correct values or are zero (meaning 'default')
       
   382 	if(config.iPddBufferSize && config.iPddBufferSize!=Pdd()->BufferSize())
       
   383 		return KErrArgument;
       
   384 
       
   385 	if(config.iMaxSendDataSize && config.iMaxSendDataSize!=KLoopbackMTU)
       
   386 		return KErrArgument;
       
   387 
       
   388 	if(config.iMaxReceiveDataSize && config.iMaxReceiveDataSize!=KLoopbackMTU)
       
   389 		return KErrArgument;
       
   390 
       
   391 	r=Pdd()->SetSpeed(config.iSpeed);
       
   392 	if(r!=KErrNone)
       
   393 		return r;
       
   394 
       
   395 	return r;
       
   396 	}
       
   397 
       
   398 /**
       
   399 @purpose Create a local pond with a flattened description passed from the client
       
   400 @param aPond The pond in a descriptor form
       
   401 */
       
   402 TInt DZeroCopyLoopbackChannel::LoadPond(TPondTransferBuf* aPond)
       
   403 	{
       
   404 	// Load the local pond with the flattened representation of it
       
   405 	TInt r = iPond->Load(*aPond, iClient);
       
   406 	if(r != KErrNone)
       
   407 		{
       
   408 		return r;
       
   409 		}
       
   410 	
       
   411 	// Now seems like the right time to set the default allocation pool
       
   412 	r = iPond->SetDefaultAllocPool(KLoopbackMTU);
       
   413 	if (r != KErrNone)
       
   414 		{
       
   415 		iPond->Unload();
       
   416 		return r;
       
   417 		}
       
   418 	
       
   419 	return KErrNone;
       
   420 	}
       
   421 
       
   422 
       
   423 
       
   424 /**
       
   425 @purpose Unloads the local commsbuf pond
       
   426 */
       
   427 TInt DZeroCopyLoopbackChannel::UnloadPond()
       
   428 	{
       
   429 	__ASSERT_DEBUG(iPond, Kern::ThreadKill(iClient, EExitPanic, 0, KZeroCopyLoopbackPanicCategory));
       
   430 	if(iPond)
       
   431 		{
       
   432 		iPond->Unload();
       
   433 		return KErrNone;
       
   434 		}
       
   435 	else
       
   436 		{
       
   437 		return KErrNotFound;
       
   438 		}
       
   439 	}
       
   440 
       
   441 /**
       
   442   Fill a TConfig with the drivers current configuration.
       
   443 */
       
   444 void DZeroCopyLoopbackChannel::CurrentConfig(RZeroCopyLoopbackDriver::TConfig& aConfig)
       
   445 	{
       
   446 	aConfig.iSpeed = Pdd()->Speed();
       
   447 	aConfig.iPddBufferSize = Pdd()->BufferSize();
       
   448 	aConfig.iMaxSendDataSize = KLoopbackMTU;
       
   449 	aConfig.iMaxReceiveDataSize = KLoopbackMTU;
       
   450 	}
       
   451 
       
   452 /**
       
   453 @purpose Processes a request to send a commsbuf
       
   454 @param aStatus
       
   455 @param aUserHandle Opaque handle to commsbuf to be sent.
       
   456 */
       
   457 TInt DZeroCopyLoopbackChannel::SendData(TRequestStatus* aStatus, TInt aUserHandle)
       
   458 	{
       
   459 	// Check that a 'SendData' isn't already in progress
       
   460 	PROBE_LDD(0);
       
   461 	if(iSendDataStatus)
       
   462 		{
       
   463 		Kern::ThreadKill(iClient, EExitPanic, ERequestAlreadyPending, KZeroCopyLoopbackPanicCategory);
       
   464 		return KErrInUse;
       
   465 		}
       
   466 
       
   467 	// Open the commsbuf received from the user for ourselves - the user side hold on it will be dropped
       
   468 	// We need to provide a kernel private location for the incoming buffer so the current send buffer will do nicely
       
   469 	DCommsBuf* sendBuf = Pdd()->SendBuffer();
       
   470 	if(sendBuf)
       
   471 		{
       
   472 		TInt r = DCommsBuf::AcceptFromClient(iClient, aUserHandle, sendBuf);
       
   473 
       
   474 		// Outbound packet loaded in to the output buffer so can now ask the pdd to send it
       
   475 		if(r == KErrNone)
       
   476 			{
       
   477 			r = Pdd()->RequestDataSend();
       
   478 			if(r != KErrNone)
       
   479 				return r;
       
   480 
       
   481 			// Save the client request status and return
       
   482 			iSendDataStatus = aStatus;
       
   483 			return KErrNone;
       
   484 			}
       
   485 		else
       
   486 			{
       
   487 			return r;
       
   488 			}
       
   489 		}
       
   490 	else
       
   491 		{
       
   492 		// No where to put outbound buffer so can only drop it
       
   493 		DCommsBuf sendBuf;
       
   494 		TInt r = DCommsBuf::AcceptFromClient(iClient, aUserHandle, &sendBuf);
       
   495 		sendBuf.Free();
       
   496 		return KErrNone;
       
   497 		}
       
   498 	}
       
   499 
       
   500 /**
       
   501   Cancel a SendData request.
       
   502 */
       
   503 void DZeroCopyLoopbackChannel::SendDataCancel()
       
   504 	{
       
   505 	if(iSendDataStatus)
       
   506 		{
       
   507 		// Tell PDD to stop processing the request
       
   508 		Pdd()->SendDataCancel();
       
   509 
       
   510 		// Cancel DFC
       
   511 		iSendDataDfc.Cancel();
       
   512 
       
   513 		// Complete clients request
       
   514 		Kern::RequestComplete(iClient,iSendDataStatus,KErrCancel);
       
   515 		}
       
   516 	}
       
   517 
       
   518 /**
       
   519   Called by PDD from ISR to indicate that a SendData operation has completed.
       
   520 */
       
   521 void DZeroCopyLoopbackChannel::SendDataComplete(TInt aResult)
       
   522 	{
       
   523 	PROBE_LDD(2);
       
   524 	// Save result code
       
   525 	iSendDataResult = aResult;
       
   526 
       
   527 	// Queue DFC
       
   528 	iSendDataDfc.Add();
       
   529 	}
       
   530 
       
   531 /**
       
   532   DFC callback which gets triggered after the PDD has signalled that SendData completed.
       
   533   This just casts aPtr and calls DoSendDataComplete().
       
   534 */
       
   535 void DZeroCopyLoopbackChannel::SendDataDfc(TAny* aPtr)
       
   536 	{
       
   537 	PROBE_LDD_STATIC(3, ((DZeroCopyLoopbackChannel*)aPtr));
       
   538 	((DZeroCopyLoopbackChannel*)aPtr)->DoSendDataComplete();
       
   539 	}
       
   540 
       
   541 /**
       
   542   Called from a DFC after the PDD has signalled that SendData completed.
       
   543 */
       
   544 void DZeroCopyLoopbackChannel::DoSendDataComplete()
       
   545 	{
       
   546 	TInt result = iSendDataResult;
       
   547 
       
   548 	// Complete clients request
       
   549 	Kern::RequestComplete(iClient,iSendDataStatus,result);
       
   550 	}
       
   551 
       
   552 /**
       
   553   Start processing a ReceiveData request.
       
   554 */
       
   555 TInt DZeroCopyLoopbackChannel::ReceiveData(TRequestStatus* aStatus, TInt* aRxBufferPtr)
       
   556 	{
       
   557 	PROBE_LDD(4);
       
   558 	// Check that a 'ReceiveData' isn't already in progress
       
   559 	if(iReceiveDataStatus)
       
   560 		{
       
   561 		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KZeroCopyLoopbackPanicCategory);
       
   562 		return KErrInUse;
       
   563 		}
       
   564 
       
   565 	// Save the client request status and descriptor for later completion
       
   566 	iReceiveDataStatus = aStatus;
       
   567 	iReceiveDataDescriptor = aRxBufferPtr;
       
   568 	
       
   569 	if(Pdd()->ReceivedQueueLen() > 0)
       
   570 		{
       
   571 		// complete with waiting data
       
   572 		DoReceiveDataComplete();
       
   573 		}
       
   574 
       
   575 	// Ask PDD for data
       
   576 	NKern::Lock(); 
       
   577 	TInt r = Pdd()->RequestDataReceipt();
       
   578 	NKern::Unlock(); 
       
   579 
       
   580 	if(r != KErrNone)
       
   581 		{
       
   582 		iReceiveDataDescriptor = NULL;
       
   583 		return r;
       
   584 		}
       
   585 
       
   586 	PROBE_LDD(5);
       
   587 	return KErrNone;
       
   588 	}
       
   589 
       
   590 /**
       
   591   Cancel a ReceiveData request.
       
   592 */
       
   593 void DZeroCopyLoopbackChannel::ReceiveDataCancel()
       
   594 	{
       
   595 	if(iReceiveDataStatus)
       
   596 		{
       
   597 		// Tell PDD to stop processing the request
       
   598 		Pdd()->ReceiveDataCancel();
       
   599 
       
   600 		// Cancel DFC
       
   601 		iReceiveDataDfc.Cancel();
       
   602 
       
   603 		// Finished with client descriptor, so NULL it to help detect coding errors
       
   604 		iReceiveDataDescriptor = NULL;
       
   605 
       
   606 		// Complete clients request
       
   607 		Kern::RequestComplete(iClient,iReceiveDataStatus,KErrCancel);
       
   608 		}
       
   609 	}
       
   610 
       
   611 /**
       
   612   Called by PDD from ISR to indicate that a ReceiveData operation has completed.
       
   613 */
       
   614 void DZeroCopyLoopbackChannel::ReceiveDataComplete(TInt aResult)
       
   615 	{
       
   616 	PROBE_LDD(6);
       
   617 	// Save result code
       
   618 	iReceiveDataResult = aResult;
       
   619 
       
   620 	// Queue DFC
       
   621 	NKern::Lock(); 
       
   622 	iReceiveDataDfc.Add();
       
   623 	NKern::Unlock(); 
       
   624 	}
       
   625 
       
   626 /**
       
   627   DFC Callback which gets triggered after the PDD has signalled that ReceiveData completed.
       
   628   This just casts aPtr and calls DoReceiveDataComplete().
       
   629 */
       
   630 void DZeroCopyLoopbackChannel::ReceiveDataDfc(TAny* aPtr)
       
   631 	{
       
   632 	PROBE_LDD_STATIC(7, ((DZeroCopyLoopbackChannel*)aPtr));
       
   633 	((DZeroCopyLoopbackChannel*)aPtr)->DoReceiveDataComplete();
       
   634 	}
       
   635 
       
   636 /**
       
   637   Called from a DFC after the PDD has signalled that ReceiveData completed.
       
   638 */
       
   639 void DZeroCopyLoopbackChannel::DoReceiveDataComplete()
       
   640 	{
       
   641 	if(iReceiveDataStatus)
       
   642 		{
       
   643 		PROBE_LDD(8);
       
   644 
       
   645 		// Fetch the receive buffer. We shouldn't be told to complete rx unless there is data waiting
       
   646 		DCommsBuf* rxBuf = Pdd()->ReceiveBuffer();
       
   647 		__ASSERT_ALWAYS(rxBuf, Kern::Fault("comms loopback", KErrUnderflow));
       
   648 
       
   649 		// Prepare commsbuf for handing to the client and close our reference to it
       
   650 		TInt result;
       
   651 		result = rxBuf->TransferToClient(iClient);
       
   652 		
       
   653 		// If we managed to create a handle for the client
       
   654 		if(result > 0)
       
   655 			{
       
   656 			// Complete client's request (it will carry the handle to the received buffer)
       
   657 			Kern::RequestComplete(iClient, iReceiveDataStatus, result);
       
   658 			}
       
   659 
       
   660 		// Step the receive queue
       
   661 		Pdd()->AdvanceReceiveQueue();
       
   662 		}
       
   663 	}