GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_configuration_set.c Lines: 85 85 100.0 %
Date: 2024-12-12 17:16:36 Branches: 52 52 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** USBX Component                                                        */
16
/**                                                                       */
17
/**   Device Stack                                                        */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define UX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "ux_api.h"
28
#include "ux_device_stack.h"
29
30
31
/**************************************************************************/
32
/*                                                                        */
33
/*  FUNCTION                                               RELEASE        */
34
/*                                                                        */
35
/*    _ux_device_stack_configuration_set                  PORTABLE C      */
36
/*                                                           6.1.12       */
37
/*  AUTHOR                                                                */
38
/*                                                                        */
39
/*    Chaoqiong Xiao, Microsoft Corporation                               */
40
/*                                                                        */
41
/*  DESCRIPTION                                                           */
42
/*                                                                        */
43
/*    This function sets the configuration from the host and will enable  */
44
/*    the default alternate setting 0 for all the interfaces attached to  */
45
/*    this configuration.                                                 */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    endpoint                              Pointer to endpoint           */
50
/*    configuration_value                   Configuration selected        */
51
/*                                                                        */
52
/*  OUTPUT                                                                */
53
/*                                                                        */
54
/*    Completion Status                                                   */
55
/*                                                                        */
56
/*  CALLS                                                                 */
57
/*                                                                        */
58
/*    (ux_slave_class_entry_function)       Device class entry function   */
59
/*    (ux_slave_dcd_function)               DCD dispatch function         */
60
/*    _ux_device_stack_interface_delete     Delete interface              */
61
/*    _ux_device_stack_interface_set        Set interface                 */
62
/*    _ux_utility_descriptor_parse          Parse descriptor              */
63
/*                                                                        */
64
/*  CALLED BY                                                             */
65
/*                                                                        */
66
/*    Application                                                         */
67
/*    Device Stack                                                        */
68
/*                                                                        */
69
/*  RELEASE HISTORY                                                       */
70
/*                                                                        */
71
/*    DATE              NAME                      DESCRIPTION             */
72
/*                                                                        */
73
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
74
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
75
/*                                            optimized based on compile  */
76
/*                                            definitions,                */
77
/*                                            resulting in version 6.1    */
78
/*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
79
/*                                            fixed parameter/variable    */
80
/*                                            names conflict C++ keyword, */
81
/*                                            resulting in version 6.1.12 */
82
/*                                                                        */
83
/**************************************************************************/
84
930
UINT  _ux_device_stack_configuration_set(ULONG configuration_value)
85
{
86
87
UX_SLAVE_DCD                    *dcd;
88
UCHAR *                         device_framework;
89
ULONG                           device_framework_length;
90
ULONG                           descriptor_length;
91
UCHAR                           descriptor_type;
92
930
UX_CONFIGURATION_DESCRIPTOR     configuration_descriptor = { 0 };
93
UX_INTERFACE_DESCRIPTOR         interface_descriptor;
94
UX_SLAVE_INTERFACE              *interface_ptr;
95
#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
96
UX_SLAVE_INTERFACE              *next_interface;
97
#endif
98
UX_SLAVE_CLASS                  *class_inst;
99
930
UX_SLAVE_CLASS                  *current_class =  UX_NULL;
100
UX_SLAVE_CLASS_COMMAND          class_command;
101
UX_SLAVE_DEVICE                 *device;
102
ULONG                           iad_flag;
103
930
ULONG                           iad_first_interface =  0;
104
930
ULONG                           iad_number_interfaces =  0;
105
#if UX_MAX_SLAVE_CLASS_DRIVER > 1
106
ULONG                           class_index;
107
#endif
108
109
110
    /* If trace is enabled, insert this event into the trace buffer.  */
111
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_CONFIGURATION_SET, configuration_value, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
112
113
    /* Get the pointer to the DCD.  */
114
930
    dcd =  &_ux_system_slave -> ux_system_slave_dcd;
115
116
    /* Get the pointer to the device.  */
117
930
    device =  &_ux_system_slave -> ux_system_slave_device;
118
119
    /* Reset the IAD flag.  */
120
930
    iad_flag =  UX_FALSE;
121
122
    /* If the configuration value is already selected, keep it.  */
123
930
    if (device -> ux_slave_device_configuration_selected == configuration_value)
124
10
        return(UX_SUCCESS);
125
126
    /* We may have multiple configurations !, the index will tell us what
127
       configuration descriptor we need to return.  */
128
920
    device_framework = _ux_system_slave -> ux_system_slave_device_framework;
129
920
    device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
130
131
    /* Parse the device framework and locate a configuration descriptor.  */
132
2310
    while (device_framework_length != 0)
133
    {
134
        /* Get the length of the current descriptor.  */
135
2296
        descriptor_length =  (ULONG) *device_framework;
136
137
        /* And its type.  */
138
2296
        descriptor_type =  *(device_framework + 1);
139
140
        /* Check if this is a configuration descriptor.  */
141
2296
        if (descriptor_type == UX_CONFIGURATION_DESCRIPTOR_ITEM)
142
        {
143
            /* Parse the descriptor in something more readable.  */
144
941
            _ux_utility_descriptor_parse(device_framework,
145
                        _ux_system_configuration_descriptor_structure,
146
                        UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
147
                        (UCHAR *) &configuration_descriptor);
148
149
            /* Now we need to check the configuration value. It has
150
               to be the same as the one specified in the setup function.  */
151
941
            if (configuration_descriptor.bConfigurationValue == configuration_value)
152
                /* The configuration is found. */
153
906
                break;
154
        }
155
156
        /* Adjust what is left of the device framework.  */
157
1390
        device_framework_length -= descriptor_length;
158
        /* Point to the next descriptor.  */
159
1390
        device_framework += descriptor_length;
160
    }
161
162
    /* Configuration not found. */
163

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