|
1 // Copyright (c) 2010 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 // d_timestamp.cpp |
|
15 // |
|
16 |
|
17 #include <kern_priv.h> |
|
18 #include <kernel.h> |
|
19 #include "d_timestamp.h" |
|
20 #include "d_timestamp_dev.h" |
|
21 |
|
22 // time stamp test defaults |
|
23 static const TInt KTimerDurationS = 5; // time interval for NTimer |
|
24 static const TInt KNErrPercent = 1; // percent error acceptable |
|
25 static const TInt KIterations = 5; // required number of valid runs (with LPM entry) |
|
26 static const TInt KRetries = 4; // retries are reset on every succesful run |
|
27 |
|
28 // |
|
29 // DTimestampTestFactory |
|
30 // |
|
31 |
|
32 /** |
|
33 Standard export function for LDDs. This creates a DLogicalDevice derived object, |
|
34 in this case, our DTimestampTestFactory |
|
35 */ |
|
36 DECLARE_STANDARD_LDD() |
|
37 { |
|
38 return new DTimestampTestFactory; |
|
39 } |
|
40 |
|
41 /** |
|
42 Constructor |
|
43 */ |
|
44 DTimestampTestFactory::DTimestampTestFactory() |
|
45 { |
|
46 // Set version number for this device |
|
47 iVersion=RTimestampTest::VersionRequired(); |
|
48 // Indicate that we work with a PDD |
|
49 iParseMask=KDeviceAllowPhysicalDevice; |
|
50 } |
|
51 |
|
52 /** |
|
53 Second stage constructor for DTimestampTestFactory. |
|
54 This must at least set a name for the driver object. |
|
55 |
|
56 @return KErrNone if successful, otherwise one of the other system wide error codes. |
|
57 */ |
|
58 TInt DTimestampTestFactory::Install() |
|
59 { |
|
60 return SetName(&RTimestampTest::Name()); |
|
61 } |
|
62 |
|
63 /** |
|
64 Destructor |
|
65 */ |
|
66 DTimestampTestFactory::~DTimestampTestFactory() |
|
67 { |
|
68 |
|
69 } |
|
70 |
|
71 /** |
|
72 Return the drivers capabilities. |
|
73 Called in the response to an RDevice::GetCaps() request. |
|
74 |
|
75 @param aDes User-side descriptor to write capabilities information into |
|
76 */ |
|
77 void DTimestampTestFactory::GetCaps(TDes8& aDes) const |
|
78 { |
|
79 // Create a capabilities object |
|
80 RTimestampTest::TCaps caps; |
|
81 caps.iVersion = iVersion; |
|
82 // Write it back to user memory |
|
83 Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps)); |
|
84 } |
|
85 |
|
86 |
|
87 /** |
|
88 Called by the kernel's device driver framework to create a Logical Channel. |
|
89 This is called in the context of the user thread (client) which requested the creation of a Logical Channel |
|
90 (E.g. through a call to RBusLogicalChannel::DoCreate) |
|
91 The thread is in a critical section. |
|
92 |
|
93 @param aChannel Set to point to the created Logical Channel |
|
94 |
|
95 @return KErrNone if successful, otherwise one of the other system wide error codes. |
|
96 */ |
|
97 TInt DTimestampTestFactory::Create(DLogicalChannelBase*& aChannel) |
|
98 { |
|
99 aChannel=new DTimestampTestChannel; |
|
100 if(!aChannel) |
|
101 { |
|
102 return KErrNoMemory; |
|
103 } |
|
104 |
|
105 return KErrNone; |
|
106 } |
|
107 |
|
108 |
|
109 // |
|
110 // Logical Channel |
|
111 // |
|
112 |
|
113 /** |
|
114 Constructor |
|
115 */ |
|
116 DTimestampTestChannel::DTimestampTestChannel() |
|
117 :iTimer(timerExpire,this),iDfc(dfcFn,this,7),iStarted(EFalse) |
|
118 { |
|
119 // Get pointer to client threads DThread object |
|
120 iClient=&Kern::CurrentThread(); |
|
121 // Open a reference on client thread so it's control block can't dissapear until |
|
122 // this driver has finished with it. |
|
123 // Note, this call to Open can't fail since its the thread we are currently running in |
|
124 iClient->Open(); |
|
125 } |
|
126 |
|
127 /** |
|
128 Second stage constructor called by the kernel's device driver framework. |
|
129 This is called in the context of the user thread (client) which requested the creation of a Logical Channel |
|
130 (E.g. through a call to RBusLogicalChannel::DoCreate) |
|
131 The thread is in a critical section. |
|
132 |
|
133 @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate |
|
134 @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate |
|
135 @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate |
|
136 |
|
137 @return KErrNone if successful, otherwise one of the other system wide error codes. |
|
138 */ |
|
139 TInt DTimestampTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) |
|
140 { |
|
141 // Check version |
|
142 if (!Kern::QueryVersionSupported(RTimestampTest::VersionRequired(),aVer)) |
|
143 return KErrNotSupported; |
|
144 |
|
145 // Setup LDD for receiving client messages |
|
146 TInt r = Kern::CreateClientRequest(iStartRequest); |
|
147 if (r != KErrNone) return r; |
|
148 r = Kern::CreateClientDataRequest(iWaitOnTimerRequest); |
|
149 if (r != KErrNone) return r; |
|
150 r = Kern::DynamicDfcQCreate(iQue,Kern::DfcQue0()->iThread->iPriority,RTimestampTest::Name()); |
|
151 if (KErrNone!=r) return r; |
|
152 iDfc.SetDfcQ(iQue); |
|
153 SetDfcQ(iQue); |
|
154 iMsgQ.Receive(); |
|
155 // Done |
|
156 return KErrNone; |
|
157 } |
|
158 |
|
159 |
|
160 /** |
|
161 Destructor |
|
162 */ |
|
163 DTimestampTestChannel::~DTimestampTestChannel() |
|
164 { |
|
165 // Cancel all processing that we may be doing |
|
166 DoCancel(TUint(RTimestampTest::EAllRequests)); |
|
167 Kern::DestroyClientRequest(iWaitOnTimerRequest); |
|
168 Kern::DestroyClientRequest(iStartRequest); |
|
169 iQue->Destroy(); |
|
170 // Close our reference on the client thread |
|
171 Kern::SafeClose((DObject*&)iClient,NULL); |
|
172 } |
|
173 |
|
174 /** |
|
175 Called when a user thread requests a handle to this channel. |
|
176 */ |
|
177 TInt DTimestampTestChannel::RequestUserHandle(DThread* aThread, TOwnerType aType) |
|
178 { |
|
179 // Make sure that only our client can get a handle |
|
180 if (aType!=EOwnerThread || aThread!=iClient) |
|
181 return KErrAccessDenied; |
|
182 return KErrNone; |
|
183 } |
|
184 |
|
185 /** |
|
186 override SendMsg method to allow pinning data in the context of the client thread |
|
187 */ |
|
188 TInt DTimestampTestChannel::SendMsg(TMessageBase* aMsg) |
|
189 { |
|
190 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
191 TInt id = m.iValue; |
|
192 |
|
193 // we only support one client |
|
194 if (id != (TInt)ECloseMsg && m.Client() != iClient) |
|
195 return KErrAccessDenied; |
|
196 |
|
197 TInt r = KErrNone; |
|
198 if (id != (TInt)ECloseMsg && id != KMaxTInt) |
|
199 { |
|
200 if (id<0) |
|
201 { |
|
202 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
203 r = SendRequest(aMsg); |
|
204 if (r != KErrNone) |
|
205 Kern::RequestComplete(pS,r); |
|
206 } |
|
207 else |
|
208 r = SendControl(aMsg); |
|
209 } |
|
210 else |
|
211 r = DLogicalChannel::SendMsg(aMsg); |
|
212 |
|
213 return r; |
|
214 } |
|
215 |
|
216 /** |
|
217 Process a message for this logical channel. |
|
218 This function is called in the context of a DFC thread. |
|
219 |
|
220 @param aMessage The message to process. |
|
221 The iValue member of this distinguishes the message type: |
|
222 iValue==ECloseMsg, channel close message |
|
223 iValue==KMaxTInt, a 'DoCancel' message |
|
224 iValue>=0, a 'DoControl' message with function number equal to iValue |
|
225 iValue<0, a 'DoRequest' message with function number equal to ~iValue |
|
226 */ |
|
227 void DTimestampTestChannel::HandleMsg(TMessageBase* aMsg) |
|
228 { |
|
229 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
230 |
|
231 // Get message type |
|
232 TInt id=m.iValue; |
|
233 |
|
234 // Decode the message type and dispatch it to the relevent handler function... |
|
235 |
|
236 if (id==(TInt)ECloseMsg) |
|
237 { |
|
238 // Channel Close |
|
239 DoCancel(TUint(RTimestampTest::EAllRequests)); |
|
240 iMsgQ.CompleteAll(KErrServerTerminated); |
|
241 m.Complete(KErrNone, EFalse); |
|
242 return; |
|
243 } |
|
244 |
|
245 if (id==KMaxTInt) |
|
246 { |
|
247 // DoCancel |
|
248 DoCancel(m.Int0()); |
|
249 m.Complete(KErrNone,ETrue); |
|
250 return; |
|
251 } |
|
252 |
|
253 if (id<0) |
|
254 { |
|
255 // DoRequest |
|
256 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
257 DoRequest(~id,pS,m.Ptr1(),m.Ptr2()); |
|
258 m.Complete(KErrNone,ETrue); |
|
259 } |
|
260 else |
|
261 { |
|
262 // DoControl |
|
263 TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); |
|
264 m.Complete(r,ETrue); |
|
265 } |
|
266 } |
|
267 |
|
268 /** |
|
269 Preprocess synchronous 'control' requests |
|
270 */ |
|
271 TInt DTimestampTestChannel::SendControl(TMessageBase* aMsg) |
|
272 { |
|
273 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
274 TInt id=m.iValue; |
|
275 |
|
276 switch (id) |
|
277 { |
|
278 |
|
279 case RTimestampTest::EConfig: |
|
280 { |
|
281 STimestampTestConfig info; |
|
282 #ifdef __SMP__ |
|
283 info.iFreq = NKern::TimestampFrequency(); |
|
284 #else |
|
285 info.iFreq = NKern::FastCounterFrequency(); |
|
286 #endif |
|
287 info.iIterations = KIterations; |
|
288 info.iRetries = KRetries; |
|
289 info.iTimerDurationS = KTimerDurationS; |
|
290 info.iErrorPercent = KNErrPercent; |
|
291 // Allow PDD to override defaults |
|
292 Pdd().TestConfig(info); |
|
293 kumemput(m.Ptr0(),&info,sizeof(STimestampTestConfig)); |
|
294 return KErrNone; |
|
295 } |
|
296 |
|
297 } |
|
298 |
|
299 |
|
300 TInt r = DLogicalChannel::SendMsg(aMsg); |
|
301 if (r != KErrNone) |
|
302 return r; |
|
303 |
|
304 // switch (id) |
|
305 // { |
|
306 // } |
|
307 |
|
308 return r; |
|
309 } |
|
310 |
|
311 /** |
|
312 Process synchronous 'control' requests |
|
313 */ |
|
314 TInt DTimestampTestChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) |
|
315 { |
|
316 (void)a2; |
|
317 (void)a1; |
|
318 (void) aFunction; |
|
319 |
|
320 // TInt r = KErrNone; |
|
321 // switch (aFunction) |
|
322 // { |
|
323 // default: |
|
324 // r = KErrNotSupported; |
|
325 // } |
|
326 |
|
327 return KErrNotSupported; |
|
328 } |
|
329 |
|
330 |
|
331 /** |
|
332 Preprocess asynchronous requests. |
|
333 */ |
|
334 TInt DTimestampTestChannel::SendRequest(TMessageBase* aMsg) |
|
335 { |
|
336 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
337 TInt function = ~m.iValue; |
|
338 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
339 |
|
340 TInt r = KErrNotSupported; |
|
341 |
|
342 switch (function) |
|
343 { |
|
344 case RTimestampTest::EStart: |
|
345 if (!iStarted) |
|
346 { |
|
347 r = iStartRequest->SetStatus(pS); |
|
348 } |
|
349 else |
|
350 { |
|
351 r = KErrInUse; |
|
352 } |
|
353 break; |
|
354 |
|
355 case RTimestampTest::EWaitOnTimer: |
|
356 if (iStarted) |
|
357 { |
|
358 iWaitOnTimerRequest->SetDestPtr(m.Ptr1()); |
|
359 r = iWaitOnTimerRequest->SetStatus(pS); |
|
360 } |
|
361 else |
|
362 { |
|
363 r = KErrNotReady; |
|
364 } |
|
365 |
|
366 break; |
|
367 default: |
|
368 r = KErrNotSupported; |
|
369 } |
|
370 |
|
371 if (r == KErrNone) |
|
372 r = DLogicalChannel::SendMsg(aMsg); |
|
373 return r; |
|
374 } |
|
375 |
|
376 |
|
377 /** |
|
378 Process asynchronous requests. |
|
379 */ |
|
380 void DTimestampTestChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) |
|
381 { |
|
382 (void)a2; |
|
383 (void)a1; |
|
384 (void)aStatus; |
|
385 |
|
386 TInt r = KErrNone; |
|
387 |
|
388 switch(aReqNo) |
|
389 { |
|
390 case RTimestampTest::EStart: |
|
391 iNTicks = (TInt) a1; |
|
392 r = iTimer.OneShot(0); |
|
393 if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iStartRequest,r); |
|
394 break; |
|
395 case RTimestampTest::EWaitOnTimer: |
|
396 Pdd().StartLPMEntryCheck(); // PDD will start checking if we have entered LPM |
|
397 r = iTimer.Again(iNTicks); |
|
398 if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,r); |
|
399 break; |
|
400 } |
|
401 |
|
402 } |
|
403 |
|
404 |
|
405 |
|
406 /** |
|
407 Process cancelling of asynchronous requests. |
|
408 */ |
|
409 void DTimestampTestChannel::DoCancel(TUint aMask) |
|
410 { |
|
411 (void)aMask; |
|
412 iTimer.Cancel(); // no real guarantees on SMP systems |
|
413 iDfc.Cancel(); |
|
414 } |
|
415 |
|
416 |
|
417 /** |
|
418 * process timer expiry |
|
419 */ |
|
420 void DTimestampTestChannel::DoTimerExpire() |
|
421 { |
|
422 #ifdef __SMP__ |
|
423 TUint64 ts = NKern::Timestamp(); |
|
424 #else |
|
425 TUint64 ts = NKern::FastCounter(); |
|
426 #endif |
|
427 iTimestampDelta = ts-iLastTimestamp; |
|
428 iLastTimestamp = ts; |
|
429 iDfc.Add(); |
|
430 } |
|
431 |
|
432 void DTimestampTestChannel::timerExpire(TAny* aParam) |
|
433 { |
|
434 DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam; |
|
435 pD->DoTimerExpire(); |
|
436 } |
|
437 |
|
438 |
|
439 |
|
440 void DTimestampTestChannel::DoDfcFn() |
|
441 { |
|
442 if (!iStarted) |
|
443 { |
|
444 iStarted = ETrue; |
|
445 Kern::QueueRequestComplete(iClient,iStartRequest,KErrNone); |
|
446 } |
|
447 else |
|
448 { |
|
449 iWaitOnTimerRequest->Data().iDelta = iTimestampDelta; |
|
450 // PDD will return ETrue here if we have entered LPM |
|
451 iWaitOnTimerRequest->Data().iLPMEntered = Pdd().EndLPMEntryCheck(); |
|
452 Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,KErrNone); |
|
453 } |
|
454 } |
|
455 |
|
456 void DTimestampTestChannel::dfcFn(TAny* aParam) |
|
457 { |
|
458 DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam; |
|
459 pD->DoDfcFn(); |
|
460 } |
|
461 |