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