GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_initialize.c Lines: 110 117 94.0 %
Date: 2026-03-06 18:57:10 Branches: 61 77 79.2 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
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
/**************************************************************************/
96
378
UINT  _ux_device_stack_initialize(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed,
97
                                  UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed,
98
                                  UCHAR * string_framework, ULONG string_framework_length,
99
                                  UCHAR * language_id_framework, ULONG language_id_framework_length,
100
                                  UINT (*ux_system_slave_change_function)(ULONG))
101
{
102
UX_SLAVE_DEVICE                 *device;
103
UX_SLAVE_ENDPOINT               *endpoints_pool;
104
UX_SLAVE_INTERFACE              *interfaces_pool;
105
UX_SLAVE_TRANSFER               *transfer_request;
106
UINT                            status;
107
ULONG                           interfaces_found;
108
ULONG                           endpoints_found;
109
#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE)
110
ULONG                           max_interface_number;
111
ULONG                           local_interfaces_found;
112
ULONG                           local_endpoints_found;
113
ULONG                           endpoints_in_interface_found;
114
UCHAR                           *device_framework;
115
ULONG                           device_framework_length;
116
UCHAR                           descriptor_type;
117
ULONG                           descriptor_length;
118
#endif
119
UCHAR                           *memory;
120
121
    /* If trace is enabled, insert this event into the trace buffer.  */
122
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_INITIALIZE, 0, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
123
124
    /* Get the pointer to the device. */
125
378
    device =  &_ux_system_slave -> ux_system_slave_device;
126
127
    /* Store the high speed device framework address and length in the project structure.  */
128
378
    _ux_system_slave -> ux_system_slave_device_framework_high_speed =             device_framework_high_speed;
129
378
    _ux_system_slave -> ux_system_slave_device_framework_length_high_speed =      device_framework_length_high_speed;
130
131
    /* Store the string framework address and length in the project structure.  */
132
378
    _ux_system_slave -> ux_system_slave_device_framework_full_speed =             device_framework_full_speed;
133
378
    _ux_system_slave -> ux_system_slave_device_framework_length_full_speed =      device_framework_length_full_speed;
134
135
    /* Store the string framework address and length in the project structure.  */
136
378
    _ux_system_slave -> ux_system_slave_string_framework =                         string_framework;
137
378
    _ux_system_slave -> ux_system_slave_string_framework_length =                  string_framework_length;
138
139
    /* Store the language ID list in the project structure.  */
140
378
    _ux_system_slave -> ux_system_slave_language_id_framework =                 language_id_framework;
141
378
    _ux_system_slave -> ux_system_slave_language_id_framework_length =          language_id_framework_length;
142
143
    /* Store the max number of slave class drivers in the project structure.  */
144
378
    UX_SYSTEM_DEVICE_MAX_CLASS_SET(UX_MAX_SLAVE_CLASS_DRIVER);
145
146
    /* Store the device state change function callback.  */
147
378
    _ux_system_slave -> ux_system_slave_change_function =  ux_system_slave_change_function;
148
149
    /* Allocate memory for the classes.
150
     * sizeof(UX_SLAVE_CLASS) * UX_MAX_SLAVE_CLASS_DRIVER) overflow is checked
151
     * outside of the function.
152
     */
153
378
    memory =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS) * UX_MAX_SLAVE_CLASS_DRIVER);
154
378
    if (memory == UX_NULL)
155
1
        return(UX_MEMORY_INSUFFICIENT);
156
157
    /* Save this memory allocation in the USBX project.  */
158
377
    _ux_system_slave -> ux_system_slave_class_array =  (UX_SLAVE_CLASS *) ((void *) memory);
159
160
    /* Allocate some memory for the Control Endpoint.  First get the address of the transfer request for the
161
       control endpoint. */
162
377
    transfer_request =  &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
163
164
    /* Acquire a buffer for the size of the endpoint.  */
165
377
    transfer_request -> ux_slave_transfer_request_data_pointer =
166
377
          _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH);
167
168
    /* Ensure we have enough memory.  */
169
377
    if (transfer_request -> ux_slave_transfer_request_data_pointer == UX_NULL)
170
1
        status = UX_MEMORY_INSUFFICIENT;
171
    else
172
376
        status = UX_SUCCESS;
173
174
#if defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE)
175
176
    /* No scan, just assign predefined value.  */
177
    interfaces_found = UX_MAX_SLAVE_INTERFACES;
