1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/include/drivers/dma_v1.h Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,834 @@
1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0""
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// include/drivers/dma_v1.h
1.18 +// DMA Framework API v1
1.19 +//
1.20 +// NB: DMA clients should never include this file directly, but only ever the
1.21 +// generic header file <drivers/dma.h>.
1.22 +//
1.23 +
1.24 +#ifndef __DMA_H__
1.25 +#error "dma_v1.h must'n be included directly - use <drivers/dma.h> instead"
1.26 +#endif // #ifndef __DMA_H__
1.27 +
1.28 +#ifndef __DMA_V1_H__
1.29 +#define __DMA_V1_H__
1.30 +
1.31 +#include <kernel/kern_priv.h>
1.32 +
1.33 +
1.34 +//////////////////////////////////////////////////////////////////////////////
1.35 +// Debug Support - KDmaPanicCat is defined in each source file
1.36 +
1.37 +#define __DMA_ASSERTD(e) __ASSERT_DEBUG(e, Kern::Fault(KDmaPanicCat, __LINE__))
1.38 +#define __DMA_ASSERTA(e) __ASSERT_ALWAYS(e, Kern::Fault(KDmaPanicCat, __LINE__))
1.39 +#ifdef _DEBUG
1.40 +#define __DMA_CANT_HAPPEN() Kern::Fault(KDmaPanicCat, __LINE__)
1.41 +#define __DMA_DECLARE_INVARIANT public: void Invariant();
1.42 +#define __DMA_INVARIANT() Invariant()
1.43 +#else
1.44 +#define __DMA_CANT_HAPPEN()
1.45 +#define __DMA_DECLARE_INVARIANT
1.46 +#define __DMA_INVARIANT()
1.47 +#endif
1.48 +
1.49 +
1.50 +//////////////////////////////////////////////////////////////////////////////
1.51 +// INTERFACE EXPOSED TO DEVICE-DRIVERS
1.52 +//////////////////////////////////////////////////////////////////////////////
1.53 +
1.54 +/**
1.55 +Bitmasks used for configuring a DMA request.
1.56 +
1.57 +In general, specify KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest) if
1.58 +the source (resp. destination) is a memory buffer and clear
1.59 +KDmaMemSrc|KDmaIncSrc (resp. KDmaMemDest|KDmaIncDest) if the source
1.60 +(resp. destination) is a peripheral.
1.61 +
1.62 +If the location is given as a physical address (rather than a linear one)
1.63 +then also specify KDmaPhysAddrSrc and/or KDmaPhysAddrDest.
1.64 +
1.65 +The EKA1 "Fill Mode" can be implemented by omitting KDmaIncSrc.
1.66 +
1.67 +Some peripherals may require a post-increment address mode.
1.68 +
1.69 +@see DDmaRequest::Fragment
1.70 +@publishedPartner
1.71 +@released
1.72 +*/
1.73 +
1.74 +enum TDmaRequestFlags
1.75 + {
1.76 + /** Source is address of memory buffer */
1.77 + KDmaMemSrc = 0x01,
1.78 + /** Destination is address of memory buffer */
1.79 + KDmaMemDest = 0x02,
1.80 + /** Source address must be post-incremented during transfer */
1.81 + KDmaIncSrc = 0x04,
1.82 + /** Destination address must be post-incremented during transfer */
1.83 + KDmaIncDest = 0x08,
1.84 + /** Source address is a physical address (as opposed to a linear one) */
1.85 + KDmaPhysAddrSrc = 0x10,
1.86 + /** Destination address is a physical address (as opposed to a linear one) */
1.87 + KDmaPhysAddrDest = 0x20,
1.88 + /** Request a different max transfer size (for instance for test purposes) */
1.89 + KDmaAltTransferLen = 0x40
1.90 + };
1.91 +
1.92 +
1.93 +//////////////////////////////////////////////////////////////////////////////
1.94 +
1.95 +class TDmaChannel;
1.96 +struct SDmaDesHdr;
1.97 +
1.98 +/** A DMA request is a list of fragments small enough to be transferred in one go
1.99 + by the DMAC.
1.100 +
1.101 + In general, fragmentation is done in the framework by calling Fragment() but
1.102 + clients with special needs can allocate a blank descriptor list with
1.103 + ExpandDesList() and customise it to fit their needs.
1.104 +
1.105 + Clients should not set attributes directly, but should use the various functions
1.106 + instead.
1.107 +
1.108 + This class has not been designed to be called from several concurrent threads.
1.109 + Multithreaded clients must implement their own locking scheme (via DMutex).
1.110 +
1.111 + Fast mutexes are used internally to protect data structures accessed both
1.112 + by the client thread and the DFC thread. Therefore no fast mutex can be held
1.113 + when calling a request function.
1.114 +
1.115 + @publishedPartner
1.116 + @released
1.117 + */
1.118 +class DDmaRequest : public DBase
1.119 + {
1.120 + friend class TDmaChannel;
1.121 +public:
1.122 + /** The outcome of the transfer */
1.123 + enum TResult {EBadResult=0, EOk, EError};
1.124 + /** The signature of the completion/failure callback function */
1.125 + typedef void (*TCallback)(TResult, TAny*);
1.126 +public:
1.127 +
1.128 + /**
1.129 + Create a new transfer request.
1.130 +
1.131 + @param aChannel The channel this request is bound to.
1.132 + @param aCb Callback function called on transfer completion or failure (in channel
1.133 + DFC context). Can be NULL.
1.134 + @param aCbArg Argument passed to callback function.
1.135 + @param aMaxTransferSize Maximum fragment size. If not specified, defaults to the maximum size
1.136 + supported by the DMA controller for the type of transfer that is later scheduled.
1.137 + */
1.138 + IMPORT_C DDmaRequest(TDmaChannel& aChannel, TCallback aCb=NULL, TAny* aCbArg=NULL, TInt aMaxTransferSize=0);
1.139 +
1.140 +
1.141 + /**
1.142 + Destructor.
1.143 +
1.144 + Assume the request is not being transferred or pending.
1.145 + */
1.146 + IMPORT_C ~DDmaRequest();
1.147 +
1.148 +
1.149 + /**
1.150 + Split request into a list of fragments small enough to be fed to the DMAC.
1.151 +
1.152 + The size of each fragment is smaller than or equal to the maximum transfer size
1.153 + supported by the DMAC. If the source and/or destination is memory, each
1.154 + fragment points to memory which is physically contiguous.
1.155 +
1.156 + The kind of transfer to perform is specified via a set of flags used by a PIL
1.157 + and a magic cookie passed to the PSL. If the source (resp. destination) is a
1.158 + peripheral, aSrc (resp. aDest) is treated as a magic cookie by the PIL and
1.159 + passed straight to the PSL.
1.160 +
1.161 + The request can be uninitialised or may have been fragmented previously. The
1.162 + previous configuration if any is lost whether or not the function succeeds.
1.163 +
1.164 + @param aSrc Source memory buffer linear address or peripheral magic cookie.
1.165 + @param aDest Destination memory buffer linear address or peripheral magic cookie.
1.166 + @param aCount Number of bytes to transfer.
1.167 + @param aFlags Bitmask characterising the transfer.
1.168 + @param aPslInfo Hardware-specific information passed to PSL.
1.169 +
1.170 + @return KErrNone if success. KErrArgument if aFlags and/or aPslInfo are invalid when finding
1.171 + the maximum transfer size. May also fail if running out of descriptors.
1.172 +
1.173 + @pre The request is not being transferred or pending.
1.174 + @pre The various parameters must be valid. The PIL or PSL will fault the
1.175 + kernel if not.
1.176 +
1.177 + @see TDmaRequestFlags
1.178 + */
1.179 + IMPORT_C TInt Fragment(TUint32 aSrc, TUint32 aDest, TInt aCount, TUint aFlags, TUint32 aPslInfo);
1.180 +
1.181 +
1.182 + /**
1.183 + Transfer asynchronously this request.
1.184 +
1.185 + If this request's channel is idle, the request is transferred immediately.
1.186 + Otherwise, it is queued and transferred later.
1.187 +
1.188 + The client is responsible for ensuring cache consistency before and/or after the
1.189 + transfer if necessary.
1.190 + */
1.191 + IMPORT_C void Queue();
1.192 +
1.193 +
1.194 + /**
1.195 + Append new descriptor(s) to existing list.
1.196 +
1.197 + Clients needing to build a custom descriptor list should call this function to
1.198 + allocate the list and access the resulting list through iFirstHdr and iLastHdr.
1.199 +
1.200 + Clients should not change the value of iFirstHdr, iLastHdr and the iNext field
1.201 + of the descriptor headers to ensure descriptors can be deallocated. Clients
1.202 + are free to change hardware descriptors, including chaining, in whatever way
1.203 + suit them.
1.204 +
1.205 + Assume the request is not being transferred or pending.
1.206 +
1.207 + @param aCount Number of descriptors to append.
1.208 +
1.209 + @return KErrNone or KErrTooBig if not enough descriptors available.
1.210 + */
1.211 + IMPORT_C TInt ExpandDesList(TInt aCount=1);
1.212 +
1.213 +
1.214 + /**
1.215 + Free resources associated with this request.
1.216 +
1.217 + Assume the request is not being transferred or pending.
1.218 + */
1.219 + IMPORT_C void FreeDesList();
1.220 +private:
1.221 + inline void OnDeque();
1.222 +public:
1.223 + // WARNING: The following attributes are accessed both in client and DFC
1.224 + // context and so accesses must be protected with the channel lock.
1.225 + TDmaChannel& iChannel; /**< The channel this request is bound to */
1.226 + volatile TCallback iCb; /**< Called on completion/failure (can be NULL) */
1.227 + TAny* volatile iCbArg; /**< Callback argument */
1.228 + TInt iDesCount; /**< The number of fragments in list */
1.229 + SDmaDesHdr* iFirstHdr; /**< The first fragment in the list (or NULL) */
1.230 + SDmaDesHdr* iLastHdr; /**< The last fragment in the list (or NULL) */
1.231 + SDblQueLink iLink; /**< The link on channel queue of pending requests */
1.232 + TBool iQueued; /**< Indicates whether request is pending or being transferred */
1.233 + TInt iMaxTransferSize; /**< Defaults to DMA controller max. transfer size */
1.234 + __DMA_DECLARE_INVARIANT
1.235 + };
1.236 +
1.237 +
1.238 +//////////////////////////////////////////////////////////////////////////////
1.239 +
1.240 +class TDmac;
1.241 +class DmaChannelMgr;
1.242 +
1.243 +/** DMA channel base class.
1.244 +
1.245 + This class has not been designed to be called from several concurrent
1.246 + client threads. Multithreaded clients must implement their own locking
1.247 + scheme (via DMutex).
1.248 +
1.249 + Fast mutexes are used internally to protect data structures accessed both
1.250 + by the client thread and the DFC one. Therefore no fast mutex can be held
1.251 + when calling a channel function.
1.252 +
1.253 + Must be allocated in BSS because it relies on being zeroed at
1.254 + creation-time. If the PSL really needs to allocate channels on the kernel
1.255 + heap, it must manually zero-initialises the instances. This can be
1.256 + achieved either by allocating raw memory and using placement new, or by
1.257 + wrapping channels into a DBase-derived wrapper.
1.258 +
1.259 + @publishedPartner
1.260 + @released
1.261 + */
1.262 +class TDmaCancelInfo;
1.263 +class TDmaChannel
1.264 + {
1.265 + friend class DDmaRequest;
1.266 + friend class TDmac;
1.267 + friend class DmaChannelMgr;
1.268 +public:
1.269 + /** Information passed by client when opening channel */
1.270 + struct SCreateInfo
1.271 + {
1.272 + /** Identifier used by PSL to select channel to open */
1.273 + TUint32 iCookie;
1.274 + /** Number of descriptors this channel can use */
1.275 + TInt iDesCount;
1.276 + /** DFC queue used to service DMA interrupts. The DFC thread
1.277 + priority must be higher than any client thread priority to
1.278 + avoid a situation where a transfer completes while being
1.279 + cancelled and another transfer is started before the DFC
1.280 + thread gets a chance to run. This would lead to a stray
1.281 + DFC.
1.282 + */
1.283 + TDfcQue* iDfcQ;
1.284 + /** DFC priority */
1.285 + TUint8 iDfcPriority;
1.286 + };
1.287 +public:
1.288 + /**
1.289 + Opens the DMA channel.
1.290 +
1.291 + Channel selection is done by the hardware-specific layer using a cookie passed in
1.292 + via aInfo.
1.293 +
1.294 + The client should not delete the returned pointer as the framework owns
1.295 + channel objects. However, the client should explicitly close the channel when
1.296 + finished with it.
1.297 +
1.298 + @param aInfo Information passed by caller to select and configure channel.
1.299 + @param aChannel Point to open channel on successful return. NULL otherwise.
1.300 +
1.301 + @return KErrNone or standard error code.
1.302 + */
1.303 + IMPORT_C static TInt Open(const SCreateInfo& aInfo, TDmaChannel*& aChannel);
1.304 +
1.305 +
1.306 + /**
1.307 + Closes a previously opened DMA channel.
1.308 +
1.309 + Assume the channel is idle and all requests have been deleted.
1.310 + */
1.311 + IMPORT_C void Close();
1.312 +
1.313 +
1.314 + /**
1.315 + Cancels the current request and all the pending ones.
1.316 + */
1.317 + IMPORT_C void CancelAll();
1.318 + inline TBool IsOpened() const;
1.319 + inline TBool IsQueueEmpty() const;
1.320 + inline TUint32 PslId() const;
1.321 + inline TInt FailNext(TInt aFragmentCount);
1.322 + inline TInt MissNextInterrupts(TInt aInterruptCount);
1.323 + inline TInt Extension(TInt aCmd, TAny* aArg);
1.324 +
1.325 + /**
1.326 + This is a function that allows the Platform Specific Layer (PSL) to extend the DMA API
1.327 + with new channel-independent operations.
1.328 +
1.329 + @param aCmd Command identifier. Negative values are reserved for Symbian use.
1.330 + @param aArg PSL-specific.
1.331 +
1.332 + @return KErrNotSupported if aCmd is not supported; a PSL specific value otherwise.
1.333 + */
1.334 + IMPORT_C TInt StaticExtension(TInt aCmd, TAny* aArg);
1.335 + inline const TDmac* Controller() const;
1.336 + inline TInt MaxTransferSize(TUint aFlags, TUint32 aPslInfo);
1.337 + inline TUint MemAlignMask(TUint aFlags, TUint32 aPslInfo);
1.338 +protected:
1.339 + // Interface with state machines
1.340 + TDmaChannel();
1.341 + virtual void DoQueue(DDmaRequest& aReq) = 0;
1.342 + virtual void DoCancelAll() = 0;
1.343 + virtual void DoUnlink(SDmaDesHdr& aHdr);
1.344 + virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr) = 0;
1.345 + /**
1.346 + This function allows the Platform Specific Layer (PSL) to control the
1.347 + power management of the channel or its controller by overriding the
1.348 + PIL's default implementation (which does nothing) and making appropriate
1.349 + use of the Power Resource Manager (PRM).
1.350 +
1.351 + The function gets called by the PIL whenever the channel's queued
1.352 + requests count has changed in a significant way, either before the
1.353 + channel's Transfer() method is invoked for a request on a previously
1.354 + empty request queue, or immediately after the request count has become
1.355 + zero because of request cancellation or completion.
1.356 +
1.357 + Depending on the current value of iQueuedRequests, the PSL may power
1.358 + down or power up the channel. Note that iQueuedRequests gets accessed
1.359 + and changed by different threads, so the PSL needs to take the usual
1.360 + precautions when evaluating the variable's value.
1.361 +
1.362 + None of the internal DMA framework mutexes is being held by the PIL when
1.363 + calling this function.
1.364 +
1.365 + @see iQueuedRequests
1.366 + */
1.367 + virtual void QueuedRequestCountChanged();
1.368 +#if defined(__CPU_ARM) && !defined(__EABI__)
1.369 + inline virtual ~TDmaChannel() {} // kill really annoying warning
1.370 +#endif
1.371 +private:
1.372 + static void Dfc(TAny*);
1.373 + void DoDfc();
1.374 + inline void Wait();
1.375 + inline void Signal();
1.376 + inline TBool Flash();
1.377 + void ResetStateMachine();
1.378 +protected:
1.379 + TDmac* iController; // DMAC this channel belongs to (NULL when closed)
1.380 + TUint32 iPslId; // unique identifier provided by PSL
1.381 + NFastMutex iLock; // for data accessed in both client & DFC context
1.382 + SDmaDesHdr* iCurHdr; // fragment being transferred or NULL
1.383 + SDmaDesHdr** iNullPtr; // Pointer to NULL pointer following last fragment
1.384 + TDfc iDfc; // transfer completion/failure DFC
1.385 + TInt iMaxDesCount; // maximum number of allocable descriptors
1.386 + TInt iAvailDesCount; // available number of descriptors
1.387 + volatile TUint32 iIsrDfc; // Interface between ISR and DFC:
1.388 + enum { KErrorFlagMask = 0x80000000 }; // bit 31 - error flag
1.389 + enum { KCancelFlagMask = 0x40000000 }; // bit 30 - cancel flag
1.390 + enum { KDfcCountMask = 0x3FFFFFFF }; // bits 0-29 - number of queued DFCs
1.391 + SDblQue iReqQ; // being/about to be transferred request queue
1.392 + TInt iReqCount; // number of requests attached to this channel
1.393 + TInt iQueuedRequests; // number of requests currently queued on this channel
1.394 +private:
1.395 + TDmaCancelInfo* iCancelInfo;
1.396 + __DMA_DECLARE_INVARIANT
1.397 + };
1.398 +
1.399 +
1.400 +//////////////////////////////////////////////////////////////////////////////
1.401 +// PIL-PSL INTERFACE
1.402 +//////////////////////////////////////////////////////////////////////////////
1.403 +
1.404 +/**
1.405 +Generic DMA descriptor used if the DMAC does not have support for hardware
1.406 +descriptor.
1.407 +@see DDmaRequest::Fragment
1.408 +@publishedPartner
1.409 +@released
1.410 +*/
1.411 +
1.412 +struct SDmaPseudoDes
1.413 + {
1.414 + /** Source linear address or peripheral cookie */
1.415 + TUint32 iSrc;
1.416 + /** Destination linear address or peripheral cookie */
1.417 + TUint32 iDest;
1.418 + /** Number of bytes to transfer */
1.419 + TInt iCount;
1.420 + /** @see TDmaRequestFlags */
1.421 + TUint iFlags;
1.422 + /** PSL-specific information provided by client */
1.423 + TUint32 iPslInfo;
1.424 + /** The same as TDmaChannel::SCreateInfo.iCookie */
1.425 + TUint32 iCookie;
1.426 + };
1.427 +
1.428 +
1.429 +/**
1.430 +Each hardware or pseudo descriptor is associated with a header. Headers are
1.431 +needed because hardware descriptors can not easily be extended to store
1.432 +additional information.
1.433 +@publishedPartner
1.434 +@released
1.435 +*/
1.436 +
1.437 +struct SDmaDesHdr
1.438 + {
1.439 + SDmaDesHdr* iNext;
1.440 + };
1.441 +
1.442 +
1.443 +/**
1.444 +Interface used by PIL to open and close DMA channels.
1.445 +
1.446 +Must be implemented by PSL.
1.447 +@publishedPartner
1.448 +@released
1.449 +*/
1.450 +
1.451 +class DmaChannelMgr
1.452 + {
1.453 +public:
1.454 + /** Opens a channel using a client-provided identifier.
1.455 + This function must be implemented by the PSL.
1.456 + @param aOpenId Magic cookie passed by client
1.457 + This may identify the channel (if a static channel
1.458 + allocation scheme is used) or may indicate some
1.459 + properties which the channel must possess (if a dynamic
1.460 + channel allocation scheme is used). It may be set to
1.461 + zero always if dynamic allocation is used and all
1.462 + channels are equivalent.
1.463 + @return Pointer to channel if available, NULL otherwise.
1.464 + @pre The PIL calls this function with a global fast mutex held to
1.465 + avoid race conditions.
1.466 + @post If a non-NULL pointer is returned, the object pointed to has its
1.467 + iController and iPslId members set to valid states.
1.468 + iController should point to the controller handling that channel.
1.469 + iPslId should contain a value uniquely identifying the channel -
1.470 + it is used only for debug tracing by PIL. It can be given any
1.471 + convenient value by PSL (channel index, I/O port address, ...).
1.472 + */
1.473 + static TDmaChannel* Open(TUint32 aOpenId);
1.474 +
1.475 + /** Performs platform-specific operations when a channel is closed.
1.476 + This function must be implemented by the PSL but the implementation can be
1.477 + a no-op.
1.478 + @param aChannel The channel to close
1.479 + @pre The PIL calls this function with a global fast mutex held to
1.480 + avoid race conditions.
1.481 + */
1.482 + static void Close(TDmaChannel* aChannel);
1.483 +
1.484 + /** Function allowing PSL to extend DMA API with new channel-independent operations.
1.485 + This function must be implemented by the PSL.
1.486 + @param aCmd Command identifier. Negative values are reserved for Symbian use.
1.487 + @param aArg PSL-specific
1.488 + @return KErrNotSupported if aCmd is not supported. PSL-specific value otherwise.
1.489 + */
1.490 + static TInt StaticExtension(TInt aCmd, TAny* aArg);
1.491 +
1.492 + static inline void Wait();
1.493 + static inline void Signal();
1.494 +private:
1.495 + static NFastMutex Lock;
1.496 + };
1.497 +
1.498 +
1.499 +//////////////////////////////////////////////////////////////////////////////
1.500 +
1.501 +/**
1.502 + Abstract base class representing a DMA controller.
1.503 +
1.504 + The class has two purposes.
1.505 +
1.506 + First, it is a container for channels, descriptors and descriptor headers.
1.507 +
1.508 + Second, it exposes a set of virtual functions implemented by
1.509 + the PSL (platform-specific layer).
1.510 + These functions are the main interfaces between
1.511 + the PIL (platform-independent layer) and PSL.
1.512 +
1.513 + Must be allocated in BSS because it relies on being zeroed at creation-time.
1.514 +
1.515 + @publishedPartner
1.516 + @released
1.517 + */
1.518 +
1.519 +class TDmac
1.520 + {
1.521 + friend class DmaChannelMgr;
1.522 +// protected: VC++ complains when building PSL if following decl is protected
1.523 +public:
1.524 + /** Data required for creating a new instance */
1.525 + struct SCreateInfo
1.526 + {
1.527 + /** Number of channels in controller */
1.528 + TInt iChannelCount;
1.529 + /** Maximum number of descriptors (shared by all channels) */
1.530 + TInt iDesCount;
1.531 + /** Bitmask. The only supported value is KCapsBitHwDes (hardware
1.532 + descriptors used). */
1.533 + TUint32 iCaps;
1.534 + /** Size of individual descriptors. Use sizeof(SDmaPseudoDes) for
1.535 + single-buffer and double-buffer controllers. */
1.536 + TInt iDesSize;
1.537 + /** Bitmask used when creating the hardware chunk storing the descriptor
1.538 + pool. Used only for hardware descriptors. The access part must be
1.539 + EMapAttrSupRw. If the chunk is cached and/or buffered, the PSL must
1.540 + flush the data cache and/or drain the write buffer in InitHwDes()
1.541 + and related functions.
1.542 + @see TMappingAttributes
1.543 + */
1.544 + TUint iDesChunkAttribs;
1.545 + };
1.546 +public:
1.547 + TInt Create(const SCreateInfo& aInfo);
1.548 + virtual ~TDmac();
1.549 + TInt ReserveSetOfDes(TInt aCount);
1.550 + void ReleaseSetOfDes(TInt aCount);
1.551 + void InitDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
1.552 + TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
1.553 + inline SDmaPseudoDes& HdrToDes(const SDmaDesHdr& aHdr) const;
1.554 + inline TAny* HdrToHwDes(const SDmaDesHdr& aHdr) const;
1.555 + inline TUint32 DesLinToPhys(TAny* aDes) const;
1.556 + inline void Wait();
1.557 + inline void Signal();
1.558 +protected:
1.559 + TDmac(const SCreateInfo& aInfo);
1.560 +
1.561 +public:
1.562 + /**
1.563 + Called by PIL when one fragment (single-buffer and double-buffer DMACs) or
1.564 + list of fragments (scatter/gather DMAC) is to be transferred.
1.565 +
1.566 + Called when initiating a new transfer and also, for double-buffer DMACs, for
1.567 + configuring the next fragment to transfer while the current one is
1.568 + ongoing. Must always be implemented by PSL.
1.569 + @param aChannel The channel to use
1.570 + @param aHdr Header associated with fragment to transfer
1.571 + */
1.572 + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) = 0;
1.573 +
1.574 + /**
1.575 + Called by PIL to suspend transfer on a given channel.
1.576 +
1.577 + The suspension must occur synchronously as the PSL assumes the channel
1.578 + is suspended after calling this function. Must always be implemented by PSL.
1.579 + @param aChannel The channel to suspend
1.580 + */
1.581 + virtual void StopTransfer(const TDmaChannel& aChannel) = 0;
1.582 +
1.583 + /**
1.584 + Called by PIL to check whether a DMA channel is idle.
1.585 + @param aChannel The channel to test
1.586 + @return ETrue if channel idle, EFalse if transferring.
1.587 + */
1.588 + virtual TBool IsIdle(const TDmaChannel& aChannel) = 0;
1.589 +
1.590 + /**
1.591 + Called by PIL to retrieve from the PSL the maximum transfer size based on the
1.592 + parameters passed.
1.593 + @param aChannel Channel to be used for the transfer
1.594 + @param aFlags Bitmask characterising transfer
1.595 + @param aPslInfo Cookie passed by client and used by PSL
1.596 + @return 0 if invalid argument(s), -1 if transfer size not limited, the maximum
1.597 + transfer size otherwise.
1.598 + */
1.599 + virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0;
1.600 +
1.601 + /**
1.602 + Called by PIL to retrieve from the PSL the memory alignment mask based on the
1.603 + parameters passed. Some DMA controllers impose alignment constraints on the base
1.604 + address of memory buffers. This mask is AND'ed against memory addresses computed
1.605 + during fragmentation.
1.606 + @param aChannel Channel to be used for the transfer
1.607 + @param aFlags Bitmask characterising transfer
1.608 + @param aPslInfo Cookie passed by client and used by PSL
1.609 + @return A value representing the alignment mask (e.g. 3 if buffer must be 4-byte aligned)
1.610 + */
1.611 + virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo) = 0;
1.612 +
1.613 + /**
1.614 + Called by PIL during fragmentation to initialise a hardware descriptor.
1.615 +
1.616 + The PSL must assume the descriptor is the last in the chain and so set the
1.617 + interrupt bit and set the next descriptor field to an end of chain marker.
1.618 + Must be implemented by PSL if and only if the DMAC supports hardware
1.619 + descriptors.
1.620 + @param aHdr Header associated with hardware descriptor to initialise
1.621 + @param aSrc Transfer source
1.622 + @param aDest Transfer destination
1.623 + @param aCount Number of bytes to transfer (<= max. size supported by DMAC)
1.624 + @param aFlags Bitmask characterising transfer
1.625 + @param aPslInfo Cookie passed by client and used by PSL
1.626 + @param aCookie the channel selection cookie
1.627 + @see DDmaRequest::Fragment
1.628 + */
1.629 + virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
1.630 + TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
1.631 +
1.632 + /**
1.633 + Called by PIL, when fragmenting a request, to append a new hardware
1.634 + descriptor to an existing descriptor chain.
1.635 +
1.636 + Must clear the interrupt bit of the descriptor associated with aHdr.
1.637 + Must be implemented by PSL if and only if the DMAC supports hardware descriptors.
1.638 + @param aHdr Header associated with last fragment in chain
1.639 + @param aNextHdr Header associated with fragment to append
1.640 + */
1.641 + virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
1.642 +
1.643 + /**
1.644 + Called by PIL when queuing a new request while the channel is running.
1.645 +
1.646 + Must append the first hardware descriptor of the new request to the last
1.647 + descriptor in the existing chain. Must be implemented by PSL if and only if
1.648 + the DMAC supports hardware descriptors.
1.649 + @param aChannel The channel where the transfer takes place
1.650 + @param aLastHdr Header associated with last hardware descriptor in chain
1.651 + @param aNewHdr Header associated with first hardware descriptor in new request
1.652 + */
1.653 + virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
1.654 + const SDmaDesHdr& aNewHdr);
1.655 +
1.656 + /**
1.657 + Called by PIL when completing or cancelling a request to cause the PSL to unlink
1.658 + the last item in the h/w descriptor chain from a subsequent chain that it was
1.659 + possibly linked to. Must be implemented by the PSL if and only if the DMAC supports
1.660 + hardware descriptors.
1.661 +
1.662 + @param aChannel The channel where the request (and thus the descriptor) was queued
1.663 + @param aHdr Header associated with last h/w descriptor in completed/cancelled chain
1.664 + */
1.665 + virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
1.666 +
1.667 + /**
1.668 + Called by test harness to force an error when the next fragment is
1.669 + transferred.
1.670 +
1.671 + Must be implemented by the PSL only if possible.
1.672 + @param aChannel The channel where the error is to occur.
1.673 + @return KErrNone if implemented. The default PIL implementation returns
1.674 + KErrNotSupported and the test harness knows how to deal with that.
1.675 + */
1.676 + virtual TInt FailNext(const TDmaChannel& aChannel);
1.677 +
1.678 + /**
1.679 + Called by test harness to force the DMA controller to miss one or
1.680 + more interrupts.
1.681 +
1.682 + Must be implemented by the PSL only if possible.
1.683 + @param aChannel The channel where the error is to occur
1.684 + @param aInterruptCount The number of interrupt to miss.
1.685 + @return KErrNone if implemented. The default PIL implementation returns
1.686 + KErrNotSupported and the test harness knows how to deal with that.
1.687 + */
1.688 + virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
1.689 +
1.690 + /** Function allowing platform-specific layer to extend channel API with
1.691 + new channel-specific operations.
1.692 + @param aChannel Channel to operate on
1.693 + @param aCmd Command identifier. Negative values are reserved for Symbian use.
1.694 + @param aArg PSL-specific
1.695 + @return KErrNotSupported if aCmd is not supported. PSL-specific value otherwise.
1.696 + @see TDmaChannel::Extension
1.697 + */
1.698 + virtual TInt Extension(TDmaChannel& aChannel, TInt aCmd, TAny* aArg);
1.699 +
1.700 +protected:
1.701 + static void HandleIsr(TDmaChannel& aChannel, TBool aIsComplete);
1.702 +private:
1.703 + TInt AllocDesPool(TUint aAttribs);
1.704 + void FreeDesPool();
1.705 +private:
1.706 + NFastMutex iLock; // protect descriptor reservation and allocation
1.707 + const TInt iMaxDesCount; // initial number of descriptors and headers
1.708 + TInt iAvailDesCount; // current available number of descriptors and headers
1.709 + SDmaDesHdr* iHdrPool; // descriptor header dynamic array
1.710 +#ifndef __WINS__
1.711 + DPlatChunkHw* iHwDesChunk; // chunk for hardware descriptor pool
1.712 +#endif
1.713 + TAny* iDesPool; // hardware or pseudo descriptor dynamic array
1.714 + const TInt iDesSize; // descriptor size in bytes
1.715 +public:
1.716 + const TUint iCaps; /*< what is supported by DMA controller */
1.717 + enum {KCapsBitHwDes = 1}; /*< hardware descriptors supported */
1.718 + SDmaDesHdr* iFreeHdr; /*< head of unallocated descriptors linked list */
1.719 +#ifdef _DEBUG
1.720 + TBool IsValidHdr(const SDmaDesHdr* aHdr);
1.721 +#endif
1.722 + __DMA_DECLARE_INVARIANT
1.723 + };
1.724 +
1.725 +
1.726 +//////////////////////////////////////////////////////////////////////////////
1.727 +
1.728 +/**
1.729 +Single-buffer DMA channel.
1.730 +
1.731 +Can be instantiated or further derived by PSL. Not
1.732 +intended to be instantiated by client device drivers.
1.733 +@publishedPartner
1.734 +@released
1.735 +*/
1.736 +
1.737 +class TDmaSbChannel : public TDmaChannel
1.738 + {
1.739 +private:
1.740 + virtual void DoQueue(DDmaRequest& aReq);
1.741 + virtual void DoCancelAll();
1.742 + virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
1.743 +private:
1.744 + TBool iTransferring;
1.745 + };
1.746 +
1.747 +
1.748 +/**
1.749 +Double-buffer DMA channel.
1.750 +
1.751 +Can be instantiated or further derived by PSL. Not
1.752 +intended to be instantiated by client device drivers.
1.753 +@publishedPartner
1.754 +@released
1.755 +*/
1.756 +
1.757 +class TDmaDbChannel : public TDmaChannel
1.758 + {
1.759 +private:
1.760 + virtual void DoQueue(DDmaRequest& aReq);
1.761 + virtual void DoCancelAll();
1.762 + virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
1.763 +private:
1.764 + enum { EIdle = 0, ETransferring, ETransferringLast } iState;
1.765 + };
1.766 +
1.767 +
1.768 +/**
1.769 +Scatter-gather DMA channel.
1.770 +
1.771 +Can be instantiated or further derived by PSL.
1.772 +Not intended to be instantiated by client device drivers.
1.773 +@publishedPartner
1.774 +@released
1.775 +*/
1.776 +
1.777 +class TDmaSgChannel : public TDmaChannel
1.778 + {
1.779 +private:
1.780 + virtual void DoQueue(DDmaRequest& aReq);
1.781 + virtual void DoCancelAll();
1.782 + virtual void DoUnlink(SDmaDesHdr& aHdr);
1.783 + virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr);
1.784 +private:
1.785 + TBool iTransferring;
1.786 + };
1.787 +
1.788 +
1.789 +//////////////////////////////////////////////////////////////////////////////
1.790 +// INTERFACE WITH TEST HARNESS
1.791 +//////////////////////////////////////////////////////////////////////////////
1.792 +
1.793 +/**
1.794 +Set of information used by test harness.
1.795 +@publishedPartner
1.796 +@released
1.797 +*/
1.798 +
1.799 +struct TDmaTestInfo
1.800 + {
1.801 + /** Maximum transfer size in bytes for all channels (ie. the minimum of all channels' maximum size)*/
1.802 + TInt iMaxTransferSize;
1.803 + /** 3->Memory buffers must be 4-byte aligned, 7->8-byte aligned, ... */
1.804 + TUint iMemAlignMask;
1.805 + /** Cookie to pass to DDmaRequest::Fragment for memory-memory transfer*/
1.806 + TUint32 iMemMemPslInfo;
1.807 + /** Number of test single-buffer channels */
1.808 + TInt iMaxSbChannels;
1.809 + /** Pointer to array containing single-buffer test channel ids */
1.810 + TUint32* iSbChannels;
1.811 + /** Number of test double-buffer channels */
1.812 + TInt iMaxDbChannels;
1.813 + /** Pointer to array containing double-buffer test channel ids */
1.814 + TUint32* iDbChannels;
1.815 + /** Number of test scatter-gather channels */
1.816 + TInt iMaxSgChannels;
1.817 + /** Pointer to array containing scatter-gather test channel ids */
1.818 + TUint32* iSgChannels;
1.819 + };
1.820 +
1.821 +
1.822 +/**
1.823 +Provides access to test information structure stored in the PSL.
1.824 +
1.825 +Must be implemented by the PSL.
1.826 +@publishedPartner
1.827 +@released
1.828 +*/
1.829 +
1.830 +IMPORT_C const TDmaTestInfo& DmaTestInfo();
1.831 +
1.832 +
1.833 +//////////////////////////////////////////////////////////////////////////////
1.834 +
1.835 +#include <drivers/dma_v1.inl>
1.836 +
1.837 +#endif