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: 2024-12-12 17:16:36 Branches: 40 40 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_report_add                       PORTABLE C      */
37
/*                                                           6.3.0        */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    Chaoqiong Xiao, Microsoft Corporation                               */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    This function adds a report (input/output/feature) to the current   */
45
/*    parser.                                                             */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    hid                                   Pointer to HID class          */
50
/*    descriptor                            Pointer to descriptor         */
51
/*    item                                  Pointer to item               */
52
/*                                                                        */
53
/*  OUTPUT                                                                */
54
/*                                                                        */
55
/*    Completion Status                                                   */
56
/*                                                                        */
57
/*  CALLS                                                                 */
58
/*                                                                        */
59
/*    _ux_host_class_hid_item_data_get      Get data item                 */
60
/*    _ux_utility_memory_allocate           Allocate memory block         */
61
/*    _ux_utility_memory_copy               Copy memory block             */
62
/*    _ux_utility_memory_free               Release memory block          */
63
/*                                                                        */
64
/*  CALLED BY                                                             */
65
/*                                                                        */
66
/*    HID Class                                                           */
67
/*                                                                        */
68
/*  RELEASE HISTORY                                                       */
69
/*                                                                        */
70
/*    DATE              NAME                      DESCRIPTION             */
71
/*                                                                        */
72
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
73
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
74
/*                                            verified memset and memcpy  */
75
/*                                            cases,                      */
76
/*                                            resulting in version 6.1    */
77
/*  08-02-2021     Wen Wang                 Modified comment(s),          */
78
/*                                            fixed spelling error,       */
79
/*                                            resulting in version 6.1.8  */
80
/*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
81
/*                                            fixed field managing issue, */
82
/*                                            improved usage handling,    */
83
/*                                            resulting in version 6.3.0  */
84
/*                                                                        */
85
/**************************************************************************/
86
2021
UINT  _ux_host_class_hid_report_add(UX_HOST_CLASS_HID *hid, UCHAR *descriptor, UX_HOST_CLASS_HID_ITEM *item)
87
{
88
89
UX_HOST_CLASS_HID_PARSER    *hid_parser;
90
ULONG                       hid_field_value;
91
ULONG                       hid_field_count;
92
UX_HOST_CLASS_HID_REPORT    *new_hid_report;
93
UX_HOST_CLASS_HID_REPORT    *hid_report;
94
UX_HOST_CLASS_HID_FIELD     *hid_field;
95
UX_HOST_CLASS_HID_FIELD     *new_hid_field;
96
ULONG                       current_field_address;
97
98
99
    /* Get the parser structure pointer.  */
100
2021
    hid_parser =  &hid -> ux_host_class_hid_parser;
101
102
    /* Obtain the field value from the report.  */
103
2021
    hid_field_value =  _ux_host_class_hid_item_data_get(descriptor, item);
104
105
    /* Allocate some memory to store this new report.  */
106
2021
    new_hid_report =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_HID_REPORT));
107
2021
    if (new_hid_report == UX_NULL)
108
30
        return(UX_MEMORY_INSUFFICIENT);
109
110
    /* We need to select the report entry based on the type of report. If the entry in the
111
       report chain is NULL, this is the first report so update the start of the chain.  */
112

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

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