178
    endpoints_found = UX_MAX_DEVICE_ENDPOINTS;
179
#else
180
181
    /* Reset all values we are using during the scanning of the framework.  */
182
377
    interfaces_found                   =  0;
183
377
    endpoints_found                    =  0;
184
377
    max_interface_number               =  0;
185
186
    /* Go on to scan interfaces if no error.  */
187
377
    if (status == UX_SUCCESS)
188
    {
189
190
        /* We need to determine the maximum number of interfaces and endpoints declared in the device framework.
191
        This mechanism requires that both framework behave the same way regarding the number of interfaces
192
        and endpoints.  */
193
376
        device_framework        =  _ux_system_slave -> ux_system_slave_device_framework_full_speed;
194
376
        device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length_full_speed;
195
196
        /* Reset all values we are using during the scanning of the framework.  */
197
376
        local_interfaces_found             =  0;
198
376
        local_endpoints_found              =  0;
199
376
        endpoints_in_interface_found       =  0;
200
201
        /* Parse the device framework and locate interfaces and endpoint descriptor(s).  */
202
3474
        while (device_framework_length != 0)
203
        {
204
205
            /* Get the length of this descriptor.  */
206
3098
            descriptor_length =  (ULONG) *device_framework;
207
208
            /* And its type.  */
209
3098
            descriptor_type =  *(device_framework + 1);
210
211
            /* Check if this is an endpoint descriptor.  */
212
3098
            switch(descriptor_type)
213
            {
214
215
662
            case UX_INTERFACE_DESCRIPTOR_ITEM:
216
217
                /* Check if this is alternate setting 0. If not, do not add another interface found.
218
                If this is alternate setting 0, reset the endpoints count for this interface.  */
219
662
                if (*(device_framework + 3) == 0)
220
                {
221
222
                    /* Add the cumulated number of endpoints in the previous interface.  */
223
560
                    local_endpoints_found += endpoints_in_interface_found;
224
225
                    /* Read the number of endpoints for this alternate setting.  */
226
560
                    endpoints_in_interface_found = (ULONG) *(device_framework + 4);
227
228
                    /* Increment the number of interfaces found in the current configuration.  */
229
560
                    local_interfaces_found++;
230
                }
231
                else
232
                {
233
234
                    /* Compare the number of endpoints found in this non 0 alternate setting.  */
235
102
                    if (endpoints_in_interface_found < (ULONG) *(device_framework + 4))
236
237
                        /* Adjust the number of maximum endpoints in this interface.  */
238
94
                        endpoints_in_interface_found = (ULONG) *(device_framework + 4);
239
                }
240
241
                /* Check and update max interface number.  */
242
662
                if (*(device_framework + 2) > max_interface_number)
243
294
                    max_interface_number = *(device_framework + 2);
244
245
662
                break;
246
247
389
            case UX_CONFIGURATION_DESCRIPTOR_ITEM:
248
249
                /* Check if the number of interfaces found in this configuration is the maximum so far. */
250
389
                if (local_interfaces_found > interfaces_found)
251
252
                    /* We need to adjust the number of maximum interfaces.  */
253
8
                    interfaces_found =  local_interfaces_found;
254
255
                /* We have a new configuration. We need to reset the number of local interfaces. */
256
389
                local_interfaces_found =  0;
257
258
                /* Add the cumulated number of endpoints in the previous interface.  */
259
389
                local_endpoints_found += endpoints_in_interface_found;
260
261
                /* Check if the number of endpoints found in the previous configuration is the maximum so far. */
262
389
                if (local_endpoints_found > endpoints_found)
263
264
                    /* We need to adjust the number of maximum endpoints.  */
265
11
                    endpoints_found =  local_endpoints_found;
266
267
                /* We have a new configuration. We need to reset the number of local endpoints. */
268
389
                local_endpoints_found         =  0;
269
389
                endpoints_in_interface_found  =  0;
270
271
389
                break;
272
273
2047
            default:
274
2047
                break;
275
            }
276
277
            /* Adjust what is left of the device framework.  */
278
3098
            device_framework_length -=  descriptor_length;
279
280
            /* Point to the next descriptor.  */
281
3098
            device_framework +=  descriptor_length;
282
        }
283
284
        /* Add the cumulated number of endpoints in the previous interface.  */
285
376
        local_endpoints_found += endpoints_in_interface_found;
286
287
        /* Check if the number of endpoints found in the previous interface is the maximum so far. */
288
376
        if (local_endpoints_found > endpoints_found)
289
290
            /* We need to adjust the number of maximum endpoints.  */
291
364
            endpoints_found =  local_endpoints_found;
292
293
294
        /* Check if the number of interfaces found in this configuration is the maximum so far. */
295
376
        if (local_interfaces_found > interfaces_found)
296
297
            /* We need to adjust the number of maximum interfaces.  */
298
369
            interfaces_found =  local_interfaces_found;
299
300
        /* We do a sanity check on the finding. At least there must be one interface but endpoints are
301
        not necessary.  */
302
376
        if (interfaces_found == 0)
303
        {
304
305
            /* Error trap. */
306
1
            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_INIT, UX_DESCRIPTOR_CORRUPTED);
307
308
            /* If trace is enabled, insert this event into the trace buffer.  */
309
            UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, device_framework, 0, 0, UX_TRACE_ERRORS, 0, 0)
