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_transfer_request_completed       PORTABLE C      */
38 /*                                                           6.2.1        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function is called by the completion thread when a transfer    */
46 /*    request has been completed either because the transfer is           */
47 /*    successful or there was an error.                                   */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    transfer_request                      Pointer to transfer request   */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    (ux_host_class_hid_report_callback_function)                        */
60 /*                                          Callback function for report  */
61 /*    _ux_host_class_hid_report_decompress  Decompress HID report         */
62 /*    _ux_host_stack_transfer_request       Process transfer request      */
63 /*    _ux_utility_memory_allocate           Allocate memory block         */
64 /*    _ux_utility_memory_free               Release memory block          */
65 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    HID Class                                                           */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
75 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            resulting in version 6.1    */
77 /*  03-08-2023     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            supported report IDs,       */
79 /*                                            resulting in version 6.2.1  */
80 /*                                                                        */
81 /**************************************************************************/
_ux_host_class_hid_transfer_request_completed(UX_TRANSFER * transfer_request)82 VOID  _ux_host_class_hid_transfer_request_completed(UX_TRANSFER *transfer_request)
83 {
84 
85 UX_HOST_CLASS_HID                   *hid;
86 UX_HOST_CLASS_HID_CLIENT            *hid_client;
87 UX_HOST_CLASS_HID_REPORT            *hid_report;
88 UINT                                status;
89 VOID                                *report_buffer;
90 UX_HOST_CLASS_HID_REPORT_CALLBACK   callback;
91 UX_HOST_CLASS_HID_CLIENT_REPORT     client_report;
92 ULONG                               *client_buffer;
93 UX_HOST_CLASS_HID_FIELD             *hid_field;
94 ULONG                               field_report_count;
95 
96     /* Set Status to success. Optimistic view.  */
97     status = UX_SUCCESS;
98 
99     /* Get the class instance for this transfer request.  */
100     hid =  (UX_HOST_CLASS_HID *) transfer_request -> ux_transfer_request_class_instance;
101 
102     /* Check the state of the transfer.  If there is an error, we do not proceed with this report.  */
103     if (transfer_request -> ux_transfer_request_completion_code != UX_SUCCESS)
104     {
105 
106         /* We have an error. We do not rehook another transfer if the device instance is shutting down or
107            if the transfer was aborted by the class.  */
108         if ((hid -> ux_host_class_hid_state ==  UX_HOST_CLASS_INSTANCE_SHUTDOWN) ||
109             (transfer_request -> ux_transfer_request_completion_code == UX_TRANSFER_STATUS_ABORT))
110 
111             /* We do not proceed.  */
112             return;
113 
114         else
115         {
116 
117             /* Reactivate the HID interrupt pipe.  */
118             _ux_host_stack_transfer_request(transfer_request);
119 
120             /* We do not proceed.  */
121             return;
122         }
123     }
124 
125     /* Get the client instance attached to the HID.  */
126     hid_client =  hid -> ux_host_class_hid_client;
127 
128     /* Get the pointer to the report buffer in the transfer request.  */
129     report_buffer =  transfer_request -> ux_transfer_request_data_pointer;
130 
131     /* We know this incoming report is for the Input report.  */
132     hid_report =  hid -> ux_host_class_hid_parser.ux_host_class_hid_parser_input_report;
133 
134     /* If there are multiple HID reports, report ID must be checked.  */
135     if (hid_report -> ux_host_class_hid_report_next_report != UX_NULL)
136     {
137 
138         /* Scan the reports to find the report expected. */
139         while(1)
140         {
141 
142             /* Check report ID at buffer start.  */
143             if (*(UCHAR*)report_buffer == hid_report -> ux_host_class_hid_report_id)
144                 break;
145 
146             /* If there is no more report, it's done.  */
147             if (hid_report -> ux_host_class_hid_report_next_report == UX_NULL)
148                 break;
149 
150             /* There is more reports, next.  */
151             hid_report = hid_report -> ux_host_class_hid_report_next_report;
152         }
153 
154         /* Check if the report is what we expected.  */
155         if (*(UCHAR*)report_buffer != hid_report -> ux_host_class_hid_report_id)
156 
157             /* Report not found.  */
158             hid_report = UX_NULL;
159     }
160 
161     /* For this report to be used, the HID client must have registered
162        the report. We check the call back function.  */
163     if ((hid_report != UX_NULL) &&
164         (hid_report -> ux_host_class_hid_report_callback_function != UX_NULL))
165     {
166 
167         /* initialize some of the callback structure which are generic to any
168            reporting method.  */
169         callback.ux_host_class_hid_report_callback_client =  hid_client;
170         callback.ux_host_class_hid_report_callback_id =      hid_report -> ux_host_class_hid_report_id;
171 
172         /* The report is now in memory in a raw format the application may desire to handle it that way!  */
173         if (hid_report -> ux_host_class_hid_report_callback_flags & UX_HOST_CLASS_HID_REPORT_RAW)
174         {
175 
176             /* Put the length of the report in raw form in the callers callback structure.  */
177             callback.ux_host_class_hid_report_callback_actual_length =  transfer_request -> ux_transfer_request_actual_length;
178             callback.ux_host_class_hid_report_callback_buffer =         report_buffer;
179 
180             /* Build the callback structure status.  */
181             callback.ux_host_class_hid_report_callback_status =  status;
182 
183             /* Set the flags to indicate the type of report.  */
184             callback.ux_host_class_hid_report_callback_flags =  hid_report -> ux_host_class_hid_report_callback_flags;
185 
186             /* Call the report owner.  */
187             hid_report -> ux_host_class_hid_report_callback_function(&callback);
188         }
189         else
190         {
191 
192             /* The report may be decompressed, buffer length is based on number of items in report.
193                Each item is a pair of words (usage and the value itself), so the required decompress memory for each
194                item is 4 (word size) * 2 (number of word) = 8 bytes.
195                To accelerate we shift number of item by 3 to get the result.  */
196             if (UX_OVERFLOW_CHECK_MULC_ULONG(hid_report->ux_host_class_hid_report_number_item, 8))
197                 client_buffer = UX_NULL;
198             else
199             {
200                 client_report.ux_host_class_hid_client_report_length = hid_report->ux_host_class_hid_report_number_item << 3;
201 
202                 /* We need to allocate some memory to build the decompressed report.  */
203                 client_buffer =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, client_report.ux_host_class_hid_client_report_length);
204             }
205 
206             /* Check completion status.  */
207             if (client_buffer == UX_NULL)
208             {
209                 /* We have an error of memory, do not proceed */
210                 status =  UX_MEMORY_INSUFFICIENT;
211             }
212             else
213             {
214 
215                 /* We need to build a client structure to be used by the decompression engine.  */
216                 client_report.ux_host_class_hid_client_report_buffer =         client_buffer;
217                 client_report.ux_host_class_hid_client_report_actual_length =  0;
218                 client_report.ux_host_class_hid_client_report =                hid_report;
219 
220                 /* The report buffer must be parsed and decompressed into the local buffer.  */
221                 _ux_host_class_hid_report_decompress(hid, &client_report, report_buffer, transfer_request -> ux_transfer_request_actual_length);
222 
223                 /* The report may be decompressed and returned as individual Usages.  */
224                 if (hid_report -> ux_host_class_hid_report_callback_flags & UX_HOST_CLASS_HID_REPORT_INDIVIDUAL_USAGE)
225                 {
226 
227                     /* Now, we need to call the HID client call back function with a usage/value couple.  */
228                     hid_field =  hid_report -> ux_host_class_hid_report_field;
229 
230                     /* Set the flags to indicate the type of report (usage/value couple).  */
231                     callback.ux_host_class_hid_report_callback_flags =  hid_report -> ux_host_class_hid_report_callback_flags;
232 
233                     /* The length of the buffer is irrelevant here so we reset it.  */
234                     callback.ux_host_class_hid_report_callback_actual_length =  0;
235 
236                     /* Scan all the fields and send each usage/value.   */
237                     while(hid_field != UX_NULL)
238                     {
239 
240                         /* Build each report item.  */
241                         for (field_report_count = 0; field_report_count < hid_field -> ux_host_class_hid_field_report_count; field_report_count++)
242                         {
243 
244                             /* Insert the usage and the report value into the callback structure.  */
245                             callback.ux_host_class_hid_report_callback_usage =  *client_report.ux_host_class_hid_client_report_buffer++;
246                             callback.ux_host_class_hid_report_callback_value =  *client_report.ux_host_class_hid_client_report_buffer++;
247 
248                             /* Build the callback structure status.  */
249                             callback.ux_host_class_hid_report_callback_status =  status;
250 
251                             /* Call the report owner */
252                             hid_report -> ux_host_class_hid_report_callback_function(&callback);
253                         }
254 
255                         /* Get the next field.  */
256                         hid_field =  hid_field -> ux_host_class_hid_field_next_field;
257                     }
258                 }
259                 else
260                 {
261 
262                     /* Add the length actually valid in the caller's buffer.  */
263                     callback.ux_host_class_hid_report_callback_actual_length =  client_report.ux_host_class_hid_client_report_actual_length;
264 
265                     /* Add the caller's buffer address.  */
266                     callback.ux_host_class_hid_report_callback_buffer =  client_report.ux_host_class_hid_client_report_buffer;
267 
268                     /* Build the callback structure status.  */
269                     callback.ux_host_class_hid_report_callback_status =  status;
270 
271                     /* Set the flags to indicate the type of report.  */
272                     callback.ux_host_class_hid_report_callback_flags =  hid_report -> ux_host_class_hid_report_callback_flags;
273 
274                     /* Call the report owner.  */
275                     hid_report -> ux_host_class_hid_report_callback_function(&callback);
276                 }
277 
278                 /* Free the memory resource we used.  */
279                 _ux_utility_memory_free(client_buffer);
280             }
281         }
282     }
283 
284     /* Check latest status.  */
285     if (status != UX_SUCCESS)
286 
287         /* Error trap. */
288         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
289 
290     /* Reactivate the HID interrupt pipe.  */
291     status =  _ux_host_stack_transfer_request(transfer_request);
292 
293     /* Check latest status.  */
294     if (status != UX_SUCCESS)
295 
296         /* Error trap. */
297         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
298 
299     /* Return to caller.  */
300     return;
301 }
302 
303