GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_descriptor_send.c Lines: 116 116 100.0 %
Date: 2026-03-06 18:57:10 Branches: 60 60 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
#if (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_DESCRIPTOR_LENGTH) || \
33
    (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH) || \
34
    (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_OTG_DESCRIPTOR_LENGTH)
35
/* #error UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH too small, please check  */
36
/* Build option checked runtime by UX_ASSERT  */
37
#endif
38
39
/**************************************************************************/
40
/*                                                                        */
41
/*  FUNCTION                                               RELEASE        */
42
/*                                                                        */
43
/*    _ux_device_stack_descriptor_send                    PORTABLE C      */
44
/*                                                           6.3.0        */
45
/*  AUTHOR                                                                */
46
/*                                                                        */
47
/*    Chaoqiong Xiao, Microsoft Corporation                               */
48
/*                                                                        */
49
/*  DESCRIPTION                                                           */
50
/*                                                                        */
51
/*    This function sends back the device descriptor required by the host.*/
52
/*                                                                        */
53
/*  INPUT                                                                 */
54
/*                                                                        */
55
/*    descriptor_type                       Descriptor type               */
56
/*    descriptor_index                      Index of descriptor           */
57
/*    host_length                           Length requested by host      */
58
/*                                                                        */
59
/*  OUTPUT                                                                */
60
/*                                                                        */
61
/*    Completion Status                                                   */
62
/*                                                                        */
63
/*  CALLS                                                                 */
64
/*                                                                        */
65
/*    (ux_slave_dcd_function)               DCD dispatch function         */
66
/*    _ux_device_stack_transfer_request     Process transfer request      */
67
/*    _ux_utility_descriptor_parse          Parse descriptor              */
68
/*    _ux_utility_memory_copy               Memory copy                   */
69
/*    _ux_utility_short_get                 Get short value               */
70
/*                                                                        */
71
/*  CALLED BY                                                             */
72
/*                                                                        */
73
/*    Application                                                         */
74
/*    Device Stack                                                        */
75
/*                                                                        */
76
/**************************************************************************/
77
4951
UINT  _ux_device_stack_descriptor_send(ULONG descriptor_type, ULONG request_index, ULONG host_length)
78
{
79
80
UX_SLAVE_DCD                    *dcd;
81
UX_SLAVE_DEVICE                 *device;
82
ULONG                           descriptor_index;
83
ULONG                           parsed_descriptor_index;
84
UX_SLAVE_TRANSFER               *transfer_request;
85
UX_CONFIGURATION_DESCRIPTOR     configuration_descriptor;
86
#ifndef UX_BOS_SUPPORT_DISABLE
87
UX_BOS_DESCRIPTOR               bos_descriptor;
88
#endif
89
UX_SLAVE_ENDPOINT               *endpoint;
90
UCHAR                           *device_framework;
91
UCHAR                           *device_framework_end;
92
ULONG                           device_framework_length;
93
ULONG                           descriptor_length;
94
4951
ULONG                           target_descriptor_length = 0;
95
4951
UINT                            status =  UX_ERROR;
96
ULONG                           length;
97
UCHAR                           *string_memory;
98
UCHAR                           *string_framework;
99
ULONG                           string_framework_length;
100
ULONG                           string_length;
101
102
103
    /* Build option check.  */
104
    UX_ASSERT((UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_DEVICE_DESCRIPTOR_LENGTH) &&
105
              (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH) &&
106
              (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_OTG_DESCRIPTOR_LENGTH));
107
108
    /* If trace is enabled, insert this event into the trace buffer.  */
109
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_DESCRIPTOR_SEND, descriptor_type, request_index, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
110
111
    /* Get the pointer to the DCD.  */
112
4951
    dcd =  &_ux_system_slave -> ux_system_slave_dcd;
113
114
    /* Get the pointer to the device.  */
115
4951
    device =  &_ux_system_slave -> ux_system_slave_device;
116
117
    /* Get the control endpoint associated with the device.  */
118
4951
    endpoint =  &device -> ux_slave_device_control_endpoint;
119
120
    /* Get the pointer to the transfer request associated with the endpoint.  */
121
4951
    transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
122
123
    /* Set the direction to OUT.  */
124
4951
    transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_OUT;
125
126
    /* Isolate the descriptor index.  */
127
4951
    descriptor_index =  descriptor_type & 0xff;
128
129
    /* Reset the parsed index.  */
130
4951
    parsed_descriptor_index =  0;
131
132
    /* Shift the descriptor type in the low byte field.  */
133
4951
    descriptor_type =  (UCHAR) ((descriptor_type >> 8) & 0xff);
134
135
    /* Default descriptor length is host length.  */
136
4951
    length =  host_length;
137
138
    /* What type of descriptor do we need to return?  */
139

4951
    switch (descriptor_type)
140
    {
141
142
2128
    case UX_DEVICE_DESCRIPTOR_ITEM:
143
144
		/* Setup device descriptor length.  */
145
2128
        if (host_length > UX_DEVICE_DESCRIPTOR_LENGTH)
146
3
            length =  UX_DEVICE_DESCRIPTOR_LENGTH;
147
148
        /* Fall through.  */
149
    case UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM:
150
151
        /* Setup qualifier descriptor length.  */
152

2131
        if (descriptor_type == UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM &&
153
            host_length > UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH)
154
2
            length =  UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH;
155
156
        /* Fall through.  */
157
    case UX_OTG_DESCRIPTOR_ITEM:
158
159
        /* Setup OTG descriptor length.  */
160

2134
        if (descriptor_type == UX_OTG_DESCRIPTOR_ITEM &&
161
            host_length > UX_OTG_DESCRIPTOR_LENGTH)
162
2
            length =  UX_OTG_DESCRIPTOR_LENGTH;
163
164
        /* We may or may not have a device qualifier descriptor.  */
165
2134
        device_framework =  _ux_system_slave -> ux_system_slave_device_framework;
166
2134
        device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
167
2134
        device_framework_end = device_framework + device_framework_length;
168
169
        /* Parse the device framework and locate a device qualifier descriptor.  */
170
2266
        while (device_framework < device_framework_end)
171
        {
172
173
            /* Get descriptor length.  */
174
2264
            descriptor_length =  (ULONG) *device_framework;
175
176
            /* Check if this is a descriptor expected.  */
177
2264
            if (*(device_framework + 1) == descriptor_type)
178
            {
179
180
                /* Copy the device descriptor into the transfer request memory.  */
181
2132
                _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
182
                                                device_framework, length); /* Use case of memcpy is verified. */
183
184
                /* Perform the data transfer.  */
185
2132
                status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
186
2132
                break;
187
            }
188
189
            /* Adjust what is left of the device framework.  */
190
132
            device_framework_length -=  descriptor_length;
191
192
            /* Point to the next descriptor.  */
193
132
            device_framework +=  descriptor_length;
194
        }
195
2134
        break;
196
197
#ifndef UX_BOS_SUPPORT_DISABLE
198
2744
    case UX_BOS_DESCRIPTOR_ITEM:
199
        /* Fall through.  */
200
#endif
201
    case UX_OTHER_SPEED_DESCRIPTOR_ITEM:
202
        /* Fall through.  */
203
    case UX_CONFIGURATION_DESCRIPTOR_ITEM:
204
205
2744
        if (descriptor_type == UX_OTHER_SPEED_DESCRIPTOR_ITEM)
206
        {
207
208
            /* This request is used by the host to find out the capability of this device
209
            if it was running at full speed. The behavior is the same as in a GET_CONFIGURATIOn descriptor
210
            but we do not use the current device framework but rather the full speed framework. */
211
4
            device_framework =  _ux_system_slave -> ux_system_slave_device_framework_full_speed;
212
4
            device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length_full_speed;
213
4
            device_framework_end = device_framework + device_framework_length;
214
        }
215
        else
216
        {
217
218
            /* We may have multiple configurations !, the index will tell us what
219
            configuration descriptor we need to return.  */
220
2740
            device_framework =  _ux_system_slave -> ux_system_slave_device_framework;
221
2740
            device_framework_length =  _ux_system_slave -> ux_system_slave_device_framework_length;
222
2740
            device_framework_end = device_framework + device_framework_length;
223
        }
224
225
        /* Parse the device framework and locate a configuration descriptor.  */
226
7197
        while (device_framework < device_framework_end)
227
        {
228
229
            /* Get descriptor length. */
230
7195
            descriptor_length =  (ULONG) *device_framework;
231
232
#ifndef UX_BOS_SUPPORT_DISABLE
233
234
            /* Check if we are finding BOS descriptor.  */
235
7195
            if (descriptor_type == UX_BOS_DESCRIPTOR_ITEM)
236
            {
237
2
                if (*(device_framework + 1) == UX_BOS_DESCRIPTOR_ITEM)
238
                {
239
240
                    /* Parse the BOS descriptor.  */
241
1
                    _ux_utility_descriptor_parse(device_framework,
242
                                _ux_system_bos_descriptor_structure,
243
                                UX_BOS_DESCRIPTOR_ENTRIES,
244
                                (UCHAR *) &bos_descriptor);
245
246
                    /* Get the length of entire BOS descriptor.  */
247
1
                    target_descriptor_length = bos_descriptor.wTotalLength;
248
249
                    /* Descriptor is found.  */
250
1
                    status = UX_SUCCESS;
251
1
                    break;
252
                }
253
            }
254
            else
255
#endif
256
257
            {
258
259
                /* Check if this is a configuration descriptor.  We are cheating here. Instead of creating
260
                a OTHER SPEED descriptor, we simply scan the configuration descriptor for the Full Speed
261
                framework and return this configuration after we manually changed the configuration descriptor
262
                item into a Other Speed Descriptor. */
263
7193
                if (*(device_framework + 1) == UX_CONFIGURATION_DESCRIPTOR_ITEM)
264
                {
265
266
                    /* Check the index. It must be the same as the one requested.  */
267
2767
                    if (parsed_descriptor_index == descriptor_index)
268
                    {
269
270
                        /* Parse the configuration descriptor. */
271
2741
                        _ux_utility_descriptor_parse(device_framework,
272
                                    _ux_system_configuration_descriptor_structure,
273
                                    UX_CONFIGURATION_DESCRIPTOR_ENTRIES,
274
                                    (UCHAR *) &configuration_descriptor);
275
276
                        /* Get the length of entire configuration descriptor.  */
277
2741
                        target_descriptor_length = configuration_descriptor.wTotalLength;
278
279
                        /* Descriptor is found.  */
280
2741
                        status = UX_SUCCESS;
281
2741
                        break;
282
                    }
283
                    else
284
                    {
285
286
                        /* There may be more configuration descriptors in this framework.  */
287
26
                        parsed_descriptor_index++;
288
                    }
289
                }
290
            }
291
292
            /* Adjust what is left of the device framework.  */
293
4453
            device_framework_length -=  descriptor_length;
294
295
            /* Point to the next descriptor.  */
296
4453
            device_framework +=  descriptor_length;
297
        }
298
299
        /* Send the descriptor.  */
300
2744
        if (status == UX_SUCCESS)
301
        {
302
303
            /* Ensure the host does not demand a length beyond our descriptor (Windows does that)
304
                and do not return more than what is allowed.  */
305
2742
            if (target_descriptor_length < host_length)
306
6
                length =  target_descriptor_length;
307
            else
308
2736
                length =  host_length;
309
310
            /* Check buffer length, since total descriptors length may exceed buffer...  */
311
2742
            if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
312
            {
313
                /* Error trap. */
314
2
                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
315
316
                /* If trace is enabled, insert this event into the trace buffer.  */
317
                UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
318
319
                /* Stall the endpoint.  */
320
2
                status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
321
2
                break;
322
            }
323
324
            /* Copy the device descriptor into the transfer request memory.  */
325
2740
            _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
326
                                device_framework, length); /* Use case of memcpy is verified. */
327
328
            /* Now we need to hack the found descriptor because this request expect a requested
329
                descriptor type instead of the regular descriptor.  */
330
2740
            *(transfer_request -> ux_slave_transfer_request_data_pointer + 1) = (UCHAR)descriptor_type;
331
332
            /* We can return the configuration descriptor.  */
333
2740
            status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
334
        }
