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