GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hid_descriptor_parse.c Lines: 51 51 100.0 %
Date: 2026-03-06 18:57:10 Branches: 22 22 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
/**   HID Class                                                           */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
24
/* Include necessary system files.  */
25
26
#define UX_SOURCE_CODE
27
28
#include "ux_api.h"
29
#include "ux_host_class_hid.h"
30
#include "ux_host_stack.h"
31
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _ux_host_class_hid_descriptor_parse                 PORTABLE C      */
38
/*                                                           6.1.12       */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Chaoqiong Xiao, Microsoft Corporation                               */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function obtains the HID descriptor and parses it.             */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    hid                                   Pointer to HID class          */
50
/*                                                                        */
51
/*  OUTPUT                                                                */
52
/*                                                                        */
53
/*    Completion Status                                                   */
54
/*                                                                        */
55
/*  CALLS                                                                 */
56
/*                                                                        */
57
/*    _ux_host_class_hid_report_descriptor_get                            */
58
/*                                          Get HID report descriptor     */
59
/*    _ux_host_stack_transfer_request       Process transfer request      */
60
/*    _ux_utility_descriptor_parse          Parse descriptor              */
61
/*    _ux_utility_memory_allocate           Allocate memory block         */
62
/*    _ux_utility_memory_free               Release memory block          */
63
/*                                                                        */
64
/*  CALLED BY                                                             */
65
/*                                                                        */
66
/*    HID Class                                                           */
67
/*                                                                        */
68
/**************************************************************************/
69
502
UINT  _ux_host_class_hid_descriptor_parse(UX_HOST_CLASS_HID *hid)
70
{
71
72
UX_DEVICE                       *device;
73
UX_CONFIGURATION                *configuration;
74
UCHAR                           *descriptor;
75
UCHAR                           *start_descriptor;
76
UX_ENDPOINT                     *control_endpoint;
77
UX_TRANSFER                     *transfer_request;
78
UX_HID_DESCRIPTOR               hid_descriptor;
79
UX_INTERFACE_DESCRIPTOR         interface_descriptor;
80
UINT                            status;
81
ULONG                           total_configuration_length;
82
UINT                            descriptor_length;
83
UINT                            descriptor_type;
84
ULONG                           current_interface;
85
86
    /* Get device, current configuration.  */
87
502
    device = hid -> ux_host_class_hid_device;
88
502
    configuration = device -> ux_device_current_configuration;
89
502
    total_configuration_length = configuration -> ux_configuration_descriptor.wTotalLength;
90
91
    /* Check if descriptor is previously saved.  */
92
502
    if (device -> ux_device_packed_configuration != UX_NULL)
93
    {
94
129
        start_descriptor = device -> ux_device_packed_configuration;
95
129
        descriptor = start_descriptor;
96
129
        status = UX_SUCCESS;
97
    }
98
    else
99
    {
100
101
        /* We need to get the default control endpoint transfer request pointer.  */
102
373
        control_endpoint =  &device -> ux_device_control_endpoint;
103
373
        transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
104
105
        /* Need to allocate memory for the descriptor. Since we do not know the size of the
106
        descriptor, we first read the first bytes.  */
107
373
        descriptor =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, total_configuration_length);
108
373
        if (descriptor == UX_NULL)
109
2
            return(UX_MEMORY_INSUFFICIENT);
110
111
        /* Memorize the descriptor start address.  */
112
371
        start_descriptor =  descriptor;
113
114
        /* Create a transfer request for the GET_DESCRIPTOR request.  */
115
371
        transfer_request -> ux_transfer_request_data_pointer =      descriptor;
116
371
        transfer_request -> ux_transfer_request_requested_length =  total_configuration_length;
117
371
        transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
118
371
        transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
119
371
        transfer_request -> ux_transfer_request_value =             UX_CONFIGURATION_DESCRIPTOR_ITEM << 8;
120
371
        transfer_request -> ux_transfer_request_index =             0;
121
122
        /* Send request to HCD layer.  */
123
371
        status =  _ux_host_stack_transfer_request(transfer_request);
124
125
        /* Check descriptor length.  */
126
371
        if (transfer_request -> ux_transfer_request_actual_length != total_configuration_length)
127
4
            status = UX_DESCRIPTOR_CORRUPTED;
128
    }
