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

160
                            if (class_ptr == UX_NULL || class_ptr -> ux_slave_class_status == UX_UNUSED)
416
                            {
417
418
5
                                return (UX_NO_CLASS_MATCH);
419
                            }
420
421
                            /* The interface attached to this configuration must be changed at the class
422
                               level.  */
423
155
                            class_command.ux_slave_class_command_request   =    UX_SLAVE_CLASS_COMMAND_CHANGE;
424
155
                            class_command.ux_slave_class_command_interface =   (VOID *) interface_ptr;
425
426
                            /* And store it.  */
427
155
                            class_command.ux_slave_class_command_class_ptr =  class_ptr;
428
429
                            /* We can now memorize the interface pointer associated with this class.  */
430
155
                            class_ptr -> ux_slave_class_interface = interface_ptr;
431
432
                            /* We have found a potential candidate. Call this registered class entry function to change the alternate setting.  */
433
155
                            status = class_ptr -> ux_slave_class_entry_function(&class_command);
434
435
                            /* We are done here.  */
436
155
                            return(status);
437
                        }
438
                    }
439
440
                    /* Adjust what is left of the device framework.  */
441
1419
                    device_framework_length -=  descriptor_length;
442
443
                    /* Point to the next descriptor.  */
444
1419
                    device_framework +=  descriptor_length;
445
                }
446
447
                /* In case alter setting not found, report protocol error. */
448
4
                break;
449
            }
450
        }
451
452
        /* Adjust what is left of the device framework.  */
453
243
        device_framework_length -=  descriptor_length;
454
455
        /* Point to the next descriptor.  */
456
243
        device_framework +=  descriptor_length;
457
    }
458
459
    /* Return error completion.  */
460
5
    return(UX_ERROR);
461
#endif
462
}
463