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