129
130
    /* Reset the current interface to keep compiler warnings happy. */
131
500
    current_interface = 0;
132
133
    /* Check for correct transfer and entire descriptor returned.  */
134
500
    if (status == UX_SUCCESS)
135
    {
136
137
        /* The HID descriptor is embedded within the configuration descriptor. We parse the
138
            entire descriptor to locate the HID portion.  */
139
1987
        while (total_configuration_length)
140
        {
141
142
            /* Gather the length and type of the descriptor.   */
143
1983
            descriptor_length =  *descriptor;
144
1983
            descriptor_type =    *(descriptor + 1);
145
146
            /* Make sure this descriptor has at least the minimum length.  */
147
1983
            if (descriptor_length < 3)
148
            {
149
150
                /* Error trap. */
151
2
                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
152
153
                /* If trace is enabled, insert this event into the trace buffer.  */
154
                UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
155
156
                /* Error, release the memory and return an error.  */
157
2
                _ux_utility_memory_free(start_descriptor);
158
159
2
                return(UX_DESCRIPTOR_CORRUPTED);
160
            }
161
162
            /* Check the type for an interface descriptor.  */
163
1981
            if (descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM)
164
            {
165
166
                /* Parse the interface descriptor and make it machine independent.  */
167
653
                _ux_utility_descriptor_parse(descriptor,
168
                            _ux_system_interface_descriptor_structure,
169
                            UX_INTERFACE_DESCRIPTOR_ENTRIES,
170
                            (UCHAR *) &interface_descriptor);
171
172
                /* Memorize the interface we are scanning.  */
173
653
                current_interface = interface_descriptor.bInterfaceNumber;
174
            }
175
176
            /* Check the type for an interface descriptor.  */
177
            /* Check if the descriptor belongs to interface attached to this instance.  */
178
1981
            if (descriptor_type == UX_HOST_CLASS_HID_DESCRIPTOR)
179
            {
180
181
                /* Ensure this interface is the one we need to scan.  */
182
644
                if (current_interface == hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber)
183
                {
184
185
                    /* Obtain the length of the HID descriptor. We need to make machine
186
                        independent first.  */
187
489
                    _ux_utility_descriptor_parse(descriptor, _ux_system_hid_descriptor_structure,
188
                                                    UX_HID_DESCRIPTOR_ENTRIES, (UCHAR *) &hid_descriptor);
189
190
                    /* We have found the hid descriptor. Now we should get the HID report descriptor.  */
191
489
                    status =  _ux_host_class_hid_report_descriptor_get(hid, hid_descriptor.wItemLength);
192
193
                    /* No release, the memory will be released after all interface scan done(enumeration done).  */
194
489
                    device -> ux_device_packed_configuration = start_descriptor;
195
196
                    /* Return completion status.  */
197
489
                    return(status);
198
                }
199
            }
200
201
            /* Verify if the descriptor is still valid.  */
202
1492
            if (descriptor_length > total_configuration_length)
203
            {
204
205
                /* Error trap. */
206
1
                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
207
208
                /* If trace is enabled, insert this event into the trace buffer.  */
209
                UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
210
211
                /* Release the memory.  */
212
1
                _ux_utility_memory_free(start_descriptor);
213
214
                /* Return an error.  */
215
1
                return(UX_DESCRIPTOR_CORRUPTED);
216
            }
217
218
            /* Jump to the next descriptor if we have not reached the end.  */
219
1491
            descriptor +=  descriptor_length;
220
221
            /* And adjust the length left to parse in the descriptor.  */
222
1491
            total_configuration_length -=  descriptor_length;
223
        }
224
    }
225
226
    /* Error trap. */
227
8
    _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
228
229
    /* If trace is enabled, insert this event into the trace buffer.  */
230
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, start_descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
231
232
    /* Free all used resources.  */
233
8
    if (device -> ux_device_packed_configuration == UX_NULL)
234
7
        _ux_utility_memory_free(start_descriptor);
235
236
    /* Return an error.  */
237
8
    return(UX_DESCRIPTOR_CORRUPTED);
238
}
239