335
2742
        break;
336
337
72
    case UX_STRING_DESCRIPTOR_ITEM:
338
339
        /* We need to filter for the index 0 which is the language ID string.  */
340
72
        if (descriptor_index == 0)
341
        {
342
343
            /* We need to check request buffer size in case it's possible exceed. */
344
4
            if (_ux_system_slave -> ux_system_slave_language_id_framework_length + 2 > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
345
            {
346
347
                /* Error trap. */
348
1
                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
349
350
                /* If trace is enabled, insert this event into the trace buffer.  */
351
                UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
352
353
                /* Stall the endpoint.  */
354
1
                status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
355
1
                break;
356
            }
357
358
            /* We have a request to send back the language ID list. Use the transfer request buffer.  */
359
3
            string_memory =  transfer_request -> ux_slave_transfer_request_data_pointer;
360
361
            /* Store the total length of the response.  */
362
3
            *string_memory =  (UCHAR)(_ux_system_slave -> ux_system_slave_language_id_framework_length + 2);
363
364
            /* Store the descriptor type.  */
365
3
            *(string_memory +1) =  UX_STRING_DESCRIPTOR_ITEM;
366
367
            /* Store the language ID into the buffer.  */
368
3
            _ux_utility_memory_copy(string_memory+2, _ux_system_slave -> ux_system_slave_language_id_framework,
369
3
                                                        _ux_system_slave -> ux_system_slave_language_id_framework_length); /* Use case of memcpy is verified. */
370
371
            /* Filter the length asked/required.  */
372
3
            if (host_length > _ux_system_slave -> ux_system_slave_language_id_framework_length + 2)
373
2
                length =  _ux_system_slave -> ux_system_slave_language_id_framework_length + 2;
374
            else
375
1
                length =  host_length;
376
377
            /* We can return the string language ID descriptor.  */
378
3
            status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
379
        }
380
        else
381
        {
382
#ifdef UX_DEVICE_ENABLE_GET_STRING_WITH_ZERO_LANGUAGE_ID
383
384
            /* Check if the language ID is zero.  */
385
68
            if (request_index == 0)
386
            {
387
388
                /* Get the first language ID in the language ID framework.  */
389
1
                request_index =  _ux_utility_short_get(_ux_system_slave -> ux_system_slave_language_id_framework);
390
            }
391
#endif
392
393
            /* The host wants a specific string index returned. Get the string framework pointer
394
               and length.  */
395
68
            string_framework =  _ux_system_slave -> ux_system_slave_string_framework;
396
68
            string_framework_length =  _ux_system_slave -> ux_system_slave_string_framework_length;
397
398
            /* We search through the string framework until we find the right index.
399
               The index is in the lower byte of the descriptor type. */
400
260
            while (string_framework_length != 0)
401
            {
402
403
                /* Ensure we have the correct language page.  */
404
259
                if (_ux_utility_short_get(string_framework) == request_index)
405
                {
406
407
                    /* Check the index.  */
408
258
                    if (*(string_framework + 2) == descriptor_index)
409
                    {
410
411
                        /* We need to check request buffer size in case it's possible exceed. */
412
67
                        if (((*(string_framework + 3)*2) + 2) > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
413
                        {
414
415
                            /* Error trap. */
416
1
                            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_DEVICE_STACK, UX_MEMORY_INSUFFICIENT);
417
418
                            /* If trace is enabled, insert this event into the trace buffer.  */
419
                            UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
420
421
                            /* Stall the endpoint.  */
422
1
                            status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
423
1
                            break;
424
                        }
425
426
                        /* We have a request to send back a string. Use the transfer request buffer.  */
427
66
                        string_memory =  transfer_request -> ux_slave_transfer_request_data_pointer;
428
429
                        /* Store the length in the string buffer. The length
430
                           of the string descriptor is stored in the third byte,
431
                           hence the ' + 3'. The encoding must be in 16-bit
432
                           unicode, hence the '*2'. The length includes the size
433
                           of the length itself as well as the descriptor type,
434
                           hence the ' + 2'.  */
435
66
                        *string_memory =  (UCHAR)((*(string_framework + 3)*2) + 2);
436
437
                        /* Store the Descriptor type. */
438
66
                        *(string_memory + 1) =  UX_STRING_DESCRIPTOR_ITEM;
439
440
                        /* Create the Unicode string.  */
441
894
                        for (string_length = 0; string_length <  *(string_framework + 3) ; string_length ++)
442
                        {
443
444
                            /* Insert a Unicode byte.  */
445
828
                            *(string_memory + 2 + (string_length * 2)) =  *(string_framework + 4 + string_length);
446
447
                            /* Insert a zero after the Unicode byte.  */
448
828
                            *(string_memory + 2 + (string_length * 2) + 1) =  0;
449
                        }
450
451
                        /* Filter the length asked/required.  */
452
66
                        if (host_length > (UINT)((*(string_framework + 3)*2) + 2))
453
62
                            length =  (ULONG)((*(string_framework + 3)*2) + 2);
454
                        else
455
4
                            length =  host_length;
456
457
                        /* We can return the string descriptor.  */
458
66
                        status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
459
66
                        break;
460
                    }
461
                }
462
463
                /* This is the wrong string descriptor, jump to the next.  */
464
192
                string_framework_length -=  (ULONG) *(string_framework + 3) + 4;
465
192
                string_framework +=  (ULONG) *(string_framework + 3) + 4;
466
            }
467
468
            /* Have we exhausted all the string descriptors?  */
469
68
            if (string_framework_length == 0)
470
            {
471
472
                /* Could not find the required string index. Stall the endpoint.  */
473
1
                dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
474
1
                return(UX_ERROR);
475
            }
476
        }
477
70
        break;
478
479
1
    default:
480
481
        /* Stall the endpoint.  */
482
1
        dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
483
1
        return(UX_ERROR);
484
    }
485
486
    /* Return the status to the caller.  */
487
4949
    return(status);
488
}
489