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 UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG(sizeof(UX_HCD), UX_MAX_HCD), UX_MAX_HCD_mul_ovf)
31 UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG(sizeof(UX_HOST_CLASS), UX_MAX_CLASS_DRIVER), UX_MAX_CLASS_DRIVER_mul_ovf)
32 UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG(sizeof(UX_DEVICE), UX_MAX_DEVICES), UX_MAX_DEVICES_mul_ovf)
33 
34 #ifndef UX_HOST_HNP_POLLING_THREAD_STACK_SIZE
35 #define UX_HOST_HNP_POLLING_THREAD_STACK_SIZE UX_THREAD_STACK_SIZE
36 #endif
37 
38 /* Defined USBX host variables.  */
39 
40 UX_SYSTEM_HOST     *_ux_system_host;
41 
42 /* Define table of periodic tree entries, properly indexed.  */
43 
44 UINT _ux_system_host_hcd_periodic_tree_entries[32] = {
45                                                                             0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c,
46                                                                             0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e,
47                                                                             0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d,
48                                                                             0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f};
49 
50 /* Define the names of all the USB Classes of USBX.  */
51 
52 UCHAR _ux_system_host_class_hub_name[] =                                    "ux_host_class_hub";
53 UCHAR _ux_system_host_class_printer_name[] =                                "ux_host_class_printer";
54 UCHAR _ux_system_host_class_storage_name[] =                                "ux_host_class_storage";
55 UCHAR _ux_system_host_class_hid_name[] =                                    "ux_host_class_hid";
56 UCHAR _ux_system_host_class_audio_name[] =                                  "ux_host_class_audio";
57 UCHAR _ux_system_host_class_cdc_acm_name[] =                                "ux_host_class_cdc_acm";
58 UCHAR _ux_system_host_class_cdc_dlc_name[] =                                "ux_host_class_cdc_dlc";
59 UCHAR _ux_system_host_class_cdc_ecm_name[] =                                "ux_host_class_cdc_ecm";
60 UCHAR _ux_system_host_class_prolific_name[] =                               "ux_host_class_prolific";
61 UCHAR _ux_system_host_class_pima_name[] =                                   "ux_host_class_pima";
62 UCHAR _ux_system_host_class_dpump_name[] =                                  "ux_host_class_dpump";
63 UCHAR _ux_system_host_class_asix_name[] =                                   "ux_host_class_asix";
64 UCHAR _ux_system_host_class_swar_name[] =                                   "ux_host_class_sierra_wireless";
65 UCHAR _ux_system_host_class_gser_name[] =                                   "ux_host_class_generic_serial";
66 UCHAR _ux_system_host_class_hid_client_remote_control_name[] =              "ux_host_class_hid_client_remote_control";
67 UCHAR _ux_system_host_class_hid_client_mouse_name[] =                       "ux_host_class_hid_client_mouse";
68 UCHAR _ux_system_host_class_hid_client_keyboard_name[] =                    "ux_host_class_hid_client_keyboard";
69 
70 /* Define the name of all the USB Host Controllers of USBX.  */
71 
72 UCHAR _ux_system_host_hcd_ohci_name[] =                                     "ux_hcd_ohci";
73 UCHAR _ux_system_host_hcd_ehci_name[] =                                     "ux_hcd_ehci";
74 UCHAR _ux_system_host_hcd_isp1161_name[] =                                  "ux_hcd_isp1161";
75 UCHAR _ux_system_host_hcd_isp1362_name[] =                                  "ux_hcd_isp1362";
76 UCHAR _ux_system_host_hcd_sh2_name[] =                                      "ux_hcd_rx";
77 UCHAR _ux_system_host_hcd_rx_name[] =                                       "ux_hcd_sh2";
78 UCHAR _ux_system_host_hcd_pic32_name[] =                                    "ux_hcd_pic32";
79 UCHAR _ux_system_host_hcd_stm32_name[] =                                    "ux_hcd_stm32";
80 UCHAR _ux_system_host_hcd_musb_name[] =                                     "ux_hcd_musb";
81 UCHAR _ux_system_host_hcd_atm7_name[] =                                     "ux_hcd_atm7";
82 UCHAR _ux_system_host_hcd_simulator_name[] =                                "ux_hcd_simulator";
83 
84 /**************************************************************************/
85 /*                                                                        */
86 /*  FUNCTION                                               RELEASE        */
87 /*                                                                        */
88 /*    _ux_host_stack_initialize                           PORTABLE C      */
89 /*                                                           6.1.10       */
90 /*  AUTHOR                                                                */
91 /*                                                                        */
92 /*    Chaoqiong Xiao, Microsoft Corporation                               */
93 /*                                                                        */
94 /*  DESCRIPTION                                                           */
95 /*                                                                        */
96 /*    This function initializes all the host code for USBX to work on a   */
97 /*    specific platform.                                                  */
98 /*                                                                        */
99 /*  INPUT                                                                 */
100 /*                                                                        */
101 /*    (ux_system_host_change_function)        Function pointer to the     */
102 /*                                            callback function for a     */
103 /*                                            device change               */
104 /*                                                                        */
105 /*  OUTPUT                                                                */
106 /*                                                                        */
107 /*    Completion Status                                                   */
108 /*                                                                        */
109 /*                                                                        */
110 /*  CALLS                                                                 */
111 /*                                                                        */
112 /*    _ux_utility_memory_allocate           Allocate host memory          */
113 /*    _ux_utility_semaphore_create          Create host semaphore         */
114 /*    _ux_utility_mutex_create             Create host mutex              */
115 /*    _ux_utility_thread_create             Create host thread            */
116 /*                                                                        */
117 /*  CALLED BY                                                             */
118 /*                                                                        */
119 /*    Application                                                         */
120 /*                                                                        */
121 /*  RELEASE HISTORY                                                       */
122 /*                                                                        */
123 /*    DATE              NAME                      DESCRIPTION             */
124 /*                                                                        */
125 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
126 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
127 /*                                            optimized based on compile  */
128 /*                                            definitions, used UX prefix */
129 /*                                            to refer to TX symbols      */
130 /*                                            instead of using them       */
131 /*                                            directly,                   */
132 /*                                            resulting in version 6.1    */
133 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
134 /*                                            added standalone support,   */
135 /*                                            resulting in version 6.1.10 */
136 /*                                                                        */
137 /**************************************************************************/
_ux_host_stack_initialize(UINT (* ux_system_host_change_function)(ULONG,UX_HOST_CLASS *,VOID *))138 UINT  _ux_host_stack_initialize(UINT (*ux_system_host_change_function)(ULONG, UX_HOST_CLASS *, VOID *))
139 {
140 
141 UINT        status;
142 UCHAR       *memory;
143 #if defined(UX_HOST_STANDALONE)
144 UINT        i;
145 UX_DEVICE   *device;
146 #endif
147 
148     /* If trace is enabled, insert this event into the trace buffer.  */
149     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_INITIALIZE, 0, 0, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
150 
151     /* Initialize some of the global so that we don't have to recompile the
152        core code when one item is adjusted.  */
153     _ux_system_host -> ux_system_host_max_ed =        UX_MAX_ED;
154     _ux_system_host -> ux_system_host_max_td =        UX_MAX_TD;
155     _ux_system_host -> ux_system_host_max_iso_td =    UX_MAX_ISO_TD;
156     UX_SYSTEM_HOST_MAX_CLASS_SET(UX_MAX_CLASS_DRIVER);
157     UX_SYSTEM_HOST_MAX_HCD_SET(UX_MAX_HCD);
158     UX_SYSTEM_HOST_MAX_DEVICES_SET(UX_MAX_DEVICES);
159 
160     /* Set the change device function address.  */
161     _ux_system_host -> ux_system_host_change_function =  ux_system_host_change_function;
162 
163     /* Allocate memory for the HCDs.
164      * sizeof(UX_HCD)*UX_MAX_HCD overflow is checked outside of the function.
165      */
166     memory =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HCD)*UX_MAX_HCD);
167 
168     /* Check for successful allocation.  */
169     if (memory == UX_NULL)
170         return(UX_MEMORY_INSUFFICIENT);
171 
172     /* Set to success by default.  */
173     status = UX_SUCCESS;
174 
175     /* Store memory in system structure.  */
176     _ux_system_host -> ux_system_host_hcd_array =  (UX_HCD *) memory;
177 
178     /* Allocate memory for the classes.
179      * sizeof(UX_HOST_CLASS)*UX_MAX_CLASS_DRIVER overflow is checked outside of the function.
180      */
181     memory =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS)*UX_MAX_CLASS_DRIVER);
182 
183     /* Check for successful allocation.  */
184     if (memory == UX_NULL)
185         status = UX_MEMORY_INSUFFICIENT;
186     else
187 
188         /* Store memory in system structure.  */
189         _ux_system_host -> ux_system_host_class_array =  (UX_HOST_CLASS *) memory;
190 
191     /* Allocate memory for the device containers.
192      * sizeof(UX_DEVICE)*UX_MAX_DEVICES overflow is checked outside of the function.
193      */
194     if (status == UX_SUCCESS)
195     {
196         memory =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_DEVICE)*UX_MAX_DEVICES);
197 
198         /* Check for successful allocation.  */
199         if(memory == UX_NULL)
200             status = UX_MEMORY_INSUFFICIENT;
201         else
202 
203             /* Store memory in system structure.  */
204             _ux_system_host -> ux_system_host_device_array =  (UX_DEVICE *) memory;
205 
206 #if defined(UX_HOST_STANDALONE)
207 
208         /* Add devices to the enumeration list, with ENUM flags cleared.  */
209         if (status == UX_SUCCESS)
210         {
211 
212             /* Start from the last device instance.  */
213             device = &_ux_system_host -> ux_system_host_device_array[UX_MAX_DEVICES - 1];
214 
215             /* Insert all devices to enumeration list head.  */
216             for (i = 0; i < UX_MAX_DEVICES; i ++)
217             {
218 
219                 /* Insert to head.  */
220                 device -> ux_device_enum_next = _ux_system_host -> ux_system_host_enum_device;
221                 _ux_system_host -> ux_system_host_enum_device = device;
222 
223                 /* Next device.  */
224                 device --;
225             }
226         }
227 #endif
228 
229     }
230 
231 #if !defined(UX_HOST_STANDALONE)
232     /* Obtain enough stack for the two USBX host threads.  */
233     if (status == UX_SUCCESS)
234     {
235         _ux_system_host -> ux_system_host_enum_thread_stack =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,
236                                                                             UX_HOST_ENUM_THREAD_STACK_SIZE);
237 
238         /* Check for successful allocation.  */
239         if (_ux_system_host -> ux_system_host_enum_thread_stack == UX_NULL)
240             status = UX_MEMORY_INSUFFICIENT;
241     }
242 
243     /* Allocate another stack area.  */
244     if (status == UX_SUCCESS)
245     {
246         _ux_system_host -> ux_system_host_hcd_thread_stack =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,
247                                                                             UX_HOST_HCD_THREAD_STACK_SIZE);
248 
249         /* Check for successful allocation.  */
250         if (_ux_system_host -> ux_system_host_hcd_thread_stack == UX_NULL)
251             status = UX_MEMORY_INSUFFICIENT;
252     }
253 
254     /* Create the semaphores used by the hub and root hub to awake the enumeration thread.  */
255     if (status == UX_SUCCESS)
256     {
257         status =  _ux_utility_semaphore_create(&_ux_system_host -> ux_system_host_enum_semaphore, "ux_system_host_enum_semaphore", 0);
258         if(status != UX_SUCCESS)
259             status = UX_SEMAPHORE_ERROR;
260     }
261 
262     /* Create the semaphores used by the HCD to perform the completion phase of transfer_requests.  */
263     if (status == UX_SUCCESS)
264     {
265         status =  _ux_utility_semaphore_create(&_ux_system_host -> ux_system_host_hcd_semaphore, "ux_system_host_hcd_semaphore", 0);
266         if(status != UX_SUCCESS)
267             status = UX_SEMAPHORE_ERROR;
268     }
269 
270     /* Create the enumeration thread of USBX.  */
271     if (status == UX_SUCCESS)
272     {
273         status =  _ux_utility_thread_create(&_ux_system_host -> ux_system_host_enum_thread, "ux_system_host_enum_thread", _ux_host_stack_enum_thread_entry,
274                             0, _ux_system_host -> ux_system_host_enum_thread_stack,
275                             UX_HOST_ENUM_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_ENUM,
276                             UX_THREAD_PRIORITY_ENUM, UX_NO_TIME_SLICE, UX_AUTO_START);
277 
278         /* Check the completion status.  */
279         if(status != UX_SUCCESS)
280             status = UX_THREAD_ERROR;
281     }
282 
283     /* Create the HCD thread of USBX.  */
284     if (status == UX_SUCCESS)
285     {
286         status =  _ux_utility_thread_create(&_ux_system_host -> ux_system_host_hcd_thread, "ux_host_stack_hcd_thread", _ux_host_stack_hcd_thread_entry,
287                             0, _ux_system_host -> ux_system_host_hcd_thread_stack,
288                             UX_HOST_HCD_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_HCD,
289                             UX_THREAD_PRIORITY_HCD, UX_NO_TIME_SLICE,UX_AUTO_START);
290 
291         /* Check the completion status.  */
292         if(status != UX_SUCCESS)
293             status = UX_THREAD_ERROR;
294     }
295 #endif
296 
297 #if defined(UX_OTG_SUPPORT) && !defined(UX_OTG_STANDALONE)
298     /* Allocate another stack area for the HNP polling thread.  */
299     if (status == UX_SUCCESS)
300     {
301         _ux_system_host -> ux_system_host_hnp_polling_thread_stack =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY,
302                                                                             UX_HOST_HNP_POLLING_THREAD_STACK_SIZE);
303 
304         /* Check for successful allocation.  */
305         if (_ux_system_host -> ux_system_host_hnp_polling_thread_stack == UX_NULL)
306             status = UX_MEMORY_INSUFFICIENT;
307     }
308 
309     /* Create the HNP polling thread of USBX.  */
310     if (status == UX_SUCCESS)
311     {
312         status =  _ux_utility_thread_create(&_ux_system_host -> ux_system_host_hnp_polling_thread, "ux_host_stack_hnp_polling_thread", _ux_host_stack_hnp_polling_thread_entry,
313                             0, _ux_system_host -> ux_system_host_hnp_polling_thread_stack,
314                             UX_HOST_HNP_POLLING_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_ENUM,
315                             UX_THREAD_PRIORITY_ENUM, UX_NO_TIME_SLICE, UX_AUTO_START);
316 
317         /* Check the completion status.  */
318         if (status != UX_SUCCESS)
319             status = UX_THREAD_ERROR;
320 
321         /* Return success (SUCCESS).  */
322         else
323             return(status);
324     }
325 
326     /* Free up resources on error cases.  */
327 
328     /* Last resource, _ux_system_host -> ux_system_host_hnp_polling_thread is not created or created error,
329      * no need to delete it.  */
330 
331     /* Free _ux_system_host -> ux_system_host_hnp_polling_thread_stack.  */
332     if (_ux_system_host -> ux_system_host_hnp_polling_thread_stack)
333         _ux_utility_memory_free(_ux_system_host -> ux_system_host_hnp_polling_thread_stack);
334 
335     /* Delete _ux_system_host -> ux_system_host_hcd_thread.  */
336     if (_ux_system_host -> ux_system_host_hcd_thread.tx_thread_id != 0)
337         _ux_utility_thread_delete(&_ux_system_host -> ux_system_host_hcd_thread);
338 #else
339 
340     /* Return completion status to caller if success.  */
341     if (status == UX_SUCCESS)
342         return(status);
343 
344     /* Free up resources on error cases.  */
345 
346     /* Last resource, _ux_system_host -> ux_system_host_hcd_thread is not created or created error,
347      * no need to delete it.  */
348 #endif
349 
350 #if !defined(UX_HOST_STANDALONE)
351     /* Delete _ux_system_host -> ux_system_host_enum_thread.  */
352     if (_ux_system_host -> ux_system_host_enum_thread.tx_thread_id != 0)
353         _ux_utility_thread_delete(&_ux_system_host -> ux_system_host_enum_thread);
354 
355     /* Delete _ux_system_host -> ux_system_host_hcd_semaphore.  */
356     if (_ux_system_host -> ux_system_host_hcd_semaphore.tx_semaphore_id != 0)
357         _ux_utility_semaphore_delete(&_ux_system_host -> ux_system_host_hcd_semaphore);
358 
359     /* Delete _ux_system_host -> ux_system_host_enum_semaphore.  */
360     if (_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_id != 0)
361         _ux_utility_semaphore_delete(&_ux_system_host -> ux_system_host_enum_semaphore);
362 
363     /* Free _ux_system_host -> ux_system_host_hcd_thread_stack.  */
364     if (_ux_system_host -> ux_system_host_hcd_thread_stack)
365         _ux_utility_memory_free(_ux_system_host -> ux_system_host_hcd_thread_stack);
366 
367     /* Free _ux_system_host -> ux_system_host_enum_thread_stack.  */
368     if (_ux_system_host -> ux_system_host_enum_thread_stack)
369         _ux_utility_memory_free(_ux_system_host -> ux_system_host_enum_thread_stack);
370 #endif
371 
372     /* Free _ux_system_host -> ux_system_host_device_array.  */
373     if (_ux_system_host -> ux_system_host_device_array)
374         _ux_utility_memory_free(_ux_system_host -> ux_system_host_device_array);
375 
376     /* Free _ux_system_host -> ux_system_host_class_array.  */
377     if (_ux_system_host -> ux_system_host_class_array)
378         _ux_utility_memory_free(_ux_system_host -> ux_system_host_class_array);
379 
380     /* Free _ux_system_host -> ux_system_host_hcd_array.  */
381     _ux_utility_memory_free(_ux_system_host -> ux_system_host_hcd_array);
382 
383     /* Return completion status to caller.  */
384     return(status);
385 }
386 
387