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