|
1 // Copyright (c) 2002-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 // e32test\dma\dmasim.cpp |
|
15 // DMA framework Platform Specific Layer (PSL) for software-emulated |
|
16 // DMA controller used for testing the DMA framework PIL. |
|
17 // |
|
18 // |
|
19 |
|
20 #include <drivers/dma.h> |
|
21 #include <kernel/kern_priv.h> |
|
22 |
|
23 |
|
24 const char KDmaPanicCat[] = "DMASIM"; |
|
25 |
|
26 const TInt KMaxTransferSize = 0x1FFF; |
|
27 const TInt KMemAlignMask = 3; // memory addresses passed to DMAC must be multiple of 4 |
|
28 const TInt KBurstSize = 0x800; |
|
29 |
|
30 typedef void (*TPseudoIsr)(); |
|
31 |
|
32 const TInt KChannelCount = 4; // # of channels per controller |
|
33 const TInt KDesCount = 256; // # of descriptors allocated per controller |
|
34 |
|
35 ////////////////////////////////////////////////////////////////////////////// |
|
36 // SOFTWARE DMA CONTROLLER SIMULATION |
|
37 ////////////////////////////////////////////////////////////////////////////// |
|
38 |
|
39 class DmacSb |
|
40 /** Single-buffer DMA controller software simulation */ |
|
41 { |
|
42 public: |
|
43 enum { ECsRun = 0x80000000 }; |
|
44 public: |
|
45 static void DoTransfer(); |
|
46 private: |
|
47 static void BurstTransfer(); |
|
48 private: |
|
49 static TInt CurrentChannel; |
|
50 public: |
|
51 // pseudo registers |
|
52 static TUint8* SrcAddr[KChannelCount]; |
|
53 static TUint8* DestAddr[KChannelCount]; |
|
54 static TInt Count[KChannelCount]; |
|
55 static TUint32 ControlStatus[KChannelCount]; |
|
56 static TUint32 CompletionInt; |
|
57 static TUint32 ErrorInt; |
|
58 // hook for pseudo ISR |
|
59 static TPseudoIsr Isr; |
|
60 // transfer failure simulation |
|
61 static TInt FailCount[KChannelCount]; |
|
62 }; |
|
63 |
|
64 TUint8* DmacSb::SrcAddr[KChannelCount]; |
|
65 TUint8* DmacSb::DestAddr[KChannelCount]; |
|
66 TInt DmacSb::Count[KChannelCount]; |
|
67 TUint32 DmacSb::ControlStatus[KChannelCount]; |
|
68 TUint32 DmacSb::CompletionInt; |
|
69 TUint32 DmacSb::ErrorInt; |
|
70 TPseudoIsr DmacSb::Isr; |
|
71 TInt DmacSb::FailCount[KChannelCount]; |
|
72 TInt DmacSb::CurrentChannel; |
|
73 |
|
74 void DmacSb::DoTransfer() |
|
75 { |
|
76 if (ControlStatus[CurrentChannel] & ECsRun) |
|
77 { |
|
78 if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0) |
|
79 { |
|
80 ControlStatus[CurrentChannel] &= ~ECsRun; |
|
81 ErrorInt |= 1 << CurrentChannel; |
|
82 Isr(); |
|
83 } |
|
84 else |
|
85 { |
|
86 //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer channel %d", CurrentChannel)); |
|
87 if (Count[CurrentChannel] == 0) |
|
88 { |
|
89 //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer transfer complete")); |
|
90 ControlStatus[CurrentChannel] &= ~ECsRun; |
|
91 CompletionInt |= 1 << CurrentChannel; |
|
92 Isr(); |
|
93 } |
|
94 else |
|
95 BurstTransfer(); |
|
96 } |
|
97 } |
|
98 |
|
99 CurrentChannel++; |
|
100 if (CurrentChannel >= KChannelCount) |
|
101 CurrentChannel = 0; |
|
102 } |
|
103 |
|
104 void DmacSb::BurstTransfer() |
|
105 { |
|
106 //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::BurstTransfer")); |
|
107 TInt s = Min(Count[CurrentChannel], KBurstSize); |
|
108 memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s); |
|
109 Count[CurrentChannel] -= s; |
|
110 SrcAddr[CurrentChannel] += s; |
|
111 DestAddr[CurrentChannel] += s; |
|
112 } |
|
113 |
|
114 ////////////////////////////////////////////////////////////////////////////// |
|
115 |
|
116 class DmacDb |
|
117 /** Double-buffer DMA controller software simulation */ |
|
118 { |
|
119 public: |
|
120 enum { ECsRun = 0x80000000, ECsPrg = 0x40000000 }; |
|
121 public: |
|
122 static void Enable(TInt aIdx); |
|
123 static void DoTransfer(); |
|
124 private: |
|
125 static TInt CurrentChannel; |
|
126 private: |
|
127 // internal pseudo-registers |
|
128 static TUint8* ActSrcAddr[KChannelCount]; |
|
129 static TUint8* ActDestAddr[KChannelCount]; |
|
130 static TInt ActCount[KChannelCount]; |
|
131 public: |
|
132 // externally accessible pseudo-registers |
|
133 static TUint32 ControlStatus[KChannelCount]; |
|
134 static TUint8* PrgSrcAddr[KChannelCount]; |
|
135 static TUint8* PrgDestAddr[KChannelCount]; |
|
136 static TInt PrgCount[KChannelCount]; |
|
137 static TUint32 CompletionInt; |
|
138 static TUint32 ErrorInt; |
|
139 // hook for pseudo ISR |
|
140 static TPseudoIsr Isr; |
|
141 // transfer failure simulation |
|
142 static TInt FailCount[KChannelCount]; |
|
143 static TInt InterruptsToMiss[KChannelCount]; |
|
144 }; |
|
145 |
|
146 TUint8* DmacDb::PrgSrcAddr[KChannelCount]; |
|
147 TUint8* DmacDb::PrgDestAddr[KChannelCount]; |
|
148 TInt DmacDb::PrgCount[KChannelCount]; |
|
149 TUint8* DmacDb::ActSrcAddr[KChannelCount]; |
|
150 TUint8* DmacDb::ActDestAddr[KChannelCount]; |
|
151 TInt DmacDb::ActCount[KChannelCount]; |
|
152 TUint32 DmacDb::ControlStatus[KChannelCount]; |
|
153 TUint32 DmacDb::CompletionInt; |
|
154 TUint32 DmacDb::ErrorInt; |
|
155 TPseudoIsr DmacDb::Isr; |
|
156 TInt DmacDb::FailCount[KChannelCount]; |
|
157 TInt DmacDb::InterruptsToMiss[KChannelCount]; |
|
158 TInt DmacDb::CurrentChannel; |
|
159 |
|
160 void DmacDb::Enable(TInt aIdx) |
|
161 { |
|
162 if (ControlStatus[aIdx] & ECsRun) |
|
163 ControlStatus[aIdx] |= ECsPrg; |
|
164 else |
|
165 { |
|
166 ActSrcAddr[aIdx] = PrgSrcAddr[aIdx]; |
|
167 ActDestAddr[aIdx] = PrgDestAddr[aIdx]; |
|
168 ActCount[aIdx] = PrgCount[aIdx]; |
|
169 ControlStatus[aIdx] |= ECsRun; |
|
170 } |
|
171 } |
|
172 |
|
173 void DmacDb::DoTransfer() |
|
174 { |
|
175 if (ControlStatus[CurrentChannel] & ECsRun) |
|
176 { |
|
177 if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0) |
|
178 { |
|
179 ControlStatus[CurrentChannel] &= ~ECsRun; |
|
180 ErrorInt |= 1 << CurrentChannel; |
|
181 Isr(); |
|
182 } |
|
183 else |
|
184 { |
|
185 if (ActCount[CurrentChannel] == 0) |
|
186 { |
|
187 if (ControlStatus[CurrentChannel] & ECsPrg) |
|
188 { |
|
189 ActSrcAddr[CurrentChannel] = PrgSrcAddr[CurrentChannel]; |
|
190 ActDestAddr[CurrentChannel] = PrgDestAddr[CurrentChannel]; |
|
191 ActCount[CurrentChannel] = PrgCount[CurrentChannel]; |
|
192 ControlStatus[CurrentChannel] &= ~ECsPrg; |
|
193 } |
|
194 else |
|
195 ControlStatus[CurrentChannel] &= ~ECsRun; |
|
196 if (InterruptsToMiss[CurrentChannel] > 0) |
|
197 InterruptsToMiss[CurrentChannel]--; |
|
198 else |
|
199 { |
|
200 CompletionInt |= 1 << CurrentChannel; |
|
201 Isr(); |
|
202 } |
|
203 } |
|
204 else |
|
205 { |
|
206 TInt s = Min(ActCount[CurrentChannel], KBurstSize); |
|
207 memcpy(ActDestAddr[CurrentChannel], ActSrcAddr[CurrentChannel], s); |
|
208 ActCount[CurrentChannel] -= s; |
|
209 ActSrcAddr[CurrentChannel] += s; |
|
210 ActDestAddr[CurrentChannel] += s; |
|
211 } |
|
212 } |
|
213 } |
|
214 |
|
215 CurrentChannel++; |
|
216 if (CurrentChannel >= KChannelCount) |
|
217 CurrentChannel = 0; |
|
218 } |
|
219 |
|
220 |
|
221 ////////////////////////////////////////////////////////////////////////////// |
|
222 |
|
223 class DmacSg |
|
224 /** Scatter/gather DMA controller software simulation */ |
|
225 { |
|
226 public: |
|
227 enum { EChannelBitRun = 0x80000000 }; |
|
228 enum { EDesBitInt = 1 }; |
|
229 struct SDes |
|
230 { |
|
231 TUint8* iSrcAddr; |
|
232 TUint8* iDestAddr; |
|
233 TInt iCount; |
|
234 TUint iControl; |
|
235 SDes* iNext; |
|
236 }; |
|
237 public: |
|
238 static void DoTransfer(); |
|
239 static void Enable(TInt aIdx); |
|
240 private: |
|
241 static TInt CurrentChannel; |
|
242 static TBool IsDescriptorLoaded[KChannelCount]; |
|
243 public: |
|
244 // externally accessible pseudo-registers |
|
245 static TUint32 ChannelControl[KChannelCount]; |
|
246 static TUint8* SrcAddr[KChannelCount]; |
|
247 static TUint8* DestAddr[KChannelCount]; |
|
248 static TInt Count[KChannelCount]; |
|
249 static TUint Control[KChannelCount]; |
|
250 static SDes* NextDes[KChannelCount]; |
|
251 static TUint32 CompletionInt; |
|
252 static TUint32 ErrorInt; |
|
253 // hook for pseudo ISR |
|
254 static TPseudoIsr Isr; |
|
255 // transfer failure simulation |
|
256 static TInt FailCount[KChannelCount]; |
|
257 static TInt InterruptsToMiss[KChannelCount]; |
|
258 }; |
|
259 |
|
260 TUint32 DmacSg::ChannelControl[KChannelCount]; |
|
261 TUint8* DmacSg::SrcAddr[KChannelCount]; |
|
262 TUint8* DmacSg::DestAddr[KChannelCount]; |
|
263 TInt DmacSg::Count[KChannelCount]; |
|
264 TUint DmacSg::Control[KChannelCount]; |
|
265 DmacSg::SDes* DmacSg::NextDes[KChannelCount]; |
|
266 TUint32 DmacSg::CompletionInt; |
|
267 TUint32 DmacSg::ErrorInt; |
|
268 TPseudoIsr DmacSg::Isr; |
|
269 TInt DmacSg::FailCount[KChannelCount]; |
|
270 TInt DmacSg::InterruptsToMiss[KChannelCount]; |
|
271 TInt DmacSg::CurrentChannel; |
|
272 TBool DmacSg::IsDescriptorLoaded[KChannelCount]; |
|
273 |
|
274 |
|
275 void DmacSg::DoTransfer() |
|
276 { |
|
277 if (ChannelControl[CurrentChannel] & EChannelBitRun) |
|
278 { |
|
279 if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0) |
|
280 { |
|
281 ChannelControl[CurrentChannel] &= ~EChannelBitRun; |
|
282 ErrorInt |= 1 << CurrentChannel; |
|
283 Isr(); |
|
284 } |
|
285 else |
|
286 { |
|
287 if (IsDescriptorLoaded[CurrentChannel]) |
|
288 { |
|
289 if (Count[CurrentChannel] == 0) |
|
290 { |
|
291 IsDescriptorLoaded[CurrentChannel] = EFalse; |
|
292 if (Control[CurrentChannel] & EDesBitInt) |
|
293 { |
|
294 if (InterruptsToMiss[CurrentChannel] > 0) |
|
295 InterruptsToMiss[CurrentChannel]--; |
|
296 else |
|
297 { |
|
298 CompletionInt |= 1 << CurrentChannel; |
|
299 Isr(); |
|
300 } |
|
301 } |
|
302 } |
|
303 else |
|
304 { |
|
305 TInt s = Min(Count[CurrentChannel], KBurstSize); |
|
306 memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s); |
|
307 Count[CurrentChannel] -= s; |
|
308 SrcAddr[CurrentChannel] += s; |
|
309 DestAddr[CurrentChannel] += s; |
|
310 } |
|
311 } |
|
312 // Need to test again as new descriptor must be loaded if |
|
313 // completion has just occured. |
|
314 if (! IsDescriptorLoaded[CurrentChannel]) |
|
315 { |
|
316 if (NextDes[CurrentChannel] != NULL) |
|
317 { |
|
318 SrcAddr[CurrentChannel] = NextDes[CurrentChannel]->iSrcAddr; |
|
319 DestAddr[CurrentChannel] = NextDes[CurrentChannel]->iDestAddr; |
|
320 Count[CurrentChannel] = NextDes[CurrentChannel]->iCount; |
|
321 Control[CurrentChannel] = NextDes[CurrentChannel]->iControl; |
|
322 NextDes[CurrentChannel] = NextDes[CurrentChannel]->iNext; |
|
323 IsDescriptorLoaded[CurrentChannel] = ETrue; |
|
324 } |
|
325 else |
|
326 ChannelControl[CurrentChannel] &= ~EChannelBitRun; |
|
327 } |
|
328 } |
|
329 } |
|
330 |
|
331 CurrentChannel++; |
|
332 if (CurrentChannel >= KChannelCount) |
|
333 CurrentChannel = 0; |
|
334 } |
|
335 |
|
336 |
|
337 void DmacSg::Enable(TInt aIdx) |
|
338 { |
|
339 SrcAddr[aIdx] = NextDes[aIdx]->iSrcAddr; |
|
340 DestAddr[aIdx] = NextDes[aIdx]->iDestAddr; |
|
341 Count[aIdx] = NextDes[aIdx]->iCount; |
|
342 Control[aIdx] = NextDes[aIdx]->iControl; |
|
343 NextDes[aIdx] = NextDes[aIdx]->iNext; |
|
344 IsDescriptorLoaded[aIdx] = ETrue; |
|
345 ChannelControl[aIdx] |= EChannelBitRun; |
|
346 } |
|
347 |
|
348 ////////////////////////////////////////////////////////////////////////////// |
|
349 |
|
350 class DmacSim |
|
351 /** |
|
352 Harness calling the various DMA controller simulators periodically. |
|
353 */ |
|
354 { |
|
355 public: |
|
356 static void StartEmulation(); |
|
357 static void StopEmulation(); |
|
358 private: |
|
359 enum { KPeriod = 1 }; // in ms |
|
360 static void TickCB(TAny* aThis); |
|
361 static NTimer Timer; |
|
362 }; |
|
363 |
|
364 NTimer DmacSim::Timer; |
|
365 |
|
366 void DmacSim::StartEmulation() |
|
367 { |
|
368 new (&Timer) NTimer(&TickCB, 0); |
|
369 __DMA_ASSERTA(Timer.OneShot(KPeriod, EFalse) == KErrNone); |
|
370 } |
|
371 |
|
372 void DmacSim::StopEmulation() |
|
373 { |
|
374 Timer.Cancel(); |
|
375 } |
|
376 |
|
377 void DmacSim::TickCB(TAny*) |
|
378 { |
|
379 DmacSb::DoTransfer(); |
|
380 DmacDb::DoTransfer(); |
|
381 DmacSg::DoTransfer(); |
|
382 __DMA_ASSERTA(Timer.Again(KPeriod) == KErrNone); |
|
383 } |
|
384 |
|
385 ////////////////////////////////////////////////////////////////////////////// |
|
386 // PSL FOR DMA SIMULATION |
|
387 ////////////////////////////////////////////////////////////////////////////// |
|
388 |
|
389 class DSimSbController : public TDmac |
|
390 { |
|
391 public: |
|
392 DSimSbController(); |
|
393 private: |
|
394 static void Isr(); |
|
395 // from TDmac |
|
396 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); |
|
397 virtual void StopTransfer(const TDmaChannel& aChannel); |
|
398 virtual TInt FailNext(const TDmaChannel& aChannel); |
|
399 virtual TBool IsIdle(const TDmaChannel& aChannel); |
|
400 virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
401 virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
402 public: |
|
403 static const SCreateInfo KInfo; |
|
404 TDmaSbChannel iChannels[KChannelCount]; |
|
405 }; |
|
406 |
|
407 DSimSbController SbController; |
|
408 |
|
409 const TDmac::SCreateInfo DSimSbController::KInfo = |
|
410 { |
|
411 KChannelCount, |
|
412 KDesCount, |
|
413 0, |
|
414 sizeof(SDmaPseudoDes), |
|
415 0, |
|
416 }; |
|
417 |
|
418 DSimSbController::DSimSbController() |
|
419 : TDmac(KInfo) |
|
420 { |
|
421 DmacSb::Isr = Isr; |
|
422 } |
|
423 |
|
424 |
|
425 void DSimSbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) |
|
426 { |
|
427 TUint32 i = aChannel.PslId(); |
|
428 const SDmaPseudoDes& des = HdrToDes(aHdr); |
|
429 DmacSb::SrcAddr[i] = (TUint8*) des.iSrc; |
|
430 DmacSb::DestAddr[i] = (TUint8*) des.iDest; |
|
431 DmacSb::Count[i] = des.iCount; |
|
432 DmacSb::ControlStatus[i] |= DmacSb::ECsRun; |
|
433 } |
|
434 |
|
435 |
|
436 void DSimSbController::StopTransfer(const TDmaChannel& aChannel) |
|
437 { |
|
438 __e32_atomic_and_ord32(&DmacSb::ControlStatus[aChannel.PslId()], (TUint32)~DmacSb::ECsRun); |
|
439 } |
|
440 |
|
441 |
|
442 TInt DSimSbController::FailNext(const TDmaChannel& aChannel) |
|
443 { |
|
444 DmacSb::FailCount[aChannel.PslId()] = 1; |
|
445 return KErrNone; |
|
446 } |
|
447 |
|
448 |
|
449 TBool DSimSbController::IsIdle(const TDmaChannel& aChannel) |
|
450 { |
|
451 return (DmacSb::ControlStatus[aChannel.PslId()] & DmacSb::ECsRun) == 0; |
|
452 } |
|
453 |
|
454 |
|
455 TInt DSimSbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
|
456 { |
|
457 return KMaxTransferSize; |
|
458 } |
|
459 |
|
460 |
|
461 TUint DSimSbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
|
462 { |
|
463 return KMemAlignMask; |
|
464 } |
|
465 |
|
466 |
|
467 void DSimSbController::Isr() |
|
468 { |
|
469 for (TInt i = 0; i < KChannelCount; i++) |
|
470 { |
|
471 TUint32 mask = (1 << i); |
|
472 if (DmacSb::CompletionInt & mask) |
|
473 { |
|
474 DmacSb::CompletionInt &= ~mask; |
|
475 HandleIsr(SbController.iChannels[i], ETrue); |
|
476 } |
|
477 if (DmacSb::ErrorInt & mask) |
|
478 { |
|
479 DmacSb::ErrorInt &= ~mask; |
|
480 HandleIsr(SbController.iChannels[i], EFalse); |
|
481 } |
|
482 } |
|
483 } |
|
484 |
|
485 ////////////////////////////////////////////////////////////////////////////// |
|
486 |
|
487 class DSimDbController : public TDmac |
|
488 { |
|
489 public: |
|
490 DSimDbController(); |
|
491 private: |
|
492 static void Isr(); |
|
493 // from TDmac |
|
494 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); |
|
495 virtual void StopTransfer(const TDmaChannel& aChannel); |
|
496 virtual TInt FailNext(const TDmaChannel& aChannel); |
|
497 virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount); |
|
498 virtual TBool IsIdle(const TDmaChannel& aChannel); |
|
499 virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
500 virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
501 public: |
|
502 static const SCreateInfo KInfo; |
|
503 TDmaDbChannel iChannels[KChannelCount]; |
|
504 }; |
|
505 |
|
506 DSimDbController DbController; |
|
507 |
|
508 const TDmac::SCreateInfo DSimDbController::KInfo = |
|
509 { |
|
510 KChannelCount, |
|
511 KDesCount, |
|
512 0, |
|
513 sizeof(SDmaPseudoDes), |
|
514 0, |
|
515 }; |
|
516 |
|
517 |
|
518 DSimDbController::DSimDbController() |
|
519 : TDmac(KInfo) |
|
520 { |
|
521 DmacDb::Isr = Isr; |
|
522 } |
|
523 |
|
524 |
|
525 void DSimDbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) |
|
526 { |
|
527 TUint32 i = aChannel.PslId(); |
|
528 const SDmaPseudoDes& des = HdrToDes(aHdr); |
|
529 DmacDb::PrgSrcAddr[i] = (TUint8*) des.iSrc; |
|
530 DmacDb::PrgDestAddr[i] = (TUint8*) des.iDest; |
|
531 DmacDb::PrgCount[i] = des.iCount; |
|
532 DmacDb::Enable(i); |
|
533 } |
|
534 |
|
535 |
|
536 void DSimDbController::StopTransfer(const TDmaChannel& aChannel) |
|
537 { |
|
538 __e32_atomic_and_ord32(&DmacDb::ControlStatus[aChannel.PslId()], (TUint32)~(DmacDb::ECsRun|DmacDb::ECsPrg)); |
|
539 } |
|
540 |
|
541 |
|
542 TInt DSimDbController::FailNext(const TDmaChannel& aChannel) |
|
543 { |
|
544 DmacDb::FailCount[aChannel.PslId()] = 1; |
|
545 return KErrNone; |
|
546 } |
|
547 |
|
548 |
|
549 TInt DSimDbController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount) |
|
550 { |
|
551 __DMA_ASSERTD((DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0); |
|
552 __DMA_ASSERTD(aInterruptCount >= 0); |
|
553 // At most one interrupt can be missed with double-buffer controller |
|
554 if (aInterruptCount == 1) |
|
555 { |
|
556 DmacDb::InterruptsToMiss[aChannel.PslId()] = aInterruptCount; |
|
557 return KErrNone; |
|
558 } |
|
559 else |
|
560 return KErrNotSupported; |
|
561 } |
|
562 |
|
563 |
|
564 TBool DSimDbController::IsIdle(const TDmaChannel& aChannel) |
|
565 { |
|
566 return (DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0; |
|
567 } |
|
568 |
|
569 |
|
570 TInt DSimDbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
|
571 { |
|
572 return KMaxTransferSize; |
|
573 } |
|
574 |
|
575 |
|
576 TUint DSimDbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
|
577 { |
|
578 return KMemAlignMask; |
|
579 } |
|
580 |
|
581 |
|
582 void DSimDbController::Isr() |
|
583 { |
|
584 for (TInt i = 0; i < KChannelCount; i++) |
|
585 { |
|
586 TUint32 mask = (1 << i); |
|
587 if (DmacDb::CompletionInt & mask) |
|
588 { |
|
589 DmacDb::CompletionInt &= ~mask; |
|
590 HandleIsr(DbController.iChannels[i], ETrue); |
|
591 } |
|
592 if (DmacDb::ErrorInt & mask) |
|
593 { |
|
594 DmacDb::ErrorInt &= ~mask; |
|
595 HandleIsr(DbController.iChannels[i], EFalse); |
|
596 } |
|
597 } |
|
598 } |
|
599 |
|
600 ////////////////////////////////////////////////////////////////////////////// |
|
601 |
|
602 class DSimSgController : public TDmac |
|
603 { |
|
604 public: |
|
605 DSimSgController(); |
|
606 private: |
|
607 static void Isr(); |
|
608 // from TDmac |
|
609 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); |
|
610 virtual void StopTransfer(const TDmaChannel& aChannel); |
|
611 virtual TBool IsIdle(const TDmaChannel& aChannel); |
|
612 virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
613 virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
614 virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
615 TUint aFlags, TUint32 aPslInfo, TUint32 aCookie); |
|
616 virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); |
|
617 virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
|
618 const SDmaDesHdr& aNewHdr); |
|
619 virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); |
|
620 virtual TInt FailNext(const TDmaChannel& aChannel); |
|
621 virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount); |
|
622 private: |
|
623 inline DmacSg::SDes* HdrToHwDes(const SDmaDesHdr& aHdr); |
|
624 public: |
|
625 static const SCreateInfo KInfo; |
|
626 TDmaSgChannel iChannels[KChannelCount]; |
|
627 }; |
|
628 |
|
629 DSimSgController SgController; |
|
630 |
|
631 const TDmac::SCreateInfo DSimSgController::KInfo = |
|
632 { |
|
633 KChannelCount, |
|
634 KDesCount, |
|
635 KCapsBitHwDes, |
|
636 sizeof(DmacSg::SDes), |
|
637 #ifdef __WINS__ |
|
638 0, |
|
639 #else |
|
640 EMapAttrSupRw|EMapAttrFullyBlocking, |
|
641 #endif |
|
642 }; |
|
643 |
|
644 |
|
645 inline DmacSg::SDes* DSimSgController::HdrToHwDes(const SDmaDesHdr& aHdr) |
|
646 { |
|
647 return static_cast<DmacSg::SDes*>(TDmac::HdrToHwDes(aHdr)); |
|
648 } |
|
649 |
|
650 |
|
651 DSimSgController::DSimSgController() |
|
652 : TDmac(KInfo) |
|
653 { |
|
654 DmacSg::Isr = Isr; |
|
655 } |
|
656 |
|
657 |
|
658 void DSimSgController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) |
|
659 { |
|
660 TUint32 i = aChannel.PslId(); |
|
661 DmacSg::NextDes[i] = HdrToHwDes(aHdr); |
|
662 DmacSg::Enable(i); |
|
663 } |
|
664 |
|
665 |
|
666 void DSimSgController::StopTransfer(const TDmaChannel& aChannel) |
|
667 { |
|
668 __e32_atomic_and_ord32(&DmacSg::ChannelControl[aChannel.PslId()], (TUint32)~DmacSg::EChannelBitRun); |
|
669 } |
|
670 |
|
671 |
|
672 void DSimSgController::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
673 TUint /*aFlags*/, TUint32 /*aPslInfo*/, TUint32 /*aCookie*/) |
|
674 { |
|
675 DmacSg::SDes& des = *HdrToHwDes(aHdr); |
|
676 des.iSrcAddr = reinterpret_cast<TUint8*>(aSrc); |
|
677 des.iDestAddr = reinterpret_cast<TUint8*>(aDest); |
|
678 des.iCount = static_cast<TInt16>(aCount); |
|
679 des.iControl |= DmacSg::EDesBitInt; |
|
680 des.iNext = NULL; |
|
681 } |
|
682 |
|
683 |
|
684 void DSimSgController::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr) |
|
685 { |
|
686 DmacSg::SDes& des = *HdrToHwDes(aHdr); |
|
687 des.iControl &= ~DmacSg::EDesBitInt; |
|
688 des.iNext = HdrToHwDes(aNextHdr); |
|
689 } |
|
690 |
|
691 |
|
692 void DSimSgController::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
|
693 const SDmaDesHdr& aNewHdr) |
|
694 { |
|
695 TUint32 i = aChannel.PslId(); |
|
696 DmacSg::SDes* pNewDes = HdrToHwDes(aNewHdr); |
|
697 TInt prevLevel = NKern::DisableAllInterrupts(); |
|
698 |
|
699 if ((DmacSg::ChannelControl[i] & DmacSg::EChannelBitRun) == 0) |
|
700 { |
|
701 DmacSg::NextDes[i] = pNewDes; |
|
702 DmacSg::Enable(i); |
|
703 } |
|
704 else if (DmacSg::NextDes[i] == NULL) |
|
705 DmacSg::NextDes[i] = pNewDes; |
|
706 else |
|
707 HdrToHwDes(aLastHdr)->iNext = pNewDes; |
|
708 |
|
709 NKern::RestoreInterrupts(prevLevel); |
|
710 } |
|
711 |
|
712 |
|
713 void DSimSgController::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr) |
|
714 { |
|
715 DmacSg::SDes* pD = HdrToHwDes(aHdr); |
|
716 pD->iNext = NULL; |
|
717 pD->iControl |= DmacSg::EDesBitInt; |
|
718 } |
|
719 |
|
720 |
|
721 TInt DSimSgController::FailNext(const TDmaChannel& aChannel) |
|
722 { |
|
723 __DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0); |
|
724 DmacSg::FailCount[aChannel.PslId()] = 1; |
|
725 return KErrNone; |
|
726 } |
|
727 |
|
728 |
|
729 TInt DSimSgController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount) |
|
730 { |
|
731 __DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0); |
|
732 __DMA_ASSERTD(aInterruptCount >= 0); |
|
733 DmacSg::InterruptsToMiss[aChannel.PslId()] = aInterruptCount; |
|
734 return KErrNone; |
|
735 } |
|
736 |
|
737 |
|
738 TBool DSimSgController::IsIdle(const TDmaChannel& aChannel) |
|
739 { |
|
740 return (DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0; |
|
741 } |
|
742 |
|
743 |
|
744 TInt DSimSgController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
|
745 { |
|
746 return KMaxTransferSize; |
|
747 } |
|
748 |
|
749 |
|
750 TUint DSimSgController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) |
|
751 { |
|
752 return KMemAlignMask; |
|
753 } |
|
754 |
|
755 |
|
756 void DSimSgController::Isr() |
|
757 { |
|
758 for (TInt i = 0; i < KChannelCount; i++) |
|
759 { |
|
760 TUint32 mask = (1 << i); |
|
761 if (DmacSg::CompletionInt & mask) |
|
762 { |
|
763 DmacSg::CompletionInt &= ~mask; |
|
764 HandleIsr(SgController.iChannels[i], ETrue); |
|
765 } |
|
766 if (DmacSg::ErrorInt & mask) |
|
767 { |
|
768 DmacSg::ErrorInt &= ~mask; |
|
769 HandleIsr(SgController.iChannels[i], EFalse); |
|
770 } |
|
771 } |
|
772 } |
|
773 |
|
774 |
|
775 ////////////////////////////////////////////////////////////////////////////// |
|
776 // Channel opening/closing |
|
777 |
|
778 enum TController { ESb=0, EDb=1, ESg=2 }; |
|
779 |
|
780 const TUint32 KControllerMask = 0x30; |
|
781 const TUint32 KControllerShift = 4; |
|
782 const TUint32 KChannelIdxMask = 3; |
|
783 |
|
784 #define MKCHN(type, idx) (((type)<<KControllerShift)|idx) |
|
785 |
|
786 static TUint32 TestSbChannels[] = { MKCHN(ESb,0), MKCHN(ESb,1), MKCHN(ESb,2), MKCHN(ESb,3) }; |
|
787 static TUint32 TestDbChannels[] = { MKCHN(EDb,0), MKCHN(EDb,1), MKCHN(EDb,2), MKCHN(EDb,3) }; |
|
788 static TUint32 TestSgChannels[] = { MKCHN(ESg,0), MKCHN(ESg,1), MKCHN(ESg,2), MKCHN(ESg,3) }; |
|
789 |
|
790 static TDmaTestInfo TestInfo = |
|
791 { |
|
792 KMaxTransferSize, |
|
793 KMemAlignMask, |
|
794 0, |
|
795 KChannelCount, |
|
796 TestSbChannels, |
|
797 KChannelCount, |
|
798 TestDbChannels, |
|
799 KChannelCount, |
|
800 TestSgChannels, |
|
801 }; |
|
802 |
|
803 EXPORT_C const TDmaTestInfo& DmaTestInfo() |
|
804 { |
|
805 return TestInfo; |
|
806 } |
|
807 |
|
808 // Keep track of opened channels so Tick callback used to fake DMA |
|
809 // transfers is enabled only when necessary. |
|
810 static TInt OpenChannelCount = 0; |
|
811 |
|
812 |
|
813 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId) |
|
814 { |
|
815 TInt dmac = (aOpenId & KControllerMask) >> KControllerShift; |
|
816 __DMA_ASSERTD(dmac < 3); |
|
817 TInt i = aOpenId & KChannelIdxMask; |
|
818 TDmaChannel* pC = NULL; |
|
819 TDmac* controller = NULL; |
|
820 switch (dmac) |
|
821 { |
|
822 case ESb: |
|
823 pC = SbController.iChannels + i; |
|
824 controller = &SbController; |
|
825 break; |
|
826 case EDb: |
|
827 pC = DbController.iChannels + i; |
|
828 controller = &DbController; |
|
829 break; |
|
830 case ESg: |
|
831 pC = SgController.iChannels + i; |
|
832 controller = &SgController; |
|
833 break; |
|
834 default: |
|
835 __DMA_CANT_HAPPEN(); |
|
836 } |
|
837 |
|
838 if (++OpenChannelCount == 1) |
|
839 { |
|
840 __KTRACE_OPT(KDMA, Kern::Printf("Enabling DMA simulation")); |
|
841 DmacSim::StartEmulation(); |
|
842 } |
|
843 if (pC->IsOpened()) |
|
844 return NULL; |
|
845 pC->iController = controller; |
|
846 pC->iPslId = i; |
|
847 return pC; |
|
848 } |
|
849 |
|
850 |
|
851 void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/) |
|
852 { |
|
853 if (--OpenChannelCount == 0) |
|
854 { |
|
855 DmacSim::StopEmulation(); |
|
856 __KTRACE_OPT(KDMA, Kern::Printf("Stopping DMA simulation")); |
|
857 } |
|
858 } |
|
859 |
|
860 TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/) |
|
861 { |
|
862 return KErrNotSupported; |
|
863 } |
|
864 |
|
865 ////////////////////////////////////////////////////////////////////////////// |
|
866 |
|
867 // |
|
868 // On hardware, this code is inside a kernel extension. |
|
869 // |
|
870 |
|
871 DECLARE_STANDARD_EXTENSION() |
|
872 { |
|
873 __KTRACE_OPT(KDMA, Kern::Printf("Starting DMA simulator...")); |
|
874 TInt r; |
|
875 r = SbController.Create(DSimSbController::KInfo); |
|
876 if (r != KErrNone) |
|
877 return r; |
|
878 r = DbController.Create(DSimDbController::KInfo); |
|
879 if (r != KErrNone) |
|
880 return r; |
|
881 r = SgController.Create(DSimSgController::KInfo); |
|
882 if (r != KErrNone) |
|
883 return r; |
|
884 |
|
885 return KErrNone; |
|
886 } |
|
887 |
|
888 // |
|
889 // On WINS, this code is inside a LDD (see mmp file) so we need some |
|
890 // bootstrapping code to call the kernel extension entry point. |
|
891 // |
|
892 |
|
893 class DDummyLdd : public DLogicalDevice |
|
894 { |
|
895 public: |
|
896 // from DLogicalDevice |
|
897 TInt Install(); |
|
898 void GetCaps(TDes8& aDes) const; |
|
899 TInt Create(DLogicalChannelBase*& aChannel); |
|
900 }; |
|
901 |
|
902 TInt DDummyLdd::Create(DLogicalChannelBase*& aChannel) |
|
903 { |
|
904 aChannel=NULL; |
|
905 return KErrNone; |
|
906 } |
|
907 |
|
908 TInt DDummyLdd::Install() |
|
909 { |
|
910 _LIT(KLddName, "DmaSim"); |
|
911 TInt r = SetName(&KLddName); |
|
912 if (r == KErrNone) |
|
913 r = InitExtension(); |
|
914 return r; |
|
915 } |
|
916 |
|
917 void DDummyLdd::GetCaps(TDes8& /*aDes*/) const |
|
918 { |
|
919 } |
|
920 |
|
921 EXPORT_C DLogicalDevice* CreateLogicalDevice() |
|
922 { |
|
923 return new DDummyLdd; |
|
924 } |
|
925 |
|
926 |
|
927 //--- |