kernel/eka/include/drivers/dma.h
branchRCL_3
changeset 43 c1f20ce4abcf
parent 41 0ffb4e86fcc9
child 44 3e88ff8f41d5
equal deleted inserted replaced
42:a179b74831c9 43:c1f20ce4abcf
     1 // Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
     1 // Copyright (c) 2002-2009 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 "Eclipse Public License v1.0""
     4 // under the terms of the License "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 API
    15 // DMA Framework - Client API definition.
       
    16 //
    16 //
    17 //
    17 
    18 
    18 #ifndef __DMA_H__
    19 #ifndef __DMA_H__
    19 #define __DMA_H__
    20 #define __DMA_H__
    20 
    21 
    21 #include <kernel/kern_priv.h>
    22 
       
    23 #ifndef DMA_APIV2
       
    24 # include <drivers/dma_v1.h>
       
    25 #else
       
    26 # include <drivers/dma_v2.h>
       
    27 #endif	// #ifndef DMA_APIV2
    22 
    28 
    23 
    29 
    24 //////////////////////////////////////////////////////////////////////////////
    30 #endif	// #ifndef __DMA_H__
    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()
       
    33 #else
       
    34 #define __DMA_CANT_HAPPEN()
       
    35 #define __DMA_DECLARE_INVARIANT
       
    36 #define __DMA_INVARIANT()
       
    37 #endif
       
    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
       
   339 	appropriate 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 and previous observed values of
       
   348 	iQueuedRequests, the PSL may power down or power up the channel.
       
   349 
       
   350 	Note that iQueuedRequests gets accessed and changed by different
       
   351 	threads, so the PSL needs to take the usual precautions when evaluating
       
   352 	the variable's value. Also, due to the multithreaded framework
       
   353 	architecture, there is no guarantee that the function calls always
       
   354 	arrive at the PSL level in the strict chronological order of
       
   355 	iQueuedRequests being incremented/decremented in the PIL, i.e. it might
       
   356 	happen that the PSL finds iQueuedRequests to have the same value in two
       
   357 	or more consecutive calls (that's why the previous observed value needs
       
   358 	to be locally available and taken into account). It is however promised
       
   359 	that before any actual transfer commences the PSL will find the request
       
   360 	count to be greater than zero and that after the last request has
       
   361 	finished it will be found to be zero.
       
   362 
       
   363 	None of the internal DMA framework mutexes is being held by the PIL
       
   364 	when calling this function.
       
   365 
       
   366 	Here is an example implementation for a derived channel class:
       
   367 
       
   368 	@code
       
   369 
       
   370 		class TFooDmaChannel : public TDmaSgChannel
       
   371 			{
       
   372 			DMutex* iDmaMutex;
       
   373 			TInt iPrevQueuedRequests;
       
   374 			virtual void QueuedRequestCountChanged();
       
   375 			};
       
   376 
       
   377 		void TFooDmaChannel::QueuedRequestCountChanged()
       
   378 			{
       
   379 			Kern::MutexWait(*iDmaMutex);
       
   380 			const TInt queued_now = __e32_atomic_load_acq32(&iQueuedRequests);
       
   381 			if ((queued_now > 0) && (iPrevQueuedRequests == 0))
       
   382 				{
       
   383 				IncreasePowerCount(); // Base port specific
       
   384 				}
       
   385 			else if ((queued_now == 0) && (iPrevQueuedRequests > 0))
       
   386 				{
       
   387 				DecreasePowerCount(); // Base port specific
       
   388 				}
       
   389 			iPrevQueuedRequests = queued_now;
       
   390 			Kern::MutexSignal(*iDmaMutex);
       
   391 			}
       
   392 
       
   393 	@endcode
       
   394 
       
   395 	@see iQueuedRequests
       
   396 	*/
       
   397 	virtual void QueuedRequestCountChanged();
       
   398 #if defined(__CPU_ARM) && !defined(__EABI__)
       
   399 	inline virtual ~TDmaChannel() {}	// kill really annoying warning
       
   400 #endif
       
   401 private:
       
   402 	static void Dfc(TAny*);
       
   403 	void DoDfc();
       
   404 	inline void Wait();
       
   405 	inline void Signal();
       
   406 	inline TBool Flash();
       
   407 	void ResetStateMachine();
       
   408 protected:
       
   409 	TDmac* iController;										// DMAC this channel belongs to (NULL when closed)
       
   410 	TUint32 iPslId;											// unique identifier provided by PSL
       
   411 	NFastMutex iLock;										// for data accessed in both client & DFC context
       
   412 	SDmaDesHdr* iCurHdr;									// fragment being transferred or NULL
       
   413 	SDmaDesHdr** iNullPtr;									// Pointer to NULL pointer following last fragment
       
   414 	TDfc iDfc;												// transfer completion/failure DFC
       
   415 	TInt iMaxDesCount;										// maximum number of allocable descriptors
       
   416 	TInt iAvailDesCount;									// available number of descriptors
       
   417 	volatile TUint32 iIsrDfc;								// Interface between ISR and DFC:
       
   418 	enum { KErrorFlagMask = 0x80000000 };					// bit 31 - error flag
       
   419 	enum { KCancelFlagMask = 0x40000000 };					// bit 30 - cancel flag
       
   420 	enum { KDfcCountMask = 0x3FFFFFFF };					// bits 0-29 - number of queued DFCs
       
   421 	SDblQue iReqQ;											// being/about to be transferred request queue
       
   422 	TInt iReqCount;											// number of requests attached to this channel
       
   423 	TInt iQueuedRequests; 									// number of requests currently queued on this channel
       
   424 private:
       
   425 	TDmaCancelInfo* iCancelInfo;
       
   426 	__DMA_DECLARE_INVARIANT
       
   427 	};
       
   428 
       
   429 
       
   430 //////////////////////////////////////////////////////////////////////////////
       
   431 // PIL-PSL INTERFACE
       
   432 //////////////////////////////////////////////////////////////////////////////
       
   433 
       
   434 // Trace macros intended for use by the DMA PSL
       
   435 #define DMA_PRINTF(MSG) __KTRACE_OPT(KDMA, Kern::Printf((MSG)))
       
   436 #define DMA_PRINTF1(MSG, ARG1) __KTRACE_OPT(KDMA, Kern::Printf((MSG), (ARG1)))
       
   437 #define DMA_PRINTF2(MSG, ARG1, ARG2) __KTRACE_OPT(KDMA, Kern::Printf((MSG), (ARG1), (ARG2)))
       
   438 
       
   439 #define DMA_PSL_MESG "DMA PSL: "
       
   440 
       
   441 // General PSL tracing
       
   442 #define DMA_PSL_TRACE(MSG) DMA_PRINTF(DMA_PSL_MESG MSG)
       
   443 #define DMA_PSL_TRACE1(MSG, ARG1) DMA_PRINTF1(DMA_PSL_MESG MSG, (ARG1))
       
   444 #define DMA_PSL_TRACE2(MSG, ARG1, ARG2) DMA_PRINTF2(DMA_PSL_MESG MSG, (ARG1), (ARG2))
       
   445 
       
   446 
       
   447 #define DMA_PSL_CHAN_MESG DMA_PSL_MESG "ChanId %d: "
       
   448 #define DMA_PSL_CHAN_ARGS(CHAN) ((CHAN).PslId())
       
   449 
       
   450 // For channel specific tracing (where CHAN is a TDmaChannel)
       
   451 #define DMA_PSL_CHAN_TRACE_STATIC(CHAN, MSG) DMA_PRINTF1(DMA_PSL_CHAN_MESG MSG, DMA_PSL_CHAN_ARGS(CHAN))
       
   452 #define DMA_PSL_CHAN_TRACE_STATIC1(CHAN, MSG, ARG1) DMA_PRINTF2(DMA_PSL_CHAN_MESG MSG, DMA_PSL_CHAN_ARGS(CHAN), (ARG1))
       
   453 
       
   454 // For channel specific tracing, for use within methods of TDmaChannel derived
       
   455 // class
       
   456 #define DMA_PSL_CHAN_TRACE(MSG) DMA_PSL_CHAN_TRACE_STATIC(*this, MSG)
       
   457 #define DMA_PSL_CHAN_TRACE1(MSG, ARG1) DMA_PSL_CHAN_TRACE_STATIC1(*this, MSG, (ARG1))
       
   458 
       
   459 
       
   460 /**
       
   461 Generic DMA descriptor used if the DMAC does not have support for hardware
       
   462 descriptor.
       
   463 @see DDmaRequest::Fragment
       
   464 @publishedPartner
       
   465 @released
       
   466 */
       
   467 
       
   468 struct SDmaPseudoDes
       
   469 	{
       
   470 	/** Source linear address or peripheral cookie */
       
   471 	TUint32 iSrc;
       
   472 	/** Destination linear address or peripheral cookie */
       
   473 	TUint32 iDest;
       
   474 	/** Number of bytes to transfer */
       
   475 	TInt iCount;
       
   476 	/** @see TDmaRequestFlags */
       
   477 	TUint iFlags;
       
   478 	/** PSL-specific information provided by client */
       
   479 	TUint32 iPslInfo;
       
   480 	/** The same as TDmaChannel::SCreateInfo.iCookie */
       
   481 	TUint32 iCookie;
       
   482 	};
       
   483 
       
   484 
       
   485 /**
       
   486 Each hardware or pseudo descriptor is associated with a header.  Headers are
       
   487 needed because hardware descriptors can not easily be extended to store
       
   488 additional information.
       
   489 @publishedPartner
       
   490 @released
       
   491 */
       
   492 
       
   493 struct SDmaDesHdr
       
   494 	{
       
   495 	SDmaDesHdr* iNext;
       
   496 	};
       
   497 
       
   498 
       
   499 /**
       
   500 Interface used by PIL to open and close DMA channels.
       
   501 
       
   502 Must be implemented by PSL.
       
   503 @publishedPartner
       
   504 @released
       
   505 */
       
   506 
       
   507 class DmaChannelMgr
       
   508 	{
       
   509 public:
       
   510 	/** Opens a channel using a client-provided identifier.
       
   511 		This function must be implemented by the PSL.
       
   512 		@param	aOpenId Magic cookie passed by client
       
   513 				This may identify the channel (if a static channel
       
   514 				allocation scheme is used) or may indicate some
       
   515 				properties which the channel must possess (if a dynamic
       
   516 				channel allocation scheme is used). It may be set to
       
   517 				zero always if dynamic allocation is used and all
       
   518 				channels are equivalent.
       
   519 		@return	Pointer to channel if available, NULL otherwise.
       
   520 		@pre	The PIL calls this function with a global fast mutex held to
       
   521 				avoid race conditions.
       
   522 		@post	If a non-NULL pointer is returned, the object pointed to has its
       
   523 				iController and iPslId members set to valid states.
       
   524 				iController should point to the controller handling that channel.
       
   525 				iPslId should contain a value uniquely identifying the channel -
       
   526 				it is used only for debug tracing by PIL. It can be given any
       
   527 				convenient value by PSL	(channel index, I/O port address, ...).
       
   528 	*/
       
   529 	static TDmaChannel* Open(TUint32 aOpenId);
       
   530 
       
   531 	/** Performs platform-specific operations when a channel is closed.
       
   532 		This function must be implemented by the PSL but the implementation can be
       
   533 		a no-op.
       
   534 		@param aChannel The channel to close
       
   535 		@pre The PIL calls this function with a global fast mutex held to
       
   536 			avoid race conditions.
       
   537 	*/
       
   538 	static void Close(TDmaChannel* aChannel);
       
   539 
       
   540 	/** Function allowing PSL to extend DMA API with new channel-independent operations.
       
   541 		This function must be implemented by the PSL.
       
   542 		@param aCmd Command identifier.  Negative values are reserved for Symbian use.
       
   543 		@param aArg PSL-specific
       
   544 		@return KErrNotSupported if aCmd is not supported.  PSL-specific value otherwise.
       
   545 	 */
       
   546 	static TInt StaticExtension(TInt aCmd, TAny* aArg);
       
   547 
       
   548 	static inline void Wait();
       
   549 	static inline void Signal();
       
   550 private:
       
   551 	static NFastMutex Lock;
       
   552 	};
       
   553 
       
   554 
       
   555 //////////////////////////////////////////////////////////////////////////////
       
   556 
       
   557 /**
       
   558  Abstract base class representing a DMA controller.
       
   559 
       
   560  The class has two purposes.
       
   561 
       
   562  First, it is a container for channels, descriptors and descriptor headers.
       
   563 
       
   564  Second, it exposes a set of virtual functions implemented by
       
   565  the PSL (platform-specific layer).
       
   566  These functions are the main interfaces between
       
   567  the PIL (platform-independent layer) and PSL.
       
   568 
       
   569  Must be allocated in BSS because it relies on being zeroed at creation-time.
       
   570 
       
   571  @publishedPartner
       
   572  @released
       
   573  */
       
   574 
       
   575 class TDmac
       
   576 	{
       
   577 	friend class DmaChannelMgr;
       
   578 // protected: VC++ complains when building PSL if following decl is protected
       
   579 public:
       
   580 	/** Data required for creating a new instance */
       
   581 	struct SCreateInfo
       
   582 		{
       
   583 		/** Number of channels in controller */
       
   584 		TInt iChannelCount;
       
   585         /** Maximum number of descriptors (shared by all channels) */
       
   586 		TInt iDesCount;
       
   587 		/** Bitmask.  The only supported value is KCapsBitHwDes (hardware
       
   588 			descriptors used). */
       
   589 		TUint32 iCaps;
       
   590 		/** Size of individual descriptors.  Use sizeof(SDmaPseudoDes) for
       
   591 		 	single-buffer and double-buffer controllers. */
       
   592 		TInt iDesSize;
       
   593 		/** Bitmask used when creating the hardware chunk storing the descriptor
       
   594 			pool. Used only for hardware descriptors. The access part must be
       
   595 			EMapAttrSupRw.  If the chunk is cached and/or buffered, the PSL must
       
   596 			flush the data cache and/or drain the write buffer in InitHwDes()
       
   597 			and related functions.
       
   598 		 	@see TMappingAttributes
       
   599 		 */
       
   600 		TUint iDesChunkAttribs;
       
   601 		};
       
   602 public:
       
   603 	TInt Create(const SCreateInfo& aInfo);
       
   604 	virtual ~TDmac();
       
   605 	TInt ReserveSetOfDes(TInt aCount);
       
   606 	void ReleaseSetOfDes(TInt aCount);
       
   607 	void InitDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
       
   608 				 TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
       
   609 	inline SDmaPseudoDes& HdrToDes(const SDmaDesHdr& aHdr) const;
       
   610 	inline TAny* HdrToHwDes(const SDmaDesHdr& aHdr) const;
       
   611 	inline TUint32 DesLinToPhys(TAny* aDes) const;
       
   612 	inline void Wait();
       
   613 	inline void Signal();
       
   614 protected:
       
   615 	TDmac(const SCreateInfo& aInfo);
       
   616 
       
   617 public:
       
   618 	/**
       
   619 	Called by PIL when one fragment (single-buffer and double-buffer DMACs) or
       
   620 	list of fragments (scatter/gather DMAC) is to be transferred.
       
   621 
       
   622 	Called when	initiating a new transfer and also, for double-buffer DMACs, for
       
   623 	configuring the next fragment to transfer while the current one is
       
   624 	ongoing. Must always be implemented by PSL.
       
   625 	@param aChannel The channel to use
       
   626 	@param aHdr Header associated with fragment to transfer
       
   627 	*/
       
   628 	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) = 0;
       
   629 
       
   630 	/**
       
   631     Called by PIL to suspend transfer on a given channel.
       
   632 
       
   633     The suspension must occur synchronously as the PSL assumes the channel
       
   634     is suspended after calling this function. Must always be implemented by PSL.
       
   635 	@param aChannel The channel to suspend
       
   636 	*/
       
   637 	virtual void StopTransfer(const TDmaChannel& aChannel) = 0;
       
   638 
       
   639 	/**
       
   640 	Called by PIL to check whether a DMA channel is idle.
       
   641 	@param aChannel The channel to test
       
   642 	@return ETrue if channel idle, EFalse if transferring.
       
   643 	 */
       
   644 	virtual TBool IsIdle(const TDmaChannel& aChannel) = 0;
       
   645 
       
   646 	/**
       
   647 	Called by PIL to retrieve from the PSL the maximum transfer size based on the
       
   648 	parameters passed.
       
   649 	@param aChannel Channel to be used for the transfer
       
   650 	@param aFlags Bitmask characterising transfer
       
   651 	@param aPslInfo Cookie passed by client and used by PSL
       
   652 	@return 0 if invalid argument(s), -1 if transfer size not limited, the maximum
       
   653 	transfer size otherwise.
       
   654 	*/
       
   655 	virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0;
       
   656 
       
   657 	/**
       
   658 	Called by PIL to retrieve from the PSL the memory alignment mask based on the
       
   659 	parameters passed. Some DMA controllers impose alignment constraints on the base
       
   660 	address of memory buffers. This mask is AND'ed against memory addresses computed
       
   661 	during fragmentation.
       
   662 	@param aChannel Channel to be used for the transfer
       
   663 	@param aFlags Bitmask characterising transfer
       
   664 	@param aPslInfo Cookie passed by client and used by PSL
       
   665 	@return A value representing the alignment mask (e.g. 3 if buffer must be 4-byte aligned)
       
   666 	*/
       
   667 	virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0;
       
   668 
       
   669 	/**
       
   670     Called by PIL during fragmentation to initialise a hardware descriptor.
       
   671 
       
   672     The PSL must assume the descriptor is the last in the chain and so set the
       
   673 	interrupt bit and set the next descriptor field to an end of chain marker.
       
   674 	Must be implemented by PSL if and only if the DMAC supports hardware
       
   675 	descriptors.
       
   676 	@param aHdr Header associated with hardware descriptor to initialise
       
   677 	@param aSrc Transfer source
       
   678 	@param aDest Transfer destination
       
   679 	@param aCount Number of bytes to transfer (<= max. size supported by DMAC)
       
   680 	@param aFlags Bitmask characterising transfer
       
   681 	@param aPslInfo Cookie passed by client and used by PSL
       
   682 	@param aCookie the channel selection cookie
       
   683 	@see DDmaRequest::Fragment
       
   684 	*/
       
   685 	virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
       
   686 						   TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
       
   687 
       
   688 	/**
       
   689 	Called by PIL, when fragmenting a request, to append a new hardware
       
   690 	descriptor to an existing descriptor chain.
       
   691 
       
   692 	Must clear the interrupt bit of	the descriptor associated with aHdr.
       
   693 	Must be implemented by PSL if and only if the DMAC supports hardware descriptors.
       
   694 	@param aHdr Header associated with last fragment in chain
       
   695 	@param aNextHdr Header associated with fragment to append
       
   696 	*/
       
   697 	virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
       
   698 
       
   699 	/**
       
   700 	Called by PIL when queuing a new request while the channel is running.
       
   701 
       
   702 	Must append the first hardware descriptor of the new request to the last
       
   703 	descriptor in the existing chain. Must be implemented by PSL if and only if
       
   704 	the DMAC supports hardware descriptors.
       
   705 	@param aChannel The channel where the transfer takes place
       
   706 	@param aLastHdr Header associated with last hardware descriptor in chain
       
   707 	@param aNewHdr Header associated with first hardware descriptor in new request
       
   708 	*/
       
   709 	virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
       
   710 							 const SDmaDesHdr& aNewHdr);
       
   711 
       
   712 	/**
       
   713 	Called by PIL when completing or cancelling a request to cause the PSL to unlink
       
   714 	the last item in the h/w descriptor chain from a subsequent chain that it was
       
   715 	possibly linked to. Must be implemented by the PSL if and only if the DMAC supports
       
   716 	hardware descriptors.
       
   717 
       
   718 	@param aChannel The channel where the request (and thus the descriptor) was queued
       
   719 	@param aHdr Header associated with last h/w descriptor in completed/cancelled chain
       
   720 	*/
       
   721 	virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
       
   722 
       
   723 	/**
       
   724 	Called by test harness to force an error when the next fragment is
       
   725 	transferred.
       
   726 
       
   727 	Must be implemented by the PSL only if possible.
       
   728 	@param aChannel The channel where the error is to occur.
       
   729 	@return KErrNone if implemented.  The default PIL implementation returns
       
   730 	KErrNotSupported and the test harness knows how to deal with that.
       
   731 	*/
       
   732 	virtual TInt FailNext(const TDmaChannel& aChannel);
       
   733 
       
   734 	/**
       
   735 	Called by test harness to force the DMA controller to miss one or
       
   736 	more interrupts.
       
   737 
       
   738 	Must be implemented by the PSL only if possible.
       
   739 	@param aChannel The channel where the error is to occur
       
   740 	@param aInterruptCount The number of interrupt to miss.
       
   741 	@return KErrNone if implemented.  The default PIL implementation returns
       
   742 	KErrNotSupported and the test harness knows how to deal with that.
       
   743 	*/
       
   744 	virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
       
   745 
       
   746 	/** Function allowing platform-specific layer to extend channel API with
       
   747 		new channel-specific operations.
       
   748 		@param aChannel Channel to operate on
       
   749 		@param aCmd Command identifier.  Negative values are reserved for Symbian use.
       
   750 		@param aArg PSL-specific
       
   751 		@return KErrNotSupported if aCmd is not supported.  PSL-specific value otherwise.
       
   752 		@see TDmaChannel::Extension
       
   753 	*/
       
   754 	virtual TInt Extension(TDmaChannel& aChannel, TInt aCmd, TAny* aArg);
       
   755 
       
   756 protected:
       
   757 	static void HandleIsr(TDmaChannel& aChannel, TBool aIsComplete);
       
   758 private:
       
   759 	TInt AllocDesPool(TUint aAttribs);
       
   760 	void FreeDesPool();
       
   761 private:
       
   762 	NFastMutex iLock;			 // protect descriptor reservation and allocation
       
   763 	const TInt iMaxDesCount;	 // initial number of descriptors and headers
       
   764 	TInt iAvailDesCount;		 // current available number of descriptors and headers
       
   765 	SDmaDesHdr* iHdrPool;		 // descriptor header dynamic array
       
   766 #ifndef __WINS__
       
   767 	DPlatChunkHw* iHwDesChunk;	 // chunk for hardware descriptor pool
       
   768 #endif
       
   769 	TAny* iDesPool;				 // hardware or pseudo descriptor dynamic array
       
   770 	const TInt iDesSize;		 // descriptor size in bytes
       
   771 public:
       
   772 	const TUint iCaps;  		 /*< what is supported by DMA controller */
       
   773 	enum {KCapsBitHwDes = 1};	 /*< hardware descriptors supported */
       
   774 	SDmaDesHdr* iFreeHdr;		 /*< head of unallocated descriptors linked list */
       
   775 #ifdef _DEBUG
       
   776 	TBool IsValidHdr(const SDmaDesHdr* aHdr);
       
   777 #endif
       
   778 	__DMA_DECLARE_INVARIANT
       
   779 	};
       
   780 
       
   781 
       
   782 //////////////////////////////////////////////////////////////////////////////
       
   783 
       
   784 /**
       
   785 Single-buffer DMA channel.
       
   786 
       
   787 Can be instantiated or further derived by PSL.  Not
       
   788 intended to be instantiated by client device drivers.
       
   789 @publishedPartner
       
   790 @released
       
   791 */
       
   792 
       
   793 class TDmaSbChannel : public TDmaChannel
       
   794 	{
       
   795 private:
       
   796 	virtual void DoQueue(DDmaRequest& aReq);
       
   797 	virtual void DoCancelAll();
       
   798 	virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
       
   799 private:
       
   800 	TBool iTransferring;
       
   801 	};
       
   802 
       
   803 
       
   804 /**
       
   805 Double-buffer DMA channel.
       
   806 
       
   807 Can be instantiated or further derived by PSL.  Not
       
   808 intended to be instantiated by client device drivers.
       
   809 @publishedPartner
       
   810 @released
       
   811 */
       
   812 
       
   813 class TDmaDbChannel : public TDmaChannel
       
   814 	{
       
   815 private:
       
   816 	virtual void DoQueue(DDmaRequest& aReq);
       
   817 	virtual void DoCancelAll();
       
   818 	virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
       
   819 private:
       
   820 	enum { EIdle = 0, ETransferring, ETransferringLast } iState;
       
   821 	};
       
   822 
       
   823 
       
   824 /**
       
   825 Scatter-gather DMA channel.
       
   826 
       
   827 Can be instantiated or further derived by PSL.
       
   828 Not intended to be instantiated by client device drivers.
       
   829 @publishedPartner
       
   830 @released
       
   831 */
       
   832 
       
   833 class TDmaSgChannel : public TDmaChannel
       
   834 	{
       
   835 private:
       
   836 	virtual void DoQueue(DDmaRequest& aReq);
       
   837 	virtual void DoCancelAll();
       
   838 	virtual void DoUnlink(SDmaDesHdr& aHdr);
       
   839 	virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
       
   840 private:
       
   841 	TBool iTransferring;
       
   842 	};
       
   843 
       
   844 
       
   845 //////////////////////////////////////////////////////////////////////////////
       
   846 // INTERFACE WITH TEST HARNESS
       
   847 //////////////////////////////////////////////////////////////////////////////
       
   848 
       
   849 /**
       
   850 Set of information used by test harness.
       
   851 @publishedPartner
       
   852 @released
       
   853 */
       
   854 
       
   855 struct TDmaTestInfo
       
   856 	{
       
   857 	/** Maximum transfer size in bytes for all channels (ie. the minimum of all channels' maximum size)*/
       
   858 	TInt iMaxTransferSize;
       
   859 	/** 3->Memory buffers must be 4-byte aligned, 7->8-byte aligned, ... */
       
   860 	TUint iMemAlignMask;
       
   861 	/** Cookie to pass to DDmaRequest::Fragment for memory-memory transfer*/
       
   862 	TUint32 iMemMemPslInfo;
       
   863 	/** Number of test single-buffer channels */
       
   864 	TInt iMaxSbChannels;
       
   865 	/** Pointer to array containing single-buffer test channel ids */
       
   866 	TUint32* iSbChannels;
       
   867 	/** Number of test double-buffer channels */
       
   868 	TInt iMaxDbChannels;
       
   869 	/** Pointer to array containing double-buffer test channel ids */
       
   870 	TUint32* iDbChannels;
       
   871 	/** Number of test scatter-gather channels */
       
   872 	TInt iMaxSgChannels;
       
   873 	/** Pointer to array containing scatter-gather test channel ids */
       
   874 	TUint32* iSgChannels;
       
   875 	};
       
   876 
       
   877 
       
   878 /**
       
   879 Provides access to test information structure stored in the PSL.
       
   880 
       
   881 Must be implemented by the PSL.
       
   882 @publishedPartner
       
   883 @released
       
   884 */
       
   885 
       
   886 IMPORT_C const TDmaTestInfo& DmaTestInfo();
       
   887 
       
   888 
       
   889 //////////////////////////////////////////////////////////////////////////////
       
   890 
       
   891 #include <drivers/dma.inl>
       
   892 
       
   893 #endif