Adaptation/GUID-AC560324-798C-5D0A-B23D-2419A7688A5B.dita
changeset 15 307f4279f433
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Adaptation/GUID-AC560324-798C-5D0A-B23D-2419A7688A5B.dita	Fri Oct 15 14:32:18 2010 +0100
@@ -0,0 +1,583 @@
+<?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-AC560324-798C-5D0A-B23D-2419A7688A5B" xml:lang="en"><title>Channel
+Implementation</title><shortdesc>Describes how to implement the physical channels with the template
+port. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
+<p>A Sound Driver PDD must implement physical channels to use the audio hardware
+of the phone. The main Sound Driver PDD class is derived from <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita"><apiname>DSoundScPdd</apiname></xref>.
+A Sound Driver PDD that provides record and playback functions must implement
+a record driver channel and a playback driver channel. </p>
+<p>The template defines two classes: <codeph>DTemplateSoundScRxPdd</codeph> and <codeph>DTemplateSoundScTxPdd</codeph>,
+corresponding to record and playback respectively. The classes provide default
+implementations for the virtual functions defined by <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita"><apiname>DSoundScPdd</apiname></xref>,
+together with a constructor and destructor, and typically need little or no
+modification. </p>
+<section id="GUID-61725EEB-5114-5A85-9C28-57A47F14000C"><title>PDD class constructor</title> <p>Implement
+the PDD class constructor for both the playback and record driver channels.
+This is normally limited to </p> <ul>
+<li id="GUID-E02B0EE1-5171-5E9F-9BFE-FFAB6E15B290"><p>initialising any data
+members that need values other than zero </p> </li>
+<li id="GUID-4B39AEC4-0A02-5099-9805-F35B2AF4AD90"><p>initialising any DFC
+call-backs added. </p> </li>
+</ul> <p>Access to hardware has the potential to fail and so should be deferred
+to the second stage constructor <xref href="GUID-AC560324-798C-5D0A-B23D-2419A7688A5B.dita#GUID-AC560324-798C-5D0A-B23D-2419A7688A5B/GUID-F66BF339-FCE6-5859-87D1-7A0B0ED69D84">DoCreate()</xref>. </p> </section>
+<section id="GUID-CD12E6E9-C363-5CF9-91E1-694C34DE2BD9"><title>PDD class destructor</title> <p>Implement
+the PDD class destructor for both the playback and record driver channels.
+The destructor must release any hardware and Symbian platform resources that
+have been allocated to the driver. For example, this might include: </p> <ul>
+<li id="GUID-6D33C44B-B88F-504B-B750-FF010A72A290"><p>unbinding ISRs </p> </li>
+<li id="GUID-9DF0D93B-6782-5E94-80EB-A806BC1AB6B9"><p>cancelling private DFCs </p> </li>
+<li id="GUID-157C24A6-52F6-5BF1-BF94-035394F274F5"><p>closing DMA channels </p> </li>
+<li id="GUID-47452140-FA8E-55A8-BE2D-32AC87FF215E"><p>deleting any mono-to-stereo
+conversion buffers </p> </li>
+</ul> <p>The template versions of this function delete each DMA request object
+created in the PDD second stage constructor <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-C0CA28E4-2356-333D-B708-CBE469F1614F"><apiname>DSoundScPdd::DoCreate()</apiname></xref> and
+close the DMA channel. </p> </section>
+<section id="GUID-F66BF339-FCE6-5859-87D1-7A0B0ED69D84"><title>DoCreate()</title> <p>Implement
+a PDD class second stage constructor for both the playback and record driver
+channels. In the template version, the function <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-C0CA28E4-2356-333D-B708-CBE469F1614F"><apiname>DSoundScPdd::DoCreate()</apiname></xref> is
+called from the PDD factory when a channel is opened on the device. Generally,
+any hardware or Symbian platform resources required by the driver
+channel should be acquired here. However, powering up the sound device should
+be deferred to the <xref href="GUID-AC560324-798C-5D0A-B23D-2419A7688A5B.dita#GUID-AC560324-798C-5D0A-B23D-2419A7688A5B/GUID-B72057E6-B93C-505F-9789-83251D09B78E">PowerUp()</xref> function.
+Operations performed by this function include: </p> <ul>
+<li id="GUID-C3E2E6ED-14AE-52D1-9F11-618DCE7D2C1E"><p>binding an ISR to an
+audio related interrupt </p> </li>
+<li id="GUID-129BD014-9302-50AE-A33B-728D40DBF428"><p>open a DMA channel </p> </li>
+<li id="GUID-51B51BEC-B8B8-50CF-8618-BB0B5B00F999"><p>allocate a mono-to-stereo
+conversion buffer </p> </li>
+</ul> <p>The template versions of this function include code to set up a DMA
+channel. This involves opening a DMA channel in the appropriate direction
+for the driver channel and then allocating a set of DMA request objects. However,
+to use this implementation you must supply the missing platform specific information: </p> <ul>
+<li id="GUID-64F62CF9-9D26-5E39-A632-39DF91AB1E98"><p>Provide values for the
+maximum number of DMA requests outstanding on the DMA channel. These values
+determine the number of separate DMA request objects allocated for the DMA
+channel, and so the number of transfer fragments that the PDD can accept from
+the LDD at any time. See <xref href="GUID-15FDDEED-89F1-5BE5-97AD-8DFD3640369A.dita">playback</xref> and <xref href="GUID-4AEF7595-17C0-513E-9568-B212E6194388.dita">record</xref>. </p> </li>
+<li id="GUID-60C86EBD-B26F-501D-B7D5-CE113D4368C0"><p>Set the appropriate
+DMA values for your device within the file <filepath>soundsc_plat.h</filepath>.
+These values, renamed in section <xref href="GUID-C6ABE2CA-901E-55F1-9837-7018A1612BCF.dita">copying
+the template port implementation</xref> to reflect your device name, are <codeph>KTemplateMaxTxDmaRequests</codeph> or <codeph>KTemplateMaxRxDmaRequests</codeph> for playback and record respectively. </p> </li>
+<li id="GUID-BBF4F320-22A7-54AE-ACD1-6C10138F5031"><p>Setup the DMA channel
+information for the device. This includes the following members of <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-6B973278-8BE7-3CE5-97D8-60E8D3F4D473"><apiname>TDmaChannel::SCreateInfo</apiname></xref>. </p> <ul>
+<li id="GUID-084CF2BA-308D-5F32-9BC2-C5B39DEC497B"><p> <codeph>iCookie</codeph>:
+The platform specific ID used by the DMA controller to select the DMA channel
+to open. </p> </li>
+<li id="GUID-7EE1F596-9FB5-5C29-8130-097CE6129F91"><p> <codeph>iDesCount</codeph>:
+The number of DMA descriptors the DMA controller should create. This is typically
+set with the same value as <codeph>KTemplateMaxTxDmaRequests</codeph> or <codeph>KTemplateMaxRxDmaRequests</codeph>. </p> </li>
+<li id="GUID-0B12DDF1-AC34-5592-AC55-E0363C60449A"><p> <codeph>iDfcQ</codeph>:
+The DFC queue to use to service DMA interrupts. This should point to the same
+DFC queue that is returned to the LDD for client request handling. See the <xref href="GUID-AC560324-798C-5D0A-B23D-2419A7688A5B.dita#GUID-AC560324-798C-5D0A-B23D-2419A7688A5B/GUID-32C77B77-76CE-54AE-B791-28A7DD309A7D">DfcQ()</xref> section. </p> </li>
+<li id="GUID-AE4E59DD-4FBB-54A8-BE79-F4138AB34D5C"><p> <codeph>iDfcPriority</codeph>:
+The DFC priority. This should be set to a higher value than that used by the
+LDD for handling client requests. For example, higher than one. </p> </li>
+</ul> </li>
+</ul> </section>
+<section id="GUID-32C77B77-76CE-54AE-B791-28A7DD309A7D"><title>DfcQ()</title> <p>Make
+sure that the template version of the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-C41B9733-BE86-3CF1-83A7-150EC9D35249"><apiname>DSoundScPdd::DfcQ()</apiname></xref> function
+is appropriate for your configuration. This function has the following signature: </p> <codeblock id="GUID-28E301B7-C032-5F6E-BCA7-A6D20FC541EA" xml:space="preserve">TDfcQue* DfcQ()</codeblock> <p>The
+supplied implementation is as follows </p> <codeblock id="GUID-D95DC9F9-C68A-50E2-ADA6-8D1268A18147" xml:space="preserve">TDfcQue* DTemplateSoundScTxPdd::DfcQ()
+    {
+    return(iPhysicalDevice-&gt;iDfcQPtr);
+    }</codeblock> <p>Many requests are executed in the context of a kernel-side
+thread. Rather than assign a kernel thread for the driver in the LDD, the
+Sound Driver allows the PDD to specify the DFC thread returned via the <xref href="GUID-71190437-912E-3E23-8E68-4FA8FF913D7A.dita"><apiname>DfcQ()</apiname></xref> function,
+which it calls when the driver channel is opened. </p> <p>The default implementation
+for the record and playback driver channels, returns a pointer to the DFC
+queue created by the PDD factory class. </p> <p>See also <xref href="GUID-1138D29D-2EC5-59DF-9AA7-2D863FBC024F.dita">Implementing
+the PDD factory</xref>  </p> </section>
+<section id="GUID-B549F062-061D-5876-AB43-AC10C62477EE"><title>GetChunkCreateInfo()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-9F845935-A6AA-320B-AF09-F121F95C44B2"><apiname>DSoundScPdd::GetChunkCreateInfo()</apiname></xref> function for both
+the playback and record driver channels. This function has the following signature: </p> <codeblock id="GUID-934D39E5-5DDE-5165-BCED-255CA6D0B0F2" xml:space="preserve">void DSoundScPdd::GetChunkCreateInfo(TChunkCreateInfo&amp; aChunkCreateInfo)</codeblock> <p>The
+supplied implementation is as follows: </p> <codeblock id="GUID-47334636-5E5D-59CF-A894-62747DD648BD" xml:space="preserve">void DTemplateSoundScTxPdd::GetChunkCreateInfo(TChunkCreateInfo&amp; aChunkCreateInfo)
+    {
+    __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::GetChunkCreateInfo"));
+
+    // TO DO: (mandatory)
+    // Setup the shared chunk create information in aChunkCreateInfo for this play device.
+    aChunkCreateInfo.iType=TChunkCreateInfo::ESharedKernelMultiple;
+    // aChunkCreateInfo.iMapAttr=???
+    aChunkCreateInfo.iOwnsMemory=ETrue;                 // Using RAM pages.
+    aChunkCreateInfo.iDestroyedDfc=NULL;                // No chunk destroy DFC.
+    }</codeblock> <p>The PDD must initialise the <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita"><apiname>TChunkCreateInfo</apiname></xref> object
+with the information that defines the characteristics of the shared chunk
+required for the audio device. This function is called by the LDD just before
+it creates a shared chunk for the channel, in response to an <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-1978D84C-6E2A-39C0-AF5F-17C85E5B25B4"><apiname>RSoundSc::SetBufferChunkCreate()</apiname></xref> request
+from the client. </p> <p>Values for the following data members must be supplied
+by the PDD: </p> <ul>
+<li id="GUID-10F7ED98-299F-5D90-A7EC-85BD97BBECEF"><p> <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-4384AF76-CECE-3B86-BE92-375C1DEA36DA"><apiname>TChunkCreateInfo::iType</apiname></xref>  </p> </li>
+<li id="GUID-10159693-8680-5CD7-88C8-A967DDC53024"><p> <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-4D355352-04CA-34D2-B1F4-684E07E7DDE9"><apiname>TChunkCreateInfo::iMapAttr</apiname></xref>  </p> </li>
+<li id="GUID-06459B1A-5D5A-5013-912D-0C52E7FD398A"><p> <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-106850A0-5498-387F-AF70-F9D04EB6318D"><apiname>TChunkCreateInfo::iOwnsMemory</apiname></xref>  </p> </li>
+<li id="GUID-D8DE49EB-04D5-50BA-8CEA-7EFFA7584A74"><p> <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-58271733-146A-3ECB-91AC-C38BD2ADC9A0"><apiname>TChunkCreateInfo::iDestroyedDfc</apiname></xref>  </p> </li>
+</ul> <p>The data member <xref href="GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4.dita#GUID-51F7DBCF-BFB6-31F9-8882-5D263A1AD4B4/GUID-3BE6D452-84D0-3E80-8238-7A9114A89ED5"><apiname>TChunkCreateInfo::iMaxSize</apiname></xref> is
+calculated by the LDD so there is no need to define it. </p> <p>See <xref href="GUID-51514A4B-0220-557B-9F7A-FB110CEFEF10.dita">How to share chunks</xref>. </p> </section>
+<section id="GUID-9D4D9F06-8C88-51C1-9E29-D0B95B523A8D"><title>Caps()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-B80B86C6-696A-37AA-9ACD-2BC76B88762C"><apiname>DSoundScPdd::Caps()</apiname></xref> function for both the playback
+and record driver channels. The function has the following signature: </p> <codeblock id="GUID-8306A135-350C-5F8D-B51D-F8A2EED41244" xml:space="preserve">void DSoundScPdd::Caps(TDes8&amp; aCapsBuf) const</codeblock> <p>The
+supplied implementation is as follows: </p> <codeblock id="GUID-27BE7DD7-D42B-54BA-AC77-1201C1F09F68" xml:space="preserve">void DTemplateSoundScTxPdd::Caps(TDes8&amp; aCapsBuf) const
+    {
+    __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::Caps"));
+    
+    // Copy iCaps back.
+    TPtrC8 ptr((const TUint8*)&amp;iCaps,sizeof(iCaps));
+    aCapsBuf.FillZ(aCapsBuf.MaxLength());
+    aCapsBuf=ptr.Left(Min(ptr.Length(),aCapsBuf.MaxLength()));      
+    }</codeblock> <p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita"><apiname>TSoundFormatsSupportedV02</apiname></xref> is the
+main audio capabilities class. The PDD must fill this object with the capabilities
+for the particular audio device. the LDD uses this to get the play or record
+capabilities of a particular sound device once a driver channel to the device
+has been opened. </p> <p>Values for the following variables must be supplied
+by the PDD: </p> <ul>
+<li id="GUID-2F03F186-D9AF-5431-B3F8-D3B794352208"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-1FE2868A-1823-308A-B1C9-2DAD557F6F3A"><apiname>TSoundFormatsSupportedV02::iDirection</apiname></xref>  </p> <ul>
+<li id="GUID-053B114E-2A52-53FD-912F-F8FF890601C4"><p> <xref href="GUID-AF772B74-0D5F-3270-BA61-2503BA5DFE6B.dita"><apiname>ESoundDirRecord</apiname></xref>  </p> </li>
+<li id="GUID-CEADC6F1-6016-5AB1-9349-EEFB63EF26AA"><p> <xref href="GUID-708043EB-5ED5-3923-B41A-321AD7DF3D8C.dita"><apiname>ESoundDirPlayback</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-95FC1D2B-BBFB-52DC-ADE3-BA980E7E46F3"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-75B0E2F7-44BE-3A97-B482-E1CB29D9F2E5"><apiname>TSoundFormatsSupportedV02::iChannels</apiname></xref>  </p> <ul>
+<li id="GUID-998425C3-E73B-5DB4-94F8-10BDCFBBE779"><p> <xref href="GUID-65BCF594-59A1-335F-AADB-1920E7AD3F71.dita"><apiname>KSoundMonoChannel</apiname></xref>  </p> </li>
+<li id="GUID-7D5EE578-16AC-56A0-B064-6000F5A9C2DF"><p> <xref href="GUID-4E63CE9C-C604-3B2C-993D-9A0502A39064.dita"><apiname>KSoundStereoChannel</apiname></xref>  </p> </li>
+<li id="GUID-0C17CB17-7452-5A1A-B76D-75A57960BDE8"><p> <xref href="GUID-30E8F803-39E1-3F53-AB5A-3B593BC1D69F.dita"><apiname>KSoundThreeChannel</apiname></xref>  </p> </li>
+<li id="GUID-E1DE0CD0-DD63-5140-A5C5-7141A5E9632D"><p> <xref href="GUID-BD021640-3457-3721-9DF1-A15EE8A874AC.dita"><apiname>KSoundFourChannel</apiname></xref>  </p> </li>
+<li id="GUID-E59E9D5E-F360-52FD-A0D0-C7CDAE5593DC"><p> <xref href="GUID-3E3B5485-F69B-3ECC-A0A4-12183444E61F.dita"><apiname>KSoundFiveChannel</apiname></xref>  </p> </li>
+<li id="GUID-56DD5098-0C0C-5175-B375-766FE628C359"><p> <xref href="GUID-83C9F5FE-DE44-3940-B738-BD4486293C39.dita"><apiname>KSoundSixChannel</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-A6847CF6-48DC-510E-BCFF-33E7E5FB0161"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-1F79E9BB-BF7C-31AD-AA0C-A85748F4231A"><apiname>TSoundFormatsSupportedV02::iRates</apiname></xref>  </p> <ul>
+<li id="GUID-99377F03-BA89-5DB0-AC4D-5F8892EB1F65"><p> <xref href="GUID-F98BADA5-852B-3859-B74A-B9747F79A754.dita"><apiname>KSoundRate7350Hz</apiname></xref>  </p> </li>
+<li id="GUID-99FFC99B-740B-5809-9C75-C8CC1157F4E3"><p> <xref href="GUID-47512813-5787-3328-9980-399AA782E6A2.dita"><apiname>KSoundRate8000Hz</apiname></xref>  </p> </li>
+<li id="GUID-D2C75BB5-5D8B-556B-A5BF-6A8C24D07D74"><p> <xref href="GUID-A622C93B-DF18-359D-B74A-0F90695900B7.dita"><apiname>KSoundRate8820Hz</apiname></xref>  </p> </li>
+<li id="GUID-83D98EBD-AD0E-588E-8CFD-59B44C22FE6A"><p> <xref href="GUID-165180AC-1227-30BF-97DA-860C3AC3AA4E.dita"><apiname>KSoundRate9600Hz</apiname></xref>  </p> </li>
+<li id="GUID-8D99D6B7-7FA7-5B8A-BEB9-2D982273C201"><p> <xref href="GUID-8DF1D395-4AC1-38AA-9F6A-C8867B1F4A60.dita"><apiname>KSoundRate11025Hz</apiname></xref>  </p> </li>
+<li id="GUID-98353A3A-EFAC-5B6C-A779-8F12BB9150BA"><p> <xref href="GUID-512150A4-0796-3016-9CBC-83117E2930ED.dita"><apiname>KSoundRate12000Hz</apiname></xref>  </p> </li>
+<li id="GUID-C27DD198-13FA-522A-9079-0BAA37094E16"><p> <xref href="GUID-892B4698-4914-348B-AB88-A1AC33D1E5EE.dita"><apiname>KSoundRate14700Hz</apiname></xref>  </p> </li>
+<li id="GUID-71087DE2-06A9-536A-94DF-74FFFCB2F0DF"><p> <xref href="GUID-1A199051-5D76-396B-AA44-89506A128BFF.dita"><apiname>KSoundRate16000Hz</apiname></xref>  </p> </li>
+<li id="GUID-666FA027-30AF-593B-894B-443B5C57E2DF"><p> <xref href="GUID-4021CE80-6667-36BB-9839-583E84AB9E83.dita"><apiname>KSoundRate22050Hz</apiname></xref>  </p> </li>
+<li id="GUID-9D0D7E14-1FBE-5C80-A108-D3903D57ED49"><p> <xref href="GUID-73C38AA3-92AD-3EF0-BF60-3A207CD29C0E.dita"><apiname>KSoundRate24000Hz</apiname></xref>  </p> </li>
+<li id="GUID-721DCA57-6E9B-5B02-9EA4-7640C652C5CE"><p> <xref href="GUID-9092C33B-C406-3044-AC8F-885F3EAE8B86.dita"><apiname>KSoundRate29400Hz</apiname></xref>  </p> </li>
+<li id="GUID-5362CD78-1981-559B-9E1B-C999CDC8E3D9"><p> <xref href="GUID-0237DB93-3C16-3DCF-836E-CDECE95EAB1E.dita"><apiname>KSoundRate32000Hz</apiname></xref>  </p> </li>
+<li id="GUID-61D0A788-2160-538F-82DB-414E6A34EC97"><p> <xref href="GUID-D3045D52-3092-3CCA-9AA5-05DE1ACAB92C.dita"><apiname>KSoundRate44100Hz</apiname></xref>  </p> </li>
+<li id="GUID-28474DAC-AD25-506B-9112-F56825F845D2"><p> <xref href="GUID-DBD2AD6A-79F9-3D94-B6CB-1ED1E45F401A.dita"><apiname>KSoundRate48000Hz</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-CB112345-C035-5F7E-9AE5-B5222FF4F0A9"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-21F664A7-046E-3B1F-8C0B-A8B0EC0EC16C"><apiname>TSoundFormatsSupportedV02::iEncodings</apiname></xref>  </p> <ul>
+<li id="GUID-F5833DD3-D273-5B62-9F4B-FEEC51D8CDF2"><p> <xref href="GUID-5BE58F42-47B2-3EB8-9F3B-DEF019C79499.dita"><apiname>KSoundEncodings8BitPCM</apiname></xref>  </p> </li>
+<li id="GUID-B58CB616-CDCD-5CD0-AEC4-622F5AAB2474"><p> <xref href="GUID-790BA733-2B34-33B2-BF7B-7113DB1856A6.dita"><apiname>KSoundEncodings16BitPCM</apiname></xref>  </p> </li>
+<li id="GUID-A4019328-CC8B-5224-8808-F3822230C389"><p> <xref href="GUID-EAB5A509-B0D6-3E2F-8106-D87A7C9D504F.dita"><apiname>KSoundEncodings24BitPCM</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-52DDB751-925B-5CC5-81F9-6F65A9D2039E"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-7950BC29-5C2E-34E0-B037-DDDDE0261DB7"><apiname>TSoundFormatsSupportedV02::iDataFormats</apiname></xref>  </p> <ul>
+<li id="GUID-AD7EA560-7914-5D9D-B548-14DB3FA4AC7A"><p> <xref href="GUID-E02D661C-430F-306F-BD12-42238A91D83A.dita"><apiname>KSoundDataFormatInterleaved</apiname></xref>  </p> </li>
+<li id="GUID-36EAAA69-B18A-555A-9646-FB8F6EC66505"><p> <xref href="GUID-ACC09AC6-A29B-3926-8AE4-4DA60416A3C1.dita"><apiname>KSoundDataFormatNonInterleaved</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-905CC707-760B-52F3-A942-0ADA02B69FA8"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-6F2D37B3-C465-3C77-A861-7FF9061F8EB9"><apiname>TSoundFormatsSupportedV02::iRequestMinSize</apiname></xref>  </p> </li>
+<li id="GUID-8FCD4F3E-F70F-5E1B-8952-B667DC9D4AD2"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-472BCD65-11CE-3AEE-8DAE-9E56523AC096"><apiname>TSoundFormatsSupportedV02::iRequestAlignment</apiname></xref>  </p> </li>
+<li id="GUID-749CE201-0554-5202-ABFC-FF9C0C4B1C1A"><p> <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita#GUID-39915413-31A6-360F-9758-5DBDF9D70103/GUID-AB35243B-ECD9-3268-A6FF-5079D1A45EA0"><apiname>TSoundFormatsSupportedV02::iHwConfigNotificationSupport</apiname></xref> </p> </li>
+</ul> <p>Many of the attribute ranges are passed as bit settings, and can
+assume all the values independently of one another. </p> <p>The following
+is a portion of the <xref href="GUID-161BA615-FD2C-3A7E-992E-FBBED621CBBB.dita"><apiname>Caps()</apiname></xref> function for the template port
+for the playback path of the AC97 Controller Unit (UCB140) codec device. </p> <p>The
+PDD maintains a <xref href="GUID-39915413-31A6-360F-9758-5DBDF9D70103.dita"><apiname>TSoundFormatsSupportedV02</apiname></xref> object as one
+of its data members named <codeph>iCaps</codeph>. The contents of <codeph>iCaps</codeph> is
+copied into the descriptor and passed as an argument to the <xref href="GUID-161BA615-FD2C-3A7E-992E-FBBED621CBBB.dita"><apiname>Caps()</apiname></xref> function: </p> <codeblock id="GUID-21B70DCD-7133-53A1-AE5C-848E0F68DF43" xml:space="preserve">void DTemplateSoundScTxPdd::Caps(TDes8&amp; aCapsBuf) const
+    {
+     __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::Caps"));
+    
+     // Copy iCaps back.
+     TPtrC8 ptr((const TUint8*)&amp;iCaps,sizeof(iCaps));
+     aCapsBuf.FillZ(aCapsBuf.MaxLength());
+     aCapsBuf=ptr.Left(Min(ptr.Length(),aCapsBuf.MaxLength()));        
+    }
+</codeblock> <p>The data member <codeph>iCaps</codeph> is initialised by the
+function <xref href="GUID-681FB26E-0027-38E6-88A1-9E9046011312.dita"><apiname>SetCaps()</apiname></xref> called from the second stage constructor
+of the PDD object: </p> <codeblock id="GUID-B17BA93D-14D6-56A9-8F1F-9FFEF88559D3" xml:space="preserve">void DTemplateSoundScTxPdd::SetCaps()
+    {
+     __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::SetCaps"));
+    
+     // The data transfer direction for this unit is play.
+     iCaps.iDirection=ESoundDirPlayback;
+    
+     // TO DO: (mandatory)
+     // Setup the rest of the capabilities structure DTemplateSoundScTxPdd::iCaps with the capabilities of this
+     // audio playback device.
+    }</codeblock> </section>
+<section id="GUID-A2A7A6FF-8F46-589D-B5D6-E33ED3FF0692"><title>MaxTransferLen()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-534D46F4-2CB1-3130-9E72-A1C3BF085865"><apiname>DSoundScPdd::MaxTransferLen()</apiname></xref> function for both playback
+and record driver channels. The function has the following signature: </p> <codeblock id="GUID-039E8EF1-AA13-5C38-92DD-46AFC8E1E8F3" xml:space="preserve">TInt DSoundScPdd::MaxTransferLen() const</codeblock> <p>The
+supplied implementation is as follows: </p> <codeblock id="GUID-E27E52F5-175A-5264-8B08-AE0BDAD5B495" xml:space="preserve">TInt DTemplateSoundScTxPdd::MaxTransferLen() const
+    {
+    return(KTemplateMaxTxDmaTransferLen);
+    }</codeblock> <p>This function is called each time the LDD alters the
+audio configuration of the channel. For example, after calling <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-39AA2B2D-E98B-33A0-9C46-08B783413860"><apiname>DSoundScPdd::SetConfig()</apiname></xref>.
+The LDD uses the value returned to fragment record and playback data transfers
+so that they are manageable by the PDD. See <xref href="GUID-15FDDEED-89F1-5BE5-97AD-8DFD3640369A.dita">playback</xref> and <xref href="GUID-4AEF7595-17C0-513E-9568-B212E6194388.dita">record</xref>. </p> <p>The
+value returned by <xref href="GUID-615DF55C-EC50-3BF0-9C46-AB24E9505C5E.dita"><apiname>MaxTransferLen()</apiname></xref> is not as important
+for PDDs that use the Symbian DMA framework because the DMA framework handles
+fragmentation. </p> <p>If the PDD has to employ mono-to-stereo data conversion
+using a conversion buffer when configured in mono mode, then it needs to return
+the value that corresponds with the size of the conversion buffer each time
+it is configured in mono mode. See <xref href="GUID-E2641957-8163-5EF4-B282-FC3FD9CA75A6.dita#GUID-E2641957-8163-5EF4-B282-FC3FD9CA75A6/GUID-5C66667B-55C0-521D-86E3-67593DB381C9">mono
+to stereo conversion</xref>. </p> </section>
+<section id="GUID-B72057E6-B93C-505F-9789-83251D09B78E"><title>PowerUp()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-6301A4AA-CC41-3DBC-A349-9BD5C9B01276"><apiname>DSoundScPdd::PowerUp</apiname></xref> function for both the playback
+and record driver channels. The function has the following signature: </p> <codeblock id="GUID-F9706BE3-125F-56B3-947E-3534FB3A5D23" xml:space="preserve">TInt DSoundScPdd::PowerUp()</codeblock> <p>The
+supplied implementation is as follows: </p> <codeblock id="GUID-DB986B0B-CC10-5842-BB54-76683A35EB38" xml:space="preserve">TInt DTemplateSoundScTxPdd::PowerUp()
+    {
+    // TO DO: (mandatory)
+    // Power up the audio device.
+    
+    return(KErrNone);
+    }</codeblock> <p>This function initialises the codec device and any associated
+controller hardware that allows the CPU to communicate with it. However, at
+this stage only basic initialisation of these hardware components is required,
+as the specific audio configuration has not yet been specified, and data transfer
+has not yet started. </p> <p>If the PDD supports both record and playback
+driver channels then most, if not all, of this hardware initialisation is
+common to both channels. It may be necessary to ensure that such initialisation
+on one channel cannot interfere with the other. For example, when calling <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-1B2E2F89-75A8-3740-893A-4DCDB0A350D3"><apiname>DSoundScPdd::PowerUp()</apiname></xref> on
+the record driver channel while the playback driver channel is active, make
+sure that it does not interfere with audio playback. This typically requires
+hardware status information to be held in the PDD factory object that is common
+to both channels. </p> </section>
+<section id="GUID-3764C238-A458-5D13-8AB2-EE53CA91F6E5"><title>SetConfig()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-39AA2B2D-E98B-33A0-9C46-08B783413860"><apiname>DSoundScPdd::SetConfig()</apiname></xref> function for both playback
+and record driver channels. The function has the following signature: </p> <codeblock id="GUID-DB782F12-E5CE-5D13-8C12-8E57AB47BDB4" xml:space="preserve">TInt DSoundScPdd::SetConfig(const TDesC8&amp; aConfigBuf)</codeblock> <codeblock id="GUID-868A3301-3CAD-5077-88AC-2A2A6C125AFD" xml:space="preserve">TInt DTemplateSoundScTxPdd::SetConfig(const TDesC8&amp; aConfigBuf)
+    {
+    __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::SetConfig"));
+    
+    // Read the new configuration from the LDD.
+    TCurrentSoundFormatV02 config;
+    TPtr8 ptr((TUint8*)&amp;config,sizeof(config));
+    Kern::InfoCopy(ptr,aConfigBuf);
+    
+    // TO DO: (mandatory)
+    // Apply the specified audio configuration to the audio device.
+    TInt r=KErrNone;
+    
+    __KTRACE_SND(Kern::Printf("&lt;DTemplateSoundScTxPdd::SetConfig - %d",r));
+    return(r);
+    }</codeblock> <p>A configuration buffer in a packaged <xref href="GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68.dita"><apiname>TCurrentSoundFormatV02</apiname></xref> object
+containing the new configuration settings. </p> <ul>
+<li id="GUID-2D88064E-2258-55FA-BE68-831889E9E2C8"><p> <xref href="GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68.dita#GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68/GUID-AE4EDE94-5902-3D73-BAE4-4A49B3E3CC6C"><apiname>TCurrentSoundFormatV02::iChannels</apiname></xref>  </p> </li>
+<li id="GUID-CBACC0C9-1C73-59E0-BAA4-63110DECDED9"><p> <xref href="GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68.dita#GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68/GUID-FA39A28F-4B0C-3B89-AB4B-763E0369AD31"><apiname>TCurrentSoundFormatV02::iRate</apiname></xref>  </p> <ul>
+<li id="GUID-00FD1F5A-7941-5ED8-9878-69EDAE03F630"><p> <xref href="GUID-306655BD-FD24-37CE-8F67-F6BC5FBAA455.dita"><apiname>ESoundRate7350Hz</apiname></xref>  </p> </li>
+<li id="GUID-3BEB74D8-B829-5B49-A740-F4BC0597E389"><p> <xref href="GUID-F6D595E9-BE6E-3D5F-AEEF-57FEBA5D165F.dita"><apiname>ESoundRate8000Hz</apiname></xref>  </p> </li>
+<li id="GUID-E077B1A6-A625-55C8-8587-96EF7242C5F0"><p> <xref href="GUID-256AD4BA-8D30-38B8-8AC3-A63AFDCDF82E.dita"><apiname>ESoundRate8820Hz</apiname></xref>  </p> </li>
+<li id="GUID-5664E1E2-DBC3-5F2C-A5BD-3EE5512C254E"><p> <xref href="GUID-3A48C172-FEEF-3A5A-A986-E5C1FD8E5048.dita"><apiname>ESoundRate9600Hz</apiname></xref>  </p> </li>
+<li id="GUID-7E607F76-3975-591F-AEE3-D4CBC2B0F003"><p> <xref href="GUID-0B13D3F1-57D0-3741-BCC8-3E3BE50B59DE.dita"><apiname>ESoundRate11025Hz</apiname></xref>  </p> </li>
+<li id="GUID-8054CF86-27CF-531A-9233-C6602BB958EF"><p> <xref href="GUID-88C3603E-D69F-3DE9-9AA0-F6F724432C76.dita"><apiname>ESoundRate12000Hz</apiname></xref>  </p> </li>
+<li id="GUID-1AD1415C-0D0D-508F-B63E-69B553AA4109"><p> <xref href="GUID-D49E0BA6-AB68-334A-BECF-7221996C71CF.dita"><apiname>ESoundRate14700Hz</apiname></xref>  </p> </li>
+<li id="GUID-1D23B890-0AFC-5E2B-8D00-E56CF1E75D07"><p> <xref href="GUID-6FDDFE56-B32E-3DA1-8E90-DCAE1476A75F.dita"><apiname>ESoundRate16000Hz</apiname></xref>  </p> </li>
+<li id="GUID-A2637B2C-AD6B-5A87-86AC-FDB56DBF46C0"><p> <xref href="GUID-86882923-4DB3-3461-AF9E-D36BF75125AB.dita"><apiname>ESoundRate22050Hz</apiname></xref>  </p> </li>
+<li id="GUID-8682C600-A7C8-5B8B-9824-DD670812C598"><p> <xref href="GUID-2E1FC700-5B43-39DE-8B67-7DADD38B55A5.dita"><apiname>ESoundRate24000Hz</apiname></xref>  </p> </li>
+<li id="GUID-51A42D66-5B71-5325-90B7-B5A1503F21C5"><p> <xref href="GUID-244A1091-0F4A-376B-AE3E-93F09029ECF0.dita"><apiname>ESoundRate29400Hz</apiname></xref>  </p> </li>
+<li id="GUID-04621385-220C-587B-9C59-68115E251D8C"><p> <xref href="GUID-1C1526A2-4BA2-3296-BBE0-152070B43EE9.dita"><apiname>ESoundRate32000Hz</apiname></xref>  </p> </li>
+<li id="GUID-5DECBAD3-09E7-5967-82B3-7C923F870DA6"><p> <xref href="GUID-028FCDA8-E1FC-3E5D-827B-E4513991C1F2.dita"><apiname>ESoundRate44100Hz</apiname></xref>  </p> </li>
+<li id="GUID-27AA4D39-3CA5-52A0-9F97-C8543AAECB97"><p> <xref href="GUID-14D9C50A-2F72-3D1D-A15B-BDE4FAA33ED8.dita"><apiname>ESoundRate48000Hz</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-95DDDF4C-B70E-56B1-92E6-616ADCB45025"><p> <xref href="GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68.dita#GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68/GUID-1A4256A2-A2FE-3FD0-8849-A9F37E1D7A77"><apiname>TCurrentSoundFormatV02::iEncoding</apiname></xref>  </p> <ul>
+<li id="GUID-48484A2E-6970-59AE-9CD5-C93BE349C28D"><p> <xref href="GUID-866386CC-C9CA-3029-95C2-800F6B6C3C2D.dita"><apiname>ESoundEncoding8BitPCM</apiname></xref>  </p> </li>
+<li id="GUID-357130A0-C112-5803-A4D3-9B1237B5931C"><p> <xref href="GUID-E69FCDC5-9A22-3C5A-89C9-A7B869744948.dita"><apiname>ESoundEncoding16BitPCM</apiname></xref>  </p> </li>
+<li id="GUID-E2920329-BDFC-5B28-BF53-F4CF45DBE9AC"><p> <xref href="GUID-289CBD4B-ACEF-3A43-8935-201635AC658F.dita"><apiname>ESoundEncoding24BitPCM</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-406F8EE9-885D-5569-98E0-A473BB7462FB"><p> <xref href="GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68.dita#GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68/GUID-3A9546CB-33D6-3171-A8F7-0E642EB8E798"><apiname>TCurrentSoundFormatV02::iDataformat</apiname></xref>  </p> <ul>
+<li id="GUID-D21416A0-3E78-5D5C-BFE3-0C8A75F80429"><p> <xref href="GUID-5ADC3C98-2D05-35E1-96D2-42B3A65BF25F.dita"><apiname>ESoundDateFormatInterleaved</apiname></xref>  </p> </li>
+<li id="GUID-1A7EC2CC-D94F-514E-BB8A-9A3B3551B13F"><p> <xref href="GUID-352ED2EF-C98C-305E-80F1-FE30DF1BE4CA.dita"><apiname>ESoundDateFormatNonInterleaved</apiname></xref>  </p> </li>
+</ul> </li>
+</ul> <p>The PDD must read and locally save the contents of the <xref href="GUID-EF1D41AB-929D-3E51-98AA-F175DDB58F68.dita"><apiname>TCurrentSoundFormatV02</apiname></xref> configuration
+object that has been passed as a descriptor from the LDD. The template version
+contains the following code to achieve this: </p> <codeblock id="GUID-7FF5383E-FAE0-51A7-8E9E-0F489D841C72" xml:space="preserve">// Read the new configuration from the LDD.
+TCurrentSoundFormatV02 config;
+TPtr8 ptr((TUint8*)&amp;config, sizeof(config));
+Kern::InfoCopy(ptr, aConfigBuf);</codeblock> <p>It is not necessary to check
+for configurations requested by the LDD that are not supported by the audio
+hardware device if the <xref href="GUID-161BA615-FD2C-3A7E-992E-FBBED621CBBB.dita"><apiname>Caps()</apiname></xref> function has been implemented
+correctly by the PDD. This is because the LDD rejects such audio configuration
+requests from the client. However, if the PDD supports both playback and record
+driver channels then it needs to check that the specified configuration does
+not conflict with one already in use by the other channel. </p> <p>The PDD
+sets up the audio hardware device according to the audio configuration specified
+if it is required. Some, if not all of this hardware configuration may be
+put off until data transfer is started, this is when <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-54D3CC19-0C00-3FFA-BD1A-62618D36EB20"><apiname>DSoundScPdd::StartTransfer()</apiname></xref> is
+called, so for now the PDD needs to save the configuration. </p> <p>If the
+PDD has to employ mono-to-stereo conversion of data using a conversion buffer
+while the audio configuration is set to mono, then the memory for the conversion
+buffer should be allocated at this time. </p> </section>
+<section id="GUID-51420A2F-180B-5916-AF5A-685ABD156A2D"><title>SetVolume()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-3C56E870-1F05-31BC-B799-AF49F77E2930"><apiname>DSoundScPdd::SetVolume</apiname></xref> function for both the playback
+and record driver channels. This has the following signature: </p> <codeblock id="GUID-6FEA0876-7753-54C7-A414-9A54913F1778" xml:space="preserve">TInt DSoundScPdd::SetVolume(TInt aVolume)</codeblock> <p>The
+supplied implementation is as follows: </p> <codeblock id="GUID-14196DC5-8630-5E06-869A-D9A5EE423BF6" xml:space="preserve">TInt DTemplateSoundScTxPdd::SetVolume(TInt aVolume)
+    {
+    __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::SetVolume"));
+    
+    // TO DO: (mandatory)
+    // Set the specified play volume on the audio device.
+    TInt r=KErrNone;
+    
+    return(r);
+    }</codeblock> <p>The PDD must first convert the volume/record level information
+specified into a form which can be used to program the hardware. This may
+require converting the value from a gain factor to an attenuation factor and/or
+applying a scaling factor. The LDD detects situations where the client specifies
+a record level /volume that is already in effect, and in this case does not
+unnecessarily call the PDD. </p> <p>The PDD may opt to setup the audio hardware
+device within this function or it may defer this until data transfer is started
+with the function <xref href="GUID-CCACE58D-8884-37A4-B7DB-F1DFDEE4A8F1.dita#GUID-CCACE58D-8884-37A4-B7DB-F1DFDEE4A8F1/GUID-788592C9-FCCA-3E34-BEA7-5DC5E6A497C8"><apiname>DSOundScPdd::StartTransfer()</apiname></xref>. For PDDs
+which support both record and playback driver channels, it is normal for audio
+devices to allow the record and playback gains to be programmed independently,
+this means that checking for conflicts between the channels is rarely required
+for this function. </p> </section>
+<section id="GUID-287BB55C-E0FD-5214-9FAA-857AB46C64ED"><title>StartTransfer()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-66F3D9DA-F61F-3C1D-8C95-02C7C561AE64"><apiname>DSoundScPdd::StartTransfer</apiname></xref> function for both the playback
+and record driver channels. This has the following signature: </p> <codeblock id="GUID-02F7B0B7-35A7-525C-A88D-6555113D6D62" xml:space="preserve">TInt DSoundScPdd::StartTransfer()</codeblock> <p>The
+supplied implementation is as follows: </p> <codeblock id="GUID-DE7BF31A-B5D4-5348-9280-0C326D37DAF8" xml:space="preserve">TInt DTemplateSoundScTxPdd::StartTransfer()
+    {
+    __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::StartTransfer"));
+    
+    // TO DO: (mandatory)
+    // Prepare the audio device for playback.
+    TInt r=KErrNone;
+    
+    __KTRACE_SND(Kern::Printf("&lt;DTemplateSoundScTxPdd::StartTransfer - %d",r));
+    return(r);
+    }</codeblock> <p>This function performs any configurations of the audio
+hardware device that were deferred from the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-39AA2B2D-E98B-33A0-9C46-08B783413860"><apiname>DSoundScPdd::SetConfig()</apiname></xref> function.
+These configurations may include start-up of the DMA engine, enabling any
+interrupts related to audio transfer and interrupts that detect error conditions,
+for example. At this stage, no data has yet been supplied to the device for
+transfer as the function <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-8C79D09B-317A-3D8E-B9C2-474812F17529"><apiname>DSoundScPdd::TransferData()</apiname></xref> has
+not yet been called. </p> <p>If the PDD supports both record and playback
+driver channels then it may be necessary to ensure that such hardware configuration
+on one channel cannot interfere with the other. </p> </section>
+<section id="GUID-5E29637F-140F-5F1B-B969-DF9682CEF5E2"><title>TransferData()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-EF749829-6C35-3954-A48D-483FD0182CC9"><apiname>DSoundScPdd::TransferData</apiname></xref> function for both playback
+and record driver channels. This has the following signature: </p> <codeblock id="GUID-F13C3C46-D208-5E24-B986-3A32FAFBE453" xml:space="preserve">TInt DSoundScPdd::TransferData(TUint aTransferID,TLinAddr aLinAddr,
+                               TPhysAddr aPhysAddr,TInt aNumBytes)</codeblock> <p>Once
+transfer has been started by calling <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-54D3CC19-0C00-3FFA-BD1A-62618D36EB20"><apiname>DSoundScPdd::StartTransfer()</apiname></xref>,
+the function <xref href="GUID-209D8909-56BD-3601-98C4-FB6E004D78EE.dita"><apiname>TransferData</apiname></xref> is called repeatedly by the LDD
+for the transfer of each fragment. See the <xref href="GUID-15FDDEED-89F1-5BE5-97AD-8DFD3640369A.dita">playback</xref> and <xref href="GUID-4AEF7595-17C0-513E-9568-B212E6194388.dita">record</xref> sections for
+details. </p> <p>The template version for the record driver channel contains
+the following code: </p> <codeblock id="GUID-C86982D4-A2FE-5904-A46C-D52D349D018E" xml:space="preserve">TInt DTemplateSoundScRxPdd::TransferData(TUint aTransferID, TLinAddr aLinAddr,
+                                         TPhysAddr /*aPhysAddr*/, TInt aNumBytes)
+    {  
+    TInt r=KErrNone;
+   
+    // Check that we can accept the request
+    if (iPendingRecord&gt;=KTemplateMaxRxDmaRequests)
+        r=KErrNotReady;
+    else
+        {
+        // Start a DMA transfer.
+        iDmaRequest[iFlag]-&gt;iTransferID=aTransferID;
+        iDmaRequest[iFlag]-&gt;iTransferSize=aNumBytes;
+        // TO DO: (mandatory)
+        // Supply the DMA source information.
+        TUint32 src=0; // ???
+        r=iDmaRequest[iFlag]-&gt;Fragment(src,aLinAddr,aNumBytes,KDmaMemDest|KDmaIncDest,0);
+        if (r==KErrNone)
+            {
+            iDmaRequest[iFlag]-&gt;Queue();
+            iPendingRecord++;
+            if ((++iFlag)&gt;=KTemplateMaxRxDmaRequests)
+                iFlag=0;
+         
+            // TO DO: (mandatory)
+            // Start the audio device transferring data.
+            }
+        }
+                                    
+    return(r);
+    }</codeblock> <p><note> The template version used by the playback function
+is very similar. </note></p> <p>The first step is for the PDD to check that
+it has the capacity to accept a further transfer. For example, check that
+the PDD has a DMA request object that is free and that the DMA controller
+has the capacity for another transfer to be queued. If the PDD does not have
+the capacity to accept another transfer then it should immediately return <xref href="GUID-51298FCE-7857-39F8-BFAB-49AF5556D0CC.dita"><apiname>KErrNotReady</apiname></xref> to
+signal this. </p> <p>Otherwise, the PDD can start a DMA transfer. To do this
+it must acquire a DMA request object. The class <xref href="GUID-6B0DB695-9033-3F85-AC3A-1867E99BE2BD.dita"><apiname>DTemplateSoundScRxDmaRequest</apiname></xref> is
+the abstraction for a DMA record request and is defined as follows: </p> <codeblock id="GUID-04B1D7FD-4E17-5CD0-974F-A3A1BCB04C58" xml:space="preserve">/** Wrapper function for a shared chunk sound driver record DMA request. */
+class DTemplateSoundScRxDmaRequest : public DDmaRequest
+    {
+public:  
+    DTemplateSoundScRxDmaRequest(TDmaChannel&amp; aChannel, DTemplateSoundScRxPdd* aPdd,
+                                 TInt aMaxTransferSize=0);
+    static void DmaService(TResult aResult, TAny* aArg);
+public:
+    /** Pointer back to the PDD. */
+    DTemplateSoundScRxPdd* iPdd;
+    /** The transfer ID for this DMA request - supplied by the LDD. */
+    TUint iTransferID;
+    /** The transfer sizes in progress. */
+    TUint iTransferSize;
+    };
+    This is derived from DDmaRequest the base class
+    for a DMA request.</codeblock> <p>The data member <codeph>iPdd</codeph> is
+a pointer to the owning PDD object. This is used within the member function <xref href="GUID-8B538AA6-9489-309F-8756-2474310CD5DA.dita"><apiname>DmaService()</apiname></xref> which
+is the DMA callback function, and is called when the DMA request has been
+completed by the DMA framework. The data member <codeph>iTransferID</codeph> is
+a value supplied by the LDD which it uses to identify the transfer fragment.
+The PDD must save this value and pass it back to the LDD when the transfer
+is completed. Similarly, the member <codeph>iTransferSize</codeph> is used
+to hold the length of the transfer fragment in bytes. If the transfer is successful
+then this value is also passed back to the LDD to allow it to maintain its
+count of bytes recorded. </p> <p>The record PDD class owns an array of DMA
+request objects: </p> <codeblock id="GUID-8314BE9B-2D19-585F-B44E-17C8529CEFEF" xml:space="preserve">/** The DMA request structures used for transfers. */             
+DTemplateSoundScRxDmaRequest* iDmaRequest[KTemplateMaxRxDmaRequests];</codeblock> <p>It
+also owns the data member <codeph>iFlag</codeph>, which always holds the number
+for the next DMA request that should be used for transfer. Before starting
+the DMA transfer, setup the appropriate DMA request object with the transfer
+ID and the transfer length. </p> <codeblock id="GUID-2F4CB025-C2E2-52DD-A679-CF1DCC3677FA" xml:space="preserve">/** A flag selecting the next DMA request for transfer. */
+TInt iFlag;</codeblock> <p>Next the function <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita#GUID-780F4D53-5546-3B69-B328-0226C70EBDE2/GUID-B14B0478-80D6-3F5E-88B6-1676411D9CF2"><apiname>DDmaRequest::Fragment()</apiname></xref> is
+called to specify the details of the transfer to the DMA framework and to
+allow it to analyse this. Here the appropriate platform specific 32-bit DMA
+source identifier, <codeph>src</codeph>, needs to be supplied. The template
+driver shown previously specifies the destination memory address as a linear
+address but the physical address may be used instead. Both forms of this address
+are passed as arguments to the <xref href="GUID-34E7FF1F-091A-3C45-B83A-AEB64E2AD286.dita"><apiname>TransferData()</apiname></xref> function. </p> <p>If
+fragmentation is successful then the request object is queued on the DMA channel <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita#GUID-780F4D53-5546-3B69-B328-0226C70EBDE2/GUID-0A83F782-DB62-39ED-8D32-DBD5949C8D3F"><apiname>DDmaRequest::Queue()</apiname></xref> and
+the value of <codeph>iFlag</codeph> is updated ready for the next transfer.
+The PDD class also keeps a count of the number of transfer fragments outstanding
+by incrementing the variable <codeph>iPendingRecord</codeph>: </p> <codeblock id="GUID-5C738134-0683-5FAB-8733-29D9A336402F" xml:space="preserve">/** The number of outstanding DMA record requests on the DMA channel. */   
+TInt iPendingRecord;</codeblock> <p>The final part of this function requires
+platform specific code to start the audio hardware device transferring data.
+This needs to be executed for each fragment transferred or just for the first
+fragment queued following the <xref href="GUID-FE6DE994-719C-3900-B4A0-009914697380.dita"><apiname>StartTransfer()</apiname></xref> function. </p> <p>Once
+the transfer is complete, either successfully or with an error, the DMA framework
+executes the static DMA callback function, <xref href="GUID-6B0DB695-9033-3F85-AC3A-1867E99BE2BD.dita#GUID-6B0DB695-9033-3F85-AC3A-1867E99BE2BD/GUID-E12BA027-3D58-30A8-A9F7-B7B7DC55D0D5"><apiname>DTemplateSoundScRxDmaRequest::DmaService()</apiname></xref>,
+as follows: </p> <codeblock id="GUID-2ED07474-F489-5545-9FB6-BC229C00D4F3" xml:space="preserve">/**
+DMA rx service routine. Called in the sound thread's DFC context by the s/w DMA controller.
+@param aResult Status of DMA transfer.
+@param aArg Argument passed to DMA controller.
+*/ 
+void DTemplateSoundScRxDmaRequest::DmaService(TResult aResult, TAny* aArg)
+    {
+    DTemplateSoundScRxDmaRequest&amp; req=*(DTemplateSoundScRxDmaRequest*)aArg;
+   
+    TInt res=KErrNone;
+    TInt bytesTransferred=req.iTransferSize;
+    if (aResult!=DDmaRequest::EOk)
+        {
+        res=KErrCorrupt;
+        bytesTransferred=0;
+        }
+      
+    // Inform the LDD of the result of the transfer.
+    req.iPdd-&gt;RecordCallback(req.iTransferID,res,bytesTransferred);   
+    return;
+    }</codeblock> <p>This function receives two arguments: </p> <ul>
+<li id="GUID-7D4D15BD-3BA0-5899-B67E-C7F24F548D22"><p>the result of the transfer
+from the DMA framework </p> </li>
+<li id="GUID-FE18B3C9-A3B3-5599-8CC6-66977D0FA56A"><p>an argument supplied
+to the DMA framework when the request object was created </p> </li>
+</ul> <p>In this specific case, the argument type is a pointer to the DMA
+request object, and allows the retrieval of the transfer ID and the transfer
+size. In the template driver version an unsuccessful transfer returns an error
+value of <xref href="GUID-253F06EA-F14E-3A8E-BA4C-8E787B5F0670.dita"><apiname>KErrCorrupt</apiname></xref> with a transfer byte count of zero. </p> <p>From
+the callback function we call the record PDD function to decrement the count
+of transfer fragments outstanding and to inform the LDD of the completion
+of transfer. </p> <codeblock id="GUID-69C81D24-D725-51B2-8099-1D089A70AE00" xml:space="preserve">void DTemplateSoundScRxPdd::RecordCallback(TUint aTransferID, TInt aTransferResult,TInt aBytesTransferred)
+    {
+    iPendingRecord--;
+    Ldd()-&gt;RecordCallback(aTransferID,aTransferResult,aBytesTransferred);
+    } 
+</codeblock> </section>
+<section id="GUID-E9B63AC5-4AED-53E3-B7CA-21AACE04FC37"><title>StopTransfer()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-7C629A7C-0C64-32AB-8159-A4075DEEF544"><apiname>DSoundScPdd::StopTransfer</apiname></xref> function for both the play
+and record driver channels. This has the following signature: </p> <codeblock id="GUID-E56EFFEC-59CA-595F-BFA8-72299999DD05" xml:space="preserve">void DSoundScPdd::StopTransfer()</codeblock> <p>The
+PDD must reverse any operation performed on the audio hardware device done
+as part of <xref href="GUID-FE6DE994-719C-3900-B4A0-009914697380.dita"><apiname>StartTransfer()</apiname></xref> or <xref href="GUID-34E7FF1F-091A-3C45-B83A-AEB64E2AD286.dita"><apiname>TransferData()</apiname></xref>.
+This includes stopping the audio hardware device from transferring data and
+stopping the DMA channel. </p> <p>The template version for the record driver
+channel contains the following code: </p> <codeblock id="GUID-D8A0C5F9-3E9D-54F5-8906-465801CC3A3E" xml:space="preserve">void DTemplateSoundScRxPdd::StopTransfer()
+    {
+    // Stop the DMA channel.
+    iDmaChannel-&gt;CancelAll();
+    iFlag=0;
+    iPendingRecord=0;
+    
+    // TO DO: (mandatory)
+    // Stop the audio device transferring data.
+    }</codeblock> <p> <note> The version used by the playback function is
+very similar. </note></p> </section>
+<section id="GUID-2F694050-660B-5941-B9AA-FB21C1D33400"><title>PauseTransfer()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-0608766F-2645-3E28-B804-BD4B953DB5FF"><apiname>DSoundScPdd::PauseTransfer()</apiname></xref> function for both the
+playback and record driver channels. This has the following signature: </p> <codeblock id="GUID-51C0B918-4883-574A-B1AF-476C61A85120" xml:space="preserve">TInt DSoundScPdd::PauseTransfer()</codeblock> <p>When
+pausing playback, there is normally some way to temporarily stop the codec
+and pause the DMA channel so that it can be resumed later starting from the
+next play sample. </p> <p>Pausing record requires a different implementation.
+All active transfers must be aborted. When this has been achieved, the PDD
+must report back to the LDD how much data has been received for the fragment
+that was actively being transferred when the abort took place by calling <xref href="GUID-5807543D-A30F-3EB9-8F28-91A623B0D484.dita#GUID-5807543D-A30F-3EB9-8F28-91A623B0D484/GUID-9112E399-DC3C-334F-BE16-B5F42216F903"><apiname>DSoundScLdd::RecordCallBack()</apiname></xref>.
+If it is not possible to determine the byte count for the last fragment from
+the DMA controller, then you must find some other way to discover its value.
+One solution is to re-start a timer at the start of each record fragment,
+and use this to calculate how much data will have been written into the record
+buffer at the point the transfer is aborted. </p><p><note> In this case the
+returned transfer ID is not important.</note> </p> <p>The supplied template
+implementation is as follows: </p> <codeblock id="GUID-5B5B290E-C751-5599-AA67-0AC59E697898" xml:space="preserve">TInt DTemplateSoundScRxPdd::PauseTransfer()
+    {    
+    // Stop the DMA channel.
+    iDmaChannel-&gt;CancelAll();
+   
+    if (iPendingRecord)
+        {
+        // TO DO: (mandatory)
+        // Determine how much data was successfully transferred to the
+        // record buffer before transfer was aborted.
+        TInt byteCount=0; // ???
+        Ldd()-&gt;RecordCallback(0,KErrNone,byteCount);
+        iPendingRecord=0;
+        }
+    iFlag=0;
+    
+    // TO DO: (mandatory)
+    // Halt recording on the audio device.
+    TInt r=KErrNone;
+    
+    return(r); 
+    }
+</codeblock> <p> <note> There is no need for the PDD to perform any state
+checking as this is already performed by the LDD. For example, checking that
+the device is not already paused or transferring data. </note></p> </section>
+<section id="GUID-00368C95-2AE6-5EBA-8C09-787D0E7C10BC"><title>ResumeTransfer()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-788AEAF9-E33A-3BD2-8B60-9A066DBA2496"><apiname>DSoundScPdd::ResumeTransfer</apiname></xref> function for both the playback
+and record driver channels. This has the following signature: </p> <codeblock id="GUID-81A86CB7-E089-5B3D-A28F-A371AFDF5471" xml:space="preserve">TInt DSoundScPdd::ResumeTransfer()</codeblock> <p>The
+template version for the record driver channel contains the following code: </p> <codeblock id="GUID-D72D3F34-197F-500F-8483-E307418127F6" xml:space="preserve">TInt DTemplateSoundScTxPdd::ResumeTransfer()
+    {
+    __KTRACE_SND(Kern::Printf("&gt;DTemplateSoundScTxPdd::ResumeTransfer"));
+    
+    // TO DO: (mandatory)
+    // Resume playback on the audio device.
+    TInt r=KErrNone;
+            
+    return(r);
+    }</codeblock> <p>To resume playback, it is normally necessary to re-start
+the codec and resume the DMA channel in order to restart playback from the
+next play sample. </p> <p>To resume record, all active transfers should have
+been aborted when the device was paused with the function <xref href="GUID-1126E802-39C1-3BAD-85BA-A6DDED981B8A.dita"><apiname>PauseTransfer()</apiname></xref>.
+However, the LDD issues a new <xref href="GUID-34E7FF1F-091A-3C45-B83A-AEB64E2AD286.dita"><apiname>TransferData()</apiname></xref> request subsequent
+to this function to resume record data transfer so the only action required
+here is to recreate the same audio hardware setup that was achieved in response
+to the <xref href="GUID-FE6DE994-719C-3900-B4A0-009914697380.dita"><apiname>StartTransfer()</apiname></xref> function. </p> <p>There is no need
+for the PDD to perform any state checking as this is already performed by
+the LDD. For example, checking that the device is not already paused. </p> </section>
+<section id="GUID-3155494B-AFFD-5E07-8E2F-D6EC81E4E69B"><title>PowerDown()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-53CDB4F4-470C-3A40-B948-C14B0FCA0E24"><apiname>DSoundScPdd::PowerDown()</apiname></xref> function for both the playback
+and record driver channels. This has the following signature: </p> <codeblock id="GUID-69B46DDC-DA62-55E2-9E7C-A4E0B1550E03" xml:space="preserve">void DSoundScPdd::PowerDown()</codeblock> <p>The
+PDD must reverse any operation performed on the audio hardware as part of <xref href="GUID-B70A3916-5644-330F-872B-FADB8E3D80B5.dita"><apiname>PowerUp()</apiname></xref>. </p> </section>
+<section id="GUID-4B71AE98-3692-54B3-9CD8-525991DBAEAA"><title>CustomConfig()</title> <p>Implement
+the <xref href="GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424.dita#GUID-61CC68CB-A01D-3CA0-93D9-F3717ABD6424/GUID-B0F89BCD-69AF-3D40-A601-EB22C6FA0435"><apiname>DSoundScPdd::CustomConfig()</apiname></xref> function for both the playback
+and record driver channels. This has the following signature: </p> <codeblock id="GUID-C24D93F2-9A7E-5E43-8750-6BE8978B9C01" xml:space="preserve">TInt DSoundScPdd::CustomConfig(TInt aFunction,TAny* aParam)</codeblock> <p> <xref href="GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3.dita#GUID-B0118EDD-2B08-353E-BE92-2DC75E5622B3/GUID-78AA2782-80D0-3815-8F71-AA218756BAE6"><apiname>RSoundSc::CustomConfig()</apiname></xref> is called by the LDD in response to a custom configuration request by the
+client. Custom configurations allow clients to issue requests to setup platform
+specific audio configuration settings. Any such requests from the client with
+a function identifier equal to or above 0x10000000 are passed straight through
+to the PDD for function identification and implementation. These are handled
+in the context of the sound driver DFC thread. </p> <p>If custom configuration
+is not supported, then the PDD should simply return <codeph>KErrNotSupported</codeph>. </p> </section>
+</conbody></concept>
\ No newline at end of file