|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-C74770A5-ADD4-4AB1-946F-77105E2B8C10" xml:lang="en"><title>DMA |
|
13 Request Operations</title><shortdesc>This document describes the operations which a device driver performs |
|
14 on a DMA request.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
15 <p>After doing the required DMA initialisation, a driver can start a DMA operation. |
|
16 To do this, the driver fragments the request and then queues the request. </p> |
|
17 <section id="GUID-24567A76-814B-4E1C-81CA-61D9142B442B"><title>Fragment</title> <p>A |
|
18 DMA request can be split into different fragments that are small enough to |
|
19 be sent to DMAC. The size of each fragment is smaller than or equal to the |
|
20 maximum transfer size supported by the DMAC. To fragment a DMA request, a |
|
21 source and destination address, and the size of data to be transferred, must |
|
22 be provided. If the source and/or destination is in memory, each fragment |
|
23 points to memory which is physically contiguous. </p> <p>The kind of transfer |
|
24 to perform is specified using a set of flags and hardware-specific information. |
|
25 The flags can be: </p> <table id="GUID-52098463-21DE-5D42-8F35-9B6D67CE93BC"> |
|
26 <tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/> |
|
27 <tbody> |
|
28 <row> |
|
29 <entry><p> <xref href="GUID-F607BDD4-4ED7-3841-B355-C5099C42612A.dita"><apiname>KDmaMemSrc</apiname></xref> </p> </entry> |
|
30 <entry><p>Source is the address of a memory buffer </p> </entry> |
|
31 </row> |
|
32 <row> |
|
33 <entry><p> <xref href="GUID-B9018464-BBE0-3CF6-9B15-94E9658D1821.dita"><apiname>KDmaMmeDest </apiname></xref> </p> </entry> |
|
34 <entry><p>Destination is the address of a memory buffer </p> </entry> |
|
35 </row> |
|
36 <row> |
|
37 <entry><p> <xref href="GUID-018CF7EC-55F3-38CB-9AC5-31ADE568F20B.dita"><apiname>KDmaIncSrc</apiname></xref> </p> </entry> |
|
38 <entry><p>Source address must be post-incremented during transfer </p> </entry> |
|
39 </row> |
|
40 <row> |
|
41 <entry><p> <xref href="GUID-74D836AD-5A93-3971-9C73-583B4471AB18.dita"><apiname>KDmaIncDest</apiname></xref> </p> </entry> |
|
42 <entry><p>Destination address must be post-incremented during transfer </p> </entry> |
|
43 </row> |
|
44 <row> |
|
45 <entry><p> <xref href="GUID-45E60D7F-0309-3EC0-B621-A1DF4A3358B9.dita"><apiname>KDmaPhysAddrSrc</apiname></xref> </p> </entry> |
|
46 <entry><p>Source address is a physical address (as opposed to a linear one) </p> </entry> |
|
47 </row> |
|
48 <row> |
|
49 <entry><p> <xref href="GUID-82B3046B-F41C-3C99-8EAD-2F072D210BEF.dita"><apiname>KDmaPhysAddrDest</apiname></xref> </p> </entry> |
|
50 <entry><p>Destination address is a physical address (as opposed to a linear |
|
51 one) </p> </entry> |
|
52 </row> |
|
53 </tbody> |
|
54 </tgroup> |
|
55 </table> <p>The following shows an example of fragmenting a DMA request: </p> <codeblock id="GUID-E2DE10F1-7E22-5EA6-A05C-1A76B98D1F91" xml:space="preserve">/** |
|
56 Start the DMA transfer. This function fragments the DMA request and |
|
57 queues it for processing and actually triggers the DMA transfer. |
|
58 |
|
59 @param aSource |
|
60 Source address for DMA transfer |
|
61 |
|
62 @param aCount |
|
63 Size of data to be transferred |
|
64 |
|
65 @return KErrNone on success, else standard error code on failure |
|
66 */ |
|
67 TInt DExDriverUartTxDma::Start(const TUint8* aSource, TInt aCount) |
|
68 { |
|
69 ... |
|
70 // Fragment the DMA request. DDmaRequest::Fragment() creates |
|
71 // the DMA descriptor with source, destination address, size |
|
72 // and attributes. |
|
73 // |
|
74 // Flags KDmaMemSrc|KDmaIncSrc or KDmaMemDest|KDmaIncDest |
|
75 // should be set if the source/destination is a memory buffer, |
|
76 // or cleared if the source/destination is a peripheral. If the address |
|
77 // specified is physical address instead of linear, |
|
78 // then specify KDmaPhysAddrSrc or KDmaPhysAddrDest accordingly. |
|
79 // |
|
80 TInt retval = iTxDmaRequest->Fragment((TUint32)buf, |
|
81 (TUint32)(iUartComm->iPortAddr + KHoUART_THR), aCount, |
|
82 KDmaMemSrc |KDmaIncSrc, // source is a buffer |
|
83 0 ); // no HW Flags |
|
84 if(retval != KErrNone) |
|
85 { |
|
86 return retval; |
|
87 } |
|
88 ... |
|
89 }</codeblock> </section> |
|
90 <section id="GUID-72984A7F-C2C4-48E5-8656-638D472A2ACD"><title>Queue</title> <p>DMA transfer is initiated by queuing the |
|
91 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 |
|
92 fragmenting the DMA request. This is an asynchronous call and the transfer |
|
93 of DMA will actually start once the request is scheduled. </p> <codeblock id="GUID-FD225A28-4AFA-5CE0-A341-2261C97E7D1A" xml:space="preserve">/** |
|
94 Start the DMA transfer. This function fragments the DMA request and |
|
95 queues it for processing and actually triggers the DMA transfer. |
|
96 @param aSource Source address for DMA transfer |
|
97 @param aCount Size of data to be transferred |
|
98 @return KErrNone on success, else standard error code on failure |
|
99 */ |
|
100 TInt DExDriverUartTxDma::Start(const TUint8* aSource, TInt aCount) |
|
101 { |
|
102 ... |
|
103 |
|
104 // Queue the DMA request. DDmaRequest::Queue() queues the |
|
105 // request on the DFCQ. When it is processed, the SDMAC driver calls |
|
106 // the helper ChannelTransfer() to start the transfer on the |
|
107 // device. DMA operation starts at this point. |
|
108 // |
|
109 iTxDmaRequest->Queue(); |
|
110 |
|
111 ... |
|
112 }</codeblock> <p>If the request channel is idle when a request is queued, |
|
113 the request is transferred immediately. Otherwise, it is queued and transferred |
|
114 later. The client is responsible for ensuring cache consistency before and/or |
|
115 after the transfer if necessary. </p></section> |
|
116 <section id="GUID-FA035D89-F593-49C5-84EC-BC5019C63F0B"><title>Completion notification</title> <p>Once the DMA request is |
|
117 handled by the DMAC, the DMA service callback function is called by the DMA |
|
118 driver. This runs in a DFC context, that is scheduled from a DMA interrupt |
|
119 service routine. </p> <p>The DMA service callback function pointer must be |
|
120 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 |
|
121 request, so it needs to check the request result. On success, the function |
|
122 should either initiate another DMA request, or stop DMA and close the request. |
|
123 On failure, the function should stop DMA by cancelling the request. </p> <codeblock id="GUID-BD28E559-FA5B-564E-BC00-3BD98C61F201" xml:space="preserve">/** |
|
124 DMA service callback function for transmit. This static function is |
|
125 called on the completion of DMA transfer request. This function |
|
126 pointer is provided while creating the DMA request, i.e. in |
|
127 DDmaRequest(). After the request is queued, the System DMA controller |
|
128 completes the request and calls this service function. Here, we do |
|
129 the processing that needs to be done post the DMA request |
|
130 completion. |
|
131 |
|
132 This function shall be called both when the DMA request succeeds or fails, |
|
133 so both must be handled appropriately. |
|
134 |
|
135 @param aResult |
|
136 DMA result, can be DDmaRequest::EOk in case of success, else error |
|
137 |
|
138 @param aArg pointer passed at time of registration, typically <this> |
|
139 pointer |
|
140 |
|
141 @return none |
|
142 */ |
|
143 static void TxDmaService(DDmaRequest::TResult aResult, TAny* aArg) |
|
144 { |
|
145 // Check the result of DMA service function call. It can be |
|
146 // either of the DDmaRequest::TResult enumerated values. |
|
147 // |
|
148 if ( aResult != DDmaRequest::EOk) |
|
149 { |
|
150 // DMA request failed, so stop the DMA. |
|
151 Stop (); |
|
152 |
|
153 // Notify request completion with an error result |
|
154 ... |
|
155 } |
|
156 else |
|
157 { |
|
158 // DMA request was successful. |
|
159 // The program can start another DMA request, or stop |
|
160 // the DMA, if no more DMA requests are needed. |
|
161 // Notify request operation complete with success. |
|
162 ... |
|
163 } |
|
164 }</codeblock></section> |
|
165 </conbody></concept> |