diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/kernel/eka/include/drivers/dma_v2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/kernel/eka/include/drivers/dma_v2.h Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1135 @@ +// 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_v2.h +// DMA Framework - Client API v2 definition. +// +// NB: DMA clients should never include this file directly, but only ever the +// generic header file . +// + +#ifndef __DMA_H__ +#error "dma_v2.h must'n be included directly - use instead" +#endif // #ifndef __DMA_H__ + +#ifndef __DMA_V2_H__ +#define __DMA_V2_H__ + + +#include +#include + + +////////////////////////////////////////////////////////////////////////////// +// 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_INVARIANT() Invariant() +#else +#define __DMA_CANT_HAPPEN() +#define __DMA_DECLARE_INVARIANT +#define __DMA_INVARIANT() +#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 + @publishedPartner + @released +*/ +enum TDmaRequestFlags + { + // Note: This enum is only required for backwards compatibility with the + // old DMA framework, it can be removed once this is no longer needed. + + /** 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. + + @publishedPartner + @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. + */ +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. + + @publishedPartner + @released + */ +class DDmaRequest : public DBase + { + friend class TDmaChannel; + +public: + /** The outcome of the transfer + + @deprecated + @see TDmaResult + */ + enum TResult {EBadResult=0, EOk, EError}; + /** The signature of the completion/failure callback function + + @deprecated + @see TDmaCallback + */ + 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. + */ + IMPORT_C DDmaRequest(TDmaChannel& aChannel, TDmaCallback aDmaCb, TAny* aCbArg=NULL, + TUint aMaxTransferSize=0); + + + /** Destructor. + + Assume the request is not being transferred or pending. + */ + 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. + + @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. + */ + 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. + */ + 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. + */ + 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 can only be used if SDmacCaps::iAsymHwDescriptors is + true, otherwise it will just return KErrGeneral. + + @param aCount Number of descriptors to append. + + @return KErrNone or standard error code. + */ + 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 can only be used if SDmacCaps::iAsymHwDescriptors is + true, otherwise it will just return KErrGeneral. + + @param aCount Number of descriptors to append. + + @return KErrNone or standard error code. + */ + IMPORT_C TInt ExpandDstDesList(TInt aCount=1); + + + /** Free resources associated with this request. + + Assume the request is not being transferred or pending. + */ + IMPORT_C void FreeDesList(); + + + /** Free resources associated with this request. This function variant + operates on the source port descriptor chain. + + @see FreeDesList + + This function can only be used if SDmacCaps::iAsymHwDescriptors is + true, otherwise it will do nothing. + */ + IMPORT_C void FreeSrcDesList(); + + + /** Free resources associated with this request. This function variant + operates on the destination port descriptor chain. + + @see FreeDesList + + This function can only be used if SDmacCaps::iAsymHwDescriptors is + true, otherwise it will do nothing. + */ + 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() + */ + 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() + */ + 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() + */ + 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() + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + IMPORT_C TInt DstFragmentCount(); + +private: + inline void OnDeque(); + TUint GetTransferCount(const TDmaTransferArgs& aTransferArgs); + 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 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 + // context and 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. + + @publishedPartner + @released + */ +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. + */ + SCreateInfo() : iPriority(KDmaPriorityNone), iDynChannel(EFalse) {}; + + /** Identifier used by PSL to select channel to open */ + TUint32 iCookie; + /** Number of descriptors this channel can use. + + This number is not used in the upgraded version of the DMA + framework and is kept there only for source compatibility. If the + client is certain that it will only ever use that version, then the + value passed here doesn't matter - the framework will ignore it. + + @deprecated + */ + TInt iDesCount; + /** DFC queue used to service DMA interrupts. + + The DFC thread priority must be higher than any client thread + priority to avoid a situation where a transfer completes while + being cancelled and another transfer is started before the DFC + thread gets a chance to run. This would lead to a stray DFC. + */ + TDfcQue* iDfcQ; + /** DFC priority */ + TUint8 iDfcPriority; + /** Used by PSL to configure a channel priority (if possible). + + The default is KDmaPriorityNone (the don't care value). + + @see TDmaPriority + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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 + + @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. + */ + IMPORT_C TInt Resume(); + + + /** Cancels the current request and all the pending ones. + */ + 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. + */ + 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) + */ + 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. + */ + 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. + */ + 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. Therefore 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. + */ + 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. + */ + 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 + */ + 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 + */ + IMPORT_C TInt MissNextInterrupts(TInt aInterruptCount); + + + /** Function allowing platform-specific layer to extend channel API with + new channel-specific operations. + + @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. + */ + 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. Negative values are reserved for + Symbian use. + @param aArg PSL-specific. + + @return KErrNotSupported if aCmd is not supported; a PSL specific value + otherwise. + */ + IMPORT_C TInt StaticExtension(TInt aCmd, TAny* aArg); + + + /** @deprecated + @see DmacCaps() + */ + inline const TDmac* Controller() const; + + /** @deprecated + @see MaxTransferLength() + */ + inline TInt MaxTransferSize(TUint aFlags, TUint32 aPslInfo); + + /** @deprecated + @see AddressAlignMask() + */ + inline TUint MemAlignMask(TUint aFlags, TUint32 aPslInfo); + +protected: + // Interface with state machines + 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 + */ + virtual void DoQueue(const DDmaRequest& aReq); + + /** Called by the PIL in response to a CancelAll call. It should update + the channel state appropriately. + */ + 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) + */ + 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. + */ + 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. + */ + virtual void DoDfc(const DDmaRequest& aCurReq, SDmaDesHdr*& aSrcCompletedHdr, + SDmaDesHdr*& aDstCompletedHdr); + + virtual ~TDmaChannel(); + +private: + static void Dfc(TAny*); + void DoDfc(); + inline void Wait(); + inline void Signal(); + inline void Flash(); + void ResetStateMachine(); + +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 + DMutex* iMutex; // 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 +private: + TDmaCancelInfo* iCancelInfo; // ... + TBool iRedoRequest; // client ISR callback wants a redo of request + TBool iIsrCbRequest; // request on queue using ISR callback + + __DMA_DECLARE_INVARIANT + }; + + +////////////////////////////////////////////////////////////////////////////// +// INTERFACE WITH TEST HARNESS +////////////////////////////////////////////////////////////////////////////// + +/** Set of information used by test harness. + + @publishedPartner + @released +*/ +struct TDmaTestInfo + { + /** Maximum transfer size in bytes for all channels (ie. the minimum of all channels' maximum size)*/ + TUint iMaxTransferSize; + /** 3->Memory buffers must be 4-byte aligned, 7->8-byte aligned, ... */ + TUint iMemAlignMask; + /** Cookie to pass to DDmaRequest::Fragment for memory-memory transfer*/ + TUint32 iMemMemPslInfo; + /** Number of test single-buffer channels */ + TInt iMaxSbChannels; + /** Pointer to array containing single-buffer test channel ids */ + TUint32* iSbChannels; + /** Number of test double-buffer channels */ + TInt iMaxDbChannels; + /** Pointer to array containing double-buffer test channel ids */ + TUint32* iDbChannels; + /** Number of test scatter-gather channels */ + TInt iMaxSgChannels; + /** Pointer to array containing scatter-gather test channel ids */ + TUint32* iSgChannels; + }; + + +/** Provides access to test information structure stored in the PSL. + + Must be implemented by the PSL. + + @publishedPartner + @released +*/ +IMPORT_C const TDmaTestInfo& DmaTestInfo(); + +/** Provides access to test information structure stored in the PSL. + + Must be implemented by the PSL. + + @publishedPartner + @released +*/ +IMPORT_C const TDmaV2TestInfo& DmaTestInfoV2(); + + + +////////////////////////////////////////////////////////////////////////////// + + +#include +#include + + +#endif // #ifndef __DMA_V2_H__