|
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-F20D5802-7B83-5B78-8753-A88E74E28398" xml:lang="en"><title>PSL Implementation</title><shortdesc>This topic describes how to implement the <codeph>DUsbClientController</codeph> interface to provide a platform-specific layer implementation for |
|
13 the USB client controller.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <p>The platform-specific layer only contains functionality that cannot |
|
15 be abstracted and made generic because different USB device controller |
|
16 designs operate differently. For example, the internal (and therefore |
|
17 external) management of the endpoint FIFOs can be different. In some |
|
18 USB device controller designs, the endpoints have hardwired FIFOs |
|
19 of specific sizes, which may possibly be configured, whereas other |
|
20 designs have a defined maximum amount of FIFO RAM available that has |
|
21 to be shared by all endpoints in use in a given configuration. The |
|
22 way that the chip is programmed can also differ. Some designs have |
|
23 a single register into which all commands and their parameters are |
|
24 written, whereas others are programmed via a number of special purpose |
|
25 control registers. </p> |
|
26 <p>Everything else that has to be common because it is defined in |
|
27 the USB specification, is contained in the <i>platform-independent |
|
28 layer</i>. </p> |
|
29 <p>The operation of the USB device controller is hardware specific |
|
30 and the implementers of the platform-specific layer is free to do |
|
31 whatever is necessary to use the hardware. All of this is transparent |
|
32 to the platform-independent layer, which uses only the fixed set of |
|
33 pure virtual functions defined in <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita"><apiname>DUsbClientController</apiname></xref> to communicate with the platform-specific layer, and therefore with |
|
34 the hardware. </p> |
|
35 <p>The platform-specific layer is also responsible for managing the |
|
36 transfer of data over the endpoints, and it is important that it can |
|
37 provide the services expected by the platform-independent layer. Data |
|
38 transfers are normally set up by the platform-independent layer by |
|
39 calling one of the following member functions of <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita"><apiname>DUsbClientController</apiname></xref>: </p> |
|
40 <codeblock id="GUID-34B3EEE2-F83F-5063-9885-5CC0092FB518" xml:space="preserve">TInt SetupEndpointRead(TInt aRealEndpoint, TUsbcRequestCallback& aCallback) = 0; |
|
41 TInt SetupEndpointWrite(TInt aRealEndpoint, TUsbcRequestCallback& aCallback) = 0; |
|
42 TInt SetupEndpointZeroRead() = 0; |
|
43 TInt SetupEndpointZeroWrite(const TUint8* aBuffer, TInt aLength, TBool aZlpReqd=EFalse) = 0; |
|
44 TInt SendEp0ZeroByteStatusPacket() = 0;</codeblock> |
|
45 <p>which the platform-specific layer implements. </p> |
|
46 <p>These data transfer functions fall into two groups: one for handling |
|
47 endpoint-0 and another for handling general endpoints. Endpoint-0 |
|
48 is handled differently from general endpoints throughout the USB stack. |
|
49 The functions for handling general endpoints are used to transfer |
|
50 user data. In addition to taking an endpoint number, these functions |
|
51 also take a reference to a <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita"><apiname>TUsbcRequestCallback</apiname></xref> object. This is a request callback, it is key to the data transfer |
|
52 mechanism. </p> |
|
53 <section id="GUID-B9C7FD99-E5D9-5E08-A219-AD1FE89ED139"><title>Reading |
|
54 data</title> <ul> |
|
55 <li id="GUID-96C81B48-9C6A-5EDB-86B3-8F8EC9F94DF0"><p> <xref href="GUID-F20D5802-7B83-5B78-8753-A88E74E28398.dita#GUID-F20D5802-7B83-5B78-8753-A88E74E28398/GUID-4076097E-5FC3-594B-BA00-4A45B78E84CD">General endpoints</xref> </p> </li> |
|
56 <li id="GUID-260D22D3-5BA7-50A3-B382-D2E5F74CA5D5"><p> <xref href="GUID-F20D5802-7B83-5B78-8753-A88E74E28398.dita#GUID-F20D5802-7B83-5B78-8753-A88E74E28398/GUID-DD28FFFD-9433-57C9-A517-81BA8E001129">Endpoint-0</xref> </p> </li> |
|
57 </ul> <p id="GUID-4076097E-5FC3-594B-BA00-4A45B78E84CD"><b>General endpoints</b> </p> <p>The platform-independent layer issues a request to read |
|
58 data by calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-907F6988-4336-3160-BD41-7FBECE9C6E88"><apiname>DUsbClientController::SetupEndpointRead()</apiname></xref>, which is implemented by the platform-specific layer, passing it |
|
59 the endpoint and a <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita"><apiname>TUsbcRequestCallback</apiname></xref> object. </p> <p>Data is read into a large buffer, whose address and length are |
|
60 passed as data members of the <codeph>TUsbcRequestCallback</codeph> object: <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-B8507E01-B472-3FE6-82E7-281094A491C5"><apiname>TUsbcRequestCallback::iBufferStart</apiname></xref> and <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-565F9CC5-15CE-3AF3-87DD-539737E0E628"><apiname>TUsbcRequestCallback::iLength</apiname></xref> respectively. For Bulk reads, |
|
61 this buffer is intended to catch a burst of data transmitted from |
|
62 the host rather than just a single packet. </p> <p>For all other transfer |
|
63 types (Control, Interrupt, Isochronous) it is usual to return only |
|
64 single packets to the LDD. The amount of data returned is controlled |
|
65 – and limited - by the USB client driver (the LDD) through the <codeph>iLength</codeph> value. </p> <p>The <codeph>TUsbcRequestCallback</codeph> object also supplies a pair of arrays: </p> <ul> |
|
66 <li id="GUID-D1993F45-0E58-5ECA-A845-3B300558759B"><p> <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-843E57D1-4703-3127-B1BE-4C93F1AD54FC"><apiname>TUsbcRequestCallback::iPacketIndex</apiname></xref> containing the offset(s) into the data buffer of the single packet |
|
67 or burst data. </p> </li> |
|
68 <li id="GUID-6A2DDA06-DCB4-5675-AF62-6A9A5226AA2B"><p> <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-2C7B48F0-5A57-3D72-91ED-9FABC99D25EE"><apiname>TUsbcRequestCallback::iPacketSize</apiname></xref> containing the size(s) of the packet or burst data. </p> </li> |
|
69 </ul> <p>These arrays are logically linked; both are the same size |
|
70 and can hold information for two entries each. </p> <p>Therefore, |
|
71 received single packets have to be merged into one 'superpacket' in |
|
72 the read buffer. It is assumed that these merged packets consist of |
|
73 maximum packet sized packets, possibly terminated by a short packet. |
|
74 A zero length packet or ZLP must appear separately; this would be |
|
75 the optional second packet in the respective array. </p> <p>For example, |
|
76 for a Bulk endpoint with a maximum packet size of 64 bytes: </p> <ul> |
|
77 <li id="GUID-65A91C14-FD6C-5FDD-9DDF-9E9A5F11271A"><p>If 10 x 64 byte |
|
78 packets and one 10 byte packet arrive, then these are marked as a |
|
79 single large 650 byte packet. </p> </li> |
|
80 <li id="GUID-AEA01430-333D-5A6E-B32D-017FEF9B93F7"><p>If 10 x 64 byte |
|
81 packets and one ZLP arrive, then these should be entered as two packets |
|
82 in the arrays; one of size 640 bytes and one of size zero. </p> </li> |
|
83 </ul> <p>The general aim when servicing a Bulk read request from the |
|
84 platform-independent layer is to capture as much data as possible |
|
85 whilst not holding onto data too long before returning the data to |
|
86 the LDD and receiving another buffer. There is considerable flexibility |
|
87 in how this is achieved and the design does not mandate any particular |
|
88 method; it also depends to a certain extent on the USB device controller |
|
89 hardware used. </p> <p>The platform implementation can use a re-startable |
|
90 timer to see whether data has been received in the time (usually milliseconds) |
|
91 since the last data was received. If data has been received, then |
|
92 the timer is restarted. If data has not been received, then the timer |
|
93 is not restarted, and the buffer is marked as complete for the platform-independent |
|
94 layer by calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-30D6B783-B27B-3ECD-AF34-D22ADF34A12D"><apiname>DUsbClientController::EndpointRequestComplete()</apiname></xref>. </p> <p>Note the following: </p> <ul> |
|
95 <li id="GUID-60992745-5A02-5177-9707-B9DD6F087AE0"><p>In the interrupt |
|
96 service routine (ISR), the flag <codeph>iRxMoreDataRcvd</codeph> is |
|
97 used to indicate that data has been received. </p> </li> |
|
98 <li id="GUID-2B15F54F-66A6-5788-89E9-68D12D3EB8AF"><p>The timer is |
|
99 not restarted in the ISR - the timer is allowed to expire and then |
|
100 a test is made for received data. </p> </li> |
|
101 <li id="GUID-F5FEF7D6-8DD1-5B12-9AF3-2EBBB18F75A4"><p>Typical values |
|
102 for the timer range from 1—5 ms. </p> </li> |
|
103 <li id="GUID-D46B9ABA-5719-5FC3-89F0-3745779F5900"><p>Each OUT endpoint |
|
104 requires a separate timer. </p> </li> |
|
105 <li id="GUID-585E00C0-FE41-5176-8DEF-54C0AD8F55E2"><p>The read is |
|
106 not flagged as complete to the platform-independent layer if no data |
|
107 has been received. The timer is only started once the first packet/transfer |
|
108 has been received. </p> </li> |
|
109 <li id="GUID-62CCCC78-AD45-5570-BC15-050BD4509BC7"><p>The bare minimum |
|
110 of work is done in the ISR. After draining the FIFO, update the <codeph>iPacketSize</codeph> and <codeph>iPacketIndex</codeph> arrays and |
|
111 recalculate the buffer address ready for the next packet, taking into |
|
112 account any alignment restrictions. </p> </li> |
|
113 </ul> <p>The platform-specific layer completes a non endpoint-0 read |
|
114 request by calling the platform-independent layer function <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-30D6B783-B27B-3ECD-AF34-D22ADF34A12D"><apiname>DUsbClientController::EndpointRequestComplete()</apiname></xref>. This function |
|
115 takes as its sole argument a pointer to the updated request callback |
|
116 structure that was initially passed to the platform-specific layer |
|
117 for that read. Members that need to be updated, in addition to the |
|
118 packet arrays <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-843E57D1-4703-3127-B1BE-4C93F1AD54FC"><apiname>TUsbcRequestCallback::iPacketIndex</apiname></xref> and <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-2C7B48F0-5A57-3D72-91ED-9FABC99D25EE"><apiname>TUsbcRequestCallback::iPacketSize</apiname></xref>, are: </p> <ul> |
|
119 <li id="GUID-7EF9E9C2-DE14-5290-B3FE-B91918669AE2"><p> <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-8B2D125B-9943-386F-9A27-11CC1A25A0C2"><apiname>TUsbcRequestCallback::iRxPackets</apiname></xref>, with possible values: 1 or 2. </p> </li> |
|
120 <li id="GUID-9E1800A9-8D39-5D5D-92D0-13AF9CD3EF2A"><p> <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-A00F6B27-655A-3182-96E2-8B3D2404CB7C"><apiname>TUsbcRequestCallback::iError</apiname></xref> </p> </li> |
|
121 </ul> <p><b>Summary of Completion Criteria for general Endpoints</b> </p> <p>The platform-specific layer completes a read request by calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-30D6B783-B27B-3ECD-AF34-D22ADF34A12D"><apiname>DUsbClientController::EndpointRequestComplete()</apiname></xref> when any |
|
122 of the following conditions are met: </p> <ul> |
|
123 <li id="GUID-F66AF5EC-56D4-5133-A930-2BB793478B31"><p>The requested |
|
124 number of bytes has been received. </p> </li> |
|
125 <li id="GUID-91D9D4E4-2196-55C9-9595-1BA6AE2C2848"><p>A short packet, |
|
126 including a ZLP, is received. In the case of a ZLP being received, |
|
127 it must be represented separately in the <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-E5FD5F91-B22B-31A9-8482-635B2F1EB0B4"><apiname>DUsbClientController::iPacketIndex</apiname></xref> and <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-BFB565F1-C8F9-3E44-88FB-E81E88D2DF3A"><apiname>DUsbClientController::iPacketSize</apiname></xref> arrays. </p> </li> |
|
128 <li id="GUID-42124450-1AC8-59F3-9C30-8C74EC425CAE"><p>If the number |
|
129 of bytes in the current packet (still in the FIFO) were to cause the |
|
130 total number of bytes to exceed the buffer length <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-A0A7399A-A51E-3544-A181-5C45B69AB121"><apiname>DUsbClientController::iLength</apiname></xref>. </p> </li> |
|
131 <li id="GUID-09281AB5-7240-5B29-B0C1-C5A4A8289B7F"><p>The timer has |
|
132 expired, data is available, but no further packets have been received. </p> </li> |
|
133 </ul> <p id="GUID-DD28FFFD-9433-57C9-A517-81BA8E001129"><b>Endpoint-0</b> </p> <p>The handling of endpoint-0 read requests is similar to general |
|
134 endpoints except for the following: </p> <ul> |
|
135 <li id="GUID-D9361990-1591-522E-9F9E-7E38A6EB0B08"><p>The platform-independent |
|
136 layer issues the request by calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-B3B4793E-7B75-3C40-A6FA-CD17B460CC73"><apiname>DUsbClientController::SetupEndpointZeroRead()</apiname></xref>. This function does not take any parameters because: </p> <ul> |
|
137 <li id="GUID-4AED5324-65B5-5BD3-AACA-5EA9FB7CB90A"><p>The endpoint |
|
138 number is known, this is zero. </p> </li> |
|
139 <li id="GUID-9CEAFC92-DF2D-5B07-B623-5BA562EC61BE"><p>The request |
|
140 is completed after every received packet, and a <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita"><apiname>TUsbcRequestCallback</apiname></xref> object is not needed. </p> </li> |
|
141 </ul> </li> |
|
142 </ul> <p>All the platform-specific layer needs to know is where to |
|
143 place the received data, and its size. Both are fixed values: <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-BC2DF410-292B-354A-BCEF-2C9E520024B8"><apiname>DUsbClientController::iEp0_RxBuf</apiname></xref> and <xref href="GUID-D0DFABCF-15B4-347E-BAE5-0F050E137949.dita"><apiname>KUsbcBufSzControl</apiname></xref> respectively. </p> <p>An endpoint-0 read request is completed by |
|
144 calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-71E33976-C185-34FA-A8BF-7DB3404DDA78"><apiname>DUsbClientController::Ep0RequestComplete()</apiname></xref>, passing the endpoint number (0, or symbolically, <codeph>KEp0_Out</codeph>), the number of bytes received, and the resulting error code for |
|
145 this request. </p> </section> |
|
146 <section id="GUID-2617EDBD-6792-53B9-9CE0-6B0CC729728C"><title>Writing |
|
147 data</title> <ul> |
|
148 <li id="GUID-97BDD391-F5BE-509C-AF67-51AD4822FD11"><p> <xref href="GUID-F20D5802-7B83-5B78-8753-A88E74E28398.dita#GUID-F20D5802-7B83-5B78-8753-A88E74E28398/GUID-69839EA3-9DC0-5A3C-BE62-AC91708477BA">General endpoints</xref> </p> </li> |
|
149 <li id="GUID-8E0F6F8F-D3DA-5E67-8E8C-E4BE983DBF1A"><p> <xref href="GUID-F20D5802-7B83-5B78-8753-A88E74E28398.dita#GUID-F20D5802-7B83-5B78-8753-A88E74E28398/GUID-C674608C-393B-5397-A1E4-3C8368E2144C">Endpoint-0</xref> </p> </li> |
|
150 </ul> <p id="GUID-69839EA3-9DC0-5A3C-BE62-AC91708477BA"><b>General endpoints</b> </p> <p>The platform-independent layer issues a request to write |
|
151 data by calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-F7880D1C-7E7D-3214-BF84-8811DA935B0C"><apiname>DUsbClientController::SetupEndpointWrite()</apiname></xref>, which is implemented by the platform-specific layer, passing the |
|
152 function an endpoint and a <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita"><apiname>TUsbcRequestCallback</apiname></xref> object. </p> <p>The address of the buffer, containing the data to |
|
153 be written, is passed into the data member <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-B8507E01-B472-3FE6-82E7-281094A491C5"><apiname>TUsbcRequestCallback::iBufferStart</apiname></xref>. The length of this buffer is passed into <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-565F9CC5-15CE-3AF3-87DD-539737E0E628"><apiname>TUsbcRequestCallback::iLength</apiname></xref>. The buffer is a single contiguous piece of memory. </p> <p>The |
|
154 platform-specific layer's implementation needs to set up the transfer, |
|
155 either using DMA or a conventional interrupt driven mechanism, and |
|
156 then wait for the host to collect, by sending an IN token, the data |
|
157 from the respective endpoint’s primed FIFO. This continues until all |
|
158 data from the buffer has been transmitted to the host. </p> <p>If |
|
159 the ZLP request flag <codeph>iZlpReqd</codeph> in the <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita"><apiname>TUsbcRequestCallback</apiname></xref> structure is set (=<xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref>), then the platform |
|
160 specific layer must determine, after all data has been sent, whether |
|
161 to send a ZLP or not. The decision is based on the size of the last |
|
162 packet sent and the current maximum packet size of the endpoint. </p> <p>To summarize, a ZLP should be sent at the end of a write request |
|
163 if: </p> <ul> |
|
164 <li id="GUID-B3AFEC6D-EB74-57FE-9618-E44C6AE10460"><p>The ZLP flag |
|
165 is set. </p> </li> |
|
166 <li id="GUID-970EE707-24D1-53B8-A830-3824562F2AA8"><p>The last packet |
|
167 of the write request was not a short packet (i.e. it was a max-packet-sized |
|
168 packet). </p> </li> |
|
169 </ul> <p>The platform-specific layer completes a non endpoint-0 write |
|
170 request by calling the platform-independent layer function <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-30D6B783-B27B-3ECD-AF34-D22ADF34A12D"><apiname>DUsbClientController::EndpointRequestComplete()</apiname></xref>. This function |
|
171 takes only one argument, a pointer to the updated request callback |
|
172 structure passed to the platform-specific layer for this write. Members |
|
173 that need to be updated are: </p> <ul> |
|
174 <li id="GUID-F02F662E-ABAE-5519-A80C-DA4D66F7A51A"><p> <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-31AF87D2-C1F3-3367-93AA-52924612A7D0"><apiname>TUsbcRequestCallback::iTxBytes</apiname></xref> </p> </li> |
|
175 <li id="GUID-D8416C51-7A46-560F-9F6F-2565DA445004"><p> <xref href="GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F.dita#GUID-D395BF82-65B3-3A98-800B-E6EF43150E8F/GUID-A00F6B27-655A-3182-96E2-8B3D2404CB7C"><apiname>TUsbcRequestCallback::iError</apiname></xref> </p> </li> |
|
176 </ul> <p id="GUID-C674608C-393B-5397-A1E4-3C8368E2144C"><b>Endpoint-0</b> </p> <p>The handling of endpoint-0 write requests is similar to general |
|
177 endpoints except for the following: </p> <p>The platform-independent |
|
178 layer issues the request by calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-DBE7AC29-8B85-3D98-BAF9-8EF059B33331"><apiname>DUsbClientController::SetupEndpointZeroWrite()</apiname></xref>. Unlike the equivalent read function, this function takes a number |
|
179 of parameters: </p> <ul> |
|
180 <li id="GUID-9831D5A3-2032-5C6C-B2AF-C78D9E00D09C"><p>the address |
|
181 of the location containing the data to be written </p> </li> |
|
182 <li id="GUID-C7F55C63-4AD4-5A37-B25B-1249850C5A92"><p>the length of |
|
183 the data to be written </p> </li> |
|
184 <li id="GUID-C2D21E5A-6FB9-5170-80F2-6B6351E5B11A"><p>a <xref href="GUID-4B942C06-1BAC-3A21-B3B1-89FB5C51ADA0.dita"><apiname>TBool</apiname></xref> parameter that indicates whether a zero length packet (ZLP) is to |
|
185 be sent immediately after the data has been sent. </p> </li> |
|
186 </ul> <p>An endpoint-0 write request is completed by calling <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-71E33976-C185-34FA-A8BF-7DB3404DDA78"><apiname>DUsbClientController::Ep0RequestComplete()</apiname></xref>, in the platform-independent |
|
187 layer, passing the function the endpoint number (0, or symbolically <codeph>KEp0_In</codeph>), the number of bytes written, and the error code |
|
188 for this write request. </p> <p>There is another endpoint-0 write |
|
189 function, <xref href="GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941.dita#GUID-82FA9C04-0B7E-3FAD-9AAD-3A68E1E6A941/GUID-95CCCE69-C8AA-39B1-8152-37AA0A7B9CEB"><apiname>DUsbClientController::SendEp0ZeroByteStatusPacket()</apiname></xref>, which is used for sending a zero length packet (ZLP) on its own. |
|
190 This separate function is provided because the USB device controller |
|
191 mechanism for transmitting a ZLP on its own can be different to the |
|
192 mechanism for transmitting the ZLP at the end of a data transmission. </p> </section> |
|
193 <section id="GUID-0805DDC6-2C17-50A2-97B6-F51C77DF3E4F"><title>Using |
|
194 DMA</title> <p>When planning to use DMA for transferring data from |
|
195 and to the endpoints’ FIFOs, there are two things that must be considered: </p> <ul> |
|
196 <li id="GUID-0E6B3A5B-CA84-5BB1-9447-70C7E493D8D2"><p> <xref href="GUID-F20D5802-7B83-5B78-8753-A88E74E28398.dita#GUID-F20D5802-7B83-5B78-8753-A88E74E28398/GUID-838483AC-BDDD-5A6A-AB8A-F26587851D9E">Flushing cached information for the data buffers</xref> </p> </li> |
|
197 <li id="GUID-B9545262-93E4-5AA9-837F-D909B278B19F"><p> <xref href="GUID-F20D5802-7B83-5B78-8753-A88E74E28398.dita#GUID-F20D5802-7B83-5B78-8753-A88E74E28398/GUID-840EB8C0-8C29-5FDE-9505-D6D7131E61A4">Implementing DMA mode for OUT transfers (DMA reads)</xref> </p> </li> |
|
198 </ul> <p id="GUID-838483AC-BDDD-5A6A-AB8A-F26587851D9E"><b>Flushing cached |
|
199 information for the data buffers</b> </p> <p>The cached information |
|
200 for the data buffers must be flushed before a DMA write operation, |
|
201 (i.e. transfer memory to a FIFO), and both before and after a DMA |
|
202 read operation, (i.e. transfer a FIFO to memory). </p> <p>The kernel |
|
203 provides three functions for that purpose. These are static functions |
|
204 in the class <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita"><apiname>Cache</apiname></xref>, declared in <filepath>...\e32\include\kernel\cache.h</filepath>: </p> <ul> |
|
205 <li id="GUID-4402C336-1638-5830-90A8-0A9746BC3CC7"><p> <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-5F08DEAA-1237-32DE-AE41-CE7B18230972"><apiname>Cache::SyncMemoryBeforeDmaWrite()</apiname></xref> </p> </li> |
|
206 <li id="GUID-BD880077-FF37-5604-BECF-EB4D86803EB4"><p> <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-3FF3C567-C1BD-3D4E-97E1-B036456A374E"><apiname>Cache::SyncMemoryBeforeDmaRead()</apiname></xref> </p> </li> |
|
207 <li id="GUID-49E1143C-2B5C-5E92-8ED8-66F75EB41D69"><p> <xref href="GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F.dita#GUID-4425E698-EE8A-369B-92CD-09B1CBD2911F/GUID-78E6DE46-61F0-3840-B555-6926D21141BF"><apiname>Cache::SyncMemoryAfterDmaRead()</apiname></xref> </p> </li> |
|
208 </ul> <p id="GUID-840EB8C0-8C29-5FDE-9505-D6D7131E61A4"><b>Implementing DMA |
|
209 mode for OUT transfers (DMA reads)</b> </p> <p>The implementation |
|
210 of DMA mode for IN transfers is normally relatively straightforward, |
|
211 however complications can occur with OUT transfers (DMA reads), depending |
|
212 on the DMA controller, the USB device controller and the way the two |
|
213 are connected. </p> <p>There are two issues: </p> <ol id="GUID-324F21A0-F3EB-5994-B23C-B0AD18973C2B"> |
|
214 <li id="GUID-7513B814-D305-50A0-B18D-779D8F5B741E"><p>If we set up |
|
215 a DMA read for 4kB, for example, and this request returns after a |
|
216 short packet, we must be able to tell how much data has been received |
|
217 and is now in our buffer. In other words, the DMA controller must |
|
218 provide a way of finding out how many bytes have been received, otherwise |
|
219 we cannot complete the read request to the LDD. </p> <p>Here is a |
|
220 theoretical solution for a Scatter/Gather controller that doesn’t |
|
221 provide information about the number of bytes transferred directly. <b>Note: </b> This proposal has not been tested in practice! </p> <p>Instead of using one large DMA descriptor for 4kB, we could set up |
|
222 a chain of descriptors for max-packet-size bytes each. When the DMA |
|
223 completes, it will be: </p> <ul> |
|
224 <li id="GUID-B088943E-BEC6-568B-8E0E-7AA177566599"><p>for the whole |
|
225 transfer, in which case we know the number of bytes received. </p> </li> |
|
226 <li id="GUID-33974049-2069-57A3-A784-4A312BA846D8"><p>because it is |
|
227 a short packet. In this case we can try and find out which descriptor |
|
228 was being served at the time. The number of bytes received is then </p> <codeblock id="GUID-56C3A794-4077-5A83-BA17-E6BE58A675D4" xml:space="preserve">number of completed descriptors * max-packet-size + number of bytes in short packet.</codeblock> </li> |
|
229 </ul> </li> |
|
230 <li id="GUID-E7406164-A6C4-5508-AD5D-A8DA4F2E4AAC"><p>Another potential |
|
231 problem is posed by the restartable OUT endpoint timer described in |
|
232 the section <xref href="GUID-F20D5802-7B83-5B78-8753-A88E74E28398.dita#GUID-F20D5802-7B83-5B78-8753-A88E74E28398/GUID-B9C7FD99-E5D9-5E08-A219-AD1FE89ED139">Reading data</xref>. The situation in the timer callback DFC, when |
|
233 the LDD read request is about to complete, has to be handled with |
|
234 care in order to avoid data loss. If at this point the pending DMA |
|
235 request has already started transferring data from the endpoint FIFO |
|
236 into our data buffer, then we cannot complete the LDD request anymore |
|
237 (this data would be lost because the LDD would not know about it as |
|
238 the variables in the request structure do not take account of it). |
|
239 The buffer cannot be removed while it is receiving data from a DMA |
|
240 transfer. A possible solution would be as follows: (again, this is |
|
241 just an idea and therefore untested). In the timer DFC, before we |
|
242 complete to the LDD, we cancel the pending DMA request. If a DMA transfer |
|
243 was already happening, then this will somehow complete and the DMA |
|
244 complete DFC will be queued. What we need to find out in that situation |
|
245 is whether or not that DFC is pending: </p> <ul> |
|
246 <li id="GUID-EA31A9E0-5783-5E3C-BFAF-AE041FBC61F1"><p>if not, then |
|
247 there was no DMA transfer ongoing, and we can just complete our read |
|
248 request to the LDD. </p> </li> |
|
249 <li id="GUID-E971CEC8-B0EA-5924-83A6-6FF4E4EB8C9E"><p>otherwise we |
|
250 have to abandon, at this point, the plan to complete and return from |
|
251 the timer callback (without doing any damage). In this case, the DMA |
|
252 complete DFC will run next, the LDD read request structure will be |
|
253 updated, the RX timer will be set again, and we can proceed as normal. </p> </li> |
|
254 </ul> </li> |
|
255 </ol> </section> |
|
256 </conbody></concept> |