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