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 /** Host Stack */
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_host_stack.h"
30
31
32 #if defined(UX_HOST_STANDALONE)
33
34 #define UX_HOST_STACK_TRANSFER_LIST_IS_NULL 0
35 #define UX_HOST_STACK_TRANSFER_NOT_IN_LIST 1
36 #define UX_HOST_STACK_TRANSFER_AT_LIST_HEAD 2
37 #define UX_HOST_STACK_TRANSFER_IN_LIST 3
38 static inline UINT _ux_host_stack_transfer_locate(UX_TRANSFER *transfer, UX_TRANSFER **previous);
39 static inline void _ux_host_stack_transfer_retire(UX_TRANSFER *transfer);
40
41
42 /**************************************************************************/
43 /* */
44 /* FUNCTION RELEASE */
45 /* */
46 /* _ux_host_stack_transfer_run PORTABLE C */
47 /* 6.1.10 */
48 /* AUTHOR */
49 /* */
50 /* Chaoqiong Xiao, Microsoft Corporation */
51 /* */
52 /* DESCRIPTION */
53 /* */
54 /* This function performs a USB transaction. On entry the transfer */
55 /* request gives the endpoint pipe selected for this transaction and */
56 /* the parameters associated with the transfer (data payload, length */
57 /* of transaction) */
58 /* */
59 /* Note after transfer is done, it's in error or idle state. To ensure */
60 /* transfer is ready for next round, use UX_TRANSFER_STATE_RESET(). */
61 /* */
62 /* It's for standalone mode. */
63 /* */
64 /* INPUT */
65 /* */
66 /* transfer_request Transfer request structure */
67 /* */
68 /* OUTPUT */
69 /* */
70 /* State machine Status to check */
71 /* UX_STATE_NEXT Transfer done, to next state */
72 /* UX_STATE_EXIT Abnormal, to reset state */
73 /* (others) Keep running, waiting */
74 /* */
75 /* CALLS */
76 /* */
77 /* HCD Entry Function */
78 /* */
79 /* CALLED BY */
80 /* */
81 /* Application */
82 /* USBX Components */
83 /* */
84 /* RELEASE HISTORY */
85 /* */
86 /* DATE NAME DESCRIPTION */
87 /* */
88 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
89 /* */
90 /**************************************************************************/
_ux_host_stack_transfer_run(UX_TRANSFER * transfer_request)91 UINT _ux_host_stack_transfer_run(UX_TRANSFER *transfer_request)
92 {
93
94 UX_INTERRUPT_SAVE_AREA
95
96 UX_ENDPOINT *endpoint;
97 UX_DEVICE *device;
98 UX_HCD *hcd;
99 ULONG endpoint_type;
100 UINT status;
101
102
103 /* Get the endpoint container from the transfer_request */
104 endpoint = transfer_request -> ux_transfer_request_endpoint;
105
106 /* Sanity check. */
107 if (endpoint == UX_NULL)
108 return(UX_STATE_EXIT);
109
110 /* Get the endpoint type. */
111 endpoint_type = endpoint -> ux_endpoint_descriptor.bmAttributes;
112 endpoint_type &= UX_MASK_ENDPOINT_TYPE;
113
114 /* Get the device container from the endpoint. */
115 device = endpoint -> ux_endpoint_device;
116
117 /* Sanity check. */
118 if (device == UX_NULL)
119 return(UX_STATE_EXIT);
120
121 /* Ensure we are not preempted by the enum thread while we check the device
122 state and set the transfer status. */
123 UX_DISABLE
124
125 /* Check if it's default endpoint 0. */
126 if (endpoint -> ux_endpoint_descriptor.bEndpointAddress & ~UX_ENDPOINT_DIRECTION)
127 {
128
129 /* It's not endpoint 0, check device state. */
130 if (device -> ux_device_state != UX_DEVICE_ATTACHED &&
131 device -> ux_device_state != UX_DEVICE_ADDRESSED &&
132 device -> ux_device_state != UX_DEVICE_CONFIGURED)
133 {
134 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_NOT_READY;
135 transfer_request -> ux_transfer_request_state = UX_STATE_EXIT;
136 _ux_host_stack_transfer_retire(transfer_request);
137
138 /* Restore interrupts. */
139 UX_RESTORE
140 return(UX_STATE_EXIT);
141 }
142 }
143
144 /* With the device we have the pointer to the HCD. */
145 hcd = UX_DEVICE_HCD_GET(device);
146
147 /* Process states. */
148 switch(transfer_request -> ux_transfer_request_state)
149 {
150 case UX_STATE_RESET:
151
152 /* Initialize request fields. */
153 transfer_request -> ux_transfer_request_actual_length = 0;
154 transfer_request -> ux_transfer_request_status = UX_TRANSFER_STATUS_NOT_PENDING;
155 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING;
156 transfer_request -> ux_transfer_request_state = UX_STATE_WAIT;
157 transfer_request -> ux_transfer_request_time_start = _ux_utility_time_get();
158
159 /* Add request to system pending request list. Note request may be kept
160 if transfer callback is used. */
161 if (_ux_host_stack_transfer_locate(transfer_request, UX_NULL) <
162 UX_HOST_STACK_TRANSFER_AT_LIST_HEAD)
163 {
164 transfer_request -> ux_transfer_request_next_pending =
165 _ux_system_host -> ux_system_host_pending_transfers;
166 _ux_system_host -> ux_system_host_pending_transfers = transfer_request;
167 }
168
169 /* Do immediate HCD call to start transfer in background. */
170 /* Fall through. */
171 case UX_STATE_WAIT:
172 UX_RESTORE
173
174 {
175
176 /* Send the command to the controller. */
177 status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_TRANSFER_RUN, transfer_request);
178 }
179
180 /* Any error or end: simplify to idle. */
181 if (status < UX_STATE_WAIT)
182 {
183 UX_DISABLE
184 UX_TRANSFER_STATE_IDLE(transfer_request);
185 _ux_host_stack_transfer_retire(transfer_request);
186 UX_RESTORE
187 return(status);
188 }
189
190 /* Timeout check. */
191 if (transfer_request -> ux_transfer_request_timeout_value != UX_WAIT_FOREVER)
192 {
193 if (transfer_request -> ux_transfer_request_timeout_value <
194 _ux_utility_time_elapsed(transfer_request -> ux_transfer_request_time_start,
195 _ux_utility_time_get()))
196 {
197
198 /* All transfers pending need to abort. There may have been a partial transfer. */
199 _ux_host_stack_transfer_request_abort(transfer_request);
200
201 /* Set the completion code. */
202 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT;
203
204 /* There was an error: simplify to idle. */
205 UX_DISABLE
206 UX_TRANSFER_STATE_IDLE(transfer_request);
207 _ux_host_stack_transfer_retire(transfer_request);
208 UX_RESTORE
209 return(UX_STATE_ERROR);
210 }
211 }
212
213 /* And return the status. */
214 return(status);
215
216 case UX_STATE_EXIT:
217 UX_RESTORE
218 return(UX_STATE_EXIT);
219 case UX_STATE_IDLE:
220 UX_RESTORE
221 return(UX_STATE_IDLE);
222
223 default: /* Error case, return EXIT. */
224 break;
225 }
226
227 /* Error case, return EXIT. */
228 transfer_request -> ux_transfer_request_state = UX_STATE_RESET;
229 _ux_host_stack_transfer_retire(transfer_request);
230 UX_RESTORE
231 return(UX_STATE_EXIT);
232 }
_ux_host_stack_transfer_locate(UX_TRANSFER * transfer,UX_TRANSFER ** previous)233 static inline UINT _ux_host_stack_transfer_locate(UX_TRANSFER *transfer, UX_TRANSFER **previous)
234 {
235 UX_TRANSFER *prev;
236
237 /* Case 0: pending list is NULL. */
238 if (_ux_system_host -> ux_system_host_pending_transfers == UX_NULL)
239 return(UX_HOST_STACK_TRANSFER_LIST_IS_NULL);
240
241 /* Case 1: it's list head. */
242 if (_ux_system_host -> ux_system_host_pending_transfers == transfer)
243 return(UX_HOST_STACK_TRANSFER_AT_LIST_HEAD);
244
245 /* Case 2: scan list. */
246 prev = _ux_system_host -> ux_system_host_pending_transfers;
247 do
248 {
249 if (prev -> ux_transfer_request_next_pending == transfer)
250 {
251 if (previous)
252 *previous = prev;
253 return(UX_HOST_STACK_TRANSFER_IN_LIST);
254 }
255 prev = prev -> ux_transfer_request_next_pending;
256 } while (prev);
257
258 /* Case 3: not found. */
259 return(UX_HOST_STACK_TRANSFER_NOT_IN_LIST);
260 }
_ux_host_stack_transfer_retire(UX_TRANSFER * transfer)261 static inline void _ux_host_stack_transfer_retire(UX_TRANSFER *transfer)
262 {
263 ULONG flags;
264 UX_TRANSFER *previous;
265
266 /* Locate the request in pending list. */
267 switch(_ux_host_stack_transfer_locate(transfer, &previous))
268 {
269 case UX_HOST_STACK_TRANSFER_AT_LIST_HEAD:
270
271 /* Unlink from pending transfer list head. */
272 _ux_system_host -> ux_system_host_pending_transfers =
273 transfer -> ux_transfer_request_next_pending;
274 break;
275 case UX_HOST_STACK_TRANSFER_IN_LIST:
276
277 /* Unlink from pending transfer list. */
278 previous -> ux_transfer_request_next_pending =
279 transfer -> ux_transfer_request_next_pending;
280 break;
281
282 default:
283 break;
284 }
285
286 /* Process transfer flags. */
287 flags = transfer -> ux_transfer_request_flags;
288 transfer -> ux_transfer_request_flags &=
289 ~(UX_TRANSFER_FLAG_LOCK | UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK);
290 if (flags & UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK)
291 {
292 transfer -> ux_transfer_request_endpoint ->
293 ux_endpoint_device -> ux_device_flags &= ~UX_DEVICE_FLAG_LOCK;
294 }
295 }
296 #endif
297