310
311
1
            status = UX_DESCRIPTOR_CORRUPTED;
312
        }
313
314
        /* We do a sanity check on the finding. Max interface number should not exceed limit.  */
315

376
        if (status == UX_SUCCESS &&
316
            max_interface_number >= UX_MAX_SLAVE_INTERFACES)
317
        {
318
319
            /* Error trap. */
320
1
            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_INIT, UX_MEMORY_INSUFFICIENT);
321
322
            /* If trace is enabled, insert this event into the trace buffer.  */
323
            UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device_framework, 0, 0, UX_TRACE_ERRORS, 0, 0)
324
325
1
            status = UX_MEMORY_INSUFFICIENT;
326
        }
327
    }
328
#endif
329
330
    /* Go on to allocate interfaces pool if no error.  */
331
377
    if (status == UX_SUCCESS)
332
    {
333
334
        /* Memorize both pool sizes.  */
335
374
        device -> ux_slave_device_interfaces_pool_number = interfaces_found;
336
374
        device -> ux_slave_device_endpoints_pool_number  = endpoints_found;
337
338
        /* We assign a pool for the interfaces.  */
339
374
        interfaces_pool =  _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, interfaces_found, sizeof(UX_SLAVE_INTERFACE));
340
374
        if (interfaces_pool == UX_NULL)
341
1
            status = UX_MEMORY_INSUFFICIENT;
342
        else
343
344
            /* Save the interface pool address in the device container.  */
345
373
            device -> ux_slave_device_interfaces_pool =  interfaces_pool;
346
    }
347
348
    /* Do we need an endpoint pool ?  */
349

377
    if (endpoints_found != 0 && status == UX_SUCCESS)
350
    {
351
352
        /* We assign a pool for the endpoints.  */
353
366
        endpoints_pool =  _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, endpoints_found, sizeof(UX_SLAVE_ENDPOINT));
354
366
        if (endpoints_pool == UX_NULL)
355
1
            status = UX_MEMORY_INSUFFICIENT;
356
        else
357
        {
358
359
            /* Save the endpoint pool address in the device container.  */
360
365
            device -> ux_slave_device_endpoints_pool =  endpoints_pool;
361
362
            /* We need to assign a transfer buffer to each endpoint. Each endpoint is assigned the
363
            maximum buffer size.  We also assign the semaphore used by the endpoint to synchronize transfer
364
            completion. */
365
1124
            while (endpoints_pool < (device -> ux_slave_device_endpoints_pool + endpoints_found))
366
            {
367
368
#if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 0
369
370
                /* Obtain some memory.  */
371
765
                endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
372
765
                                _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
373
374
                /* Ensure we could allocate memory.  */
375
765
                if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer == UX_NULL)
376
                {
377
3
                    status = UX_MEMORY_INSUFFICIENT;
378
3
                    break;
379
                }
380
#endif
381
382
                /* Create the semaphore for the endpoint.  */
383
762
                status =  _ux_device_semaphore_create(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore,
384
                                                    "ux_transfer_request_semaphore", 0);
385
386
                /* Check completion status.  */
387
762
                if (status != UX_SUCCESS)
388
                {
389
3
                    status = UX_SEMAPHORE_ERROR;
390
3
                    break;
391
                }
392
393
                /* Next endpoint.  */
394
759
                endpoints_pool++;
395
            }
396
        }
397
    }
398
    else
399
11
        endpoints_pool = UX_NULL;
400
401
    /* Return successful completion.  */
