GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hid_report_add.c Lines: 86 86 100.0 %
Date: 2026-03-06 18:57:10 Branches: 40 40 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_report_add                       PORTABLE C      */
38
/*                                                           6.3.0        */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Chaoqiong Xiao, Microsoft Corporation                               */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function adds a report (input/output/feature) to the current   */
46
/*    parser.                                                             */
47
/*                                                                        */
48
/*  INPUT                                                                 */
49
/*                                                                        */
50
/*    hid                                   Pointer to HID class          */
51
/*    descriptor                            Pointer to descriptor         */
52
/*    item                                  Pointer to item               */
53
/*                                                                        */
54
/*  OUTPUT                                                                */
55
/*                                                                        */
56
/*    Completion Status                                                   */
57
/*                                                                        */
58
/*  CALLS                                                                 */
59
/*                                                                        */
60
/*    _ux_host_class_hid_item_data_get      Get data item                 */
61
/*    _ux_utility_memory_allocate           Allocate memory block         */
62
/*    _ux_utility_memory_copy               Copy memory block             */
63
/*    _ux_utility_memory_free               Release memory block          */
64
/*                                                                        */
65
/*  CALLED BY                                                             */
66
/*                                                                        */
67
/*    HID Class                                                           */
68
/*                                                                        */
69
/**************************************************************************/
70
2021
UINT  _ux_host_class_hid_report_add(UX_HOST_CLASS_HID *hid, UCHAR *descriptor, UX_HOST_CLASS_HID_ITEM *item)
71
{
72
73
UX_HOST_CLASS_HID_PARSER    *hid_parser;
74
ULONG                       hid_field_value;
75
ULONG                       hid_field_count;
76
UX_HOST_CLASS_HID_REPORT    *new_hid_report;
77
UX_HOST_CLASS_HID_REPORT    *hid_report;
78
UX_HOST_CLASS_HID_FIELD     *hid_field;
79
UX_HOST_CLASS_HID_FIELD     *new_hid_field;
80
ULONG                       current_field_address;
81
82
83
    /* Get the parser structure pointer.  */
84
2021
    hid_parser =  &hid -> ux_host_class_hid_parser;
85
86
    /* Obtain the field value from the report.  */
87
2021
    hid_field_value =  _ux_host_class_hid_item_data_get(descriptor, item);
88
89
    /* Allocate some memory to store this new report.  */
90
2021
    new_hid_report =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_HID_REPORT));
91
2021
    if (new_hid_report == UX_NULL)
92
30
        return(UX_MEMORY_INSUFFICIENT);
93
94
    /* We need to select the report entry based on the type of report. If the entry in the
95
       report chain is NULL, this is the first report so update the start of the chain.  */
96

1991
    switch (item -> ux_host_class_hid_item_report_tag)
97
    {
98
99
1162
    case UX_HOST_CLASS_HID_MAIN_TAG_INPUT:
100
101
1162
        hid_report =  hid_parser -> ux_host_class_hid_parser_input_report;
102
1162
        if (hid_report == UX_NULL)
103
401
            hid_parser -> ux_host_class_hid_parser_input_report =  new_hid_report;
104
105
        /* This is a Input report.  */
106
1162
        new_hid_report -> ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT;
107
1162
        break;
108
109
496
    case UX_HOST_CLASS_HID_MAIN_TAG_OUTPUT:
110
111
496
        hid_report =  hid_parser -> ux_host_class_hid_parser_output_report;
112
496
        if (hid_report == UX_NULL)
113
257
            hid_parser -> ux_host_class_hid_parser_output_report =  new_hid_report;
114
115
        /* This is output report.  */
116
496
        new_hid_report -> ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT;
117
496
        break;
118
119
332
    case UX_HOST_CLASS_HID_MAIN_TAG_FEATURE:
120
121
332
        hid_report =  hid_parser -> ux_host_class_hid_parser_feature_report;
122
332
        if (hid_report == UX_NULL)
123
117
            hid_parser -> ux_host_class_hid_parser_feature_report =  new_hid_report;
124
125
        /* This is a Feature report.  */
126
332
        new_hid_report -> ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE;
127
332
        break;
128
129
130
1
    default:
131
132
1
        _ux_utility_memory_free(new_hid_report);
133
134
        /* Error trap. */
135
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_HID_REPORT_ERROR);
136
137
        /* If trace is enabled, insert this event into the trace buffer.  */
