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