os/kernelhwsrv/kerneltest/e32test/demandpaging/d_pagingexample_2_post.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2008-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 // e32\e32test\demandpaging\d_pagingexample_2_post.cpp
    15 // Demand paging migration example device driver d_pagingexample_2_post: a
    16 // DLogicalChannelBase-dervied driver, post-migration
    17 // 
    18 //
    19 
    20 #include "d_pagingexample.h"
    21 #include <kernel/kernel.h>
    22 #include <kernel/kern_priv.h>
    23 
    24 const TInt KDfcQThreadPriority = 25;
    25 const TInt KBufferSize = KMaxTransferSize;
    26 
    27 //
    28 // Logical channel
    29 //
    30 
    31 class DExampleChannel : public DLogicalChannelBase
    32 	{
    33 public:
    34 	typedef RPagingExample::TConfigData TConfigData;
    35 	typedef RPagingExample::TValueStruct TValueStruct;
    36 public:
    37 	DExampleChannel();
    38 	~DExampleChannel();
    39 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
    40 	virtual TInt Request(TInt aReqNo, TAny* a1, TAny* a2);
    41 	TInt DoControl(TInt aFunction, TAny* a1, TAny* a2);
    42 	TInt DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2);
    43 	TInt DoCancel(TUint aMask);
    44 private:
    45  	TDfcQue* DfcQ();
    46 	void Shutdown();
    47 	void GetConfig(TConfigData&);
    48 	void SetConfig(const TConfigData&);
    49 	TInt StartNotify(TRequestStatus* aStatus);
    50 	TInt StartAsyncGetValue(TInt* aValue, TRequestStatus* aStatus);
    51 	TInt StartAsyncGetValue2(TInt* aValue1, TInt* aValue2, TRequestStatus* aStatus);
    52 	TInt StartRead(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus);
    53 	TInt StartReadDes(TDes8* aDesOut, TRequestStatus* aStatus);
    54 	TInt StartWrite(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus);
    55 	TInt StartWriteDes(const TDesC8* aDesIn, TRequestStatus* aStatus);
    56 	void ReceiveToReadBuffer();
    57 	void SendFromWriteBuffer();
    58 	static void CancelDfcFunc(TAny* aPtr);
    59 	static void AsyncGetValueCompleteDfcFunc(TAny* aPtr);
    60 	static void AsyncGetValue2CompleteDfcFunc(TAny* aPtr);
    61 	static void ReceiveCompleteDfcFunc(TAny* aPtr);
    62 	static void SendCompleteDfcFunc(TAny* aPtr);
    63 	void CompleteNotify();
    64 	void CompleteAsyncGetValue();
    65 	void CompleteAsyncGetValue2();
    66 	void CompleteRead();
    67 	void CompleteWrite();
    68 	void Cancel();
    69 private:
    70 	NFastMutex iLock;
    71 	TDynamicDfcQue* iDynamicDfcQ;
    72 	TConfigData iConfig;
    73 	DThread* iClient;
    74 	TDfc iCancelDfc;
    75 	
    76 	// Notify
    77 	TClientRequest* iNotifyRequest;
    78 	
    79 	// Async get value
    80 	TClientDataRequest<TValueStruct>* iAsyncGetValueRequest;
    81 	NTimer iAsyncGetValueTimer;
    82 	TDfc iAsyncGetValueDfc;
    83 
    84 	// Async get value
    85 	TClientDataRequest2<TInt,TInt>* iAsyncGetValue2Request;
    86 	NTimer iAsyncGetValue2Timer;
    87 	TDfc iAsyncGetValue2Dfc;
    88 
    89 	// Read
    90 	TClientBufferRequest* iReadRequest;
    91 	NTimer iReadTimer;
    92 	TClientBuffer* iClientReadBuffer;
    93 	TDfc iCompleteReadDfc;
    94 	
    95 	// Write
    96 	TClientBufferRequest* iWriteRequest;
    97 	NTimer iWriteTimer;
    98 	TClientBuffer* iClientWriteBuffer;
    99 	TDfc iCompleteWriteDfc;
   100 	TUint8 iBuffer[KBufferSize];
   101 	};
   102 
   103 DExampleChannel::DExampleChannel() :
   104 	iCancelDfc(CancelDfcFunc, this, 0),
   105 	iAsyncGetValueTimer(NULL, this),
   106 	iAsyncGetValueDfc(AsyncGetValueCompleteDfcFunc, this, 0),
   107 	iAsyncGetValue2Timer(NULL, this),
   108 	iAsyncGetValue2Dfc(AsyncGetValue2CompleteDfcFunc, this, 0),
   109 	iReadTimer(NULL, this),
   110 	iCompleteReadDfc(ReceiveCompleteDfcFunc, this, 0),
   111 	iWriteTimer(NULL, this),
   112 	iCompleteWriteDfc(SendCompleteDfcFunc, this, 0)
   113 	{
   114 	iClient = &Kern::CurrentThread();
   115 	iClient->Open();
   116 	}
   117 
   118 DExampleChannel::~DExampleChannel()
   119 	{
   120 	Kern::SafeClose((DObject*&)iClient, NULL);
   121 	if (iDynamicDfcQ)
   122 		iDynamicDfcQ->Destroy();
   123 	Kern::DestroyClientRequest(iNotifyRequest);
   124 	Kern::DestroyClientRequest(iAsyncGetValueRequest);
   125 	Kern::DestroyClientRequest(iAsyncGetValue2Request);
   126 	Kern::DestroyClientBufferRequest(iReadRequest);
   127 	Kern::DestroyClientBufferRequest(iWriteRequest);
   128 	}
   129 
   130 TDfcQue* DExampleChannel::DfcQ()
   131 	{
   132 	return iDynamicDfcQ;
   133 	}
   134 
   135 TInt DExampleChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
   136 	{
   137 	TInt r;
   138 	
   139 	r = Kern::CreateClientRequest(iNotifyRequest);
   140 	if (r != KErrNone)
   141 		return r;
   142 	r = Kern::CreateClientDataRequest(iAsyncGetValueRequest);
   143 	if (r != KErrNone)
   144 		return r;
   145 	r = Kern::CreateClientDataRequest2(iAsyncGetValue2Request);
   146 	if (r != KErrNone)
   147 		return r;
   148 	r = Kern::CreateClientBufferRequest(iWriteRequest, 1, TClientBufferRequest::EPinVirtual);
   149 	if (r != KErrNone)
   150 		return r;
   151 	
   152 	// create a dynamic DFC queue, which is used for handling client messages and for our own DFCs
   153 	r = Kern::DynamicDfcQCreate(iDynamicDfcQ, KDfcQThreadPriority, KPagingExample1PostLdd);
   154 	if (r != KErrNone)
   155 		return r;
   156 
   157 	// todo: this will be the default anyway
   158 	iDynamicDfcQ->SetRealtimeState(ERealtimeStateOn);
   159 	
   160 	iCancelDfc.SetDfcQ(DfcQ());
   161 	iAsyncGetValueDfc.SetDfcQ(DfcQ());
   162 	iAsyncGetValue2Dfc.SetDfcQ(DfcQ());
   163 	iCompleteReadDfc.SetDfcQ(DfcQ());
   164 	iCompleteWriteDfc.SetDfcQ(DfcQ());
   165 	return KErrNone;
   166 	}
   167 
   168 TInt DExampleChannel::Request(TInt aReqNo, TAny* a1, TAny* a2)
   169 	{
   170 	TInt r = KErrNone;
   171 	if (&Kern::CurrentThread() != iClient)
   172 		r = KErrAccessDenied;  // we only support one client
   173 	else if (aReqNo==KMaxTInt)
   174 		{
   175 		// DoCancel
   176 		r = DoCancel((TInt)a1);
   177 		}
   178     else if (aReqNo<0)
   179 		{
   180 		// DoRequest
   181 		TRequestStatus* pS=(TRequestStatus*)a1;
   182 		TAny* array[2] = { NULL, NULL };
   183 		kumemget32(array, a2, 2 * sizeof(TAny*));
   184 		r = DoRequest(~aReqNo, pS, array[0], array[1]);
   185 		if(r != KErrNone)
   186 			Kern::RequestComplete(pS, r);
   187 		r = KErrNone;
   188 		}
   189     else
   190 		{
   191 		// DoControl
   192 		r = DoControl(aReqNo, a1, a2);
   193 		}
   194 	return r;
   195 	}
   196 
   197 TInt DExampleChannel::DoControl(TInt aFunction,TAny* a1,TAny* /*a2*/)
   198 	{
   199 	TInt r = KErrNone;
   200 	TConfigData configBuffer;
   201 	switch (aFunction)
   202 		{
   203 		case RPagingExample::EGetConfig:
   204 			GetConfig(configBuffer);
   205 			umemput32(a1, (TAny*)&configBuffer, sizeof(TConfigData));
   206 			break;
   207 
   208 		case RPagingExample::ESetConfig:
   209 			umemget32(&configBuffer, a1, sizeof(TConfigData));
   210 			SetConfig(configBuffer);
   211 			break;
   212 
   213 		default:
   214 			r = KErrNotSupported;
   215 		}
   216 	return r;
   217 	}
   218 
   219 TInt DExampleChannel::DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2)
   220 	{
   221 	TInt r = KErrNotSupported;
   222 	switch (aFunction)
   223 		{
   224 		case RPagingExample::ERequestNotify:
   225 			r = StartNotify(aStatus);
   226 			break;
   227 			
   228 		case RPagingExample::ERequestAsyncGetValue:
   229 			r = StartAsyncGetValue((TInt*)a1, aStatus);
   230 			break;
   231 			
   232 		case RPagingExample::ERequestAsyncGetValue2:
   233 			r = StartAsyncGetValue2((TInt*)a1, (TInt*)a2, aStatus);
   234 			break;
   235 			
   236 		case RPagingExample::ERequestRead:
   237 			r = StartRead(a1, (TInt)a2, aStatus);
   238 			break;
   239 			
   240 		case RPagingExample::ERequestReadDes:
   241 			r = StartReadDes((TDes8*)a1, aStatus);
   242 			break;
   243 
   244 		case RPagingExample::ERequestWrite:
   245 			r = StartWrite(a1, (TInt)a2, aStatus);
   246 			break;
   247 			
   248 		case RPagingExample::ERequestWriteDes:
   249 			r = StartWriteDes((TDes8*)a1, aStatus);
   250 			break;
   251 		}
   252 	return r;
   253 	}
   254 
   255 TInt DExampleChannel::DoCancel(TUint /*aMask*/)
   256 	{
   257 	iCancelDfc.Enque();
   258 	return KErrNone;
   259 	}
   260 
   261 void DExampleChannel::CancelDfcFunc(TAny* aPtr)
   262 	{
   263 	DExampleChannel* self = (DExampleChannel*)aPtr;
   264 	self->Cancel();
   265 	}
   266 
   267 void DExampleChannel::Cancel()
   268 	{
   269 	if (iAsyncGetValueRequest->IsReady())
   270 		{
   271 		iAsyncGetValueTimer.Cancel();
   272 		iAsyncGetValueDfc.Cancel();
   273 		Kern::QueueRequestComplete(iClient, iAsyncGetValueRequest, KErrCancel);
   274 		}
   275 	
   276 	if (iAsyncGetValue2Request->IsReady())
   277 		{
   278 		iAsyncGetValue2Timer.Cancel();
   279 		iAsyncGetValue2Dfc.Cancel();
   280 		Kern::QueueRequestComplete(iClient, iAsyncGetValue2Request, KErrCancel);
   281 		}
   282 
   283 	if (iReadRequest && iReadRequest->IsReady())
   284 		{
   285 		iReadTimer.Cancel();
   286 		iCompleteReadDfc.Cancel();
   287 		Kern::QueueBufferRequestComplete(iClient, iReadRequest, KErrCancel);
   288 		Kern::DestroyClientBufferRequest(iReadRequest);
   289 		}
   290 
   291 	if (iWriteRequest->IsReady())
   292 		{
   293 		iWriteTimer.Cancel();
   294 		iCompleteWriteDfc.Cancel();
   295 		Kern::QueueBufferRequestComplete(iClient, iWriteRequest, KErrCancel);
   296 		}
   297 	}
   298 
   299 void DExampleChannel::Shutdown()
   300 	{
   301 	}
   302 
   303 void DExampleChannel::GetConfig(TConfigData& aConfigOut)
   304 	{
   305 	NKern::FMWait(&iLock);
   306 	aConfigOut = iConfig;
   307 	NKern::FMSignal(&iLock);
   308 	}
   309 
   310 void DExampleChannel::SetConfig(const TConfigData& aNewConfig)
   311 	{
   312 	NKern::FMWait(&iLock);
   313 	iConfig = aNewConfig;
   314 	NKern::FMSignal(&iLock);
   315 	}
   316 
   317 TInt DExampleChannel::StartNotify(TRequestStatus* aStatus)
   318 	{
   319 	// example implementation completes the request immediately
   320 	TInt r = iNotifyRequest->SetStatus(aStatus);
   321 	if (r != KErrNone)
   322 		return r;
   323 	CompleteNotify(); // example implementation completes the request immediately
   324 	return KErrNone;
   325 	}
   326 
   327 void DExampleChannel::CompleteNotify()
   328 	{
   329 	Kern::QueueRequestComplete(iClient, iNotifyRequest, KErrNone);
   330 	}
   331 
   332 TInt DExampleChannel::StartAsyncGetValue(TInt* aValue, TRequestStatus* aStatus)
   333 	{
   334 	// use of TClientDataRequest API protected by fast mutex
   335 	NKern::FMWait(&iLock);
   336 	TInt r = iAsyncGetValueRequest->SetStatus(aStatus);
   337 	if (r == KErrNone)
   338 		iAsyncGetValueRequest->SetDestPtr(aValue);
   339 	NKern::FMSignal(&iLock);
   340 	if (r != KErrNone)
   341 		return r;
   342 
   343 	// queue a timer to simulate an asynchronous operation
   344 	iAsyncGetValueTimer.OneShot(KAsyncDelay, iAsyncGetValueDfc);
   345 	return KErrNone;
   346 	}
   347 
   348 void DExampleChannel::AsyncGetValueCompleteDfcFunc(TAny* aPtr)
   349 	{
   350 	DExampleChannel* self = (DExampleChannel*)aPtr;
   351 	self->CompleteAsyncGetValue();
   352 	}
   353 
   354 void DExampleChannel::CompleteAsyncGetValue()
   355 	{
   356 	// use of TClientDataRequest API protected by fast mutex
   357 	NKern::FMWait(&iLock);
   358 	if (iAsyncGetValueRequest->IsReady())
   359 		{
   360 		iAsyncGetValueRequest->Data().iValue1 = 1;
   361 		iAsyncGetValueRequest->Data().iValue2 = _L8("shrt");
   362 		Kern::QueueRequestComplete(iClient, iAsyncGetValueRequest, KErrNone);
   363 		}
   364 	NKern::FMSignal(&iLock);
   365 	}
   366 
   367 TInt DExampleChannel::StartAsyncGetValue2(TInt* aValue1, TInt* aValue2, TRequestStatus* aStatus)
   368 	{
   369 	// use of TClientDataRequest API protected by fast mutex
   370 	NKern::FMWait(&iLock);
   371 	TInt r = iAsyncGetValue2Request->SetStatus(aStatus);
   372 	if (r == KErrNone)
   373 		iAsyncGetValue2Request->SetDestPtr1(aValue1);
   374 	if (r == KErrNone)
   375 		iAsyncGetValue2Request->SetDestPtr2(aValue2);
   376 	NKern::FMSignal(&iLock);
   377 	if (r != KErrNone)
   378 		return r;
   379 
   380 	// queue a timer to simulate an asynchronous operation
   381 	iAsyncGetValue2Timer.OneShot(KAsyncDelay, iAsyncGetValue2Dfc);
   382 	return KErrNone;
   383 	}
   384 
   385 void DExampleChannel::AsyncGetValue2CompleteDfcFunc(TAny* aPtr)
   386 	{
   387 	DExampleChannel* self = (DExampleChannel*)aPtr;
   388 	self->CompleteAsyncGetValue2();
   389 	}
   390 
   391 void DExampleChannel::CompleteAsyncGetValue2()
   392 	{
   393 	// use of TClientDataRequest API protected by fast mutex
   394 	NKern::FMWait(&iLock);
   395 	if (iAsyncGetValue2Request->IsReady())
   396 		{
   397 		iAsyncGetValue2Request->Data1() = 1;
   398 		iAsyncGetValue2Request->Data2() = 2;
   399 		Kern::QueueRequestComplete(iClient, iAsyncGetValue2Request, KErrNone);
   400 		}
   401 	NKern::FMSignal(&iLock);
   402 	}
   403 
   404 TInt DExampleChannel::StartRead(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus)
   405 	{
   406 	// check length argument first
   407 	if (aLength < 1 || aLength > KBufferSize)
   408 		return KErrArgument;
   409 
   410 	// normally drivers would pre-create a TClientBufferRequest where possible, but here we create
   411 	// one on demand to test this possibilty
   412 	NKern::ThreadEnterCS();
   413 	TInt r = Kern::CreateClientBufferRequest(iReadRequest, 1, TClientBufferRequest::EPinVirtual);
   414 	NKern::ThreadLeaveCS();  // iReadRequest is deleted by the destructor
   415 	if (r != KErrNone)
   416 		return r;
   417 
   418 	// start request setup
   419 	r = iReadRequest->StartSetup(aStatus);
   420 	if (r != KErrNone)
   421 		return r;
   422 	
   423 	// add client buffer, this does pinning in context of client thread
   424 	r = iReadRequest->AddBuffer(iClientReadBuffer, (TLinAddr)aBuffer, aLength, ETrue);
   425 	if (r != KErrNone)
   426 		return KErrNoMemory;
   427 
   428 	iReadRequest->EndSetup();
   429 	
   430 	ReceiveToReadBuffer();
   431 	return KErrNone;
   432 	}
   433 
   434 TInt DExampleChannel::StartReadDes(TDes8* aDesOut, TRequestStatus* aStatus)
   435 	{
   436 	// normally drivers would pre-create a TClientBufferRequest where possible, but here we create
   437 	// one on demand to test this possibilty
   438 	NKern::ThreadEnterCS();
   439 	TInt r = Kern::CreateClientBufferRequest(iReadRequest, 1, TClientBufferRequest::EPinVirtual);
   440 	NKern::ThreadLeaveCS();  // iReadRequest is deleted by the destructor
   441 	if (r != KErrNone)
   442 		return r;
   443 	
   444 	// start request setup
   445 	r = iReadRequest->StartSetup(aStatus);
   446 	if (r != KErrNone)
   447 		return r;
   448 
   449 	// add client descriptor, this does pinning in context of client thread
   450 	r = iReadRequest->AddBuffer(iClientReadBuffer, aDesOut);
   451 	if (r != KErrNone)
   452 		return r;
   453 
   454 	// can check length argument here
   455 	TInt length = iClientReadBuffer->MaxLength();
   456 	if (length < 1 || length > KBufferSize)
   457 		{
   458 		// need to reset object so it can be reused
   459 		iReadRequest->Reset();
   460 		return KErrArgument;
   461 		}
   462 
   463 	iReadRequest->EndSetup();	
   464 
   465 	ReceiveToReadBuffer();
   466 	return KErrNone;
   467 	}
   468 
   469 TInt DExampleChannel::StartWrite(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus)
   470 	{
   471 	// check length argument first
   472 	if (aLength < 1 || aLength > KBufferSize)
   473 		return KErrArgument;
   474 
   475 	// demonstrate use the single-buffer version of Setup
   476 	TInt r = iWriteRequest->Setup(iClientWriteBuffer, aStatus, (TLinAddr)aBuffer, aLength);
   477 	if (r != KErrNone)
   478 		return r;
   479 
   480 	SendFromWriteBuffer();
   481 	return KErrNone;
   482 	}
   483 
   484 TInt DExampleChannel::StartWriteDes(const TDesC8* aDesIn, TRequestStatus* aStatus)
   485 	{
   486 	// demonstrate use the single-buffer version of Setup
   487 	TInt r = iWriteRequest->Setup(iClientWriteBuffer, aStatus, (TAny*)aDesIn);
   488 	if (r != KErrNone)
   489 		return r;
   490 
   491 	// can check length argument here
   492 	TInt length = iClientWriteBuffer->Length();
   493 	if (length < 1 || length > KBufferSize)
   494 		{
   495 		// need to reset object so it can be reused
   496 		iWriteRequest->Reset();
   497 		return KErrArgument;
   498 		}
   499 	
   500 	SendFromWriteBuffer();
   501 	return KErrNone;
   502 	}
   503 
   504 void DExampleChannel::ReceiveToReadBuffer()
   505 	{
   506 	// just queue a timer to simulate an asynchronous receive operation
   507 	// actually will return the previous contents of the buffer
   508 	NKern::FMWait(&iLock);
   509 	// The synchonisation is for illustrative purposes only - in a real driver we might make use of
   510 	// the configution here, so this would need to be protected from concurrent modification.
   511 	NKern::FMSignal(&iLock);
   512 	iReadTimer.OneShot(KAsyncDelay, iCompleteReadDfc);
   513 	}
   514 
   515 void DExampleChannel::SendFromWriteBuffer()
   516 	{
   517 	// just queue a timer to simulate an asynchronous send operation
   518 	NKern::FMWait(&iLock);
   519 	// The synchonisation is for illustrative purposes only - in a real driver we might make use of
   520 	// the configution here, so this would need to be protected from concurrent modification.
   521 	NKern::FMSignal(&iLock);
   522 	iWriteTimer.OneShot(KAsyncDelay, iCompleteWriteDfc);
   523 	}
   524 
   525 void DExampleChannel::ReceiveCompleteDfcFunc(TAny* aPtr)
   526 	{
   527 	DExampleChannel* self = (DExampleChannel*)aPtr;
   528 	self->CompleteRead();
   529 	}
   530 
   531 void DExampleChannel::SendCompleteDfcFunc(TAny* aPtr)
   532 	{
   533 	DExampleChannel* self = (DExampleChannel*)aPtr;
   534 	self->CompleteWrite();
   535 	}
   536 
   537 void DExampleChannel::CompleteRead()
   538 	{
   539 	TPtrC8 des(iBuffer, iClientReadBuffer->MaxLength());
   540 	TInt r = Kern::ThreadBufWrite(iClient, iClientReadBuffer, des, 0, KChunkShiftBy0, iClient);
   541 	Kern::QueueBufferRequestComplete(iClient, iReadRequest, r);
   542 	Kern::DestroyClientBufferRequest(iReadRequest);
   543 	}
   544 
   545 void DExampleChannel::CompleteWrite()
   546 	{
   547 	TPtr8 des(iBuffer, iClientWriteBuffer->Length());
   548 	TInt r = Kern::ThreadBufRead(iClient, iClientWriteBuffer, des, 0, KChunkShiftBy0);
   549 	Kern::QueueBufferRequestComplete(iClient, iWriteRequest, r);
   550 	}
   551 
   552 //
   553 // Logical device
   554 //
   555 
   556 class DExampleFactory : public DLogicalDevice
   557 	{
   558 public:
   559 	DExampleFactory();
   560 	virtual TInt Install();
   561 	virtual void GetCaps(TDes8& aDes) const;
   562 	virtual TInt Create(DLogicalChannelBase*& aChannel);
   563 	};
   564 
   565 DExampleFactory::DExampleFactory()
   566 	{
   567 	iParseMask = 0;
   568 	iVersion = TVersion(1, 0, 0);
   569 	}
   570 
   571 TInt DExampleFactory::Install()
   572 	{
   573 	return SetName(&KPagingExample2PostLdd);
   574 	}
   575 
   576 void DExampleFactory::GetCaps(TDes8& /*aDes*/) const
   577 	{
   578 	// not used but required as DLogicalDevice::GetCaps is pure virtual
   579 	}
   580 
   581 TInt DExampleFactory::Create(DLogicalChannelBase*& aChannel)
   582 	{
   583 	aChannel = new DExampleChannel;
   584 	return aChannel ? KErrNone : KErrNoMemory;
   585 	}
   586 
   587 DECLARE_STANDARD_LDD()
   588 	{
   589 	return new DExampleFactory;
   590 	}