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