Adaptation/GUID-A4C19890-2380-5498-A5F8-3B6D95CEFEF4.dita
changeset 15 307f4279f433
equal deleted inserted replaced
14:578be2adaf3e 15:307f4279f433
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-A4C19890-2380-5498-A5F8-3B6D95CEFEF4" xml:lang="en"><title>PSL
       
    13 Implementation</title><shortdesc>Describes how to create the PSL implementation.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    14 <p>To create a port of the DMA Framework, you must create an implementation
       
    15 of the PSL for the DMA controller hardware.</p>
       
    16 <section id="GUID-8664FA8F-E53A-5DBA-999F-A0B800C1F54B"><title>Define and
       
    17 implement PSL-specific channel classes</title> <p>The choice of class to be
       
    18 used for implementing DMA channels is governed by the mode of operation to
       
    19 be supported: </p> <ul>
       
    20 <li id="GUID-C254C7CA-D010-5885-811D-05BEAF068EDD"><p>single-buffer channels
       
    21 should use <xref href="GUID-A8B4AD1B-770C-363E-A0DE-C78A9786CBDC.dita"><apiname>TDmaSbChannel</apiname></xref>  </p> </li>
       
    22 <li id="GUID-91DDE5AD-16E5-5FCE-86E9-80069F2CCDDB"><p>double-buffer channels
       
    23 should use <xref href="GUID-FD76AF08-6250-3054-8A06-16343E385B23.dita"><apiname>TDmaDbChannel</apiname></xref>  </p> </li>
       
    24 <li id="GUID-994E863D-2C32-5AE3-931A-B852855883CA"><p>scatter-gather channels
       
    25 should use <xref href="GUID-2D4CFBB1-8D64-3CF5-B6F0-B24D16D5BAD4.dita"><apiname>TDmaSgChannel</apiname></xref>  </p> </li>
       
    26 </ul> <p>These three classes are defined in <filepath>dma.h</filepath>. </p> <p>In
       
    27 addition, the PSL may need to store channel-specific data. One way of achieving
       
    28 this is by deriving a PSL-specific class from one of the generic ones. For
       
    29 example, the template scatter-gather implementation defines a <codeph>TTemplateSgChannel</codeph> class
       
    30 derived from <codeph>TDmaSgChannel</codeph> for storing data when appending
       
    31 new descriptors to a running channel: </p> <codeblock id="GUID-C4807321-01A3-5893-800A-6E22B8B5E131" xml:space="preserve">class TTemplateSgChannel : public TDmaSgChannel
       
    32     {
       
    33 public:
       
    34     TDmaDesc* iTmpDes;
       
    35     TPhysAddr iTmpDesPhysAddr;
       
    36     };
       
    37 
       
    38       </codeblock> </section>
       
    39 <section id="GUID-0991CFB7-B37E-57B9-BC1F-4A69FEDAF5A5"><title>Define and
       
    40 implement the controller classes</title> <p>A controller can either be a physical
       
    41 controller, or a logical one depending on which <xref href="GUID-97F97D7B-D5A3-5471-A359-77B805ED198C.dita">DMA
       
    42 mode you intend to support</xref>. </p> <p>The PSL (platform-specific layer)
       
    43 must define one concrete controller class per supported controller. A controller
       
    44 class is derived from <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref>. The concrete class must implement
       
    45 all the pure virtual functions defined in <codeph>TDmac</codeph>, and, optionally
       
    46 the functions used to manipulate hardware descriptors. </p> <p>Taking the
       
    47 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
       
    48     {
       
    49 public:
       
    50     TTemplateDmac();
       
    51     TInt Create();
       
    52 private:
       
    53     // from TDmac (PIL pure virtual)
       
    54     virtual void Transfer(const TDmaChannel&amp; aChannel, const SDmaDesHdr&amp; aHdr);
       
    55     virtual void StopTransfer(const TDmaChannel&amp; aChannel);
       
    56     virtual TBool IsIdle(const TDmaChannel&amp; aChannel);
       
    57     virtual TInt MaxTransferSize(TDmaChannel&amp; aChannel, TUint aFlags, TUint32 aPslInfo);
       
    58     virtual TUint MemAlignMask(TDmaChannel&amp; aChannel, TUint aFlags, TUint32 aPslInfo);
       
    59     // from TDmac (PIL virtual)
       
    60     virtual void InitHwDes(const SDmaDesHdr&amp; aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
       
    61                             TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
       
    62     virtual void ChainHwDes(const SDmaDesHdr&amp; aHdr, const SDmaDesHdr&amp; aNextHdr);
       
    63     virtual void AppendHwDes(const TDmaChannel&amp; aChannel, const SDmaDesHdr&amp; aLastHdr,
       
    64                              const SDmaDesHdr&amp; aNewHdr);
       
    65     virtual void UnlinkHwDes(const TDmaChannel&amp; aChannel, SDmaDesHdr&amp; aHdr);
       
    66     // other
       
    67     static void Isr(TAny* aThis);
       
    68     inline TDmaDesc* HdrToHwDes(const SDmaDesHdr&amp; aHdr);
       
    69 private:
       
    70     static const SCreateInfo KInfo;
       
    71 public:
       
    72     TTemplateSgChannel iChannels[KChannelCount];
       
    73     };
       
    74 </codeblock> <p>Notes: </p> <ul>
       
    75 <li id="GUID-4E8059FF-0BBC-5F65-9F66-3C96BC86FE55"><p>The array of channels
       
    76 must be defined in the PSL controller class because only the PSL knows what
       
    77 kind of channels are used. </p> </li>
       
    78 <li id="GUID-66E7787B-E933-5E17-9169-E0D245B9D27A"><p>The PSL controller class
       
    79 must be allocated in the BSS section of the DMA kernel extension. The second
       
    80 phase constructor must be called from the extension entry point. </p> </li>
       
    81 <li id="GUID-7306F4CB-5D0F-5E82-AC61-E068A48C9C9B"><p>The C++ constructor
       
    82 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.
       
    83 This structure defines what the PIL (platform-independent layer) needs to
       
    84 know about the underlying DMA controller. The template <codeph>TTemplateDmac</codeph> constructor
       
    85 just passes a <codeph>TDmac::ScreateInfo</codeph> structure, which defines
       
    86 the layout of the (base class managed) descriptor pool to the base class constructor
       
    87 through a ctor list: </p> <codeblock id="GUID-E00DD5C0-0976-58A0-B3C0-22DFD9216BC0" xml:space="preserve">TTemplateDmac::TTemplateDmac()
       
    88 //
       
    89 // Constructor.
       
    90 //
       
    91     : TDmac(KInfo)
       
    92     {}
       
    93 
       
    94           </codeblock> <p>where KInfo is a <codeph>TDmac::ScreateInfo</codeph> type. </p> </li>
       
    95 <li id="GUID-4C6FB95D-BE6F-5938-8AC3-824B3BB508EE"><p>The PSL controller class
       
    96 needs a second phase constructor. This is the <codeph>Create()</codeph> function,
       
    97 which must: </p> <ol id="GUID-33DC912F-C5B4-5F33-A427-62700522D958">
       
    98 <li id="GUID-F0E8A497-B09F-5DA0-A94A-3B08FC28707C"><p>call the second phase
       
    99 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>
       
   100 <li id="GUID-1FD43FAD-4F43-557E-9EF0-19C725DD5FF5"><p>perform any hardware-specific
       
   101 initialisation. </p> </li>
       
   102 <li id="GUID-A522B8D4-744B-5C5B-B684-C82F34462171"><p>bind and enable the
       
   103 DMA interrupt(s). </p> </li>
       
   104 </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
       
   105 and then initialises the template specific channel object members (the temporary
       
   106 descriptor fields used for appending requests to live channels), and performs
       
   107 platform specific initialisation for the interrupt dispatch of DMA interrupt
       
   108 events: </p> <codeblock id="GUID-FBCC8132-129C-53A4-99B7-290B56C3035D" xml:space="preserve">TInt TTemplateDmac::Create()
       
   109 //
       
   110 // Second phase construction.
       
   111 //
       
   112     {
       
   113     TInt r = TDmac::Create(KInfo);                            // Base class Create()
       
   114     if (r == KErrNone)
       
   115         {
       
   116         __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone);
       
   117         for (TInt i=0; i &lt; KChannelCount; ++i)
       
   118             {
       
   119             TDmaDesc* pD = HdrToHwDes(*iFreeHdr);
       
   120             iChannels[i].iTmpDes = pD;
       
   121             iChannels[i].iTmpDesPhysAddr = DesLinToPhys(pD);
       
   122             iFreeHdr = iFreeHdr-&gt;iNext;
       
   123             }
       
   124         r = Interrupt::Bind(EAsspIntIdDma, Isr, this);
       
   125         if (r == KErrNone)
       
   126             {
       
   127             // TO DO: Map DMA clients (requests) to DMA channels here.
       
   128 
       
   129             r = Interrupt::Enable(EAsspIntIdDma);
       
   130             }
       
   131         }
       
   132     return r;
       
   133     }
       
   134           </codeblock> </li>
       
   135 </ul> </section>
       
   136 <section id="GUID-0DBA2E68-7759-5447-B34B-14F237369CB1"><title>Implement the
       
   137 channel allocator</title> <p>Channel allocation is implemented in the PSL
       
   138 (platform-specific layer) because this is a hardware-specific operation. There
       
   139 are two basic options: </p> <ul>
       
   140 <li id="GUID-A9246754-F21B-5BFC-9FDB-2CE5C92D1FA3"><p>Preallocate, at design
       
   141 time, one channel per DMA-aware peripheral. This is the simplest approach,
       
   142 and it should be acceptable for most Symbian platform devices because the
       
   143 set of supported peripherals is closed. In this case, cookies passed by client
       
   144 device drivers map uniquely to DMA channels. </p> </li>
       
   145 <li id="GUID-C1164FA0-9B70-55C1-9C5A-2D02728FA67A"><p>Full dynamic allocation.
       
   146 This is a simple approach too, but DMA channels are, in general, not completely
       
   147 identical. For example, some channels may have greater priorities than others. </p> </li>
       
   148 </ul> <p>Mixed schemes are also possible, for example, client device driver
       
   149 cookies could be used to select a subset of channels, and dynamic allocation
       
   150 used inside this subset. </p> <p>Whatever option is chosen, the PSL must provide
       
   151 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>.
       
   152 The template implementation is: </p> <codeblock id="GUID-9C7F5850-F72B-5A16-9DA0-606FBABAB5F0" xml:space="preserve">TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)
       
   153 //
       
   154 //
       
   155 //
       
   156     {
       
   157     __KTRACE_OPT(KDMA, Kern::Printf("&gt;DmaChannelMgr::Open aOpenId=%d", aOpenId));
       
   158 
       
   159     __DMA_ASSERTA(aOpenId &lt; static_cast&lt;TUint32&gt;(KChannelCount));
       
   160 
       
   161     TDmaChannel* pC = Controller.iChannels + aOpenId;
       
   162     if (pC-&gt;IsOpened())
       
   163         pC = NULL;
       
   164     else
       
   165         {
       
   166         pC-&gt;iController = &amp;Controller;
       
   167         pC-&gt;iPslId = aOpenId;
       
   168         }
       
   169 
       
   170     return pC;
       
   171     }
       
   172       </codeblock> <p>The template DMA channel manager returns a pointer to
       
   173 a DMA channel if the channel has not been previously allocated. Note that
       
   174 since channels possess preset priorities, the device drivers must be aware
       
   175 of which channel(s) they require DMA service from and configure the DMA controller
       
   176 to route sources to allocated channels accordingly. </p> <p>The platform-specific
       
   177 cookies passed by client device drivers to the PSL must be defined somewhere
       
   178 so that client device drivers can access them. </p> </section>
       
   179 <section id="GUID-6B35E9A7-11D6-5B26-B562-934169503412"><title>[Optionally]
       
   180 implement channel cleanup</title> <p>In the template PSL (platform-specific
       
   181 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.
       
   182 This function is called by the PIL (platform-independent layer) when client
       
   183 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
       
   184 to perform any hardware-specific operation when the channel is closed, then
       
   185 the implementation of <codeph>DmaChannelMgr::Close()</codeph> should be updated
       
   186 to reflect that. </p> </section>
       
   187 <section id="GUID-C9439F04-0BCC-5BC7-B18B-5C1B88515340"><title>Implement the
       
   188 mandatory controller virtual functions</title> <p>The <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> class
       
   189 contains several pure virtual functions that must be implemented by the PSL
       
   190 (platform-specific layer): </p> <ul>
       
   191 <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>
       
   192 <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>
       
   193 <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>
       
   194 </ul> <p>These functions start and stop transfers on a DMA channel and are
       
   195 the main interface between the PIL (platform-independent layer) and the PSL.
       
   196 The implementation of these functions depends on the hardware available for
       
   197 performing DMA, and on the characteristics used to specify a DMA transfer: </p> <ul>
       
   198 <li id="GUID-81DA9FED-18F0-5205-9597-33542B0CB3CC"><p>the source and destination
       
   199 addresses </p> </li>
       
   200 <li id="GUID-D6684249-31CC-544B-8CEE-DD1D7FC8A8A1"><p>the burst size </p> </li>
       
   201 <li id="GUID-91D910DB-E1D7-5993-9ADB-6823662249D0"><p>the maximum transfer
       
   202 size </p> </li>
       
   203 <li id="GUID-C1926D7D-8349-5BA1-8E21-AB5D90486443"><p>the transfer width,
       
   204 i.e. number of bits per memory access </p> </li>
       
   205 <li id="GUID-C091D505-1088-56CA-8630-F1099B0A2234"><p>the memory alignment
       
   206 and endianness. </p> </li>
       
   207 </ul> <p>The DMA Framework manages the transfer descriptors according to the
       
   208 descriptor parameter passed into the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor
       
   209 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.
       
   210 The per-request transfer parameters are passed into the descriptors for each
       
   211 request issued by a driver. </p> <p><b>The
       
   212 transfer function: Transfer()</b> </p> <p>This function initiates a previously
       
   213 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&amp; aChannel, const SDmaDesHdr&amp; aHdr)
       
   214 //
       
   215 // Initiates a (previously constructed) request on a specific channel.
       
   216 //
       
   217     {
       
   218     const TUint8 i = static_cast&lt;TUint8&gt;(aChannel.PslId());
       
   219     TDmaDesc* pD = HdrToHwDes(aHdr);
       
   220 
       
   221     __KTRACE_OPT(KDMA, Kern::Printf("&gt;TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
       
   222 
       
   223     // TO DO (for instance): Load the first descriptor address into the DMAC and start it
       
   224     // by setting the RUN bit.
       
   225     (void) *pD, (void) i;
       
   226 
       
   227     }
       
   228         </codeblock> <p><b>The
       
   229 stop transfer function: StopTransfer()</b> </p> <p>This function requires
       
   230 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&amp; aChannel)
       
   231 //
       
   232 // Stops a running channel.
       
   233 //
       
   234     {
       
   235     const TUint8 i = static_cast&lt;TUint8&gt;(aChannel.PslId());
       
   236 
       
   237     __KTRACE_OPT(KDMA, Kern::Printf("&gt;TTemplateDmac::StopTransfer channel=%d", i));
       
   238 
       
   239     // TO DO (for instance): Clear the RUN bit of the channel.
       
   240     (void) i;
       
   241 
       
   242     }
       
   243         </codeblock> <p><b>The
       
   244 function: IsIdle()</b> </p> <p> <codeph>IsIdle()</codeph> returns the state
       
   245 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&amp; aChannel)
       
   246 //
       
   247 // Returns the state of a given channel.
       
   248 //
       
   249     {
       
   250     const TUint8 i = static_cast&lt;TUint8&gt;(aChannel.PslId());
       
   251 
       
   252     __KTRACE_OPT(KDMA, Kern::Printf("&gt;TTemplateDmac::IsIdle channel=%d", i));
       
   253 
       
   254     // TO DO (for instance): Return the state of the RUN bit of the channel.
       
   255     // The return value should reflect the actual state.
       
   256     (void) i;
       
   257 
       
   258     return ETrue;
       
   259     }
       
   260         </codeblock> </section>
       
   261 <section id="GUID-A362A7CF-3674-525C-8114-485315E6594B"><title>Implement the
       
   262 non-mandatory controller virtual functions</title> <p>The following auxiliary
       
   263 functions are used to implement the scatter-gather transfer mode behaviour
       
   264 by creating and manipulating the linked list of transfer fragment headers
       
   265 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
       
   266 class functions when the instance of the <codeph>TDmac</codeph> derived class
       
   267 reports itself as being capable of scatter-gather operations. </p> <ul>
       
   268 <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>
       
   269 <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>
       
   270 <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>
       
   271 </ul> <p><b>First
       
   272 scatter-gather support function: InitHwDes()</b> </p> <p>This is a function
       
   273 for creating a scatter-gather list. From the information in the passed-in
       
   274 request, the function sets up the descriptor with that fragment's: </p> <ul>
       
   275 <li id="GUID-098E886D-D98D-5AC9-BB25-7FF8E6F0D05B"><p>source and destination
       
   276 address </p> </li>
       
   277 <li id="GUID-83440454-B955-55C8-BF10-DF86CDA0C466"><p>size </p> </li>
       
   278 <li id="GUID-294D3B08-0A64-534D-858F-F43759A2DC59"><p>driver/DMA controller
       
   279 specific transfer parameters: memory/peripheral, burst size, transfer width. </p> </li>
       
   280 </ul> <p>This is the template implementation: </p> <codeblock id="GUID-EB6F9C76-EC23-5464-A6C5-AB0B36717D2B" xml:space="preserve">void TTemplateDmac::InitHwDes(const SDmaDesHdr&amp; aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
       
   281                               TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/)
       
   282 //
       
   283 // Sets up (from a passed in request) the descriptor with that fragment's source and destination address,
       
   284 // the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral,
       
   285 // burst size, transfer width).
       
   286 //
       
   287     {
       
   288     TDmaDesc* pD = HdrToHwDes(aHdr);
       
   289 
       
   290     __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
       
   291 
       
   292     // Unaligned descriptor? Error in generic layer!
       
   293     __DMA_ASSERTD(IsHwDesAligned(pD));
       
   294 
       
   295     pD-&gt;iSrcAddr = (aFlags &amp; KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc);
       
   296     pD-&gt;iDestAddr = (aFlags &amp; KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest);
       
   297     pD-&gt;iCmd = DcmdReg(aCount, aFlags, aPslInfo);
       
   298     pD-&gt;iDescAddr = TDmaDesc::KStopBitMask;
       
   299     }
       
   300 
       
   301           </codeblock> <p><b>Second
       
   302 scatter-gather support function: ChainHwDes()</b> </p> <p>If the framework
       
   303 needs to fragment the client’s request, for transfer size or memory discontiguousness
       
   304 reasons, then the framework calls this function. It chains hardware descriptors
       
   305 together by setting the next pointer of the original descriptor to the physical
       
   306 address of the descriptor to be chained. It assumes that the DMAC channel
       
   307 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&amp; aHdr, const SDmaDesHdr&amp; aNextHdr)
       
   308 //
       
   309 // Chains hardware descriptors together by setting the next pointer of the original descriptor
       
   310 // to the physical address of the descriptor to be chained.
       
   311 //
       
   312     {
       
   313     TDmaDesc* pD = HdrToHwDes(aHdr);
       
   314     TDmaDesc* pN = HdrToHwDes(aNextHdr);
       
   315 
       
   316     __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
       
   317 
       
   318     // Unaligned descriptor? Error in generic layer!
       
   319     __DMA_ASSERTD(IsHwDesAligned(pD) &amp;&amp; IsHwDesAligned(pN));
       
   320 
       
   321     // TO DO: Modify pD-&gt;iCmd so that no end-of-transfer interrupt gets raised any longer.
       
   322 
       
   323     pD-&gt;iDescAddr = DesLinToPhys(pN);
       
   324     }
       
   325 
       
   326 </codeblock> <p><b>Third
       
   327 scatter-gather support function: AppendHwDes()</b> </p> <p>This function is
       
   328 called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base class when a driver request is
       
   329 called for a channel that is still active, i.e. where the intent is to provide
       
   330 data streaming so that the target device is constantly provided with data;
       
   331 for example, an audio device playing a track. In this case, the function provided
       
   332 by the derived class must: </p> <ul>
       
   333 <li id="GUID-F94FBAA8-2A0D-5863-BA09-0EC1D61005A9"><p>stop the DMAC to prevent
       
   334 any corruption of the scatter-gather list while appending the new fragment
       
   335 descriptor </p> </li>
       
   336 <li id="GUID-AEF81B78-73D8-5B70-AFE4-0AEA7862CB74"><p>append the new descriptor </p> </li>
       
   337 <li id="GUID-2304F2D4-833E-5F75-B88E-C794DF9D984E"><p>re-enable the channel,
       
   338 ideally before the target has detected the gap in service. </p> </li>
       
   339 </ul> <p>This is the template implementation: </p> <codeblock id="GUID-18512439-C781-5267-ADBC-B9047942F800" xml:space="preserve">void TTemplateDmac::AppendHwDes(const TDmaChannel&amp; aChannel, const SDmaDesHdr&amp; aLastHdr,
       
   340                                 const SDmaDesHdr&amp; aNewHdr)
       
   341 //
       
   342 // Appends a descriptor to the chain while the channel is running.
       
   343 //
       
   344     {
       
   345     const TUint8 i = static_cast&lt;TUint8&gt;(aChannel.PslId());
       
   346 
       
   347     TDmaDesc* pL = HdrToHwDes(aLastHdr);
       
   348     TDmaDesc* pN = HdrToHwDes(aNewHdr);
       
   349 
       
   350     __KTRACE_OPT(KDMA, Kern::Printf("&gt;TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
       
   351                                     i, pL, pN));
       
   352     // Unaligned descriptor? Error in generic layer!
       
   353     __DMA_ASSERTD(IsHwDesAligned(pL) &amp;&amp; IsHwDesAligned(pN));
       
   354 
       
   355     TPhysAddr newPhys = DesLinToPhys(pN);
       
   356 
       
   357     const TInt irq = NKern::DisableAllInterrupts();
       
   358     StopTransfer(aChannel);
       
   359 
       
   360     pL-&gt;iDescAddr = newPhys;
       
   361     const TTemplateSgChannel&amp; channel = static_cast&lt;const TTemplateSgChannel&amp;&gt;(aChannel);
       
   362     TDmaDesc* pD = channel.iTmpDes;
       
   363 
       
   364     // TO DO: Implement the appropriate algorithm for appending a descriptor here.
       
   365     (void) *pD, (void) i;
       
   366 
       
   367     NKern::RestoreInterrupts(irq);
       
   368 
       
   369     __KTRACE_OPT(KDMA, Kern::Printf("&lt;TTemplateDmac::AppendHwDes"));
       
   370     }
       
   371     </codeblock> </section>
       
   372 <section id="GUID-F5968000-0C3E-5E53-A2D5-120B81F3140F"><title>Implement an
       
   373 interrupt service routine</title> <p>The interrupt service routine needs to
       
   374 do the following: </p> <ul>
       
   375 <li id="GUID-CE55E999-0886-5620-87BA-99A36D694FD4"><p>identify the channel
       
   376 that raised the interrupt </p> </li>
       
   377 <li id="GUID-02467F17-DC1E-552C-B1C2-D3C2CCE12347"><p>decide whether the interrupt
       
   378 was raised because of a successful data transfer or because of an error </p> </li>
       
   379 <li id="GUID-0D5FDA57-A45E-54E5-A69C-64D22B916AB4"><p>call the base class
       
   380 function <codeph>TDmac::HandleIsr()</codeph>, which queues a DFC, or increments
       
   381 the number of pending interrupts if a DFC is already queued. </p> </li>
       
   382 </ul> <p>This is the template implementation: </p> <codeblock id="GUID-4CFCA5A1-9657-55F1-BE3C-AFF1F3974F80" xml:space="preserve">void TTemplateDmac::Isr(TAny* aThis)
       
   383 //
       
   384 // This ISR reads the interrupt identification and calls back into the base class
       
   385 // interrupt service handler with the channel identifier and an indication whether the
       
   386 // transfer completed correctly or with an error.
       
   387 //
       
   388     {
       
   389     TTemplateDmac&amp; me = *static_cast&lt;TTemplateDmac*&gt;(aThis);
       
   390 
       
   391     // TO DO: Implement the behaviour described above, call HandleIsr().
       
   392 
       
   393     HandleIsr(me.iChannels[5], 0);                            // Example
       
   394 
       
   395     }
       
   396      </codeblock> </section>
       
   397 <section id="GUID-D7F410A1-DC70-515D-A00D-3955B534C62F"><title>Implement the
       
   398 test support table and function</title> <p>The DMA Framework comes with a
       
   399 test harness that can be used to validate the port if the underlying DMA controller
       
   400 supports memory to memory transfers. </p> <p>The test harness needs to know
       
   401 about the capabilities of the port being tested. The PSL provides the global
       
   402 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
       
   403 that contains this information. In the template PSL, this structure is initialised
       
   404 to binary zeroes. Before using the test harness, it must be initialised with
       
   405 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>
       
   406 <section id="GUID-D452D2CD-D251-50F4-818E-E7125501CE8F"><title>Optimise the
       
   407 performance of critical functions</title> <p>You can optionally optimise critical
       
   408 functions by writing them in assembler. The two candidates for an assembler
       
   409 rewrite are: </p> <ul>
       
   410 <li id="GUID-157E6F4A-0310-5923-B446-040F75E469D4"><p>The interrupt service
       
   411 routine </p> </li>
       
   412 <li id="GUID-74C9D4DB-9CA9-5C5E-A475-B6840EBC2245"><p>In scatter-gather mode,
       
   413 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
       
   414 a transfer when appending a new descriptor chain to an existing one. </p> </li>
       
   415 </ul> </section>
       
   416 <section id="GUID-A2AF293F-558A-5F69-821F-EC2B202A5A4F"><title>Extend the
       
   417 framework with platform-specific functionality</title> <p>There are two ways
       
   418 of extending the DMA Framework: </p> <ol id="GUID-D6C660FC-FF23-55B2-B91E-4BC04C592059">
       
   419 <li id="GUID-4453F4C2-3444-5A3E-94C7-BE6320B1EF89"><p>to provide platform-specific
       
   420 functionality on a per-channel basis. </p> </li>
       
   421 <li id="GUID-C0C6A072-134A-5753-A6DC-185F3975C2A6"><p>to provide platform-specific
       
   422 functionality on a <i>channel independent</i> basis. </p> </li>
       
   423 </ol> <p>In the first case, the PSL provides an implementation of the virtual
       
   424 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
       
   425 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
       
   426 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
       
   427 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>
       
   428 </conbody></concept>