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