Week 12 contribution of PDK documentation_content. See release notes for details. Fixes Bug 2054, Bug 1583, Bug 381, Bug 390, Bug 463, Bug 1897, Bug 344, Bug 1319, Bug 394, Bug 1520, Bug 1522, Bug 1892"
<?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->Fragment((TUint32)buf,
(TUint32)(iUartComm->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->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 <this>
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>