os/kernelhwsrv/kerneltest/e32test/demandpaging/d_pagingexample_1_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_1_post.cpp
    15 // Demand paging migration example device driver d_pagingexample_1_post: a DLogicalChannel-dervied
    16 // 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 DLogicalChannel
    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 SendMsg(TMessageBase* aMsg);
    41 	TInt SendControl(TMessageBase* aMsg);
    42 	TInt SendRequest(TMessageBase* aMsg);
    43 	virtual void HandleMsg(TMessageBase* aMsg);
    44 	TInt DoControl(TInt aFunction, TAny* a1, TAny* a2);
    45 	void DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2);
    46 	TInt DoCancel(TUint aMask);
    47 private:
    48 	TDfcQue* DfcQ();
    49 	void Shutdown();
    50 	void SetConfig(const TConfigData&);
    51 	TInt PreNotify(TRequestStatus* aStatus);
    52 	void StartNotify();
    53 	TInt PreAsyncGetValue(TInt* aValue, TRequestStatus* aStatus);
    54 	void StartAsyncGetValue();
    55 	TInt PreAsyncGetValue2(TInt* aValue1, TInt* aValue2, TRequestStatus* aStatus);
    56 	void StartAsyncGetValue2();
    57 	TInt PreRead(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus);
    58 	void StartRead();
    59 	TInt PreReadDes(TDes8* aDesOut, TRequestStatus* aStatus);
    60 	void StartReadDes();
    61 	TInt PreWrite(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus);
    62 	void StartWrite();
    63 	TInt PreWriteDes(const TDesC8* aDesIn, TRequestStatus* aStatus);
    64 	void StartWriteDes();
    65 	void ReceiveToReadBuffer();
    66 	void SendFromWriteBuffer();
    67 	static void AsyncGetValueCompleteDfcFunc(TAny* aPtr);
    68 	static void AsyncGetValue2CompleteDfcFunc(TAny* aPtr);
    69 	static void ReceiveCompleteDfcFunc(TAny* aPtr);
    70 	static void SendCompleteDfcFunc(TAny* aPtr);
    71 	void CompleteNotify();
    72 	void CompleteAsyncGetValue();
    73 	void CompleteAsyncGetValue2();
    74 	void CompleteRead();
    75 	void CompleteWrite();
    76 private:
    77 	TDynamicDfcQue* iDynamicDfcQ;
    78 	TConfigData iConfig;
    79 	DThread* iClient;
    80 	
    81 	// Notify
    82 	TClientRequest* iNotifyRequest;
    83 	
    84 	// Async get value
    85 	TClientDataRequest<TValueStruct>* iAsyncGetValueRequest;
    86 	NTimer iAsyncGetValueTimer;
    87 	TDfc iAsyncGetValueDfc;
    88 	
    89 	// Async get value 2
    90 	TClientDataRequest2<TInt,TInt>* iAsyncGetValue2Request;
    91 	NTimer iAsyncGetValue2Timer;
    92 	TDfc iAsyncGetValue2Dfc;
    93 	
    94 	// Read
    95 	TClientBufferRequest* iReadRequest;
    96 	NTimer iReadTimer;
    97 	TClientBuffer* iClientReadBuffer;
    98 	TDfc iCompleteReadDfc;
    99 	
   100 	// Write
   101 	TClientBufferRequest* iWriteRequest;
   102 	NTimer iWriteTimer;
   103 	TClientBuffer* iClientWriteBuffer;
   104 	TDfc iCompleteWriteDfc;
   105 	TUint8 iBuffer[KBufferSize];
   106 	};
   107 
   108 DExampleChannel::DExampleChannel() :
   109 	iAsyncGetValueTimer(NULL, this),
   110 	iAsyncGetValueDfc(AsyncGetValueCompleteDfcFunc, this, 0),
   111 	iAsyncGetValue2Timer(NULL, this),
   112 	iAsyncGetValue2Dfc(AsyncGetValue2CompleteDfcFunc, this, 0),
   113 	iReadTimer(NULL, this),
   114 	iCompleteReadDfc(ReceiveCompleteDfcFunc, this, 0),
   115 	iWriteTimer(NULL, this),
   116 	iCompleteWriteDfc(SendCompleteDfcFunc, this, 0)
   117 	{
   118 	iClient = &Kern::CurrentThread();
   119 	iClient->Open();
   120 	}
   121 
   122 DExampleChannel::~DExampleChannel()
   123 	{
   124 	Kern::SafeClose((DObject*&)iClient, NULL);
   125 	if (iDynamicDfcQ)
   126 		iDynamicDfcQ->Destroy();
   127 	Kern::DestroyClientRequest(iNotifyRequest);
   128 	Kern::DestroyClientRequest(iAsyncGetValueRequest);
   129 	Kern::DestroyClientRequest(iAsyncGetValue2Request);
   130 	Kern::DestroyClientBufferRequest(iReadRequest);
   131 	Kern::DestroyClientBufferRequest(iWriteRequest);
   132 	}
   133 
   134 TDfcQue* DExampleChannel::DfcQ()
   135 	{
   136 	return iDynamicDfcQ;
   137 	}
   138 
   139 TInt DExampleChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
   140 	{
   141 	TInt r;
   142 	
   143 	r = Kern::CreateClientRequest(iNotifyRequest);
   144 	if (r != KErrNone)
   145 		return r;
   146 	r = Kern::CreateClientDataRequest(iAsyncGetValueRequest);
   147 	if (r != KErrNone)
   148 		return r;
   149 	r = Kern::CreateClientDataRequest2(iAsyncGetValue2Request);
   150 	if (r != KErrNone)
   151 		return r;
   152 	r = Kern::CreateClientBufferRequest(iReadRequest, 1, TClientBufferRequest::EPinVirtual);
   153 	if (r != KErrNone)
   154 		return r;
   155 	r = Kern::CreateClientBufferRequest(iWriteRequest, 1, TClientBufferRequest::EPinVirtual);
   156 	if (r != KErrNone)
   157 		return r;
   158 	
   159 	// create a dynamic DFC queue, which is used for handling client messages and for our own DFCs
   160 	r = Kern::DynamicDfcQCreate(iDynamicDfcQ, KDfcQThreadPriority, KPagingExample1PostLdd);
   161 	if (r != KErrNone)
   162 		return r;
   163 
   164 	// todo: this will be the default anyway
   165 	iDynamicDfcQ->SetRealtimeState(ERealtimeStateOn);
   166 	
   167 	SetDfcQ(DfcQ());
   168 	iAsyncGetValueDfc.SetDfcQ(DfcQ());
   169 	iAsyncGetValue2Dfc.SetDfcQ(DfcQ());
   170 	iCompleteReadDfc.SetDfcQ(DfcQ());
   171 	iCompleteWriteDfc.SetDfcQ(DfcQ());
   172 	iMsgQ.Receive();
   173 	return KErrNone;
   174 	}
   175 
   176 // override SendMsg method to allow pinning data in the context of the client thread
   177 TInt DExampleChannel::SendMsg(TMessageBase* aMsg)
   178 	{
   179 	TThreadMessage& m=*(TThreadMessage*)aMsg;
   180     TInt id = m.iValue;
   181 
   182 	// we only support one client
   183 	if (id != (TInt)ECloseMsg && m.Client() != iClient)
   184 		return KErrAccessDenied;
   185 	
   186 	TInt r = KErrNone;
   187 	if (id != (TInt)ECloseMsg && id != KMaxTInt)
   188 		{
   189 		if (id<0)
   190 			{
   191 			TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
   192 			r = SendRequest(aMsg);
   193 			if (r != KErrNone)
   194 				Kern::RequestComplete(pS,r);
   195 			}
   196 		else
   197 			r = SendControl(aMsg);
   198 		}
   199 	else
   200 		r = DLogicalChannel::SendMsg(aMsg);
   201 	
   202 	return r;
   203 	}
   204 
   205 void DExampleChannel::HandleMsg(TMessageBase* aMsg)
   206 	{
   207 	TThreadMessage& m=*(TThreadMessage*)aMsg;
   208     TInt id=m.iValue;
   209 	
   210 	if (id==(TInt)ECloseMsg)
   211 		{
   212 		Shutdown();
   213 		m.Complete(KErrNone,EFalse);
   214 		return;
   215 		}
   216     else if (id==KMaxTInt)
   217 		{
   218 		// DoCancel
   219 		DoCancel(m.Int0());
   220 		m.Complete(KErrNone,ETrue);
   221 		return;
   222 		}
   223     else if (id<0)
   224 		{
   225 		// DoRequest
   226 		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
   227 		DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
   228 		m.Complete(KErrNone,ETrue);
   229 		}
   230     else
   231 		{
   232 		// DoControl
   233 		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
   234 		m.Complete(r,ETrue);
   235 		}
   236 	}
   237 	
   238 TInt DExampleChannel::SendControl(TMessageBase* aMsg)
   239 	{
   240 	TThreadMessage& m=*(TThreadMessage*)aMsg;
   241     TInt id=m.iValue;
   242 
   243 	// thread-local copy of configuration data
   244 	TConfigData kernelConfigBuffer;
   245 	TAny* userConfigPtr = m.Ptr0();
   246 	
   247 	switch (id)
   248 		{
   249 		case RPagingExample::ESetConfig:
   250 			// copy config from client to local buffer in context of client thread
   251 			umemget32(&kernelConfigBuffer, userConfigPtr, sizeof(TConfigData));
   252 			// update message to point to kernel-side buffer
   253 			m.iArg[0] = &kernelConfigBuffer;
   254 			break;
   255 			
   256 		case RPagingExample::EGetConfig:
   257 			// update message to point to kernel-side buffer
   258 			m.iArg[0] = &kernelConfigBuffer;
   259 			break;
   260 		}
   261 
   262 	TInt r = DLogicalChannel::SendMsg(aMsg);
   263 	if (r != KErrNone)
   264 		return r;
   265 
   266 	switch (id)
   267 		{
   268 		case RPagingExample::EGetConfig:
   269 			// copy config from local bufferto client in context of client thread
   270 			umemput32(userConfigPtr, &kernelConfigBuffer, sizeof(TConfigData));
   271 			break;
   272 		}
   273 
   274 	return r;
   275 	}
   276 
   277 TInt DExampleChannel::DoControl(TInt aFunction,TAny* a1,TAny* /*a2*/)
   278 	{
   279 	TInt r = KErrNone;
   280 	TConfigData* configBuffer = (TConfigData*)a1;
   281 	switch (aFunction)
   282 		{
   283 		case RPagingExample::EGetConfig:
   284 			// copy current config into local buffer in context of DFC thread to avoid potential race conditions
   285 			*configBuffer = iConfig;
   286 			break;
   287 
   288 		case RPagingExample::ESetConfig:
   289 			// set config from copy in local buffer in context of DFC thread to avoid potential race conditions
   290 			SetConfig(*configBuffer);
   291 			break;
   292 
   293 		default:
   294 			r = KErrNotSupported;
   295 		}
   296 	return r;
   297 	}
   298 
   299 TInt DExampleChannel::SendRequest(TMessageBase* aMsg)
   300 	{
   301 	TThreadMessage& m=*(TThreadMessage*)aMsg;
   302     TInt function = ~m.iValue;
   303 	TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
   304 	TAny* a1 = m.Ptr1();
   305 	TAny* a2 = m.Ptr2();
   306 		
   307 	TInt r = KErrNotSupported;
   308 	switch (function)
   309 		{
   310 		case RPagingExample::ERequestNotify:
   311 			r = PreNotify(pS);
   312 			break;
   313 
   314 		case RPagingExample::ERequestAsyncGetValue:
   315 			r = PreAsyncGetValue((TInt*)a1, pS);
   316 			break;
   317 
   318 		case RPagingExample::ERequestAsyncGetValue2:
   319 			r = PreAsyncGetValue2((TInt*)a1, (TInt*)a2, pS);
   320 			break;
   321 			
   322 		case RPagingExample::ERequestRead:
   323 			r = PreRead(a1, (TInt)a2, pS);
   324 			break;
   325 			
   326 		case RPagingExample::ERequestReadDes:
   327 			r = PreReadDes((TDes8*)a1, pS);
   328 			break;
   329 
   330 		case RPagingExample::ERequestWrite:
   331 			r = PreWrite(a1, (TInt)a2, pS);
   332 			break;
   333 			
   334 		case RPagingExample::ERequestWriteDes:
   335 			r = PreWriteDes((TDes8*)a1, pS);
   336 			break;
   337 		}
   338 
   339 	if (r == KErrNone)
   340 		r = DLogicalChannel::SendMsg(aMsg);
   341 	return r;
   342 	}
   343 
   344 void DExampleChannel::DoRequest(TInt aFunction, TRequestStatus* /*aStatus*/, TAny* /*a1*/, TAny* /*a2*/)
   345 	{
   346 	switch (aFunction)
   347 		{
   348 		case RPagingExample::ERequestNotify:
   349 			StartNotify();
   350 			break;
   351 			
   352 		case RPagingExample::ERequestAsyncGetValue:
   353 			StartAsyncGetValue();
   354 			break;
   355 			
   356 		case RPagingExample::ERequestAsyncGetValue2:
   357 			StartAsyncGetValue2();
   358 			break;
   359 			
   360 		case RPagingExample::ERequestRead:
   361 			StartRead();
   362 			break;
   363 			
   364 		case RPagingExample::ERequestReadDes:
   365 			StartReadDes();
   366 			break;
   367 
   368 		case RPagingExample::ERequestWrite:
   369 			StartWrite();
   370 			break;
   371 			
   372 		case RPagingExample::ERequestWriteDes:
   373 			StartWriteDes();
   374 			break;
   375 
   376 		default:
   377 			__NK_ASSERT_ALWAYS(EFalse);  // we already validated the request number
   378 		}
   379 	}
   380 
   381 TInt DExampleChannel::DoCancel(TUint /*aMask*/)
   382 	{
   383 	if (iAsyncGetValueRequest->IsReady())	
   384 		{
   385 		iAsyncGetValueTimer.Cancel();
   386 		iAsyncGetValueDfc.Cancel();
   387 		Kern::QueueRequestComplete(iClient, iAsyncGetValueRequest, KErrCancel);
   388 		}
   389 	
   390 	if (iAsyncGetValue2Request->IsReady())
   391 		{
   392 		iAsyncGetValue2Timer.Cancel();
   393 		iAsyncGetValue2Dfc.Cancel();
   394 		Kern::QueueRequestComplete(iClient, iAsyncGetValue2Request, KErrCancel);
   395 		}
   396 	
   397 	if (iReadRequest->IsReady())
   398 		{
   399 		iReadTimer.Cancel();
   400 		iCompleteReadDfc.Cancel();
   401 		Kern::QueueBufferRequestComplete(iClient, iReadRequest, KErrCancel);
   402 		}
   403 	
   404 	if (iWriteRequest->IsReady())
   405 		{
   406 		iWriteTimer.Cancel();
   407 		iCompleteWriteDfc.Cancel();
   408 		Kern::QueueBufferRequestComplete(iClient, iWriteRequest, KErrCancel);
   409 		}
   410 	
   411 	return KErrNone;
   412 	}
   413 
   414 void DExampleChannel::Shutdown()
   415 	{
   416 	}
   417 
   418 void DExampleChannel::SetConfig(const TConfigData& aNewConfig)
   419 	{
   420 	iConfig = aNewConfig;
   421 	}
   422 
   423 TInt DExampleChannel::PreNotify(TRequestStatus* aStatus)
   424 	{
   425 	return iNotifyRequest->SetStatus(aStatus);
   426 	}
   427 
   428 void DExampleChannel::StartNotify()
   429 	{
   430 	CompleteNotify(); // example implementation completes the request immediately
   431 	}
   432 
   433 void DExampleChannel::CompleteNotify()
   434 	{
   435 	Kern::QueueRequestComplete(iClient, iNotifyRequest, KErrNone);
   436 	}
   437 
   438 TInt DExampleChannel::PreAsyncGetValue(TInt* aValue, TRequestStatus* aStatus)
   439 	{
   440 	TInt r = iAsyncGetValueRequest->SetStatus(aStatus);
   441 	if (r != KErrNone)
   442 		return r;
   443 	iAsyncGetValueRequest->SetDestPtr(aValue);
   444 	return KErrNone;
   445 	}
   446 
   447 void DExampleChannel::StartAsyncGetValue()
   448 	{
   449 	// queue a timer to simulate an asynchronous operation
   450 	iAsyncGetValueTimer.OneShot(KAsyncDelay, iAsyncGetValueDfc);
   451 	}
   452 
   453 void DExampleChannel::AsyncGetValueCompleteDfcFunc(TAny* aPtr)
   454 	{
   455 	DExampleChannel* self = (DExampleChannel*)aPtr;
   456 	self->CompleteAsyncGetValue();
   457 	}
   458 
   459 void DExampleChannel::CompleteAsyncGetValue()
   460 	{
   461 	iAsyncGetValueRequest->Data().iValue1 = 1;
   462 	iAsyncGetValueRequest->Data().iValue2 = _L8("shrt");
   463 	Kern::QueueRequestComplete(iClient, iAsyncGetValueRequest, KErrNone);
   464 	}
   465 
   466 TInt DExampleChannel::PreAsyncGetValue2(TInt* aValue1, TInt* aValue2, TRequestStatus* aStatus)
   467 	{
   468 	TInt r = iAsyncGetValue2Request->SetStatus(aStatus);
   469 	if (r != KErrNone)
   470 		return r;
   471 	iAsyncGetValue2Request->SetDestPtr1(aValue1);
   472 	iAsyncGetValue2Request->SetDestPtr2(aValue2);
   473 	return KErrNone;
   474 	}
   475 
   476 void DExampleChannel::StartAsyncGetValue2()
   477 	{
   478 	// queue a timer to simulate an asynchronous operation
   479 	iAsyncGetValue2Timer.OneShot(KAsyncDelay, iAsyncGetValue2Dfc);
   480 	}
   481 
   482 void DExampleChannel::AsyncGetValue2CompleteDfcFunc(TAny* aPtr)
   483 	{
   484 	DExampleChannel* self = (DExampleChannel*)aPtr;
   485 	self->CompleteAsyncGetValue2();
   486 	}
   487 
   488 void DExampleChannel::CompleteAsyncGetValue2()
   489 	{
   490 	iAsyncGetValue2Request->Data1() = 1;
   491 	iAsyncGetValue2Request->Data2() = 2;
   492 	Kern::QueueRequestComplete(iClient, iAsyncGetValue2Request, KErrNone);
   493 	}
   494 
   495 TInt DExampleChannel::PreRead(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus)
   496 	{
   497 	// check length argument first
   498 	if (aLength < 1 || aLength > KBufferSize)
   499 		return KErrArgument;
   500 
   501 	// start request setup
   502 	TInt r = iReadRequest->StartSetup(aStatus);
   503 	if (r != KErrNone)
   504 		return r;
   505 	
   506 	// add client buffer, this does pinning in context of client thread
   507 	r = iReadRequest->AddBuffer(iClientReadBuffer, (TLinAddr)aBuffer, aLength, ETrue);
   508 	if (r != KErrNone)
   509 		return KErrNoMemory;
   510 
   511 	iReadRequest->EndSetup();
   512 	return KErrNone;
   513 	}
   514 
   515 void DExampleChannel::StartRead()
   516 	{	
   517 	ReceiveToReadBuffer(); // called in DFC thread as may require serialised access to hardware
   518 	}
   519 
   520 TInt DExampleChannel::PreReadDes(TDes8* aDesOut, TRequestStatus* aStatus)
   521 	{
   522 	// start request setup
   523 	TInt r = iReadRequest->StartSetup(aStatus);
   524 	if (r != KErrNone)
   525 		return r;
   526 
   527 	// add client descriptor, this does pinning in context of client thread
   528 	r = iReadRequest->AddBuffer(iClientReadBuffer, aDesOut);
   529 	if (r != KErrNone)
   530 		return r;
   531 
   532 	// can check length argument here
   533 	TInt length = iClientReadBuffer->MaxLength();
   534 	if (length < 1 || length > KBufferSize)
   535 		{
   536 		// need to reset object so it can be reused
   537 		iReadRequest->Reset();
   538 		return KErrArgument;
   539 		}
   540 
   541 	iReadRequest->EndSetup();	
   542 	return KErrNone;
   543 	}
   544 
   545 void DExampleChannel::StartReadDes()
   546 	{
   547 	ReceiveToReadBuffer(); // called in DFC thread as may require serialised access to hardware
   548 	}
   549 
   550 TInt DExampleChannel::PreWrite(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus)
   551 	{
   552 	// check length argument first
   553 	if (aLength < 1 || aLength > KBufferSize)
   554 		return KErrArgument;
   555 
   556 	// demonstrate use the single-buffer version of Setup
   557 	return iWriteRequest->Setup(iClientWriteBuffer, aStatus, (TLinAddr)aBuffer, aLength);
   558 	}
   559 
   560 void DExampleChannel::StartWrite()
   561 	{
   562 	SendFromWriteBuffer(); // called in DFC thread as may require serialised access to hardware
   563 	}
   564 
   565 TInt DExampleChannel::PreWriteDes(const TDesC8* aDesIn, TRequestStatus* aStatus)
   566 	{
   567 	// demonstrate use the single-buffer version of Setup
   568 	TInt r = iWriteRequest->Setup(iClientWriteBuffer, aStatus, (TAny*)aDesIn);
   569 	if (r != KErrNone)
   570 		return r;
   571 
   572 	// can check length argument here
   573 	TInt length = iClientWriteBuffer->Length();
   574 	if (length < 1 || length > KBufferSize)
   575 		{
   576 		// need to reset object so it can be reused
   577 		iWriteRequest->Reset();
   578 		return KErrArgument;
   579 		}
   580 	
   581 	return KErrNone;
   582 	}
   583 
   584 void DExampleChannel::StartWriteDes()
   585 	{
   586 	SendFromWriteBuffer(); // called in DFC thread as may require serialised access to hardware
   587 	}
   588 
   589 void DExampleChannel::ReceiveToReadBuffer()
   590 	{
   591 	// just queue a timer to simulate an asynchronous receive operation
   592 	// actually will return the previous contents of the buffer
   593 	iReadTimer.OneShot(KAsyncDelay, iCompleteReadDfc);
   594 	}
   595 
   596 void DExampleChannel::SendFromWriteBuffer()
   597 	{
   598 	// just queue a timer to simulate an asynchronous send operation
   599 	iWriteTimer.OneShot(KAsyncDelay, iCompleteWriteDfc);
   600 	}
   601 
   602 void DExampleChannel::ReceiveCompleteDfcFunc(TAny* aPtr)
   603 	{
   604 	DExampleChannel* self = (DExampleChannel*)aPtr;
   605 	self->CompleteRead();
   606 	}
   607 
   608 void DExampleChannel::SendCompleteDfcFunc(TAny* aPtr)
   609 	{
   610 	DExampleChannel* self = (DExampleChannel*)aPtr;
   611 	self->CompleteWrite();
   612 	}
   613 
   614 void DExampleChannel::CompleteRead()
   615 	{
   616 	TPtrC8 des(iBuffer, iClientReadBuffer->MaxLength());
   617 	TInt r = Kern::ThreadBufWrite(iClient, iClientReadBuffer, des, 0, KChunkShiftBy0, iClient);
   618 	Kern::QueueBufferRequestComplete(iClient, iReadRequest, r);
   619 	}
   620 
   621 void DExampleChannel::CompleteWrite()
   622 	{
   623 	TPtr8 des(iBuffer, iClientWriteBuffer->Length());
   624 	TInt r = Kern::ThreadBufRead(iClient, iClientWriteBuffer, des, 0, KChunkShiftBy0);
   625 	Kern::QueueBufferRequestComplete(iClient, iWriteRequest, r);
   626 	}
   627 
   628 //
   629 // Logical device
   630 //
   631 
   632 class DExampleFactory : public DLogicalDevice
   633 	{
   634 public:
   635 	DExampleFactory();
   636 	virtual TInt Install();
   637 	virtual void GetCaps(TDes8& aDes) const;
   638 	virtual TInt Create(DLogicalChannelBase*& aChannel);
   639 	};
   640 
   641 DExampleFactory::DExampleFactory()
   642 	{
   643 	iParseMask = 0;
   644 	iVersion = TVersion(1, 0, 0);
   645 	}
   646 
   647 TInt DExampleFactory::Install()
   648 	{
   649 	return SetName(&KPagingExample1PostLdd);
   650 	}
   651 
   652 void DExampleFactory::GetCaps(TDes8& /*aDes*/) const
   653 	{
   654 	// not used but required as DLogicalDevice::GetCaps is pure virtual
   655 	}
   656 
   657 TInt DExampleFactory::Create(DLogicalChannelBase*& aChannel)
   658 	{
   659 	aChannel = new DExampleChannel;
   660 	return aChannel ? KErrNone : KErrNoMemory;
   661 	}
   662 
   663 DECLARE_STANDARD_LDD()
   664 	{
   665 	return new DExampleFactory;
   666 	}