GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_alternate_setting_set.c Lines: 111 111 100.0 %
Date: 2026-03-06 18:57:10 Branches: 53 53 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_alternate_setting_set              PORTABLE C      */
37
/*                                                           6.1.12       */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    Chaoqiong Xiao, Microsoft Corporation                               */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    This function sets the alternate setting for a specific interface.  */
45
/*    The previous interface is unmounted and all the endpoints           */
46
/*    associated with the alternate setting are mounted.                  */
47
/*                                                                        */
48
/*  INPUT                                                                 */
49
/*                                                                        */
50
/*    endpoint                              Pointer to endpoint           */
51
/*    interface_value                       Interface value               */
52
/*    alternate_setting_value               Alternate setting value       */
53
/*                                                                        */
54
/*  OUTPUT                                                                */
55
/*                                                                        */
56
/*    Completion Status                                                   */
57
/*                                                                        */
58
/*  CALLS                                                                 */
59
/*                                                                        */
60
/*    (ux_slave_dcd_function)               DCD dispatch function         */
61
/*    _ux_utility_descriptor_parse          Parse descriptor              */
62
/*    _ux_device_stack_transfer_all_request_abort                         */
63
/*                                          Abort transfer                */
64
/*    _ux_utility_memory_copy               Copy memory                   */
65
/*                                                                        */
66
/*  CALLED BY                                                             */
67
/*                                                                        */
68
/*    Application                                                         */
69
/*    Device Stack                                                        */
70
/*                                                                        */
71
/**************************************************************************/
72
172
UINT  _ux_device_stack_alternate_setting_set(ULONG interface_value, ULONG alternate_setting_value)
73
{
74
75
UX_SLAVE_DEVICE                 *device;
76
UX_SLAVE_INTERFACE              *interface_ptr;
77
#if !defined(UX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE)
78
UX_SLAVE_DCD                    *dcd;
79
UX_SLAVE_TRANSFER               *transfer_request;
80
UCHAR                           *device_framework;
81
ULONG                           device_framework_length;
82
ULONG                           descriptor_length;
83
UCHAR                           descriptor_type;
84
UX_CONFIGURATION_DESCRIPTOR     configuration_descriptor;
85
UX_INTERFACE_DESCRIPTOR         interface_descriptor;
86
UX_SLAVE_ENDPOINT               *endpoint;
87
UX_SLAVE_ENDPOINT               *next_endpoint;
88
UX_SLAVE_ENDPOINT               *endpoint_link;
89
ULONG                            endpoints_pool_number;
90
UX_SLAVE_CLASS_COMMAND          class_command;
91
UX_SLAVE_CLASS                  *class_ptr;
92
UINT                            status;
93
ULONG                           max_transfer_length, n_trans;
94
#endif
95
96
    /* If trace is enabled, insert this event into the trace buffer.  */
97
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_ALTERNATE_SETTING_SET, interface_value, alternate_setting_value, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
98
99
    /* Get the pointer to the device. */
100
172
    device =  &_ux_system_slave -> ux_system_slave_device;
101
102
    /* Protocol error must be reported when it's unconfigured */
103
172
    if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
104
1
        return(UX_FUNCTION_NOT_SUPPORTED);
105
106
    /* Find the current interface.  */
107
171
    interface_ptr =  device -> ux_slave_device_first_interface;
108
109
#if !defined(UX_DEVICE_INITIALIZE_FRAMEWORK_SCAN_DISABLE) || UX_MAX_DEVICE_INTERFACES > 1
110
    /* Scan all interfaces if any. */
111
335
    while (interface_ptr != UX_NULL)
112
    {
113
114
334
        if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceNumber == interface_value)
115
170
            break;
116
        else
117
164
            interface_ptr =  interface_ptr -> ux_slave_interface_next_interface;
118
    }
119
#else
120
    if (interface_ptr -> ux_slave_interface_descriptor.bInterfaceNumber != interface_value)
121
        interface_ptr = UX_NULL;
122
#endif
123
124
    /* We must have found the interface pointer for the interface value
125
       requested by the caller.  */
126
171
    if (interface_ptr == UX_NULL)
127
    {
128
129
        /* Error trap. */
130
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_INTERFACE_HANDLE_UNKNOWN);
131
132
        /* If trace is enabled, insert this event into the trace buffer.  */
133
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_INTERFACE_HANDLE_UNKNOWN, interface_ptr, 0, 0, UX_TRACE_ERRORS, 0, 0)
134
135
1
        return(UX_INTERFACE_HANDLE_UNKNOWN);
136
    }
