1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
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.1.8 */
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 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
74 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
75 /* verified memset and memcpy */
76 /* cases, */
77 /* resulting in version 6.1 */
78 /* 08-02-2021 Wen Wang Modified comment(s), */
79 /* fixed spelling error, */
80 /* resulting in version 6.1.8 */
81 /* */
82 /**************************************************************************/
_ux_host_class_hid_report_add(UX_HOST_CLASS_HID * hid,UCHAR * descriptor,UX_HOST_CLASS_HID_ITEM * item)83 UINT _ux_host_class_hid_report_add(UX_HOST_CLASS_HID *hid, UCHAR *descriptor, UX_HOST_CLASS_HID_ITEM *item)
84 {
85
86 UX_HOST_CLASS_HID_PARSER *hid_parser;
87 ULONG hid_field_value;
88 ULONG hid_field_count;
89 UX_HOST_CLASS_HID_REPORT *new_hid_report;
90 UX_HOST_CLASS_HID_REPORT *hid_report;
91 UX_HOST_CLASS_HID_FIELD *hid_field;
92 UX_HOST_CLASS_HID_FIELD *new_hid_field;
93 ULONG current_field_address;
94
95
96 /* Get the parser structure pointer. */
97 hid_parser = &hid -> ux_host_class_hid_parser;
98
99 /* Obtain the field value from the report. */
100 hid_field_value = _ux_host_class_hid_item_data_get(descriptor, item);
101
102 /* Allocate some memory to store this new report. */
103 new_hid_report = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_HID_REPORT));
104 if (new_hid_report == UX_NULL)
105 return(UX_MEMORY_INSUFFICIENT);
106
107 /* We need to select the report entry based on the type of report. If the entry in the
108 report chain is NULL, this is the first report so update the start of the chain. */
109 switch (item -> ux_host_class_hid_item_report_tag)
110 {
111
112 case UX_HOST_CLASS_HID_MAIN_TAG_INPUT:
113
114 hid_report = hid_parser -> ux_host_class_hid_parser_input_report;
115 if (hid_report == UX_NULL)
116 hid_parser -> ux_host_class_hid_parser_input_report = new_hid_report;
117
118 /* This is a Input report. */
119 new_hid_report -> ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_INPUT;
120 break;
121
122 case UX_HOST_CLASS_HID_MAIN_TAG_OUTPUT:
123
124 hid_report = hid_parser -> ux_host_class_hid_parser_output_report;
125 if (hid_report == UX_NULL)
126 hid_parser -> ux_host_class_hid_parser_output_report = new_hid_report;
127
128 /* This is output report. */
129 new_hid_report -> ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_OUTPUT;
130 break;
131
132 case UX_HOST_CLASS_HID_MAIN_TAG_FEATURE:
133
134 hid_report = hid_parser -> ux_host_class_hid_parser_feature_report;
135 if (hid_report == UX_NULL)
136 hid_parser -> ux_host_class_hid_parser_feature_report = new_hid_report;
137
138 /* This is a Feature report. */
139 new_hid_report -> ux_host_class_hid_report_type = UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE;
140 break;
141
142
143 default:
144
145 _ux_utility_memory_free(new_hid_report);
146
147 /* Error trap. */
148 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_HID_REPORT_ERROR);
149
150 /* If trace is enabled, insert this event into the trace buffer. */
151 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_HID_REPORT_ERROR, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
152
153 /* Return an error. */
154 return(UX_HOST_CLASS_HID_REPORT_ERROR);
155 }
156
157 /* If there is a preceding report, locate the end of the report chain. */
158 if (hid_report != UX_NULL)
159 {
160
161 while (hid_report -> ux_host_class_hid_report_next_report != UX_NULL)
162 hid_report = hid_report -> ux_host_class_hid_report_next_report;
163 }
164
165 /* If this report is part of the current global report, use the last report
166 to add the fields. */
167 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))
168 {
169
170 /* So we did not need a new report after all! */
171 _ux_utility_memory_free(new_hid_report);
172 new_hid_report = hid_report;
173 }
174 else
175 {
176
177 /* We do have to build a new report. Add the new one to the chain. */
178 if (hid_report != UX_NULL)
179 hid_report -> ux_host_class_hid_report_next_report = new_hid_report;
180
181 /* Add the new report ID. */
182 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;
183 }
184
185 /* Compute the size of the report. The size is first calculated in bits. */
186 current_field_address = new_hid_report -> ux_host_class_hid_report_bit_length;
187 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*
188 hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count;
189
190 /* Now compute the size in bytes (easier for the end/receive reports functions). */
191 new_hid_report -> ux_host_class_hid_report_byte_length = new_hid_report -> ux_host_class_hid_report_bit_length >> 3;
192
193 /* Take care of the bit padding if necessary. */
194 if (new_hid_report -> ux_host_class_hid_report_bit_length & 7)
195 new_hid_report -> ux_host_class_hid_report_byte_length++;
196
197 /* Get the number of field usage for this report, this value depends on the report type. If this is
198 an array, we use the number of usages; if this a variable, we use the report count. */
199 if (hid_field_value & UX_HOST_CLASS_HID_ITEM_VARIABLE)
200 hid_field_count = hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_report_count;
201 else
202 hid_field_count = hid_parser -> ux_host_class_hid_parser_local.ux_host_class_hid_local_item_number_usage;
203
204 /* If the field count is null, this is only padding and there is no field to be allocated to the report. */
205 if (hid_field_count == 0)
206 return(UX_SUCCESS);
207
208 /* Create the field structure. */
209 new_hid_field = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_HID_FIELD));
210 if (new_hid_field == UX_NULL)
211 return(UX_MEMORY_INSUFFICIENT);
212
213 /* Attach the new field to the report. The report may already contain a field, if so parse the chain
214 until we reach the end of the chain. */
215 new_hid_report -> ux_host_class_hid_report_number_item += hid_field_count;
216 if (new_hid_report -> ux_host_class_hid_report_field == UX_NULL)
217 {
218
219 /* This is the first field for the report. */
220 new_hid_report -> ux_host_class_hid_report_field = new_hid_field;
221 }
222 else
223 {
224
225 /* We have previous HID fields, so search for the end of the chain. */
226 hid_field = new_hid_report -> ux_host_class_hid_report_field;
227 while(hid_field -> ux_host_class_hid_field_next_field != UX_NULL)
228 hid_field = hid_field -> ux_host_class_hid_field_next_field;
229
230 /* Attach the new field to the end of the chain. */
231 hid_field -> ux_host_class_hid_field_next_field = new_hid_field;
232 }
233
234 /* From the parser structure, update the new field values. Start with logical values. */
235 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;
236 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;
237
238 /* Then the usage values. Note that these are only used if the item is an array. */
239 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;
240 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;
241 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;
242
243 /* Then physical values. */
244 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;
245 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;
246
247 /* Then unit values. */
248 new_hid_field -> ux_host_class_hid_field_unit = hid_parser -> ux_host_class_hid_parser_global.ux_host_class_hid_global_item_unit;
249 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;
250
251 /* Then report values. */
252 new_hid_field -> ux_host_class_hid_field_report_type = item -> ux_host_class_hid_item_report_tag;
253 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;
254 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;
255 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;
256 new_hid_field -> ux_host_class_hid_field_report_offset = current_field_address;
257
258 /* Save the HID field value. */
259 new_hid_field -> ux_host_class_hid_field_value = hid_field_value;
260
261 /* We need some memory for the values. */
262 new_hid_field -> ux_host_class_hid_field_values = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY,
263 new_hid_field -> ux_host_class_hid_field_report_count, 4);
264
265 /* Check the memory pointer. */
266 if (new_hid_field -> ux_host_class_hid_field_values == UX_NULL)
267 {
268
269 _ux_utility_memory_free(new_hid_field);
270 return(UX_MEMORY_INSUFFICIENT);
271 }
272
273 /* We need some memory for the usages, but only for variable items; usage
274 values for array items can be calculated. */
275 if (hid_field_value & UX_HOST_CLASS_HID_ITEM_VARIABLE)
276 {
277
278 /* Allocate memory for the usages. */
279 new_hid_field -> ux_host_class_hid_field_usages = _ux_utility_memory_allocate_mulc_safe(UX_NO_ALIGN, UX_REGULAR_MEMORY, hid_field_count, 4);
280 if (new_hid_field -> ux_host_class_hid_field_usages == UX_NULL)
281 {
282
283 _ux_utility_memory_free(new_hid_field -> ux_host_class_hid_field_values);
284 _ux_utility_memory_free(new_hid_field);
285 return(UX_MEMORY_INSUFFICIENT);
286 }
287
288 /* Copy the current usages in the field structure. */
289 _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_field_count*4); /* Use case of memcpy is verified. */
290 }
291
292 /* Save the number of usages. */
293 new_hid_field -> ux_host_class_hid_field_number_usage = hid_field_count;
294
295 /* Return successful completion. */
296 return(UX_SUCCESS);
297 }
298
299