GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_device_stack_descriptor_send.c Lines: 116 116 100.0 %
Date: 2024-12-12 17:16:36 Branches: 60 60 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
#if (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_DESCRIPTOR_LENGTH) || \
32
    (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH) || \
33
    (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_OTG_DESCRIPTOR_LENGTH)
34
/* #error UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH too small, please check  */
35
/* Build option checked runtime by UX_ASSERT  */
36
#endif
37
38
/**************************************************************************/
39
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _ux_device_stack_descriptor_send                    PORTABLE C      */
43
/*                                                           6.3.0        */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    Chaoqiong Xiao, Microsoft Corporation                               */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function sends back the device descriptor required by the host.*/
51
/*                                                                        */
52
/*  INPUT                                                                 */
53
/*                                                                        */
54
/*    descriptor_type                       Descriptor type               */
55
/*    descriptor_index                      Index of descriptor           */
56
/*    host_length                           Length requested by host      */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    Completion Status                                                   */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    (ux_slave_dcd_function)               DCD dispatch function         */
65
/*    _ux_device_stack_transfer_request     Process transfer request      */
66
/*    _ux_utility_descriptor_parse          Parse descriptor              */
67
/*    _ux_utility_memory_copy               Memory copy                   */
68
/*    _ux_utility_short_get                 Get short value               */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    Application                                                         */
73
/*    Device Stack                                                        */
74
/*                                                                        */
75
/*  RELEASE HISTORY                                                       */
76
/*                                                                        */
77
/*    DATE              NAME                      DESCRIPTION             */
78
/*                                                                        */
79
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
80
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
81
/*                                            optimized descriptor search */
82
/*                                            logic, verified memset and  */
83
/*                                            memcpy cases,               */
84
/*                                            resulting in version 6.1    */
85
/*  12-31-2020     Chaoqiong Xiao           Modified comment(s),          */
86
/*                                            added BOS support,          */
87
/*                                            resulting in version 6.1.3  */
88
/*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
89
/*                                            internal clean up,          */
90
/*                                            resulting in version 6.1.11 */
91
/*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
92
/*                                            moved compile option check, */
93
/*                                            added support for get string*/
94
/*                                            requests with zero wIndex,  */
95
/*                                            resulting in version 6.3.0  */
96
/*                                                                        */
97
/**************************************************************************/
98
4947
UINT  _ux_device_stack_descriptor_send(ULONG descriptor_type, ULONG request_index, ULONG host_length)
99
{
100
101
UX_SLAVE_DCD                    *dcd;
102
UX_SLAVE_DEVICE                 *device;
103
ULONG                           descriptor_index;
104
ULONG                           parsed_descriptor_index;
105
UX_SLAVE_TRANSFER               *transfer_request;
106
UX_CONFIGURATION_DESCRIPTOR     configuration_descriptor;
107
#ifndef UX_BOS_SUPPORT_DISABLE
108
UX_BOS_DESCRIPTOR               bos_descriptor;
109
#endif
110
UX_SLAVE_ENDPOINT               *endpoint;
111
UCHAR                           *device_framework;
112
UCHAR                           *device_framework_end;
113
ULONG                           device_framework_length;
114
ULONG                           descriptor_length;
115
4947
ULONG                           target_descriptor_length = 0;
116
4947
UINT                            status =  UX_ERROR;
117
ULONG                           length;
118
UCHAR                           *string_memory;
119
UCHAR                           *string_framework;
120
ULONG                           string_framework_length;
121
ULONG                           string_length;
122
123
124
    /* Build option check.  */
125
    UX_ASSERT((UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_DEVICE_DESCRIPTOR_LENGTH) &&
126
              (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH) &&
127
              (UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH >= UX_OTG_DESCRIPTOR_LENGTH));
128
129
    /* If trace is enabled, insert this event into the trace buffer.  */
130
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_DESCRIPTOR_SEND, descriptor_type, request_index, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
131
132
    /* Get the pointer to the DCD.  */
133
4947
    dcd =  &_ux_system_slave -> ux_system_slave_dcd;
134
135
    /* Get the pointer to the device.  */
136
4947
    device =  &_ux_system_slave -> ux_system_slave_device;
137
138
    /* Get the control endpoint associated with the device.  */
139
4947
    endpoint =  &device -> ux_slave_device_control_endpoint;
140
141
    /* Get the pointer to the transfer request associated with the endpoint.  */
142
4947
    transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
143
144
    /* Set the direction to OUT.  */
145
4947
    transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_OUT;
146
147
    /* Isolate the descriptor index.  */
148
4947
    descriptor_index =  descriptor_type & 0xff;
149
150
    /* Reset the parsed index.  */
151
4947
    parsed_descriptor_index =  0;
152
153
    /* Shift the descriptor type in the low byte field.  */
154
4947
    descriptor_type =  (UCHAR) ((descriptor_type >> 8) & 0xff);
155
156
    /* Default descriptor length is host length.  */
157
4947
    length =  host_length;
158
159
    /* What type of descriptor do we need to return?  */
160

4947
    switch (descriptor_type)
161
    {
162
163
2126
    case UX_DEVICE_DESCRIPTOR_ITEM:
164
165
		/* Setup device descriptor length.  */
166
2126
        if (host_length > UX_DEVICE_DESCRIPTOR_LENGTH)
167
3
            length =  UX_DEVICE_DESCRIPTOR_LENGTH;
168
169
        /* Fall through.  */
170
    case UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM:
171
172
        /* Setup qualifier descriptor length.  */
173

2129
        if (descriptor_type == UX_DEVICE_QUALIFIER_DESCRIPTOR_ITEM &&
174
            host_length > UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH)
175
2
            length =  UX_DEVICE_QUALIFIER_DESCRIPTOR_LENGTH;
176
177
        /* Fall through.  */
178
    case UX_OTG_DESCRIPTOR_ITEM:
179
180
        /* Setup OTG descriptor length.  */
181

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