1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** EHCI Controller Driver */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_hcd_ehci.h"
30 #include "ux_host_stack.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_hcd_ehci_request_control_transfer PORTABLE C */
38 /* 6.1.10 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function performs a control transfer from a transfer request. */
46 /* The USB control transfer is in 3 phases (setup, data, status). */
47 /* This function will chain all phases of the control sequence before */
48 /* setting the EHCI endpoint as a candidate for transfer. */
49 /* */
50 /* The max aggregated size of a data payload in EHCI is 16K. We are */
51 /* assuming that this size will be sufficient to contain the control */
52 /* packet. */
53 /* */
54 /* INPUT */
55 /* */
56 /* hcd_ehci Pointer to EHCI controller */
57 /* transfer_request Pointer to transfer request */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* Completion Status */
62 /* */
63 /* CALLS */
64 /* */
65 /* _ux_hcd_ehci_ed_clean Clean TDs */
66 /* _ux_hcd_ehci_request_transfer_add Add transfer to ED */
67 /* _ux_host_stack_transfer_request_abort Abort transfer request */
68 /* _ux_utility_memory_allocate Allocate memory block */
69 /* _ux_utility_memory_free Release memory block */
70 /* _ux_host_semaphore_get Get semaphore */
71 /* _ux_utility_short_put Write a 16-bit value */
72 /* */
73 /* CALLED BY */
74 /* */
75 /* EHCI Controller Driver */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
82 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
83 /* prefixed UX to MS_TO_TICK, */
84 /* resulting in version 6.1 */
85 /* 11-09-2020 Chaoqiong Xiao Modified comment(s), */
86 /* refined macros names, */
87 /* fixed compile warnings, */
88 /* resulting in version 6.1.2 */
89 /* */
90 /**************************************************************************/
_ux_hcd_ehci_request_control_transfer(UX_HCD_EHCI * hcd_ehci,UX_TRANSFER * transfer_request)91 UINT _ux_hcd_ehci_request_control_transfer(UX_HCD_EHCI *hcd_ehci, UX_TRANSFER *transfer_request)
92 {
93
94 UX_DEVICE *device;
95 UX_ENDPOINT *endpoint;
96 UCHAR * setup_request;
97 UX_EHCI_ED *ed;
98 ULONG td_component;
99 UINT status;
100 UINT pid;
101
102
103 /* Get the pointer to the Endpoint and to the device. */
104 endpoint = (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
105 device = endpoint -> ux_endpoint_device;
106
107 /* Now get the physical ED attached to this endpoint. */
108 ed = endpoint -> ux_endpoint_ed;
109
110 /* Build the SETUP packet (phase 1 of the control transfer). */
111 setup_request = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SETUP_SIZE);
112 if (setup_request == UX_NULL)
113 return(UX_MEMORY_INSUFFICIENT);
114
115 *setup_request = (UCHAR)transfer_request -> ux_transfer_request_function;
116 *(setup_request + UX_SETUP_REQUEST_TYPE) = (UCHAR)transfer_request -> ux_transfer_request_type;
117 *(setup_request + UX_SETUP_REQUEST) = (UCHAR)transfer_request -> ux_transfer_request_function;
118 _ux_utility_short_put(setup_request + UX_SETUP_VALUE, (USHORT)transfer_request -> ux_transfer_request_value);
119 _ux_utility_short_put(setup_request + UX_SETUP_INDEX, (USHORT)transfer_request -> ux_transfer_request_index);
120 _ux_utility_short_put(setup_request + UX_SETUP_LENGTH, (USHORT) transfer_request -> ux_transfer_request_requested_length);
121
122 /* Reset the last TD pointer since it is the first time we hook a transaction. */
123 ed -> ux_ehci_ed_last_td = UX_NULL;
124
125 /* Set the ED address and MPS values since they may have changed from 0 to x
126 The ED direction will be set from the TD. */
127 ed -> ux_ehci_ed_cap0 |= (endpoint -> ux_endpoint_descriptor.bEndpointAddress & ~UX_ENDPOINT_DIRECTION) << UX_EHCI_QH_ED_AD_LOC;
128
129 /* Set the endpoint address (this should have changed after address setting). */
130 ed -> ux_ehci_ed_cap0 |= device -> ux_device_address;
131
132 /* Set the default MPS Capability info in the ED. */
133 ed -> ux_ehci_ed_cap0 &= ~UX_EHCI_QH_MPS_MASK;
134 ed -> ux_ehci_ed_cap0 |= endpoint -> ux_endpoint_descriptor.wMaxPacketSize << UX_EHCI_QH_MPS_LOC;
135
136 /* On Control transfers, the toggle is set in the TD, not the QH. */
137 ed -> ux_ehci_ed_cap0 |= UX_EHCI_QH_DTC;
138
139 /* The overlay parameters should be reset now. */
140 ed -> ux_ehci_ed_current_td = UX_NULL;
141 ed -> ux_ehci_ed_queue_element = (UX_EHCI_TD *) UX_EHCI_TD_T;
142 ed -> ux_ehci_ed_alternate_td = (UX_EHCI_TD *) UX_EHCI_TD_T;
143 ed -> ux_ehci_ed_state &= UX_EHCI_QH_TOGGLE;
144 ed -> ux_ehci_ed_bp0 = UX_NULL;
145 ed -> ux_ehci_ed_bp1 = UX_NULL;
146 ed -> ux_ehci_ed_bp2 = UX_NULL;
147 ed -> ux_ehci_ed_bp3 = UX_NULL;
148 ed -> ux_ehci_ed_bp4 = UX_NULL;
149
150 /* Build and hook the setup phase to the ED. */
151 status = _ux_hcd_ehci_request_transfer_add(hcd_ehci, ed, UX_EHCI_TD_SETUP_PHASE, UX_EHCI_PID_SETUP, UX_EHCI_TOGGLE_0,
152 setup_request, UX_SETUP_SIZE, transfer_request);
153 if (status != UX_SUCCESS)
154 {
155
156 /* We need to clean the tds attached if any. */
157 _ux_hcd_ehci_ed_clean(ed);
158 return(status);
159 }
160
161 /* Test if data phase required, if so decide the PID to use and build/hook it to the ED. */
162 if (transfer_request -> ux_transfer_request_requested_length != 0)
163 {
164
165 if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
166
167 pid = UX_EHCI_PID_IN;
168 else
169
170 pid = UX_EHCI_PID_OUT;
171
172 status = _ux_hcd_ehci_request_transfer_add(hcd_ehci, ed, UX_EHCI_TD_DATA_PHASE, pid, UX_EHCI_TOGGLE_1,
173 transfer_request -> ux_transfer_request_data_pointer,
174 transfer_request -> ux_transfer_request_requested_length,
175 transfer_request);
176 if (status != UX_SUCCESS)
177 {
178
179 /* We need to clean the tds attached if any. */
180 _ux_hcd_ehci_ed_clean(ed);
181 return(status);
182 }
183 }
184
185 /* Program the status phase. the PID is the opposite of the data phase. */
186 if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
187 pid = UX_EHCI_PID_OUT;
188 else
189 pid = UX_EHCI_PID_IN;
190
191 status = _ux_hcd_ehci_request_transfer_add(hcd_ehci, ed, UX_EHCI_TD_STATUS_PHASE, pid,
192 UX_EHCI_TOGGLE_1, UX_NULL, 0, transfer_request);
193
194 if (status != UX_SUCCESS)
195 {
196
197 /* We need to clean the tds attached if any. */
198 _ux_hcd_ehci_ed_clean(ed);
199 return(status);
200 }
201
202 /* Set the IOC bit in the last TD. */
203 ed -> ux_ehci_ed_last_td -> ux_ehci_td_control |= UX_EHCI_TD_IOC;
204
205 /* Ensure the IOC bit is set before activating the TD. This is necessary
206 for some processors that perform writes out of order as an optimization. */
207 UX_DATA_MEMORY_BARRIER
208
209 /* Activate the first TD linked to the ED. */
210 td_component = (ULONG) ed -> ux_ehci_ed_queue_element;
211 td_component &= ~UX_EHCI_TD_T;
212 ed -> ux_ehci_ed_queue_element = (UX_EHCI_TD *) td_component;
213
214 /* Wait for the completion of the transfer request. */
215 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_CONTROL_TRANSFER_TIMEOUT));
216
217 /* If the semaphore did not succeed we probably have a time out. */
218 if (status != UX_SUCCESS)
219 {
220
221 /* All transfers pending need to abort. There may have been a partial transfer. */
222 _ux_host_stack_transfer_request_abort(transfer_request);
223
224 /* There was an error, return to the caller. */
225 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT;
226
227 /* Error trap. */
228 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_TIMEOUT);
229
230 /* If trace is enabled, insert this event into the trace buffer. */
231 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
232
233 }
234
235 /* Free the resources. */
236 _ux_utility_memory_free(setup_request);
237
238 /* Return completion status. */
239 return(transfer_request -> ux_transfer_request_completion_code);
240 }
241
242