GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_configuration_set.c Lines: 85 85 100.0 %
Date: 2026-03-06 18:57:10 Branches: 52 52 100.0 %

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
32
/**************************************************************************/
33
/*                                                                        */
34
/*  FUNCTION                                               RELEASE        */
35
/*                                                                        */
36
/*    _ux_device_stack_configuration_set                  PORTABLE C      */
37
/*                                                           6.1.12       */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    Chaoqiong Xiao, Microsoft Corporation                               */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    This function sets the configuration from the host and will enable  */
45
/*    the default alternate setting 0 for all the interfaces attached to  */
46
/*    this configuration.                                                 */
47
/*                                                                        */
48
/*  INPUT                                                                 */
49
/*                                                                        */
50
/*    endpoint                              Pointer to endpoint           */
51
/*    configuration_value                   Configuration selected        */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    Completion Status                                                   */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    (ux_slave_class_entry_function)       Device class entry function   */
60
/*    (ux_slave_dcd_function)               DCD dispatch function         */
61
/*    _ux_device_stack_interface_delete     Delete interface              */
62
/*    _ux_device_stack_interface_set        Set interface                 */
63
/*    _ux_utility_descriptor_parse          Parse descriptor              */
64
/*                                                                        */
65
/*  CALLED BY                                                             */
66
/*                                                                        */
67
/*    Application                                                         */
68
/*    Device Stack                                                        */
69
/*                                                                        */
70
/**************************************************************************/
71
931
UINT  _ux_device_stack_configuration_set(ULONG configuration_value)
72
{
73
74
UX_SLAVE_DCD                    *dcd;
75
UCHAR *                         device_framework;
76
ULONG                           device_framework_length;
77
ULONG                           descriptor_length;
78
UCHAR                           descriptor_type;
79
931
UX_CONFIGURATION_DESCRIPTOR     configuration_descriptor = { 0 };
80
UX_INTERFACE_DESCRIPTOR         interface_descriptor;
81
UX_SLAVE_INTERFACE              *interface_ptr;
82
#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
83
UX_SLAVE_INTERFACE              *next_interface;
84
#endif
85
UX_SLAVE_CLASS                  *class_inst;
86
931
UX_SLAVE_CLASS                  *current_class =  UX_NULL;
87
UX_SLAVE_CLASS_COMMAND          class_command;
88
UX_SLAVE_DEVICE                 *device;
89
ULONG                           iad_flag;
90
931
ULONG                           iad_first_interface =  0;
91
931
ULONG                           iad_number_interfaces =  0;
92
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
93
ULONG                           class_index;
94
#endif
95
96
97
    /* If trace is enabled, insert this event into the trace buffer.  */
98
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_CONFIGURATION_SET, configuration_value, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
99
100
    /* Get the pointer to the DCD.  */
101
931
    dcd =  &_ux_system_slave -> ux_system_slave_dcd;
102
103
    /* Get the pointer to the device.  */
104
931
    device =  &_ux_system_slave -> ux_system_slave_device;
105
106
    /* Reset the IAD flag.  */
107
931
    iad_flag =  UX_FALSE;
108
109
    /* If the configuration value is already selected, keep it.  */
110
931
    if (device -> ux_slave_device_configuration_selected == configuration_value)
111
10
        return(UX_SUCCESS);
112
113
    /* We may have multiple configurations !, the index will tell us what
114
       configuration descriptor we need to return.  */
115
921
    device_framework = _ux_system_slave -> ux_system_slave_device_framework;
116
921
    device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
117
118
    /* Parse the device framework and locate a configuration descriptor.  */
119
2312
    while (device_framework_length != 0)
120
    {
121
        /* Get the length of the current descriptor.  */
122
2298
        descriptor_length =  (ULONG) *device_framework;
123
124
        /* And its type.  */
125
2298
        descriptor_type =  *(device_framework + 1);
126
127
        /* Check if this is a configuration descriptor.  */
128
2298
        if (descriptor_type == UX_CONFIGURATION_DESCRIPTOR_ITEM)
129
        {
130
            /* Parse the descriptor in something more readable.  */
131
942
            _ux_utility_descriptor_parse(device_framework,
132
                        _ux_system_configuration_descriptor_structure,
133
                        UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
134
                        (UCHAR *) &configuration_descriptor);
135
136
            /* Now we need to check the configuration value. It has
137
               to be the same as the one specified in the setup function.  */
138
942
            if (configuration_descriptor.bConfigurationValue == configuration_value)
139
                /* The configuration is found. */
140
907
                break;
141
        }
142
143
        /* Adjust what is left of the device framework.  */
144
1391
        device_framework_length -= descriptor_length;
145
        /* Point to the next descriptor.  */
146
1391
        device_framework += descriptor_length;
147
    }
148
149
    /* Configuration not found. */
150

921
    if (device_framework_length == 0 && configuration_value != 0)
151
1
        return(UX_ERROR);
152
153
    /* We unmount the configuration if there is previous configuration selected. */
154
920
    if (device -> ux_slave_device_configuration_selected)
155
    {
156
157
        /* Get the pointer to the first interface.  */
158
20
        interface_ptr =  device -> ux_slave_device_first_interface;
159
160
#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
161
        /* Deactivate all the interfaces if any.  */
162
52
        while (interface_ptr != UX_NULL)
163
        {
164
#endif
165
            /* Build all the fields of the Class Command.  */
166
32
            class_command.ux_slave_class_command_request =   UX_SLAVE_CLASS_COMMAND_DEACTIVATE;
167
32
            class_command.ux_slave_class_command_interface =  (VOID *) interface_ptr;
168
169
            /* Get the pointer to the class container of this interface.  */
170
32
            class_inst =  interface_ptr -> ux_slave_interface_class;
171
172
            /* Store the class container. */
173
32
            class_command.ux_slave_class_command_class_ptr =  class_inst;
174
175
            /* If there is a class container for this instance, deactivate it.  */
176
32
            if (class_inst != UX_NULL)
177
178
                /* Call the class with the DEACTIVATE signal.  */
179
19
                class_inst -> ux_slave_class_entry_function(&class_command);
180
181
#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
182
            /* Get the next interface.  */
183
32
            next_interface =  interface_ptr -> ux_slave_interface_next_interface;
184
#endif
185
186
            /* Remove the interface and all endpoints associated with it.  */
187
32
            _ux_device_stack_interface_delete(interface_ptr);
188
189
#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
190
            /* Now we refresh the interface pointer.  */
191
32
            interface_ptr =  next_interface;
192
        }
193
#endif
194
195
    }
196
197
    /* No configuration is selected.  */
198
920
    device -> ux_slave_device_configuration_selected =  0;
199
200
    /* Mark the device as attached now. */
201
920
    device -> ux_slave_device_state =  UX_DEVICE_ATTACHED;
202
203
    /* The DCD needs to update the device state too.  */
204
920
    dcd -> ux_slave_dcd_function(dcd, UX_DCD_CHANGE_STATE, (VOID *) UX_DEVICE_ATTACHED);
205
206
    /* If the host tries to unconfigure, we are done. */
207
920
    if (configuration_value == 0)
208
13
        return(UX_SUCCESS);
209
210
    /* Memorize the configuration selected.  */
211
907
    device -> ux_slave_device_configuration_selected =  configuration_value;
212
213
    /* We have found the configuration value requested by the host.
214
       Create the configuration descriptor and attach it to the device.  */
215
907
    _ux_utility_descriptor_parse(device_framework,
216
                _ux_system_configuration_descriptor_structure,
217
                UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
218
907
                (UCHAR *) &device -> ux_slave_device_configuration_descriptor);
219
220
    /* Configuration character D6 is for Self-powered */
221
907
    _ux_system_slave -> ux_system_slave_power_state = (configuration_descriptor.bmAttributes & 0x40) ? UX_DEVICE_SELF_POWERED : UX_DEVICE_BUS_POWERED;
222
223
    /* Configuration character D5 is for Remote Wakeup */
224
907
    _ux_system_slave -> ux_system_slave_remote_wakeup_capability = (configuration_descriptor.bmAttributes & 0x20) ? UX_TRUE : UX_FALSE;
225
226
    /* Search only in current configuration */
227
907
    device_framework_length =  configuration_descriptor.wTotalLength;
228
229
    /*  We need to scan all the interface descriptors following this
230
        configuration descriptor and enable all endpoints associated
231
        with the default alternate setting of each interface.  */
232
8051
    while (device_framework_length != 0)
233
    {
234
235
        /* Get the length of the current descriptor.  */
236
7144
        descriptor_length =  (ULONG) *device_framework;
237
238
        /* And its type.  */
239
7144
        descriptor_type =  *(device_framework + 1);
240
241
        /* Check if this is an interface association descriptor.  */
242
7144
        if(descriptor_type == UX_INTERFACE_ASSOCIATION_DESCRIPTOR_ITEM)
243
        {
244
245
            /* Set the IAD flag.  */
246
231
            iad_flag = UX_TRUE;
247
248
            /* Get the first interface we have in the IAD. */
249
231
            iad_first_interface = (ULONG)  *(device_framework + 2);
250
251
            /* Get the number of interfaces we have in the IAD. */
252
231
            iad_number_interfaces = (ULONG)  *(device_framework + 3);
253
        }
254
255
        /* Check if this is an interface descriptor.  */
256
7144
        if(descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM)
257
        {
258
259
            /* Parse the descriptor in something more readable.  */
260
1821
            _ux_utility_descriptor_parse(device_framework,
261
                        _ux_system_interface_descriptor_structure,
262
                        UX_INTERFACE_DESCRIPTOR_ENTRIES,
263
                        (UCHAR *) &interface_descriptor);
264
265
            /* If the alternate setting is 0 for this interface, we need to
266
               memorize its class association and start it.  */
267
1821
            if (interface_descriptor.bAlternateSetting == 0)
268
            {
269
270
                /* Are we in a IAD scenario ? */
271
1544
                if (iad_flag == UX_TRUE)
272
                {
273
274
                    /* Check if this is the first interface from the IAD. In this case,
275
                       we need to match a class to this interface.  */
276
471
                    if (interface_descriptor.bInterfaceNumber == iad_first_interface)
277
                    {
278
279
                        /* First interface. Scan the list of classes to find a match.  */
280
231
                        class_inst =  _ux_system_slave -> ux_system_slave_class_array;
281
282
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
283
                        /* Parse all the class drivers.  */
284
265
                        for (class_index = 0; class_index < _ux_system_slave -> ux_system_slave_max_class; class_index++)
285
                        {
286
#endif
287
288
                            /* Check if this class driver is used.  */
289
255
                            if (class_inst -> ux_slave_class_status == UX_USED)
290
                            {
291
292
                                /* Check if this is the same interface for the same configuration. */
293
248
                                if ((interface_descriptor.bInterfaceNumber == class_inst -> ux_slave_class_interface_number) &&
294
226
                                    (configuration_value == class_inst -> ux_slave_class_configuration_number))
295
                                {
296
297
                                    /* Memorize the class in the class/interface array.  */
298
221
                                    _ux_system_slave -> ux_system_slave_interface_class_array[interface_descriptor.bInterfaceNumber] = class_inst;
299
300
                                    /* And again as the current class.  */
301
221
                                    current_class = class_inst;
302
303
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
304
                                    /* We are done here.  */
305
221
                                    break;
306
#endif
307
                                }
308
                            }
309
310
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
311
                            /* Move to the next registered class.  */
312
34
                            class_inst ++;
313
                        }
314
#endif
315
                    }
316
                    else
317
318
                        /* Memorize the class in the class/interface array.  We use the current class. */
319
240
                        _ux_system_slave -> ux_system_slave_interface_class_array[interface_descriptor.bInterfaceNumber] = current_class;
320
321
                    /* Decrement the number of interfaces found in the same IAD.  */
322
471
                    iad_number_interfaces--;
323
324
                    /* If none are left, get out of the IAD state machine.  */
325
471
                    if (iad_number_interfaces == 0)
326
327
                        /* We have exhausted the interfaces within the IAD.  */
328
231
                        iad_flag = UX_FALSE;
329
330
                }
331
                else
332
                {
333
334
                    /* First interface. Scan the list of classes to find a match.  */
335
1073
                    class_inst =  _ux_system_slave -> ux_system_slave_class_array;
336
337
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
338
                    /* Parse all the class drivers.  */
339
1742
                    for (class_index = 0; class_index < _ux_system_slave -> ux_system_slave_max_class; class_index++)
340
                    {
341
#endif
342
343
                        /* Check if this class driver is used.  */
344
1687
                        if (class_inst -> ux_slave_class_status == UX_USED)
345
                        {
346
347
                            /* Check if this is the same interface for the same configuration. */
348
1577
                            if ((interface_descriptor.bInterfaceNumber == class_inst -> ux_slave_class_interface_number) &&
349
1022
                                    (configuration_value == class_inst -> ux_slave_class_configuration_number))
350
                            {
351
352
                                /* Memorize the class in the class/interface array.  */
353
1018
                                _ux_system_slave -> ux_system_slave_interface_class_array[interface_descriptor.bInterfaceNumber] = class_inst;
354
355
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
356
                                /* We are done here.  */
357
1018
                                break;
358
#endif
359
                            }
360
                        }
361
362
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
363
                        /* Move to the next registered class.  */
364
669
                        class_inst ++;
365
                    }
366
#endif
367
                }
368
369
                /* Set the interface.  */
370
1544
                _ux_device_stack_interface_set(device_framework, device_framework_length, 0);
371
            }
372
        }
373
374
        /* Adjust what is left of the device framework.  */
375
7144
        device_framework_length -=  descriptor_length;
376
377
        /* Point to the next descriptor.  */
378
7144
        device_framework +=  descriptor_length;
379
    }
380
381
    /* Mark the device as configured now. */
382
907
    device -> ux_slave_device_state =  UX_DEVICE_CONFIGURED;
383
384
    /* The DCD needs to update the device state too.  */
385
907
    dcd -> ux_slave_dcd_function(dcd, UX_DCD_CHANGE_STATE, (VOID *) UX_DEVICE_CONFIGURED);
386
387
    /* Configuration mounted. */
388
907
    return(UX_SUCCESS);
389
}
390