1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** USBX Component */
16 /** */
17 /** Host Stack */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_stack.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_host_stack_transfer_request PORTABLE C */
36 /* 6.1.10 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function performs a USB transaction. On entry the transfer */
44 /* request gives the endpoint pipe selected for this transaction and */
45 /* the parameters associated with the transfer (data payload, length */
46 /* of transaction) */
47 /* */
48 /* For Control pipe, the transaction is blocking and will only return */
49 /* when the 3 phases of the control transfer have been completed or if */
50 /* there is a previous error. For other pipes, the USB stack will */
51 /* schedule the transaction on the USB but will not wait for its */
52 /* completion. Each request for non blocking pipes has to specify a */
53 /* completion routine. */
54 /* */
55 /* INPUT */
56 /* */
57 /* transfer_request Transfer request structure */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* Completion Status If UX_SUCCESS, transfer was */
62 /* successfully started */
63 /* */
64 /* CALLS */
65 /* */
66 /* HCD Entry Function */
67 /* _ux_utility_semaphore_put Put semaphore */
68 /* _ux_utility_semaphore_get Get semaphore */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* Application */
73 /* USBX Components */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
80 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
81 /* optimized based on compile */
82 /* definitions, used UX prefix */
83 /* to refer to TX symbols */
84 /* instead of using them */
85 /* directly, */
86 /* resulting in version 6.1 */
87 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
88 /* added standalone support, */
89 /* resulting in version 6.1.10 */
90 /* */
91 /**************************************************************************/
_ux_host_stack_transfer_request(UX_TRANSFER * transfer_request)92 UINT _ux_host_stack_transfer_request(UX_TRANSFER *transfer_request)
93 {
94 #if defined(UX_HOST_STANDALONE)
95 UINT status;
96
97 UX_TRANSFER_STATE_RESET(transfer_request);
98 _ux_host_stack_transfer_run(transfer_request);
99 if ((transfer_request -> ux_transfer_request_flags & UX_TRANSFER_FLAG_AUTO_WAIT))
100 {
101 while(1)
102 {
103
104 /* Allow tasks running during waiting. */
105 _ux_system_host_tasks_run();
106
107 if (transfer_request -> ux_transfer_request_state <= UX_STATE_NEXT)
108 break;
109 }
110 status = transfer_request -> ux_transfer_request_completion_code;
111 }
112 else
113 {
114
115 /* In this mode, transfer pending is a success started case. */
116 if (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_PENDING)
117 status = UX_SUCCESS;
118 else
119 status = transfer_request -> ux_transfer_request_completion_code;
120 }
121
122 /* Return transfer completion status. */
123 return(status);
124 #else
125 UX_INTERRUPT_SAVE_AREA
126
127 UX_ENDPOINT *endpoint;
128 UX_DEVICE *device;
129 UX_HCD *hcd;
130 UINT status;
131
132
133 /* Get the endpoint container from the transfer_request */
134 endpoint = transfer_request -> ux_transfer_request_endpoint;
135
136 /* Get the device container from the endpoint. */
137 device = endpoint -> ux_endpoint_device;
138
139 /* Ensure we are not preempted by the enum thread while we check the device
140 state and set the transfer status. */
141 UX_DISABLE
142
143 /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED. */
144 if ((device -> ux_device_state == UX_DEVICE_ATTACHED) || (device -> ux_device_state == UX_DEVICE_ADDRESSED)
145 || (device -> ux_device_state == UX_DEVICE_CONFIGURED))
146 {
147
148 /* Set the transfer to pending. */
149 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING;
150 #if !defined(UX_HOST_STANDALONE)
151 /* Save the thread making this transfer. If we're under interrupt, this
152 will be null. */
153 transfer_request -> ux_transfer_request_thread_pending = _ux_utility_thread_identify();
154 #endif
155 }
156 else
157 {
158
159 /* The device is in an invalid state. Restore interrupts and return error. */
160 UX_RESTORE
161
162 /* Check if this is endpoint 0. */
163 if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & (UINT)~UX_ENDPOINT_DIRECTION) == 0)
164 {
165
166 /* Check if the class has already protected it. */
167 if (!_ux_host_semaphore_waiting(&device -> ux_device_protection_semaphore))
168 {
169
170 /* Class is using endpoint 0. Unprotect semaphore. */
171 _ux_host_semaphore_put(&device -> ux_device_protection_semaphore);
172 }
173 }
174
175 return(UX_TRANSFER_NOT_READY);
176 }
177
178 /* Restore interrupts. */
179 UX_RESTORE
180
181 /* If trace is enabled, insert this event into the trace buffer. */
182 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_TRANSFER_REQUEST, device, endpoint, transfer_request, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
183
184 /* With the device we have the pointer to the HCD. */
185 hcd = UX_DEVICE_HCD_GET(device);
186
187 /* If this is endpoint 0, we protect the endpoint from a possible re-entry. */
188 if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & (UINT)~UX_ENDPOINT_DIRECTION) == 0)
189 {
190
191 /* Check if the class has already protected it. */
192 if (_ux_host_semaphore_waiting(&device -> ux_device_protection_semaphore))
193 {
194
195 /* We are using endpoint 0. Protect with semaphore. */
196 status = _ux_host_semaphore_get(&device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
197
198 /* Check for status. */
199 if (status != UX_SUCCESS)
200
201 /* Something went wrong. */
202 return(status);
203 }
204 }
205
206 /* Send the command to the controller. */
207 status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_TRANSFER_REQUEST, transfer_request);
208
209 /* If this is endpoint 0, we unprotect the endpoint. */
210 if ((endpoint -> ux_endpoint_descriptor.bEndpointAddress & (UINT)~UX_ENDPOINT_DIRECTION) == 0)
211
212 /* We are using endpoint 0. Unprotect with semaphore. */
213 _ux_host_semaphore_put(&device -> ux_device_protection_semaphore);
214
215 /* And return the status. */
216 return(status);
217 #endif
218 }
219
220
221 /**************************************************************************/
222 /* */
223 /* FUNCTION RELEASE */
224 /* */
225 /* _uxe_host_stack_transfer_request PORTABLE C */
226 /* 6.3.0 */
227 /* AUTHOR */
228 /* */
229 /* Chaoqiong Xiao, Microsoft Corporation */
230 /* */
231 /* DESCRIPTION */
232 /* */
233 /* This function checks errors in host stack transfer function call. */
234 /* */
235 /* INPUT */
236 /* */
237 /* transfer_request Pointer to transfer */
238 /* */
239 /* OUTPUT */
240 /* */
241 /* None */
242 /* */
243 /* CALLS */
244 /* */
245 /* _ux_host_stack_transfer_request Issue a transfer request */
246 /* */
247 /* CALLED BY */
248 /* */
249 /* Application */
250 /* */
251 /* RELEASE HISTORY */
252 /* */
253 /* DATE NAME DESCRIPTION */
254 /* */
255 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
256 /* */
257 /**************************************************************************/
_uxe_host_stack_transfer_request(UX_TRANSFER * transfer_request)258 UINT _uxe_host_stack_transfer_request(UX_TRANSFER *transfer_request)
259 {
260
261 /* Sanity checks. */
262 if (transfer_request == UX_NULL)
263 return(UX_INVALID_PARAMETER);
264 if (transfer_request -> ux_transfer_request_endpoint == UX_NULL)
265 return(UX_ENDPOINT_HANDLE_UNKNOWN);
266 if (transfer_request -> ux_transfer_request_endpoint -> ux_endpoint_device == UX_NULL)
267 return(UX_DEVICE_HANDLE_UNKNOWN);
268 if (UX_DEVICE_HCD_GET(transfer_request -> ux_transfer_request_endpoint -> ux_endpoint_device) == UX_NULL)
269 return(UX_INVALID_PARAMETER);
270
271 /* Invoke transfer request function. */
272 return(_ux_host_stack_transfer_request(transfer_request));
273 }
274