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