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