138
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_HID_REPORT_ERROR, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
139
140
        /* Return an error.  */
141
1
        return(UX_HOST_CLASS_HID_REPORT_ERROR);
142
    }
143
144
    /* If there is a preceding report, locate the end of the report chain.  */
145
1990
    if (hid_report != UX_NULL)
146
    {
147
148
1342
        while (hid_report -> ux_host_class_hid_report_next_report != UX_NULL)
149
127
            hid_report =  hid_report -> ux_host_class_hid_report_next_report;
150
    }
151
152
    /* If this report is part of the current global report, use the last report
153
       to add the fields.  */
154

1990
    if ((hid_report != UX_NULL) && (hid_report -> ux_host_class_hid_report_id == hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_id))
155
    {
156
157
        /* So we did not need a new report after all!  */
158
991
        _ux_utility_memory_free(new_hid_report);
159
991
        new_hid_report =  hid_report;
160
    }
161
    else
162
    {
163
164
        /* We do have to build a new report. Add the new one to the chain.  */
165
999
        if (hid_report != UX_NULL)
166
224
            hid_report -> ux_host_class_hid_report_next_report =  new_hid_report;
167
168
        /* Add the new report ID.  */
169
999
        new_hid_report -> ux_host_class_hid_report_id =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_id;
170
    }
171
172
    /* Compute the size of the report. The size is first calculated in bits.  */
173
1990
    current_field_address =  new_hid_report -> ux_host_class_hid_report_bit_length;
174
1990
    new_hid_report -> ux_host_class_hid_report_bit_length +=  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_size*
175
1990
                                                            hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count;
176
177
    /* Now compute the size in bytes (easier for the end/receive reports functions).  */
178
1990
    new_hid_report -> ux_host_class_hid_report_byte_length =  new_hid_report -> ux_host_class_hid_report_bit_length >> 3;
179
180
    /* Take care of the bit padding if necessary.  */
181
1990
    if (new_hid_report -> ux_host_class_hid_report_bit_length & 7)
182
438
        new_hid_report -> ux_host_class_hid_report_byte_length++;
183
184
    /* Get the number of fields for this report.  */
185
1990
    hid_field_count =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count;
186
187
    /* If the field count is null, this is only padding and there is no field to be allocated to the report.  */
188
1990
    if (hid_field_count == 0)
189
1
        return(UX_SUCCESS);
190
191
    /* Create the field structure.  */
192
1989
    new_hid_field =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_HID_FIELD));
193
1989
    if (new_hid_field == UX_NULL)
194
28
        return(UX_MEMORY_INSUFFICIENT);
195
196
    /* From the parser structure, update the new field values. Start with logical values.  */
197
1961
    new_hid_field -> ux_host_class_hid_field_logical_min =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_logical_min;
198
1961
    new_hid_field -> ux_host_class_hid_field_logical_max =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_logical_max;
199
200
    /* Then the usage values. Note that these are only used if the item is an array.  */
201
1961
    new_hid_field -> ux_host_class_hid_field_usage_page =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_usage_page;
202
1961
    new_hid_field -> ux_host_class_hid_field_usage_min =  hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_usage_min;
203
1961
    new_hid_field -> ux_host_class_hid_field_usage_max =  hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_usage_max;
204
205
    /* Then physical values.  */
206
1961
    new_hid_field -> ux_host_class_hid_field_physical_min =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_physical_min;
