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