|
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-A4C19890-2380-5498-A5F8-3B6D95CEFEF4" xml:lang="en"><title>PSL |
|
13 Implementation</title><shortdesc>Describes how to create the PSL implementation.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <p>To create a port of the DMA Framework, you must create an implementation |
|
15 of the PSL for the DMA controller hardware.</p> |
|
16 <section id="GUID-8664FA8F-E53A-5DBA-999F-A0B800C1F54B"><title>Define and |
|
17 implement PSL-specific channel classes</title> <p>The choice of class to be |
|
18 used for implementing DMA channels is governed by the mode of operation to |
|
19 be supported: </p> <ul> |
|
20 <li id="GUID-C254C7CA-D010-5885-811D-05BEAF068EDD"><p>single-buffer channels |
|
21 should use <xref href="GUID-A8B4AD1B-770C-363E-A0DE-C78A9786CBDC.dita"><apiname>TDmaSbChannel</apiname></xref> </p> </li> |
|
22 <li id="GUID-91DDE5AD-16E5-5FCE-86E9-80069F2CCDDB"><p>double-buffer channels |
|
23 should use <xref href="GUID-FD76AF08-6250-3054-8A06-16343E385B23.dita"><apiname>TDmaDbChannel</apiname></xref> </p> </li> |
|
24 <li id="GUID-994E863D-2C32-5AE3-931A-B852855883CA"><p>scatter-gather channels |
|
25 should use <xref href="GUID-2D4CFBB1-8D64-3CF5-B6F0-B24D16D5BAD4.dita"><apiname>TDmaSgChannel</apiname></xref> </p> </li> |
|
26 </ul> <p>These three classes are defined in <filepath>dma.h</filepath>. </p> <p>In |
|
27 addition, the PSL may need to store channel-specific data. One way of achieving |
|
28 this is by deriving a PSL-specific class from one of the generic ones. For |
|
29 example, the template scatter-gather implementation defines a <codeph>TTemplateSgChannel</codeph> class |
|
30 derived from <codeph>TDmaSgChannel</codeph> for storing data when appending |
|
31 new descriptors to a running channel: </p> <codeblock id="GUID-C4807321-01A3-5893-800A-6E22B8B5E131" xml:space="preserve">class TTemplateSgChannel : public TDmaSgChannel |
|
32 { |
|
33 public: |
|
34 TDmaDesc* iTmpDes; |
|
35 TPhysAddr iTmpDesPhysAddr; |
|
36 }; |
|
37 |
|
38 </codeblock> </section> |
|
39 <section id="GUID-0991CFB7-B37E-57B9-BC1F-4A69FEDAF5A5"><title>Define and |
|
40 implement the controller classes</title> <p>A controller can either be a physical |
|
41 controller, or a logical one depending on which <xref href="GUID-97F97D7B-D5A3-5471-A359-77B805ED198C.dita">DMA |
|
42 mode you intend to support</xref>. </p> <p>The PSL (platform-specific layer) |
|
43 must define one concrete controller class per supported controller. A controller |
|
44 class is derived from <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref>. The concrete class must implement |
|
45 all the pure virtual functions defined in <codeph>TDmac</codeph>, and, optionally |
|
46 the functions used to manipulate hardware descriptors. </p> <p>Taking the |
|
47 template port as an example, the class is defined as: </p> <codeblock id="GUID-1C275111-6597-5616-822A-9EABF40BFE77" xml:space="preserve">class TTemplateDmac : public TDmac |
|
48 { |
|
49 public: |
|
50 TTemplateDmac(); |
|
51 TInt Create(); |
|
52 private: |
|
53 // from TDmac (PIL pure virtual) |
|
54 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); |
|
55 virtual void StopTransfer(const TDmaChannel& aChannel); |
|
56 virtual TBool IsIdle(const TDmaChannel& aChannel); |
|
57 virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
58 virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); |
|
59 // from TDmac (PIL virtual) |
|
60 virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
61 TUint aFlags, TUint32 aPslInfo, TUint32 aCookie); |
|
62 virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); |
|
63 virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
|
64 const SDmaDesHdr& aNewHdr); |
|
65 virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); |
|
66 // other |
|
67 static void Isr(TAny* aThis); |
|
68 inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr); |
|
69 private: |
|
70 static const SCreateInfo KInfo; |
|
71 public: |
|
72 TTemplateSgChannel iChannels[KChannelCount]; |
|
73 }; |
|
74 </codeblock> <p>Notes: </p> <ul> |
|
75 <li id="GUID-4E8059FF-0BBC-5F65-9F66-3C96BC86FE55"><p>The array of channels |
|
76 must be defined in the PSL controller class because only the PSL knows what |
|
77 kind of channels are used. </p> </li> |
|
78 <li id="GUID-66E7787B-E933-5E17-9169-E0D245B9D27A"><p>The PSL controller class |
|
79 must be allocated in the BSS section of the DMA kernel extension. The second |
|
80 phase constructor must be called from the extension entry point. </p> </li> |
|
81 <li id="GUID-7306F4CB-5D0F-5E82-AC61-E068A48C9C9B"><p>The C++ constructor |
|
82 must pass a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure to the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor. |
|
83 This structure defines what the PIL (platform-independent layer) needs to |
|
84 know about the underlying DMA controller. The template <codeph>TTemplateDmac</codeph> constructor |
|
85 just passes a <codeph>TDmac::ScreateInfo</codeph> structure, which defines |
|
86 the layout of the (base class managed) descriptor pool to the base class constructor |
|
87 through a ctor list: </p> <codeblock id="GUID-E00DD5C0-0976-58A0-B3C0-22DFD9216BC0" xml:space="preserve">TTemplateDmac::TTemplateDmac() |
|
88 // |
|
89 // Constructor. |
|
90 // |
|
91 : TDmac(KInfo) |
|
92 {} |
|
93 |
|
94 </codeblock> <p>where KInfo is a <codeph>TDmac::ScreateInfo</codeph> type. </p> </li> |
|
95 <li id="GUID-4C6FB95D-BE6F-5938-8AC3-824B3BB508EE"><p>The PSL controller class |
|
96 needs a second phase constructor. This is the <codeph>Create()</codeph> function, |
|
97 which must: </p> <ol id="GUID-33DC912F-C5B4-5F33-A427-62700522D958"> |
|
98 <li id="GUID-F0E8A497-B09F-5DA0-A94A-3B08FC28707C"><p>call the second phase |
|
99 constructor of the base class: <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref>. </p> </li> |
|
100 <li id="GUID-1FD43FAD-4F43-557E-9EF0-19C725DD5FF5"><p>perform any hardware-specific |
|
101 initialisation. </p> </li> |
|
102 <li id="GUID-A522B8D4-744B-5C5B-B684-C82F34462171"><p>bind and enable the |
|
103 DMA interrupt(s). </p> </li> |
|
104 </ol> <p>In the template port, <codeph>Create()</codeph> calls the base class <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref> function |
|
105 and then initialises the template specific channel object members (the temporary |
|
106 descriptor fields used for appending requests to live channels), and performs |
|
107 platform specific initialisation for the interrupt dispatch of DMA interrupt |
|
108 events: </p> <codeblock id="GUID-FBCC8132-129C-53A4-99B7-290B56C3035D" xml:space="preserve">TInt TTemplateDmac::Create() |
|
109 // |
|
110 // Second phase construction. |
|
111 // |
|
112 { |
|
113 TInt r = TDmac::Create(KInfo); // Base class Create() |
|
114 if (r == KErrNone) |
|
115 { |
|
116 __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone); |
|
117 for (TInt i=0; i < KChannelCount; ++i) |
|
118 { |
|
119 TDmaDesc* pD = HdrToHwDes(*iFreeHdr); |
|
120 iChannels[i].iTmpDes = pD; |
|
121 iChannels[i].iTmpDesPhysAddr = DesLinToPhys(pD); |
|
122 iFreeHdr = iFreeHdr->iNext; |
|
123 } |
|
124 r = Interrupt::Bind(EAsspIntIdDma, Isr, this); |
|
125 if (r == KErrNone) |
|
126 { |
|
127 // TO DO: Map DMA clients (requests) to DMA channels here. |
|
128 |
|
129 r = Interrupt::Enable(EAsspIntIdDma); |
|
130 } |
|
131 } |
|
132 return r; |
|
133 } |
|
134 </codeblock> </li> |
|
135 </ul> </section> |
|
136 <section id="GUID-0DBA2E68-7759-5447-B34B-14F237369CB1"><title>Implement the |
|
137 channel allocator</title> <p>Channel allocation is implemented in the PSL |
|
138 (platform-specific layer) because this is a hardware-specific operation. There |
|
139 are two basic options: </p> <ul> |
|
140 <li id="GUID-A9246754-F21B-5BFC-9FDB-2CE5C92D1FA3"><p>Preallocate, at design |
|
141 time, one channel per DMA-aware peripheral. This is the simplest approach, |
|
142 and it should be acceptable for most Symbian platform devices because the |
|
143 set of supported peripherals is closed. In this case, cookies passed by client |
|
144 device drivers map uniquely to DMA channels. </p> </li> |
|
145 <li id="GUID-C1164FA0-9B70-55C1-9C5A-2D02728FA67A"><p>Full dynamic allocation. |
|
146 This is a simple approach too, but DMA channels are, in general, not completely |
|
147 identical. For example, some channels may have greater priorities than others. </p> </li> |
|
148 </ul> <p>Mixed schemes are also possible, for example, client device driver |
|
149 cookies could be used to select a subset of channels, and dynamic allocation |
|
150 used inside this subset. </p> <p>Whatever option is chosen, the PSL must provide |
|
151 an implementation for the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-934F46B3-1DF9-3870-87EE-A8E2DEF82810"><apiname>DmaChannelMgr::Open()</apiname></xref>. |
|
152 The template implementation is: </p> <codeblock id="GUID-9C7F5850-F72B-5A16-9DA0-606FBABAB5F0" xml:space="preserve">TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId) |
|
153 // |
|
154 // |
|
155 // |
|
156 { |
|
157 __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId)); |
|
158 |
|
159 __DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount)); |
|
160 |
|
161 TDmaChannel* pC = Controller.iChannels + aOpenId; |
|
162 if (pC->IsOpened()) |
|
163 pC = NULL; |
|
164 else |
|
165 { |
|
166 pC->iController = &Controller; |
|
167 pC->iPslId = aOpenId; |
|
168 } |
|
169 |
|
170 return pC; |
|
171 } |
|
172 </codeblock> <p>The template DMA channel manager returns a pointer to |
|
173 a DMA channel if the channel has not been previously allocated. Note that |
|
174 since channels possess preset priorities, the device drivers must be aware |
|
175 of which channel(s) they require DMA service from and configure the DMA controller |
|
176 to route sources to allocated channels accordingly. </p> <p>The platform-specific |
|
177 cookies passed by client device drivers to the PSL must be defined somewhere |
|
178 so that client device drivers can access them. </p> </section> |
|
179 <section id="GUID-6B35E9A7-11D6-5B26-B562-934169503412"><title>[Optionally] |
|
180 implement channel cleanup</title> <p>In the template PSL (platform-specific |
|
181 layer), the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-909D795A-7303-3A76-9C8E-3B07A97DD716"><apiname>DmaChannelMgr::Close()</apiname></xref> is a no-operation. |
|
182 This function is called by the PIL (platform-independent layer) when client |
|
183 device drivers call <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-8204AFBD-2A60-372E-B626-35BD19851FF7"><apiname>TDmaChannel::Close()</apiname></xref>. If the PSL needs |
|
184 to perform any hardware-specific operation when the channel is closed, then |
|
185 the implementation of <codeph>DmaChannelMgr::Close()</codeph> should be updated |
|
186 to reflect that. </p> </section> |
|
187 <section id="GUID-C9439F04-0BCC-5BC7-B18B-5C1B88515340"><title>Implement the |
|
188 mandatory controller virtual functions</title> <p>The <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> class |
|
189 contains several pure virtual functions that must be implemented by the PSL |
|
190 (platform-specific layer): </p> <ul> |
|
191 <li id="GUID-FF533DDF-E4B1-5AD1-9CBD-19A1D94AB07D"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-81921A9D-41F5-34BC-B882-60CC4CD807FB"><apiname>TDmac::Transfer()</apiname></xref> </p> </li> |
|
192 <li id="GUID-F6D6524A-09E3-54C0-AEB6-1D6BAB29210C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-B738D1B9-80FA-334D-ABEB-DFFF093E0B9D"><apiname>TDmac::StopTransfer()</apiname></xref> </p> </li> |
|
193 <li id="GUID-6209F3C7-9E3C-58BF-ABA4-6DF4BBF44A82"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-7422834D-CE6B-32DB-A040-7762A8BAB7D7"><apiname>TDmac::IsIdle()</apiname></xref> </p> </li> |
|
194 </ul> <p>These functions start and stop transfers on a DMA channel and are |
|
195 the main interface between the PIL (platform-independent layer) and the PSL. |
|
196 The implementation of these functions depends on the hardware available for |
|
197 performing DMA, and on the characteristics used to specify a DMA transfer: </p> <ul> |
|
198 <li id="GUID-81DA9FED-18F0-5205-9597-33542B0CB3CC"><p>the source and destination |
|
199 addresses </p> </li> |
|
200 <li id="GUID-D6684249-31CC-544B-8CEE-DD1D7FC8A8A1"><p>the burst size </p> </li> |
|
201 <li id="GUID-91D910DB-E1D7-5993-9ADB-6823662249D0"><p>the maximum transfer |
|
202 size </p> </li> |
|
203 <li id="GUID-C1926D7D-8349-5BA1-8E21-AB5D90486443"><p>the transfer width, |
|
204 i.e. number of bits per memory access </p> </li> |
|
205 <li id="GUID-C091D505-1088-56CA-8630-F1099B0A2234"><p>the memory alignment |
|
206 and endianness. </p> </li> |
|
207 </ul> <p>The DMA Framework manages the transfer descriptors according to the |
|
208 descriptor parameter passed into the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor |
|
209 by the derived class constructor; the descriptor parameter is a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure. |
|
210 The per-request transfer parameters are passed into the descriptors for each |
|
211 request issued by a driver. </p> <p><b>The |
|
212 transfer function: Transfer()</b> </p> <p>This function initiates a previously |
|
213 constructed request on a specific channel. This is the template implementation: </p> <codeblock id="GUID-80B95C0E-B30D-5A10-8512-68317D404DB3" xml:space="preserve">void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) |
|
214 // |
|
215 // Initiates a (previously constructed) request on a specific channel. |
|
216 // |
|
217 { |
|
218 const TUint8 i = static_cast<TUint8>(aChannel.PslId()); |
|
219 TDmaDesc* pD = HdrToHwDes(aHdr); |
|
220 |
|
221 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD)); |
|
222 |
|
223 // TO DO (for instance): Load the first descriptor address into the DMAC and start it |
|
224 // by setting the RUN bit. |
|
225 (void) *pD, (void) i; |
|
226 |
|
227 } |
|
228 </codeblock> <p><b>The |
|
229 stop transfer function: StopTransfer()</b> </p> <p>This function requires |
|
230 that the RUN mode is cleared. This is the template implementation: </p> <codeblock id="GUID-1BF7A5B4-2723-5A18-98E0-1F79A4928121" xml:space="preserve">void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel) |
|
231 // |
|
232 // Stops a running channel. |
|
233 // |
|
234 { |
|
235 const TUint8 i = static_cast<TUint8>(aChannel.PslId()); |
|
236 |
|
237 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i)); |
|
238 |
|
239 // TO DO (for instance): Clear the RUN bit of the channel. |
|
240 (void) i; |
|
241 |
|
242 } |
|
243 </codeblock> <p><b>The |
|
244 function: IsIdle()</b> </p> <p> <codeph>IsIdle()</codeph> returns the state |
|
245 of a given channel. This is the template implementation: </p> <codeblock id="GUID-C7CC986E-986B-5C5E-AA3D-86851131BE93" xml:space="preserve">TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel) |
|
246 // |
|
247 // Returns the state of a given channel. |
|
248 // |
|
249 { |
|
250 const TUint8 i = static_cast<TUint8>(aChannel.PslId()); |
|
251 |
|
252 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::IsIdle channel=%d", i)); |
|
253 |
|
254 // TO DO (for instance): Return the state of the RUN bit of the channel. |
|
255 // The return value should reflect the actual state. |
|
256 (void) i; |
|
257 |
|
258 return ETrue; |
|
259 } |
|
260 </codeblock> </section> |
|
261 <section id="GUID-A362A7CF-3674-525C-8114-485315E6594B"><title>Implement the |
|
262 non-mandatory controller virtual functions</title> <p>The following auxiliary |
|
263 functions are used to implement the scatter-gather transfer mode behaviour |
|
264 by creating and manipulating the linked list of transfer fragment headers |
|
265 that describe a given scatter-gather transaction. They are called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base |
|
266 class functions when the instance of the <codeph>TDmac</codeph> derived class |
|
267 reports itself as being capable of scatter-gather operations. </p> <ul> |
|
268 <li id="GUID-D401D7C8-B086-56CD-BAE0-96EEB0AA7E38"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-90AC3E58-E589-3F91-85F7-16A4ADFFFA69"><apiname>TDmac::InitHwDes()</apiname></xref> </p> </li> |
|
269 <li id="GUID-58633367-FE56-53B7-A967-21828DA85F5C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-05021B05-75DE-3F75-92C6-8B9445EB86D3"><apiname>TDmac::ChainHwDes()</apiname></xref> </p> </li> |
|
270 <li id="GUID-94F81366-77D4-5AF6-9933-53E964863301"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> </p> </li> |
|
271 </ul> <p><b>First |
|
272 scatter-gather support function: InitHwDes()</b> </p> <p>This is a function |
|
273 for creating a scatter-gather list. From the information in the passed-in |
|
274 request, the function sets up the descriptor with that fragment's: </p> <ul> |
|
275 <li id="GUID-098E886D-D98D-5AC9-BB25-7FF8E6F0D05B"><p>source and destination |
|
276 address </p> </li> |
|
277 <li id="GUID-83440454-B955-55C8-BF10-DF86CDA0C466"><p>size </p> </li> |
|
278 <li id="GUID-294D3B08-0A64-534D-858F-F43759A2DC59"><p>driver/DMA controller |
|
279 specific transfer parameters: memory/peripheral, burst size, transfer width. </p> </li> |
|
280 </ul> <p>This is the template implementation: </p> <codeblock id="GUID-EB6F9C76-EC23-5464-A6C5-AB0B36717D2B" xml:space="preserve">void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, |
|
281 TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/) |
|
282 // |
|
283 // Sets up (from a passed in request) the descriptor with that fragment's source and destination address, |
|
284 // the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral, |
|
285 // burst size, transfer width). |
|
286 // |
|
287 { |
|
288 TDmaDesc* pD = HdrToHwDes(aHdr); |
|
289 |
|
290 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD)); |
|
291 |
|
292 // Unaligned descriptor? Error in generic layer! |
|
293 __DMA_ASSERTD(IsHwDesAligned(pD)); |
|
294 |
|
295 pD->iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc); |
|
296 pD->iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest); |
|
297 pD->iCmd = DcmdReg(aCount, aFlags, aPslInfo); |
|
298 pD->iDescAddr = TDmaDesc::KStopBitMask; |
|
299 } |
|
300 |
|
301 </codeblock> <p><b>Second |
|
302 scatter-gather support function: ChainHwDes()</b> </p> <p>If the framework |
|
303 needs to fragment the client’s request, for transfer size or memory discontiguousness |
|
304 reasons, then the framework calls this function. It chains hardware descriptors |
|
305 together by setting the next pointer of the original descriptor to the physical |
|
306 address of the descriptor to be chained. It assumes that the DMAC channel |
|
307 is quiescent when called. </p> <p>This is the template implementation: </p> <codeblock id="GUID-7979A1FB-5FA1-5078-8762-3874A62E6C63" xml:space="preserve">void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr) |
|
308 // |
|
309 // Chains hardware descriptors together by setting the next pointer of the original descriptor |
|
310 // to the physical address of the descriptor to be chained. |
|
311 // |
|
312 { |
|
313 TDmaDesc* pD = HdrToHwDes(aHdr); |
|
314 TDmaDesc* pN = HdrToHwDes(aNextHdr); |
|
315 |
|
316 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN)); |
|
317 |
|
318 // Unaligned descriptor? Error in generic layer! |
|
319 __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN)); |
|
320 |
|
321 // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer. |
|
322 |
|
323 pD->iDescAddr = DesLinToPhys(pN); |
|
324 } |
|
325 |
|
326 </codeblock> <p><b>Third |
|
327 scatter-gather support function: AppendHwDes()</b> </p> <p>This function is |
|
328 called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base class when a driver request is |
|
329 called for a channel that is still active, i.e. where the intent is to provide |
|
330 data streaming so that the target device is constantly provided with data; |
|
331 for example, an audio device playing a track. In this case, the function provided |
|
332 by the derived class must: </p> <ul> |
|
333 <li id="GUID-F94FBAA8-2A0D-5863-BA09-0EC1D61005A9"><p>stop the DMAC to prevent |
|
334 any corruption of the scatter-gather list while appending the new fragment |
|
335 descriptor </p> </li> |
|
336 <li id="GUID-AEF81B78-73D8-5B70-AFE4-0AEA7862CB74"><p>append the new descriptor </p> </li> |
|
337 <li id="GUID-2304F2D4-833E-5F75-B88E-C794DF9D984E"><p>re-enable the channel, |
|
338 ideally before the target has detected the gap in service. </p> </li> |
|
339 </ul> <p>This is the template implementation: </p> <codeblock id="GUID-18512439-C781-5267-ADBC-B9047942F800" xml:space="preserve">void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, |
|
340 const SDmaDesHdr& aNewHdr) |
|
341 // |
|
342 // Appends a descriptor to the chain while the channel is running. |
|
343 // |
|
344 { |
|
345 const TUint8 i = static_cast<TUint8>(aChannel.PslId()); |
|
346 |
|
347 TDmaDesc* pL = HdrToHwDes(aLastHdr); |
|
348 TDmaDesc* pN = HdrToHwDes(aNewHdr); |
|
349 |
|
350 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X", |
|
351 i, pL, pN)); |
|
352 // Unaligned descriptor? Error in generic layer! |
|
353 __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN)); |
|
354 |
|
355 TPhysAddr newPhys = DesLinToPhys(pN); |
|
356 |
|
357 const TInt irq = NKern::DisableAllInterrupts(); |
|
358 StopTransfer(aChannel); |
|
359 |
|
360 pL->iDescAddr = newPhys; |
|
361 const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel); |
|
362 TDmaDesc* pD = channel.iTmpDes; |
|
363 |
|
364 // TO DO: Implement the appropriate algorithm for appending a descriptor here. |
|
365 (void) *pD, (void) i; |
|
366 |
|
367 NKern::RestoreInterrupts(irq); |
|
368 |
|
369 __KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes")); |
|
370 } |
|
371 </codeblock> </section> |
|
372 <section id="GUID-F5968000-0C3E-5E53-A2D5-120B81F3140F"><title>Implement an |
|
373 interrupt service routine</title> <p>The interrupt service routine needs to |
|
374 do the following: </p> <ul> |
|
375 <li id="GUID-CE55E999-0886-5620-87BA-99A36D694FD4"><p>identify the channel |
|
376 that raised the interrupt </p> </li> |
|
377 <li id="GUID-02467F17-DC1E-552C-B1C2-D3C2CCE12347"><p>decide whether the interrupt |
|
378 was raised because of a successful data transfer or because of an error </p> </li> |
|
379 <li id="GUID-0D5FDA57-A45E-54E5-A69C-64D22B916AB4"><p>call the base class |
|
380 function <codeph>TDmac::HandleIsr()</codeph>, which queues a DFC, or increments |
|
381 the number of pending interrupts if a DFC is already queued. </p> </li> |
|
382 </ul> <p>This is the template implementation: </p> <codeblock id="GUID-4CFCA5A1-9657-55F1-BE3C-AFF1F3974F80" xml:space="preserve">void TTemplateDmac::Isr(TAny* aThis) |
|
383 // |
|
384 // This ISR reads the interrupt identification and calls back into the base class |
|
385 // interrupt service handler with the channel identifier and an indication whether the |
|
386 // transfer completed correctly or with an error. |
|
387 // |
|
388 { |
|
389 TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis); |
|
390 |
|
391 // TO DO: Implement the behaviour described above, call HandleIsr(). |
|
392 |
|
393 HandleIsr(me.iChannels[5], 0); // Example |
|
394 |
|
395 } |
|
396 </codeblock> </section> |
|
397 <section id="GUID-D7F410A1-DC70-515D-A00D-3955B534C62F"><title>Implement the |
|
398 test support table and function</title> <p>The DMA Framework comes with a |
|
399 test harness that can be used to validate the port if the underlying DMA controller |
|
400 supports memory to memory transfers. </p> <p>The test harness needs to know |
|
401 about the capabilities of the port being tested. The PSL provides the global |
|
402 function <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> that returns a <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref> object |
|
403 that contains this information. In the template PSL, this structure is initialised |
|
404 to binary zeroes. Before using the test harness, it must be initialised with |
|
405 valid values. </p> <p>See <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref>, <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> and <xref href="GUID-8552E66E-73D6-51DA-8F53-DDF437186CD6.dita">Validation</xref>. </p> </section> |
|
406 <section id="GUID-D452D2CD-D251-50F4-818E-E7125501CE8F"><title>Optimise the |
|
407 performance of critical functions</title> <p>You can optionally optimise critical |
|
408 functions by writing them in assembler. The two candidates for an assembler |
|
409 rewrite are: </p> <ul> |
|
410 <li id="GUID-157E6F4A-0310-5923-B446-040F75E469D4"><p>The interrupt service |
|
411 routine </p> </li> |
|
412 <li id="GUID-74C9D4DB-9CA9-5C5E-A475-B6840EBC2245"><p>In scatter-gather mode, |
|
413 the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> function if it needs to suspend |
|
414 a transfer when appending a new descriptor chain to an existing one. </p> </li> |
|
415 </ul> </section> |
|
416 <section id="GUID-A2AF293F-558A-5F69-821F-EC2B202A5A4F"><title>Extend the |
|
417 framework with platform-specific functionality</title> <p>There are two ways |
|
418 of extending the DMA Framework: </p> <ol id="GUID-D6C660FC-FF23-55B2-B91E-4BC04C592059"> |
|
419 <li id="GUID-4453F4C2-3444-5A3E-94C7-BE6320B1EF89"><p>to provide platform-specific |
|
420 functionality on a per-channel basis. </p> </li> |
|
421 <li id="GUID-C0C6A072-134A-5753-A6DC-185F3975C2A6"><p>to provide platform-specific |
|
422 functionality on a <i>channel independent</i> basis. </p> </li> |
|
423 </ol> <p>In the first case, the PSL provides an implementation of the virtual |
|
424 function <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. The default implementation |
|
425 just returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-2CF7498E-F5D2-3C4A-8E98-47504F9FC404"><apiname>TDmaChannel::Extension()</apiname></xref> calls <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. </p> <p>In the second case, the PSL provides an implementation of the static |
|
426 function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. The template |
|
427 PSL implementation just returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-75562653-1F27-39D3-96D8-55A94BA9B68B"><apiname>TDmaChannel::StaticExtension()</apiname></xref> calls <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. </p> </section> |
|
428 </conbody></concept> |