|
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 // e32\include\drivers\dma.h |
|
15 // DMA framework API |
|
16 // |
|
17 // |
|
18 |
|
19 #ifndef __DMA_H__ |
|
20 #define __DMA_H__ |
|
21 |
|
22 #include <kernel/kern_priv.h> |
|
23 |
|
24 |
|
25 ////////////////////////////////////////////////////////////////////////////// |
|
26 // Debug Support - KDmaPanicCat is defined in each source file |
|
27 |
|
28 #define __DMA_ASSERTD(e) __ASSERT_DEBUG(e, Kern::Fault(KDmaPanicCat, __LINE__)) |
|
29 #define __DMA_ASSERTA(e) __ASSERT_ALWAYS(e, Kern::Fault(KDmaPanicCat, __LINE__)) |
|
30 #ifdef _DEBUG |
|
31 #define __DMA_CANT_HAPPEN() Kern::Fault(KDmaPanicCat, __LINE__) |
|
32 #define __DMA_DECLARE_INVARIANT public: void Invariant(); |
|
33 #define __DMA_INVARIANT() Invariant() |
|
34 #else |
|
35 #define __DMA_CANT_HAPPEN() |
|
36 #define __DMA_DECLARE_INVARIANT |
|
37 #define __DMA_INVARIANT() |
|
38 #endif |
|
39 |
|
40 |
|
41 ////////////////////////////////////////////////////////////////////////////// |
|
42 // INTERFACE EXPOSED TO DEVICE-DRIVERS |
|
43 ////////////////////////////////////////////////////////////////////////////// |
|
44 |
|
45 /** |
|
46 Bitmasks used for configuring a DMA request. |
|
47 |
|
48 In general, specify KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest) if |
|
49 the source (resp. destination) is a memory buffer and clear |
|
50 KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest) if the source |
|
51 (resp. destination) is a peripheral. |
|
52 |
|
53 If the location is given as a physical address (rather than a linear one) |
|
54 then also specify KDmaPhysAddrSrc and/or KDmaPhysAddrDest. |
|
55 |
|
56 The EKA1 "Fill Mode" can be implemented by omitting KDmaIncSrc. |
|
57 |
|
58 Some peripherals may require a post-increment address mode. |
|
59 |
|
60 @see DDmaRequest::Fragment |
|
61 @publishedPartner |
|
62 @released |
|
63 */ |
|
64 |
|
65 enum TDmaRequestFlags |
|
66 { |
|
67 /** Source is address of memory buffer */ |
|
68 KDmaMemSrc = 0x01, |
|
69 /** Destination is address of memory buffer */ |
|
70 KDmaMemDest = 0x02, |
|
71 /** Source address must be post-incremented during transfer */ |
|
72 KDmaIncSrc = 0x04, |
|
73 /** Destination address must be post-incremented during transfer */ |
|
74 KDmaIncDest = 0x08, |
|
75 /** Source address is a physical address (as opposed to a linear one) */ |
|
76 KDmaPhysAddrSrc = 0x10, |
|
77 /** Destination address is a physical address (as opposed to a linear one) */ |
|
78 KDmaPhysAddrDest = 0x20, |
|
79 /** Request a different max transfer size (for instance for test purposes) */ |
|
80 KDmaAltTransferLen = 0x40 |
|
81 }; |
|
82 |
|
83 |
|
84 ////////////////////////////////////////////////////////////////////////////// |
|
85 |
|
86 class TDmaChannel; |
|
87 struct SDmaDesHdr; |
|
88 |
|
89 /** A DMA request is a list of fragments small enough to be transferred in one go |
|
90 by the DMAC. |
|
91 |
|
92 In general, fragmentation is done in the framework by calling Fragment() but |
|
93 clients with special needs can allocate a blank descriptor list with |
|
94 ExpandDesList() and customise it to fit their needs. |
|
95 |
|
96 Clients should not set attributes directly, but should use the various functions |
|
97 instead. |
|
98 |
|
99 This class has not been designed to be called from several concurrent threads. |
|
100 Multithreaded clients must implement their own locking scheme (via DMutex). |
|
101 |
|
102 Fast mutexes are used internally to protect data structures accessed both |
|
103 by the client thread and the DFC thread. Therefore no fast mutex can be held |
|
104 when calling a request function. |
|
105 |
|
106 @publishedPartner |
|
107 @released |
|
108 */ |
|
109 class DDmaRequest : public DBase |
|
110 { |
|
111 friend class TDmaChannel; |
|
112 public: |
|
113 /** The outcome of the transfer */ |
|
114 enum TResult {EBadResult=0, EOk, EError}; |
|
115 /** The signature of the completion/failure callback function */ |
|
116 typedef void (*TCallback)(TResult, TAny*); |
|
117 public: |
|
118 |
|
119 /** |
|
120 Create a new transfer request. |
|
121 |
|
122 @param aChannel The channel this request is bound to. |
|
123 @param aCb Callback function called on transfer completion or failure (in channel |
|
124 DFC context). Can be NULL. |
|
125 @param aCbArg Argument passed to callback function. |
|
126 @param aMaxTransferSize Maximum fragment size. If not specified, defaults to the maximum size |
|
127 supported by the DMA controller for the type of transfer that is later scheduled. |
|
128 */ |
|
129 IMPORT_C DDmaRequest(TDmaChannel& aChannel, TCallback aCb=NULL, TAny* aCbArg=NULL, TInt aMaxTransferSize=0); |
|
130 |
|
131 |
|
132 /** |
|
133 Destructor. |
|
134 |
|
135 Assume the request is not being transferred or pending. |
|
136 */ |
|
137 IMPORT_C ~DDmaRequest(); |
|
138 |
|
139 |
|
140 /** |
|
141 Split request into a list of fragments small enough to be fed to the DMAC. |
|
142 |
|
143 The size of each fragment is smaller than or equal to the maximum transfer size |
|
144 supported by the DMAC. If the source and/or destination is memory, each |
|
145 fragment points to memory which is physically contiguous. |
|
146 |
|
147 The kind of transfer to perform is specified via a set of flags used by a PIL |
|
148 and a magic cookie passed to the PSL. If the source (resp. destination) is a |
|
149 peripheral, aSrc (resp. aDest) is treated as a magic cookie by the PIL and |
|
150 passed straight to the PSL. |
|
151 |
|
152 The request can be uninitialised or may have been fragmented previously. The |
|
153 previous configuration if any is lost whether or not the function succeeds. |
|
154 |
|
155 @param aSrc Source memory buffer linear address or peripheral magic cookie. |
|
156 @param aDest Destination memory buffer linear address or peripheral magic cookie. |
|
157 @param aCount Number of bytes to transfer. |
|
158 @param aFlags Bitmask characterising the transfer. |
|
159 @param aPslInfo Hardware-specific information passed to PSL. |
|
160 |
|
161 @return KErrNone if success. KErrArgument if aFlags and/or aPslInfo are invalid when finding |
|
162 the maximum transfer size. May also fail if running out of descriptors. |
|
163 |
|
164 @pre The request is not being transferred or pending. |
|
165 @pre The various parameters must be valid. The PIL or PSL will fault the |
|
166 kernel if not. |
|
167 |
|
168 @see TDmaRequestFlags |
|
169 */ |
|
170 IMPORT_C TInt Fragment(TUint32 aSrc, TUint32 aDest, TInt aCount, TUint aFlags, TUint32 aPslInfo); |
|
171 |
|
172 |
|
173 /** |
|
174 Transfer asynchronously this request. |
|
175 |
|
176 If this request's channel is idle, the request is transferred immediately. |
|
177 Otherwise, it is queued and transferred later. |
|
178 |
|
179 The client is responsible for ensuring cache consistency before and/or after the |
|
180 transfer if necessary. |
|
181 */ |
|
182 IMPORT_C void Queue(); |
|
183 |
|
184 |
|
185 /** |
|
186 Append new descriptor(s) to existing list. |
|
187 |
|
188 Clients needing to build a custom descriptor list should call this function to |
|
189 allocate the list and access the resulting list through iFirstHdr and iLastHdr. |
|
190 |
|
191 Clients should not change the value of iFirstHdr, iLastHdr and the iNext field |
|
192 of the descriptor headers to ensure descriptors can be deallocated. Clients |
|
193 are free to change hardware descriptors, including chaining, in whatever way |
|
194 suit them. |
|
195 |
|
196 Assume the request is not being transferred or pending. |
|
197 |
|
198 @param aCount Number of descriptors to append. |
|
199 |
|
200 @return KErrNone or KErrTooBig if not enough descriptors available. |
|
201 */ |
|
202 IMPORT_C TInt ExpandDesList(TInt aCount=1); |
|
203 |
|
204 |
|
205 /** |
|
206 Free resources associated with this request. |
|
207 |
|
208 Assume the request is not being transferred or pending. |
|
209 */ |
|
210 IMPORT_C void FreeDesList(); |
|
211 private: |
|
212 inline void OnDeque(); |
|
213 public: |
|
214 // WARNING: The following attributes are accessed both in client and DFC |
|
215 // context and so accesses must be protected with the channel lock. |
|
216 TDmaChannel& iChannel; /**< The channel this request is bound to */ |
|
217 volatile TCallback iCb; /**< Called on completion/failure (can be NULL) */ |
|
218 TAny* volatile iCbArg; /**< Callback argument */ |
|
219 TInt iDesCount; /**< The number of fragments in list */ |
|
220 SDmaDesHdr* iFirstHdr; /**< The first fragment in the list (or NULL) */ |
|
221 SDmaDesHdr* iLastHdr; /**< The last fragment in the list (or NULL) */ |
|
222 SDblQueLink iLink; /**< The link on channel queue of pending requests */ |
|
223 TBool iQueued; /**< Indicates whether request is pending or being transferred */ |
|
224 TInt iMaxTransferSize; /**< Defaults to DMA controller max. transfer size */ |
|
225 __DMA_DECLARE_INVARIANT |
|
226 }; |
|
227 |
|
228 |
|
229 ////////////////////////////////////////////////////////////////////////////// |
|
230 |
|
231 class TDmac; |
|
232 class DmaChannelMgr; |
|
233 |
|
234 /** DMA channel base class. |
|
235 |
|
236 This class has not been designed to be called from several concurrent |
|
237 client threads. Multithreaded clients must implement their own locking |
|
238 scheme (via DMutex). |
|
239 |
|
240 Fast mutexes are used internally to protect data structures accessed both |
|
241 by the client thread and the DFC one. Therefore no fast mutex can be held |
|
242 when calling a channel function. |
|
243 |
|
244 Must be allocated in BSS because it relies on being zeroed at |
|
245 creation-time. If the PSL really needs to allocate channels on the kernel |
|
246 heap, it must manually zero-initialises the instances. This can be |
|
247 achieved either by allocating raw memory and using placement new, or by |
|
248 wrapping channels into a DBase-derived wrapper. |
|
249 |
|
250 @publishedPartner |
|
251 @released |
|
252 */ |
|
253 class TDmaCancelInfo; |
|
254 class TDmaChannel |
|
255 { |
|
256 friend class DDmaRequest; |
|
257 friend class TDmac; |
|
258 friend class DmaChannelMgr; |
|
259 public: |
|
260 /** Information passed by client when opening channel */ |
|
261 struct SCreateInfo |
|
262 { |
|
263 /** Identifier used by PSL to select channel to open */ |
|
264 TUint32 iCookie; |
|
265 /** Number of descriptors this channel can use */ |
|
266 TInt iDesCount; |
|
267 /** DFC queue used to service DMA interrupts. The DFC thread |
|
268 priority must be higher than any client thread priority to |
|
269 avoid a situation where a transfer completes while being |
|
270 cancelled and another transfer is started before the DFC |
|
271 thread gets a chance to run. This would lead to a stray |
|
272 DFC. |
|
273 */ |
|
274 TDfcQue* iDfcQ; |
|
275 /** DFC priority */ |
|
276 TUint8 iDfcPriority; |
|
277 }; |
|
278 public: |
|
279 /** |
|
280 Opens the DMA channel. |
|
281 |
|
282 Channel selection is done by the hardware-specific layer using a cookie passed in |
|
283 via aInfo. |
|
284 |
|
285 The client should not delete the returned pointer as the framework owns |
|
286 channel objects. However, the client should explicitly close the channel when |
|
287 finished with it. |
|
288 |
|
289 @param aInfo Information passed by caller to select and configure channel. |
|
290 @param aChannel Point to open channel on successful return. NULL otherwise. |
|
291 |
|
292 @return KErrNone or standard error code. |
|
293 */ |
|
294 IMPORT_C static TInt Open(const SCreateInfo& aInfo, TDmaChannel*& aChannel); |
|
295 |
|
296 |
|
297 /** |
|
298 Closes a previously opened DMA channel. |
|
299 |
|
300 Assume the channel is idle and all requests have been deleted. |
|
301 */ |
|
302 IMPORT_C void Close(); |
|
303 |
|
304 |
|
305 /** |
|
306 Cancels the current request and all the pending ones. |
|
307 */ |
|
308 IMPORT_C void CancelAll(); |
|
309 inline TBool IsOpened() const; |
|
310 inline TBool IsQueueEmpty() const; |
|
311 inline TUint32 PslId() const; |
|
312 inline TInt FailNext(TInt aFragmentCount); |
|
313 inline TInt MissNextInterrupts(TInt aInterruptCount); |
|
314 inline TInt Extension(TInt aCmd, TAny* aArg); |
|
315 |
|
316 /** |
|
317 This is a function that allows the Platform Specific Layer (PSL) to extend the DMA API |
|
318 with new channel-independent operations. |
|
319 |
|
320 @param aCmd Command identifier. Negative values are reserved for Symbian use. |
|
321 @param aArg PSL-specific. |
|
322 |
|
323 @return KErrNotSupported if aCmd is not supported; a PSL specific value otherwise. |
|
324 */ |
|
325 IMPORT_C TInt StaticExtension(TInt aCmd, TAny* aArg); |
|
326 inline const TDmac* Controller() const; |
|
327 inline TInt MaxTransferSize(TUint aFlags, TUint32 aPslInfo); |
|
328 inline TUint MemAlignMask(TUint aFlags, TUint32 aPslInfo); |
|
329 protected: |
|
330 // Interface with state machines |
|
331 TDmaChannel(); |
|
332 virtual void DoQueue(DDmaRequest& aReq) = 0; |
|
333 virtual void DoCancelAll() = 0; |
|
334 virtual void DoUnlink(SDmaDesHdr& aHdr); |
|
335 virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr) = 0; |
|
336 #if defined(__CPU_ARM) && !defined(__EABI__) |
|
337 inline virtual ~TDmaChannel() {} // kill really annoying warning |
|
338 #endif |
|
339 private: |
|
340 static void Dfc(TAny*); |
|
341 void DoDfc(); |
|
342 inline void Wait(); |
|
343 inline void Signal(); |
|
344 inline TBool Flash(); |
|
345 void ResetStateMachine(); |
|
346 protected: |
|
347 TDmac* iController; // DMAC this channel belongs to (NULL when closed) |
|
348 TUint32 iPslId; // unique identifier provided by PSL |
|
349 NFastMutex iLock; // for data accessed in both client & DFC context |
|
350 SDmaDesHdr* iCurHdr; // fragment being transferred or NULL |
|
351 SDmaDesHdr** iNullPtr; // Pointer to NULL pointer following last fragment |
|
352 TDfc iDfc; // transfer completion/failure DFC |
|
353 TInt iMaxDesCount; // maximum number of allocable descriptors |
|
354 TInt iAvailDesCount; // available number of descriptors |
|
355 volatile TUint32 iIsrDfc; // Interface between ISR and DFC: |
|
356 enum { KErrorFlagMask = 0x80000000 }; // bit 31 - error flag |
|
357 enum { KCancelFlagMask = 0x40000000 }; // bit 30 - cancel flag |
|
358 enum { KDfcCountMask = 0x3FFFFFFF }; // bits 0-29 - number of queued DFCs |
|
359 SDblQue iReqQ; // being/about to be transferred request queue |
|
360 TInt iReqCount; // number of requests attached to this channel |
|
361 private: |
|
362 TDmaCancelInfo* iCancelInfo; |
|
363 __DMA_DECLARE_INVARIANT |
|
364 }; |
|
365 |
|
366 |
|
367 ////////////////////////////////////////////////////////////////////////////// |
|
368 // PIL-PSL INTERFACE |
|
369 ////////////////////////////////////////////////////////////////////////////// |
|
370 |
|
371 /** |
|
372 Generic DMA descriptor used if the DMAC does not have support for hardware |
|
373 descriptor. |
|
374 @see DDmaRequest::Fragment |
|
375 @publishedPartner |
|
376 @released |
|
377 */ |
|
378 |
|
379 struct SDmaPseudoDes |
|
380 { |
|
381 /** Source linear address or peripheral cookie */ |
|
382 TUint32 iSrc; |
|
383 /** Destination linear address or peripheral cookie */ |
|
384 TUint32 iDest; |
|
385 /** Number of bytes to transfer */ |
|
386 TInt iCount; |
|
387 /** @see TDmaRequestFlags */ |
|
388 TUint iFlags; |
|
389 /** PSL-specific information provided by client */ |
|
390 TUint32 iPslInfo; |
|
391 /** The same as TDmaChannel::SCreateInfo.iCookie */ |
|
392 TUint32 iCookie; |
|
393 }; |
|
394 |
|
395 |
|
396 /** |
|
397 Each hardware or pseudo descriptor is associated with a header. Headers are |
|
398 needed because hardware descriptors can not easily be extended to store |
|
399 additional information. |
|
400 @publishedPartner |
|
401 @released |
|
402 */ |
|
403 |
|
404 struct SDmaDesHdr |
|
405 { |
|
406 SDmaDesHdr* iNext; |
|
407 }; |
|
408 |
|
409 |
|
410 /** |
|
411 Interface used by PIL to open and close DMA channels. |
|
412 |
|
413 Must be implemented by PSL. |
|
414 @publishedPartner |
|
415 @released |
|
416 */ |
|
417 |
|
418 class DmaChannelMgr |
|
419 { |
|
420 public: |
|
421 /** Opens a channel using a client-provided identifier. |
|
422 This function must be implemented by the PSL. |
|
423 @param aOpenId Magic cookie passed by client |
|
424 This may identify the channel (if a static channel |
|
425 allocation scheme is used) or may indicate some |
|
426 properties which the channel must possess (if a dynamic |
|
427 channel allocation scheme is used). It may be set to |
|
428 zero always if dynamic allocation is used and all |
|
429 channels are equivalent. |
|
430 @return Pointer to channel if available, NULL otherwise. |
|
431 @pre The PIL calls this function with a global fast mutex held to |
|
432 avoid race conditions. |
|
433 @post If a non-NULL pointer is returned, the object pointed to has its |
|
434 iController and iPslId members set to valid states. |
|
435 iController should point to the controller handling that channel. |
|
436 iPslId should contain a value uniquely identifying the channel - |
|
437 it is used only for debug tracing by PIL. It can be given any |
|
438 convenient value by PSL (channel index, I/O port address, ...). |
|
439 */ |
|
440 static TDmaChannel* Open(TUint32 aOpenId); |
|
441 |
|
442 /** Performs platform-specific operations when a channel is closed. |
|
443 This function must be implemented by the PSL but the implementation can be |
|
444 a no-op. |
|
445 @param aChannel The channel to close |
|
446 @pre The PIL calls this function with a global fast mutex held to |
|
447 avoid race conditions. |
|
448 */ |
|
449 static void Close(TDmaChannel* aChannel); |
|
450 |
|
451 /** Function allowing PSL to extend DMA API with new channel-independent operations. |
|
452 This function must be implemented by the PSL. |
|
453 @param aCmd Command identifier. Negative values are reserved for Symbian use. |
|
454 @param aArg PSL-specific |
|
455 @return KErrNotSupported if aCmd is not supported. PSL-specific value otherwise. |
|
456 */ |
|
457 static TInt StaticExtension(TInt aCmd, TAny* aArg); |
|
458 |
|
459 static inline void Wait(); |
|
460 static inline void Signal(); |
|
461 private: |
|
462 static NFastMutex Lock; |
|
463 }; |
|
464 |
|
465 |
|
466 ////////////////////////////////////////////////////////////////////////////// |
|
467 |
|
468 /** |
|
469 Abstract base class representing a DMA controller. |
|
470 |
|
471 The class has two purposes. |
|
472 |
|
473 First, it is a container for channels, descriptors and descriptor headers. |
|
474 |
|
475 Second, it exposes a set of virtual functions implemented by |
|
476 the PSL (platform-specific layer). |
|
477 These functions are the main interfaces between |
|
478 the PIL (platform-independent layer) and PSL. |
|
479 |
|
480 Must be allocated in BSS because it relies on being zeroed at creation-time. |
|
481 |
|
482 @publishedPartner |
|
483 @released |
|
484 */ |
|
485 |
|
486 class TDmac |
|
487 { |
|
488 friend class DmaChannelMgr; |
|
489 // protected: VC++ complains when building PSL if following decl is protected |
|
490 public: |
|
491 /** Data required for creating a new instance */ |
|
492 struct SCreateInfo |
|
493 { |
|
494 /** Number of channels in controller */ |
|
495 TInt iChannelCount; |
|
496 /** Maximum number of descriptors (shared by all channels) */ |
|
497 TInt iDesCount; |
|
498 /** Bitmask. The only supported value is KCapsBitHwDes (hardware |
|
499 descriptors used). */ |
|
500 TUint32 iCaps; |
|
501 /** Size of individual descriptors. Use sizeof(SDmaPseudoDes) for |
|
502 single-buffer and double-buffer controllers. */ |
|
503 TInt iDesSize; |
|
504 /** Bitmask used when creating the hardware chunk storing the descriptor |
|
505 pool. Used only for hardware descriptors. The access part must be |
|
506 EMapAttrSupRw. If the chunk is cached and/or buffered, the PSL must |
|
507 flush the data cache and/or drain the write buffer in InitHwDes() |
|
508 and related functions. |
|
509 @see TMappingAttributes |
|
510 */ |
|
511 TUint iDesChunkAttribs; |
|
512 }; |
|
513 public: |
|
514 TInt Create(const SCreateInfo& aInfo); |
|
515 virtual ~TDmac(); |
|
516 TInt ReserveSetOfDes(TInt aCount); |
|
517 void ReleaseSetOfDes(TInt aCount); |
|
518 void InitDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
519 TUint aFlags, TUint32 aPslInfo, TUint32 aCookie); |
|
520 inline SDmaPseudoDes& HdrToDes(const SDmaDesHdr& aHdr) const; |
|
521 inline TAny* HdrToHwDes(const SDmaDesHdr& aHdr) const; |
|
522 inline TUint32 DesLinToPhys(TAny* aDes) const; |
|
523 inline void Wait(); |
|
524 inline void Signal(); |
|
525 protected: |
|
526 TDmac(const SCreateInfo& aInfo); |
|
527 |
|
528 public: |
|
529 /** |
|
530 Called by PIL when one fragment (single-buffer and double-buffer DMACs) or |
|
531 list of fragments (scatter/gather DMAC) is to be transferred. |
|
532 |
|
533 Called when initiating a new transfer and also, for double-buffer DMACs, for |
|
534 configuring the next fragment to transfer while the current one is |
|
535 ongoing. Must always be implemented by PSL. |
|
536 @param aChannel The channel to use |
|
537 @param aHdr Header associated with fragment to transfer |
|
538 */ |
|
539 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) = 0; |
|
540 |
|
541 /** |
|
542 Called by PIL to suspend transfer on a given channel. |
|
543 |
|
544 The suspension must occur synchronously as the PSL assumes the channel |
|
545 is suspended after calling this function. Must always be implemented by PSL. |
|
546 @param aChannel The channel to suspend |
|
547 */ |
|
548 virtual void StopTransfer(const TDmaChannel& aChannel) = 0; |
|
549 |
|
550 /** |
|
551 Called by PIL to check whether a DMA channel is idle. |
|
552 @param aChannel The channel to test |
|
553 @return ETrue if channel idle, EFalse if transferring. |
|
554 */ |
|
555 virtual TBool IsIdle(const TDmaChannel& aChannel) = 0; |
|
556 |
|
557 /** |
|
558 Called by PIL to retrieve from the PSL the maximum transfer size based on the |
|
559 parameters passed. |
|
560 @param aChannel Channel to be used for the transfer |
|
561 @param aFlags Bitmask characterising transfer |
|
562 @param aPslInfo Cookie passed by client and used by PSL |
|
563 @return 0 if invalid argument(s), -1 if transfer size not limited, the maximum |
|
564 transfer size otherwise. |
|
565 */ |
|
566 virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0; |
|
567 |
|
568 /** |
|
569 Called by PIL to retrieve from the PSL the memory alignment mask based on the |
|
570 parameters passed. Some DMA controllers impose alignment constraints on the base |
|
571 address of memory buffers. This mask is AND'ed against memory addresses computed |
|
572 during fragmentation. |
|
573 @param aChannel Channel to be used for the transfer |
|
574 @param aFlags Bitmask characterising transfer |
|
575 @param aPslInfo Cookie passed by client and used by PSL |
|
576 @return A value representing the alignment mask (e.g. 3 if buffer must be 4-byte aligned) |
|
577 */ |
|
578 virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0; |
|
579 |
|
580 /** |
|
581 Called by PIL during fragmentation to initialise a hardware descriptor. |
|
582 |
|
583 The PSL must assume the descriptor is the last in the chain and so set the |
|
584 interrupt bit and set the next descriptor field to an end of chain marker. |
|
585 Must be implemented by PSL if and only if the DMAC supports hardware |
|
586 descriptors. |
|
587 @param aHdr Header associated with hardware descriptor to initialise |
|
588 @param aSrc Transfer source |
|
589 @param aDest Transfer destination |
|
590 @param aCount Number of bytes to transfer (<= max. size supported by DMAC) |
|
591 @param aFlags Bitmask characterising transfer |
|
592 @param aPslInfo Cookie passed by client and used by PSL |
|
593 @param aCookie the channel selection cookie |
|
594 @see DDmaRequest::Fragment |
|
595 */ |
|
596 virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
597 TUint aFlags, TUint32 aPslInfo, TUint32 aCookie); |
|
598 |
|
599 /** |
|
600 Called by PIL, when fragmenting a request, to append a new hardware |
|
601 descriptor to an existing descriptor chain. |
|
602 |
|
603 Must clear the interrupt bit of the descriptor associated with aHdr. |
|
604 Must be implemented by PSL if and only if the DMAC supports hardware descriptors. |
|
605 @param aHdr Header associated with last fragment in chain |
|
606 @param aNextHdr Header associated with fragment to append |
|
607 */ |
|
608 virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); |
|
609 |
|
610 /** |
|
611 Called by PIL when queuing a new request while the channel is running. |
|
612 |
|
613 Must append the first hardware descriptor of the new request to the last |
|
614 descriptor in the existing chain. Must be implemented by PSL if and only if |
|
615 the DMAC supports hardware descriptors. |
|
616 @param aChannel The channel where the transfer takes place |
|
617 @param aLastHdr Header associated with last hardware descriptor in chain |
|
618 @param aNewHdr Header associated with first hardware descriptor in new request |
|
619 */ |
|
620 virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
|
621 const SDmaDesHdr& aNewHdr); |
|
622 |
|
623 /** |
|
624 Called by PIL when completing or cancelling a request to cause the PSL to unlink |
|
625 the last item in the h/w descriptor chain from a subsequent chain that it was |
|
626 possibly linked to. Must be implemented by the PSL if and only if the DMAC supports |
|
627 hardware descriptors. |
|
628 |
|
629 @param aChannel The channel where the request (and thus the descriptor) was queued |
|
630 @param aHdr Header associated with last h/w descriptor in completed/cancelled chain |
|
631 */ |
|
632 virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); |
|
633 |
|
634 /** |
|
635 Called by test harness to force an error when the next fragment is |
|
636 transferred. |
|
637 |
|
638 Must be implemented by the PSL only if possible. |
|
639 @param aChannel The channel where the error is to occur. |
|
640 @return KErrNone if implemented. The default PIL implementation returns |
|
641 KErrNotSupported and the test harness knows how to deal with that. |
|
642 */ |
|
643 virtual TInt FailNext(const TDmaChannel& aChannel); |
|
644 |
|
645 /** |
|
646 Called by test harness to force the DMA controller to miss one or |
|
647 more interrupts. |
|
648 |
|
649 Must be implemented by the PSL only if possible. |
|
650 @param aChannel The channel where the error is to occur |
|
651 @param aInterruptCount The number of interrupt to miss. |
|
652 @return KErrNone if implemented. The default PIL implementation returns |
|
653 KErrNotSupported and the test harness knows how to deal with that. |
|
654 */ |
|
655 virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount); |
|
656 |
|
657 /** Function allowing platform-specific layer to extend channel API with |
|
658 new channel-specific operations. |
|
659 @param aChannel Channel to operate on |
|
660 @param aCmd Command identifier. Negative values are reserved for Symbian use. |
|
661 @param aArg PSL-specific |
|
662 @return KErrNotSupported if aCmd is not supported. PSL-specific value otherwise. |
|
663 @see TDmaChannel::Extension |
|
664 */ |
|
665 virtual TInt Extension(TDmaChannel& aChannel, TInt aCmd, TAny* aArg); |
|
666 |
|
667 protected: |
|
668 static void HandleIsr(TDmaChannel& aChannel, TBool aIsComplete); |
|
669 private: |
|
670 TInt AllocDesPool(TUint aAttribs); |
|
671 void FreeDesPool(); |
|
672 private: |
|
673 NFastMutex iLock; // protect descriptor reservation and allocation |
|
674 const TInt iMaxDesCount; // initial number of descriptors and headers |
|
675 TInt iAvailDesCount; // current available number of descriptors and headers |
|
676 SDmaDesHdr* iHdrPool; // descriptor header dynamic array |
|
677 #ifndef __WINS__ |
|
678 DPlatChunkHw* iHwDesChunk; // chunk for hardware descriptor pool |
|
679 #endif |
|
680 TAny* iDesPool; // hardware or pseudo descriptor dynamic array |
|
681 const TInt iDesSize; // descriptor size in bytes |
|
682 public: |
|
683 const TUint iCaps; /*< what is supported by DMA controller */ |
|
684 enum {KCapsBitHwDes = 1}; /*< hardware descriptors supported */ |
|
685 SDmaDesHdr* iFreeHdr; /*< head of unallocated descriptors linked list */ |
|
686 #ifdef _DEBUG |
|
687 TBool IsValidHdr(const SDmaDesHdr* aHdr); |
|
688 #endif |
|
689 __DMA_DECLARE_INVARIANT |
|
690 }; |
|
691 |
|
692 |
|
693 ////////////////////////////////////////////////////////////////////////////// |
|
694 |
|
695 /** |
|
696 Single-buffer DMA channel. |
|
697 |
|
698 Can be instantiated or further derived by PSL. Not |
|
699 intended to be instantiated by client device drivers. |
|
700 @publishedPartner |
|
701 @released |
|
702 */ |
|
703 |
|
704 class TDmaSbChannel : public TDmaChannel |
|
705 { |
|
706 private: |
|
707 virtual void DoQueue(DDmaRequest& aReq); |
|
708 virtual void DoCancelAll(); |
|
709 virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr); |
|
710 private: |
|
711 TBool iTransferring; |
|
712 }; |
|
713 |
|
714 |
|
715 /** |
|
716 Double-buffer DMA channel. |
|
717 |
|
718 Can be instantiated or further derived by PSL. Not |
|
719 intended to be instantiated by client device drivers. |
|
720 @publishedPartner |
|
721 @released |
|
722 */ |
|
723 |
|
724 class TDmaDbChannel : public TDmaChannel |
|
725 { |
|
726 private: |
|
727 virtual void DoQueue(DDmaRequest& aReq); |
|
728 virtual void DoCancelAll(); |
|
729 virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr); |
|
730 private: |
|
731 enum { EIdle = 0, ETransferring, ETransferringLast } iState; |
|
732 }; |
|
733 |
|
734 |
|
735 /** |
|
736 Scatter-gather DMA channel. |
|
737 |
|
738 Can be instantiated or further derived by PSL. |
|
739 Not intended to be instantiated by client device drivers. |
|
740 @publishedPartner |
|
741 @released |
|
742 */ |
|
743 |
|
744 class TDmaSgChannel : public TDmaChannel |
|
745 { |
|
746 private: |
|
747 virtual void DoQueue(DDmaRequest& aReq); |
|
748 virtual void DoCancelAll(); |
|
749 virtual void DoUnlink(SDmaDesHdr& aHdr); |
|
750 virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr); |
|
751 private: |
|
752 TBool iTransferring; |
|
753 }; |
|
754 |
|
755 |
|
756 ////////////////////////////////////////////////////////////////////////////// |
|
757 // INTERFACE WITH TEST HARNESS |
|
758 ////////////////////////////////////////////////////////////////////////////// |
|
759 |
|
760 /** |
|
761 Set of information used by test harness. |
|
762 @publishedPartner |
|
763 @released |
|
764 */ |
|
765 |
|
766 struct TDmaTestInfo |
|
767 { |
|
768 /** Maximum transfer size in byte */ |
|
769 TInt iMaxTransferSize; |
|
770 /** 3->Memory buffers must be 4-byte aligned, 7->8-byte aligned, ... */ |
|
771 TUint iMemAlignMask; |
|
772 /** Cookie to pass to DDmaRequest::Fragment for memory-memory transfer*/ |
|
773 TUint32 iMemMemPslInfo; |
|
774 /** Number of test single-buffer channels */ |
|
775 TInt iMaxSbChannels; |
|
776 /** Pointer to array containing single-buffer test channel ids */ |
|
777 TUint32* iSbChannels; |
|
778 /** Number of test double-buffer channels */ |
|
779 TInt iMaxDbChannels; |
|
780 /** Pointer to array containing double-buffer test channel ids */ |
|
781 TUint32* iDbChannels; |
|
782 /** Number of test scatter-gather channels */ |
|
783 TInt iMaxSgChannels; |
|
784 /** Pointer to array containing scatter-gather test channel ids */ |
|
785 TUint32* iSgChannels; |
|
786 }; |
|
787 |
|
788 |
|
789 /** |
|
790 Provides access to test information structure stored in the PSL. |
|
791 |
|
792 Must be implemented by the PSL. |
|
793 @publishedPartner |
|
794 @released |
|
795 */ |
|
796 |
|
797 IMPORT_C const TDmaTestInfo& DmaTestInfo(); |
|
798 |
|
799 |
|
800 ////////////////////////////////////////////////////////////////////////////// |
|
801 |
|
802 #include <drivers/dma.inl> |
|
803 |
|
804 #endif |