Adaptation/GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita
changeset 15 307f4279f433
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Adaptation/GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita	Fri Oct 15 14:32:18 2010 +0100
@@ -0,0 +1,1012 @@
+<?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-E55B4FE5-517C-5A23-8ACA-E28EE202330B" xml:lang="en"><title>Platform
+Specific Layer Implementation</title><shortdesc>Describes how to implement the Platform Specific Layer of the MMC
+Controller. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
+<section id="GUID-4C6CA873-A798-5C79-8838-0CC3C9E914FB"><title>DMMCStack derived
+class</title> <p>This class controls access to the MultiMediaCard stack. This
+class has a number of pure virtual functions that need to be implemented in
+your Variant DLL. The diagram at <xref href="GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF.dita#GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF/GUID-92F5EBE4-C9AD-5D9A-A80E-9AFD1A09B6B3">MultiMediaCard
+controller basic structure</xref> shows the class in context. </p> <p>There
+is one virtual function with a default implementation that needs to be overridden. </p> <ul>
+<li id="GUID-01ABEA80-002F-5490-B90F-3AE83927220B"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-0B55A650-E9ED-56CB-B06F-B1113ACDF282">Init()</xref>  </p> </li>
+<li id="GUID-04245FCC-D55A-5840-98CC-2113E7B6D9E4"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-CEF0EDF7-4B33-5452-8635-51C5319F78AE">MachineInfo()</xref> </p> </li>
+<li id="GUID-C5C86175-9100-5687-96EB-F4AEAF0CE161"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-F41EA0A6-1CBF-5AE2-9C66-DD6E3B7312E0">ProgramPeriodInMilliSeconds()</xref>  </p> </li>
+<li id="GUID-12B3B751-9EFE-5273-844B-A18D99E2A7FF"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-A7EC6536-3822-58C8-9A65-B71FDDBA10F3">AdjustPartialRead()</xref> </p> </li>
+<li id="GUID-AF40CF60-918D-5D9D-96C3-D96FDAD94B85"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-8A3E9782-C8D4-562D-9470-5CCE0ED1C303">GetBufferInfo()</xref> </p> </li>
+<li id="GUID-60AC1F94-4936-5AB1-B31E-CEDBDE59E08E"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-BC742EB6-7063-5D00-B422-96B3772605D5">SetBusConfigDefaults()</xref> </p> </li>
+<li id="GUID-592CDEF6-F450-572A-878E-077ED633C621"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-49DF2E60-AE31-502E-B7CB-694AFAF69F1B">InitClockOff()</xref>  </p> </li>
+<li id="GUID-82080A27-BCB7-5EC3-8F3E-2C1CDEDCA601"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-0DF60D11-AAD6-59E2-AE81-16E0DF96291B">ASSPDisengage()</xref> </p> </li>
+<li id="GUID-5E0E9EC9-742A-5265-9429-C52B60D83863"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-99AC4F3B-E273-515E-8690-983E98E17256">ASSPReset()</xref> </p> </li>
+<li id="GUID-DA38EA59-0A91-5498-9B3A-1F17D4511EFC"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-6EEE7EF6-4272-5116-BCEF-A852BB7B8FBD">CardDetect()</xref> </p> </li>
+<li id="GUID-9F025A5A-F303-55C8-85C4-BAC0BF0C27E4"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-3F34865D-5B16-5F53-AF9E-9F52DB5D0FB5">WriteProtected()</xref> </p> </li>
+<li id="GUID-D1B3A73F-E3AC-55C6-84E4-11A2AA9C3A7F"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-65547330-E112-55F2-AD4A-9B9CA5617E33">DoPowerDown()</xref> </p> </li>
+<li id="GUID-4117DD14-59D4-5257-AAAD-79498391979E"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-C8C15101-4614-5DEC-A620-6EAE8EC463ED">DoPowerUpSM()</xref> </p> </li>
+<li id="GUID-D93B8DEC-CFA0-5FC9-AF46-81A3B21F3545"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-C976320E-80FF-50F8-A882-F89C74F76ED3">InitClockOnSM()</xref> </p> </li>
+<li id="GUID-F6BB7D3C-8A9A-5228-88ED-2F28980373D8"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-FABAED76-FC63-577B-9436-DC7C8978E2AE">IssueMMCCommandSM()</xref>  </p> </li>
+</ul> <p id="GUID-0B55A650-E9ED-56CB-B06F-B1113ACDF282"><b>Init()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-43A06EF7-FA7B-3653-97B4-B04336E3EB54"><apiname>DMMCStack::Init()</apiname></xref>  </p> <p>The
+function is intended to initialize the stack, and is called during initialization
+of the MultiMediaCard controller Variant DLL from <xref href="GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7.dita#GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7/GUID-18825E56-F155-38D0-A4DF-A7C57D73C1EF"><apiname>DMMCSocket::Init()</apiname></xref>: </p> <p>You
+will almost certainly need to provide your own implementation to perform any
+platform-specific MultiMediaCard stack initialization. Whatever your implementation
+provides, <i>it is important that you call the base class function from within
+your derived version</i>. </p> <p>Return <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> if initialization
+is successful, otherwise return one of the system-wide error codes to indicate
+initialization failure. Note that returning a value other than <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> will
+cause the kernel to panic and to fail to boot. </p> <p>You will allocate a
+data transfer buffer here. The MultiMediaCard media driver needs a memory
+buffer to perform data transfer operations. Where supported, DMA is generally
+used to do this, and requires physically contiguous memory. However, the media
+driver is created each time a card is inserted into a machine and destroyed
+when the card is removed, and giving the media driver the responsibility for
+allocating the memory buffer means that it might not always be possible to
+allocate physically contiguous pages for it as memory becomes fragmented over
+time. </p> <p>The MultiMediaCard media driver uses the <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-8A3E9782-C8D4-562D-9470-5CCE0ED1C303">GetBufferInfo()</xref> function each time it is created to get a pointer
+to the buffer, and to get its length. </p> <p>Although the MultiMediaCard
+media driver only expects a single buffer, it actually uses this as two separate
+buffers: </p> <ul>
+<li id="GUID-21E69407-DEB2-5DBE-9614-ADFF7DBF06B6"><p>a minor buffer which
+must have at least enough space for the MBR (512 bytes) </p> </li>
+<li id="GUID-1FF25456-0CE3-582C-9FEC-B5913C1E437A"><p>a cache buffer to cache
+data blocks from the card. </p> </li>
+</ul> <p>The ideal size of the cache buffer depends on the characteristics
+of the card present at the time, and it is possible to customize the MultiMediaCard
+controller at the platform specific layer for a particular card. </p> <p>The
+following example code allocates a physically contiguous buffer - a minor
+buffer size of one block is allocated together with a cache buffer size of
+eight blocks. The whole buffer is then rounded up to a whole number of memory
+pages. </p> <codeblock id="GUID-B01B50BE-6574-5A81-BA25-8FDFEB2C5620" xml:space="preserve">// The constant calculations could be explicitly folded, but this illustrates
+// how the values are derived.
+const TUint blkSzLog2 = 9;                    
+const TUint blkSz = 1 &lt;&lt; blkSzLog2;
+const TInt minorBufLen = Max(KDiskSectorSize, blkSz);
+
+const TInt KMinBlocksInBuffer = 8;
+const TInt cchBufLen = KMinBlocksInBuffer &lt;&lt; blkSzLog2;
+
+TInt totalBufLen = minorBufLen + cchBufLen;
+
+// Allocate contiguous physical memory
+totalBufLen = Kern::RoundToPageSize(totalBufLen);
+
+TPhysAddr physAddr = 0;
+r = Epoc::AllocPhysicalRam(totalBufLen, physAddr);
+__KTRACE_OPT(KHARDWARE, Kern::Printf("mmc:ini:physical = %08x", physAddr));
+if (r != KErrNone)
+    {
+    return r;
+    }
+
+DPlatChunkHw* bufChunk = NULL;
+r = DPlatChunkHw::New(bufChunk, physAddr, totalBufLen, EMapAttrCachedWBRA|EMapAttrSupRw);
+
+if(r != KErrNone)
+    {
+    if (physAddr)
+        {
+        Epoc::FreePhysicalRam(physAddr, totalBufLen);
+        }
+    return r;
+    }
+          
+iMDBuf = reinterpret_cast&lt;TUint8*&gt;(bufChunk-&gt;LinearAddress());
+iMDBufLen = totalBufLen;
+</codeblock> <p id="GUID-CEF0EDF7-4B33-5452-8635-51C5319F78AE"><b>MachineInfo()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-3E5532A5-4645-3F77-A7A9-7AFF334FA5A4"><apiname>DMMCStack::MachineInfo()</apiname></xref>  </p> <p>The
+function returns configuration information for the MultiMediaCard stack. </p> <p>The
+function takes a reference to a <xref href="GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8.dita"><apiname>TMMCMachineInfo</apiname></xref> object,
+and your implementation must fill the public data members of the object. </p> <p id="GUID-F41EA0A6-1CBF-5AE2-9C66-DD6E3B7312E0"><b>ProgramPeriodInMilliSeconds()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-C0998F1F-EE3B-32C1-9898-288EA1D71AC0"><apiname>DMMCStack::ProgramPeriodInMilliSeconds()</apiname></xref>  </p> <p>When a data block is written to a card, the data is read into an
+internal buffer on the card and is then programmed into the payload memory.
+While the card is in <i>programming mode</i>, it cannot be read from, or written
+to, but it is possible to query its status using CMD13. </p> <p>Immediately
+after a block of data is written by <codeph>CIMReadWriteBlocksSM()</codeph>,
+the MultiMediaCard controller requests the card's state using CMD13. If the
+card is still in the programming state, then the state machine <codeph>ProgramTimerSM()</codeph> launches
+a timer with the period returned by <codeph>ProgramPeriodInMilliSeconds()</codeph>.
+The state of the card is periodically checked until it is no longer in programming
+mode. </p> <p>For platforms that do not provide an interrupt to indicate when
+programming mode is finished, <codeph>ProgramPeriodInMilliSeconds()</codeph> should
+return the interval, in milliseconds, to be used by the poll timer. </p> <p id="GUID-A7EC6536-3822-58C8-9A65-B71FDDBA10F3"><b>AdjustPartialRead()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-7FEC1574-5448-3DF5-8BD2-AABDBD0211C3"><apiname>DMMCStack::AdjustPartialRead()</apiname></xref>  </p> <p>Some
+cards support a partial read feature, which is indicated by the <codeph>READ_BL_PARTIAL</codeph> bit
+in the <codeph>CSD</codeph> register. When this is the case, it is possible
+to read a section within a single physical block, without having to read the
+entire block. </p> <p>The MultiMediaCard media driver uses this feature to
+read small amounts of data more quickly. However, many hardware implementations
+impose restrictions on the granularity of the data that can be read from the
+card. For example, they may use a 32-bit FIFO. </p> <p>This function allows
+you to enforce the limits imposed by the hardware. </p> <p>The <codeph>aStart</codeph> and <codeph>aEnd</codeph> arguments
+of <codeph>AdjustPartialRead()</codeph> define the range on the card from
+which the media driver would like to read. Your implementation should return
+in <codeph>*aPhysStart</codeph> and <codeph>*aPhysEnd</codeph> the range that
+the hardware will allow to be read. </p> <p>For example, to word align data,
+the function would be implemented using the following code: </p> <codeblock id="GUID-30DE526C-70C2-5118-BFBB-72759EFC8C93" xml:space="preserve">void AdjustPartialRead(const TMMCard* aCard, TUint32 aStart, TUint32 aEnd, TUint32* aPhysStart, TUint32* aPhysEnd);
+    {
+    ...
+    const TUint32 KWordMask = 3;
+    *aPhysStart = aStart &amp; ~KWordMask;
+    *aPhysEnd = (aEnd + KWordMask) &amp; ~KWordMask;
+    ...
+    }
+</codeblock> <p id="GUID-8A3E9782-C8D4-562D-9470-5CCE0ED1C303"><b>GetBufferInfo()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-EC9B740A-3A07-35AB-BACE-2EC1F96EEF0F"><apiname>DMMCStack::GetBufferInfo()</apiname></xref>  </p> <p>The
+MultiMediaCard media driver needs a memory buffer to perform data transfer
+operations, and this is, typically, allocated once only by the <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-0B55A650-E9ED-56CB-B06F-B1113ACDF282">Init()</xref> function when this stack object is initialized. </p> <p>The
+MultiMediaCard media driver is created each time a card is inserted into a
+machine and destroyed when the card is removed, and it uses this function,
+each time it is created to get a pointer to the memory buffer, and to get
+its length. The MultiMediaCard media driver then uses this buffer, over its
+lifetime, for data transfer operations. </p> <p id="GUID-BC742EB6-7063-5D00-B422-96B3772605D5"><b>SetBusConfigDefaults()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-C7297E13-5F78-396D-842B-FB16D3424374"><apiname>DMMCStack::SetBusConfigDefaults()</apiname></xref>  </p> <p>The function returns information about the MultiMediaCard bus configuration
+for this platform. </p> <p>The function takes a <xref href="GUID-F9432D7B-41C9-3048-AC50-B5BCF8BE11D0.dita"><apiname>TUint</apiname></xref> value
+containing the bus speed that the controller intends to use, and a reference
+to a <xref href="GUID-C0E2780A-47B3-31A2-827C-AF89C1B65F2E.dita"><apiname>TMMCBusConfig</apiname></xref> object. The implementation of this function
+must fill the public data members of this object. See the class reference
+documentation for the data members. </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita"><apiname>DMMCStack</apiname></xref> has
+two private data members of type <xref href="GUID-75FF770B-07D1-3C07-9577-5A37841E53E7.dita"><apiname>TMMCStackConfig</apiname></xref>: </p> <ul>
+<li id="GUID-A56BF364-F02F-54EA-80F8-E4AB5E7A10C9"><p> <codeph>iMasterConfig</codeph>  </p> </li>
+<li id="GUID-C94FFA4E-51C7-5CBA-BFBB-F692438412FE"><p> <codeph>iConfig</codeph>  </p> </li>
+</ul> <p>The information returned by the call to <codeph>SetBusConfigDefaults()</codeph> is
+stored in <codeph>iMasterConfig</codeph>'s <codeph>iBusConfig</codeph> private
+data member. </p> <p> <codeph>iMasterConfig</codeph> contains the master bus
+configuration settings for the platform. Each time a new session is made current,
+the master bus configuration settings are merged with the specific bus configuration
+settings for that session, (as set up in the public data member <xref href="GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A.dita#GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A/GUID-73BC8CE4-593E-3BAC-909A-FB8F419895C8"><apiname>DMMCSession::iConfig</apiname></xref>),
+and the result is stored in <codeph>iConfig</codeph>. It is these merged bus
+configuration settings that are used to configure the hardware interface.
+The platform specific layer can access these settings with a call to Master<xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E0275614-109E-3803-A0AE-3313E1E0038B"><apiname>DMMCStack::BusConfig()</apiname></xref>. </p> <p> <codeph> SetBusConfigDefaults()</codeph> is called at two stages in the execution of the macro CIM_UPDATE_ACQ to
+update the <codeph>iMasterConfig</codeph> object. </p> <ul>
+<li id="GUID-5C98DB8C-60AF-5333-A250-5D6509D754E5"><p>First, it is called
+at the start of the card initialization stage with the bus speed argument, <codeph>aClock</codeph>,
+set to the fOD rate (400kHz). </p> </li>
+<li id="GUID-0CD15184-15F8-5104-908F-612CCBCA953A"><p>Second, it is called
+after the CSD registers for each card have been read with the bus speed argument, <codeph>aClock</codeph>,
+set to the slowest maximum transfer rate (TRAN_SPEED) reported by any of the
+CSD registers. </p> </li>
+</ul> <p id="GUID-49DF2E60-AE31-502E-B7CB-694AFAF69F1B"><b> InitClockOff()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-BF94B298-7F72-33F7-A2F0-F19807BF2CDC"><apiname>DMMCStack::InitClockOff()</apiname></xref>  </p> <p>Switches
+from identification mode of operation to data transfer mode operation. </p> <p>When
+this function is called, the clock information in the <codeph>iBusConfig</codeph> member
+(see <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-BC742EB6-7063-5D00-B422-96B3772605D5">SetBusConfigDefaults()</xref>)
+will not have been updated to the new data transfer rate. </p> <p>This function
+should, in general, just switch from open drain to push-pull bus mode, with
+the clock rate being changed at the start of <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-A48C1C16-B465-3DDA-9C83-00DEB8D27B68"><apiname>DMMCStack::IssueMMCCommandSM()</apiname></xref>,
+when <codeph>iBusConfig</codeph> will be valid. </p> <p id="GUID-0DF60D11-AAD6-59E2-AE81-16E0DF96291B"><b> ASSPDisengage()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-36C720F9-DEAF-3896-A12A-2AE2581AA347"><apiname>DMMCStack::ASSPDisengage()</apiname></xref>  </p> <p>This
+function is called by the platform independent layer each time a session has
+completed or has been aborted. </p> <p>The function gives the platform specific
+layer the chance to free resources or disable any activities that were required
+to perform the session. </p> <p>The implementation should not turn off the
+clock to the hardware interface as this will be turned off by the inactivity
+timer. Typically, the implementation disables DMA and interface interrupts,
+and forces the hardware interface into idle. </p> <p>At the end of your implementation,
+you must add a call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-3DFCBE96-E9F3-3FF3-97BC-A3A3024089BD"><apiname>DMMCStack::ReportASSPDisengaged()</apiname></xref> to
+report to the platform independent layer that platform specific layer resources
+have been disengaged. </p> <p id="GUID-99AC4F3B-E273-515E-8690-983E98E17256"><b>ASSPReset()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-36D3F4D9-A2FC-3355-ABE0-31C9F7397E2D"><apiname>DMMCStack::ASSPReset()</apiname></xref>  </p> <p>This
+function is called by the platform independent layer when the current session
+is being aborted, and platform specific asynchronous activity is to be cancelled.
+The function may also be called by the platform specific layer as part of
+the <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-65547330-E112-55F2-AD4A-9B9CA5617E33">DoPowerDown()</xref> implementation. </p> <p>The function gives the platform specific layer the chance to stop all activities
+on the host stack. It will, in general, perform the same operations as <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-0DF60D11-AAD6-59E2-AE81-16E0DF96291B">ASSPDisengage()</xref> but,
+in addition, will turn off the clock to the hardware interface and release
+any requested power requirements made on the power model, i.e. release any
+power requirements made by <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-C976320E-80FF-50F8-A882-F89C74F76ED3">InitClockOnSM()</xref>. </p> <p>At the end of your implementation, you must add a call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-3DFCBE96-E9F3-3FF3-97BC-A3A3024089BD"><apiname>DMMCStack::ReportASSPDisengaged()</apiname></xref> to
+report to the platform independent layer that platform specific layer resources
+have been disengaged. </p> <p id="GUID-6EEE7EF6-4272-5116-BCEF-A852BB7B8FBD"><b>CardDetect()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-02C4D1A0-6149-389D-9F31-3E7EBF1DCA66"><apiname>DMMCStack::CardDetect()</apiname></xref>  </p> <p>Implement
+this function to report whether a card is present in a specified card socket. </p> <p>This
+function takes a <xref href="GUID-F9432D7B-41C9-3048-AC50-B5BCF8BE11D0.dita"><apiname>TUint</apiname></xref> value containing the card socket
+that is to be queried. </p> <p id="GUID-3F34865D-5B16-5F53-AF9E-9F52DB5D0FB5"><b>WriteProtected()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-E7E97501-10E7-38E6-9F8C-2A62F260BA46"><apiname>DMMCStack::WriteProtected()</apiname></xref>  </p> <p>Implement
+this function to report whether a card in a specified card socket is mechanically
+write protected. </p> <p>This function takes a <xref href="GUID-F9432D7B-41C9-3048-AC50-B5BCF8BE11D0.dita"><apiname>TUint</apiname></xref> value
+containing the card socket that is to be queried. </p> <p id="GUID-65547330-E112-55F2-AD4A-9B9CA5617E33"><b>DoPowerDown()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-3E90AF73-F4D3-34C5-B6D3-6BF69C6137C8"><apiname>DMMCStack::DoPowerDown()</apiname></xref>  </p> <p>This
+function is called as part of the bus power down sequence: </p> <ul>
+<li id="GUID-E9E072D3-A2F7-5DD2-B7D9-A89840BBA914"><p>by the power model,
+in power standby and power emergency standby situations </p> </li>
+<li id="GUID-1EFB0616-45B9-5EC2-9456-54F7D10D2894"><p>when a door-open event
+occurs </p> </li>
+<li id="GUID-83F42DEB-C6EE-5558-8907-CFD141461456"><p>when the bus inactivity
+timer has timed out </p> </li>
+<li id="GUID-0EA77E57-E2D0-599D-8E90-ECE1D21BC329"><p>if a power supply unit
+(PSU) voltage check fails. </p> </li>
+</ul> <p>The function should stop all activities on the host stack, turn off
+the clock to the hardware interface and release any requested power requirements
+made on the power model. The function is very often implemented as a call
+of <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-99AC4F3B-E273-515E-8690-983E98E17256">ASSPReset()</xref>. </p> <p>The
+function should not turn off the MultiMediaCard power supply unit as this
+will be performed immediately afterwards by a call to the <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita#GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B/GUID-4DF0741F-B143-3B46-82BE-9CD0261C27E5"><apiname>DMMCPsu::DoSetState()</apiname></xref> derived
+class function from the platform independent layer. </p> <p id="GUID-C8C15101-4614-5DEC-A620-6EAE8EC463ED"><b> DoPowerUpSM()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-791BCA03-61F3-3C1C-BA2D-D633A94AF299"><apiname>DMMCStack::DoPowerUpSM()</apiname></xref>  </p> <p>This
+is a state machine function, called as a child function at the start of the <codeph>CIM_UPDATE_ACQ</codeph> macro
+state machine. </p> <p>The function should perform the necessary platform
+specific actions associated with powering up the bus. This includes turning
+on the MultiMediaCard PSU. However, the hardware interface clock should <i>not</i> be
+turned on as part of this function. </p> <p>If the controller has to request
+power resources from the power model, e.g. where a fast system clock is required
+all the time the bus is powered, then this state machine function can be used
+to wait asynchronously for this resource to become available. </p> <p>If the
+activity performed by this function completes successfully: </p> <ul>
+<li id="GUID-7C64DB32-139B-5F45-9F2C-6693F9E16F83"><p>it must call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-40973A35-3A73-3DBD-9EB7-99CE55E6D694"><apiname>DMMCStack::ReportPowerUp()</apiname></xref>. </p> </li>
+<li id="GUID-42E872B5-EA6A-5901-AD93-5F9B99C81D69"><p>it returns <xref href="GUID-E7D46003-E502-39D1-AF52-83B87AE6930B.dita"><apiname>KMMCErrNone</apiname></xref>. </p> </li>
+</ul> <p>The function should return <xref href="GUID-E7D46003-E502-39D1-AF52-83B87AE6930B.dita"><apiname>KMMCErrNone</apiname></xref> if it completes
+successfully or one of the other <xref href="GUID-FF4AB1CF-7A2C-3FC6-B123-D6819E1BCDCA.dita"><apiname>TMMCErr</apiname></xref> error codes. </p> <p>See
+the general background information on <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita">the
+state machine</xref>. </p> <p id="GUID-C976320E-80FF-50F8-A882-F89C74F76ED3"><b>InitClockOnSM()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-7B91EF52-26E5-333C-A037-B142B492BCC4"><apiname>DMMCStack::InitClockOnSM()</apiname></xref>  </p> <p>This
+is a state machine function, called as part of the <codeph>CIM_UPDATE_ACQ</codeph> macro
+state machine. </p> <p>The function should turn on the clock to the hardware
+interface. The function is so named because this clock is always first turned
+on at the identification mode frequency. </p> <p>The function is implemented
+as a state machine function because it may be necessary to include a short
+delay after the clock has been turned on to allow it to stabilize. </p> <p>If
+it is necessary for the MultiMediaCard controller to request any power resources
+from the power model on this platform, for example, requesting a necessary
+system clock, then it should be performed as part of this function. In some
+cases, it may be necessary to wait for this power resource to become available. </p> <p>At
+the <i>beginning</i> of your implementation, you must add a call <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-D797747A-0AF6-36B1-BD92-3D6950A3B7B4"><apiname>DMMCStack::ReportASSPEngaged()</apiname></xref> to
+report to the platform independent layer that platform specific layer resources
+have been engaged. </p> <p>The function should return <xref href="GUID-E7D46003-E502-39D1-AF52-83B87AE6930B.dita"><apiname>KMMCErrNone</apiname></xref> if
+it completes successfully or one of the other <xref href="GUID-FF4AB1CF-7A2C-3FC6-B123-D6819E1BCDCA.dita"><apiname>TMMCErr</apiname></xref> error
+codes. </p> <p>Note: </p> <ul>
+<li id="GUID-2474710D-C595-5331-9182-A2EF97A1EB27"><p>the function is only
+called once for each invocation of the CIM_UPDATE_ACQ macro and the important
+thing to stress is that the interface clock is being turned on after a period
+when it has been off, and therefore often requires time to stabilize. </p> </li>
+<li id="GUID-FE92334D-757D-5C08-AF98-9E0912BA2820"><p>In the course of executing
+a session, the MultiMediaCard controller may switch the clock more than once
+between the identification mode frequency and the data transfer mode frequency,
+but this function only ever gets called once. </p> </li>
+</ul> <p>See the general background information on <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita">the
+state machine</xref>. </p> <p id="GUID-FABAED76-FC63-577B-9436-DC7C8978E2AE"><b> IssueMMCCommandSM()</b> </p> <p> <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-A48C1C16-B465-3DDA-9C83-00DEB8D27B68"><apiname>DMMCStack::IssueMMCCommandSM()</apiname></xref>  </p> <p>This
+is a <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita">state machine</xref> function
+that executes a single command over the bus. The implementation of this function
+is an important part in the process of porting the MultiMediaCard controller. </p> <p>The
+input parameters for the command are passed via the current command descriptor,
+an instance of the <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita"><apiname>TMMCCommandDesc</apiname></xref> class, on the session’s
+command stack. The parameters contain information such as: the type of command,
+the response type, the command arguments, the data source/destination for
+data transfer commands etc. Use <xref href="GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A.dita#GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A/GUID-931547BD-665D-326A-92B5-909B2D57F8C6"><apiname>DMMCSession::Command()</apiname></xref> to
+get the current command descriptor. </p> <p>Information about the command
+response, the number of bytes transferred etc., is passed back using the same
+command descriptor. Specifically, the platform independent layer relies on
+responses to the following commands being returned in the <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-86553172-AE4E-3707-A0D2-8C2BB8880253"><apiname>TMMCCommandDesc::iResponse</apiname></xref> member,
+in big-endian format: </p> <ul>
+<li id="GUID-45605105-B91A-506B-A0F9-A317CA84D5EF"><p>Returns the OCR register
+value in response to a SEND_OP_COND command (CMD1). Note that there is <i>no
+CRC</i> with this response. Your code should ignore any CRC failure indication
+from the MultiMediaCard controller hardware, and just copy the response into <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-86553172-AE4E-3707-A0D2-8C2BB8880253"><apiname>TMMCCommandDesc::iResponse</apiname></xref>. </p> </li>
+<li id="GUID-3E8B7D20-71F1-5609-8A16-24C6E2A7186A"><p>Returns the CID register
+value in response to an ALL_SEND_CID command (CMD2) and a SEND_CID command
+(CMD10). </p> </li>
+<li id="GUID-8D051F10-65BB-57AF-8B75-247829DC239A"><p>Returns the CSD register
+value in response to a SEND_CSD command (CMD9). </p> </li>
+<li id="GUID-C899645F-8478-57BF-8E1E-58AC50EB9FE3"><p>Returns the card status
+in response to all R1 and R1b commands. </p> </li>
+</ul> <p>Note that you can use the functions <xref href="GUID-32036692-8BA3-3AAF-9FD8-D135DFADAE77.dita#GUID-32036692-8BA3-3AAF-9FD8-D135DFADAE77/GUID-D2EFC17B-FC2E-3FDC-AE7A-E2AA109D4B40"><apiname>TMMC::BigEndian4Bytes()</apiname></xref> and
+TMC::to help with conversion to big-endian format. </p> <p>The function should
+return <xref href="GUID-E7D46003-E502-39D1-AF52-83B87AE6930B.dita"><apiname>KMMCErrNone</apiname></xref> if it completes successfully or one
+of the other <xref href="GUID-FF4AB1CF-7A2C-3FC6-B123-D6819E1BCDCA.dita"><apiname>TMMCErr</apiname></xref> error codes. </p> <p>See also background
+information: </p> <ul>
+<li id="GUID-0667980A-4A9E-5BD0-952E-97AD4C83B939"><p> <xref href="GUID-C059F39F-BC53-5C92-B05E-863B8CF22859.dita">Issuing
+commands</xref>  </p> </li>
+<li id="GUID-DF2B96DD-DD85-52C2-9EC8-30379E03D1DA"><p> <xref href="GUID-80E0DB93-A96A-54A8-A201-E11935418BE7.dita">The
+state machine</xref>. </p> </li>
+</ul> </section>
+<section id="GUID-3A1E907E-A74D-59CB-A1D6-FEF4849EF2D5"><title>DMMCPsu derived
+class</title> <p>This class controls the MultiMediaCard socket's power supply.
+A class needs to be derived from this in the platform specific layer to handle
+the Variant specific functionality of the power supply. </p> <p>This class
+has a number of pure virtual functions that need to be implemented in your
+Variant DLL. The diagram at <xref href="GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF.dita#GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF/GUID-92F5EBE4-C9AD-5D9A-A80E-9AFD1A09B6B3">MultiMediaCard
+controller basic structure</xref> shows the class in context. </p> <p>There
+is one virtual function with an empty default implementation that needs to
+be overridden. </p> <ul>
+<li id="GUID-025272EF-9DE8-5975-8993-006EE4D56E80"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-6EB8EF1C-BCCB-54A1-8CBA-4E8A2A20CABE">DoCreate()</xref>  </p> </li>
+<li id="GUID-6BAFE3AA-6CCA-581B-A96C-D1FD89D1D8CD"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-99529E84-17E1-5F23-9A1B-EBE3976D9B14">PsuInfo()</xref>  </p> </li>
+<li id="GUID-7419D681-D0CC-5CA7-8EE7-0D5A20779921"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-5809318D-E3E1-5261-AABA-604EBE72523F">DoSetState()</xref>  </p> </li>
+<li id="GUID-E570E830-B57E-5A39-9EF1-CF68F3853AFF"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-B5030D2E-A466-596C-A2C3-73F38CF9C1A7">DoCheckVoltage()</xref>  </p> </li>
+</ul> <p id="GUID-6EB8EF1C-BCCB-54A1-8CBA-4E8A2A20CABE"><b>DoCreate()</b> </p> <p> <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita#GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B/GUID-32771B9D-D2B8-33F5-AFC5-4476165C0A76"><apiname>DMMCPsu::DoCreate()</apiname></xref>  </p> <p>The
+function is intended to perform hardware initialization on the MultiMediaCard
+power supply, for example, setting port direction registers. </p> <p>The function
+is called after creation of the <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita"><apiname>DMMCPsu</apiname></xref> derived class instance,
+which is done during kernel initialization when the MultiMediaCard controller
+Variant DLL extension is loaded. </p> <p>The function has a default implementation
+that just returns <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref>. </p> <p>Your implementation
+should <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> if the hardware initialization is successful,
+otherwise it should return one of the system-wide error codes to indicate
+initialization failure. Note that returning a value other than <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> will
+cause the kernel to panic and to fail to boot. </p> <p id="GUID-99529E84-17E1-5F23-9A1B-EBE3976D9B14"><b>PsuInfo()</b> </p> <p> <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita#GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B/GUID-C7600EDA-B564-31E2-835C-9C580A29FC1D"><apiname>DMMCPsu::PsuInfo()</apiname></xref>  </p> <p>The
+function returns information about the MultiMediaCard power supply. </p> <p>The
+function takes a reference to a <xref href="GUID-E3BB783F-423F-352A-9B6E-FD23EC80AA8D.dita"><apiname>TPBusPsuInfo</apiname></xref> object, and
+your implementation must fill the public data members of the object. </p> <p>Note: </p> <ul>
+<li id="GUID-B8527FE4-61BB-574A-A200-5EA083A76A6D"><p>You can use the constant <xref href="GUID-3B63FFD6-AE21-366A-B435-AE6213AA2EE0.dita"><apiname>KMMCAdjustableOpVoltage</apiname></xref> to
+set bit 31 in <xref href="GUID-E3BB783F-423F-352A-9B6E-FD23EC80AA8D.dita#GUID-E3BB783F-423F-352A-9B6E-FD23EC80AA8D/GUID-6B1E1CDD-A0E7-3AA5-989E-8D7A199ADE2A"><apiname>TPBusPsuInfo::iVoltageSupported</apiname></xref>. </p> </li>
+<li id="GUID-694DB272-C66E-5392-8C7E-DC1B875E9DD3"><p>Set <xref href="GUID-E3BB783F-423F-352A-9B6E-FD23EC80AA8D.dita#GUID-E3BB783F-423F-352A-9B6E-FD23EC80AA8D/GUID-8C9792BC-8FAA-3DE5-8032-7546887FA8FB"><apiname>TPBusPsuInfo::iNotLockedTimeOut</apiname></xref> to
+0. </p> </li>
+</ul> <p id="GUID-5809318D-E3E1-5261-AABA-604EBE72523F"><b> DoSetState()</b> </p> <p> <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita#GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B/GUID-4DF0741F-B143-3B46-82BE-9CD0261C27E5"><apiname>DMMCPsu::DoSetState()</apiname></xref>  </p> <p>The
+function is called to turn the PSU on or off. </p> <p>The requested state
+of the PSU depends on the <xref href="GUID-CD00D507-CC86-33BE-91A7-FAF7EAFD4840.dita"><apiname>TPBusPsuState</apiname></xref> value passed to
+it. </p> <p>If the PSU supports voltage adjustment, rather than a single fixed
+value, then the required voltage setting is contained in the protected data
+member <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita#GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B/GUID-7A625108-D5AE-301F-9CAB-2625DAD0C0B0"><apiname>DMMCPsu::iVoltageSetting</apiname></xref>. </p> <p>Note that the
+stack may call this function to request the power to be turned on when it
+is already on. You should check for this and do nothing if the power is already
+in the requested state. </p> <p id="GUID-B5030D2E-A466-596C-A2C3-73F38CF9C1A7"><b>DoCheckVoltage()</b> </p> <p> <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita#GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B/GUID-17AC2A1C-5430-38B1-BD3F-966CE4936940"><apiname>DMMCPsu::DoCheckVoltage()</apiname></xref>  </p> <p>The
+function is called to check that the voltage level of the PSU is as expected. </p> <p>Checking
+the voltage level may be a long running operation (e.g. using an ADC), and
+it may not always be appropriate to perform and complete the check directly
+within this function. </p> <p>When voltage checking is complete, either synchronously
+in this function, or asynchronously at some later stage, the result should
+be returned by calling the base class function <xref href="GUID-A8B5FB5A-4709-3F29-B2CB-81FC5B0E7D63.dita#GUID-A8B5FB5A-4709-3F29-B2CB-81FC5B0E7D63/GUID-5643935F-9E97-35B0-9D92-88CA613F0016"><apiname>DPBusPsuBase::ReceiveVoltageCheckResult()</apiname></xref>.
+Pass <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> to indicate a successful check; pass <xref href="GUID-A94AC24A-EADF-3913-8345-708ED637968E.dita"><apiname>KErrGeneral</apiname></xref> to
+indicate a failed check. </p> <p>Note that this function is not called as
+part of <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-791BCA03-61F3-3C1C-BA2D-D633A94AF299"><apiname>DMMCStack::DoPowerUpSM()</apiname></xref> processing, which means
+that it is not possible to use this function to introduce a delay until power
+is stable when the PSU is turned on. If such a delay is required while the
+power lines stabilize, then it will be necessary to make this function part
+of the DoPowerUpSM state machine. </p> </section>
+<section id="GUID-C80E57B1-933B-55D7-949B-E68DB9B96B94"><title>DMMCMediaChange
+derived class</title> <p>This class provides support for dealing with media
+change events, i.e. the insertion and removal of removable media. </p> <p>A
+class needs to be derived from this in the platform specific layer to handle
+the Variant specific functionality. </p> <p>This class has a number of pure
+virtual functions that need to be implemented in your Variant DLL. The diagram
+at <xref href="GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF.dita#GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF/GUID-92F5EBE4-C9AD-5D9A-A80E-9AFD1A09B6B3">MultiMediaCard
+controller basic structure</xref> shows the class in context. </p> <p>There
+is one virtual function with an empty default implementation that needs to
+be overridden. </p> <ul>
+<li id="GUID-1BAEFE73-3B73-5BA7-872D-89C3B3F8BF75"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-BFC23CC1-102F-5740-A608-CF91C2BC3897">Create()</xref> </p> </li>
+<li id="GUID-C1235A87-68BB-5AF4-80F6-DFB7DBA8432C"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-726A2A5F-18D3-55BD-9B92-0676266794C6">MediaState()</xref>  </p> </li>
+<li id="GUID-BBAEC56C-DBA7-586C-A9CC-1E4E70A81096"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-1ADD0F5A-B561-54AE-BB2F-81AC3E8D81A4">DoDoorOpen()</xref>  </p> </li>
+<li id="GUID-22D6992C-868B-5E18-9AA0-624EA51DB529"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-58829228-43A9-546B-8CFD-31DF8FBB0078">DoDoorClosed()</xref>  </p> </li>
+<li id="GUID-04B7E650-7DA8-5F61-9D8E-89FC2B93AE20"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-F91B9434-5B90-5221-B5E6-D57F50391D81">ForceMediaChange()</xref>  </p> </li>
+</ul> <p id="GUID-BFC23CC1-102F-5740-A608-CF91C2BC3897"><b>Create()</b> </p> <p> <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita#GUID-2F974AD8-551B-35F0-B72C-99122913714D/GUID-F96EF34B-7B38-37DC-9B34-E0D4D1963622"><apiname>DMMCMediaChange::Create()</apiname></xref>  </p> <p>The
+function is intended to perform hardware initialization on the MultiMediaCard
+media change hardware, for example, setting port direction registers, binding
+to the door open interrupt etc. </p> <p>The function is called after creation
+of the <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita"><apiname>DMMCMediaChange</apiname></xref> derived class instance, which is
+done during kernel initialization when the MultiMediaCard controller Variant
+DLL extension is loaded. </p> <p>The function has a default implementation
+that just returns <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref>. </p> <p>Your implementation
+should return <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> if the hardware initialization is
+successful, otherwise it should return one of the system-wide error codes
+to indicate initialization failure. Note that returning a value other than <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> will
+cause the kernel to panic and to fail to boot. </p> <p id="GUID-726A2A5F-18D3-55BD-9B92-0676266794C6"><b> MediaState()</b> </p> <p> <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita#GUID-2F974AD8-551B-35F0-B72C-99122913714D/GUID-A951EF31-83F1-3E07-A5BD-5342B6125ACF"><apiname>DMMCMediaChange::MediaState()</apiname></xref>  </p> <p>The
+function should return the current state of the media, i.e. whether the media
+door is open or closed. To indicate the state, it should return one of the <xref href="GUID-49F96729-2DDB-37E0-AE39-9BEF2B7FF7F9.dita"><apiname>TMediaState</apiname></xref> enum
+values. </p> <p id="GUID-1ADD0F5A-B561-54AE-BB2F-81AC3E8D81A4"><b>DoDoorOpen()</b> </p> <p> <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita#GUID-2F974AD8-551B-35F0-B72C-99122913714D/GUID-6F734353-3458-3A8B-93E7-317674A1CAA4"><apiname>DMMCMediaChange::DoDoorOpen()</apiname></xref>  </p> <p>This
+function should handle a media door open event. What needs to be done depends
+on how door open and door closed events are detected. </p> <p>The most common
+pattern is where the platform hardware is capable of generating an interrupt
+when a door open event occurs, but cannot generate an interrupt when a door
+closed event occurs. In this situation, the hardware provides a readable door
+status that can be checked for the door closed state on a periodic basis (i.e.
+polling). </p> <p>Assuming this, <codeph>DoDoorOpen()</codeph> would need
+to enable a tick timer to poll for the door closing. The timer callback function
+would check the state of the door, and if this showed a closed door, the timer
+would be disabled and the function <xref href="GUID-C122D579-BB08-3084-A30E-DC857D6E7282.dita#GUID-C122D579-BB08-3084-A30E-DC857D6E7282/GUID-4F53C9F7-89C5-3CB6-A3D5-7DF40DAFF37F"><apiname>DMediaChangeBase::DoorClosedService()</apiname></xref> called.
+This results in a call to <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-58829228-43A9-546B-8CFD-31DF8FBB0078">DoDoorClosed()</xref>. </p> <p>Note that the door open interrupt is cleared before this function is
+called. The interrupt results in a call to <xref href="GUID-C122D579-BB08-3084-A30E-DC857D6E7282.dita#GUID-C122D579-BB08-3084-A30E-DC857D6E7282/GUID-6197984B-3884-367B-AE91-8E7E25203C95"><apiname>DMediaChangeBase::DoorOpenService()</apiname></xref>,
+which in turn results in a call to this function <codeph>DoDoorOpen()</codeph>. </p> <p>Your
+implementation would necessarily be different if an open door event could
+not be signalled by an interrupt and a tick timer were to be used to poll
+for an open door status. </p> <p id="GUID-58829228-43A9-546B-8CFD-31DF8FBB0078"><b>DoDoorClosed()</b> </p> <p> <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita#GUID-2F974AD8-551B-35F0-B72C-99122913714D/GUID-F26714BC-6648-349D-812D-6FD911602754"><apiname>DMMCMediaChange::DoDoorClosed()</apiname></xref>  </p> <p>This
+function should handle a media door closed event. What needs to be done depends
+on how door open and door closed events are detected. </p> <p>The most common
+pattern is where the platform hardware is capable of generating an interrupt
+when a door open event occurs, but cannot generate an interrupt when a door
+closed event occurs. In this situation, the hardware provides a readable door
+status that can be checked for the door closed state on a periodic basis (i.e.
+polling). </p> <p>Assuming this, <codeph>DoDoorClosed()</codeph> would be
+called by the timer callback function established by <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-1ADD0F5A-B561-54AE-BB2F-81AC3E8D81A4">DoDoorOpen()</xref> when the door status indicates a closed door; the function
+would need to re-enable the door open interrupt. </p> <p>Your implementation
+would necessarily be different if a closed door event were to be signalled
+by an interrupt. </p> <p id="GUID-F91B9434-5B90-5221-B5E6-D57F50391D81"><b> ForceMediaChange()</b> </p> <p> <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita#GUID-2F974AD8-551B-35F0-B72C-99122913714D/GUID-2DB81D37-C930-3B3C-A64E-B734039A2C95"><apiname>DMMCMediaChange::ForceMediaChange()</apiname></xref>  </p> <p>This function is called by the local media device driver to force a remount
+of the media device. For example to reopen a media driver in secure mode. </p> <p>It
+should result in the same sequence of operations as would occur if a door
+open event had taken place; for example, disabling the door open interrupt
+and calling <xref href="GUID-C122D579-BB08-3084-A30E-DC857D6E7282.dita#GUID-C122D579-BB08-3084-A30E-DC857D6E7282/GUID-6197984B-3884-367B-AE91-8E7E25203C95"><apiname>DMediaChangeBase::DoorOpenService()</apiname></xref>. </p> </section>
+<section id="GUID-7E709B21-8D38-5041-846F-CB7983B66834"><title>TMMCardControllerInterface
+derived class (The factory class)</title> <p>This is a class, also known as <xref href="GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF.dita#GUID-BE6AFD38-5952-537F-848C-C76C8F5FA9BF/GUID-26CFDD03-A4C4-5C96-88D4-5E750FDF69A3">the
+controller factory</xref> that is responsible for deciding which peripheral
+bus sockets are sockets that have been designated as a MultiMediaCard sockets
+on this platform. It is also responsible for creating the platform-specific
+layer objects associated with those MultiMediaCard sockets, i.e. the DMMCSocket,
+DMMCStack, DMMCMediaChange, and DMMCPsu objects. </p> <p>This class defines
+a number of pure virtual functions that need to be implemented in your Variant
+DLL to provide the functionality that is specific to your platform. </p> <p>An
+instance of your <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita"><apiname>TMMCardControllerInterface</apiname></xref> derived class
+is created in the <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-732EDE1D-452A-5A48-B5DB-1196C5F8BEBD">Variant
+DLL entry point code</xref>. </p> <ul>
+<li id="GUID-61BF196A-EFD3-57E1-98C2-A5B6350AC82E"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref> </p> </li>
+<li id="GUID-0FED2860-6710-517D-BB60-7FCBD043CEFB"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-829E686F-58F9-56A9-9EC4-CD59B14E127B">NewSocket()</xref> </p> </li>
+<li id="GUID-3213A9CF-3155-513D-9F29-AB573018F23B"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-E0F612EB-85BC-533D-A71C-3FC93D9CC708">NewStack()</xref>  </p> </li>
+<li id="GUID-9C8219D2-67EF-55B0-B01E-ACB2B0AC63CB"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-33A9C3DE-80EF-5895-BC7D-EA2ED6EB083B">MediaChangeID()</xref>  </p> </li>
+<li id="GUID-B8309E5D-7F8A-5B62-81B3-6679AFBC9319"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-6B1FE81F-1497-5447-9286-B0BE54AE6831">NewMediaChange()</xref> </p> </li>
+<li id="GUID-62725219-BAD2-528E-BC6A-84ACBA0A5C87"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-E969F613-01A3-54A7-8CC6-67F4A8E9558F">VccID()</xref>  </p> </li>
+<li id="GUID-67AE2495-BCF2-51B6-9F52-78FA36A65F2A"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-083F38DB-AC65-5257-B169-2099194D3082">NewVcc()</xref>  </p> </li>
+<li id="GUID-428FA30E-1E9A-50EA-BE3F-02E9B279E868"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-81A8BF8E-FB8B-596D-8C9A-690CD6449C12">Init()</xref>  </p> </li>
+</ul> <p id="GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA"><b>IsMMCSocket()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-5EC9F2EE-5D14-37F9-9EFE-95BD1062C681"><apiname>TMMCardControllerInterface::IsMMCSocket()</apiname></xref>  </p> <p>Implement this function to indicate whether the peripheral bus socket, as
+identified by the specified peripheral bus socket number, is designated as
+a MultiMediaCard socket on this platform. It should return <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref> if
+the socket has been so designated, and return <xref href="GUID-A759CA2D-8327-348F-9337-4886E619D920.dita"><apiname>EFalse</apiname></xref> if
+not. </p> <p>The function is called from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2C6EA849-1B62-3158-A328-DB2A7149346C"><apiname>TMMCardControllerInterface::Create()</apiname></xref>,
+which passes a socket number that can fall into the range 0 to <xref href="GUID-2C5A5F8F-381C-3B99-AADE-44474E629CC4.dita"><apiname>KMaxPBusSockets</apiname></xref>. </p> <p>Internally,
+Symbian platform reserves space for an array of pointers to <xref href="GUID-C988CAE6-9073-3851-A0B0-5479D1A34CFB.dita"><apiname>DPBusSocket</apiname></xref> objects,
+and this function allows the platform specific layer to identify which slot
+is to be used for the <xref href="GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7.dita"><apiname>DMMCSocket</apiname></xref> object. </p> <codeblock id="GUID-F1E0478A-8CE8-5E2F-87F8-AAFCCCE8A042" xml:space="preserve">GLDEF_D DPBusSocket* TheSockets[KMaxPBusSockets];</codeblock> <p>(This
+array is internal to Symbian platform.) </p> <p>If, on this platform, a socket
+has been designated as a MultiMediaCard stack, then the function not only
+returns <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref>, but also provides the media information
+for that socket, by filling in the members of the <xref href="GUID-FC0F974E-9ABB-348B-9AE9-778B3A1F413A.dita"><apiname>SMediaDeviceInfo</apiname></xref> object
+passed in. </p> <p id="GUID-829E686F-58F9-56A9-9EC4-CD59B14E127B"><b>NewSocket()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-90615A9A-BFC2-3E1B-B2AC-7D1CF322FC65"><apiname>TMMCardControllerInterface::NewSocket()</apiname></xref>  </p> <p>Implement
+this function to create, and return a pointer to, an instance of the <xref href="GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7.dita"><apiname>DMMCSocket</apiname></xref> class.
+This can be a class derived from <codeph>DMMCSocket</codeph>, but this should
+rarely be necessary. </p> <p>The function is called from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2C6EA849-1B62-3158-A328-DB2A7149346C"><apiname>TMMCardControllerInterface::Create()</apiname></xref>. </p> <p>If
+you create a <xref href="GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7.dita"><apiname>DMMCSocket</apiname></xref> object, simply forward the peripheral
+bus socket number and pointer to the password store; there is no need to do
+anything with them. </p> <p>If you create an instance of a <xref href="GUID-45B97680-1756-3559-8A2D-2F2E851AD6A7.dita"><apiname>DMMCSocket</apiname></xref> derived
+class, then just pass the socket number and pointer to the <codeph>DMMCSocket</codeph> constructor
+in your constructor's ctor list. </p> <p>Note: </p> <ul>
+<li id="GUID-FA8D57D9-0827-5090-A12B-A47C936B6F70"><p>The socket number can
+fall into the range 0 to <xref href="GUID-2C5A5F8F-381C-3B99-AADE-44474E629CC4.dita"><apiname>KMaxPBusSockets</apiname></xref>, and is a value
+for which <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref> returned <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref>. </p> </li>
+<li id="GUID-3C4FCA1F-558D-5964-91F5-98588694DA70"><p>This function is only
+called for sockets that are associated with MultiMediaCard devices as reported
+by the function <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref>. </p> </li>
+</ul> <p id="GUID-E0F612EB-85BC-533D-A71C-3FC93D9CC708"><b>NewStack()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-E2F99378-DD63-3BE0-8550-66EBF2C5D087"><apiname>TMMCardControllerInterface::NewStack()</apiname></xref>  </p> <p>Implement
+this function to create, and return a pointer to, an instance of a <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-4C6CA873-A798-5C79-8838-0CC3C9E914FB">DMMCStack derived class</xref>. </p> <p>The function is called from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2C6EA849-1B62-3158-A328-DB2A7149346C"><apiname>TMMCardControllerInterface::Create()</apiname></xref>. </p> <p>The
+peripheral bus socket number and pointer to the socket object should be forwarded
+to the <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita"><apiname>DMMCStack</apiname></xref> constructor in your class constructor's
+ctor list. </p> <p>Note: </p> <ul>
+<li id="GUID-CE363D03-6FEA-5AFE-A085-98D0FBAA9D52"><p>The socket number can
+fall into the range 0 to <xref href="GUID-2C5A5F8F-381C-3B99-AADE-44474E629CC4.dita"><apiname>KMaxPBusSockets</apiname></xref>, and is a value
+for which <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref> returned <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref>. </p> </li>
+<li id="GUID-7F8F2267-E8C3-5AC5-92AB-7D3179BA6D10"><p>The socket is the object
+created by <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-829E686F-58F9-56A9-9EC4-CD59B14E127B">NewSocket()</xref>. </p> </li>
+<li id="GUID-DF7C2369-D225-54E4-B6F1-D444343E7084"><p>This function is only
+called for sockets that are associated with MultiMediaCard devices as reported
+by the function <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref>. </p> </li>
+</ul> <p id="GUID-33A9C3DE-80EF-5895-BC7D-EA2ED6EB083B"><b>MediaChangeID()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-10B49F15-8ED5-3CA9-873A-788B87078367"><apiname>TMMCardControllerInterface::MediaChangeID()</apiname></xref>  </p> <p>Implement this function to report which media change object is to be
+associated with the specified peripheral bus socket number. </p> <p>The function
+is called from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2C6EA849-1B62-3158-A328-DB2A7149346C"><apiname>TMMCardControllerInterface::Create()</apiname></xref>. </p> <p>The
+media change object is represented by a number, which is simply an index value
+that ranges from 0 to <xref href="GUID-92555AA1-73A5-3F88-8227-8D20C977F046.dita"><apiname>KMaxMediaChanges</apiname></xref>. Internally, Symbian
+platform reserves space for an array of pointers to <xref href="GUID-C122D579-BB08-3084-A30E-DC857D6E7282.dita"><apiname>DMediaChangeBase</apiname></xref> objects,
+and this function allows the platform specific layer to identify which slot
+is to be used for the <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita"><apiname>DMMCMediaChange</apiname></xref> object that will
+correspond to the specified socket number. </p> <codeblock id="GUID-08AE1956-86E0-544A-A95C-0D16DE6694D3" xml:space="preserve">GLDEF_D DMediaChangeBase* TheMediaChanges[KMaxMediaChanges];</codeblock> <p>(This array is internal to Symbian platform.) </p> <p>Note: </p> <ul>
+<li id="GUID-1A4ED330-90E5-5215-8149-093987DD5D9B"><p>The socket number can
+fall into the range 0 to <xref href="GUID-2C5A5F8F-381C-3B99-AADE-44474E629CC4.dita"><apiname>KMaxPBusSockets</apiname></xref>, and is a value
+for which <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref> returned <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref>. </p> </li>
+<li id="GUID-5EA3662D-82B2-529B-8DF4-2EAA9429990A"><p>This function is only
+called for sockets that are associated with MultiMediaCard devices as reported
+by the function <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref>. </p> </li>
+</ul> <p id="GUID-6B1FE81F-1497-5447-9286-B0BE54AE6831"><b>NewMediaChange()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2961273F-0D5A-3B9E-94D8-1FE216A57985"><apiname>TMMCardControllerInterface::NewMediaChange()</apiname></xref>  </p> <p>Implement this function to create, and return a pointer to, an instance
+of a <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-C80E57B1-933B-55D7-949B-E68DB9B96B94">DMMCMediaChange
+derived class</xref>. </p> <p>The function is called from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2C6EA849-1B62-3158-A328-DB2A7149346C"><apiname>TMMCardControllerInterface::Create()</apiname></xref>. </p> <p>The
+media change number should be forwarded to the <xref href="GUID-2F974AD8-551B-35F0-B72C-99122913714D.dita"><apiname>DMMCMediaChange</apiname></xref> constructor
+in your class constructor's ctor list. </p> <p>Note: </p> <ul>
+<li id="GUID-69B6384E-1B3C-567B-89AD-E0BE42E1F043"><p>The media change number
+can fall into the range 0 to <xref href="GUID-92555AA1-73A5-3F88-8227-8D20C977F046.dita"><apiname>KMaxMediaChanges</apiname></xref>, and is the
+value returned by <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-33A9C3DE-80EF-5895-BC7D-EA2ED6EB083B">MediaChangeID()</xref>. </p> </li>
+<li id="GUID-FD2DA86D-5D0E-5661-AC09-55F10087D7A2"><p>This function is only
+called for sockets that are associated with MultiMediaCard devices as reported
+by the function <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref>. </p> </li>
+</ul> <p id="GUID-E969F613-01A3-54A7-8CC6-67F4A8E9558F"><b>VccID()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-1553B339-4171-396B-89E6-6C47C539D21F"><apiname>TMMCardControllerInterface::VccID()</apiname></xref>  </p> <p>Implement
+this function to report which power supply unit (PSU) object is to be associated
+with the specified peripheral bus socket number. </p> <p>The function is called
+from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2C6EA849-1B62-3158-A328-DB2A7149346C"><apiname>TMMCardControllerInterface::Create()</apiname></xref>. </p> <p>The
+PSU object is represented by a number, which is simply an index value that
+ranges from 0 to <xref href="GUID-E5DEB888-EC0E-3160-BA7D-76954B282D43.dita"><apiname>KMaxPBusVccs</apiname></xref>. Internally, Symbian platform
+reserves space for an array of pointers to <xref href="GUID-A8B5FB5A-4709-3F29-B2CB-81FC5B0E7D63.dita"><apiname>DPBusPsuBase</apiname></xref> objects,
+and this function allows the platform specific layer to identify which slot
+is to be used for the <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita"><apiname>DMMCPsu</apiname></xref> object that will correspond
+to the specified socket number. </p> <codeblock id="GUID-99CD9798-2CFB-533D-82E0-352B84FA5AC9" xml:space="preserve">GLDEF_D DPBusPsuBase* TheVccs[KMaxPBusVccs];
+</codeblock> <p>(This array is internal to Symbian platform.) </p> <p>Note: </p> <ul>
+<li id="GUID-2C77F138-1444-5815-AB12-16D3ED6D908E"><p>The socket number can
+fall into the range 0 to <xref href="GUID-2C5A5F8F-381C-3B99-AADE-44474E629CC4.dita"><apiname>KMaxPBusSockets</apiname></xref>, and is a value
+for which <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref> returned <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref>. </p> </li>
+<li id="GUID-F8F4E84D-C46D-5547-AD19-61FB30E2CC3F"><p>This function is only
+called for sockets that are associated with MultiMediaCard devices as reported
+by the function <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref>. </p> </li>
+</ul> <p id="GUID-083F38DB-AC65-5257-B169-2099194D3082"><b>NewVcc()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-600A5477-E99A-39BC-9982-D54C07A528BE"><apiname>TMMCardControllerInterface::NewVcc()</apiname></xref>  </p> <p>The
+function should create, and return a pointer to, an instance of a <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-3A1E907E-A74D-59CB-A1D6-FEF4849EF2D5">DMMCPsu derived class</xref>. </p> <p>The function is called from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-2C6EA849-1B62-3158-A328-DB2A7149346C"><apiname>TMMCardControllerInterface::Create()</apiname></xref>. </p> <p>The
+Power Supply Unit (PSU) number and the media change number should be forwarded
+to the <xref href="GUID-FBCEFDB6-28FF-3201-8E13-F12E3759E36B.dita"><apiname>DMMCPsu</apiname></xref> constructor in your class constructor's
+ctor list. </p> <p>Note: </p> <ul>
+<li id="GUID-833A0119-6A98-5F5F-BAEE-5070C7C23A55"><p>The PSU number can fall
+into the range 0 to <xref href="GUID-E5DEB888-EC0E-3160-BA7D-76954B282D43.dita"><apiname>KMaxPBusVccs</apiname></xref>, and is the value returned
+by <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-E969F613-01A3-54A7-8CC6-67F4A8E9558F">VccID()</xref>. </p> </li>
+<li id="GUID-25D7430A-2C12-50CF-BF84-FD2309732FC8"><p>The media change number
+can fall into the range 0 to <xref href="GUID-92555AA1-73A5-3F88-8227-8D20C977F046.dita"><apiname>KMaxMediaChanges</apiname></xref>, and is the
+value returned by <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-33A9C3DE-80EF-5895-BC7D-EA2ED6EB083B">MediaChangeID()</xref>. </p> </li>
+<li id="GUID-A8908747-E292-5D01-91E2-045DE2F341B2"><p>This function is only
+called for sockets that are associated with MultiMediaCard devices as reported
+by the function <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-2477BA25-2ADD-55CB-93F2-84F114221EBA">IsMMCSocket()</xref>. </p> </li>
+</ul> <p id="GUID-81A8BF8E-FB8B-596D-8C9A-690CD6449C12"><b>Init()</b> </p> <p> <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita#GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A/GUID-1F0C99EC-D8A9-304A-A738-BACAB5C766A6"><apiname>TMMCardControllerInterface::Init()</apiname></xref>  </p> <p>Implement
+this function to perform any initialization that the platform specific layer
+needs to do. </p> <p>It should return <xref href="GUID-6CA4F1ED-7947-3087-B618-D35858FAA3BC.dita"><apiname>KErrNone</apiname></xref> to indicate
+successful completion, or return one of the other system-wide error codes
+to indicate initialization failure. </p> <p>Note that you should <i>not</i> do
+any initialization that is specifically associated with: </p> <ul>
+<li id="GUID-9D706630-C477-5163-B0B2-5745D5D04559"><p>the stack - use <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-0B55A650-E9ED-56CB-B06F-B1113ACDF282">DMMCStack::Init()</xref> for
+this. </p> </li>
+<li id="GUID-99B883A6-FE47-5B7F-A9D1-01CCD7954DCD"><p>the power supply unit
+- use <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-6EB8EF1C-BCCB-54A1-8CBA-4E8A2A20CABE">DMMCPsu::DoCreate()</xref> for
+this. </p> </li>
+<li id="GUID-C7EAE4E6-DEE4-515A-83B1-E40EE8D37F32"><p>dealing with media change
+events - use <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-BFC23CC1-102F-5740-A608-CF91C2BC3897">DMMCMediaChange::Create()</xref> for
+this. </p> </li>
+</ul> </section>
+<section id="GUID-732EDE1D-452A-5A48-B5DB-1196C5F8BEBD"><title> Variant DLL
+entry point code</title> <p>The platform-specific layer as implemented in
+the Variant DLL is a standard kernel extension. The entry point for all standard
+kernel extensions is declared by a </p> <codeblock id="GUID-8835A131-2CDC-51AC-9C59-D72BAD651EA6" xml:space="preserve">DECLARE_STANDARD_EXTENSION()</codeblock> <p>statement,
+followed by the block of code that runs on entry to the DLL. </p> <p>Initialization
+of the MultiMediaCard DLL is done at this point, and follows the pattern shown
+below. It needs to create an instance of your <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita"><apiname>TMMCardControllerInterface</apiname></xref> derived
+class, followed by a call to <codeph>Create()</codeph> on this object. This
+starts a cascade of effects resulting in calls to your implementation of the <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita"><apiname>TMMCardControllerInterface</apiname></xref> functions,
+which in turn result in the creation of the platform-specific layer objects
+associated with the MultiMediaCard sockets, i.e. the DMMCSocket, DMMCStack,
+DMMCMediaChange, and DMMCPsu objects. </p> <codeblock id="GUID-16F754D1-6161-5E05-8BEA-2A89CC80CC41" xml:space="preserve">DECLARE_STANDARD_EXTENSION()
+//
+// Extension Entry Point
+//
+    {
+    __KTRACE_OPT(KPBUS1,Kern::Printf("Starting MMC interface"));
+
+    TInt r=KErrNoMemory;
+    TVARMMCardControllerInterface* pI=new TVARMMCardControllerInterface;
+    if (pI)
+        {
+        r=pI-&gt;Create();
+        }
+
+    __KTRACE_OPT(KPBUS1,Kern::Printf("MMC: Returns %d",r));
+    return r;
+    }
+</codeblock> <p>In this example, <codeph>TVARMMCardControllerInterface</codeph> is
+your class derived from <xref href="GUID-B1F2C60B-E098-395F-8ED0-FF33E3EC9E4A.dita"><apiname>TMMCardControllerInterface</apiname></xref>  </p> </section>
+<section id="GUID-00F918D3-761B-5500-805F-AB4DEE72144E"><title>Direct memory
+addressing</title> <p>To transfer data between a user side process and the
+media device, the Platform Specific Layer allocates a DMA-safe buffer at initialization.
+This buffer is allocated from physical memory. The memory in the user side
+process is virtual and you perform an inter-process copy of data between the
+user side process and the buffer allocated by the Platform Specific Layer. </p> <p>Data
+transfer is faster if the MultiMediaCard controller knows that an address
+passed in an I/O request is a physical address. The File caching and Demand
+Paging features in the file server and kernel can pass physical addresses.
+A physical address avoids the need for an inter-process copy operation. </p> <p>If
+you use a mechanism like <xref href="GUID-DF2F0439-AE1A-599C-91B9-6EF2177C3C7E.dita">DMA</xref> to
+transfer data, and your platform specific layer can deal with physical addresses,
+you need to make changes to the platform specific layer listed below. </p> <ul>
+<li id="GUID-04D498F3-F4BB-5A15-BE31-8DF6F11DB9BD"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-E50081BC-C923-5DAF-950C-9E1411916FED">Implement double buffers</xref>  </p> </li>
+<li id="GUID-39F10C4A-4291-579E-878B-E5BD2FB9C9D0"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-575211BC-BF66-5817-9825-EE402648D0CD">Register support for physical addresses</xref>  </p> </li>
+<li id="GUID-5638CD98-469C-587C-87B2-CA470D76F474"><p> <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-27FCEF7D-0AAB-599C-8405-4BD284308314">Modify the data transfer phase to handle physical memory</xref>  </p> </li>
+</ul> <p id="GUID-E50081BC-C923-5DAF-950C-9E1411916FED"><b>Implement double buffers</b> </p> <p>If
+you enable double buffer behavior, the MultiMediaCard subsystem can perform
+multiple data transfers in a single bus transaction. The double buffer implementation
+performs many data transfers in a single bus transaction. The MultiMediaCard
+subsystem logically splits the buffer allocated by the platform specific layer
+into two segments. Data transfer to the media device is in progress from one
+segment - this is the active segment. Concurrently, the media driver can prepare
+data in the other segment. </p> <p>To implement double buffers, you need to
+make changes to the platform specific layer. </p> <p><b>Use the command descriptor functions </b> </p> <ul>
+<li id="GUID-9471B51C-CB76-537F-B958-F61466A6B8F7"><p>Use the function <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-7BDD7C93-65D3-312B-B99E-B4B07AA32B2C"><apiname>TMMCCommandDesc::BlockLength()</apiname></xref> to
+get the block length of the transaction. Find all direct references in the
+source code of the platform specific layer to <codeph>TMMCCommandDesc::iBlockLength</codeph>.
+Replace each reference with a call to <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-7BDD7C93-65D3-312B-B99E-B4B07AA32B2C"><apiname>TMMCCommandDesc::BlockLength()</apiname></xref>  </p> </li>
+<li id="GUID-902FFE84-8F97-511D-B554-41283550DB16"><p>Use the function <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-65B1C01B-1C8D-373A-83DB-0CEFF17667FC"><apiname>TMMCCommandDesc::BufferLength()</apiname></xref> to
+get the length of the next active segment. Find all references to <codeph>TMMCCommandDesc::iTotalLength</codeph>.
+There are two areas in the code where this data member can be referenced: </p> <ul>
+<li id="GUID-626ACF48-ADD0-5530-8CDB-373A3855FF81"><p>code where you test
+the progress of the data transfer operation and set up the MMC command. Do
+not change this code, because <codeph>TMMCCommandDesc::iTotalLength</codeph> still
+represents the total amount of data to be transferred. </p> </li>
+<li id="GUID-25A1A62A-9B80-5ACB-B9BB-6884B4331CD7"><p>code where you set up
+the DMA controller to transfer a number of blocks of data. Replace references
+to <codeph>TMMCCommandDesc::iTotalLength</codeph> with calls to <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-65B1C01B-1C8D-373A-83DB-0CEFF17667FC"><apiname>TMMCCommandDesc::BufferLength()</apiname></xref>.
+This describes the size of the current segment. Note that if double buffers
+are not enabled, the value returned by this function is the same as <codeph>TMMCCommandDesc::iTotalLength</codeph>. </p> </li>
+</ul> </li>
+<li id="GUID-860835C7-D3FD-5727-9ADA-60E080EB1669"><p>You can use the function <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-DFD121A5-0C03-31A3-AF20-6E693EDC8502"><apiname>TMMCCommandDesc::IsDoubleBuffered()</apiname></xref> to
+determine if the current transaction uses double buffers. </p> </li>
+</ul> <p><b>Separate the command and data phases </b> </p> <p>Without double buffer
+behavior, a single MMC command is always associated with a single buffer into
+which the hardware transfers data. With double buffer behavior, multiple buffers
+or segments are used to transfer data within a single command. You need to
+separate the command and data transfer phases. </p> <p>This code fragment
+is a simplified example of a platform specific layer that sets up the command
+and the data transfers in separate stages: </p> <codeblock id="GUID-D349BEBB-E983-59AA-AA7F-29928D5491F5" xml:space="preserve">   
+   TMMCErr DExampleMMCStack::IssueMMCCommandSM()
+    {
+    enum states
+        {
+        EStBegin=0,
+        EStSetUpCommand,
+        EStWaitComplete,
+        EStEnd
+        };
+    
+       TMMCCommandDesc&amp; cmd = Command();
+    
+    SMF_BEGIN
+
+       /** ...omitted for clarity */
+         
+    SMF_STATE(EStSetUpCommand)
+                 
+       /**
+        * Set up the controller to issue the command.  Depending on
+        * the command type, this will prepare DMA transfers and wait
+        * for a response to be received before unblocking the stack.
+        */
+       BlockCurrentSession(KMMCBlockOnASSPFunction);
+    
+       SetupCommand(cmd);
+        
+       If(iDataTransfer)
+          SetupDataTransfer(cmd);
+
+        /**
+        * Wait for all events to be received
+        *  - command sent, data transferred, response received
+        */
+       SMF_WAITS(EStWaitComplete);
+         
+    SMF_STATE(EStWaitComplete)
+
+       /**
+        * Command issued, data transferred and response received.
+        *  - check for and report any errors
+        *
+        *  - Note, functionality omitted for clarity – in practice this will
+        *    check the controller status and wait for more events as appropriate.
+        */
+       TMMCErr err = KMMCErrNone;
+
+       if(iResponseExpected)
+          err = ExtractResponse();
+
+       if(iDataTransfer &amp;&amp; err == KMMCErrNone)
+          err = CheckDataTransferErrors();
+
+       if(err)
+           SMF_RETURN(err);
+
+    SMF_END
+    }
+
+</codeblock> <p>If you depend on the MMC controller to signal the completion
+of data transfer after all blocks have been transmitted or received, change
+the DMA controller. Change the code to block the stack when DMA transfer starts,
+and unblock the stack when the current DMA transfer finishes. Do this operation
+while you wait for the final interrupt that signals the end of the data transfer. </p> <p>The
+following code fragment shows how to set the <xref href="GUID-8A9A2DD2-C630-3651-8374-17BCF2A09AC4.dita"><apiname>KMMCBlockOnASSPFunction</apiname></xref> blocking
+condition before the start of DMA transfer. After DMA transfer has finished,
+unblock the stack in the DMA complete service routine, <xref href="GUID-8B538AA6-9489-309F-8756-2474310CD5DA.dita"><apiname>DmaService()</apiname></xref>. </p> <codeblock id="GUID-FC9573C5-7A01-536B-8DA4-82F6DB493849" xml:space="preserve">
+   void DExampleMMCStack::SetupDataTransfer(const TMMCCommandDesc&amp; aCmd)
+      {
+      TUint8* bufPtr = reinterpret_cast&lt;TUint8*&gt;(aCmd.iDataMemoryP);
+      TUint32 bufLen = aCmd.BufferLength();
+
+      /** ...omitted for clarity */
+
+      BlockCurrentSession(KMMCBlockOnASSPFunction);
+      iDmaController::Start(aCmd.Direction(), bufPtr, bufLen);
+      }
+
+
+   void DExampleDmaController::DmaService()
+      {
+      /** ...omitted for clarity */
+
+      Session().iState |= KMMCSessStateDoDFC;
+      UnBlockCurrentSession(KMMCBlockOnASSPFunction, KErrNone);
+      }
+</codeblock> <p><b>Implement the double buffer state machine </b> </p> <p>Update the platform
+specific layer to implement the double buffer state machine. You use the function <xref href="GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A.dita#GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A/GUID-32596EBB-4315-3EF7-8175-8579DE69F78B"><apiname>DMMCSession::RequestMoreData()</apiname></xref>.
+The platform specific layer uses this function to tell the MMC subsystem to
+prepare the next segment for data transfer. You call this function when the
+hardware is busy performing a DMA transfer for the current segment. This allows
+the MMC Media Driver to copy data to/from the client process ready for the
+next transfer while the MMC card is transferring it’s current payload. </p> <p>This
+function sets the static <codeph>KMMCBlockOnMoreData</codeph> blocking condition.
+The platform specific layer must use <codeph>SMF_WAITS</codeph> (or equivalent)
+to suspend the platform specific layer state machine until the media driver
+has processed the current segment. When finished, the command descriptor is
+populated with the details of the next segment to be transferred. The <codeph>KMMCBlockOnMoreData</codeph> block
+condition set by this function can be set with the <codeph>KMMCBlockOnASSPFunction</codeph> condition.
+It allows the hardware to perform useful work, (for example, transfer the
+current buffer to or from the card) while the media driver is busy preparing
+the next buffer. In this case, the platform specific layer is unblocked when
+both the hardware and media driver have completed their tasks. </p> <p>The
+following code fragment shows how you do this: </p> <codeblock id="GUID-97151CF9-2C59-57D3-8856-8BCAB9BDC5B9" xml:space="preserve">TMMCErr DExampleMMCStack::IssueMMCCommandSM()
+    {
+    enum states
+       {
+       EStBegin=0,
+       EStSetUpCommand,
+   EStWaitDataTransfer
+       EStWaitComplete,
+       EStEnd
+       };
+    
+       TMMCCommandDesc&amp; cmd = Command();
+    
+    SMF_BEGIN
+
+       /** ...omitted for clarity */
+         
+    SMF_STATE(EStSetUpCommand)
+                 
+       /**
+        * Set up the controller to issue the command.  Depending on
+        * the command type, this will prepare DMA transfers and wait
+        * for a response to be received before unblocking the stack.
+        */
+       BlockCurrentSession(KMMCBlockOnASSPFunction);
+    
+       SetupCommand(cmd);
+        
+       If(iDataTransfer)
+      {
+          /**
+       * Kick off DMA transfer for the first buffer.
+           * …the stack will be blocked on KMMCBlockOnASSPFunction until DMA complete
+       */
+          SetupDataTransfer(cmd);
+      
+      /**
+       * DMA is now active. Now request the Media Driver to prepare the next 
+       * buffer in parallel. While active, the stack will be blocked with
+       * the KMMCBlockOnMoreData blocking condition and unblocked when complete.
+       */
+      Session().RequestMoreData();      
+      }
+
+        /**
+        * Wait for DMA and Media Driver completion.
+        */
+       SMF_WAITS(EStWaitDataTransfer);
+         
+    SMF_STATE(EStWaitDataTransfer)
+
+       /**
+        * DMA is complete and the Media Driver has prepared the next buffer.
+        *  - Start the next DMA transfer and request more data from the media driver.
+        */
+
+       if(cmd.BufferLength() &gt; 0)
+          {
+          /**
+           * There is more data to transfer.
+           * ..start DMA transfer, prepare the next buffer and wait for completion.
+           */
+          SetupDataTransfer(cmd);
+      Session().RequestMoreData();      
+          SMF_WAITS(EStWaitDataTransfer);
+          }
+
+       /**
+        * There is no more data to transfer.
+        * ..do whatever we need to do to wait for hardware completion
+        */
+
+       // …omitted for clarity
+
+   SMF_WAITS(EStWaitComplete);
+
+    SMF_STATE(EStWaitComplete)
+
+       /**
+        * Command issued, data transferred and response received.
+        *  - check for and report any errors
+        *
+        *  - Note, functionality omitted for clarity – in practice this will
+        *    check the controller status and wait for more events as appropriate.
+        */
+       TMMCErr err = KMMCErrNone;
+
+       if(iResponseExpected)
+          err = ExtractResponse();
+
+       if(iDataTransfer &amp;&amp; err == KMMCErrNone)
+          err = CheckDataTransferErrors();
+
+       if(err)
+          SMF_RETURN(err);
+
+    SMF_END
+    }
+</codeblock> <p><b>Register support for double buffers with the platform independent layer </b> </p> <p>You
+must tell the <xref href="GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B.dita#GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B/GUID-119E4B4A-03DB-5C79-AA97-14434E4BC2CA">platform
+independent layer</xref> that you support double buffers. Set <xref href="GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8.dita#GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8/GUID-B11D1DA9-89C2-37E3-A2CD-19EF5706ACB8"><apiname>TMMCMachineInfo::ESupportsDoubleBuffering</apiname></xref> into
+the <xref href="GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8.dita"><apiname>TMMCMachineInfo</apiname></xref> object that you pass to <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-CEF0EDF7-4B33-5452-8635-51C5319F78AE">DMMCStack::MachineInfo()</xref>. </p> <p><b>Choose the size of the buffer </b> </p> <p>To choose the optimum size
+of buffer, you must perform benchmark tests on your system. A small buffer
+gives you a lower command setup latency, but DMA transfers and calls to the
+callback function <xref href="GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A.dita#GUID-0186BEDE-8E28-3F8C-8CAE-A8B92F41F47A/GUID-32596EBB-4315-3EF7-8175-8579DE69F78B"><apiname>DMMCSession::RequestMoreData()</apiname></xref> occur
+more frequently. The time taken to set up the DMA transfers can exceed the
+time taken to transfer the data into or out of the active segment. </p> <p><b>Testing </b> </p> <p>You need to do the standard E32 and F32 automated
+tests to check the operation of the MMC subsystem. You also need to perform
+the MMC specific manual test, T_MMCDRV. The test listed below performs data
+transfers in excess of the PSL buffer size to make sure that double buffer
+behavior is exercised. </p> <codeblock id="GUID-ED1D5B35-432C-5C54-9A13-92DD499316FD" xml:space="preserve">   
+   /**
+   @SYMTestCaseID PBASE-T_MMCDRV-0558
+   @SYMTestCaseDesc Test Long Read/Write Boundaries
+   @SYMTestPriority High
+
+   @SYMTestActions  
+
+   Perform and Write/Read/Verify for the given length (L) of data across the following boundaries.
+   Depending on the length, this will also perform a partial write/read at the end sector.
+
+             --------------
+            | Start    | End    |
+            |--------------|
+            | 0    | L    |
+            | 507    | L-507    |
+            | 10    | L    |
+            | 0    | L-3    |
+            | 27    | L-512    |
+            | 0    | L-509    |
+            | 3    | L-3    |
+             --------------
+
+   For each combination, the write/read/verify operations are performed in the following sequence:
+
+a: Write and Read in single 512-byte blocks.
+b: Write in a single operation (multiple blocks), Read in 512-Byte blocks.
+c: Write in 512-Byte blocks, Read in a single operation (multiple-blocks).
+d: Write and Read in a single operation (multiple-blocks).
+
+   In the cases where a partial read/write operation occurs (ie - the start and/or end position
+   don't lie within a sector boundary), the original contents of the start and/or end sectors are
+   read and stored at the start of the test, and compared with the contents of the sectors at the
+   end of the test to ensure that unwritten data within the sectors remain unaffected.
+  
+   @SYMTestExpectedResults All tests must pass
+
+   @SYMPREQ1389 REQ6951 Double Buffering and SD Switch
+   *
+   */
+
+</codeblock> <p>The test T_MMCDRV must be performed on versions of the platform
+specific layer that has: double buffers enabled, double buffers disabled,
+and with a number of different buffer sizes (for example, from 32k to 256k). </p> <p>The
+test cannot dynamically set the size of the buffer. You must do manual configuration
+of the buffer to test all configurations. </p> <p>To measure performance,
+use T_FSYSBM, with and without double buffers enable. </p> <p id="GUID-575211BC-BF66-5817-9825-EE402648D0CD"><b>Register support for physical
+addresses</b> </p> <p>There are three items to do: </p> <ul>
+<li id="GUID-0E169605-00B8-53F9-AF7A-5410EEE73A70"><p>you must tell the <xref href="GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B.dita#GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B/GUID-119E4B4A-03DB-5C79-AA97-14434E4BC2CA">platform
+independent layer</xref> that you support physical addresses in your implementation
+of <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-CEF0EDF7-4B33-5452-8635-51C5319F78AE">DMMCStack::MachineInfo()</xref>.
+The function takes a <xref href="GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8.dita"><apiname>TMMCMachineInfo</apiname></xref> type. Set the <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-CB8D99BA-8EC2-3A98-B3BF-BA5FEE3A6AE1"><apiname>THardwareConfig::ESupportsDMA</apiname></xref> flags
+into the <codeph>iFlags</codeph> member of <xref href="GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8.dita"><apiname>TMMCMachineInfo</apiname></xref>. </p> <p>If
+you set the <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-CB8D99BA-8EC2-3A98-B3BF-BA5FEE3A6AE1"><apiname>THardwareConfig::ESupportsDMA</apiname></xref> flag, you also
+set the <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-3276FBA3-7028-30C2-A820-CEBD77DCF817"><apiname>THardwareConfig::ESupportsDoubleBuffering</apiname></xref> flag
+automatically. This flag enables double buffer support. You must also<xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-E50081BC-C923-5DAF-950C-9E1411916FED">implement
+double buffers</xref> if you use physical addresses. </p> </li>
+<li id="GUID-752318C6-301B-51B0-A064-64EAEBCF0E35"><p>You must tell the <xref href="GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B.dita#GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B/GUID-119E4B4A-03DB-5C79-AA97-14434E4BC2CA">platform
+independent layer</xref> the maximum transfer length that you support. This
+can be a limit imposed on you by the hardware. For example, if you use DMA,
+the DMA controller can impose a limit. You set one of the flags listed below
+into the <codeph>iFlags</codeph> member of <xref href="GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8.dita"><apiname>TMMCMachineInfo</apiname></xref> in
+your implementation of <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-CEF0EDF7-4B33-5452-8635-51C5319F78AE">DMMCStack::MachineInfo()</xref>. </p> <p>Each flag represents a maximum transfer length. The MultiMediaCard
+subsystem splits a data transfer request that is bigger than the maximum into
+multiple data transfers. </p> <ul>
+<li id="GUID-1BD38D21-6B02-5610-8495-4C7C194657CF"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-3375EE8E-49B8-3F24-BF40-D780AD8E1B0A"><apiname>THardwareConfig::EMaxTransferLength_256K</apiname></xref> </p> </li>
+<li id="GUID-D4AB6165-036A-5259-922A-E9E1CB5749C8"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-F3BEFC8A-55F6-3B28-B383-6B33BAD2B5F7"><apiname>THardwareConfig::EMaxTransferLength_512K</apiname></xref> </p> </li>
+<li id="GUID-72380863-E20E-5478-98D8-FA342C14E80C"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-20FB2892-190F-31C4-9F58-66AAB02DC4E1"><apiname>THardwareConfig::EMaxTransferLength_1M</apiname></xref>  </p> </li>
+<li id="GUID-68C4292C-5D9D-5E23-8608-DFBA2846A8FA"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-45913568-5C4E-3A6F-A727-8734C303AC3D"><apiname>THardwareConfig::EMaxTransferLength_2M</apiname></xref>  </p> </li>
+<li id="GUID-D637F68D-4530-5BE5-9B99-A7437E7AF9BC"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-66707CB4-A8E0-305E-9599-D22CBBC41E91"><apiname>THardwareConfig::EMaxTransferLength_4M</apiname></xref>  </p> </li>
+<li id="GUID-69AD58F1-06F6-564C-B130-BDBF8F1745BB"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-DA25B30F-671C-3B54-B58D-9F58B17BC11F"><apiname>THardwareConfig::EMaxTransferLength_8M,</apiname></xref>  </p> </li>
+<li id="GUID-AAE1868C-8C51-58DE-8F29-34463E0F7104"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-565830C3-14D4-3AA7-990E-78A199275DDF"><apiname>THardwareConfig::EMaxTransferLength_16M</apiname></xref>  </p> </li>
+<li id="GUID-BFC9B360-8023-5AC5-A2FC-F52A7D6BFD06"><p> <xref href="GUID-FA278485-D2CC-35D8-A779-8F0BDB691C3F.dita"><apiname>TMMCMachineInfoV4.iFlags</apiname></xref>  </p> </li>
+</ul> </li>
+<li id="GUID-54BCDD97-4E54-52D5-9526-BFAC5041F8F8"><p>You must tell the <xref href="GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B.dita#GUID-40F2BC43-5022-5F4E-B445-56FEF43FEB8B/GUID-119E4B4A-03DB-5C79-AA97-14434E4BC2CA">platform
+independent layer</xref> the address scheme that the hardware uses. Mis-alignment
+of memory can corrupt data. You set <i>one</i> of the flags shown in the list
+below into the <codeph>iFlags</codeph> member of <xref href="GUID-3F9D89E8-44F0-35B3-9404-6CCAC79763E8.dita"><apiname>TMMCMachineInfo</apiname></xref> in
+your implementation of <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-CEF0EDF7-4B33-5452-8635-51C5319F78AE">DMMCStack::MachineInfo()</xref>. Each flags represents a different address scheme. You can set only one
+flag. If you set more than one of these flags, the creation of the media driver
+fails. </p> <ul>
+<li id="GUID-3055EE71-56B8-566A-A2B8-6F415F2D1675"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-A36BA08C-2010-3002-8FB2-A8E917700604"><apiname>THardwareConfig::EDma8BitAddressing</apiname></xref>  </p> </li>
+<li id="GUID-C71091D1-7E53-530B-8AE6-37BD9125B8B2"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-DA9AE183-855B-31A0-BDE3-54BFE894C1F8"><apiname>THardwareConfig::EDma16BitAddressing</apiname></xref>  </p> </li>
+<li id="GUID-6402A30F-4A49-528B-BF74-EB715521773B"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-6D844C49-AD50-3C73-BEA8-473A44B9E9D4"><apiname>THardwareConfig::EDma32BitAddressing</apiname></xref>  </p> </li>
+<li id="GUID-F10F9E09-151D-5BB2-B1B6-B0B08B49B8F6"><p> <xref href="GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6.dita#GUID-9E833DE8-E795-3EC8-B27B-CFB6D7E1C4C6/GUID-6F43817F-611B-326C-8A1C-55703FFC6500"><apiname>THardwareConfig::EDma64BitAddressing</apiname></xref>  </p> </li>
+</ul> </li>
+</ul> <p>The following code is an example implementation of <xref href="GUID-B5193656-9819-3E00-A335-EEF1726115A5.dita#GUID-B5193656-9819-3E00-A335-EEF1726115A5/GUID-3E5532A5-4645-3F77-A7A9-7AFF334FA5A4"><apiname>DMMCStack::MachineInfo()</apiname></xref>. </p> <codeblock id="GUID-BF942E07-A7E8-5300-9015-3FC06CAB835E" xml:space="preserve">void DVariantMmcHwStack::MachineInfo(TMMCMachineInfoV4&amp; aMachineInfo)
+/**
+ * Gets the machine info for the hardware variant
+ *
+ * @param aMachineInfo    Info structure to populate
+ */
+    {
+    aMachineInfo.iTotalSockets=MMC_DRIVECOUNT;
+    aMachineInfo.iTotalMediaChanges=0;          // Not used at present
+    aMachineInfo.iTotalPrimarySupplies=0;        // Not used at present
+    
+    aMachineInfo.iBaseBusNumber=0;
+    aMachineInfo.iVersion = TMMCMachineInfoV4::EVersion4;
+    aMachineInfo.iMaxBusWidth = EBusWidth4;
+
+    // Report support for Physical Addressing
+    aMachineInfo.iFlags  = TMMCMachineInfo::ESupportsDMA;
+    aMachineInfo.iFlags |= TMMCMachineInfo::EMaxTransferLength_1M; 
+    aMachineInfo.iFlags |= TMMCMachineInfo::EDma16BitAddressing;
+
+    // High voltage (3.6V) power class. Set to maximum = 2000mA RMS
+    aMachineInfo.iHighVoltagePowerClass = TMMCMachineInfoV4::EHi200mA;
+
+    // Low voltage (1.95V) power class. Set to maximum = 200mA RMS
+    aMachineInfo.iLowVoltagePowerClass = TMMCMachineInfoV4::ELo200mA;
+    
+    // 52 Mhz clock supported
+    aMachineInfo.iMaxClockSpeedInMhz = TMMCMachineInfoV4::EClockSpeed52Mhz;    
+    }</codeblock> <p id="GUID-27FCEF7D-0AAB-599C-8405-4BD284308314"><b>Modify the data transfer
+phase to handle physical memory </b> </p> <p>The implementation of double
+buffers has separated the command setup and the data transfer phases. You
+need to change the data transfer phase to handle physical memory. </p> <ul>
+<li id="GUID-59E7DD5F-39B6-5CA5-9C8C-CC4847A885DC"><p>The data member <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-596E150B-E5F1-3945-9C00-64B8EB24550C"><apiname>TMMCCommandDesc::iDataMemoryP</apiname></xref> contains
+the source or target memory address for the current data transfer command.
+Use the function <xref href="GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A.dita#GUID-6B3DDBFD-3A4A-3694-A058-7794700FEC7A/GUID-3A25BD15-A832-3C76-AB68-0B4470710C3A"><apiname>TMMCCommandDesc::IsPhysicalAddress()</apiname></xref> to
+determine if this address is a physical address or a virtual address. If you
+do not <xref href="GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B.dita#GUID-E55B4FE5-517C-5A23-8ACA-E28EE202330B/GUID-575211BC-BF66-5817-9825-EE402648D0CD">register
+support for physical addresses</xref>, this function always returns <xref href="GUID-A759CA2D-8327-348F-9337-4886E619D920.dita"><apiname>EFalse</apiname></xref>. </p> </li>
+<li id="GUID-B9D101C4-FDD1-5233-9DCB-12DDA47073FC"><p>You do not need to perform
+virtual address to physical address translation on physical addresses. </p> </li>
+<li id="GUID-2382A7A0-B0EB-5E1F-9ADE-47389FABABBA"><p>you do not need to perform
+DMA synchronization for physical addresses, because the local media subsystem
+performs DMA synchronization for you. You need to perform DMA synchronization
+for virtual addresses. DMA synchronization is performed by calls to <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-3FF3C567-C1BD-3D4E-97E1-B036456A374E"><apiname>Cache::SyncMemoryBeforeDmaRead()</apiname></xref> or <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-5F08DEAA-1237-32DE-AE41-CE7B18230972"><apiname>Cache::SyncMemoryBeforeDmaWrite()</apiname></xref>. </p> </li>
+</ul> <p>The following code is an example of the changes needed for a read
+operation. </p> <codeblock id="GUID-B92D3E0B-09F3-54C9-83AE-34DA544C0055" xml:space="preserve">TInt DMMCDmaRx::Start(const TMMCCommandDesc&amp; aCmd)
+/**
+ *  Queues a DMA request after checking the buffer alignment constraints.
+ *
+ *  @param aCmd The command structure containing the details about the command.
+ */
+{
+   …
+   TUint flags = KDmaMemDest;
+
+   // Check if a physical address has been provided with this request
+   if(aCmd.IsPhysicalAddress())
+{
+       // …if so, set the appropriate flag for this DDmaRequest
+flags |= KDmaPhysAddrDest;
+}
+
+   TInt retval = iRequest-&gt;Fragment(    KMMC_Buf_Dt_Reg,
+                                        (TUint32)aCmd.iDataMemoryP,
+                aCmd.BufferLength(), 
+                                 flags,
+                                 0 /* no HW Flags*/);
+
+   if(retval != KErrNone)
+Kern::Fault("MMC DMA RX Start Fragment", retval);
+
+   …
+   return KErrNone;
+}
+</codeblock> <codeblock id="GUID-AB1E5042-8680-57C4-87F7-71F362232C37" xml:space="preserve">void DMMCRxDmaHelp::ChannelTransfer(const SDmaPseudoDes&amp; aDes)
+    {
+…
+    TPhysAddr dest;
+
+// Don’t perform Linear to Physical translation if we 
+    // have already been supplied with a Physical Address
+    if (aDes.iFlags &amp; KDmaPhysAddrDest)
+        dest = (TPhysAddr) aDes.iDest;
+    else
+        dest = Epoc::LinearToPhysical(aDes.iDest);
+
+    TPlatDma::SetDMARegister(KHoDMA_CDSA(iChno), dest);
+…
+    }
+</codeblock> </section>
+</conbody></concept>
\ No newline at end of file