Symbian3/PDK/Source/GUID-C74770A5-ADD4-4AB1-946F-77105E2B8C10.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Tue, 30 Mar 2010 16:16:55 +0100
changeset 6 43e37759235e
parent 5 f345bda72bc4
permissions -rw-r--r--
Week 12 contribution of example code"

<?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-C74770A5-ADD4-4AB1-946F-77105E2B8C10" xml:lang="en"><title>DMA
Request Operations</title><shortdesc>This document describes the operations which a device driver performs
on a DMA request.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p>After doing the required DMA initialisation, a driver can start a DMA operation.
To do this, the driver fragments the request and then queues the request. </p>
<section id="GUID-24567A76-814B-4E1C-81CA-61D9142B442B"><title>Fragment</title> <p>A
DMA request can be split into different fragments that are small enough to
be sent to DMAC. The size of each fragment is smaller than or equal to the
maximum transfer size supported by the DMAC. To fragment a DMA request, a
source and destination address, and the size of data to be transferred, must
be provided. If the source and/or destination is in memory, each fragment
points to memory which is physically contiguous. </p> <p>The kind of transfer
to perform is specified using a set of flags and hardware-specific information.
The flags can be: </p> <table id="GUID-52098463-21DE-5D42-8F35-9B6D67CE93BC">
<tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
<tbody>
<row>
<entry><p> <xref href="GUID-F607BDD4-4ED7-3841-B355-C5099C42612A.dita"><apiname>KDmaMemSrc</apiname></xref>  </p> </entry>
<entry><p>Source is the address of a memory buffer </p> </entry>
</row>
<row>
<entry><p> <xref href="GUID-B9018464-BBE0-3CF6-9B15-94E9658D1821.dita"><apiname>KDmaMmeDest </apiname></xref>  </p> </entry>
<entry><p>Destination is the address of a memory buffer </p> </entry>
</row>
<row>
<entry><p> <xref href="GUID-018CF7EC-55F3-38CB-9AC5-31ADE568F20B.dita"><apiname>KDmaIncSrc</apiname></xref>  </p> </entry>
<entry><p>Source address must be post-incremented during transfer </p> </entry>
</row>
<row>
<entry><p> <xref href="GUID-74D836AD-5A93-3971-9C73-583B4471AB18.dita"><apiname>KDmaIncDest</apiname></xref>  </p> </entry>
<entry><p>Destination address must be post-incremented during transfer </p> </entry>
</row>
<row>
<entry><p> <xref href="GUID-45E60D7F-0309-3EC0-B621-A1DF4A3358B9.dita"><apiname>KDmaPhysAddrSrc</apiname></xref>  </p> </entry>
<entry><p>Source address is a physical address (as opposed to a linear one) </p> </entry>
</row>
<row>
<entry><p> <xref href="GUID-82B3046B-F41C-3C99-8EAD-2F072D210BEF.dita"><apiname>KDmaPhysAddrDest</apiname></xref>  </p> </entry>
<entry><p>Destination address is a physical address (as opposed to a linear
one) </p> </entry>
</row>
</tbody>
</tgroup>
</table> <p>The following shows an example of fragmenting a DMA request: </p> <codeblock id="GUID-E2DE10F1-7E22-5EA6-A05C-1A76B98D1F91" xml:space="preserve">/**
 Start the DMA transfer. This function fragments the DMA request and 
 queues it for processing and actually triggers the DMA transfer.
 
 @param    aSource
        Source address for DMA transfer
         
    @param    aCount
         Size of data to be transferred            
             
 @return    KErrNone on success, else standard error code on failure
 */    
TInt DExDriverUartTxDma::Start(const TUint8* aSource, TInt aCount)
    {
    ...
    // Fragment the DMA request. DDmaRequest::Fragment() creates 
    // the DMA descriptor with source, destination address, size 
    // and attributes.
    // 
    // Flags KDmaMemSrc|KDmaIncSrc or KDmaMemDest|KDmaIncDest 
    // should be set if the source/destination is a memory buffer, 
    // or cleared if the source/destination is a peripheral. If the address 
    // specified is physical address instead of linear, 
    // then specify KDmaPhysAddrSrc or KDmaPhysAddrDest accordingly.
    //
    TInt retval = iTxDmaRequest-&gt;Fragment((TUint32)buf,
            (TUint32)(iUartComm-&gt;iPortAddr + KHoUART_THR), aCount,
            KDmaMemSrc |KDmaIncSrc, // source is a buffer
            0 ); // no HW Flags    
    if(retval != KErrNone)
        {
        return retval;
        }
    ...
    }</codeblock> </section>
