First public contribution.
1 // Copyright (c) 1997-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 // e32test\system\d_mstim.cpp
15 // LDD for testing millisecond timer
19 #include "plat_priv.h"
22 #elif defined(__MAWD__)
23 #include <windermere.h>
24 #elif defined(__MISA__)
26 #elif defined(__MCOT__)
28 #elif defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
30 #include <omap_timer.h>
31 #elif defined(__MI920__) || defined(__NI1136__)
38 #include <integratorap.h>
40 #elif defined(__RVEMUBOARD__)
41 #include <rvemuboard.h>
42 #elif defined(__NE1_TB__)
43 #include <upd35001_timer.h>
46 #include "../misc/prbs.h"
49 typedef Int64 TCounter;
51 const TDelta KMaxDelta = 0x7fffffffffffffff;
52 const TDelta KMinDelta = 0x8000000000000000;
54 typedef TUint TCounter;
56 const TDelta KMaxDelta = KMaxTInt;
57 const TDelta KMinDelta = KMinTInt;
61 inline TCounter TIMER()
62 { return *(volatile TUint*)KHwRwOstOscr; }
64 #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
65 inline TCounter TIMER()
66 { return TOmapTimer::Timer3Value(); }
69 inline TCounter TIMER()
70 { return *(volatile TUint*)KHwRwOstOscr; }
73 inline TCounter TIMER()
74 { return *(volatile TUint*)(KWindBaseAddress+KWindTimer1Value16)&0xffff; }
77 inline TCounter TIMER()
78 { return *(volatile TUint*)(KEigerBaseAddress+KEigerTimer1Data16)&0xffff;}
80 #if defined(__MI920__) || defined(__NI1136__)
81 inline TCounter TIMER()
83 { return *(volatile TUint*)(KHwRwCoreClkCounter);} // 32-bit Core module counter inc's at 24MHz
85 { return *(volatile TUint*)(KHwCounterTimer1+KHoTimerValue)&0xffff;}
88 #if defined(__RVEMUBOARD__)
89 inline TCounter TIMER()
90 { return *(volatile TUint*)(KHwCounterTimer1+KHoTimerValue)&0xffff;}
93 inline TCounter TIMER()
94 { return NETimer::Timer(2).iTimerCount; }
96 #if defined(__EPOC32__) && defined(__CPU_X86)
98 void SetUpTimerChannel2();
102 inline TCounter TIMER()
105 QueryPerformanceCounter(&c);
110 #if defined(__MISA__) || (defined(USE_CM920_FRC) && (defined(__MI920__) || defined(__NI1136__)))
111 inline TDelta TimeDelta(TCounter initial, TCounter final)
112 { return final-initial; } // SA1100 timer counts up
114 #if defined(__MCOT__)
115 inline TDelta TimeDelta(TCounter initial, TCounter final)
116 { return final-initial; } // Cotulla timer counts up
118 #if defined(__MAWD__) || defined(__MEIG__) || (!defined(USE_CM920_FRC) && (defined(__MI920__) || defined(__NI1136__)))
119 inline TDelta TimeDelta(TCounter initial, TCounter final)
120 { return (initial-final)&0xffff; } // Eiger/Windermere/Integrator timer counts down
122 #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
123 inline TDelta TimeDelta(TCounter initial, TCounter final)
124 { return (initial-final);} // OMAP timer counts down
126 #if defined(__EPOC32__) && defined(__CPU_X86)
127 TDelta TimeDelta(TUint initial, TUint final)
129 TUint tickdiff=(initial-final)&0xffff;
130 TUint msdiff=((final>>16)-(initial>>16))&0xffff;
131 msdiff=1193*msdiff-tickdiff;
132 msdiff=(msdiff+32768)&~0xffff;
133 return msdiff+tickdiff;
137 inline TDelta TimeDelta(TCounter initial, TCounter final)
138 { return final - initial; }
141 inline TDelta TimeDelta(TCounter initial, TCounter final)
142 { return final-initial; } // counts up
144 #if defined(__RVEMUBOARD__)
145 inline TDelta TimeDelta(TCounter initial, TCounter final)
146 { return (initial-final)&0xffff; } // Timer counts down
149 const TInt KMajorVersionNumber=0;
150 const TInt KMinorVersionNumber=1;
151 const TInt KBuildVersionNumber=1;
153 const TInt KMaxMsTim=9;
154 const TInt KMaxMsTimR=9;
156 TInt TicksToMicroseconds(TDelta aTicks)
158 #if defined(__MISA__) || defined(__MCOT__)
161 ticks+=KHwOscFreqHz/2; // 3.6864MHz tick
165 #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
166 // Timer runs at 12Mhz/32 = 375kHz. Each tick is 2.66...us which is 16/6us
168 aTicks+=3; // rounding to the closest number of us
169 return (TInt)(aTicks/6); // us = (ticks*16+3)/6
171 #if defined(__MI920__) || defined(__NI1136__)
172 #if defined(USE_CM920_FRC)
179 aTicks<<=14; // 1 tick = 32/3 us
180 aTicks+=768; // round
181 return (TInt)(aTicks/1536);
184 #if defined(__RVEMUBOARD__)
185 return (TInt)(aTicks*256); // 1 tick = 256 us
187 #if defined(__MAWD__) || defined(__MEIG__)
188 return aTicks*500; // 2kHz tick
190 #if defined(__NE1_TB__)
191 NETimer& T2 = NETimer::Timer(2);
192 TUint prescale = __e32_find_ms1_32(T2.iPrescaler & 0x3f);
193 TInt f = 66666667 >> prescale;
194 TInt64 x = I64LIT(1000000);
200 #if defined(__EPOC32__) && defined(__CPU_X86)
203 y -= ((3*x)>>4); // * 0.D
204 y += (aTicks>>12); // * 0.D00D
205 TInt z = (6*x)>>8; // * 0.06
207 y += (x>>9); // * 0.D68D
208 y += (z>>16); // * 0.D68D6
209 y += (z>>20); // * 0.D68D66
214 QueryPerformanceFrequency(&f);
216 aTicks+=f.QuadPart-1;
226 // Set up timer 1 as free running 2kHz clock
227 TWind::SetBuzzerControl(0); // disable buzzer
228 TWind::SetTimer1Control(KWindTimer1ControlTimerEnable);
229 TWind::SetTimer1Load(0);
232 // Set up timer 1 as free running 2kHz clock
233 TEiger::ModifyControl21(KEigerControlTimer1PreOrFree|KEigerControlTimer1K512OrK2|
234 KEigerControlBuzzerToggle|KEigerControlBuzzerTimer1OrToggle,0);
235 TEiger::SetTimer1Data(0);
237 #if defined(__MISA__)
238 // MISA free running counter is always active - no initialisation required
240 #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
241 // Set up Timer3 as a free-running timer at 12Mhz/32 = 375kHz
242 TOmapTimer::SetTimer3Ctrl( TOmapTimer::KHtOSTimer_Cntl_Ar
243 | TOmapTimer::KHtOSTimer_Cntl_Free
244 | TOmapTimer::KHtOSTimer_Cntl_ClkEnable );
245 TOmapTimer::SetTimer3Prescale( TOmapTimer::EPrescaleBy32 );
246 // Autoreload 0xFFFFFFFF to effectively wrap from zero back to 0xFFFFFFFF
247 TOmapTimer::SetTimer3LoadTim( 0xFFFFFFFF );
248 TOmapTimer::StartTimer3();
250 #if defined(__MI920__) || defined(__NI1136__)
251 #if !defined(USE_CM920_FRC)
252 TIntegratorAP::SetTimerMode(TIntegratorAP::ECounterTimer1, TIntegratorAP::ETimerModeFreeRunning);
253 TIntegratorAP::SetTimerPreScale(TIntegratorAP::ECounterTimer1, TIntegratorAP::ETimerPreScaleDiv256); // 93.75kHz wrap 699ms
254 TIntegratorAP::EnableTimer(TIntegratorAP::ECounterTimer1, TIntegratorAP::EEnable);
257 #if defined(__RVEMUBOARD__)
258 // Switch timer 1 to a 1MHz clock in the system controller Ctrl register
259 TRvEmuBoard::SetSCCtrl(KTimer1EnSel);
261 // Set up timer 1 as free running 3.90625kHz clock
262 TRvEmuBoard::SetTimerMode(KHwCounterTimer1, TRvEmuBoard::ETimerModeFreeRunning);
263 TRvEmuBoard::SetTimerPreScale(KHwCounterTimer1, TRvEmuBoard::ETimerPreScaleDiv256);// 3.90625kHz wrap 16.777s
264 TRvEmuBoard::EnableTimer(KHwCounterTimer1, TRvEmuBoard::EEnable);
266 #if defined(__NE1_TB__)
267 // nothing to do since variant has already set up timer
269 #if defined(__EPOC32__) && defined(__CPU_X86)
270 // Set up timer channel 2 as free running counter at 14318180/12 Hz
271 SetUpTimerChannel2();
276 TDynamicDfcQue* gDfcQ;
281 static inline NTimerQ& Timer()
282 { return *(NTimerQ*)NTimerQ::TimerAddress(); }
283 static inline TUint32 MsCount()
284 { return Timer().iMsCount; }
285 static inline void Setup(TAny* aPtr)
286 { NTimerQ& m=Timer(); m.iDebugFn=Test; m.iDebugPtr=aPtr; }
287 static inline void Stop()
288 { NTimerQ& m=Timer(); m.iDebugFn=NULL; m.iDebugPtr=NULL; }
289 static inline TBool XferC()
290 { return Timer().iTransferringCancelled; }
291 static inline TBool CritC()
292 { return Timer().iCriticalCancelled; }
293 static void Test(TAny* aPtr, TInt aPos);
298 class TMsTim : public NTimer
321 TInt Start(TInt aMode, TInt aInterval, TInt aParam);
322 static void MsCallBack(TAny* aPtr);
323 static void IDfcFn(TAny* aPtr);
324 static void DfcFn(TAny* aPtr);
325 void CompleteClient(TInt aValue);
337 TClientRequest* iRequest;
342 class TMsTimRand : public NTimer
349 TInt Start(TInt aInterval, DMsTim* aLdd, TInt aPos);
350 static void MsCallBack(TAny* aPtr);
351 void FillWithGarbage(TUint aFillValue);
358 class DMsTimFactory : public DLogicalDevice
360 // Millisecond timer LDD factory
366 virtual TInt Install(); //overriding pure virtual
367 virtual void GetCaps(TDes8& aDes) const; //overriding pure virtual
368 virtual TInt Create(DLogicalChannelBase*& aChannel); //overriding pure virtual
371 class DMsTim : public DLogicalChannel
373 // Millisecond timer LDD channel
380 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
381 TInt DoControl(TInt aFunction, TAny* a1, TAny* a2);
382 TInt DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2);
383 virtual void HandleMsg(TMessageBase* aMsg);
385 void TimerExpired(TInt anId);
386 inline DThread* Client() { return iThread; }
389 TMsTim iMsTim[KMaxMsTim];
390 TMsTimRand iMsTimR[KMaxMsTimR];
402 : NTimer(MsCallBack,this),
413 iCompletionDfc(DfcFn,this,gDfcQ,1)
419 Kern::DestroyClientRequest(iRequest);
421 NTimer* nt = STATIC_CAST(NTimer*,this);
422 new (nt) NTimer(&MsCallBack, this); // so NTimer destructor doesn't kill us
426 TInt TMsTim::Create()
428 return Kern::CreateClientRequest(iRequest);
431 void TMsTim::IDfcFn(TAny* aPtr)
433 TMsTim& m=*(TMsTim*)aPtr;
434 TInt c = NKern::CurrentContext();
435 __NK_ASSERT_ALWAYS(c == NKern::EIDFC);
436 __NK_ASSERT_ALWAYS(NKern::KernelLocked(1));
437 m.iCompletionDfc.DoEnque();
440 void TMsTim::DfcFn(TAny* aPtr)
442 TMsTim& m=*(TMsTim*)aPtr;
443 if (m.iMode==EUserDfcAfter)
445 TCounter timer_val=TIMER();
446 TDelta time=TimeDelta(m.iStartTime, timer_val);
454 m.iLdd->TimerExpired(m.iId);
457 void TestThreadContext()
459 TInt c1 = NKern::CurrentContext();
461 TInt c2 = NKern::CurrentContext();
463 __NK_ASSERT_ALWAYS((c1 == NKern::EThread) && (c2 == NKern::EThread));
466 void TMsTim::MsCallBack(TAny* aPtr)
468 TInt c = NKern::CurrentContext();
469 TCounter timer_val=TIMER();
470 TMsTim& m=*(TMsTim*)aPtr;
471 TDelta time=TimeDelta(m.iStartTime, timer_val);
472 if (++m.iCount>0 || (m.iMode!=EIntAgain && m.iMode!=EDfcAgain))
483 __NK_ASSERT_ALWAYS(c == NKern::EInterrupt);
488 m.iCompletionDfc.Enque();
491 __NK_ASSERT_ALWAYS(c == NKern::EInterrupt);
492 m.iStartTime=TIMER();
493 m.Again(m.iInterval);
497 m.iStartTime=TIMER();
498 m.Again(m.iInterval);
501 __NK_ASSERT_ALWAYS(c == NKern::EInterrupt);
502 m.iLdd->iMsTim[m.iParam].Cancel();
507 m.iLdd->iMsTim[m.iParam].Cancel();
508 m.iCompletionDfc.Enque();
511 __NK_ASSERT_ALWAYS(EFalse);
516 TInt TMsTim::Start(TInt aMode, TInt aInterval, TInt aParam)
520 TCounter holder=TIMER(); // holds the start value of timer
527 r=OneShot(aInterval);
533 r=OneShot(aInterval,ETrue);
536 case EUserDfcAgainOnce:
538 i8888.iHState2=FALSE;
540 iCompleteInDfc=FALSE;
543 if (aMode==EUserDfcAgainOnce)
549 r=OneShot(aInterval, iCompletionDfc);
565 void TMsTim::CompleteClient(TInt aValue)
567 Kern::QueueRequestComplete(iLdd->Client(),iRequest,aValue);
570 TMsTimRand::TMsTimRand()
571 : NTimer(&MsCallBack,this)
573 memset(this,0,sizeof(TMsTimRand));
575 NTimer* nt = STATIC_CAST(NTimer*,this);
576 new (nt) NTimer(&MsCallBack,this);
578 iFunction=MsCallBack; // avoid triggering assertion in NTimer::OneShot()
583 TMsTimRand::~TMsTimRand()
585 NTimer* nt = STATIC_CAST(NTimer*,this);
586 new (nt) NTimer(&MsCallBack, this); // so NTimer destructor doesn't kill us
590 void TMsTimRand::FillWithGarbage(TUint aFill)
596 iNext = (SDblQueLink*)f;
597 iPrev = (SDblQueLink*)f;
601 iTiedLink.iNext = (SDblQueLink*)f;
602 iTiedLink.iPrev = (SDblQueLink*)f;
604 memset(this, (TUint8)aFill, 16);
608 TInt TMsTimRand::Start(TInt aInterval, DMsTim* aLdd, TInt aPos)
612 TUint fill=(aPos<<5)|(i8888.iHState1<<2)|3;
614 TUint fill=(aPos<<5)|(iState<<2)|3;
615 iPad1 = (TUint8)fill;
617 TInt r=OneShot(aInterval,ETrue);
625 i8888.iHState0 = (TUint8)fill;
626 if (i8888.iHState1!=EHolding)
627 *(TUint*)0xfcd1fcd1=i8888.iHState1;
629 iFunction=MsCallBack;
630 iUserFlags = (TUint8)fill;
631 if (iState!=EHolding)
632 *(TUint*)0xfcd1fcd1=iState;
638 void TMsTimRand::MsCallBack(TAny* aPtr)
640 TMsTimRand& m=*(TMsTimRand*)aPtr;
641 TCounter time=TIMER();
642 TDelta elapsed=TimeDelta(m.iStartTime,time);
643 TInt error=TicksToMicroseconds(elapsed)-m.iInterval*1000;
644 if (error<m.iLdd->iRandMin)
645 m.iLdd->iRandMin=error;
646 if (error>m.iLdd->iRandMax)
647 m.iLdd->iRandMax=error;
648 ++m.iLdd->iCompletions;
649 m.FillWithGarbage(0xd9);
652 void NTimerQTest::Test(TAny* aPtr, TInt aPos)
654 DMsTim& ldd=*(DMsTim*)aPtr;
658 TUint action=Random(ldd.iSeed)&31;
659 TMsTimRand& m=ldd.iMsTimR[action&7];
663 TUint fill=(aPos<<5)|(m.i8888.iHState1<<2)|3;
665 TUint fill=(aPos<<5)|(m.iState<<2)|3;
668 m.FillWithGarbage(fill);
672 TUint iv=(Random(ldd.iSeed)&31)+32;
673 TInt r=m.Start(iv,&ldd,aPos);
683 DECLARE_STANDARD_LDD()
685 return new DMsTimFactory;
688 DMsTimFactory::DMsTimFactory()
693 iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
694 //iParseMask=0;//No units, no info, no PDD
695 //iUnitsMask=0;//Only one thing
698 TInt DMsTimFactory::Create(DLogicalChannelBase*& aChannel)
700 // Create a new DMsTim on this logical device
704 return aChannel?KErrNone:KErrNoMemory;
707 const TInt KDMsTimThreadPriority = 27;
708 _LIT(KDMsTimThread,"DMsTimThread");
710 TInt DMsTimFactory::Install()
712 // Install the LDD - overriding pure virtual
715 // Allocate a kernel thread to run the DFC
716 TInt r = Kern::DynamicDfcQCreate(gDfcQ, KDMsTimThreadPriority, KDMsTimThread);
718 #ifdef CPU_AFFINITY_ANY
719 NKern::ThreadSetCpuAffinity((NThread*)(gDfcQ->iThread), KCpuAffinityAny);
725 return SetName(&KMsTimerLddName);
728 void DMsTimFactory::GetCaps(TDes8& aDes) const
730 // Get capabilities - overriding pure virtual
734 b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
735 Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
741 DMsTimFactory::~DMsTimFactory()
752 iThread=&Kern::CurrentThread();
755 for (i=0; i<KMaxMsTim; i++)
760 for (i=0; i<KMaxMsTimR; i++)
762 iMsTimR[i].iLdd=this;
764 iSeed[0]=NTimerQTest::MsCount();
768 TInt DMsTim::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
773 if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
774 return KErrNotSupported;
777 for (TInt i = 0 ; i < KMaxMsTim ; ++i)
779 TInt r = iMsTim[i].Create();
785 NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), NKern::NumberOfCpus() - 1); // Try and avoid the cpu the test app is running on
795 #if defined(__MI920__) || defined(__NI1136__)
796 #if !defined(USE_CM920_FRC)
797 TIntegratorAP::EnableTimer(TIntegratorAP::ECounterTimer1, TIntegratorAP::EDisable);
800 #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__)
801 TOmapTimer::SetTimer3Ctrl( 0 ); // disable the timer
803 Kern::SafeClose((DObject*&)iThread, NULL);
806 void DMsTim::HandleMsg(TMessageBase* aMsg)
809 TThreadMessage& m=*(TThreadMessage*)aMsg;
811 if (id==(TInt)ECloseMsg)
815 for (i=0; i<KMaxMsTim; i++)
818 iMsTim[i].iCompletionDfc.Cancel();
819 iMsTim[i].CompleteClient(KErrCancel);
821 for (i=0; i<KMaxMsTimR; i++)
824 iMsTimR[i].FillWithGarbage(0x01);
826 m.Complete(KErrNone,EFalse);
827 iMsgQ.CompleteAll(KErrServerTerminated);
832 TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
833 r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
837 r=DoControl(id,m.Ptr0(),m.Ptr1());
842 TInt DMsTim::DoControl(TInt aFunction, TAny* a1, TAny* a2)
846 TMsTim& m=iMsTim[id];
847 TInt interval=(TInt)a2;
850 case RMsTim::EControlStartPeriodicInt:
851 r=m.Start(TMsTim::EIntAgain,interval,0);
853 case RMsTim::EControlStartPeriodicDfc:
854 r=m.Start(TMsTim::EDfcAgain,interval,0);
856 case RMsTim::EControlStopPeriodic:
858 m.iCompletionDfc.Cancel();
860 case RMsTim::EControlGetInfo:
863 info.iCount=m.iCount;
864 Int64 avg=m.iTotal/m.iCount;
865 info.iAvg=TicksToMicroseconds((TInt)avg);
870 info.iMin=TicksToMicroseconds(m.iMin);
871 info.iMax=TicksToMicroseconds(m.iMax);
874 r=Kern::ThreadRawWrite(iThread,a2,&info,sizeof(info));
877 case RMsTim::EControlBeginRandomTest:
886 NTimerQTest::Setup(this);
889 case RMsTim::EControlEndRandomTest:
893 for (i=0; i<KMaxMsTimR; i++)
896 iMsTimR[i].FillWithGarbage(0x35);
900 case RMsTim::EControlGetRandomTestInfo:
902 SRandomTestInfo info;
907 info.iStartFail=iStartFail;
908 info.iCallBacks=iCallBacks;
909 info.iCompletions=iCompletions;
910 r=Kern::ThreadRawWrite(iThread,a1,&info,sizeof(info));
913 case RMsTim::EControlGetIdleTime:
915 TInt irq=NKern::DisableAllInterrupts();
916 r=NTimerQ::IdleTime();
917 NKern::RestoreInterrupts(irq);
927 TInt DMsTim::DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2)
930 TMsTim& m=iMsTim[aFunction == RMsTim::ERequestIntCancel ? 7 : id];
931 TInt interval=(TInt)a2;
935 case RMsTim::ERequestOneShotInt:
936 r=m.Start(TMsTim::EIntAfter,interval,0);
938 case RMsTim::ERequestOneShotDfc:
939 r=m.Start(TMsTim::EDfcAfter,interval,0);
941 case RMsTim::ERequestIntCancel:
942 r=m.Start(TMsTim::EIntCancel,interval,id);
944 case RMsTim::ERequestOneShotIntAgain:
945 r=m.Start(TMsTim::EIntAgainOnce,interval,0);
947 case RMsTim::ERequestOneShotUserDfc:
948 r=m.Start(TMsTim::EUserDfcAfter,interval,0);
950 case RMsTim::ERequestOneShotUserDfcAgain:
951 r=m.Start(TMsTim::EUserDfcAgainOnce,interval,0);
957 m.iRequest->SetStatus(aStatus);
959 Kern::QueueRequestComplete(iThread,m.iRequest,r);
963 void DMsTim::TimerExpired(TInt anId)
965 TMsTim& m=iMsTim[anId];
968 case TMsTim::EIntAfter:
969 case TMsTim::EDfcAfter:
970 case TMsTim::EUserDfcAfter:
971 m.CompleteClient(KErrNone);
973 case TMsTim::EIntAgain:
974 case TMsTim::EDfcAgain:
976 case TMsTim::EIntCancel:
977 case TMsTim::EDfcCancel:
979 TMsTim& cancelled=iMsTim[m.iParam];
980 cancelled.CompleteClient(KErrAbort);
981 m.CompleteClient(KErrNone);