os/kernelhwsrv/kernel/eka/include/drivers/dma_v1.h
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kernel/eka/include/drivers/dma_v1.h	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,834 @@
     1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0""
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// include/drivers/dma_v1.h
    1.18 +// DMA Framework API v1
    1.19 +//
    1.20 +// NB: DMA clients should never include this file directly, but only ever the
    1.21 +// generic header file <drivers/dma.h>.
    1.22 +//
    1.23 +
    1.24 +#ifndef __DMA_H__
    1.25 +#error "dma_v1.h must'n be included directly - use <drivers/dma.h> instead"
    1.26 +#endif	// #ifndef __DMA_H__
    1.27 +
    1.28 +#ifndef __DMA_V1_H__
    1.29 +#define __DMA_V1_H__
    1.30 +
    1.31 +#include <kernel/kern_priv.h>
    1.32 +
    1.33 +
    1.34 +//////////////////////////////////////////////////////////////////////////////
    1.35 +// Debug Support - KDmaPanicCat is defined in each source file
    1.36 +
    1.37 +#define __DMA_ASSERTD(e) __ASSERT_DEBUG(e, Kern::Fault(KDmaPanicCat, __LINE__))
    1.38 +#define __DMA_ASSERTA(e) __ASSERT_ALWAYS(e, Kern::Fault(KDmaPanicCat, __LINE__))
    1.39 +#ifdef _DEBUG
    1.40 +#define __DMA_CANT_HAPPEN() Kern::Fault(KDmaPanicCat, __LINE__)
    1.41 +#define __DMA_DECLARE_INVARIANT public: void Invariant();
    1.42 +#define __DMA_INVARIANT() Invariant()
    1.43 +#else
    1.44 +#define __DMA_CANT_HAPPEN()
    1.45 +#define __DMA_DECLARE_INVARIANT
    1.46 +#define __DMA_INVARIANT()
    1.47 +#endif
    1.48 +
    1.49 +
    1.50 +//////////////////////////////////////////////////////////////////////////////
    1.51 +// INTERFACE EXPOSED TO DEVICE-DRIVERS
    1.52 +//////////////////////////////////////////////////////////////////////////////
    1.53 +
    1.54 +/**
    1.55 +Bitmasks used for configuring a DMA request.
    1.56 +
    1.57 +In general, specify KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest) if
    1.58 +the source (resp. destination) is a memory buffer and clear
    1.59 +KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest) if the source
    1.60 +(resp. destination) is a peripheral.
    1.61 +
    1.62 +If the location is given as a physical address (rather than a linear one)
    1.63 +then also specify KDmaPhysAddrSrc and/or KDmaPhysAddrDest.
    1.64 +
    1.65 +The EKA1 "Fill Mode" can be implemented by omitting KDmaIncSrc.
    1.66 +
    1.67 +Some peripherals may require a post-increment address mode.
    1.68 +
    1.69 +@see DDmaRequest::Fragment
    1.70 +@publishedPartner
    1.71 +@released
    1.72 +*/
    1.73 +
    1.74 +enum TDmaRequestFlags
    1.75 +	{
    1.76 +	/** Source is address of memory buffer */
    1.77 +	KDmaMemSrc       = 0x01,
    1.78 +	/** Destination is address of memory buffer */
    1.79 +	KDmaMemDest      = 0x02,
    1.80 +	/** Source address must be post-incremented during transfer */
    1.81 +	KDmaIncSrc       = 0x04,
    1.82 +	/** Destination address must be post-incremented during transfer */
    1.83 +	KDmaIncDest      = 0x08,
    1.84 +	/** Source address is a physical address (as opposed to a linear one) */
    1.85 +	KDmaPhysAddrSrc  = 0x10,
    1.86 +	/** Destination address is a physical address (as opposed to a linear one) */
    1.87 +	KDmaPhysAddrDest = 0x20,
    1.88 +	/** Request a different max transfer size (for instance for test purposes) */
    1.89 +	KDmaAltTransferLen = 0x40
    1.90 +	};
    1.91 +
    1.92 +
    1.93 +//////////////////////////////////////////////////////////////////////////////
    1.94 +
    1.95 +class TDmaChannel;
    1.96 +struct SDmaDesHdr;
    1.97 +
    1.98 +/** A DMA request is a list of fragments small enough to be transferred in one go
    1.99 +	by the DMAC.
   1.100 +
   1.101 +	In general, fragmentation is done in the framework by calling Fragment() but
   1.102 +	clients with special needs can allocate a blank descriptor list with
   1.103 +	ExpandDesList() and customise it to fit their needs.
   1.104 +
   1.105 +	Clients should not set attributes directly, but should use the various functions
   1.106 +	instead.
   1.107 +
   1.108 +	This class has not been designed to be called from several concurrent threads.
   1.109 +	Multithreaded clients must implement their own locking scheme (via DMutex).
   1.110 +
   1.111 +	Fast mutexes are used internally to protect data structures accessed both
   1.112 +	by the client thread and the DFC thread.  Therefore no fast mutex can be held
   1.113 +	when calling a request function.
   1.114 +
   1.115 +	@publishedPartner
   1.116 +	@released
   1.117 + */
   1.118 +class DDmaRequest : public DBase
   1.119 +	{
   1.120 +	friend class TDmaChannel;
   1.121 +public:
   1.122 +	/** The outcome of the transfer */
   1.123 +	enum TResult {EBadResult=0, EOk, EError};
   1.124 +	/** The signature of the completion/failure callback function */
   1.125 +	typedef void (*TCallback)(TResult, TAny*);
   1.126 +public:
   1.127 +   
   1.128 +    /**
   1.129 +    Create a new transfer request. 
   1.130 +
   1.131 +    @param aChannel The channel this request is bound to.
   1.132 +    @param aCb      Callback function called on transfer completion or failure (in channel
   1.133 +                    DFC context).  Can be NULL.
   1.134 +    @param aCbArg   Argument passed to callback function.
   1.135 +    @param aMaxTransferSize Maximum fragment size.  If not specified, defaults to the maximum size
   1.136 +           supported by the DMA controller for the type of transfer that is later scheduled.
   1.137 +    */
   1.138 +	IMPORT_C DDmaRequest(TDmaChannel& aChannel, TCallback aCb=NULL, TAny* aCbArg=NULL, TInt aMaxTransferSize=0);
   1.139 +	
   1.140 +	
   1.141 +	/**
   1.142 +    Destructor.
   1.143 +
   1.144 +    Assume the request is not being transferred or pending.
   1.145 +    */
   1.146 +	IMPORT_C ~DDmaRequest();
   1.147 +	
   1.148 +	
   1.149 +	/**
   1.150 +    Split request into a list of fragments small enough to be fed to the DMAC.
   1.151 +
   1.152 +    The size of each fragment is smaller than or equal to the maximum transfer size
   1.153 +    supported by the DMAC.  If the source and/or destination is memory, each
   1.154 +    fragment points to memory which is physically contiguous.
   1.155 +
   1.156 +    The kind of transfer to perform is specified via a set of flags used by a PIL
   1.157 +    and a magic cookie passed to the PSL.  If the source (resp. destination) is a
   1.158 +    peripheral, aSrc (resp. aDest) is treated as a magic cookie by the PIL and
   1.159 +    passed straight to the PSL.
   1.160 +
   1.161 +    The request can be uninitialised or may have been fragmented previously.  The
   1.162 +    previous configuration if any is lost whether or not the function succeeds.
   1.163 +
   1.164 +    @param aSrc     Source memory buffer linear address or peripheral magic cookie.
   1.165 +    @param aDest    Destination memory buffer linear address or peripheral magic cookie.
   1.166 +    @param aCount   Number of bytes to transfer.
   1.167 +    @param aFlags   Bitmask characterising the transfer.
   1.168 +    @param aPslInfo Hardware-specific information passed to PSL.
   1.169 +
   1.170 +    @return KErrNone if success. KErrArgument if aFlags and/or aPslInfo are invalid when finding
   1.171 +    the maximum transfer size. May also fail if running out of descriptors.
   1.172 +
   1.173 +    @pre The request is not being transferred or pending.
   1.174 +    @pre The various parameters must be valid.  The PIL or PSL will fault the
   1.175 +    kernel if not.
   1.176 +
   1.177 +    @see TDmaRequestFlags
   1.178 +    */
   1.179 +	IMPORT_C TInt Fragment(TUint32 aSrc, TUint32 aDest, TInt aCount, TUint aFlags, TUint32 aPslInfo);
   1.180 +	
   1.181 +	
   1.182 +	/**
   1.183 +    Transfer asynchronously this request.
   1.184 +
   1.185 +    If this request's channel is idle, the request is transferred immediately.
   1.186 +    Otherwise, it is queued and transferred later.
   1.187 +
   1.188 +    The client is responsible for ensuring cache consistency before and/or after the
   1.189 +    transfer if necessary.
   1.190 +    */
   1.191 +	IMPORT_C void Queue();
   1.192 +	
   1.193 +
   1.194 +    /**
   1.195 +    Append new descriptor(s) to existing list.
   1.196 +
   1.197 +    Clients needing to build a custom descriptor list should call this function to
   1.198 +    allocate the list and access the resulting list through iFirstHdr and iLastHdr.
   1.199 +
   1.200 +    Clients should not change the value of iFirstHdr, iLastHdr and the iNext field
   1.201 +    of the descriptor headers to ensure descriptors can be deallocated. Clients
   1.202 +    are free to change hardware descriptors, including chaining, in whatever way
   1.203 +    suit them.
   1.204 +
   1.205 +    Assume the request is not being transferred or pending.
   1.206 +
   1.207 +    @param aCount Number of descriptors to append.
   1.208 +
   1.209 +    @return KErrNone or KErrTooBig if not enough descriptors available.
   1.210 +    */
   1.211 +	IMPORT_C TInt ExpandDesList(TInt aCount=1);
   1.212 +	
   1.213 +	
   1.214 +	/**
   1.215 +    Free resources associated with this request.
   1.216 +
   1.217 +    Assume the request is not being transferred or pending.
   1.218 +    */
   1.219 +	IMPORT_C void FreeDesList();
   1.220 +private:
   1.221 +	inline void OnDeque();
   1.222 +public:
   1.223 +	// WARNING: The following attributes are accessed both in client and DFC
   1.224 +	// context and so accesses must be protected with the channel lock.
   1.225 +	TDmaChannel& iChannel;		/**< The channel this request is bound to */
   1.226 +	volatile TCallback iCb;		/**< Called on completion/failure (can be NULL) */
   1.227 +	TAny* volatile iCbArg;		/**< Callback argument */
   1.228 +	TInt iDesCount;				/**< The number of fragments in list */
   1.229 +	SDmaDesHdr* iFirstHdr;		/**< The first fragment in the list (or NULL) */
   1.230 +	SDmaDesHdr* iLastHdr;		/**< The last fragment in the list (or NULL) */
   1.231 +	SDblQueLink iLink;			/**< The link on channel queue of pending requests */
   1.232 +	TBool iQueued;				/**< Indicates whether request is pending or being transferred */
   1.233 +	TInt iMaxTransferSize;		/**< Defaults to DMA controller max. transfer size */
   1.234 +	__DMA_DECLARE_INVARIANT
   1.235 +	};
   1.236 +
   1.237 +
   1.238 +//////////////////////////////////////////////////////////////////////////////
   1.239 +
   1.240 +class TDmac;
   1.241 +class DmaChannelMgr;
   1.242 +
   1.243 +/** DMA channel base class.
   1.244 +
   1.245 +	This class has not been designed to be called from several concurrent
   1.246 +	client threads.  Multithreaded clients must implement their own locking
   1.247 +	scheme (via DMutex).
   1.248 +
   1.249 +	Fast mutexes are used internally to protect data structures accessed both
   1.250 +	by the client thread and the DFC one.  Therefore no fast mutex can be held
   1.251 +	when calling a channel function.
   1.252 +
   1.253 +	Must be allocated in BSS because it relies on being zeroed at
   1.254 +	creation-time.  If the PSL really needs to allocate channels on the kernel
   1.255 +	heap, it must manually zero-initialises the instances.  This can be
   1.256 +	achieved either by allocating raw memory and using placement new, or by
   1.257 +	wrapping channels into a DBase-derived wrapper.
   1.258 +
   1.259 +	@publishedPartner
   1.260 +	@released
   1.261 + */
   1.262 +class TDmaCancelInfo;
   1.263 +class TDmaChannel
   1.264 +	{
   1.265 +	friend class DDmaRequest;
   1.266 +	friend class TDmac;
   1.267 +	friend class DmaChannelMgr;
   1.268 +public:
   1.269 +	/**  Information passed by client when opening channel */
   1.270 +	struct SCreateInfo
   1.271 +		{
   1.272 +		/** Identifier used by PSL to select channel to open */
   1.273 +		TUint32 iCookie;
   1.274 +		/** Number of descriptors this channel can use */
   1.275 +		TInt iDesCount;
   1.276 +		/** DFC queue used to service DMA interrupts.  The DFC thread
   1.277 +			priority must be higher than any client thread priority to
   1.278 +			avoid a situation where a transfer completes while being
   1.279 +			cancelled and another transfer is started before the DFC
   1.280 +			thread gets a chance to run.  This would lead to a stray
   1.281 +			DFC.
   1.282 +		*/
   1.283 +		TDfcQue* iDfcQ;
   1.284 +		/** DFC priority */
   1.285 +		TUint8 iDfcPriority;
   1.286 +		};
   1.287 +public:
   1.288 +    /**
   1.289 + 	Opens the DMA channel.
   1.290 +
   1.291 + 	Channel selection is done by the hardware-specific layer using a cookie passed in
   1.292 + 	via aInfo.
   1.293 +
   1.294 + 	The client should not delete the returned pointer as the framework owns
   1.295 + 	channel objects.  However, the client should explicitly close the channel when
   1.296 + 	finished with it.
   1.297 +
   1.298 +	@param aInfo    Information passed by caller to select and configure channel.
   1.299 + 	@param aChannel Point to open channel on successful return.  NULL otherwise.
   1.300 +
   1.301 + 	@return KErrNone or standard error code.
   1.302 + 	*/
   1.303 +	IMPORT_C static TInt Open(const SCreateInfo& aInfo, TDmaChannel*& aChannel);
   1.304 +	
   1.305 +	
   1.306 +	/**
   1.307 + 	Closes a previously opened DMA channel.
   1.308 +
   1.309 + 	Assume the channel is idle and all requests have been deleted.
   1.310 + 	*/
   1.311 +	IMPORT_C void Close();
   1.312 +	
   1.313 +	
   1.314 +	/**
   1.315 + 	Cancels the current request and all the pending ones.
   1.316 + 	*/
   1.317 +	IMPORT_C void CancelAll();
   1.318 +	inline TBool IsOpened() const;
   1.319 +	inline TBool IsQueueEmpty() const;
   1.320 +	inline TUint32 PslId() const;
   1.321 +	inline TInt FailNext(TInt aFragmentCount);
   1.322 +	inline TInt MissNextInterrupts(TInt aInterruptCount);
   1.323 +	inline TInt Extension(TInt aCmd, TAny* aArg);
   1.324 +	
   1.325 +	/**
   1.326 +	This is a function that allows the Platform Specific Layer (PSL) to extend the DMA API
   1.327 +	with new channel-independent operations.
   1.328 +
   1.329 +	@param aCmd Command identifier.  Negative values are reserved for Symbian use.
   1.330 +	@param aArg PSL-specific.
   1.331 +	
   1.332 +	@return KErrNotSupported if aCmd is not supported; a  PSL specific value otherwise.
   1.333 + 	*/
   1.334 +	IMPORT_C TInt StaticExtension(TInt aCmd, TAny* aArg);
   1.335 +	inline const TDmac* Controller() const;
   1.336 +	inline TInt MaxTransferSize(TUint aFlags, TUint32 aPslInfo);
   1.337 +	inline TUint MemAlignMask(TUint aFlags, TUint32 aPslInfo);
   1.338 +protected:
   1.339 +	// Interface with state machines
   1.340 +	TDmaChannel();
   1.341 +	virtual void DoQueue(DDmaRequest& aReq) = 0;
   1.342 +	virtual void DoCancelAll() = 0;
   1.343 +	virtual void DoUnlink(SDmaDesHdr& aHdr);
   1.344 +	virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr) = 0;
   1.345 +	/**
   1.346 +	   This function allows the Platform Specific Layer (PSL) to control the
   1.347 +	   power management of the channel or its controller by overriding the
   1.348 +	   PIL's default implementation (which does nothing) and making appropriate
   1.349 +	   use of the Power Resource Manager (PRM).
   1.350 +
   1.351 +	   The function gets called by the PIL whenever the channel's queued
   1.352 +	   requests count has changed in a significant way, either before the
   1.353 +	   channel's Transfer() method is invoked for a request on a previously
   1.354 +	   empty request queue, or immediately after the request count has become
   1.355 +	   zero because of request cancellation or completion.
   1.356 +
   1.357 +	   Depending on the current value of iQueuedRequests, the PSL may power
   1.358 +	   down or power up the channel. Note that iQueuedRequests gets accessed
   1.359 +	   and changed by different threads, so the PSL needs to take the usual
   1.360 +	   precautions when evaluating the variable's value.
   1.361 +
   1.362 +	   None of the internal DMA framework mutexes is being held by the PIL when
   1.363 +	   calling this function.
   1.364 +
   1.365 +	   @see iQueuedRequests
   1.366 +	 */
   1.367 +	virtual void QueuedRequestCountChanged();
   1.368 +#if defined(__CPU_ARM) && !defined(__EABI__)
   1.369 +	inline virtual ~TDmaChannel() {}	// kill really annoying warning
   1.370 +#endif
   1.371 +private:
   1.372 +	static void Dfc(TAny*);
   1.373 +	void DoDfc();
   1.374 +	inline void Wait();
   1.375 +	inline void Signal();
   1.376 +	inline TBool Flash();
   1.377 +	void ResetStateMachine();
   1.378 +protected:
   1.379 +	TDmac* iController;										// DMAC this channel belongs to (NULL when closed)
   1.380 +	TUint32 iPslId;											// unique identifier provided by PSL
   1.381 +	NFastMutex iLock;										// for data accessed in both client & DFC context
   1.382 +	SDmaDesHdr* iCurHdr;									// fragment being transferred or NULL
   1.383 +	SDmaDesHdr** iNullPtr;									// Pointer to NULL pointer following last fragment
   1.384 +	TDfc iDfc;												// transfer completion/failure DFC
   1.385 +	TInt iMaxDesCount;										// maximum number of allocable descriptors
   1.386 +	TInt iAvailDesCount;									// available number of descriptors
   1.387 +	volatile TUint32 iIsrDfc;								// Interface between ISR and DFC:
   1.388 +	enum { KErrorFlagMask = 0x80000000 };					// bit 31 - error flag
   1.389 +	enum { KCancelFlagMask = 0x40000000 };					// bit 30 - cancel flag
   1.390 +	enum { KDfcCountMask = 0x3FFFFFFF };					// bits 0-29 - number of queued DFCs
   1.391 +	SDblQue iReqQ;											// being/about to be transferred request queue
   1.392 +	TInt iReqCount;											// number of requests attached to this channel
   1.393 +	TInt iQueuedRequests; 									// number of requests currently queued on this channel
   1.394 +private:
   1.395 +	TDmaCancelInfo* iCancelInfo;
   1.396 +	__DMA_DECLARE_INVARIANT
   1.397 +	};
   1.398 +
   1.399 +
   1.400 +//////////////////////////////////////////////////////////////////////////////
   1.401 +// PIL-PSL INTERFACE
   1.402 +//////////////////////////////////////////////////////////////////////////////
   1.403 +
   1.404 +/**
   1.405 +Generic DMA descriptor used if the DMAC does not have support for hardware
   1.406 +descriptor.
   1.407 +@see DDmaRequest::Fragment
   1.408 +@publishedPartner
   1.409 +@released
   1.410 +*/
   1.411 +
   1.412 +struct SDmaPseudoDes
   1.413 +	{
   1.414 +	/** Source linear address or peripheral cookie */
   1.415 +	TUint32 iSrc;
   1.416 +	/** Destination linear address or peripheral cookie */
   1.417 +	TUint32 iDest;
   1.418 +	/** Number of bytes to transfer */
   1.419 +	TInt iCount;
   1.420 +	/** @see TDmaRequestFlags */
   1.421 +	TUint iFlags;
   1.422 +	/** PSL-specific information provided by client */
   1.423 +	TUint32 iPslInfo;
   1.424 +	/** The same as TDmaChannel::SCreateInfo.iCookie */
   1.425 +	TUint32 iCookie;
   1.426 +	};
   1.427 +
   1.428 +
   1.429 +/**
   1.430 +Each hardware or pseudo descriptor is associated with a header.  Headers are
   1.431 +needed because hardware descriptors can not easily be extended to store
   1.432 +additional information.
   1.433 +@publishedPartner
   1.434 +@released
   1.435 +*/
   1.436 +
   1.437 +struct SDmaDesHdr
   1.438 +	{
   1.439 +	SDmaDesHdr* iNext;
   1.440 +	};
   1.441 +
   1.442 +
   1.443 +/**
   1.444 +Interface used by PIL to open and close DMA channels.
   1.445 +
   1.446 +Must be implemented by PSL.
   1.447 +@publishedPartner
   1.448 +@released
   1.449 +*/
   1.450 +
   1.451 +class DmaChannelMgr
   1.452 +	{
   1.453 +public:
   1.454 +	/** Opens a channel using a client-provided identifier.
   1.455 +		This function must be implemented by the PSL.
   1.456 +		@param	aOpenId Magic cookie passed by client
   1.457 +				This may identify the channel (if a static channel
   1.458 +				allocation scheme is used) or may indicate some
   1.459 +				properties which the channel must possess (if a dynamic
   1.460 +				channel allocation scheme is used). It may be set to
   1.461 +				zero always if dynamic allocation is used and all
   1.462 +				channels are equivalent.
   1.463 +		@return	Pointer to channel if available, NULL otherwise.
   1.464 +		@pre	The PIL calls this function with a global fast mutex held to
   1.465 +				avoid race conditions.
   1.466 +		@post	If a non-NULL pointer is returned, the object pointed to has its
   1.467 +				iController and iPslId members set to valid states.
   1.468 +				iController should point to the controller handling that channel.
   1.469 +				iPslId should contain a value uniquely identifying the channel -
   1.470 +				it is used only for debug tracing by PIL. It can be given any
   1.471 +				convenient value by PSL	(channel index, I/O port address, ...).
   1.472 +	*/
   1.473 +	static TDmaChannel* Open(TUint32 aOpenId);
   1.474 +
   1.475 +	/** Performs platform-specific operations when a channel is closed.
   1.476 +		This function must be implemented by the PSL but the implementation can be
   1.477 +		a no-op.
   1.478 +		@param aChannel The channel to close
   1.479 +		@pre The PIL calls this function with a global fast mutex held to
   1.480 +			avoid race conditions.
   1.481 +	*/
   1.482 +	static void Close(TDmaChannel* aChannel);
   1.483 +
   1.484 +	/** Function allowing PSL to extend DMA API with new channel-independent operations.
   1.485 +		This function must be implemented by the PSL.
   1.486 +		@param aCmd Command identifier.  Negative values are reserved for Symbian use.
   1.487 +		@param aArg PSL-specific
   1.488 +		@return KErrNotSupported if aCmd is not supported.  PSL-specific value otherwise.
   1.489 +	 */
   1.490 +	static TInt StaticExtension(TInt aCmd, TAny* aArg);
   1.491 +
   1.492 +	static inline void Wait();
   1.493 +	static inline void Signal();
   1.494 +private:
   1.495 +	static NFastMutex Lock;
   1.496 +	};
   1.497 +
   1.498 +
   1.499 +//////////////////////////////////////////////////////////////////////////////
   1.500 +
   1.501 +/**
   1.502 + Abstract base class representing a DMA controller.
   1.503 +
   1.504 + The class has two purposes.
   1.505 +
   1.506 + First, it is a container for channels, descriptors and descriptor headers.
   1.507 +
   1.508 + Second, it exposes a set of virtual functions implemented by
   1.509 + the PSL (platform-specific layer).
   1.510 + These functions are the main interfaces between
   1.511 + the PIL (platform-independent layer) and PSL.
   1.512 +
   1.513 + Must be allocated in BSS because it relies on being zeroed at creation-time.
   1.514 +
   1.515 + @publishedPartner
   1.516 + @released
   1.517 + */
   1.518 +
   1.519 +class TDmac
   1.520 +	{
   1.521 +	friend class DmaChannelMgr;
   1.522 +// protected: VC++ complains when building PSL if following decl is protected
   1.523 +public:
   1.524 +	/** Data required for creating a new instance */
   1.525 +	struct SCreateInfo
   1.526 +		{
   1.527 +		/** Number of channels in controller */
   1.528 +		TInt iChannelCount;
   1.529 +        /** Maximum number of descriptors (shared by all channels) */
   1.530 +		TInt iDesCount;
   1.531 +		/** Bitmask.  The only supported value is KCapsBitHwDes (hardware
   1.532 +			descriptors used). */
   1.533 +		TUint32 iCaps;
   1.534 +		/** Size of individual descriptors.  Use sizeof(SDmaPseudoDes) for
   1.535 +		 	single-buffer and double-buffer controllers. */
   1.536 +		TInt iDesSize;
   1.537 +		/** Bitmask used when creating the hardware chunk storing the descriptor
   1.538 +			pool. Used only for hardware descriptors. The access part must be
   1.539 +			EMapAttrSupRw.  If the chunk is cached and/or buffered, the PSL must
   1.540 +			flush the data cache and/or drain the write buffer in InitHwDes()
   1.541 +			and related functions.
   1.542 +		 	@see TMappingAttributes
   1.543 +		 */
   1.544 +		TUint iDesChunkAttribs;
   1.545 +		};
   1.546 +public:
   1.547 +	TInt Create(const SCreateInfo& aInfo);
   1.548 +	virtual ~TDmac();
   1.549 +	TInt ReserveSetOfDes(TInt aCount);
   1.550 +	void ReleaseSetOfDes(TInt aCount);
   1.551 +	void InitDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
   1.552 +				 TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
   1.553 +	inline SDmaPseudoDes& HdrToDes(const SDmaDesHdr& aHdr) const;
   1.554 +	inline TAny* HdrToHwDes(const SDmaDesHdr& aHdr) const;
   1.555 +	inline TUint32 DesLinToPhys(TAny* aDes) const;
   1.556 +	inline void Wait();
   1.557 +	inline void Signal();
   1.558 +protected:
   1.559 +	TDmac(const SCreateInfo& aInfo);
   1.560 +
   1.561 +public:
   1.562 +	/**
   1.563 +	Called by PIL when one fragment (single-buffer and double-buffer DMACs) or
   1.564 +	list of fragments (scatter/gather DMAC) is to be transferred.
   1.565 +
   1.566 +	Called when	initiating a new transfer and also, for double-buffer DMACs, for
   1.567 +	configuring the next fragment to transfer while the current one is
   1.568 +	ongoing. Must always be implemented by PSL.
   1.569 +	@param aChannel The channel to use
   1.570 +	@param aHdr Header associated with fragment to transfer
   1.571 +	*/
   1.572 +	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) = 0;
   1.573 +
   1.574 +	/**
   1.575 +    Called by PIL to suspend transfer on a given channel.
   1.576 +
   1.577 +    The suspension must occur synchronously as the PSL assumes the channel
   1.578 +    is suspended after calling this function. Must always be implemented by PSL.
   1.579 +	@param aChannel The channel to suspend
   1.580 +	*/
   1.581 +	virtual void StopTransfer(const TDmaChannel& aChannel) = 0;
   1.582 +
   1.583 +	/**
   1.584 +	Called by PIL to check whether a DMA channel is idle.
   1.585 +	@param aChannel The channel to test
   1.586 +	@return ETrue if channel idle, EFalse if transferring.
   1.587 +	 */
   1.588 +	virtual TBool IsIdle(const TDmaChannel& aChannel) = 0;
   1.589 +
   1.590 +	/**
   1.591 +	Called by PIL to retrieve from the PSL the maximum transfer size based on the
   1.592 +	parameters passed.
   1.593 +	@param aChannel Channel to be used for the transfer
   1.594 +	@param aFlags Bitmask characterising transfer
   1.595 +	@param aPslInfo Cookie passed by client and used by PSL
   1.596 +	@return 0 if invalid argument(s), -1 if transfer size not limited, the maximum
   1.597 +	transfer size otherwise.
   1.598 +	*/
   1.599 +	virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0;
   1.600 +
   1.601 +	/**
   1.602 +	Called by PIL to retrieve from the PSL the memory alignment mask based on the
   1.603 +	parameters passed. Some DMA controllers impose alignment constraints on the base
   1.604 +	address of memory buffers. This mask is AND'ed against memory addresses computed
   1.605 +	during fragmentation.
   1.606 +	@param aChannel Channel to be used for the transfer
   1.607 +	@param aFlags Bitmask characterising transfer
   1.608 +	@param aPslInfo Cookie passed by client and used by PSL
   1.609 +	@return A value representing the alignment mask (e.g. 3 if buffer must be 4-byte aligned)
   1.610 +	*/
   1.611 +	virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0;
   1.612 +
   1.613 +	/**
   1.614 +    Called by PIL during fragmentation to initialise a hardware descriptor.
   1.615 +
   1.616 +    The PSL must assume the descriptor is the last in the chain and so set the
   1.617 +	interrupt bit and set the next descriptor field to an end of chain marker.
   1.618 +	Must be implemented by PSL if and only if the DMAC supports hardware
   1.619 +	descriptors.
   1.620 +	@param aHdr Header associated with hardware descriptor to initialise
   1.621 +	@param aSrc Transfer source
   1.622 +	@param aDest Transfer destination
   1.623 +	@param aCount Number of bytes to transfer (<= max. size supported by DMAC)
   1.624 +	@param aFlags Bitmask characterising transfer
   1.625 +	@param aPslInfo Cookie passed by client and used by PSL
   1.626 +	@param aCookie the channel selection cookie
   1.627 +	@see DDmaRequest::Fragment
   1.628 +	*/
   1.629 +	virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
   1.630 +						   TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
   1.631 +
   1.632 +	/**
   1.633 +	Called by PIL, when fragmenting a request, to append a new hardware
   1.634 +	descriptor to an existing descriptor chain.
   1.635 +
   1.636 +	Must clear the interrupt bit of	the descriptor associated with aHdr.
   1.637 +	Must be implemented by PSL if and only if the DMAC supports hardware descriptors.
   1.638 +	@param aHdr Header associated with last fragment in chain
   1.639 +	@param aNextHdr Header associated with fragment to append
   1.640 +	*/
   1.641 +	virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
   1.642 +
   1.643 +	/**
   1.644 +	Called by PIL when queuing a new request while the channel is running.
   1.645 +
   1.646 +	Must append the first hardware descriptor of the new request to the last
   1.647 +	descriptor in the existing chain. Must be implemented by PSL if and only if
   1.648 +	the DMAC supports hardware descriptors.
   1.649 +	@param aChannel The channel where the transfer takes place
   1.650 +	@param aLastHdr Header associated with last hardware descriptor in chain
   1.651 +	@param aNewHdr Header associated with first hardware descriptor in new request
   1.652 +	*/
   1.653 +	virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
   1.654 +							 const SDmaDesHdr& aNewHdr);
   1.655 +
   1.656 +	/**
   1.657 +	Called by PIL when completing or cancelling a request to cause the PSL to unlink
   1.658 +	the last item in the h/w descriptor chain from a subsequent chain that it was
   1.659 +	possibly linked to. Must be implemented by the PSL if and only if the DMAC supports
   1.660 +	hardware descriptors.
   1.661 +
   1.662 +	@param aChannel The channel where the request (and thus the descriptor) was queued
   1.663 +	@param aHdr Header associated with last h/w descriptor in completed/cancelled chain
   1.664 +	*/
   1.665 +	virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
   1.666 +
   1.667 +	/**
   1.668 +	Called by test harness to force an error when the next fragment is
   1.669 +	transferred.
   1.670 +
   1.671 +	Must be implemented by the PSL only if possible.
   1.672 +	@param aChannel The channel where the error is to occur.
   1.673 +	@return KErrNone if implemented.  The default PIL implementation returns
   1.674 +	KErrNotSupported and the test harness knows how to deal with that.
   1.675 +	*/
   1.676 +	virtual TInt FailNext(const TDmaChannel& aChannel);
   1.677 +
   1.678 +	/**
   1.679 +	Called by test harness to force the DMA controller to miss one or
   1.680 +	more interrupts.
   1.681 +
   1.682 +	Must be implemented by the PSL only if possible.
   1.683 +	@param aChannel The channel where the error is to occur
   1.684 +	@param aInterruptCount The number of interrupt to miss.
   1.685 +	@return KErrNone if implemented.  The default PIL implementation returns
   1.686 +	KErrNotSupported and the test harness knows how to deal with that.
   1.687 +	*/
   1.688 +	virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
   1.689 +
   1.690 +	/** Function allowing platform-specific layer to extend channel API with
   1.691 +		new channel-specific operations.
   1.692 +		@param aChannel Channel to operate on
   1.693 +		@param aCmd Command identifier.  Negative values are reserved for Symbian use.
   1.694 +		@param aArg PSL-specific
   1.695 +		@return KErrNotSupported if aCmd is not supported.  PSL-specific value otherwise.
   1.696 +		@see TDmaChannel::Extension
   1.697 +	*/
   1.698 +	virtual TInt Extension(TDmaChannel& aChannel, TInt aCmd, TAny* aArg);
   1.699 +
   1.700 +protected:
   1.701 +	static void HandleIsr(TDmaChannel& aChannel, TBool aIsComplete);
   1.702 +private:
   1.703 +	TInt AllocDesPool(TUint aAttribs);
   1.704 +	void FreeDesPool();
   1.705 +private:
   1.706 +	NFastMutex iLock;			 // protect descriptor reservation and allocation
   1.707 +	const TInt iMaxDesCount;	 // initial number of descriptors and headers
   1.708 +	TInt iAvailDesCount;		 // current available number of descriptors and headers
   1.709 +	SDmaDesHdr* iHdrPool;		 // descriptor header dynamic array
   1.710 +#ifndef __WINS__
   1.711 +	DPlatChunkHw* iHwDesChunk;	 // chunk for hardware descriptor pool
   1.712 +#endif
   1.713 +	TAny* iDesPool;				 // hardware or pseudo descriptor dynamic array
   1.714 +	const TInt iDesSize;		 // descriptor size in bytes
   1.715 +public:
   1.716 +	const TUint iCaps;  		 /*< what is supported by DMA controller */
   1.717 +	enum {KCapsBitHwDes = 1};	 /*< hardware descriptors supported */
   1.718 +	SDmaDesHdr* iFreeHdr;		 /*< head of unallocated descriptors linked list */
   1.719 +#ifdef _DEBUG
   1.720 +	TBool IsValidHdr(const SDmaDesHdr* aHdr);
   1.721 +#endif
   1.722 +	__DMA_DECLARE_INVARIANT
   1.723 +	};
   1.724 +
   1.725 +
   1.726 +//////////////////////////////////////////////////////////////////////////////
   1.727 +
   1.728 +/**
   1.729 +Single-buffer DMA channel.
   1.730 +
   1.731 +Can be instantiated or further derived by PSL.  Not
   1.732 +intended to be instantiated by client device drivers.
   1.733 +@publishedPartner
   1.734 +@released
   1.735 +*/
   1.736 +
   1.737 +class TDmaSbChannel : public TDmaChannel
   1.738 +	{
   1.739 +private:
   1.740 +	virtual void DoQueue(DDmaRequest& aReq);
   1.741 +	virtual void DoCancelAll();
   1.742 +	virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
   1.743 +private:
   1.744 +	TBool iTransferring;
   1.745 +	};
   1.746 +
   1.747 +
   1.748 +/**
   1.749 +Double-buffer DMA channel.
   1.750 +
   1.751 +Can be instantiated or further derived by PSL.  Not
   1.752 +intended to be instantiated by client device drivers.
   1.753 +@publishedPartner
   1.754 +@released
   1.755 +*/
   1.756 +
   1.757 +class TDmaDbChannel : public TDmaChannel
   1.758 +	{
   1.759 +private:
   1.760 +	virtual void DoQueue(DDmaRequest& aReq);
   1.761 +	virtual void DoCancelAll();
   1.762 +	virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
   1.763 +private:
   1.764 +	enum { EIdle = 0, ETransferring, ETransferringLast } iState;
   1.765 +	};
   1.766 +
   1.767 +
   1.768 +/**
   1.769 +Scatter-gather DMA channel.
   1.770 +
   1.771 +Can be instantiated or further derived by PSL.
   1.772 +Not intended to be instantiated by client device drivers.
   1.773 +@publishedPartner
   1.774 +@released
   1.775 +*/
   1.776 +
   1.777 +class TDmaSgChannel : public TDmaChannel
   1.778 +	{
   1.779 +private:
   1.780 +	virtual void DoQueue(DDmaRequest& aReq);
   1.781 +	virtual void DoCancelAll();
   1.782 +	virtual void DoUnlink(SDmaDesHdr& aHdr);
   1.783 +	virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
   1.784 +private:
   1.785 +	TBool iTransferring;
   1.786 +	};
   1.787 +
   1.788 +
   1.789 +//////////////////////////////////////////////////////////////////////////////
   1.790 +// INTERFACE WITH TEST HARNESS
   1.791 +//////////////////////////////////////////////////////////////////////////////
   1.792 +
   1.793 +/**
   1.794 +Set of information used by test harness.
   1.795 +@publishedPartner
   1.796 +@released
   1.797 +*/
   1.798 +
   1.799 +struct TDmaTestInfo
   1.800 +	{
   1.801 +	/** Maximum transfer size in bytes for all channels (ie. the minimum of all channels' maximum size)*/
   1.802 +	TInt iMaxTransferSize;
   1.803 +	/** 3->Memory buffers must be 4-byte aligned, 7->8-byte aligned, ... */
   1.804 +	TUint iMemAlignMask;
   1.805 +	/** Cookie to pass to DDmaRequest::Fragment for memory-memory transfer*/
   1.806 +	TUint32 iMemMemPslInfo;
   1.807 +	/** Number of test single-buffer channels */
   1.808 +	TInt iMaxSbChannels;
   1.809 +	/** Pointer to array containing single-buffer test channel ids */
   1.810 +	TUint32* iSbChannels;
   1.811 +	/** Number of test double-buffer channels */
   1.812 +	TInt iMaxDbChannels;
   1.813 +	/** Pointer to array containing double-buffer test channel ids */
   1.814 +	TUint32* iDbChannels;
   1.815 +	/** Number of test scatter-gather channels */
   1.816 +	TInt iMaxSgChannels;
   1.817 +	/** Pointer to array containing scatter-gather test channel ids */
   1.818 +	TUint32* iSgChannels;
   1.819 +	};
   1.820 +
   1.821 +
   1.822 +/**
   1.823 +Provides access to test information structure stored in the PSL.
   1.824 +
   1.825 +Must be implemented by the PSL.
   1.826 +@publishedPartner
   1.827 +@released
   1.828 +*/
   1.829 +
   1.830 +IMPORT_C const TDmaTestInfo& DmaTestInfo();
   1.831 +
   1.832 +
   1.833 +//////////////////////////////////////////////////////////////////////////////
   1.834 +
   1.835 +#include <drivers/dma_v1.inl>
   1.836 +
   1.837 +#endif