207
1961
    new_hid_field -> ux_host_class_hid_field_physical_max =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_physical_max;
208
209
    /* Then unit values.  */
210
1961
    new_hid_field -> ux_host_class_hid_field_unit =       hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_unit;
211
1961
    new_hid_field -> ux_host_class_hid_field_unit_expo =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_unit_expo;
212
213
    /* Then report values.  */
214
1961
    new_hid_field -> ux_host_class_hid_field_report_type =   item -> ux_host_class_hid_item_report_tag;
215
1961
    new_hid_field -> ux_host_class_hid_field_report_id =     hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_id;
216
1961
    new_hid_field -> ux_host_class_hid_field_report_size =   hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_size;
217
1961
    new_hid_field -> ux_host_class_hid_field_report_count =  hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count;
218
1961
    new_hid_field -> ux_host_class_hid_field_report_offset = current_field_address;
219
220
    /* Save the HID field value.  */
221
1961
    new_hid_field -> ux_host_class_hid_field_value =  hid_field_value;
222
223
    /* We need some memory for the values.  */
224
1961
    new_hid_field -> ux_host_class_hid_field_values =  _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY,
225
                                                                                    new_hid_field -> ux_host_class_hid_field_report_count, 4);
226
227
    /* Check the memory pointer. */
228
1961
    if (new_hid_field -> ux_host_class_hid_field_values == UX_NULL)
229
    {
230
231
28
        _ux_utility_memory_free(new_hid_field);
232
28
        return(UX_MEMORY_INSUFFICIENT);
233
    }
234
235
    /* We need some memory for the usages, but only for variable items; usage
236
       values for array items can be calculated.  */
237
1933
    if ((hid_field_value & UX_HOST_CLASS_HID_ITEM_VARIABLE) &&
238
1669
        (hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage > 0))
239
    {
240
241
        /* Allocate memory for the usages.  */
242
1093
        new_hid_field -> ux_host_class_hid_field_usages =  _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage, 4);
243
1093
        if (new_hid_field -> ux_host_class_hid_field_usages == UX_NULL)
244
        {
245
246
18
            _ux_utility_memory_free(new_hid_field -> ux_host_class_hid_field_values);
247
18
            _ux_utility_memory_free(new_hid_field);
248
18
            return(UX_MEMORY_INSUFFICIENT);
249
        }
250
251
        /* Copy the current usages in the field structure.  */
252
1075
        _ux_utility_memory_copy(new_hid_field -> ux_host_class_hid_field_usages, hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_usages, hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage * 4); /* Use case of memcpy is verified. */
253
    }
254
255
    /* Save the number of usages.  */
256
1915
    new_hid_field -> ux_host_class_hid_field_number_usage = hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage;
257
258
    /* Attach the new field to the report. The report may already contain a field, if so parse the chain
259
       until we reach the end of the chain.  */
260
1915
    new_hid_report -> ux_host_class_hid_report_number_item += hid_field_count;
261
1915
    if (new_hid_report -> ux_host_class_hid_report_field == UX_NULL)
262
    {
263
264
        /* This is the first field for the report.  */
265
959
        new_hid_report -> ux_host_class_hid_report_field =  new_hid_field;
266
    }
267
    else
268
    {
269
270
        /* We have previous HID fields, so search for the end of the chain.  */
271
956
        hid_field =  new_hid_report -> ux_host_class_hid_report_field;
272
1500
        while(hid_field -> ux_host_class_hid_field_next_field != UX_NULL)
273
544
            hid_field =  hid_field -> ux_host_class_hid_field_next_field;
274
275
        /* Attach the new field to the end of the chain.  */
276
956
        hid_field -> ux_host_class_hid_field_next_field =  new_hid_field;
277
    }
278
279
    /* Return successful completion.  */
280
1915
    return(UX_SUCCESS);
281
}
282