|
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-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1" xml:lang="en"><title>DMA Request Operations</title><shortdesc>Describes the operations which a device driver performs |
|
13 on a DMA request.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <p>After doing the required DMA initialisation, a driver can start |
|
15 a DMA operation. To do this, the driver fragments the request and |
|
16 then queues the request. </p> |
|
17 <section id="GUID-24567A76-814B-4E1C-81CA-61D9142B442B-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-2"><title>Fragment</title> <p>A DMA request must be split into different fragments that are |
|
18 small enough to be transferred by the DMAC in a single transaction. |
|
19 The size of each fragment is smaller than or equal to the maximum |
|
20 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, |
|
22 must be provided. If the source and/or destination is in memory, each |
|
23 fragment points to memory which is physically contiguous. </p> <p>The kind of transfer to perform is specified using a set of flags |
|
24 and hardware-specific information. The flags can be: </p> <table id="GUID-52098463-21DE-5D42-8F35-9B6D67CE93BC-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-2-4"> |
|
25 <tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/> |
|
26 <tbody> |
|
27 <row> |
|
28 <entry><p> <codeph>KDmaMemSrc</codeph> </p> </entry> |
|
29 <entry><p>Source is the address of a memory buffer </p> </entry> |
|
30 </row> |
|
31 <row> |
|
32 <entry><p> <codeph>KDmaMmeDest</codeph> </p> </entry> |
|
33 <entry><p>Destination is the address of a memory buffer </p> </entry> |
|
34 </row> |
|
35 <row> |
|
36 <entry><p> <codeph>KDmaIncSrc</codeph> </p> </entry> |
|
37 <entry><p>Source address must be post-incremented during transfer </p> </entry> |
|
38 </row> |
|
39 <row> |
|
40 <entry><p> <codeph>KDmaIncDest</codeph> </p> </entry> |
|
41 <entry><p>Destination address must be post-incremented during transfer </p> </entry> |
|
42 </row> |
|
43 <row> |
|
44 <entry><p> <codeph>KDmaPhysAddrSrc</codeph> </p> </entry> |
|
45 <entry><p>Source address is a physical address (as opposed to a linear |
|
46 one) </p> </entry> |
|
47 </row> |
|
48 <row> |
|
49 <entry><p> <codeph>KDmaPhysAddrDest</codeph> </p> </entry> |
|
50 <entry><p>Destination address is a physical address (as opposed to |
|
51 a linear 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-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-2-6" 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-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-3"><title>Queue</title> <p>DMA transfer is initiated by queuing the DMA request. A device |
|
91 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 |
|
92 and the transfer of DMA will actually start once the request is scheduled. </p> <codeblock id="GUID-FD225A28-4AFA-5CE0-A341-2261C97E7D1A-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-3-3" xml:space="preserve">/** |
|
93 Start the DMA transfer. This function fragments the DMA request and |
|
94 queues it for processing and actually triggers the DMA transfer. |
|
95 @param aSource Source address for DMA transfer |
|
96 @param aCount Size of data to be transferred |
|
97 @return KErrNone on success, else standard error code on failure |
|
98 */ |
|
99 TInt DExDriverUartTxDma::Start(const TUint8* aSource, TInt aCount) |
|
100 { |
|
101 ... |
|
102 |
|
103 // Queue the DMA request. DDmaRequest::Queue() queues the |
|
104 // request on the DFCQ. DMA operation starts at this point. |
|
105 // |
|
106 iTxDmaRequest->Queue(); |
|
107 |
|
108 ... |
|
109 }</codeblock> <p>If the request channel is idle when a request |
|
110 is queued, the request is transferred immediately. Otherwise, it is |
|
111 queued and transferred later. The client is responsible for ensuring |
|
112 cache consistency before and/or after the transfer if necessary. </p></section> |
|
113 <section id="GUID-FA035D89-F593-49C5-84EC-BC5019C63F0B-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-4"><title>Completion |
|
114 notification</title><p>This is done by the DMA service callback function. |
|
115 The completion notification is as follows:</p> <p>Once the DMA request |
|
116 is handled by the DMAC, the DMA service callback function is called |
|
117 by the DMA driver. This runs in a DFC context, that is scheduled from |
|
118 a DMA interrupt service routine. </p> <p>The DMA service callback |
|
119 function pointer must be provided while creating the DMA request: </p> <codeblock id="GUID-0A15F944-F066-52E2-BFB6-D008DF690BA6-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-4-5" xml:space="preserve">iTxDmaRequest = new DDmaRequest(*iTxDmaChannel, TxDmaService, this);</codeblock> <p>The DMA callback function is called for both success and failure |
|
120 of the request, so it needs to check the request result. On success, |
|
121 the function should either initiate another DMA request, or stop DMA |
|
122 and close the request. On failure, the function should stop DMA. </p> <codeblock id="GUID-BD28E559-FA5B-564E-BC00-3BD98C61F201-GENID-1-2-1-10-1-5-1-5-1-1-7-1-9-1-6-1-3-4-7" xml:space="preserve">/** |
|
123 DMA service callback function for transmit. This static function is |
|
124 called on the completion of DMA transfer request. This function |
|
125 pointer is provided while creating the DMA request, i.e. in |
|
126 DDmaRequest(). After the request is queued, the System DMA controller |
|
127 completes the request and calls this service function. Here, we do |
|
128 the processing that needs to be done post the DMA request |
|
129 completion. |
|
130 |
|
131 This function shall be called both when the DMA request succeeds or fails, |
|
132 so both must be handled appropriately. |
|
133 |
|
134 @param aResult |
|
135 DMA result, can be DDmaRequest::EOk in case of success, else error |
|
136 |
|
137 @param aArg pointer passed at time of registration, typically <this> |
|
138 pointer |
|
139 |
|
140 @return none |
|
141 */ |
|
142 static void TxDmaService(DDmaRequest::TResult aResult, TAny* aArg) |
|
143 { |
|
144 // Check the result of DMA service function call. It can be |
|
145 // either of the DDmaRequest::TResult enumerated values. |
|
146 // |
|
147 if ( aResult != DDmaRequest::EOk) |
|
148 { |
|
149 // DMA request failed, so stop the DMA. |
|
150 Stop (); |
|
151 |
|
152 // Notify request completion with an error result |
|
153 ... |
|
154 } |
|
155 else |
|
156 { |
|
157 // DMA request was successful. |
|
158 // The program can start another DMA request, or stop |
|
159 // the DMA, if no more DMA requests are needed. |
|
160 // Notify request operation complete with success. |
|
161 ... |
|
162 } |
|
163 }</codeblock></section> |
|
164 </conbody><related-links> |
|
165 <link href="GUID-6AC01B10-92C1-4E56-813B-6853DFCF3386-GENID-1-2-1-9-1-6-1-8-1-7-1-5-1.dita"><linktext>DMA |
|
166 Requests</linktext></link> |
|
167 </related-links></concept> |