--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/include/drivers/dma_v2.h Tue Aug 31 16:34:26 2010 +0300
@@ -0,0 +1,1332 @@
+// Copyright (c) 2002-2010 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_v2.h
+// DMA Framework - Client API v2 definition.
+//
+// NB: DMA clients should never include this file directly, but only ever the
+// generic header file <drivers/dma.h>.
+//
+
+/** @file
+ @publishedPartner
+*/
+
+#ifndef __DMA_H__
+#error "dma_v2.h must'n be included directly - use <drivers/dma.h> instead"
+#endif // #ifndef __DMA_H__
+
+#ifndef __DMA_V2_H__
+#define __DMA_V2_H__
+
+
+#include <kernel/kernel.h>
+#include <drivers/dmadefs.h>
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Debug Support - KDmaPanicCat is defined in each source file
+
+#define __DMA_ASSERTD(e) __ASSERT_DEBUG(e, Kern::Fault(KDmaPanicCat, __LINE__))
+#define __DMA_ASSERTA(e) __ASSERT_ALWAYS(e, Kern::Fault(KDmaPanicCat, __LINE__))
+#ifdef _DEBUG
+#define __DMA_CANT_HAPPEN() Kern::Fault(KDmaPanicCat, __LINE__)
+#define __DMA_DECLARE_INVARIANT public: void Invariant();
+#define __DMA_DECLARE_VIRTUAL_INVARIANT public: virtual void Invariant();
+#define __DMA_INVARIANT() Invariant()
+#else
+#define __DMA_CANT_HAPPEN()
+#define __DMA_DECLARE_INVARIANT
+#define __DMA_DECLARE_VIRTUAL_INVARIANT
+#define __DMA_INVARIANT()
+#endif
+
+#ifdef __DMASIM__
+#ifdef __PRETTY_FUNCTION__
+#define __DMA_UNREACHABLE_DEFAULT() DMA_PSL_TRACE1("Calling default virtual: %s", __PRETTY_FUNCTION__)
+#else
+#define __DMA_UNREACHABLE_DEFAULT() DMA_PSL_TRACE("Calling default virtual function")
+#endif
+#else
+#define __DMA_UNREACHABLE_DEFAULT() __DMA_CANT_HAPPEN()
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+// INTERFACE EXPOSED TO DEVICE-DRIVERS
+//////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////
+
+/** Bitmasks used for configuring a DMA request.
+
+ In general, specify KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest)
+ if the source (resp. destination) is a memory buffer and clear
+ KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest) if the source
+ (resp. destination) is a peripheral.
+
+ If the location is given as a physical address (rather than a linear one)
+ then also specify KDmaPhysAddrSrc and/or KDmaPhysAddrDest.
+
+ The EKA1 "Fill Mode" can be implemented by omitting KDmaIncSrc.
+
+ Some peripherals may require a post-increment address mode.
+
+ @see DDmaRequest::Fragment()
+
+ Note: This enum is only required for backwards compatibility with the old
+ DMA framework, it can be removed once this is no longer needed.
+
+ @deprecated
+*/
+enum TDmaRequestFlags
+ {
+ /** Source is address of memory buffer */
+ KDmaMemSrc = 0x01,
+ /** Destination is address of memory buffer */
+ KDmaMemDest = 0x02,
+ /** Source address must be post-incremented during transfer */
+ KDmaIncSrc = 0x04,
+ /** Destination address must be post-incremented during transfer */
+ KDmaIncDest = 0x08,
+ /** Source address is a physical address (as opposed to a linear one) */
+ KDmaPhysAddrSrc = 0x10,
+ /** Destination address is a physical address (as opposed to a linear one) */
+ KDmaPhysAddrDest = 0x20,
+ /** Request a different max transfer size (for instance for test purposes) */
+ KDmaAltTransferLen = 0x40
+ };
+
+
+/** Each hardware or pseudo descriptor is associated with a header. Headers
+ are needed because hardware descriptors can not easily be extended to store
+ additional information.
+
+ @released
+*/
+struct SDmaDesHdr
+ {
+ SDmaDesHdr* iNext;
+ };
+
+
+/** Pointer to signature of the new extended callback function.
+
+ TUint - bitmask of one or more TDmaCallbackType values
+ TDmaResult - just that
+ TAny* - was provided by client in DDmaRequest constructor
+ SDmaDesHdr* - points to header (and thus descriptor) which caused a
+ 'descriptor completed' or 'descriptor paused' event
+
+ @released
+ */
+typedef void (*TDmaCallback)(TUint, TDmaResult, TAny*, SDmaDesHdr*);
+
+
+class TDmaChannel;
+
+
+/** A DMA request is a list of fragments small enough to be transferred in one go
+ by the DMAC.
+
+ In general, fragmentation is done in the framework by calling Fragment() but
+ clients with special needs can allocate a blank descriptor list with
+ ExpandDesList() and customise it to fit their needs.
+
+ Clients should not set attributes directly, but should use the various functions
+ instead.
+
+ This class has not been designed to be called from several concurrent threads.
+ Multithreaded clients must implement their own locking scheme (via DMutex).
+
+ Mutexes are used internally to protect data structures accessed both by the
+ client thread and the DFC thread. Therefore no fast mutex can be held when
+ calling a request function.
+*/
+class DDmaRequest : public DBase
+ {
+ friend class TDmaChannel;
+
+public:
+ /** The outcome of the transfer
+
+ @see TDmaResult
+
+ @deprecated
+ */
+ enum TResult {EBadResult=0, EOk, EError};
+
+ /** The signature of the completion/failure callback function
+
+ @see TDmaCallback
+
+ @deprecated
+ */
+ typedef void (*TCallback)(TResult, TAny*);
+
+public:
+ /** Constructor.
+
+ Create a new transfer request.
+
+ @param aChannel The channel this request is bound to.
+ @param aCb Callback function called on transfer completion or failure
+ (in channel DFC context). Can be NULL.
+ @param aCbArg Argument passed to callback function.
+ @param aMaxTransferSize Maximum fragment size. If not specified, defaults to the maximum size
+ supported by the DMA controller for the type of transfer that is later scheduled.
+
+ @deprecated
+ */
+ IMPORT_C DDmaRequest(TDmaChannel& aChannel, TCallback aCb=NULL, TAny* aCbArg=NULL,
+ TInt aMaxTransferSize=0);
+
+
+ /** Constructor.
+
+ Create a new transfer request.
+
+ @param aChannel The channel this request is bound to.
+ @param aDmaCb Callback function called on transfer completion or
+ failure (in channel DFC or ISR context). Can be NULL.
+ @param aCbArg Argument passed to callback function.
+ @param aMaxTransferSize Maximum fragment size. If not specified,
+ defaults to the maximum size supported by the DMA controller for the
+ type of transfer that is later scheduled.
+
+ @released
+ */
+ IMPORT_C DDmaRequest(TDmaChannel& aChannel, TDmaCallback aDmaCb,
+ TAny* aCbArg=NULL, TUint aMaxTransferSize=0);
+
+
+ /** Destructor.
+
+ Assume the request is not being transferred or pending.
+
+ @released
+ */
+ IMPORT_C ~DDmaRequest();
+
+
+ /** Split request into a list of fragments small enough to be fed to the
+ DMAC.
+
+ The size of each fragment is smaller than or equal to the maximum
+ transfer size supported by the DMAC. If the source and/or destination
+ is memory, each fragment points to memory which is physically
+ contiguous.
+
+ The kind of transfer to perform is specified via a set of flags used by
+ a PIL and a magic cookie passed to the PSL. If the source
+ (resp. destination) is a peripheral, aSrc (resp. aDest) is treated as a
+ magic cookie by the PIL and passed straight to the PSL.
+
+ The request can be uninitialised or may have been fragmented
+ previously. The previous configuration if any is lost whether or not
+ the function succeeds.
+
+ The client must ensure that any memory buffers involved in the transfer
+ have been suitably prepared for DMA. For memory allocated on the kernel
+ side or in a shared chunk this amounts to ensuring cache consistency
+ before Queue() is called. However for memory that was allocated on the
+ user side the client must also ensure that the memory is protected from
+ both data paging and RAM defragmentation before Fragment() is called
+ @see Kern::MapAndPinMemory(). Note however, that this function is only
+ available if the flexible memory model (FMM) is in use.
+
+ @param aSrc Source memory buffer linear address or peripheral magic
+ cookie.
+ @param aDest Destination memory buffer linear address or peripheral
+ magic cookie.
+ @param aCount Number of bytes to transfer.
+ @param aFlags Bitmask characterising the transfer.
+ @param aPslInfo Hardware-specific information passed to PSL.
+
+ @return KErrNone if success. KErrArgument if aFlags and/or aPslInfo are
+ invalid when finding the maximum transfer size. May also fail if
+ running out of descriptors.
+
+ @pre The request is not being transferred or pending.
+ @pre The various parameters must be valid. The PIL or PSL will fault the
+ kernel if not.
+
+ @see TDmaRequestFlags
+
+ @deprecated
+ */
+ IMPORT_C TInt Fragment(TUint32 aSrc, TUint32 aDest, TInt aCount, TUint aFlags, TUint32 aPslInfo);
+
+
+ /** New version of the DMA request fragment function, to be used with the
+ TDmaTransferArgs structure.
+
+ Split request into a list of fragments small enough to be fed to the
+ DMAC.
+
+ The size of each fragment is smaller than or equal to the maximum
+ transfer size supported by the DMAC. If the source and/or destination
+ is memory, each fragment points to memory which is physically
+ contiguous.
+
+ The request can be uninitialised or may have been fragmented
+ previously. Any previous configuration is lost whether or not the
+ function succeeds.
+
+ The client must ensure that any memory buffers involved in the transfer
+ have been suitably prepared for DMA. For memory allocated on the kernel
+ side or in a shared chunk this amounts to ensuring cache consistency
+ before Queue() is called. However for memory that was allocated on the
+ user side the client must also ensure that the memory is protected from
+ both data paging and RAM defragmentation before Fragment() is called
+ @see Kern::MapAndPinMemory(). Note however, that this function is only
+ available if the flexible memory model (FMM) is in use.
+
+ @param aTransferArgs Describes the transfer to be performed.
+
+ @return KErrNone if success. KErrArgument if certain arguments are
+ invalid. May also fail if running out of descriptors.
+
+ @pre The request is not being transferred or pending.
+ @pre The various parameters must be valid. The PIL or PSL will fault
+ the kernel if not.
+
+ @released
+ */
+ IMPORT_C TInt Fragment(const TDmaTransferArgs& aTransferArgs);
+
+
+ /** Transfer asynchronously this request.
+
+ If this request's channel is idle, the request is transferred
+ immediately. Otherwise, it is queued and transferred later.
+
+ The client is responsible for ensuring cache consistency before and/or
+ after the transfer if necessary.
+
+ @return KErrNone if success, KErrGeneral otherwise.
+
+ @released
+ */
+ IMPORT_C TInt Queue();
+
+
+ /** Append new descriptor(s) to existing list.
+
+ Clients needing to build a custom descriptor list should call this
+ function to allocate the list and access the resulting list through
+ iFirstHdr and iLastHdr.
+
+ Clients should not change the value of iFirstHdr, iLastHdr and the
+ iNext field of the descriptor headers to ensure descriptors can be
+ deallocated. Clients are free to change hardware descriptors, including
+ chaining, in whatever way suit them.
+
+ Assume the request is not being transferred or pending.
+
+ @param aCount Number of descriptors to append.
+
+ @return KErrNone or standard error code.
+
+ @released
+ */
+ IMPORT_C TInt ExpandDesList(TInt aCount=1);
+
+
+ /** Append new descriptor(s) to existing list. This function variant
+ operates on the source port descriptor chain.
+
+ Works like ExpandDesList except that it uses the iSrcFirstHdr and
+ iSrcLastHdr fields.
+
+ @see ExpandDesList()
+
+ This function should only be used if SDmacCaps::iAsymHwDescriptors is
+ reported as true, as only then the framework will actually use the
+ allocated descriptors.
+
+ @param aCount Number of descriptors to append.
+
+ @return KErrNone or standard error code.
+
+ @prototype
+ */
+ IMPORT_C TInt ExpandSrcDesList(TInt aCount=1);
+
+
+ /** Append new descriptor(s) to existing list. This function variant
+ operates on the destination port descriptor chain.
+
+ Works like ExpandDesList except that it uses the iDstFirstHdr and
+ iDstLastHdr fields.
+
+ @see ExpandDesList()
+
+ This function should only be used if SDmacCaps::iAsymHwDescriptors is
+ reported as true, as only then the framework will actually use the
+ allocated descriptors.
+
+ @param aCount Number of descriptors to append.
+
+ @return KErrNone or standard error code.
+
+ @prototype
+ */
+ IMPORT_C TInt ExpandDstDesList(TInt aCount=1);
+
+
+ /** Free resources associated with this request.
+
+ Assumes the request is not being transferred or pending.
+
+ @see ExpandDesList()
+
+ @released
+ */
+ IMPORT_C void FreeDesList();
+
+
+ /** Free resources associated with this request. This function variant
+ operates on the source port descriptor chain.
+
+ Assumes the request is not being transferred or pending.
+
+ @see ExpandSrcDesList()
+
+ @prototype
+ */
+ IMPORT_C void FreeSrcDesList();
+
+
+ /** Free resources associated with this request. This function variant
+ operates on the destination port descriptor chain.
+
+ Assumes the request is not being transferred or pending.
+
+ @see ExpandDstDesList()
+
+ @prototype
+ */
+ IMPORT_C void FreeDstDesList();
+
+
+ /** Enables the functionality for counting the transferred source
+ elements.
+
+ This function can be called at any time, but the enabled/disabled
+ status is checked by the framework only at two points in time.
+
+ The first one is after a request has been queued, and if it is enabled
+ then the counting will commence as soon as the transfer starts.
+
+ The second point is when Resume() is called for a paused transfer, and
+ in this case the following applies. If counting was enabled when the
+ transfer was paused and it is now disabled then the counting is stopped
+ at that point and the count value frozen. If counting was disabled when
+ the transfer was paused and it is now enabled then the counting will
+ commence when the transfer resumes. (The starting value will depend on
+ the argument of the enable function.) Otherwise nothing will change,
+ i.e. counting will either continue normally (enabled/enabled) or
+ neither stop nor continue (disabled/disabled).
+
+ Once a status has been set, it remains valid for the entire duration of
+ the transfer (and beyond, if it is not changed again).
+
+ @param aResetElementCount If ETrue (the default) then the count
+ variable will be reset to zero, otherwise it will retain its current
+ value.
+
+ @see Queue()
+ @see TotalNumSrcElementsTransferred()
+
+ @prototype
+ */
+ IMPORT_C void EnableSrcElementCounting(TBool aResetElementCount=ETrue);
+
+
+ /** Enables the functionality for counting the transferred destination
+ elements.
+
+ This function can be called at any time, but the enabled/disabled
+ status is checked by the framework only at two points in time.
+
+ The first one is after a request has been queued, and if it is enabled
+ then the counting will commence as soon as the transfer starts.
+
+ The second point is when Resume() is called for a paused transfer, and
+ in this case the following applies. If counting was enabled when the
+ transfer was paused and it is now disabled then the counting is stopped
+ at that point and the count value frozen. If counting was disabled when
+ the transfer was paused and it is now enabled then the counting will
+ commence when the transfer resumes. (The starting value will depend on
+ the argument of the enable function.) Otherwise nothing will change,
+ i.e. counting will either continue normally (enabled/enabled) or
+ neither stop nor continue (disabled/disabled).
+
+ Once a status has been set, it remains valid for the entire duration of
+ the transfer (and beyond, if it is not changed again).
+
+ @param aResetElementCount If ETrue (the default) then the count
+ variable will be reset to zero, otherwise it will retain its current
+ value.
+
+ @see Queue()
+ @see TotalNumDstElementsTransferred()
+
+ @prototype
+ */
+ IMPORT_C void EnableDstElementCounting(TBool aResetElementCount=ETrue);
+
+
+ /** Disables the functionality for counting the transferred source
+ elements.
+
+ This function can be called at any time, but the enabled/disabled
+ status is checked by the framework only at two points in time.
+
+ The first one is after a request has been queued, and if it is enabled
+ then the counting will commence as soon as the transfer starts.
+
+ The second point is when Resume() is called for a paused transfer, and
+ in this case the following applies. If counting was enabled when the
+ transfer was paused and it is now disabled then the counting is stopped
+ at that point and the count value frozen. If counting was disabled when
+ the transfer was paused and it is now enabled then the counting will
+ commence when the transfer resumes. (The starting value will depend on
+ the argument of the enable function.) Otherwise nothing will change,
+ i.e. counting will either continue normally (enabled/enabled) or
+ neither stop nor continue (disabled/disabled).
+
+ Once a status has been set, it remains valid for the entire duration of
+ the transfer (and beyond, if it is not changed again).
+
+ @see Queue()
+ @see TotalNumSrcElementsTransferred()
+
+ @prototype
+ */
+ IMPORT_C void DisableSrcElementCounting();
+
+
+ /** Disables the functionality for counting the transferred destination
+ elements.
+
+ This function can be called at any time, but the enabled/disabled
+ status is checked by the framework only at two points in time.
+
+ The first one is after a request has been queued, and if it is enabled
+ then the counting will commence as soon as the transfer starts.
+
+ The second point is when Resume() is called for a paused transfer, and
+ in this case the following applies. If counting was enabled when the
+ transfer was paused and it is now disabled then the counting is stopped
+ at that point and the count value frozen. If counting was disabled when
+ the transfer was paused and it is now enabled then the counting will
+ commence when the transfer resumes. (The starting value will depend on
+ the argument of the enable function.) Otherwise nothing will change,
+ i.e. counting will either continue normally (enabled/enabled) or
+ neither stop nor continue (disabled/disabled).
+
+ Once a status has been set, it remains valid for the entire duration of
+ the transfer (and beyond, if it is not changed again).
+
+ @see Queue()
+ @see TotalNumDstElementsTransferred()
+
+ @prototype
+ */
+ IMPORT_C void DisableDstElementCounting();
+
+
+ /** Returns the number of elements that have been transferred by this
+ transfer request at the source port.
+
+ To use this method, the counting functionality has to be explicitly
+ enabled, either before the transfer request is queued or while it is
+ paused.
+
+ @see EnableSrcElementCounting()
+ @see DisableSrcElementCounting()
+
+ This function should only be called after the transfer has finished
+ (completed with or without error, or because it was cancelled) or while
+ it is paused. Otherwise it may just return 0.
+
+ @return The number of elements that have been transferred by this
+ transfer request at the source port.
+
+ @prototype
+ */
+ IMPORT_C TUint32 TotalNumSrcElementsTransferred();
+
+
+ /** Returns the number of elements that have been transferred by this
+ transfer request at the destination port.
+
+ To use this method, the counting functionality has to be explicitly
+ enabled, either before the transfer request is queued or while it is
+ paused.
+
+ @see EnableDstElementCounting()
+ @see DisableDstElementCounting()
+
+ This function should only be called after the transfer has finished
+ (completed with or without error, or because it was cancelled) or while
+ it is paused. Otherwise it may just return 0.
+
+ @return The number of elements that have been transferred by this
+ transfer request at the destination port.
+
+ @prototype
+ */
+ IMPORT_C TUint32 TotalNumDstElementsTransferred();
+
+
+ /** Returns the number of fragments that this transfer request has been
+ split into.
+
+ This number will only be different from 0 once Fragment() has been
+ called or after descriptors have been manually allocated by the client
+ using ExpandDesList().
+
+ If SDmacCaps::iAsymHwDescriptors is true then this function will always
+ return 0, and SrcFragmentCount() / DstFragmentCount() should be used
+ instead.
+
+ @return The number of fragments (descriptors / pseudo descriptors) that
+ this transfer request has been split into.
+
+ @released
+ */
+ IMPORT_C TInt FragmentCount();
+
+
+ /** Returns the number of source port fragments that this transfer request
+ has been split into.
+
+ This number will only be different from 0 once Fragment() has been
+ called or after descriptors have been manually allocated by the client
+ using ExpandSrcDesList().
+
+ This function can only be used if SDmacCaps::iAsymHwDescriptors is
+ true, otherwise it will always return 0.
+
+ @return The number of source port fragments (descriptors) that this
+ transfer request has been split into.
+
+ @prototype
+ */
+ IMPORT_C TInt SrcFragmentCount();
+
+
+ /** Returns the number of destination port fragments that this transfer
+ request has been split into.
+
+ This number will only be different from 0 once Fragment() has been
+ called or after descriptors have been manually allocated by the client
+ using ExpandDstDesList().
+
+ This function can only be used if SDmacCaps::iAsymHwDescriptors is
+ true, otherwise it will always return 0.
+
+ @return The number of destination port fragments (descriptors) that
+ this transfer request has been split into.
+
+ @prototype
+ */
+ IMPORT_C TInt DstFragmentCount();
+
+private:
+ inline void OnDeque();
+ TInt CheckTransferConfig(const TDmaTransferConfig& aTarget, TUint aCount) const;
+ TInt CheckMemFlags(const TDmaTransferConfig& aTarget) const;
+ TInt AdjustFragmentSize(TUint& aFragSize, TUint aElementSize, TUint aFrameSize);
+ TUint GetTransferCount(const TDmaTransferArgs& aTransferArgs) const;
+ TUint GetMaxTransferlength(const TDmaTransferArgs& aTransferArgs, TUint aCount) const;
+ TInt Frag(TDmaTransferArgs& aTransferArgs);
+ TInt FragSym(TDmaTransferArgs& aTransferArgs, TUint aCount, TUint aMaxTransferLen);
+ TInt FragAsym(TDmaTransferArgs& aTransferArgs, TUint aCount, TUint aMaxTransferLen);
+ TInt FragAsymSrc(TDmaTransferArgs& aTransferArgs, TUint aCount, TUint aMaxTransferLen);
+ TInt FragAsymDst(TDmaTransferArgs& aTransferArgs, TUint aCount, TUint aMaxTransferLen);
+ TInt FragBalancedAsym(TDmaTransferArgs& aTransferArgs, TUint aCount, TUint aMaxTransferLen);
+ TInt ExpandDesList(TInt aCount, TInt& aDesCount, SDmaDesHdr*& aFirstHdr,
+ SDmaDesHdr*& aLastHdr);
+ void FreeDesList(TInt& aDesCount, SDmaDesHdr*& aFirstHdr, SDmaDesHdr*& aLastHdr);
+ TInt FragmentCount(const SDmaDesHdr* aHdr);
+
+public:
+ // WARNING: The following attributes are accessed both in client and DFC
+ // thread context, so accesses must be protected with the channel lock.
+ TDmaChannel& iChannel; /**< The channel this request is bound to */
+ TCallback iCb; /**< Called on completion/failure (can be NULL) */
+ TAny* iCbArg; /**< Callback argument */
+ TDmaCallback iDmaCb; // the new-style callback function
+ TAny* iDmaCbArg; // the new-style callback arg
+ TBool iIsrCb; // client wants callback in ISR context
+ TInt iDesCount; /**< The number of fragments in list */
+ SDmaDesHdr* iFirstHdr; /**< The first fragment in the list (or NULL) */
+ SDmaDesHdr* iLastHdr; /**< The last fragment in the list (or NULL) */
+ TInt iSrcDesCount; /**< The number of fragments in list */
+ SDmaDesHdr* iSrcFirstHdr; /**< The first fragment in the list (or NULL) */
+ SDmaDesHdr* iSrcLastHdr; /**< The last fragment in the list (or NULL) */
+ TInt iDstDesCount; /**< The number of fragments in list */
+ SDmaDesHdr* iDstFirstHdr; /**< The first fragment in the list (or NULL) */
+ SDmaDesHdr* iDstLastHdr; /**< The last fragment in the list (or NULL) */
+ SDblQueLink iLink; /**< The link on channel queue of pending requests */
+ TBool iQueued; /**< Indicates whether request is pending or being transferred */
+ TUint iMaxTransferSize; /**< Defaults to DMA controller max. transfer size */
+
+ TUint32 iTotalNumSrcElementsTransferred;
+ TUint32 iTotalNumDstElementsTransferred;
+
+ __DMA_DECLARE_INVARIANT
+ };
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+class TDmac;
+class DmaChannelMgr;
+class TDmaCancelInfo;
+
+/** DMA channel base class.
+
+ Standard derived classes are provided for this channel (see
+ TDmaSbChannel, TDmaDbChannel, TDmaSgChannel, and TDmaAsymSgChannel).
+ The base-port implementor will only need to write their own derived
+ class if one of the standard classes is unsuitable.
+
+ This class has not been designed to be called from several concurrent
+ client threads. Multithreaded clients must implement their own locking
+ scheme (via DMutex).
+
+ Mutexes are used internally to protect data structures accessed both by the
+ client thread and the DFC one. Therefore no fast mutex can be held when
+ calling a channel function.
+*/
+class TDmaChannel
+ {
+ friend class DDmaRequest;
+ friend class TDmac;
+ friend class DmaChannelMgr;
+
+public:
+ /** Information passed by client when opening a channel. */
+ struct SCreateInfo
+ {
+ /** Default constructor. Initializes all fields with meaningful default
+ values.
+
+ Must be inline (for now) because exporting it would break existing
+ custom DMA libs as their clients would need the export which would
+ be missing from the custom .def files.
+
+ @released
+ */
+ SCreateInfo() : iPriority(KDmaPriorityNone), iDynChannel(EFalse) {};
+
+ /** Identifier used by PSL to select channel to open.
+
+ @released
+ */
+ TUint32 iCookie;
+ /** Number of descriptors this channel can maximally use.
+
+ This value will not be used in the fully implemented new version of
+ the DMA framework. Until then it is still required.
+
+ @released
+ */
+ TInt iDesCount;
+ /** DFC queue used to service DMA interrupts.
+
+ @released
+ */
+ TDfcQue* iDfcQ;
+ /** DFC priority.
+
+ @released
+ */
+ TUint8 iDfcPriority;
+ /** Used by PSL to configure a channel priority (if possible).
+
+ The default is KDmaPriorityNone (the don't care value).
+
+ @see TDmaPriority
+
+ @prototype
+ */
+ TUint iPriority;
+ /** Request a dynamic DMA channel.
+
+ If this is set to ETrue then the Open call is for a 'dynamic' as
+ opposed to a static and solely owned DMA channel. A number of
+ properties of the opened TDmaChannel object will be different in
+ that case.
+
+ The default value is EFalse.
+
+ @prototype
+ */
+ TBool iDynChannel;
+ };
+
+public:
+ /** Opens the DMA channel.
+
+ Channel selection is done by the hardware-specific layer using a cookie
+ passed in via aInfo.
+
+ The client should not delete the returned pointer as the framework owns
+ channel objects. However, the client should explicitly close the
+ channel when finished with it.
+
+ @param aInfo Information passed by caller to select and configure
+ channel.
+
+ @param aChannel Points to open channel on successful return. NULL
+ otherwise.
+
+ @return KErrNone or standard error code.
+
+ @released
+ */
+ IMPORT_C static TInt Open(const SCreateInfo& aInfo, TDmaChannel*& aChannel);
+
+
+ /** Closes a previously opened DMA channel.
+
+ Assumes the channel is idle and all requests have been deleted.
+
+ The call will cause the resources associated with this channel to be
+ released, and the pointer/reference to it mustn't therefore be accessed
+ any longer after the function has returned. The channel pointer should
+ be set to NULL by the client.
+
+ @released
+ */
+ IMPORT_C void Close();
+
+
+ /** Logically links this channel to the one specified as an argument, or,
+ if the argument is NULL, unlinks this channel.
+
+ The effect of channel linking is that once a transfer on this channel
+ has finished, instead of causing the associated client callback to be
+ called, 'aChannel' will be enabled by hardware and a preconfigured
+ transfer on that channel will start.
+
+ Note that conceptually 'linking' here always refers to the end of a
+ channel transfer, not the beginning, i.e. a channel can only be linked
+ once and always to a successor, never twice or to a predecessor. (This
+ does not preclude the possibility that two channels are linked in a
+ circular fashion.)
+
+ This function can only be used if the DMAC supports logical channel
+ linking.
+
+ @see SDmacCaps::iChannelLinking
+
+ @param aChannel Points to the channel this one should be linked to, or
+ NULL if this channel is to be unlinked from any other one.
+
+ @return KErrNone if the channel has been linked or unlinked
+ successfully, KErrCompletion if this channel was already linked to
+ aChannel or already unlinked, KErrNotSupported if the DMAC doesn't
+ support channel linking, KErrArgument if this channel was already
+ linked to a different channel, KErrGeneral if a general error occurred
+ preventing a successful outcome.
+
+ @prototype
+ */
+ IMPORT_C TInt LinkToChannel(TDmaChannel* aChannel);
+
+
+ /** Pauses an active transfer on this channel.
+
+ A paused channel transfer can be resumed by calling Resume() or it can
+ be stopped altogether by calling CancelAll().
+
+ @see TDmaChannel::Resume()
+
+ Function can only be used if the DMAC supports this functionality.
+
+ @see SDmacCaps::iChannelPauseAndResume
+
+ @return KErrNone if a transfer has been paused successfully,
+ KErrCompletion if a transfer was already paused, KErrNotSupported if
+ the DMAC doesn't support channel transfer pausing/resuming, KErrGeneral
+ if a general error occurred preventing a successful outcome.
+
+ @released
+ */
+ IMPORT_C TInt Pause();
+
+
+ /** Resumes a transfer on this channel that is paused.
+
+ Resume() can be called to resume channel operation when the transfer is
+ paused as a result of a previous call to Pause() or because the DMAC
+ has encountered a Pause bit in a H/W descriptor.
+
+ @see TDmaChannel::Pause()
+ @see TDmaCallbackType::EDmaCallbackLinkedListPaused
+
+ Function can only be used if the DMAC supports this functionality.
+
+ @see SDmacCaps::iChannelPauseAndResume
+ @see SDmacCaps::iLinkedListPausedInterrupt
+
+ @return KErrNone if a paused transfer has been resumed successfully,
+ KErrCompletion if there was no paused transfer, KErrNotSupported if the
+ DMAC doesn't support channel transfer pausing/resuming, KErrGeneral if
+ a general error occurred preventing a successful outcome.
+
+ @released
+ */
+ IMPORT_C TInt Resume();
+
+
+ /** Cancels the current request and all the pending ones.
+
+ @released
+ */
+ IMPORT_C void CancelAll();
+
+
+ /** Returns the channel's maximum transfer length based on the passed
+ arguments.
+
+ @param aSrcFlags Bitmask characterising transfer source
+ @see TDmaTransferArgs::iSrcConfig::iFlags
+
+ @param aDstFlags Bitmask characterising transfer destination
+ @see TDmaTransferArgs::iDstConfig::iFlags
+
+ @param aPslInfo Cookie passed to the PSL
+ @see TDmaTransferArgs::iPslRequestInfo
+
+ @return 0 if transfer length is not limited, the maximum transfer
+ length in bytes otherwise.
+
+ @released
+ */
+ IMPORT_C TUint MaxTransferLength(TUint aSrcFlags, TUint aDstFlags, TUint32 aPslInfo);
+
+
+ /** Retrieves from the PSL the address / 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.
+
+ This function needs to be called separately for source and destination.
+
+ @param aTargetFlags Bitmask characterising transfer source or
+ destination
+ @see TDmaTransferArgs::iSrcConfig::iFlags
+ @see TDmaTransferArgs::iDstConfig::iFlags
+
+ @param aElementSize Element size used for the transfer. Can be zero if
+ not known or 'don't care'.
+
+ @param aPslInfo Cookie passed to the PSL
+ @see TDmaTransferArgs::iPslRequestInfo
+
+ @return A value representing the alignment mask (e.g. 3 if buffer must
+ be 4-byte aligned)
+
+ @released
+ */
+ IMPORT_C TUint AddressAlignMask(TUint aTargetFlags, TUint aElementSize,
+ TUint32 aPslInfo);
+
+
+ /** Returns a reference to a structure containing the capabilities and
+ features of the DMA controller associated with this channel.
+
+ @return A reference to a structure containing the capabilities and
+ features of the DMA controller associated with this channel.
+
+ @released
+ */
+ IMPORT_C const SDmacCaps& DmacCaps();
+
+
+ /** Sets up once more the transfer request that has just completed, after
+ optionally having adjusted the transfer parameters as specified.
+
+ This function is meant to be called exclusively from a client-supplied
+ callback that is executed in ISR context, and only in response to a
+ transfer completion notification.
+
+ If this call returns to the caller with KErrNone then the framework's
+ ISR handler will subsequently not queue the channel DFC for this
+ completed request.
+
+ The parameters specify which changes the framework should apply to the
+ descriptors of the transfer request before rescheduling it. Arguments
+ for which no change is required should be passed as their default
+ values. The parameters correspond to those in the TDmaTransferArgs
+ struct as follows.
+
+ @param aSrcAddr @see TDmaTransferArgs::iSrcConfig::iAddr
+ @param aDstAddr @see TDmaTransferArgs::iDstConfig::iAddr
+ @param aTransferCount @see TDmaTransferArgs::iTransferCount
+ @param aPslRequestInfo @see TDmaTransferArgs::iPslRequestInfo
+ @param aIsrCb If set to ETrue (the default) then the callback of the
+ rescheduled request will again be called in ISR context
+
+ Since Epoc::LinearToPhysical() cannot be called in ISR context the
+ addresses passed into this function must be physical ones, i.e.
+ TDmaTransferFlags::KDmaPhysAddr is implied.
+
+ If an address refers to a memory target then
+ TDmaTransferFlags::KDmaMemIsContiguous is implied as well as no
+ fragmentation is possible at this point.
+
+ @pre Must only be called from a 'transfer complete' client callback in
+ ISR context.
+
+ @post Framework won't queue the channel DFC for the completed request
+ in success case.
+
+ @see DDmaRequest::DDmaRequest(TDmaChannel&, TDmaCallback, TAny*, TUint)
+ @see TDmaCallbackType::EDmaCallbackRequestCompletion
+ @see TDmaPILFlags::KDmaRequestCallbackFromIsr
+
+ @return KErrGeneral if there was an error, KErrNone otherwise.
+
+ @released
+ */
+ IMPORT_C TInt IsrRedoRequest(TUint32 aSrcAddr=KPhysAddrInvalid,
+ TUint32 aDstAddr=KPhysAddrInvalid,
+ TUint aTransferCount=0,
+ TUint32 aPslRequestInfo=0,
+ TBool aIsrCb=ETrue);
+
+
+ /** Tests whether the channel is currently opened.
+
+ @return ETrue if channel is currently opened, EFalse otherwise.
+
+ NB: This API should not be used any longer.
+
+ After calling TDmaChannel::Open() successfully the channel is
+ guaranteed to be open, hence there seems no good reason for this API to
+ exist.
+
+ @deprecated
+ */
+ inline TBool IsOpened() const;
+
+
+ /** Tests whether the channel's request queue is currently empty.
+
+ @return ETrue if request queue is currently empty, EFalse otherwise.
+
+ @released
+ */
+ inline TBool IsQueueEmpty() const;
+
+
+ /** Returns a PSL-specific value which uniquely identifies this channel -
+ it is used for debug tracing by the PIL.
+
+ @return PSL-specific value which uniquely identifies this channel.
+
+ @released
+ */
+ inline TUint32 PslId() const;
+
+
+ /** Called by a test harness to force an error when the next fragment is
+ transferred.
+
+ @param aFragmentCount The number of consecutive fragments to fail
+
+ @released
+ */
+ IMPORT_C TInt FailNext(TInt aFragmentCount);
+
+
+ /** Called by a test harness to force the DMA controller to miss one or
+ more interrupts.
+
+ @param aInterruptCount The number of consecutive interrupts to miss
+
+ @released
+ */
+ IMPORT_C TInt MissNextInterrupts(TInt aInterruptCount);
+
+
+ /** Function allowing platform-specific layer to extend channel API with
+ new channel-specific operations.
+
+ @param aCmd Command identifier.
+ @param aArg PSL-specific argument
+
+ @return KErrNotSupported if aCmd is not supported. PSL-specific value
+ otherwise.
+
+ @released
+ */
+ IMPORT_C TInt Extension(TInt aCmd, TAny* aArg);
+
+
+ /** This is a function that allows the Platform Specific Layer (PSL) to
+ extend the DMA API with new channel-independent operations.
+
+ @param aCmd Command identifier.
+ @param aArg PSL-specific.
+
+ @return KErrNotSupported if aCmd is not supported; a PSL specific value
+ otherwise.
+
+ @released
+ */
+ IMPORT_C TInt StaticExtension(TInt aCmd, TAny* aArg);
+
+
+ /** @see DmacCaps()
+
+ @deprecated
+ */
+ inline const TDmac* Controller() const;
+
+ /** @see MaxTransferLength()
+
+ @deprecated
+ */
+ inline TInt MaxTransferSize(TUint aFlags, TUint32 aPslInfo);
+
+ /** @see AddressAlignMask()
+
+ @deprecated
+ */
+ inline TUint MemAlignMask(TUint aFlags, TUint32 aPslInfo);
+
+protected:
+ // Interface with state machines
+
+ /** Constructor.
+
+ @released
+ */
+ TDmaChannel();
+
+ /** Called by the PIL when adding a new request to the channel's queue.
+ The implementation should update the channel's state as appropriate
+ and begin transfer of aReq if possible.
+
+ @param aReq The request which has been added to the queue
+
+ @released
+ */
+ virtual void DoQueue(const DDmaRequest& aReq);
+
+ /** Called by the PIL in response to a CancelAll call. It should update
+ the channel state appropriately.
+
+ @released
+ */
+ virtual void DoCancelAll() = 0;
+
+ /** This is called by the PIL when a DDmaRequest is removed from the
+ channel's queue. In general the implementation simply needs to unlink
+ the hardware descriptor corresponding to aHdr from the next.
+
+ Since the PIL links the hardware descriptor chains of adjacent queued
+ requests (for speed) it is necessary to break the chain when a request
+ is completed so that the request may be requeued by the client without
+ having called DDmaRequest::Fragment again.
+
+ @param aHdr The header for a descriptor, which must be unlinked
+ from its next descriptor (if there is one)
+
+ @released
+ */
+ virtual void DoUnlink(SDmaDesHdr& aHdr);
+
+ /** Called by the PIL whenever a transfer associated with aCurReq is
+ done. The implementation must advance the channel's state and
+ may transfer the next header if necessary (the provided
+ scatter-gather channel does not do this). It must also report
+ back which header was associated with the last transfer to
+ complete.
+
+ @param aCurReq The current request.
+ @param aCompletedHdr Must be set by the implementation to the header
+ of the last transfer to complete.
+
+ @released
+ */
+ virtual void DoDfc(const DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
+
+ /** Called by the PIL whenever a transfer associated with aCurReq is
+ done. The implementation must advance the channel's state and
+ may start the transfer for the next headers if necessary (the
+ provided scatter-gather channels do not do this). If one
+ header has a successor but the other is the last in the chain it
+ is an error.
+
+ @note Must be implemented by PSL if channel uses asymmetric hardware
+ descriptors and is not derived from TDmaAsymSgChannel.
+
+ @param aCurReq The current request.
+
+ @param aSrcCompletedHdr Must be set by the implementation to
+ the header of the last source descriptor to complete.
+
+ @param aDstCompletedHdr Must be set by the implementation to
+ the header of the last destination descriptor to complete.
+
+ @prototype
+ */
+ virtual void DoDfc(const DDmaRequest& aCurReq, SDmaDesHdr*& aSrcCompletedHdr,
+ SDmaDesHdr*& aDstCompletedHdr);
+
+ /** This function allows the Platform Specific Layer (PSL) to control the
+ power management of the channel or its controller by overriding the
+ PIL's default implementation (which does nothing) and making
+ appropriate use of the Power Resource Manager (PRM).
+
+ The function gets called by the PIL whenever the channel's queued
+ requests count has changed in a significant way, either before the
+ channel's Transfer() method is invoked for a request on a previously
+ empty request queue, or immediately after the request count has become
+ zero because of request cancellation or completion.
+
+ Depending on the current and previous observed values of
+ iQueuedRequests, the PSL may power down or power up the channel.
+
+ Note that iQueuedRequests gets accessed and changed by different
+ threads, so the PSL needs to take the usual precautions when evaluating
+ the variable's value. Also, due to the multithreaded framework
+ architecture, there is no guarantee that the function calls always
+ arrive at the PSL level in the strict chronological order of
+ iQueuedRequests being incremented/decremented in the PIL, i.e. it might
+ happen that the PSL finds iQueuedRequests to have the same value in two
+ or more consecutive calls (that's why the previous observed value needs
+ to be locally available and taken into account). It is however promised
+ that before any actual transfer commences the PSL will find the request
+ count to be greater than zero and that after the last request has
+ finished it will be found to be zero.
+
+ None of the internal DMA framework mutexes is being held by the PIL
+ when calling this function.
+
+ Here is an example implementation for a derived channel class:
+
+ @code
+
+ class TFooDmaChannel : public TDmaSgChannel
+ {
+ DMutex* iDmaMutex;
+ TInt iPrevQueuedRequests;
+ virtual void QueuedRequestCountChanged();
+ };
+
+ void TFooDmaChannel::QueuedRequestCountChanged()
+ {
+ Kern::MutexWait(*iDmaMutex);
+ const TInt queued_now = __e32_atomic_load_acq32(&iQueuedRequests);
+ if ((queued_now > 0) && (iPrevQueuedRequests == 0))
+ {
+ IncreasePowerCount(); // Base port specific
+ }
+ else if ((queued_now == 0) && (iPrevQueuedRequests > 0))
+ {
+ DecreasePowerCount(); // Base port specific
+ }
+ iPrevQueuedRequests = queued_now;
+ Kern::MutexSignal(*iDmaMutex);
+ }
+
+ @endcode
+
+ @see iQueuedRequests
+ */
+ virtual void QueuedRequestCountChanged();
+
+ virtual void SetNullPtr(const DDmaRequest& aReq);
+ virtual void ResetNullPtr();
+
+ inline virtual ~TDmaChannel() {}
+
+ inline void Wait();
+ inline void Signal();
+ inline TBool Flash();
+
+private:
+ static void Dfc(TAny*);
+ void DoDfc();
+
+protected:
+ TDmac* iController; // DMAC this channel belongs to (NULL when closed)
+ const SDmacCaps* iDmacCaps; // what is supported by DMAC on this channel
+ TUint32 iPslId; // unique identifier provided by PSL
+ TBool iDynChannel; // this is a dynamically allocated channel
+ TUint iPriority; // hardware priority of this channel
+ NFastMutex iLock; // for data accessed in both client & DFC context
+ SDmaDesHdr* iCurHdr; // fragment being transferred or NULL
+ SDmaDesHdr** iNullPtr; // Pointer to NULL pointer following last fragment
+ TDfc iDfc; // transfer completion/failure DFC
+ TInt iMaxDesCount; // maximum number of allocable descriptors
+ TInt iAvailDesCount; // available number of descriptors
+ volatile TUint32 iIsrDfc; // Interface between ISR and DFC:
+ enum {KErrorFlagMask = 0x80000000}; // bit 31 - error flag
+ enum {KCancelFlagMask = 0x40000000}; // bit 30 - cancel flag
+ enum {KDfcCountMask = 0x3FFFFFFF}; // bits 0-29 - number of queued DFCs
+ SDblQue iReqQ; // being/about to be transferred request queue
+ TInt iReqCount; // number of requests attached to this channel
+ TInt iQueuedRequests; // number of requests currently queued on this channel
+ TBool iCallQueuedRequestFn; // call QueuedRequestCountChanged? (default: true)
+
+private:
+ TDmaCancelInfo* iCancelInfo; // ...
+ TBool iRedoRequest; // client ISR callback wants a redo of request
+ TBool iIsrCbRequest; // request on queue using ISR callback
+
+ __DMA_DECLARE_VIRTUAL_INVARIANT
+ };
+
+
+//////////////////////////////////////////////////////////////////////////////
+// INTERFACE WITH TEST HARNESS
+//////////////////////////////////////////////////////////////////////////////
+
+/** Provides access to test information structure stored in the PSL.
+
+ Must be implemented by the PSL (v1).
+
+ @deprecated
+*/
+IMPORT_C const TDmaTestInfo& DmaTestInfo();
+
+
+/** Provides access to test information structure stored in the PSL.
+
+ Must be implemented by the PSL (v2).
+
+ @released
+*/
+IMPORT_C const TDmaV2TestInfo& DmaTestInfoV2();
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+#include <drivers/dma_compat.inl>
+#include <drivers/dma_v2.inl>
+
+
+#endif // #ifndef __DMA_V2_H__