<section id="GUID-72984A7F-C2C4-48E5-8656-638D472A2ACD"><title>Queue</title> <p>DMA transfer is initiated by queuing the
DMA request. A device driver queues the request by calling <xref href="GUID-780F4D53-5546-3B69-B328-0226C70EBDE2.dita#GUID-780F4D53-5546-3B69-B328-0226C70EBDE2/GUID-0A83F782-DB62-39ED-8D32-DBD5949C8D3F"><apiname>DDmaRequest::Queue()</apiname></xref> after
fragmenting the DMA request. This is an asynchronous call and the transfer
of DMA will actually start once the request is scheduled. </p> <codeblock id="GUID-FD225A28-4AFA-5CE0-A341-2261C97E7D1A" xml:space="preserve">/**
 Start the DMA transfer. This function fragments the DMA request and 
 queues it for processing and actually triggers the DMA transfer.
 @param    aSource Source address for DMA transfer
 @param    aCount Size of data to be transferred            
 @return    KErrNone on success, else standard error code on failure
 */
TInt DExDriverUartTxDma::Start(const TUint8* aSource, TInt aCount)
    {
    ...

    // Queue the DMA request. DDmaRequest::Queue() queues the 
    // request on the DFCQ. When it is processed, the SDMAC driver calls 
    // the helper ChannelTransfer() to start the transfer on the 
    // device. DMA operation starts at this point.
    //
    iTxDmaRequest-&gt;Queue();

    ...
    }</codeblock> <p>If the request channel is idle when a request is queued,
the request is transferred immediately. Otherwise, it is queued and transferred
later. The client is responsible for ensuring cache consistency before and/or
after the transfer if necessary. </p></section>
<section id="GUID-FA035D89-F593-49C5-84EC-BC5019C63F0B"><title>Completion notification</title> <p>Once the DMA request is
handled by the DMAC, the DMA service callback function is called by the DMA
driver. This runs in a DFC context, that is scheduled from a DMA interrupt
service routine. </p> <p>The DMA service callback function pointer must be
provided while creating the DMA request: </p> <codeblock id="GUID-0A15F944-F066-52E2-BFB6-D008DF690BA6" xml:space="preserve">iTxDmaRequest = new DDmaRequest(*iTxDmaChannel, TxDmaService, this);</codeblock> <p>The DMA callback function is called for both success and failure of the
request, so it needs to check the request result. On success, the function
should either initiate another DMA request, or stop DMA and close the request.
On failure, the function should stop DMA by cancelling the request. </p> <codeblock id="GUID-BD28E559-FA5B-564E-BC00-3BD98C61F201" xml:space="preserve">/**
 DMA service callback function for transmit. This static function is 
 called on the completion of DMA transfer request. This function 
 pointer is provided while creating the DMA request, i.e. in     
 DDmaRequest(). After the request is queued, the System DMA controller 
 completes the request and calls this service function. Here, we do 
 the processing that needs to be done post the DMA request  
 completion.
 
 This function shall be called both when the DMA request succeeds or fails, 
    so both must be handled appropriately.
 
 @param    aResult    
     DMA result, can be DDmaRequest::EOk in case of success, else error
             
 @param    aArg pointer passed at time of registration, typically &lt;this&gt; 
        pointer
 
 @return    none 
 */
static void TxDmaService(DDmaRequest::TResult aResult, TAny* aArg)
    {
    // Check the result of DMA service function call. It can be 
    // either of the DDmaRequest::TResult enumerated values.
    //
    if ( aResult != DDmaRequest::EOk)
        {
        // DMA request failed, so stop the DMA. 
        Stop ();

        // Notify request completion with an error result
        ...
        }
    else
        {
        // DMA request was successful. 
     // The program can start another DMA request, or stop 
        // the DMA, if no more DMA requests are needed.
        // Notify request operation complete with success.
        ...
        }
    }</codeblock></section>
</conbody></concept>