--- a/Symbian3/PDK/Source/GUID-A4C19890-2380-5498-A5F8-3B6D95CEFEF4.dita Thu Mar 11 15:24:26 2010 +0000
+++ b/Symbian3/PDK/Source/GUID-A4C19890-2380-5498-A5F8-3B6D95CEFEF4.dita Thu Mar 11 18:02:22 2010 +0000
@@ -1,428 +1,428 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
-<!-- This component and the accompanying materials are made available under the terms of the License
-"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:
--->
-<!DOCTYPE concept
- PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
-<concept id="GUID-A4C19890-2380-5498-A5F8-3B6D95CEFEF4" xml:lang="en"><title>PSL
-Implementation</title><shortdesc>Describes how to create the PSL implementation.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
-<p>To create a port of the DMA Framework, you must create an implementation
-of the PSL for the DMA controller hardware.</p>
-<section id="GUID-8664FA8F-E53A-5DBA-999F-A0B800C1F54B"><title>Define and
-implement PSL-specific channel classes</title> <p>The choice of class to be
-used for implementing DMA channels is governed by the mode of operation to
-be supported: </p> <ul>
-<li id="GUID-C254C7CA-D010-5885-811D-05BEAF068EDD"><p>single-buffer channels
-should use <xref href="GUID-A8B4AD1B-770C-363E-A0DE-C78A9786CBDC.dita"><apiname>TDmaSbChannel</apiname></xref> </p> </li>
-<li id="GUID-91DDE5AD-16E5-5FCE-86E9-80069F2CCDDB"><p>double-buffer channels
-should use <xref href="GUID-FD76AF08-6250-3054-8A06-16343E385B23.dita"><apiname>TDmaDbChannel</apiname></xref> </p> </li>
-<li id="GUID-994E863D-2C32-5AE3-931A-B852855883CA"><p>scatter-gather channels
-should use <xref href="GUID-2D4CFBB1-8D64-3CF5-B6F0-B24D16D5BAD4.dita"><apiname>TDmaSgChannel</apiname></xref> </p> </li>
-</ul> <p>These three classes are defined in <filepath>dma.h</filepath>. </p> <p>In
-addition, the PSL may need to store channel-specific data. One way of achieving
-this is by deriving a PSL-specific class from one of the generic ones. For
-example, the template scatter-gather implementation defines a <codeph>TTemplateSgChannel</codeph> class
-derived from <codeph>TDmaSgChannel</codeph> for storing data when appending
-new descriptors to a running channel: </p> <codeblock id="GUID-C4807321-01A3-5893-800A-6E22B8B5E131" xml:space="preserve">class TTemplateSgChannel : public TDmaSgChannel
- {
-public:
- TDmaDesc* iTmpDes;
- TPhysAddr iTmpDesPhysAddr;
- };
-
- </codeblock> </section>
-<section id="GUID-0991CFB7-B37E-57B9-BC1F-4A69FEDAF5A5"><title>Define and
-implement the controller classes</title> <p>A controller can either be a physical
-controller, or a logical one depending on which <xref href="GUID-97F97D7B-D5A3-5471-A359-77B805ED198C.dita">DMA
-mode you intend to support</xref>. </p> <p>The PSL (platform-specific layer)
-must define one concrete controller class per supported controller. A controller
-class is derived from <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref>. The concrete class must implement
-all the pure virtual functions defined in <codeph>TDmac</codeph>, and, optionally
-the functions used to manipulate hardware descriptors. </p> <p>Taking the
-template port as an example, the class is defined as: </p> <codeblock id="GUID-1C275111-6597-5616-822A-9EABF40BFE77" xml:space="preserve">class TTemplateDmac : public TDmac
- {
-public:
- TTemplateDmac();
- TInt Create();
-private:
- // from TDmac (PIL pure virtual)
- virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
- virtual void StopTransfer(const TDmaChannel& aChannel);
- virtual TBool IsIdle(const TDmaChannel& aChannel);
- virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
- virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
- // from TDmac (PIL virtual)
- virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
- TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
- virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
- virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
- const SDmaDesHdr& aNewHdr);
- virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
- // other
- static void Isr(TAny* aThis);
- inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr);
-private:
- static const SCreateInfo KInfo;
-public:
- TTemplateSgChannel iChannels[KChannelCount];
- };
-</codeblock> <p>Notes: </p> <ul>
-<li id="GUID-4E8059FF-0BBC-5F65-9F66-3C96BC86FE55"><p>The array of channels
-must be defined in the PSL controller class because only the PSL knows what
-kind of channels are used. </p> </li>
-<li id="GUID-66E7787B-E933-5E17-9169-E0D245B9D27A"><p>The PSL controller class
-must be allocated in the BSS section of the DMA kernel extension. The second
-phase constructor must be called from the extension entry point. </p> </li>
-<li id="GUID-7306F4CB-5D0F-5E82-AC61-E068A48C9C9B"><p>The C++ constructor
-must pass a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure to the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor.
-This structure defines what the PIL (platform-independent layer) needs to
-know about the underlying DMA controller. The template <codeph>TTemplateDmac</codeph> constructor
-just passes a <codeph>TDmac::ScreateInfo</codeph> structure, which defines
-the layout of the (base class managed) descriptor pool to the base class constructor
-through a ctor list: </p> <codeblock id="GUID-E00DD5C0-0976-58A0-B3C0-22DFD9216BC0" xml:space="preserve">TTemplateDmac::TTemplateDmac()
-//
-// Constructor.
-//
- : TDmac(KInfo)
- {}
-
- </codeblock> <p>where KInfo is a <codeph>TDmac::ScreateInfo</codeph> type. </p> </li>
-<li id="GUID-4C6FB95D-BE6F-5938-8AC3-824B3BB508EE"><p>The PSL controller class
-needs a second phase constructor. This is the <codeph>Create()</codeph> function,
-which must: </p> <ol id="GUID-33DC912F-C5B4-5F33-A427-62700522D958">
-<li id="GUID-F0E8A497-B09F-5DA0-A94A-3B08FC28707C"><p>call the second phase
-constructor of the base class: <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref>. </p> </li>
-<li id="GUID-1FD43FAD-4F43-557E-9EF0-19C725DD5FF5"><p>perform any hardware-specific
-initialisation. </p> </li>
-<li id="GUID-A522B8D4-744B-5C5B-B684-C82F34462171"><p>bind and enable the
-DMA interrupt(s). </p> </li>
-</ol> <p>In the template port, <codeph>Create()</codeph> calls the base class <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref> function
-and then initialises the template specific channel object members (the temporary
-descriptor fields used for appending requests to live channels), and performs
-platform specific initialisation for the interrupt dispatch of DMA interrupt
-events: </p> <codeblock id="GUID-FBCC8132-129C-53A4-99B7-290B56C3035D" xml:space="preserve">TInt TTemplateDmac::Create()
-//
-// Second phase construction.
-//
- {
- TInt r = TDmac::Create(KInfo); // Base class Create()
- if (r == KErrNone)
- {
- __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone);
- for (TInt i=0; i < KChannelCount; ++i)
- {
- TDmaDesc* pD = HdrToHwDes(*iFreeHdr);
- iChannels[i].iTmpDes = pD;
- iChannels[i].iTmpDesPhysAddr = DesLinToPhys(pD);
- iFreeHdr = iFreeHdr->iNext;
- }
- r = Interrupt::Bind(EAsspIntIdDma, Isr, this);
- if (r == KErrNone)
- {
- // TO DO: Map DMA clients (requests) to DMA channels here.
-
- r = Interrupt::Enable(EAsspIntIdDma);
- }
- }
- return r;
- }
- </codeblock> </li>
-</ul> </section>
-<section id="GUID-0DBA2E68-7759-5447-B34B-14F237369CB1"><title>Implement the
-channel allocator</title> <p>Channel allocation is implemented in the PSL
-(platform-specific layer) because this is a hardware-specific operation. There
-are two basic options: </p> <ul>
-<li id="GUID-A9246754-F21B-5BFC-9FDB-2CE5C92D1FA3"><p>Preallocate, at design
-time, one channel per DMA-aware peripheral. This is the simplest approach,
-and it should be acceptable for most Symbian platform devices because the
-set of supported peripherals is closed. In this case, cookies passed by client
-device drivers map uniquely to DMA channels. </p> </li>
-<li id="GUID-C1164FA0-9B70-55C1-9C5A-2D02728FA67A"><p>Full dynamic allocation.
-This is a simple approach too, but DMA channels are, in general, not completely
-identical. For example, some channels may have greater priorities than others. </p> </li>
-</ul> <p>Mixed schemes are also possible, for example, client device driver
-cookies could be used to select a subset of channels, and dynamic allocation
-used inside this subset. </p> <p>Whatever option is chosen, the PSL must provide
-an implementation for the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-934F46B3-1DF9-3870-87EE-A8E2DEF82810"><apiname>DmaChannelMgr::Open()</apiname></xref>.
-The template implementation is: </p> <codeblock id="GUID-9C7F5850-F72B-5A16-9DA0-606FBABAB5F0" xml:space="preserve">TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)
-//
-//
-//
- {
- __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId));
-
- __DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount));
-
- TDmaChannel* pC = Controller.iChannels + aOpenId;
- if (pC->IsOpened())
- pC = NULL;
- else
- {
- pC->iController = &Controller;
- pC->iPslId = aOpenId;
- }
-
- return pC;
- }
- </codeblock> <p>The template DMA channel manager returns a pointer to
-a DMA channel if the channel has not been previously allocated. Note that
-since channels possess preset priorities, the device drivers must be aware
-of which channel(s) they require DMA service from and configure the DMA controller
-to route sources to allocated channels accordingly. </p> <p>The platform-specific
-cookies passed by client device drivers to the PSL must be defined somewhere
-so that client device drivers can access them. </p> </section>
-<section id="GUID-6B35E9A7-11D6-5B26-B562-934169503412"><title>[Optionally]
-implement channel cleanup</title> <p>In the template PSL (platform-specific
-layer), the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-909D795A-7303-3A76-9C8E-3B07A97DD716"><apiname>DmaChannelMgr::Close()</apiname></xref> is a no-operation.
-This function is called by the PIL (platform-independent layer) when client
-device drivers call <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-8204AFBD-2A60-372E-B626-35BD19851FF7"><apiname>TDmaChannel::Close()</apiname></xref>. If the PSL needs
-to perform any hardware-specific operation when the channel is closed, then
-the implementation of <codeph>DmaChannelMgr::Close()</codeph> should be updated
-to reflect that. </p> </section>
-<section id="GUID-C9439F04-0BCC-5BC7-B18B-5C1B88515340"><title>Implement the
-mandatory controller virtual functions</title> <p>The <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> class
-contains several pure virtual functions that must be implemented by the PSL
-(platform-specific layer): </p> <ul>
-<li id="GUID-FF533DDF-E4B1-5AD1-9CBD-19A1D94AB07D"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-81921A9D-41F5-34BC-B882-60CC4CD807FB"><apiname>TDmac::Transfer()</apiname></xref> </p> </li>
-<li id="GUID-F6D6524A-09E3-54C0-AEB6-1D6BAB29210C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-B738D1B9-80FA-334D-ABEB-DFFF093E0B9D"><apiname>TDmac::StopTransfer()</apiname></xref> </p> </li>
-<li id="GUID-6209F3C7-9E3C-58BF-ABA4-6DF4BBF44A82"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-7422834D-CE6B-32DB-A040-7762A8BAB7D7"><apiname>TDmac::IsIdle()</apiname></xref> </p> </li>
-</ul> <p>These functions start and stop transfers on a DMA channel and are
-the main interface between the PIL (platform-independent layer) and the PSL.
-The implementation of these functions depends on the hardware available for
-performing DMA, and on the characteristics used to specify a DMA transfer: </p> <ul>
-<li id="GUID-81DA9FED-18F0-5205-9597-33542B0CB3CC"><p>the source and destination
-addresses </p> </li>
-<li id="GUID-D6684249-31CC-544B-8CEE-DD1D7FC8A8A1"><p>the burst size </p> </li>
-<li id="GUID-91D910DB-E1D7-5993-9ADB-6823662249D0"><p>the maximum transfer
-size </p> </li>
-<li id="GUID-C1926D7D-8349-5BA1-8E21-AB5D90486443"><p>the transfer width,
-i.e. number of bits per memory access </p> </li>
-<li id="GUID-C091D505-1088-56CA-8630-F1099B0A2234"><p>the memory alignment
-and endianness. </p> </li>
-</ul> <p>The DMA Framework manages the transfer descriptors according to the
-descriptor parameter passed into the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor
-by the derived class constructor; the descriptor parameter is a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure.
-The per-request transfer parameters are passed into the descriptors for each
-request issued by a driver. </p> <p><b>The
-transfer function: Transfer()</b> </p> <p>This function initiates a previously
-constructed request on a specific channel. This is the template implementation: </p> <codeblock id="GUID-80B95C0E-B30D-5A10-8512-68317D404DB3" xml:space="preserve">void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
-//
-// Initiates a (previously constructed) request on a specific channel.
-//
- {
- const TUint8 i = static_cast<TUint8>(aChannel.PslId());
- TDmaDesc* pD = HdrToHwDes(aHdr);
-
- __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
-
- // TO DO (for instance): Load the first descriptor address into the DMAC and start it
- // by setting the RUN bit.
- (void) *pD, (void) i;
-
- }
- </codeblock> <p><b>The
-stop transfer function: StopTransfer()</b> </p> <p>This function requires
-that the RUN mode is cleared. This is the template implementation: </p> <codeblock id="GUID-1BF7A5B4-2723-5A18-98E0-1F79A4928121" xml:space="preserve">void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel)
-//
-// Stops a running channel.
-//
- {
- const TUint8 i = static_cast<TUint8>(aChannel.PslId());
-
- __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i));
-
- // TO DO (for instance): Clear the RUN bit of the channel.
- (void) i;
-
- }
- </codeblock> <p><b>The
-function: IsIdle()</b> </p> <p> <codeph>IsIdle()</codeph> returns the state
-of a given channel. This is the template implementation: </p> <codeblock id="GUID-C7CC986E-986B-5C5E-AA3D-86851131BE93" xml:space="preserve">TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel)
-//
-// Returns the state of a given channel.
-//
- {
- const TUint8 i = static_cast<TUint8>(aChannel.PslId());
-
- __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::IsIdle channel=%d", i));
-
- // TO DO (for instance): Return the state of the RUN bit of the channel.
- // The return value should reflect the actual state.
- (void) i;
-
- return ETrue;
- }
- </codeblock> </section>
-<section id="GUID-A362A7CF-3674-525C-8114-485315E6594B"><title>Implement the
-non-mandatory controller virtual functions</title> <p>The following auxiliary
-functions are used to implement the scatter-gather transfer mode behaviour
-by creating and manipulating the linked list of transfer fragment headers
-that describe a given scatter-gather transaction. They are called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base
-class functions when the instance of the <codeph>TDmac</codeph> derived class
-reports itself as being capable of scatter-gather operations. </p> <ul>
-<li id="GUID-D401D7C8-B086-56CD-BAE0-96EEB0AA7E38"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-90AC3E58-E589-3F91-85F7-16A4ADFFFA69"><apiname>TDmac::InitHwDes()</apiname></xref> </p> </li>
-<li id="GUID-58633367-FE56-53B7-A967-21828DA85F5C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-05021B05-75DE-3F75-92C6-8B9445EB86D3"><apiname>TDmac::ChainHwDes()</apiname></xref> </p> </li>
-<li id="GUID-94F81366-77D4-5AF6-9933-53E964863301"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> </p> </li>
-</ul> <p><b>First
-scatter-gather support function: InitHwDes()</b> </p> <p>This is a function
-for creating a scatter-gather list. From the information in the passed-in
-request, the function sets up the descriptor with that fragment's: </p> <ul>
-<li id="GUID-098E886D-D98D-5AC9-BB25-7FF8E6F0D05B"><p>source and destination
-address </p> </li>
-<li id="GUID-83440454-B955-55C8-BF10-DF86CDA0C466"><p>size </p> </li>
-<li id="GUID-294D3B08-0A64-534D-858F-F43759A2DC59"><p>driver/DMA controller
-specific transfer parameters: memory/peripheral, burst size, transfer width. </p> </li>
-</ul> <p>This is the template implementation: </p> <codeblock id="GUID-EB6F9C76-EC23-5464-A6C5-AB0B36717D2B" xml:space="preserve">void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
- TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/)
-//
-// Sets up (from a passed in request) the descriptor with that fragment's source and destination address,
-// the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral,
-// burst size, transfer width).
-//
- {
- TDmaDesc* pD = HdrToHwDes(aHdr);
-
- __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
-
- // Unaligned descriptor? Error in generic layer!
- __DMA_ASSERTD(IsHwDesAligned(pD));
-
- pD->iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc);
- pD->iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest);
- pD->iCmd = DcmdReg(aCount, aFlags, aPslInfo);
- pD->iDescAddr = TDmaDesc::KStopBitMask;
- }
-
- </codeblock> <p><b>Second
-scatter-gather support function: ChainHwDes()</b> </p> <p>If the framework
-needs to fragment the client’s request, for transfer size or memory discontiguousness
-reasons, then the framework calls this function. It chains hardware descriptors
-together by setting the next pointer of the original descriptor to the physical
-address of the descriptor to be chained. It assumes that the DMAC channel
-is quiescent when called. </p> <p>This is the template implementation: </p> <codeblock id="GUID-7979A1FB-5FA1-5078-8762-3874A62E6C63" xml:space="preserve">void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
-//
-// Chains hardware descriptors together by setting the next pointer of the original descriptor
-// to the physical address of the descriptor to be chained.
-//
- {
- TDmaDesc* pD = HdrToHwDes(aHdr);
- TDmaDesc* pN = HdrToHwDes(aNextHdr);
-
- __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
-
- // Unaligned descriptor? Error in generic layer!
- __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
-
- // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer.
-
- pD->iDescAddr = DesLinToPhys(pN);
- }
-
-</codeblock> <p><b>Third
-scatter-gather support function: AppendHwDes()</b> </p> <p>This function is
-called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base class when a driver request is
-called for a channel that is still active, i.e. where the intent is to provide
-data streaming so that the target device is constantly provided with data;
-for example, an audio device playing a track. In this case, the function provided
-by the derived class must: </p> <ul>
-<li id="GUID-F94FBAA8-2A0D-5863-BA09-0EC1D61005A9"><p>stop the DMAC to prevent
-any corruption of the scatter-gather list while appending the new fragment
-descriptor </p> </li>
-<li id="GUID-AEF81B78-73D8-5B70-AFE4-0AEA7862CB74"><p>append the new descriptor </p> </li>
-<li id="GUID-2304F2D4-833E-5F75-B88E-C794DF9D984E"><p>re-enable the channel,
-ideally before the target has detected the gap in service. </p> </li>
-</ul> <p>This is the template implementation: </p> <codeblock id="GUID-18512439-C781-5267-ADBC-B9047942F800" xml:space="preserve">void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
- const SDmaDesHdr& aNewHdr)
-//
-// Appends a descriptor to the chain while the channel is running.
-//
- {
- const TUint8 i = static_cast<TUint8>(aChannel.PslId());
-
- TDmaDesc* pL = HdrToHwDes(aLastHdr);
- TDmaDesc* pN = HdrToHwDes(aNewHdr);
-
- __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
- i, pL, pN));
- // Unaligned descriptor? Error in generic layer!
- __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
-
- TPhysAddr newPhys = DesLinToPhys(pN);
-
- const TInt irq = NKern::DisableAllInterrupts();
- StopTransfer(aChannel);
-
- pL->iDescAddr = newPhys;
- const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel);
- TDmaDesc* pD = channel.iTmpDes;
-
- // TO DO: Implement the appropriate algorithm for appending a descriptor here.
- (void) *pD, (void) i;
-
- NKern::RestoreInterrupts(irq);
-
- __KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes"));
- }
- </codeblock> </section>
-<section id="GUID-F5968000-0C3E-5E53-A2D5-120B81F3140F"><title>Implement an
-interrupt service routine</title> <p>The interrupt service routine needs to
-do the following: </p> <ul>
-<li id="GUID-CE55E999-0886-5620-87BA-99A36D694FD4"><p>identify the channel
-that raised the interrupt </p> </li>
-<li id="GUID-02467F17-DC1E-552C-B1C2-D3C2CCE12347"><p>decide whether the interrupt
-was raised because of a successful data transfer or because of an error </p> </li>
-<li id="GUID-0D5FDA57-A45E-54E5-A69C-64D22B916AB4"><p>call the base class
-function <codeph>TDmac::HandleIsr()</codeph>, which queues a DFC, or increments
-the number of pending interrupts if a DFC is already queued. </p> </li>
-</ul> <p>This is the template implementation: </p> <codeblock id="GUID-4CFCA5A1-9657-55F1-BE3C-AFF1F3974F80" xml:space="preserve">void TTemplateDmac::Isr(TAny* aThis)
-//
-// This ISR reads the interrupt identification and calls back into the base class
-// interrupt service handler with the channel identifier and an indication whether the
-// transfer completed correctly or with an error.
-//
- {
- TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis);
-
- // TO DO: Implement the behaviour described above, call HandleIsr().
-
- HandleIsr(me.iChannels[5], 0); // Example
-
- }
- </codeblock> </section>
-<section id="GUID-D7F410A1-DC70-515D-A00D-3955B534C62F"><title>Implement the
-test support table and function</title> <p>The DMA Framework comes with a
-test harness that can be used to validate the port if the underlying DMA controller
-supports memory to memory transfers. </p> <p>The test harness needs to know
-about the capabilities of the port being tested. The PSL provides the global
-function <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> that returns a <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref> object
-that contains this information. In the template PSL, this structure is initialised
-to binary zeroes. Before using the test harness, it must be initialised with
-valid values. </p> <p>See <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref>, <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> and <xref href="GUID-8552E66E-73D6-51DA-8F53-DDF437186CD6.dita">Validation</xref>. </p> </section>
-<section id="GUID-D452D2CD-D251-50F4-818E-E7125501CE8F"><title>Optimise the
-performance of critical functions</title> <p>You can optionally optimise critical
-functions by writing them in assembler. The two candidates for an assembler
-rewrite are: </p> <ul>
-<li id="GUID-157E6F4A-0310-5923-B446-040F75E469D4"><p>The interrupt service
-routine </p> </li>
-<li id="GUID-74C9D4DB-9CA9-5C5E-A475-B6840EBC2245"><p>In scatter-gather mode,
-the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> function if it needs to suspend
-a transfer when appending a new descriptor chain to an existing one. </p> </li>
-</ul> </section>
-<section id="GUID-A2AF293F-558A-5F69-821F-EC2B202A5A4F"><title>Extend the
-framework with platform-specific functionality</title> <p>There are two ways
-of extending the DMA Framework: </p> <ol id="GUID-D6C660FC-FF23-55B2-B91E-4BC04C592059">
-<li id="GUID-4453F4C2-3444-5A3E-94C7-BE6320B1EF89"><p>to provide platform-specific
-functionality on a per-channel basis. </p> </li>
-<li id="GUID-C0C6A072-134A-5753-A6DC-185F3975C2A6"><p>to provide platform-specific
-functionality on a <i>channel independent</i> basis. </p> </li>
-</ol> <p>In the first case, the PSL provides an implementation of the virtual
-function <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. The default implementation
-just returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-2CF7498E-F5D2-3C4A-8E98-47504F9FC404"><apiname>TDmaChannel::Extension()</apiname></xref> calls <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. </p> <p>In the second case, the PSL provides an implementation of the static
-function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. The template
-PSL implementation just returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-75562653-1F27-39D3-96D8-55A94BA9B68B"><apiname>TDmaChannel::StaticExtension()</apiname></xref> calls <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. </p> </section>
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
+<!-- This component and the accompanying materials are made available under the terms of the License
+"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:
+-->
+<!DOCTYPE concept
+ PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
+<concept id="GUID-A4C19890-2380-5498-A5F8-3B6D95CEFEF4" xml:lang="en"><title>PSL
+Implementation</title><shortdesc>Describes how to create the PSL implementation.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
+<p>To create a port of the DMA Framework, you must create an implementation
+of the PSL for the DMA controller hardware.</p>
+<section id="GUID-8664FA8F-E53A-5DBA-999F-A0B800C1F54B"><title>Define and
+implement PSL-specific channel classes</title> <p>The choice of class to be
+used for implementing DMA channels is governed by the mode of operation to
+be supported: </p> <ul>
+<li id="GUID-C254C7CA-D010-5885-811D-05BEAF068EDD"><p>single-buffer channels
+should use <xref href="GUID-A8B4AD1B-770C-363E-A0DE-C78A9786CBDC.dita"><apiname>TDmaSbChannel</apiname></xref> </p> </li>
+<li id="GUID-91DDE5AD-16E5-5FCE-86E9-80069F2CCDDB"><p>double-buffer channels
+should use <xref href="GUID-FD76AF08-6250-3054-8A06-16343E385B23.dita"><apiname>TDmaDbChannel</apiname></xref> </p> </li>
+<li id="GUID-994E863D-2C32-5AE3-931A-B852855883CA"><p>scatter-gather channels
+should use <xref href="GUID-2D4CFBB1-8D64-3CF5-B6F0-B24D16D5BAD4.dita"><apiname>TDmaSgChannel</apiname></xref> </p> </li>
+</ul> <p>These three classes are defined in <filepath>dma.h</filepath>. </p> <p>In
+addition, the PSL may need to store channel-specific data. One way of achieving
+this is by deriving a PSL-specific class from one of the generic ones. For
+example, the template scatter-gather implementation defines a <codeph>TTemplateSgChannel</codeph> class
+derived from <codeph>TDmaSgChannel</codeph> for storing data when appending
+new descriptors to a running channel: </p> <codeblock id="GUID-C4807321-01A3-5893-800A-6E22B8B5E131" xml:space="preserve">class TTemplateSgChannel : public TDmaSgChannel
+ {
+public:
+ TDmaDesc* iTmpDes;
+ TPhysAddr iTmpDesPhysAddr;
+ };
+
+ </codeblock> </section>
+<section id="GUID-0991CFB7-B37E-57B9-BC1F-4A69FEDAF5A5"><title>Define and
+implement the controller classes</title> <p>A controller can either be a physical
+controller, or a logical one depending on which <xref href="GUID-97F97D7B-D5A3-5471-A359-77B805ED198C.dita">DMA
+mode you intend to support</xref>. </p> <p>The PSL (platform-specific layer)
+must define one concrete controller class per supported controller. A controller
+class is derived from <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref>. The concrete class must implement
+all the pure virtual functions defined in <codeph>TDmac</codeph>, and, optionally
+the functions used to manipulate hardware descriptors. </p> <p>Taking the
+template port as an example, the class is defined as: </p> <codeblock id="GUID-1C275111-6597-5616-822A-9EABF40BFE77" xml:space="preserve">class TTemplateDmac : public TDmac
+ {
+public:
+ TTemplateDmac();
+ TInt Create();
+private:
+ // from TDmac (PIL pure virtual)
+ virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
+ virtual void StopTransfer(const TDmaChannel& aChannel);
+ virtual TBool IsIdle(const TDmaChannel& aChannel);
+ virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
+ virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
+ // from TDmac (PIL virtual)
+ virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
+ TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
+ virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
+ virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
+ const SDmaDesHdr& aNewHdr);
+ virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
+ // other
+ static void Isr(TAny* aThis);
+ inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr);
+private:
+ static const SCreateInfo KInfo;
+public:
+ TTemplateSgChannel iChannels[KChannelCount];
+ };
+</codeblock> <p>Notes: </p> <ul>
+<li id="GUID-4E8059FF-0BBC-5F65-9F66-3C96BC86FE55"><p>The array of channels
+must be defined in the PSL controller class because only the PSL knows what
+kind of channels are used. </p> </li>
+<li id="GUID-66E7787B-E933-5E17-9169-E0D245B9D27A"><p>The PSL controller class
+must be allocated in the BSS section of the DMA kernel extension. The second
+phase constructor must be called from the extension entry point. </p> </li>
+<li id="GUID-7306F4CB-5D0F-5E82-AC61-E068A48C9C9B"><p>The C++ constructor
+must pass a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure to the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor.
+This structure defines what the PIL (platform-independent layer) needs to
+know about the underlying DMA controller. The template <codeph>TTemplateDmac</codeph> constructor
+just passes a <codeph>TDmac::ScreateInfo</codeph> structure, which defines
+the layout of the (base class managed) descriptor pool to the base class constructor
+through a ctor list: </p> <codeblock id="GUID-E00DD5C0-0976-58A0-B3C0-22DFD9216BC0" xml:space="preserve">TTemplateDmac::TTemplateDmac()
+//
+// Constructor.
+//
+ : TDmac(KInfo)
+ {}
+
+ </codeblock> <p>where KInfo is a <codeph>TDmac::ScreateInfo</codeph> type. </p> </li>
+<li id="GUID-4C6FB95D-BE6F-5938-8AC3-824B3BB508EE"><p>The PSL controller class
+needs a second phase constructor. This is the <codeph>Create()</codeph> function,
+which must: </p> <ol id="GUID-33DC912F-C5B4-5F33-A427-62700522D958">
+<li id="GUID-F0E8A497-B09F-5DA0-A94A-3B08FC28707C"><p>call the second phase
+constructor of the base class: <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref>. </p> </li>
+<li id="GUID-1FD43FAD-4F43-557E-9EF0-19C725DD5FF5"><p>perform any hardware-specific
+initialisation. </p> </li>
+<li id="GUID-A522B8D4-744B-5C5B-B684-C82F34462171"><p>bind and enable the
+DMA interrupt(s). </p> </li>
+</ol> <p>In the template port, <codeph>Create()</codeph> calls the base class <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref> function
+and then initialises the template specific channel object members (the temporary
+descriptor fields used for appending requests to live channels), and performs
+platform specific initialisation for the interrupt dispatch of DMA interrupt
+events: </p> <codeblock id="GUID-FBCC8132-129C-53A4-99B7-290B56C3035D" xml:space="preserve">TInt TTemplateDmac::Create()
+//
+// Second phase construction.
+//
+ {
+ TInt r = TDmac::Create(KInfo); // Base class Create()
+ if (r == KErrNone)
+ {
+ __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone);
+ for (TInt i=0; i < KChannelCount; ++i)
+ {
+ TDmaDesc* pD = HdrToHwDes(*iFreeHdr);
+ iChannels[i].iTmpDes = pD;
+ iChannels[i].iTmpDesPhysAddr = DesLinToPhys(pD);
+ iFreeHdr = iFreeHdr->iNext;
+ }
+ r = Interrupt::Bind(EAsspIntIdDma, Isr, this);
+ if (r == KErrNone)
+ {
+ // TO DO: Map DMA clients (requests) to DMA channels here.
+
+ r = Interrupt::Enable(EAsspIntIdDma);
+ }
+ }
+ return r;
+ }
+ </codeblock> </li>
+</ul> </section>
+<section id="GUID-0DBA2E68-7759-5447-B34B-14F237369CB1"><title>Implement the
+channel allocator</title> <p>Channel allocation is implemented in the PSL
+(platform-specific layer) because this is a hardware-specific operation. There
+are two basic options: </p> <ul>
+<li id="GUID-A9246754-F21B-5BFC-9FDB-2CE5C92D1FA3"><p>Preallocate, at design
+time, one channel per DMA-aware peripheral. This is the simplest approach,
+and it should be acceptable for most Symbian platform devices because the
+set of supported peripherals is closed. In this case, cookies passed by client
+device drivers map uniquely to DMA channels. </p> </li>
+<li id="GUID-C1164FA0-9B70-55C1-9C5A-2D02728FA67A"><p>Full dynamic allocation.
+This is a simple approach too, but DMA channels are, in general, not completely
+identical. For example, some channels may have greater priorities than others. </p> </li>
+</ul> <p>Mixed schemes are also possible, for example, client device driver
+cookies could be used to select a subset of channels, and dynamic allocation
+used inside this subset. </p> <p>Whatever option is chosen, the PSL must provide
+an implementation for the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-934F46B3-1DF9-3870-87EE-A8E2DEF82810"><apiname>DmaChannelMgr::Open()</apiname></xref>.
+The template implementation is: </p> <codeblock id="GUID-9C7F5850-F72B-5A16-9DA0-606FBABAB5F0" xml:space="preserve">TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)
+//
+//
+//
+ {
+ __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId));
+
+ __DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount));
+
+ TDmaChannel* pC = Controller.iChannels + aOpenId;
+ if (pC->IsOpened())
+ pC = NULL;
+ else
+ {
+ pC->iController = &Controller;
+ pC->iPslId = aOpenId;
+ }
+
+ return pC;
+ }
+ </codeblock> <p>The template DMA channel manager returns a pointer to
+a DMA channel if the channel has not been previously allocated. Note that
+since channels possess preset priorities, the device drivers must be aware
+of which channel(s) they require DMA service from and configure the DMA controller
+to route sources to allocated channels accordingly. </p> <p>The platform-specific
+cookies passed by client device drivers to the PSL must be defined somewhere
+so that client device drivers can access them. </p> </section>
+<section id="GUID-6B35E9A7-11D6-5B26-B562-934169503412"><title>[Optionally]
+implement channel cleanup</title> <p>In the template PSL (platform-specific
+layer), the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-909D795A-7303-3A76-9C8E-3B07A97DD716"><apiname>DmaChannelMgr::Close()</apiname></xref> is a no-operation.
+This function is called by the PIL (platform-independent layer) when client
+device drivers call <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-8204AFBD-2A60-372E-B626-35BD19851FF7"><apiname>TDmaChannel::Close()</apiname></xref>. If the PSL needs
+to perform any hardware-specific operation when the channel is closed, then
+the implementation of <codeph>DmaChannelMgr::Close()</codeph> should be updated
+to reflect that. </p> </section>
+<section id="GUID-C9439F04-0BCC-5BC7-B18B-5C1B88515340"><title>Implement the
+mandatory controller virtual functions</title> <p>The <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> class
+contains several pure virtual functions that must be implemented by the PSL
+(platform-specific layer): </p> <ul>
+<li id="GUID-FF533DDF-E4B1-5AD1-9CBD-19A1D94AB07D"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-81921A9D-41F5-34BC-B882-60CC4CD807FB"><apiname>TDmac::Transfer()</apiname></xref> </p> </li>
+<li id="GUID-F6D6524A-09E3-54C0-AEB6-1D6BAB29210C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-B738D1B9-80FA-334D-ABEB-DFFF093E0B9D"><apiname>TDmac::StopTransfer()</apiname></xref> </p> </li>
+<li id="GUID-6209F3C7-9E3C-58BF-ABA4-6DF4BBF44A82"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-7422834D-CE6B-32DB-A040-7762A8BAB7D7"><apiname>TDmac::IsIdle()</apiname></xref> </p> </li>
+</ul> <p>These functions start and stop transfers on a DMA channel and are
+the main interface between the PIL (platform-independent layer) and the PSL.
+The implementation of these functions depends on the hardware available for
+performing DMA, and on the characteristics used to specify a DMA transfer: </p> <ul>
+<li id="GUID-81DA9FED-18F0-5205-9597-33542B0CB3CC"><p>the source and destination
+addresses </p> </li>
+<li id="GUID-D6684249-31CC-544B-8CEE-DD1D7FC8A8A1"><p>the burst size </p> </li>
+<li id="GUID-91D910DB-E1D7-5993-9ADB-6823662249D0"><p>the maximum transfer
+size </p> </li>
+<li id="GUID-C1926D7D-8349-5BA1-8E21-AB5D90486443"><p>the transfer width,
+i.e. number of bits per memory access </p> </li>
+<li id="GUID-C091D505-1088-56CA-8630-F1099B0A2234"><p>the memory alignment
+and endianness. </p> </li>
+</ul> <p>The DMA Framework manages the transfer descriptors according to the
+descriptor parameter passed into the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor
+by the derived class constructor; the descriptor parameter is a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure.
+The per-request transfer parameters are passed into the descriptors for each
+request issued by a driver. </p> <p><b>The
+transfer function: Transfer()</b> </p> <p>This function initiates a previously
+constructed request on a specific channel. This is the template implementation: </p> <codeblock id="GUID-80B95C0E-B30D-5A10-8512-68317D404DB3" xml:space="preserve">void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
+//
+// Initiates a (previously constructed) request on a specific channel.
+//
+ {
+ const TUint8 i = static_cast<TUint8>(aChannel.PslId());
+ TDmaDesc* pD = HdrToHwDes(aHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
+
+ // TO DO (for instance): Load the first descriptor address into the DMAC and start it
+ // by setting the RUN bit.
+ (void) *pD, (void) i;
+
+ }
+ </codeblock> <p><b>The
+stop transfer function: StopTransfer()</b> </p> <p>This function requires
+that the RUN mode is cleared. This is the template implementation: </p> <codeblock id="GUID-1BF7A5B4-2723-5A18-98E0-1F79A4928121" xml:space="preserve">void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel)
+//
+// Stops a running channel.
+//
+ {
+ const TUint8 i = static_cast<TUint8>(aChannel.PslId());
+
+ __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i));
+
+ // TO DO (for instance): Clear the RUN bit of the channel.
+ (void) i;
+
+ }
+ </codeblock> <p><b>The
+function: IsIdle()</b> </p> <p> <codeph>IsIdle()</codeph> returns the state
+of a given channel. This is the template implementation: </p> <codeblock id="GUID-C7CC986E-986B-5C5E-AA3D-86851131BE93" xml:space="preserve">TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel)
+//
+// Returns the state of a given channel.
+//
+ {
+ const TUint8 i = static_cast<TUint8>(aChannel.PslId());
+
+ __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::IsIdle channel=%d", i));
+
+ // TO DO (for instance): Return the state of the RUN bit of the channel.
+ // The return value should reflect the actual state.
+ (void) i;
+
+ return ETrue;
+ }
+ </codeblock> </section>
+<section id="GUID-A362A7CF-3674-525C-8114-485315E6594B"><title>Implement the
+non-mandatory controller virtual functions</title> <p>The following auxiliary
+functions are used to implement the scatter-gather transfer mode behaviour
+by creating and manipulating the linked list of transfer fragment headers
+that describe a given scatter-gather transaction. They are called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base
+class functions when the instance of the <codeph>TDmac</codeph> derived class
+reports itself as being capable of scatter-gather operations. </p> <ul>
+<li id="GUID-D401D7C8-B086-56CD-BAE0-96EEB0AA7E38"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-90AC3E58-E589-3F91-85F7-16A4ADFFFA69"><apiname>TDmac::InitHwDes()</apiname></xref> </p> </li>
+<li id="GUID-58633367-FE56-53B7-A967-21828DA85F5C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-05021B05-75DE-3F75-92C6-8B9445EB86D3"><apiname>TDmac::ChainHwDes()</apiname></xref> </p> </li>
+<li id="GUID-94F81366-77D4-5AF6-9933-53E964863301"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> </p> </li>
+</ul> <p><b>First
+scatter-gather support function: InitHwDes()</b> </p> <p>This is a function
+for creating a scatter-gather list. From the information in the passed-in
+request, the function sets up the descriptor with that fragment's: </p> <ul>
+<li id="GUID-098E886D-D98D-5AC9-BB25-7FF8E6F0D05B"><p>source and destination
+address </p> </li>
+<li id="GUID-83440454-B955-55C8-BF10-DF86CDA0C466"><p>size </p> </li>
+<li id="GUID-294D3B08-0A64-534D-858F-F43759A2DC59"><p>driver/DMA controller
+specific transfer parameters: memory/peripheral, burst size, transfer width. </p> </li>
+</ul> <p>This is the template implementation: </p> <codeblock id="GUID-EB6F9C76-EC23-5464-A6C5-AB0B36717D2B" xml:space="preserve">void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
+ TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/)
+//
+// Sets up (from a passed in request) the descriptor with that fragment's source and destination address,
+// the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral,
+// burst size, transfer width).
+//
+ {
+ TDmaDesc* pD = HdrToHwDes(aHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
+
+ // Unaligned descriptor? Error in generic layer!
+ __DMA_ASSERTD(IsHwDesAligned(pD));
+
+ pD->iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc);
+ pD->iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest);
+ pD->iCmd = DcmdReg(aCount, aFlags, aPslInfo);
+ pD->iDescAddr = TDmaDesc::KStopBitMask;
+ }
+
+ </codeblock> <p><b>Second
+scatter-gather support function: ChainHwDes()</b> </p> <p>If the framework
+needs to fragment the client’s request, for transfer size or memory discontiguousness
+reasons, then the framework calls this function. It chains hardware descriptors
+together by setting the next pointer of the original descriptor to the physical
+address of the descriptor to be chained. It assumes that the DMAC channel
+is quiescent when called. </p> <p>This is the template implementation: </p> <codeblock id="GUID-7979A1FB-5FA1-5078-8762-3874A62E6C63" xml:space="preserve">void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
+//
+// Chains hardware descriptors together by setting the next pointer of the original descriptor
+// to the physical address of the descriptor to be chained.
+//
+ {
+ TDmaDesc* pD = HdrToHwDes(aHdr);
+ TDmaDesc* pN = HdrToHwDes(aNextHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
+
+ // Unaligned descriptor? Error in generic layer!
+ __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
+
+ // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer.
+
+ pD->iDescAddr = DesLinToPhys(pN);
+ }
+
+</codeblock> <p><b>Third
+scatter-gather support function: AppendHwDes()</b> </p> <p>This function is
+called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base class when a driver request is
+called for a channel that is still active, i.e. where the intent is to provide
+data streaming so that the target device is constantly provided with data;
+for example, an audio device playing a track. In this case, the function provided
+by the derived class must: </p> <ul>
+<li id="GUID-F94FBAA8-2A0D-5863-BA09-0EC1D61005A9"><p>stop the DMAC to prevent
+any corruption of the scatter-gather list while appending the new fragment
+descriptor </p> </li>
+<li id="GUID-AEF81B78-73D8-5B70-AFE4-0AEA7862CB74"><p>append the new descriptor </p> </li>
+<li id="GUID-2304F2D4-833E-5F75-B88E-C794DF9D984E"><p>re-enable the channel,
+ideally before the target has detected the gap in service. </p> </li>
+</ul> <p>This is the template implementation: </p> <codeblock id="GUID-18512439-C781-5267-ADBC-B9047942F800" xml:space="preserve">void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
+ const SDmaDesHdr& aNewHdr)
+//
+// Appends a descriptor to the chain while the channel is running.
+//
+ {
+ const TUint8 i = static_cast<TUint8>(aChannel.PslId());
+
+ TDmaDesc* pL = HdrToHwDes(aLastHdr);
+ TDmaDesc* pN = HdrToHwDes(aNewHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
+ i, pL, pN));
+ // Unaligned descriptor? Error in generic layer!
+ __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
+
+ TPhysAddr newPhys = DesLinToPhys(pN);
+
+ const TInt irq = NKern::DisableAllInterrupts();
+ StopTransfer(aChannel);
+
+ pL->iDescAddr = newPhys;
+ const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel);
+ TDmaDesc* pD = channel.iTmpDes;
+
+ // TO DO: Implement the appropriate algorithm for appending a descriptor here.
+ (void) *pD, (void) i;
+
+ NKern::RestoreInterrupts(irq);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes"));
+ }
+ </codeblock> </section>
+<section id="GUID-F5968000-0C3E-5E53-A2D5-120B81F3140F"><title>Implement an
+interrupt service routine</title> <p>The interrupt service routine needs to
+do the following: </p> <ul>
+<li id="GUID-CE55E999-0886-5620-87BA-99A36D694FD4"><p>identify the channel
+that raised the interrupt </p> </li>
+<li id="GUID-02467F17-DC1E-552C-B1C2-D3C2CCE12347"><p>decide whether the interrupt
+was raised because of a successful data transfer or because of an error </p> </li>
+<li id="GUID-0D5FDA57-A45E-54E5-A69C-64D22B916AB4"><p>call the base class
+function <codeph>TDmac::HandleIsr()</codeph>, which queues a DFC, or increments
+the number of pending interrupts if a DFC is already queued. </p> </li>
+</ul> <p>This is the template implementation: </p> <codeblock id="GUID-4CFCA5A1-9657-55F1-BE3C-AFF1F3974F80" xml:space="preserve">void TTemplateDmac::Isr(TAny* aThis)
+//
+// This ISR reads the interrupt identification and calls back into the base class
+// interrupt service handler with the channel identifier and an indication whether the
+// transfer completed correctly or with an error.
+//
+ {
+ TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis);
+
+ // TO DO: Implement the behaviour described above, call HandleIsr().
+
+ HandleIsr(me.iChannels[5], 0); // Example
+
+ }
+ </codeblock> </section>
+<section id="GUID-D7F410A1-DC70-515D-A00D-3955B534C62F"><title>Implement the
+test support table and function</title> <p>The DMA Framework comes with a
+test harness that can be used to validate the port if the underlying DMA controller
+supports memory to memory transfers. </p> <p>The test harness needs to know
+about the capabilities of the port being tested. The PSL provides the global
+function <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> that returns a <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref> object
+that contains this information. In the template PSL, this structure is initialised
+to binary zeroes. Before using the test harness, it must be initialised with
+valid values. </p> <p>See <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref>, <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> and <xref href="GUID-8552E66E-73D6-51DA-8F53-DDF437186CD6.dita">Validation</xref>. </p> </section>
+<section id="GUID-D452D2CD-D251-50F4-818E-E7125501CE8F"><title>Optimise the
+performance of critical functions</title> <p>You can optionally optimise critical
+functions by writing them in assembler. The two candidates for an assembler
+rewrite are: </p> <ul>
+<li id="GUID-157E6F4A-0310-5923-B446-040F75E469D4"><p>The interrupt service
+routine </p> </li>
+<li id="GUID-74C9D4DB-9CA9-5C5E-A475-B6840EBC2245"><p>In scatter-gather mode,
+the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> function if it needs to suspend
+a transfer when appending a new descriptor chain to an existing one. </p> </li>
+</ul> </section>
+<section id="GUID-A2AF293F-558A-5F69-821F-EC2B202A5A4F"><title>Extend the
+framework with platform-specific functionality</title> <p>There are two ways
+of extending the DMA Framework: </p> <ol id="GUID-D6C660FC-FF23-55B2-B91E-4BC04C592059">
+<li id="GUID-4453F4C2-3444-5A3E-94C7-BE6320B1EF89"><p>to provide platform-specific
+functionality on a per-channel basis. </p> </li>
+<li id="GUID-C0C6A072-134A-5753-A6DC-185F3975C2A6"><p>to provide platform-specific
+functionality on a <i>channel independent</i> basis. </p> </li>
+</ol> <p>In the first case, the PSL provides an implementation of the virtual
+function <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. The default implementation
+just returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-2CF7498E-F5D2-3C4A-8E98-47504F9FC404"><apiname>TDmaChannel::Extension()</apiname></xref> calls <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. </p> <p>In the second case, the PSL provides an implementation of the static
+function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. The template
+PSL implementation just returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-75562653-1F27-39D3-96D8-55A94BA9B68B"><apiname>TDmaChannel::StaticExtension()</apiname></xref> calls <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. </p> </section>
</conbody></concept>
\ No newline at end of file