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