0
|
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
|