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 /** Device Stack */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define UX_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "ux_api.h"
29 #include "ux_device_stack.h"
30
31 UX_COMPILE_TIME_ASSERT(!UX_OVERFLOW_CHECK_MULC_ULONG(sizeof(UX_SLAVE_CLASS), UX_MAX_SLAVE_CLASS_DRIVER), UX_MAX_SLAVE_CLASS_DRIVER_mul_ovf)
32
33 /* Define the names of all the USB Classes of USBX. */
34
35 UCHAR _ux_system_slave_class_storage_name[] = "ux_slave_class_storage";
36 UCHAR _ux_system_slave_class_cdc_acm_name[] = "ux_slave_class_cdc_acm";
37 UCHAR _ux_system_slave_class_dpump_name[] = "ux_slave_class_dpump";
38 UCHAR _ux_system_slave_class_pima_name[] = "ux_slave_class_pima";
39 UCHAR _ux_system_slave_class_hid_name[] = "ux_slave_class_hid";
40 UCHAR _ux_system_slave_class_rndis_name[] = "ux_slave_class_rndis";
41 UCHAR _ux_system_slave_class_cdc_ecm_name[] = "ux_slave_class_cdc_ecm";
42 UCHAR _ux_system_slave_class_dfu_name[] = "ux_slave_class_dfu";
43 UCHAR _ux_system_slave_class_audio_name[] = "ux_slave_class_audio";
44
45 UCHAR _ux_system_device_class_printer_name[] = "ux_device_class_printer";
46 UCHAR _ux_system_device_class_ccid_name[] = "ux_device_class_ccid";
47 UCHAR _ux_system_device_class_video_name[] = "ux_device_class_video";
48
49 /* Define USBX Host variable. */
50 UX_SYSTEM_SLAVE *_ux_system_slave;
51
52 /**************************************************************************/
53 /* */
54 /* FUNCTION RELEASE */
55 /* */
56 /* _ux_device_stack_initialize PORTABLE C */
57 /* 6.3.0 */
58 /* AUTHOR */
59 /* */
60 /* Chaoqiong Xiao, Microsoft Corporation */
61 /* */
62 /* DESCRIPTION */
63 /* */
64 /* This function initializes the generic portion of the device side of */
65 /* USBX. */
66 /* */
67 /* INPUT */
68 /* */
69 /* device_framework_high_speed Pointer to high speed FW */
70 /* device_framework_length_high_speed Length of high speed FW */
71 /* device_framework_full_speed Pointer to full speed FW */
72 /* device_framework_length_full_speed Length of full speed FW */
73 /* string_framework Pointer to string FW */
74 /* string_framework_length Length of string FW */
75 /* language_id_framework Pointer to language ID FW */
76 /* language_id_framework_length Length of language ID FW */
77 /* (ux_system_slave_change_function) Pointer to callback function */
78 /* for device changes */
79 /* */
80 /* OUTPUT */
81 /* */
82 /* Completion Status */
83 /* */
84 /* CALLS */
85 /* */
86 /* _ux_utility_memory_allocate Allocate memory */
87 /* _ux_utility_memory_free Free memory */
88 /* _ux_utility_semaphore_create Create semaphore */
89 /* _ux_utility_semaphore_delete Delete semaphore */
90 /* */
91 /* CALLED BY */
92 /* */
93 /* Application */
94 /* */
95 /* RELEASE HISTORY */
96 /* */
97 /* DATE NAME DESCRIPTION */
98 /* */
99 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
100 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
101 /* optimized based on compile */
102 /* definitions, */
103 /* resulting in version 6.1 */
104 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
105 /* added standalone support, */
106 /* added printer support, */
107 /* resulting in version 6.1.10 */
108 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
109 /* added CCID support, */
110 /* added video support, */
111 /* resulting in version 6.1.11 */
112 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
113 /* added a new mode to manage */
114 /* endpoint buffer in classes, */
115 /* resulting in version 6.3.0 */
116 /* */
117 /**************************************************************************/
_ux_device_stack_initialize(UCHAR * device_framework_high_speed,ULONG device_framework_length_high_speed,UCHAR * device_framework_full_speed,ULONG device_framework_length_full_speed,UCHAR * string_framework,ULONG string_framework_length,UCHAR * language_id_framework,ULONG language_id_framework_length,UINT (* ux_system_slave_change_function)(ULONG))118 UINT _ux_device_stack_initialize(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed,
119 UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed,
120 UCHAR * string_framework, ULONG string_framework_length,
121 UCHAR * language_id_framework, ULONG language_id_framework_length,
122 UINT (*ux_system_slave_change_function)(ULONG))
123 {
124 UX_SLAVE_DEVICE *device;
125 UX_SLAVE_ENDPOINT *endpoints_pool;
126 UX_SLAVE_INTERFACE *interfaces_pool;
127 UX_SLAVE_TRANSFER *transfer_request;
128 UINT status;
129 ULONG interfaces_found;
130 ULONG endpoints_found;
131 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE)
132 ULONG max_interface_number;
133 ULONG local_interfaces_found;
134 ULONG local_endpoints_found;
135 ULONG endpoints_in_interface_found;
136 UCHAR *device_framework;
137 ULONG device_framework_length;
138 UCHAR descriptor_type;
139 ULONG descriptor_length;
140 #endif
141 UCHAR *memory;
142
143 /* If trace is enabled, insert this event into the trace buffer. */
144 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_INITIALIZE, 0, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
145
146 /* Get the pointer to the device. */
147 device = &_ux_system_slave -> ux_system_slave_device;
148
149 /* Store the high speed device framework address and length in the project structure. */
150 _ux_system_slave -> ux_system_slave_device_framework_high_speed = device_framework_high_speed;
151 _ux_system_slave -> ux_system_slave_device_framework_length_high_speed = device_framework_length_high_speed;
152
153 /* Store the string framework address and length in the project structure. */
154 _ux_system_slave -> ux_system_slave_device_framework_full_speed = device_framework_full_speed;
155 _ux_system_slave -> ux_system_slave_device_framework_length_full_speed = device_framework_length_full_speed;
156
157 /* Store the string framework address and length in the project structure. */
158 _ux_system_slave -> ux_system_slave_string_framework = string_framework;
159 _ux_system_slave -> ux_system_slave_string_framework_length = string_framework_length;
160
161 /* Store the language ID list in the project structure. */
162 _ux_system_slave -> ux_system_slave_language_id_framework = language_id_framework;
163 _ux_system_slave -> ux_system_slave_language_id_framework_length = language_id_framework_length;
164
165 /* Store the max number of slave class drivers in the project structure. */
166 UX_SYSTEM_DEVICE_MAX_CLASS_SET(UX_MAX_SLAVE_CLASS_DRIVER);
167
168 /* Store the device state change function callback. */
169 _ux_system_slave -> ux_system_slave_change_function = ux_system_slave_change_function;
170
171 /* Allocate memory for the classes.
172 * sizeof(UX_SLAVE_CLASS) * UX_MAX_SLAVE_CLASS_DRIVER) overflow is checked
173 * outside of the function.
174 */
175 memory = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS) * UX_MAX_SLAVE_CLASS_DRIVER);
176 if (memory == UX_NULL)
177 return(UX_MEMORY_INSUFFICIENT);
178
179 /* Save this memory allocation in the USBX project. */
180 _ux_system_slave -> ux_system_slave_class_array = (UX_SLAVE_CLASS *) ((void *) memory);
181
182 /* Allocate some memory for the Control Endpoint. First get the address of the transfer request for the
183 control endpoint. */
184 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
185
186 /* Acquire a buffer for the size of the endpoint. */
187 transfer_request -> ux_slave_transfer_request_data_pointer =
188 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH);
189
190 /* Ensure we have enough memory. */
191 if (transfer_request -> ux_slave_transfer_request_data_pointer == UX_NULL)
192 status = UX_MEMORY_INSUFFICIENT;
193 else
194 status = UX_SUCCESS;
195
196 #if defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE)
197
198 /* No scan, just assign predefined value. */
199 interfaces_found = UX_MAX_SLAVE_INTERFACES;
200 endpoints_found = UX_MAX_DEVICE_ENDPOINTS;
201 #else
202
203 /* Reset all values we are using during the scanning of the framework. */
204 interfaces_found = 0;
205 endpoints_found = 0;
206 max_interface_number = 0;
207
208 /* Go on to scan interfaces if no error. */
209 if (status == UX_SUCCESS)
210 {
211
212 /* We need to determine the maximum number of interfaces and endpoints declared in the device framework.
213 This mechanism requires that both framework behave the same way regarding the number of interfaces
214 and endpoints. */
215 device_framework = _ux_system_slave -> ux_system_slave_device_framework_full_speed;
216 device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_full_speed;
217
218 /* Reset all values we are using during the scanning of the framework. */
219 local_interfaces_found = 0;
220 local_endpoints_found = 0;
221 endpoints_in_interface_found = 0;
222
223 /* Parse the device framework and locate interfaces and endpoint descriptor(s). */
224 while (device_framework_length != 0)
225 {
226
227 /* Get the length of this descriptor. */
228 descriptor_length = (ULONG) *device_framework;
229
230 /* And its type. */
231 descriptor_type = *(device_framework + 1);
232
233 /* Check if this is an endpoint descriptor. */
234 switch(descriptor_type)
235 {
236
237 case UX_INTERFACE_DESCRIPTOR_ITEM:
238
239 /* Check if this is alternate setting 0. If not, do not add another interface found.
240 If this is alternate setting 0, reset the endpoints count for this interface. */
241 if (*(device_framework + 3) == 0)
242 {
243
244 /* Add the cumulated number of endpoints in the previous interface. */
245 local_endpoints_found += endpoints_in_interface_found;
246
247 /* Read the number of endpoints for this alternate setting. */
248 endpoints_in_interface_found = (ULONG) *(device_framework + 4);
249
250 /* Increment the number of interfaces found in the current configuration. */
251 local_interfaces_found++;
252 }
253 else
254 {
255
256 /* Compare the number of endpoints found in this non 0 alternate setting. */
257 if (endpoints_in_interface_found < (ULONG) *(device_framework + 4))
258
259 /* Adjust the number of maximum endpoints in this interface. */
260 endpoints_in_interface_found = (ULONG) *(device_framework + 4);
261 }
262
263 /* Check and update max interface number. */
264 if (*(device_framework + 2) > max_interface_number)
265 max_interface_number = *(device_framework + 2);
266
267 break;
268
269 case UX_CONFIGURATION_DESCRIPTOR_ITEM:
270
271 /* Check if the number of interfaces found in this configuration is the maximum so far. */
272 if (local_interfaces_found > interfaces_found)
273
274 /* We need to adjust the number of maximum interfaces. */
275 interfaces_found = local_interfaces_found;
276
277 /* We have a new configuration. We need to reset the number of local interfaces. */
278 local_interfaces_found = 0;
279
280 /* Add the cumulated number of endpoints in the previous interface. */
281 local_endpoints_found += endpoints_in_interface_found;
282
283 /* Check if the number of endpoints found in the previous configuration is the maximum so far. */
284 if (local_endpoints_found > endpoints_found)
285
286 /* We need to adjust the number of maximum endpoints. */
287 endpoints_found = local_endpoints_found;
288
289 /* We have a new configuration. We need to reset the number of local endpoints. */
290 local_endpoints_found = 0;
291 endpoints_in_interface_found = 0;
292
293 break;
294
295 default:
296 break;
297 }
298
299 /* Adjust what is left of the device framework. */
300 device_framework_length -= descriptor_length;
301
302 /* Point to the next descriptor. */
303 device_framework += descriptor_length;
304 }
305
306 /* Add the cumulated number of endpoints in the previous interface. */
307 local_endpoints_found += endpoints_in_interface_found;
308
309 /* Check if the number of endpoints found in the previous interface is the maximum so far. */
310 if (local_endpoints_found > endpoints_found)
311
312 /* We need to adjust the number of maximum endpoints. */
313 endpoints_found = local_endpoints_found;
314
315
316 /* Check if the number of interfaces found in this configuration is the maximum so far. */
317 if (local_interfaces_found > interfaces_found)
318
319 /* We need to adjust the number of maximum interfaces. */
320 interfaces_found = local_interfaces_found;
321
322 /* We do a sanity check on the finding. At least there must be one interface but endpoints are
323 not necessary. */
324 if (interfaces_found == 0)
325 {
326
327 /* Error trap. */
328 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_INIT, UX_DESCRIPTOR_CORRUPTED);
329
330 /* If trace is enabled, insert this event into the trace buffer. */
331 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, device_framework, 0, 0, UX_TRACE_ERRORS, 0, 0)
332
333 status = UX_DESCRIPTOR_CORRUPTED;
334 }
335
336 /* We do a sanity check on the finding. Max interface number should not exceed limit. */
337 if (status == UX_SUCCESS &&
338 max_interface_number >= UX_MAX_SLAVE_INTERFACES)
339 {
340
341 /* Error trap. */
342 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_INIT, UX_MEMORY_INSUFFICIENT);
343
344 /* If trace is enabled, insert this event into the trace buffer. */
345 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device_framework, 0, 0, UX_TRACE_ERRORS, 0, 0)
346
347 status = UX_MEMORY_INSUFFICIENT;
348 }
349 }
350 #endif
351
352 /* Go on to allocate interfaces pool if no error. */
353 if (status == UX_SUCCESS)
354 {
355
356 /* Memorize both pool sizes. */
357 device -> ux_slave_device_interfaces_pool_number = interfaces_found;
358 device -> ux_slave_device_endpoints_pool_number = endpoints_found;
359
360 /* We assign a pool for the interfaces. */
361 interfaces_pool = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, interfaces_found, sizeof(UX_SLAVE_INTERFACE));
362 if (interfaces_pool == UX_NULL)
363 status = UX_MEMORY_INSUFFICIENT;
364 else
365
366 /* Save the interface pool address in the device container. */
367 device -> ux_slave_device_interfaces_pool = interfaces_pool;
368 }
369
370 /* Do we need an endpoint pool ? */
371 if (endpoints_found != 0 && status == UX_SUCCESS)
372 {
373
374 /* We assign a pool for the endpoints. */
375 endpoints_pool = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, endpoints_found, sizeof(UX_SLAVE_ENDPOINT));
376 if (endpoints_pool == UX_NULL)
377 status = UX_MEMORY_INSUFFICIENT;
378 else
379 {
380
381 /* Save the endpoint pool address in the device container. */
382 device -> ux_slave_device_endpoints_pool = endpoints_pool;
383
384 /* We need to assign a transfer buffer to each endpoint. Each endpoint is assigned the
385 maximum buffer size. We also assign the semaphore used by the endpoint to synchronize transfer
386 completion. */
387 while (endpoints_pool < (device -> ux_slave_device_endpoints_pool + endpoints_found))
388 {
389
390 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 0
391
392 /* Obtain some memory. */
393 endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
394 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
395
396 /* Ensure we could allocate memory. */
397 if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer == UX_NULL)
398 {
399 status = UX_MEMORY_INSUFFICIENT;
400 break;
401 }
402 #endif
403
404 /* Create the semaphore for the endpoint. */
405 status = _ux_device_semaphore_create(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore,
406 "ux_transfer_request_semaphore", 0);
407
408 /* Check completion status. */
409 if (status != UX_SUCCESS)
410 {
411 status = UX_SEMAPHORE_ERROR;
412 break;
413 }
414
415 /* Next endpoint. */
416 endpoints_pool++;
417 }
418 }
419 }
420 else
421 endpoints_pool = UX_NULL;
422
423 /* Return successful completion. */
424 if (status == UX_SUCCESS)
425 return(UX_SUCCESS);
426
427 /* Free resources when there is error. */
428
429 /* Free device -> ux_slave_device_endpoints_pool. */
430 if (endpoints_pool)
431 {
432
433 /* In error cases creating endpoint resources, endpoints_pool is endpoint that failed.
434 * Previously allocated things should be freed. */
435 while(endpoints_pool >= device -> ux_slave_device_endpoints_pool)
436 {
437
438 /* Delete ux_slave_transfer_request_semaphore. */
439 if (_ux_device_semaphore_created(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore))
440 _ux_device_semaphore_delete(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore);
441
442 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 0
443
444 /* Free ux_slave_transfer_request_data_pointer buffer. */
445 if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer)
446 _ux_utility_memory_free(endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer);
447 #endif
448
449 /* Move to previous endpoint. */
450 endpoints_pool --;
451 }
452
453 _ux_utility_memory_free(device -> ux_slave_device_endpoints_pool);
454 }
455
456 /* Free device -> ux_slave_device_interfaces_pool. */
457 if (device -> ux_slave_device_interfaces_pool)
458 _ux_utility_memory_free(device -> ux_slave_device_interfaces_pool);
459
460 /* Free device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer. */
461 if (device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer)
462 _ux_utility_memory_free(device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer);
463
464 /* Free _ux_system_slave -> ux_system_slave_class_array. */
465 _ux_utility_memory_free(_ux_system_slave -> ux_system_slave_class_array);
466
467 /* Return completion status. */
468 return(status);
469 }
470
471
472 /**************************************************************************/
473 /* */
474 /* FUNCTION RELEASE */
475 /* */
476 /* _uxe_device_stack_initialize PORTABLE C */
477 /* 6.3.0 */
478 /* AUTHOR */
479 /* */
480 /* Chaoqiong Xiao, Microsoft Corporation */
481 /* */
482 /* DESCRIPTION */
483 /* */
484 /* This function checks errors in device stack initialization */
485 /* function call. */
486 /* */
487 /* INPUT */
488 /* */
489 /* class_name Name of class */
490 /* class_function_entry Class entry function */
491 /* */
492 /* OUTPUT */
493 /* */
494 /* None */
495 /* */
496 /* CALLS */
497 /* */
498 /* _ux_device_stack_initialize Device Stack Initialize */
499 /* */
500 /* CALLED BY */
501 /* */
502 /* Application */
503 /* */
504 /* RELEASE HISTORY */
505 /* */
506 /* DATE NAME DESCRIPTION */
507 /* */
508 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
509 /* */
510 /**************************************************************************/
_uxe_device_stack_initialize(UCHAR * device_framework_high_speed,ULONG device_framework_length_high_speed,UCHAR * device_framework_full_speed,ULONG device_framework_length_full_speed,UCHAR * string_framework,ULONG string_framework_length,UCHAR * language_id_framework,ULONG language_id_framework_length,UINT (* ux_system_slave_change_function)(ULONG))511 UINT _uxe_device_stack_initialize(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed,
512 UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed,
513 UCHAR * string_framework, ULONG string_framework_length,
514 UCHAR * language_id_framework, ULONG language_id_framework_length,
515 UINT (*ux_system_slave_change_function)(ULONG))
516 {
517
518 /* Sanity checks. */
519 if (((device_framework_high_speed == UX_NULL) && (device_framework_length_high_speed != 0)) ||
520 (device_framework_full_speed == UX_NULL) || (device_framework_length_full_speed == 0) ||
521 ((string_framework == UX_NULL) && (string_framework_length != 0)) ||
522 (language_id_framework == UX_NULL) || (language_id_framework_length == 0))
523 return(UX_INVALID_PARAMETER);
524
525 /* Invoke stack initialize function. */
526 return(_ux_device_stack_initialize(device_framework_high_speed, device_framework_length_high_speed,
527 device_framework_full_speed, device_framework_length_full_speed,
528 string_framework, string_framework_length,
529 language_id_framework, language_id_framework_length,
530 ux_system_slave_change_function));
531 }
532