kernel/eka/include/drivers/dma.h
changeset 0 a41df078684a
child 36 538db54a451d
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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