137
138
    /* If the host is requesting a change of alternate setting to the current one,
139
       we do not need to do any work.  */
140
170
    if (interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting == alternate_setting_value)
141
3
        return(UX_SUCCESS);
142
143
#if defined(UX_DEVICE_ALTERNATE_SETTING_SUPPORT_DISABLE)
144
145
    /* If alternate setting is disabled, do error trap.  */
146
    _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
147
148
    /* If trace is enabled, insert this event into the trace buffer.  */
149
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, interface_ptr, 0, 0, UX_TRACE_ERRORS, 0, 0)
150
151
    return(UX_FUNCTION_NOT_SUPPORTED);
152
#else
153
154
    /* Get the pointer to the DCD. */
155
167
    dcd =  &_ux_system_slave->ux_system_slave_dcd;
156
157
    /* We may have multiple configurations!  */
158
167
    device_framework =  _ux_system_slave -> ux_system_slave_device_framework;
159
167
    device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
160
161
    /* Parse the device framework and locate a configuration descriptor. */
162
410
    while (device_framework_length != 0)
163
    {
164
165
        /* Get the length of the current descriptor.  */
166
409
        descriptor_length =  (ULONG) *device_framework;
167
168
        /* And its length.  */
169
409
        descriptor_type =*  (device_framework + 1);
170
171
        /* Check if this is a configuration descriptor. */
172
409
        if (descriptor_type == UX_CONFIGURATION_DESCRIPTOR_ITEM)
173
        {
174
175
            /* Parse the descriptor in something more readable. */
176
170
            _ux_utility_descriptor_parse(device_framework,
177
                        _ux_system_configuration_descriptor_structure,
178
                        UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
179
                        (UCHAR *) &configuration_descriptor);
180
181
            /* Now we need to check the configuration value.  */
182
170
            if (configuration_descriptor.bConfigurationValue == device -> ux_slave_device_configuration_selected)
183
            {
184
185
                /* Limit the search in current configuration descriptor. */
186
166
                device_framework_length = configuration_descriptor.wTotalLength;
187
188
                /* We have found the configuration value that was selected by the host
189
                   We need to scan all the interface descriptors following this
190
                   configuration descriptor and locate the interface for which the alternate
191
                   setting must be changed. */
192
1585
                while (device_framework_length != 0)
193
                {
194
195
                    /* Get the length of the current descriptor.  */
196
1581
                    descriptor_length =  (ULONG) *device_framework;
197
198
                    /* And its type.  */
199
1581
                    descriptor_type = *(device_framework + 1);
200
201
                    /* Check if this is an interface descriptor. */
202
1581
                    if (descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM)
203
                    {
204
205
                        /* Parse the descriptor in something more readable. */
206
489
                        _ux_utility_descriptor_parse(device_framework,
207
                                    _ux_system_interface_descriptor_structure,
208
                                    UX_INTERFACE_DESCRIPTOR_ENTRIES,
209
                                    (UCHAR *) &interface_descriptor);
210
211
                        /* Check if this is the interface we are searching. */
212
489
                        if (interface_descriptor.bInterfaceNumber == interface_value &&
213
315
                            interface_descriptor.bAlternateSetting == alternate_setting_value)
214
                        {
215
216
                            /* We have found the right interface and alternate setting. Before
217
                               we mount all the endpoints for this interface, we need to
218
                               unmount the endpoints associated with the previous alternate setting.  */
219
162
                            endpoint =  interface_ptr -> ux_slave_interface_first_endpoint;
220
195
                            while (endpoint != UX_NULL)
221
                            {
222
223
                                /* Abort any pending transfer.  */
224
33
                                _ux_device_stack_transfer_all_request_abort(endpoint, UX_TRANSFER_BUS_RESET);
225
226
                                /* The device controller must be called to destroy the endpoint.  */
227
33
                                dcd -> ux_slave_dcd_function(dcd, UX_DCD_DESTROY_ENDPOINT, (VOID *) endpoint);
228
229
                                /* Get the next endpoint.  */
230
33
                                next_endpoint =  endpoint -> ux_slave_endpoint_next_endpoint;
231
232
                                /* Free the endpoint.  */
233
33
                                endpoint -> ux_slave_endpoint_status =  UX_UNUSED;
234
235
                                /* Make sure the endpoint instance is now cleaned up.  */
236
33
                                endpoint -> ux_slave_endpoint_state =  0;
237
33
                                endpoint -> ux_slave_endpoint_next_endpoint =  UX_NULL;
238
33
                                endpoint -> ux_slave_endpoint_interface =  UX_NULL;
239
33
                                endpoint -> ux_slave_endpoint_device =  UX_NULL;
240
241
                                /* Now we refresh the endpoint pointer.  */
242
33
                                endpoint =  next_endpoint;
243
                            }
244
245
                            /* Now clear the interface endpoint entry.  */
246
162
                            interface_ptr -> ux_slave_interface_first_endpoint = UX_NULL;
247
248
                            /* Point beyond the interface descriptor.  */
249
162
                            device_framework_length -=  (ULONG) *device_framework;
250
162
                            device_framework +=  (ULONG) *device_framework;
251
252
                            /* Parse the device framework and locate endpoint descriptor(s).  */
253
533
                            while (device_framework_length != 0)
254
                            {
255
256
                                /* Get the length of the current descriptor.  */
257
373
                                descriptor_length =  (ULONG) *device_framework;
258
259
                                /* And its type.  */
260
373
                                descriptor_type =  *(device_framework + 1);
261
262
                                /* Check if this is an endpoint descriptor.  */
263
373
                                switch(descriptor_type)
264
                                {
265
266
255
                                case UX_ENDPOINT_DESCRIPTOR_ITEM:
267
268
                                    /* Find a free endpoint in the pool and hook it to the
269
                                       existing interface after it's created by DCD.  */
270
255
                                    endpoint = device -> ux_slave_device_endpoints_pool;
271
255
                                    endpoints_pool_number = device -> ux_slave_device_endpoints_pool_number;
272
616
                                    while (endpoints_pool_number != 0)
273
                                    {
274
                                        /* Check if this endpoint is free.  */
275
615
                                        if (endpoint ->    ux_slave_endpoint_status == UX_UNUSED)
276
                                        {
277
                                            /* Mark this endpoint as used now.  */
278
254
                                            endpoint ->    ux_slave_endpoint_status = UX_USED;
279
254
                                            break;
280
                                        }
281
282
                                        /* Try the next endpoint.  */
283
361
                                        endpoint++;
284
285
                                        /* Decrement the number of endpoints to scan from the pool.  */
286
361
                                       endpoints_pool_number--;
287
                                    }
288
289
                                    /* Did we find a free endpoint ?  */
290
255
                                    if (endpoints_pool_number == 0)
291
1
                                        return(UX_MEMORY_INSUFFICIENT);
292
293
                                    /* Parse the descriptor in something more readable.  */
294
254
                                    _ux_utility_descriptor_parse(device_framework,
295
                                                    _ux_system_endpoint_descriptor_structure,
296
                                                    UX_ENDPOINT_DESCRIPTOR_ENTRIES,
297
254
                                                    (UCHAR *) &endpoint -> ux_slave_endpoint_descriptor);
298
299
                                    /* Now we create a transfer request to accept transfer on this endpoint.  */
300
254
                                    transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
301
302
                                    /* Validate descriptor wMaxPacketSize.  */
303
                                    UX_ASSERT(endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize != 0);
304
305
                                    /* Calculate endpoint transfer payload max size.  */
306
254
                                    max_transfer_length =
307
254
                                            endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
308
                                                                                UX_MAX_PACKET_SIZE_MASK;
309
254
                                    if ((_ux_system_slave -> ux_system_slave_speed == UX_HIGH_SPEED_DEVICE) &&
310
14
                                        (endpoint -> ux_slave_endpoint_descriptor.bmAttributes & 0x1u))
311
                                    {
312
6
                                        n_trans = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize &
313
                                                                    UX_MAX_NUMBER_OF_TRANSACTIONS_MASK;
314
6
                                        if (n_trans)
315
                                        {
316
5
                                            n_trans >>= UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT;
317
5
                                            n_trans ++;
318
5
                                            max_transfer_length *= n_trans;
319
                                        }
320
                                    }
321
322
                                    /* Validate max transfer size and save it.  */
323
                                    UX_ASSERT(max_transfer_length <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH);
324
254
                                    transfer_request -> ux_slave_transfer_request_transfer_length = max_transfer_length;
325
326
                                    /* We store the endpoint in the transfer request as well.  */
327
254
                                    transfer_request -> ux_slave_transfer_request_endpoint =  endpoint;
328
329
                                    /* By default the timeout is infinite on request.  */
330
254
                                    transfer_request -> ux_slave_transfer_request_timeout = UX_WAIT_FOREVER;
331
332
                                    /* Attach the interface to the endpoint.  */
333
254
                                    endpoint -> ux_slave_endpoint_interface =  interface_ptr;
334
335
                                    /* Attach the device to the endpoint.  */
336
254
                                    endpoint -> ux_slave_endpoint_device =  device;
337
338
                                    /* Create the endpoint at the DCD level.  */
339
254
                                    status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_CREATE_ENDPOINT, (VOID *) endpoint);
340
341
                                    /* Do a sanity check on endpoint creation.  */
342
254
                                    if (status != UX_SUCCESS)
343
                                    {
344
345
                                        /* Error was returned, endpoint cannot be created.  */
346
1
                                        endpoint -> ux_slave_endpoint_status = UX_UNUSED;
347
1
                                        return(status);
348
                                    }
349
350
                                    /* Attach this endpoint to the end of the endpoint chain.  */
351
253
                                    if (interface_ptr -> ux_slave_interface_first_endpoint == UX_NULL)
352
                                    {
353
354
139
                                        interface_ptr -> ux_slave_interface_first_endpoint =  endpoint;
355
                                    }
356
                                    else
357
                                    {
358
                                        /* Multiple endpoints exist, so find the end of the chain.  */
359
114
                                        endpoint_link =  interface_ptr -> ux_slave_interface_first_endpoint;
360
126
                                        while (endpoint_link -> ux_slave_endpoint_next_endpoint != UX_NULL)
361
12
                                            endpoint_link =  endpoint_link -> ux_slave_endpoint_next_endpoint;
362
114
                                        endpoint_link -> ux_slave_endpoint_next_endpoint =  endpoint;
363
                                    }
364
365
253
                                    break;
366
367
45
                                case UX_CONFIGURATION_DESCRIPTOR_ITEM:
368
                                case UX_INTERFACE_DESCRIPTOR_ITEM:
369
370
                                    /* We have found a new configuration or interface descriptor, this is the end of the current
371
                                       interface. The search for the endpoints must be terminated as if it was the end of the
372
                                       entire descriptor.  */
373
45
                                    device_framework_length =  descriptor_length;
374
375
45
                                    break;
376
377
378
73
                                default:
379
380
                                    /* We have found another descriptor embedded in the interface. Ignore it.  */
381
73
                                    break;
382
                                }
383
384
                                /* Adjust what is left of the device framework.  */
385
371
                                device_framework_length -=  descriptor_length;
386
387
                                /* Point to the next descriptor.  */
388
371
                                device_framework +=  descriptor_length;
389
                            }
390
391
                            /* The interface descriptor in the current class must be changed to the new alternate setting.  */
392
160
                            _ux_utility_memory_copy(&interface_ptr -> ux_slave_interface_descriptor, &interface_descriptor, sizeof(UX_INTERFACE_DESCRIPTOR)); /* Use case of memcpy is verified. */
393
394
                            /* Get the class for the interface.  */
395
160
                            class_ptr =  _ux_system_slave -> ux_system_slave_interface_class_array[interface_ptr -> ux_slave_interface_descriptor.bInterfaceNumber];
396
397
                            /* Check if class driver is available. */
398

160
                            if (class_ptr == UX_NULL || class_ptr -> ux_slave_class_status == UX_UNUSED)
399
                            {
400
401
5
                                return (UX_NO_CLASS_MATCH);
402
                            }
403
404
                            /* The interface attached to this configuration must be changed at the class
405
                               level.  */
406
155
                            class_command.ux_slave_class_command_request   =    UX_SLAVE_CLASS_COMMAND_CHANGE;
407
155
                            class_command.ux_slave_class_command_interface =   (VOID *) interface_ptr;
408
409
                            /* And store it.  */
410
155
                            class_command.ux_slave_class_command_class_ptr =  class_ptr;
411
412
                            /* We can now memorize the interface pointer associated with this class.  */
413
155
                            class_ptr -> ux_slave_class_interface = interface_ptr;
414
415
                            /* We have found a potential candidate. Call this registered class entry function to change the alternate setting.  */
416
155
                            status = class_ptr -> ux_slave_class_entry_function(&class_command);
417
418
                            /* We are done here.  */
419
155
                            return(status);
420
                        }
421
                    }
422
423
                    /* Adjust what is left of the device framework.  */
424
1419
                    device_framework_length -=  descriptor_length;
425
426
                    /* Point to the next descriptor.  */
427
1419
                    device_framework +=  descriptor_length;
428
                }
429
430
                /* In case alter setting not found, report protocol error. */
431
4
                break;
432
            }
433
        }
434
435
        /* Adjust what is left of the device framework.  */
436
243
        device_framework_length -=  descriptor_length;
437
438
        /* Point to the next descriptor.  */
439
243
        device_framework +=  descriptor_length;
440
    }
441
442
    /* Return error completion.  */
443
5
    return(UX_ERROR);
444
#endif
445
}
446