402
377
    if (status == UX_SUCCESS)
403
366
        return(UX_SUCCESS);
404
405
    /* Free resources when there is error.  */
406
407
    /* Free device -> ux_slave_device_endpoints_pool.  */
408
11
    if (endpoints_pool)
409
    {
410
411
        /* In error cases creating endpoint resources, endpoints_pool is endpoint that failed.
412
         * Previously allocated things should be freed.  */
413
18
        while(endpoints_pool >= device -> ux_slave_device_endpoints_pool)
414
        {
415
416
            /* Delete ux_slave_transfer_request_semaphore.  */
417
12
            if (_ux_device_semaphore_created(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore))
418
6
                _ux_device_semaphore_delete(&endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_semaphore);
419
420
#if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 0
421
422
            /* Free ux_slave_transfer_request_data_pointer buffer.  */
423
12
            if (endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer)
424
9
                _ux_utility_memory_free(endpoints_pool -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer);
425
#endif
426
427
            /* Move to previous endpoint.  */
428
12
            endpoints_pool --;
429
        }
430
431
6
        _ux_utility_memory_free(device -> ux_slave_device_endpoints_pool);
432
    }
433
434
    /* Free device -> ux_slave_device_interfaces_pool.  */
435
11
    if (device -> ux_slave_device_interfaces_pool)
436
9
        _ux_utility_memory_free(device -> ux_slave_device_interfaces_pool);
437
438
    /* Free device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer.  */
439
11
    if (device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer)
440
10
        _ux_utility_memory_free(device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer);
441
442
    /* Free _ux_system_slave -> ux_system_slave_class_array.  */
443
11
    _ux_utility_memory_free(_ux_system_slave -> ux_system_slave_class_array);
444
445
    /* Return completion status.  */
446
11
    return(status);
447
}
448
449
450
/**************************************************************************/
451
/*                                                                        */
452
/*  FUNCTION                                               RELEASE        */
453
/*                                                                        */
454
/*    _uxe_device_stack_initialize                        PORTABLE C      */
455
/*                                                           6.3.0        */
456
/*  AUTHOR                                                                */
457
/*                                                                        */
458
/*    Chaoqiong Xiao, Microsoft Corporation                               */
459
/*                                                                        */
460
/*  DESCRIPTION                                                           */
461
/*                                                                        */
462
/*    This function checks errors in device stack initialization          */
463
/*    function call.                                                      */
464
/*                                                                        */
465
/*  INPUT                                                                 */
466
/*                                                                        */
467
/*    class_name                            Name of class                 */
468
/*    class_function_entry                  Class entry function          */
469
/*                                                                        */
470
/*  OUTPUT                                                                */
471
/*                                                                        */
472
/*    None                                                                */
473
/*                                                                        */
474
/*  CALLS                                                                 */
475
/*                                                                        */
476
/*    _ux_device_stack_initialize           Device Stack Initialize       */
477
/*                                                                        */
478
/*  CALLED BY                                                             */
479
/*                                                                        */
480
/*    Application                                                         */
481
/*                                                                        */
482
/**************************************************************************/
483
UINT  _uxe_device_stack_initialize(UCHAR * device_framework_high_speed, ULONG device_framework_length_high_speed,
484
                                  UCHAR * device_framework_full_speed, ULONG device_framework_length_full_speed,
485
                                  UCHAR * string_framework, ULONG string_framework_length,
486
                                  UCHAR * language_id_framework, ULONG language_id_framework_length,
487
                                  UINT (*ux_system_slave_change_function)(ULONG))
488
{
489
490
    /* Sanity checks.  */
491
    if (((device_framework_high_speed == UX_NULL) && (device_framework_length_high_speed != 0)) ||
492
        (device_framework_full_speed == UX_NULL) || (device_framework_length_full_speed == 0) ||
493
        ((string_framework == UX_NULL) && (string_framework_length != 0)) ||
494
        (language_id_framework == UX_NULL) || (language_id_framework_length == 0))
495
        return(UX_INVALID_PARAMETER);
496
497
    /* Invoke stack initialize function.  */
498
    return(_ux_device_stack_initialize(device_framework_high_speed, device_framework_length_high_speed,
499
                                       device_framework_full_speed, device_framework_length_full_speed,
500
                                       string_framework, string_framework_length,
501
                                       language_id_framework, language_id_framework_length,
502
                                       ux_system_slave_change_function));
503
}