kernel/eka/include/drivers/dma_hai.h
changeset 36 538db54a451d
child 87 2f92ad2dc5db
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/include/drivers/dma_hai.h	Mon Jan 18 21:31:10 2010 +0200
@@ -0,0 +1,870 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// include/drivers/dma_hai.h
+// DMA Framework - Symbian Hardware Abstraction Interface (SHAI).
+//
+//
+
+#ifndef __DMA_HAI_H__
+#define __DMA_HAI_H__
+
+
+#include <kernel/kern_priv.h>
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+/** Interface used by PIL to open and close DMA channels.
+
+	Must be implemented by the PSL.
+
+	@publishedPartner
+	@released
+*/
+class DmaChannelMgr
+	{
+public:
+	/** Opens a channel using a client-provided identifier.
+
+		This function must be implemented by the PSL.
+
+		@param aOpenId PSL-specific magic cookie passed by client. This could
+		identify the channel exactly (by being just the channel number), or at
+		least sufficiently (for example for use with a certain peripheral), or
+		it may indicate some properties which the channel must possess. It may
+		be set to zero always if all channels are equivalent.
+
+		@param aDynChannel ETrue if the Open call is for a dynamic channel. A
+		dynamic channel is not exclusively reserved for just one client, and
+		further Open calls for more dynamic channels should succeed as long as
+		certain resources (but not including the number of available physical
+		channels) are not exceeded. Different transfer requests on this dynamic
+		channel may be serviced using different actual channels.
+
+		@param aPriority The desired channel priority as requested by the
+		client. This may be an actual hardware priority or a
+		platform-independent value. Not being able to satisfy the requested
+		value is not a reason for the PSL to return NULL. This parameter may be
+		ignored if aDynChannel is passed as ETrue. An overriding per-transfer
+		priority may be requested by a client later via
+		TDmaTransferArgs::iChannelPriority.
+		@see SDmacCaps::iChannelPriorities
+		@see TDmaPriority
+
+		@return Pointer to channel if available, NULL otherwise. It should not
+		be NULL if the Open call was for a dynamic channel unless a processing
+		error occurred.
+
+		@pre The PIL calls this function with a global fast mutex held to avoid
+		race conditions.
+
+		@post If a non-NULL pointer is returned, the object pointed to has its
+		iController, iDmacCaps, iPslId, iDynChannel and iPriority members set
+		to valid states.
+
+		iController should point to the controller handling the
+		channel.
+
+		iDmacCaps should point to a SDmacCaps structure containing values
+		relating to this particular channel.
+
+		iPslId should contain a value uniquely identifying the channel - the
+		PIL assigns this value later during request fragmentation to
+		TDmaTransferArgs::iChannelCookie. It can be given any convenient value
+		by the PSL (channel index, I/O port address, etc.).
+
+		iDynChannel should be set to ETrue by the PSL if a dynamic channel was
+		requested and has been opened.
+
+		If applicable, iPriority should contain the actual hardware priority
+		that has been configured or reserved. Otherwise it may be left at its
+		default value TDmaPriority::KDmaPriorityNone.
+	*/
+	static TDmaChannel* Open(TUint32 aOpenId, TBool aDynChannel, TUint aPriority);
+
+	/** Performs platform-specific operations when a channel is closed.
+
+		If aChannel was opened as a dynamic channel then this call is a sign
+		that there is a client which does not intend to queue any further
+		transfer requests via this channel.
+
+		This function must be implemented by the PSL but the implementation can
+		be a no-op.
+
+		@param aChannel The channel to close
+
+		@pre The PIL calls this function with a global fast mutex held to avoid
+		race conditions.
+	*/
+	static void Close(TDmaChannel* aChannel);
+
+	/** Function allowing PSL to extend DMA API with new channel-independent
+		operations.
+
+		This function must be implemented by the PSL.
+
+		@param aCmd Command identifier. Negative values are reserved for FW
+		internal use.
+
+		@param aArg PSL-specific
+
+		@return KErrNotSupported if aCmd is not supported. PSL-specific value
+		otherwise.
+	 */
+	static TInt StaticExtension(TInt aCmd, TAny* aArg);
+
+	/** Acquires the channel manager lock. Called by the PIL before opening and
+		closing a channel.
+	*/
+	static void Wait();
+
+	/** Releases the channel manager lock. Called by the PIL after opening and
+		closing a channel.
+	*/
+	static void Signal();
+
+private:
+	/** Declared, defined, and called by PSL's DECLARE_STANDARD_EXTENSION(). */
+	friend TInt InitExtension();
+
+	/** Must be called in the DMA DLL entry point. */
+	static TInt Initialise();
+
+	static NFastMutex Lock;
+	};
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+/** Abstract base class representing a DMA controller.
+
+	The class has two purposes.
+
+	First, it is a container for channels, descriptors and descriptor headers.
+
+	Second, it exposes a set of virtual functions implemented by the PSL
+	(platform-specific layer).
+
+	These functions are the main interfaces between the PIL
+	(platform-independent layer) and PSL.
+
+	@publishedPartner
+	@released
+*/
+class TDmac
+	{
+	friend class DmaChannelMgr;
+
+protected:
+	/** Data required for creating a new instance */
+	struct SCreateInfo
+		{
+		/** True if DMAC uses hardware descriptors (i.e. supports
+			scatter/gather mode).
+		*/
+		TBool iCapsHwDes;
+		/** Initial maximum number of descriptors and headers (shared by all
+			channels) to be allocated by the PIL. If at run time more
+			descriptors are needed then they will be dynamically allocated and
+			added to the available pool.
+
+			The PSL may consider a number of factors when providing this
+			initial value, such as the number of channels on this controller,
+			the maximum transfer size per descriptor and also likely usage
+			scenarios for the platform or device (number of drivers using DMA,
+			their traffic patterns, simultaneity of operations, etc.).
+		*/
+		TInt iDesCount;
+		/** Size of individual descriptors. Use sizeof(TDmaTransferArgs) for
+		 	single-buffer and double-buffer (i.e. non-s/g) controllers.
+		*/
+		TInt iDesSize;
+		/** Bitmask used when creating the memory chunk storing the descriptor
+			pool. Used only for hardware descriptors.
+
+			The access part must be EMapAttrSupRw. If the chunk is cached
+			and/or buffered, the PSL must flush the data cache and/or drain the
+			write buffer in InitHwDes() and related functions.
+
+			The physical start address of the chunk will always be MMU page
+		 	size aligned.
+
+		 	@see TMappingAttributes
+		 */
+		TUint iDesChunkAttribs;
+		};
+
+	/** Base class constructor. */
+	TDmac(const SCreateInfo& aInfo);
+
+	/** Base class 2nd-phase constructor. */
+	TInt Create(const SCreateInfo& aInfo);
+
+public:
+	/** Base class virtual destructor. */
+	virtual ~TDmac();
+
+	/** Allocates a number of headers (and hence also descriptors) from the
+		header/descriptor pools. Called by the PIL but may also be used by the
+		PSL.
+	*/
+	TInt ReserveSetOfDes(TInt aCount);
+
+	/** Returns previously allocated headers (and hence also descriptors) to
+		the header/descriptor pools. Called by the PIL but may also be used by
+		the PSL.
+	*/
+	void ReleaseSetOfDes(TInt aCount);
+
+	/** Called by the PIL during request fragmentation to fill a descriptor or
+		pseudo descriptor with transfer arguments.
+	*/
+	TInt InitDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs);
+
+	/** Called by the PIL in TDmaChannel::IsrRedoRequest() if any of the
+		latter's arguments is non-zero.
+	*/
+	TInt UpdateDes(const SDmaDesHdr& aHdr, TUint32 aSrcAddr, TUint32 aDstAddr,
+				   TUint aTransferCount, TUint32 aPslRequestInfo);
+
+	/** Returns a reference to the associated pseudo descriptor for a given
+		descriptor header. For use by PIL and PSL.
+	*/
+	inline TDmaTransferArgs& HdrToDes(const SDmaDesHdr& aHdr) const;
+
+	/** Returns a reference to the associated hardware descriptor for a given
+		descriptor header. For use by PIL and PSL.
+	*/
+	inline TAny* HdrToHwDes(const SDmaDesHdr& aHdr) const;
+
+	/** Returns the physical address of the hardware descriptor
+		pointed to by aDes. For use by PIL and PSL.
+	*/
+	inline TUint32 HwDesLinToPhys(TAny* aDes) const;
+
+	/** Called by the PIL to acquire the controller lock which protects the
+		header and descriptor pools.
+	*/
+	inline void Wait();
+
+	/** Called by the PIL to release the controller lock which protects the
+		header and descriptor pools.
+	*/
+	inline void Signal();
+
+public:
+	/** Called by PIL when one fragment (single-buffer and double-buffer DMACs)
+		or list of fragments (scatter/gather DMAC) is to be transferred.
+
+		Called when initiating a new transfer and also, for double-buffer
+		DMACs, for configuring the next fragment to transfer while the current
+		one is ongoing.
+
+		The function must be implemented by the PSL if
+		SCreateInfo::iCaps::iAsymHwDescriptors is reported as false.
+
+		@note This function may be called in thread or ISR context by the PIL
+
+		@param aChannel The channel to use.
+		@param aHdr Header associated with fragment to transfer.
+	*/
+	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
+
+	/** Called by PIL when two lists of fragments (scatter/gather DMAC with
+		asymmetrical linked-list capability) are to be transferred.
+
+		Called when initiating a new transfer.
+
+		The function must be implemented by the PSL if
+		SDmaCaps::iAsymHwDescriptors is reported as true.
+
+		@note This function may be called in thread or ISR context by the PIL
+
+		@param aChannel The channel to use.
+		@param aSrcHdr Header associated with descriptor to transfer on the
+		source side.
+		@param aDstHdr Header associated with descriptor to transfer on the
+		destination side.
+	*/
+	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aSrcHdr,
+						  const SDmaDesHdr& aDstHdr);
+
+	/** Called by PIL to stop a transfer on a given channel.
+
+		The stopping must occur synchronously as the PIL assumes the channel
+		is halted after calling this function. A channel stopped via this
+		function is not intended to be resumed. Function must always be
+		implemented by the PSL.
+
+		@param aChannel The channel to stop
+		@post The channel will be idle
+		@post No interrupt will occur from this channel until a new
+		request is queued.
+	*/
+	virtual void StopTransfer(const TDmaChannel& aChannel) = 0;
+
+	/** Called by PIL to pause (suspend) a transfer on a given channel.
+
+		A paused channel transfer must be able to be resumed by calling
+		ResumeTransfer().
+
+		The function must be implemented by the PSL if
+		SDmacCaps::iChannelPauseAndResume is reported as true.
+
+		@return KErrNone if the transfer has been paused successfully,
+		KErrCompletion if the transfer was already paused, KErrGeneral
+		if a general error occurred preventing a successful outcome.
+
+		@post No interrupt will occur from this channel until it is
+		resumed.
+	 */
+	virtual TInt PauseTransfer(const TDmaChannel& aChannel);
+
+	/** Called by PIL to resume a paused (suspended) transfer on a given
+		channel.
+
+		Resume() can be called when the transfer is paused as a result of a
+		previous call to PauseTransfer() or because the DMAC has encountered a
+		Pause bit in a H/W descriptor.
+
+		The function must be implemented by the PSL if
+		SDmacCaps::iChannelPauseAndResume is reported as true.
+
+		@return KErrNone if the transfer has been resumed successfully,
+		KErrCompletion if there was no paused transfer, KErrGeneral
+		if a general error occurred preventing a successful outcome.
+	 */
+	virtual TInt ResumeTransfer(const TDmaChannel& aChannel);
+
+	/** Called by PIL to check whether a DMA channel is idle.
+
+		'Idle' here means that the channel is ultimately stopped, for example
+		because the transfer has finished, or an error was encountered, or it
+		was manually stopped, but not because it was manually suspended (aka
+		'paused'), or it is waiting for a request line assertion to start the
+		transfer.
+
+		@param aChannel The channel to test
+
+		@return ETrue if channel idle, EFalse if transferring.
+	*/
+	virtual TBool IsIdle(const TDmaChannel& aChannel) = 0;
+
+	/** Called by PIL to retrieve from the PSL the maximum transfer length
+		based on the parameters passed.
+
+		@param aChannel Channel to be used for the transfer
+		@param aSrcFlags Bitmask characterising transfer source
+		@see TDmaTransferArgs::iSrcConfig::iFlags
+		@param aDstFlags Bitmask characterising transfer destination
+		@see TDmaTransferArgs::iDstConfig::iFlags
+		@param aPslInfo Cookie passed by client and used by the PSL
+		@see TDmaTransferArgs::iPslRequestInfo
+
+		@return 0 if transfer length is not limited, the maximum transfer
+		length in bytes otherwise.
+	*/
+	virtual TUint MaxTransferLength(TDmaChannel& aChannel, TUint aSrcFlags,
+									TUint aDstFlags, TUint32 aPslInfo) = 0;
+
+	/** Called by PIL to retrieve from the PSL the memory alignment mask based
+		on the parameters passed. Some DMA controllers impose alignment
+		constraints on the base address of memory buffers. This mask is AND'ed
+		against memory addresses computed during fragmentation.
+
+		The PIL will call this function separately for source and destination.
+
+		An assumption is that the PSL doesn't need to know if a call to this
+		function is for the source or the destination side, i.e. both ports
+		are, as far as the alignment is concerned, equivalent. All that matters
+		are the values of the relevant configuration parameters.
+
+		Another assumption is that the alignment requirement for a port on a
+		DMAC with potentially different values for source and destination does
+		not depend on the configuration of the respective other port.
+
+		@param aChannel Channel used for the transfer
+		@param aTargetFlags Bitmask characterising transfer source or
+		destination
+		@see TDmaTransferArgs::iSrcConfig::iFlags
+		@see TDmaTransferArgs::iDstConfig::iFlags
+		@param aElementSize Element size used for the transfer. May be zero if
+		not known or 'don't care'.
+		@param aPslInfo Cookie passed by client and used by the PSL
+		@see TDmaTransferArgs::iPslRequestInfo
+
+		@return A value representing the alignment mask (e.g. 3 if buffer must
+		be 4-byte aligned)
+	*/
+	virtual TUint AddressAlignMask(TDmaChannel& aChannel, TUint aTargetFlags,
+								   TUint aElementSize, TUint32 aPslInfo) = 0;
+
+	/** Called by PIL during fragmentation to initialise a hardware descriptor.
+
+		The PSL must assume the descriptor is the last in the chain and so set
+		the interrupt bit and set the next descriptor field to an end of chain
+		marker.
+
+		The function must be implemented by the PSL if and only if the DMAC
+		supports hardware descriptors and SDmaCaps::iAsymHwDescriptors is
+		reported as false.
+
+		@param aHdr Header associated with the hardware descriptor to
+		initialise
+		@param aTransferArgs The transfer parameters for this descriptor
+
+		@return KErrNone if the descriptor was successfully initialized,
+		KErrArgument if any of the transfer arguments were detected to be
+		invalid, KErrGeneral if a general error occurred preventing a
+		successful outcome.
+	*/
+	virtual TInt InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs);
+
+	/** Called by PIL during fragmentation to initialise a hardware descriptor
+		on the source side of an asymmetric linked list.
+
+		The function must be implemented by the PSL if
+		SDmaCaps::iAsymHwDescriptors is reported as true.
+
+		@param aHdr Header associated with the hardware descriptor to
+		initialise
+		@param aTransferArgs The transfer parameters for this descriptor. Only
+		the elements relating to the source side should be relevant to the
+		implementation.
+
+		@return KErrNone if the descriptor was successfully initialized,
+		KErrArgument if any of the transfer arguments were detected to be
+		invalid, KErrGeneral if a general error occurred preventing a
+		successful outcome.
+	*/
+	virtual TInt InitSrcHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs);
+
+	/** Called by PIL during fragmentation to initialise a hardware descriptor
+		on the destination side of an asymmetric linked list.
+
+		The function must be implemented by the PSL if
+		SDmaCaps::iAsymHwDescriptors is reported as true.
+
+		@param aHdr Header associated with the hardware descriptor to
+		initialise
+		@param aTransferArgs The transfer parameters for this descriptor. Only
+		the elements relating to the destination side should be relevant to the
+		implementation.
+
+		@return KErrNone if the descriptor was successfully initialized,
+		KErrArgument if any of the transfer arguments were detected to be
+		invalid, KErrGeneral if a general error occurred preventing a
+		successful outcome.
+	*/
+	virtual TInt InitDstHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs);
+
+	/** Called by the PIL in ISR context to change specific fields in a
+		hardware descriptor.
+
+		The function must be implemented by the PSL if and only if the DMAC
+		supports hardware descriptors and SDmaCaps::iAsymHwDescriptors is
+		reported as false.
+
+		@param aHdr Header associated with the hardware descriptor to be
+		updated
+		@param aSrcAddr @see TDmaTransferArgs::iSrcConfig::iAddr
+		@param aDstAddr @see TDmaTransferArgs::iDstConfig::iAddr
+		@param aTransferCount @see TDmaTransferArgs::iTransferCount
+		@param aPslRequestInfo @see TDmaTransferArgs::iPslRequestInfo
+
+		Since Epoc::LinearToPhysical() cannot be called in ISR context the
+		addresses passed into this function are always physical ones, i.e.
+		TDmaTransferFlags::KDmaPhysAddr is implied.
+
+		@return KErrNone if the descriptor was successfully modified,
+		KErrArgument if any of the transfer arguments were detected to be
+		invalid, KErrGeneral if a general error occurred preventing a
+		successful outcome.
+	*/
+	virtual TInt UpdateHwDes(const SDmaDesHdr& aHdr, TUint32 aSrcAddr, TUint32 aDstAddr,
+							 TUint aTransferCount, TUint32 aPslRequestInfo);
+
+	/** Called by the PIL in ISR context to change specific fields in a
+		hardware descriptor.
+
+		The function must be implemented by the PSL if
+		SDmaCaps::iAsymHwDescriptors is reported as true.
+
+		@param aHdr Header associated with the hardware descriptor to be
+		updated
+		@param aSrcAddr @see TDmaTransferArgs::iSrcConfig::iAddr
+		@param aTransferCount @see TDmaTransferArgs::iTransferCount
+		@param aPslRequestInfo @see TDmaTransferArgs::iPslRequestInfo
+
+		Since Epoc::LinearToPhysical() cannot be called in ISR context the
+		address passed into this function is always a physical ones, i.e.
+		TDmaTransferFlags::KDmaPhysAddr is implied.
+
+		@return KErrNone if the descriptor was successfully modified,
+		KErrArgument if any of the transfer arguments were detected to be
+		invalid, KErrGeneral if a general error occurred preventing a
+		successful outcome.
+	*/
+	virtual TInt UpdateSrcHwDes(const SDmaDesHdr& aHdr, TUint32 aSrcAddr,
+								TUint aTransferCount, TUint32 aPslRequestInfo);
+
+	/** Called by the PIL in ISR context to change specific fields in a
+		hardware descriptor.
+
+		The function must be implemented by the PSL if
+		SDmaCaps::iAsymHwDescriptors is reported as true.
+
+		@param aHdr Header associated with the hardware descriptor to be
+		updated
+		@param aDstAddr @see TDmaTransferArgs::iDstConfig::iAddr
+		@param aTransferCount @see TDmaTransferArgs::iTransferCount
+		@param aPslRequestInfo @see TDmaTransferArgs::iPslRequestInfo
+
+		Since Epoc::LinearToPhysical() cannot be called in ISR context the
+		address passed into this function is always a physical ones, i.e.
+		TDmaTransferFlags::KDmaPhysAddr is implied.
+
+		@return KErrNone if the descriptor was successfully modified,
+		KErrArgument if any of the transfer arguments were detected to be
+		invalid, KErrGeneral if a general error occurred preventing a
+		successful outcome.
+	*/
+	virtual TInt UpdateDstHwDes(const SDmaDesHdr& aHdr, TUint32 aDstAddr,
+								TUint aTransferCount, TUint32 aPslRequestInfo);
+
+	/** Called by PIL, when fragmenting a request, to append a new hardware
+		descriptor to an existing descriptor chain. May also be called by
+		clients who wish to create their own descriptor chains.
+
+		Must clear the interrupt bit of the descriptor associated with aHdr.
+
+		The function must be implemented by the PSL if and only if the DMAC
+		supports hardware descriptors.
+
+		@param aHdr Header associated with last fragment in chain
+		@param aNextHdr Header associated with fragment to append
+	*/
+	virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
+
+	/** Called by PIL when queuing a new request while the channel is running.
+
+		Must append the first hardware descriptor of the new request to the
+		last descriptor in the existing chain.
+
+		The function must be implemented by the PSL if and only if the DMAC
+		supports hardware descriptors.
+
+		@param aChannel The channel where the transfer takes place
+		@param aLastHdr Header associated with last hardware descriptor in
+		chain
+		@param aNewHdr Header associated with first hardware descriptor in new
+		request
+	*/
+	virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
+							 const SDmaDesHdr& aNewHdr);
+
+	/** Called by PIL when queuing a new request while the channel is running.
+
+		Must append the first hardware descriptor of the new request to the
+		last descriptor in the existing chain.
+
+		The function must be implemented by the PSL if
+		SDmaCaps::iAsymHwDescriptors is reported as true.
+
+		@param aChannel The channel where the transfer takes place
+		@param aSrcLastHdr Header associated with the last descriptor in the
+		source side chain
+		@param aSrcNewHdr Header associated with the first source side
+		descriptor of the new request
+		@param aDstLastHdr Header associated with the last descriptor in the
+		destination side chain
+		@param aDstNewHdr Header associated with the first destination side
+		descriptor of the new request
+	*/
+	virtual void AppendHwDes(const TDmaChannel& aChannel,
+							 const SDmaDesHdr& aSrcLastHdr, const SDmaDesHdr& aSrcNewHdr,
+							 const SDmaDesHdr& aDstLastHdr, const SDmaDesHdr& aDstNewHdr);
+
+	/** Called by PIL when completing or cancelling a request to cause the PSL
+		to unlink the last item in the h/w descriptor chain from a subsequent
+		chain that it was possibly linked to.
+
+		The function must be implemented by the PSL if and only if the DMAC
+		supports hardware descriptors.
+
+		@param aChannel The channel where the request (and thus the descriptor)
+		was queued
+		@param aHdr Header associated with last h/w descriptor in
+		completed / cancelled chain
+	*/
+	virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
+
+	/** Called by PIL when freeing descriptors back to the shared pool in
+		FreeDesList(). The PSL inside ClearHwDes() can clear the contents of
+		the h/w descriptor.
+
+		This may be necessary if the PSL implementation uses the h/w descriptor
+		as another header which in turn points to the actual DMA h/w descriptor
+		(aka LLI).
+
+		The function may be implemented by the PSL if the DMAC supports
+		hardware descriptors.
+
+		@param aHdr Header associated with the h/w descriptor being freed.
+	 */
+	virtual void ClearHwDes(const SDmaDesHdr& aHdr);
+
+	/** Called by PIL to logically link two physical channels.
+
+		The function must be implemented by the PSL if the DMAC supports
+		logical channel linking.
+
+		@see SDmacCaps::iChannelLinking
+
+		@param a1stChannel The channel which is to be linked to another channel
+		@param a2ndChannel The channel the first one is to be linked to
+
+		@return KErrNone if the two channels have been linked successfully,
+		KErrCompletion if a1stChannel was already linked to a2ndChannel,
+		KErrArgument if a1stChannel was already linked to a different channel,
+		KErrGeneral if a general error occurred preventing a successful
+		outcome. The default PIL implementation returns KErrNotSupported.
+	 */
+	virtual TInt LinkChannels(TDmaChannel& a1stChannel, TDmaChannel& a2ndChannel);
+
+	/** Called by PIL to logically unlink a physical channel from its linked-to
+		successor.
+
+		The function must be implemented by the PSL if the DMAC supports
+		logical channel linking.
+
+		@see SDmacCaps::iChannelLinking
+
+		@param aChannel The channel which is to be unlinked from its successor
+
+		@return KErrNone if the channel has been unlinked successfully,
+		KErrCompletion if the channel was not linked to another channel,
+		KErrGeneral if a general error occurred preventing a successful
+		outcome. The default PIL implementation returns KErrNotSupported.
+	 */
+	virtual TInt UnlinkChannel(TDmaChannel& aChannel);
+
+	/** Called by a test harness to force an error when the next fragment is
+		transferred.
+
+		Must be implemented by the PSL only if possible.
+
+		@param aChannel The channel where the error is to occur.
+
+		@return KErrNone if implemented. The default PIL implementation
+		returns KErrNotSupported.
+	*/
+	virtual TInt FailNext(const TDmaChannel& aChannel);
+
+	/** Called by a test harness to force the DMA controller to miss one or
+		more interrupts.
+
+		The function must be implemented by the PSL only if possible.
+
+		@param aChannel The channel where the error is to occur
+		@param aInterruptCount The number of interrupt to miss.
+
+		@return KErrNone if implemented. The default PIL implementation
+		returns KErrNotSupported.
+	*/
+	virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
+
+	/** Function allowing platform-specific layer to extend channel API with
+		new channel-specific operations.
+
+		@see TDmaChannel::ChannelExtension
+
+		@param aChannel Channel to operate on
+		@param aCmd Command identifier. Negative values are reserved for use by
+		Nokia.
+		@param aArg PSL-specific argument
+
+		@return KErrNotSupported if aCmd is not supported. PSL-specific value
+		otherwise.
+	*/
+	virtual TInt Extension(TDmaChannel& aChannel, TInt aCmd, TAny* aArg);
+
+	/** Called by the PIL to query the number of elements that have so far been
+		transferred by the hardware descriptor associated with aHdr at the
+		source port.
+
+		If SDmacCaps::iAsymHwDescriptors is true then the PIL will call this
+		function only for source-side descriptors, and the PSL should fault the
+		kernel if this is not the case.
+
+		The function must be implemented (i.e. overridden) by the PSL if and
+		only if the DMAC supports hardware descriptors.
+
+		@param aHdr Descriptor header associated with the hardware descriptor
+		to be queried
+
+		@return The number of elements that have been transferred by the
+		hardware descriptor associated with aHdr at the source port
+	*/
+	virtual TUint32 HwDesNumSrcElementsTransferred(const SDmaDesHdr& aHdr);
+
+	/** Called by the PIL to query the number of elements that have so far been
+		transferred by the hardware descriptor associated with aHdr at the
+		destination port.
+
+		If SDmacCaps::iAsymHwDescriptors is true then the PIL will call this
+		function only for destination-side descriptors, and the PSL should
+		panic if this is not the case.
+
+		The function must be implemented (i.e. overridden) by the PSL if and
+		only if the DMAC supports hardware descriptors.
+
+		@param aHdr Descriptor header associated with the hardware descriptor
+		to be queried
+
+		@return The number of elements that have been transferred by the
+		hardware descriptor associated with aHdr at the destination port
+	*/
+	virtual TUint32 HwDesNumDstElementsTransferred(const SDmaDesHdr& aHdr);
+
+protected:
+	/** Called by the PSL in interrupt context upon a channel interrupt event.
+
+		@param aChannel The channel the ISR relates to
+		@param aEventMask Bitmask of one or more TDmaCallbackType values
+		@param aIsComplete Set to ETrue if no error was encountered
+	 */
+	static void HandleIsr(TDmaChannel& aChannel, TUint aEventMask, TBool aIsComplete);
+
+private:
+	/** Called in Create() */
+	TInt AllocDesPool(TUint aAttribs);
+
+	/** Called in ~TDmac() */
+	void FreeDesPool();
+
+private:
+	NFastMutex iLock;			 // protect descriptor reservation and allocation
+	const TInt iMaxDesCount;	 // initial number of descriptors and headers
+	TInt iAvailDesCount;		 // current available number of descriptors and headers
+	SDmaDesHdr* iHdrPool;		 // descriptor header dynamic array
+#ifndef __WINS__
+	DPlatChunkHw* iHwDesChunk;	 // chunk for hardware descriptor pool
+#endif
+	TAny* iDesPool;				 // hardware or pseudo descriptor dynamic array
+	const TInt iDesSize;		 // descriptor size in bytes
+
+public:
+	const TBool iCapsHwDes;		 /*< True if DMAC uses h/w descriptors */
+	SDmaDesHdr* iFreeHdr;		 /*< head of unallocated descriptors linked list */
+
+#ifdef _DEBUG
+	/** Tests whether aHdr points into the descriptor header array. */
+	TBool IsValidHdr(const SDmaDesHdr* aHdr);
+#endif
+	__DMA_DECLARE_INVARIANT
+	};
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+/** Single-buffer DMA channel.
+
+	Can be instantiated or further derived by the PSL.
+
+	@publishedPartner
+	@released
+*/
+class TDmaSbChannel : public TDmaChannel
+	{
+private:
+	virtual void DoQueue(const DDmaRequest& aReq);
+	virtual void DoCancelAll();
+	virtual void DoDfc(const DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
+private:
+	enum {EIdle = 0, ETransferring} iState;
+	};
+
+
+/** Double-buffer DMA channel.
+
+	Can be instantiated or further derived by the PSL.
+
+	@publishedPartner
+	@released
+*/
+class TDmaDbChannel : public TDmaChannel
+	{
+private:
+	virtual void DoQueue(const DDmaRequest& aReq);
+	virtual void DoCancelAll();
+	virtual void DoDfc(const DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
+private:
+	enum {EIdle = 0, ETransferring, ETransferringLast} iState;
+	};
+
+
+/** Scatter-gather DMA channel.
+
+	Can be instantiated or further derived by the PSL.
+
+	@publishedPartner
+	@released
+*/
+class TDmaSgChannel : public TDmaChannel
+	{
+private:
+	virtual void DoQueue(const DDmaRequest& aReq);
+	virtual void DoCancelAll();
+	virtual void DoUnlink(SDmaDesHdr& aHdr);
+	virtual void DoDfc(const DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
+private:
+	enum {EIdle = 0, ETransferring} iState;
+	};
+
+
+/** Scatter-gather DMA channel with asymmetric linked-lists.
+
+	Can be instantiated or further derived by the PSL.
+
+	@publishedPartner
+	@released
+*/
+class TDmaAsymSgChannel : public TDmaChannel
+	{
+private:
+	virtual void DoQueue(const DDmaRequest& aReq);
+	virtual void DoCancelAll();
+	virtual void DoUnlink(SDmaDesHdr& aHdr);
+	virtual void DoDfc(const DDmaRequest& aCurReq, SDmaDesHdr*& aSrcCompletedHdr,
+					   SDmaDesHdr*& aDstCompletedHdr);
+private:
+	SDmaDesHdr* iSrcCurHdr;		   // source fragment being transferred or NULL
+	SDmaDesHdr** iSrcNullPtr; // Pointer to NULL pointer following last source fragment
+	SDmaDesHdr* iDstCurHdr;	  // destination fragment being transferred or NULL
+	SDmaDesHdr** iDstNullPtr; // Pointer to NULL pointer following last destination fragment
+	enum {EIdle = 0, ETransferring} iState;
+	};
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+#include <drivers/dma_hai.inl>
+
+
+#endif	// #ifndef __DMA_HAI_H__