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