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