First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
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
20 #include "d_pagingexample.h"
21 #include <kernel/kernel.h>
22 #include <kernel/kern_priv.h>
24 const TInt KDfcQThreadPriority = 25;
25 const TInt KBufferSize = KMaxTransferSize;
31 class DExampleChannel : public DLogicalChannelBase
34 typedef RPagingExample::TConfigData TConfigData;
35 typedef RPagingExample::TValueStruct TValueStruct;
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);
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();
71 TDynamicDfcQue* iDynamicDfcQ;
77 TClientRequest* iNotifyRequest;
80 TClientDataRequest<TValueStruct>* iAsyncGetValueRequest;
81 NTimer iAsyncGetValueTimer;
82 TDfc iAsyncGetValueDfc;
85 TClientDataRequest2<TInt,TInt>* iAsyncGetValue2Request;
86 NTimer iAsyncGetValue2Timer;
87 TDfc iAsyncGetValue2Dfc;
90 TClientBufferRequest* iReadRequest;
92 TClientBuffer* iClientReadBuffer;
93 TDfc iCompleteReadDfc;
96 TClientBufferRequest* iWriteRequest;
98 TClientBuffer* iClientWriteBuffer;
99 TDfc iCompleteWriteDfc;
100 TUint8 iBuffer[KBufferSize];
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)
114 iClient = &Kern::CurrentThread();
118 DExampleChannel::~DExampleChannel()
120 Kern::SafeClose((DObject*&)iClient, NULL);
122 iDynamicDfcQ->Destroy();
123 Kern::DestroyClientRequest(iNotifyRequest);
124 Kern::DestroyClientRequest(iAsyncGetValueRequest);
125 Kern::DestroyClientRequest(iAsyncGetValue2Request);
126 Kern::DestroyClientBufferRequest(iReadRequest);
127 Kern::DestroyClientBufferRequest(iWriteRequest);
130 TDfcQue* DExampleChannel::DfcQ()
135 TInt DExampleChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
139 r = Kern::CreateClientRequest(iNotifyRequest);
142 r = Kern::CreateClientDataRequest(iAsyncGetValueRequest);
145 r = Kern::CreateClientDataRequest2(iAsyncGetValue2Request);
148 r = Kern::CreateClientBufferRequest(iWriteRequest, 1, TClientBufferRequest::EPinVirtual);
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);
157 // todo: this will be the default anyway
158 iDynamicDfcQ->SetRealtimeState(ERealtimeStateOn);
160 iCancelDfc.SetDfcQ(DfcQ());
161 iAsyncGetValueDfc.SetDfcQ(DfcQ());
162 iAsyncGetValue2Dfc.SetDfcQ(DfcQ());
163 iCompleteReadDfc.SetDfcQ(DfcQ());
164 iCompleteWriteDfc.SetDfcQ(DfcQ());
168 TInt DExampleChannel::Request(TInt aReqNo, TAny* a1, TAny* a2)
171 if (&Kern::CurrentThread() != iClient)
172 r = KErrAccessDenied; // we only support one client
173 else if (aReqNo==KMaxTInt)
176 r = DoCancel((TInt)a1);
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]);
186 Kern::RequestComplete(pS, r);
192 r = DoControl(aReqNo, a1, a2);
197 TInt DExampleChannel::DoControl(TInt aFunction,TAny* a1,TAny* /*a2*/)
200 TConfigData configBuffer;
203 case RPagingExample::EGetConfig:
204 GetConfig(configBuffer);
205 umemput32(a1, (TAny*)&configBuffer, sizeof(TConfigData));
208 case RPagingExample::ESetConfig:
209 umemget32(&configBuffer, a1, sizeof(TConfigData));
210 SetConfig(configBuffer);
214 r = KErrNotSupported;
219 TInt DExampleChannel::DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2)
221 TInt r = KErrNotSupported;
224 case RPagingExample::ERequestNotify:
225 r = StartNotify(aStatus);
228 case RPagingExample::ERequestAsyncGetValue:
229 r = StartAsyncGetValue((TInt*)a1, aStatus);
232 case RPagingExample::ERequestAsyncGetValue2:
233 r = StartAsyncGetValue2((TInt*)a1, (TInt*)a2, aStatus);
236 case RPagingExample::ERequestRead:
237 r = StartRead(a1, (TInt)a2, aStatus);
240 case RPagingExample::ERequestReadDes:
241 r = StartReadDes((TDes8*)a1, aStatus);
244 case RPagingExample::ERequestWrite:
245 r = StartWrite(a1, (TInt)a2, aStatus);
248 case RPagingExample::ERequestWriteDes:
249 r = StartWriteDes((TDes8*)a1, aStatus);
255 TInt DExampleChannel::DoCancel(TUint /*aMask*/)
261 void DExampleChannel::CancelDfcFunc(TAny* aPtr)
263 DExampleChannel* self = (DExampleChannel*)aPtr;
267 void DExampleChannel::Cancel()
269 if (iAsyncGetValueRequest->IsReady())
271 iAsyncGetValueTimer.Cancel();
272 iAsyncGetValueDfc.Cancel();
273 Kern::QueueRequestComplete(iClient, iAsyncGetValueRequest, KErrCancel);
276 if (iAsyncGetValue2Request->IsReady())
278 iAsyncGetValue2Timer.Cancel();
279 iAsyncGetValue2Dfc.Cancel();
280 Kern::QueueRequestComplete(iClient, iAsyncGetValue2Request, KErrCancel);
283 if (iReadRequest && iReadRequest->IsReady())
286 iCompleteReadDfc.Cancel();
287 Kern::QueueBufferRequestComplete(iClient, iReadRequest, KErrCancel);
288 Kern::DestroyClientBufferRequest(iReadRequest);
291 if (iWriteRequest->IsReady())
293 iWriteTimer.Cancel();
294 iCompleteWriteDfc.Cancel();
295 Kern::QueueBufferRequestComplete(iClient, iWriteRequest, KErrCancel);
299 void DExampleChannel::Shutdown()
303 void DExampleChannel::GetConfig(TConfigData& aConfigOut)
305 NKern::FMWait(&iLock);
306 aConfigOut = iConfig;
307 NKern::FMSignal(&iLock);
310 void DExampleChannel::SetConfig(const TConfigData& aNewConfig)
312 NKern::FMWait(&iLock);
313 iConfig = aNewConfig;
314 NKern::FMSignal(&iLock);
317 TInt DExampleChannel::StartNotify(TRequestStatus* aStatus)
319 // example implementation completes the request immediately
320 TInt r = iNotifyRequest->SetStatus(aStatus);
323 CompleteNotify(); // example implementation completes the request immediately
327 void DExampleChannel::CompleteNotify()
329 Kern::QueueRequestComplete(iClient, iNotifyRequest, KErrNone);
332 TInt DExampleChannel::StartAsyncGetValue(TInt* aValue, TRequestStatus* aStatus)
334 // use of TClientDataRequest API protected by fast mutex
335 NKern::FMWait(&iLock);
336 TInt r = iAsyncGetValueRequest->SetStatus(aStatus);
338 iAsyncGetValueRequest->SetDestPtr(aValue);
339 NKern::FMSignal(&iLock);
343 // queue a timer to simulate an asynchronous operation
344 iAsyncGetValueTimer.OneShot(KAsyncDelay, iAsyncGetValueDfc);
348 void DExampleChannel::AsyncGetValueCompleteDfcFunc(TAny* aPtr)
350 DExampleChannel* self = (DExampleChannel*)aPtr;
351 self->CompleteAsyncGetValue();
354 void DExampleChannel::CompleteAsyncGetValue()
356 // use of TClientDataRequest API protected by fast mutex
357 NKern::FMWait(&iLock);
358 if (iAsyncGetValueRequest->IsReady())
360 iAsyncGetValueRequest->Data().iValue1 = 1;
361 iAsyncGetValueRequest->Data().iValue2 = _L8("shrt");
362 Kern::QueueRequestComplete(iClient, iAsyncGetValueRequest, KErrNone);
364 NKern::FMSignal(&iLock);
367 TInt DExampleChannel::StartAsyncGetValue2(TInt* aValue1, TInt* aValue2, TRequestStatus* aStatus)
369 // use of TClientDataRequest API protected by fast mutex
370 NKern::FMWait(&iLock);
371 TInt r = iAsyncGetValue2Request->SetStatus(aStatus);
373 iAsyncGetValue2Request->SetDestPtr1(aValue1);
375 iAsyncGetValue2Request->SetDestPtr2(aValue2);
376 NKern::FMSignal(&iLock);
380 // queue a timer to simulate an asynchronous operation
381 iAsyncGetValue2Timer.OneShot(KAsyncDelay, iAsyncGetValue2Dfc);
385 void DExampleChannel::AsyncGetValue2CompleteDfcFunc(TAny* aPtr)
387 DExampleChannel* self = (DExampleChannel*)aPtr;
388 self->CompleteAsyncGetValue2();
391 void DExampleChannel::CompleteAsyncGetValue2()
393 // use of TClientDataRequest API protected by fast mutex
394 NKern::FMWait(&iLock);
395 if (iAsyncGetValue2Request->IsReady())
397 iAsyncGetValue2Request->Data1() = 1;
398 iAsyncGetValue2Request->Data2() = 2;
399 Kern::QueueRequestComplete(iClient, iAsyncGetValue2Request, KErrNone);
401 NKern::FMSignal(&iLock);
404 TInt DExampleChannel::StartRead(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus)
406 // check length argument first
407 if (aLength < 1 || aLength > KBufferSize)
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
418 // start request setup
419 r = iReadRequest->StartSetup(aStatus);
423 // add client buffer, this does pinning in context of client thread
424 r = iReadRequest->AddBuffer(iClientReadBuffer, (TLinAddr)aBuffer, aLength, ETrue);
428 iReadRequest->EndSetup();
430 ReceiveToReadBuffer();
434 TInt DExampleChannel::StartReadDes(TDes8* aDesOut, TRequestStatus* aStatus)
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
444 // start request setup
445 r = iReadRequest->StartSetup(aStatus);
449 // add client descriptor, this does pinning in context of client thread
450 r = iReadRequest->AddBuffer(iClientReadBuffer, aDesOut);
454 // can check length argument here
455 TInt length = iClientReadBuffer->MaxLength();
456 if (length < 1 || length > KBufferSize)
458 // need to reset object so it can be reused
459 iReadRequest->Reset();
463 iReadRequest->EndSetup();
465 ReceiveToReadBuffer();
469 TInt DExampleChannel::StartWrite(TAny* aBuffer, TInt aLength, TRequestStatus* aStatus)
471 // check length argument first
472 if (aLength < 1 || aLength > KBufferSize)
475 // demonstrate use the single-buffer version of Setup
476 TInt r = iWriteRequest->Setup(iClientWriteBuffer, aStatus, (TLinAddr)aBuffer, aLength);
480 SendFromWriteBuffer();
484 TInt DExampleChannel::StartWriteDes(const TDesC8* aDesIn, TRequestStatus* aStatus)
486 // demonstrate use the single-buffer version of Setup
487 TInt r = iWriteRequest->Setup(iClientWriteBuffer, aStatus, (TAny*)aDesIn);
491 // can check length argument here
492 TInt length = iClientWriteBuffer->Length();
493 if (length < 1 || length > KBufferSize)
495 // need to reset object so it can be reused
496 iWriteRequest->Reset();
500 SendFromWriteBuffer();
504 void DExampleChannel::ReceiveToReadBuffer()
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);
515 void DExampleChannel::SendFromWriteBuffer()
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);
525 void DExampleChannel::ReceiveCompleteDfcFunc(TAny* aPtr)
527 DExampleChannel* self = (DExampleChannel*)aPtr;
528 self->CompleteRead();
531 void DExampleChannel::SendCompleteDfcFunc(TAny* aPtr)
533 DExampleChannel* self = (DExampleChannel*)aPtr;
534 self->CompleteWrite();
537 void DExampleChannel::CompleteRead()
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);
545 void DExampleChannel::CompleteWrite()
547 TPtr8 des(iBuffer, iClientWriteBuffer->Length());
548 TInt r = Kern::ThreadBufRead(iClient, iClientWriteBuffer, des, 0, KChunkShiftBy0);
549 Kern::QueueBufferRequestComplete(iClient, iWriteRequest, r);
556 class DExampleFactory : public DLogicalDevice
560 virtual TInt Install();
561 virtual void GetCaps(TDes8& aDes) const;
562 virtual TInt Create(DLogicalChannelBase*& aChannel);
565 DExampleFactory::DExampleFactory()
568 iVersion = TVersion(1, 0, 0);
571 TInt DExampleFactory::Install()
573 return SetName(&KPagingExample2PostLdd);
576 void DExampleFactory::GetCaps(TDes8& /*aDes*/) const
578 // not used but required as DLogicalDevice::GetCaps is pure virtual
581 TInt DExampleFactory::Create(DLogicalChannelBase*& aChannel)
583 aChannel = new DExampleChannel;
584 return aChannel ? KErrNone : KErrNoMemory;
587 DECLARE_STANDARD_LDD()
589 return new DExampleFactory;