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.1.11 */
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 /* */
113 /**************************************************************************/
_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))114 UINT _ux_device_stack_initialize(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed,
115 UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed,
116 UCHAR * string_framework, ULONG string_framework_length,
117 UCHAR * language_id_framework, ULONG language_id_framework_length,
118 UINT (*ux_system_slave_change_function)(ULONG))
119 {
120 UX_SLAVE_DEVICE *device;
121 UX_SLAVE_ENDPOINT *endpoints_pool;
122 UX_SLAVE_INTERFACE *interfaces_pool;
123 UX_SLAVE_TRANSFER *transfer_request;
124 UINT status;
125 ULONG interfaces_found;
126 ULONG endpoints_found;
127 #if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE)
128 ULONG max_interface_number;
129 ULONG local_interfaces_found;
130 ULONG local_endpoints_found;
131 ULONG endpoints_in_interface_found;
132 UCHAR *device_framework;
133 ULONG device_framework_length;
134 UCHAR descriptor_type;
135 ULONG descriptor_length;
136 #endif
137 UCHAR *memory;
138
139 /* If trace is enabled, insert this event into the trace buffer. */
140 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_INITIALIZE, 0, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
141
142 /* Get the pointer to the device. */
143 device = &_ux_system_slave -> ux_system_slave_device;
144
145 /* Store the high speed device framework address and length in the project structure. */
146 _ux_system_slave -> ux_system_slave_device_framework_high_speed = device_framework_high_speed;
147 _ux_system_slave -> ux_system_slave_device_framework_length_high_speed = device_framework_length_high_speed;
148
149 /* Store the string framework address and length in the project structure. */
150 _ux_system_slave -> ux_system_slave_device_framework_full_speed = device_framework_full_speed;
151 _ux_system_slave -> ux_system_slave_device_framework_length_full_speed = device_framework_length_full_speed;
152
153 /* Store the string framework address and length in the project structure. */
154 _ux_system_slave -> ux_system_slave_string_framework = string_framework;
155 _ux_system_slave -> ux_system_slave_string_framework_length = string_framework_length;
156
157 /* Store the language ID list in the project structure. */
158 _ux_system_slave -> ux_system_slave_language_id_framework = language_id_framework;
159 _ux_system_slave -> ux_system_slave_language_id_framework_length = language_id_framework_length;
160
161 /* Store the max number of slave class drivers in the project structure. */
162 UX_SYSTEM_DEVICE_MAX_CLASS_SET(UX_MAX_SLAVE_CLASS_DRIVER);
163
164 /* Store the device state change function callback. */
165 _ux_system_slave -> ux_system_slave_change_function = ux_system_slave_change_function;
166
167 /* Allocate memory for the classes.
168 * sizeof(UX_SLAVE_CLASS) * UX_MAX_SLAVE_CLASS_DRIVER) overflow is checked
169 * outside of the function.
170 */
171 memory = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS) * UX_MAX_SLAVE_CLASS_DRIVER);
172 if (memory == UX_NULL)
173 return(UX_MEMORY_INSUFFICIENT);
174
175 /* Save this memory allocation in the USBX project. */
176 _ux_system_slave -> ux_system_slave_class_array = (UX_SLAVE_CLASS *) ((void *) memory);
177
178 /* Allocate some memory for the Control Endpoint. First get the address of the transfer request for the
179 control endpoint. */
180 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
181
182 /* Acquire a buffer for the size of the endpoint. */
183 transfer_request -> ux_slave_transfer_request_data_pointer =
184 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH);
185
186 /* Ensure we have enough memory. */
187 if (transfer_request -> ux_slave_transfer_request_data_pointer == UX_NULL)
188 status = UX_MEMORY_INSUFFICIENT;
189 else
190 status = UX_SUCCESS;
191
192 #if defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE)
193
194 /* No scan, just assign predefined value. */
195 interfaces_found = UX_MAX_SLAVE_INTERFACES;
196 endpoints_found = UX_MAX_DEVICE_ENDPOINTS;
197 #else
198
199 /* Reset all values we are using during the scanning of the framework. */
200 interfaces_found = 0;
201 endpoints_found = 0;
202 max_interface_number = 0;
203
204 /* Go on to scan interfaces if no error. */
205 if (status == UX_SUCCESS)
206 {
207
208 /* We need to determine the maximum number of interfaces and endpoints declared in the device framework.
209 This mechanism requires that both framework behave the same way regarding the number of interfaces
210 and endpoints. */
211 device_framework = _ux_system_slave -> ux_system_slave_device_framework_full_speed;
212 device_framework_length = _ux_system_slave -> ux_system_slave_device_framework_length_full_speed;
213
214 /* Reset all values we are using during the scanning of the framework. */
215 local_interfaces_found = 0;
216 local_endpoints_found = 0;
217 endpoints_in_interface_found = 0;
218
219 /* Parse the device framework and locate interfaces and endpoint descriptor(s). */
220 while (device_framework_length != 0)
221 {
222
223 /* Get the length of this descriptor. */
224 descriptor_length = (ULONG) *device_framework;
225
226 /* And its type. */
227 descriptor_type = *(device_framework + 1);
228
229 /* Check if this is an endpoint descriptor. */
230 switch(descriptor_type)
231 {
232
233 case UX_INTERFACE_DESCRIPTOR_ITEM:
234
235 /* Check if this is alternate setting 0. If not, do not add another interface found.
236 If this is alternate setting 0, reset the endpoints count for this interface. */
237 if (*(device_framework + 3) == 0)
238 {
239
240 /* Add the cumulated number of endpoints in the previous interface. */
241 local_endpoints_found += endpoints_in_interface_found;
242
243 /* Read the number of endpoints for this alternate setting. */
244 endpoints_in_interface_found = (ULONG) *(device_framework + 4);
245
246 /* Increment the number of interfaces found in the current configuration. */
247 local_interfaces_found++;
248 }
249 else
250 {
251
252 /* Compare the number of endpoints found in this non 0 alternate setting. */
253 if (endpoints_in_interface_found < (ULONG) *(device_framework + 4))
254
255 /* Adjust the number of maximum endpoints in this interface. */
256 endpoints_in_interface_found = (ULONG) *(device_framework + 4);
257 }
258
259 /* Check and update max interface number. */
260 if (*(device_framework + 2) > max_interface_number)
261 max_interface_number = *(device_framework + 2);
262
263 break;
264
265 case UX_CONFIGURATION_DESCRIPTOR_ITEM:
266
267 /* Check if the number of interfaces found in this configuration is the maximum so far. */
268 if (local_interfaces_found > interfaces_found)
269
270 /* We need to adjust the number of maximum interfaces. */
271 interfaces_found = local_interfaces_found;
272
273 /* We have a new configuration. We need to reset the number of local interfaces. */
274 local_interfaces_found = 0;
275
276 /* Add the cumulated number of endpoints in the previous interface. */
277 local_endpoints_found += endpoints_in_interface_found;
278
279 /* Check if the number of endpoints found in the previous configuration is the maximum so far. */
280 if (local_endpoints_found > endpoints_found)
281
282 /* We need to adjust the number of maximum endpoints. */
283 endpoints_found = local_endpoints_found;
284
285 /* We have a new configuration. We need to reset the number of local endpoints. */
286 local_endpoints_found = 0;
287 endpoints_in_interface_found = 0;
288
289 break;
290
291 default:
292 break;
293 }
294
295 /* Adjust what is left of the device framework. */
296 device_framework_length -= descriptor_length;
297
298 /* Point to the next descriptor. */
299 device_framework += descriptor_length;
300 }
301
302 /* Add the cumulated number of endpoints in the previous interface. */
303 local_endpoints_found += endpoints_in_interface_found;
304
305 /* Check if the number of endpoints found in the previous interface is the maximum so far. */
306 if (local_endpoints_found > endpoints_found)
307
308 /* We need to adjust the number of maximum endpoints. */
309 endpoints_found = local_endpoints_found;
310
311
312 /* Check if the number of interfaces found in this configuration is the maximum so far. */
313 if (local_interfaces_found > interfaces_found)
314
315 /* We need to adjust the number of maximum interfaces. */
316 interfaces_found = local_interfaces_found;
317
318 /* We do a sanity check on the finding. At least there must be one interface but endpoints are
319 not necessary. */
320 if (interfaces_found == 0)
321 {
322
323 /* Error trap. */
324 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_INIT, UX_DESCRIPTOR_CORRUPTED);
325
326 /* If trace is enabled, insert this event into the trace buffer. */
327 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, device_framework, 0, 0, UX_TRACE_ERRORS, 0, 0)
328
329 status = UX_DESCRIPTOR_CORRUPTED;
330 }
331
332 /* We do a sanity check on the finding. Max interface number should not exceed limit. */
333 if (status == UX_SUCCESS &&
334 max_interface_number >= UX_MAX_SLAVE_INTERFACES)
335 {
336
337 /* Error trap. */
338 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_INIT, UX_MEMORY_INSUFFICIENT);
339
340 /* If trace is enabled, insert this event into the trace buffer. */
341 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device_framework, 0, 0, UX_TRACE_ERRORS, 0, 0)
342
343 status = UX_MEMORY_INSUFFICIENT;
344 }
345 }
346 #endif
347
348 /* Go on to allocate interfaces pool if no error. */
349 if (status == UX_SUCCESS)
350 {
351
352 /* Memorize both pool sizes. */
353 device -> ux_slave_device_interfaces_pool_number = interfaces_found;
354 device -> ux_slave_device_endpoints_pool_number = endpoints_found;
355
356 /* We assign a pool for the interfaces. */
357 interfaces_pool = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, interfaces_found, sizeof(UX_SLAVE_INTERFACE));
358 if (interfaces_pool == UX_NULL)
359 status = UX_MEMORY_INSUFFICIENT;
360 else
361
362 /* Save the interface pool address in the device container. */
363 device -> ux_slave_device_interfaces_pool = interfaces_pool;
364 }
365
366 /* Do we need an endpoint pool ? */
367 if (endpoints_found != 0 && status == UX_SUCCESS)
368 {
369
370 /* We assign a pool for the endpoints. */
371 endpoints_pool = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, endpoints_found, sizeof(UX_SLAVE_ENDPOINT));
372 if (endpoints_pool == UX_NULL)
373 status = UX_MEMORY_INSUFFICIENT;
374 else
375 {
376
377 /* Save the endpoint pool address in the device container. */
378 device -> ux_slave_device_endpoints_pool = endpoints_pool;
379
380 /* We need to assign a transfer buffer to each endpoint. Each endpoint is assigned the
381 maximum buffer size. We also assign the semaphore used by the endpoint to synchronize transfer
382 completion. */
383 while (endpoints_pool < (device -> ux_slave_device_endpoints_pool + endpoints_found))
384 {
385
386 /* Obtain some memory. */
387 endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
388 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
389
390 /* Ensure we could allocate memory. */
391 if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer == UX_NULL)
392 {
393 status = UX_MEMORY_INSUFFICIENT;
394 break;
395 }
396
397 /* Create the semaphore for the endpoint. */
398 status = _ux_device_semaphore_create(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore,
399 "ux_transfer_request_semaphore", 0);
400
401 /* Check completion status. */
402 if (status != UX_SUCCESS)
403 {
404 status = UX_SEMAPHORE_ERROR;
405 break;
406 }
407
408 /* Next endpoint. */
409 endpoints_pool++;
410 }
411 }
412 }
413 else
414 endpoints_pool = UX_NULL;
415
416 /* Return successful completion. */
417 if (status == UX_SUCCESS)
418 return(UX_SUCCESS);
419
420 /* Free resources when there is error. */
421
422 /* Free device -> ux_slave_device_endpoints_pool. */
423 if (endpoints_pool)
424 {
425
426 /* In error cases creating endpoint resources, endpoints_pool is endpoint that failed.
427 * Previously allocated things should be freed. */
428 while(endpoints_pool >= device -> ux_slave_device_endpoints_pool)
429 {
430
431 /* Delete ux_slave_transfer_request_semaphore. */
432 if (_ux_device_semaphore_created(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore))
433 _ux_device_semaphore_delete(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore);
434
435 /* Free ux_slave_transfer_request_data_pointer buffer. */
436 if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer)
437 _ux_utility_memory_free(endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer);
438
439 /* Move to previous endpoint. */
440 endpoints_pool --;
441 }
442
443 _ux_utility_memory_free(device -> ux_slave_device_endpoints_pool);
444 }
445
446 /* Free device -> ux_slave_device_interfaces_pool. */
447 if (device -> ux_slave_device_interfaces_pool)
448 _ux_utility_memory_free(device -> ux_slave_device_interfaces_pool);
449
450 /* Free device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer. */
451 if (device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer)
452 _ux_utility_memory_free(device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer);
453
454 /* Free _ux_system_slave -> ux_system_slave_class_array. */
455 _ux_utility_memory_free(_ux_system_slave -> ux_system_slave_class_array);
456
457 /* Return completion status. */
458 return(status);
459 }
460
461