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 #if !defined(UX_HOST_STANDALONE)
34
35 /* Inline the function to let compiler optimize. */
36 static inline
37 #else
38
39 /* Prototype the function to remove warnings. */
40 UINT ux_host_class_hid_report_set_buffer_allocate(
41 UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report,
42 UCHAR **allocated);
43 #endif
ux_host_class_hid_report_set_buffer_allocate(UX_HOST_CLASS_HID * hid,UX_HOST_CLASS_HID_CLIENT_REPORT * client_report,UCHAR ** allocated)44 UINT ux_host_class_hid_report_set_buffer_allocate(
45 UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report,
46 UCHAR **allocated)
47 {
48
49 UX_HOST_CLASS_HID_REPORT *hid_report;
50 UCHAR *report_buffer;
51 UCHAR *current_report_buffer;
52
53 /* Get the report pointer from the caller. */
54 hid_report = client_report -> ux_host_class_hid_client_report;
55
56 /* Ensure this is NOT an INPUT report. */
57 if (hid_report -> ux_host_class_hid_report_type == UX_HOST_CLASS_HID_REPORT_TYPE_INPUT)
58 {
59
60 /* Return error code. */
61 return(UX_HOST_CLASS_HID_REPORT_ERROR);
62 }
63
64 /* Get some memory for sending the report. */
65 if (hid_report -> ux_host_class_hid_report_id == 0)
66 report_buffer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, hid_report -> ux_host_class_hid_report_byte_length);
67 else
68 report_buffer = _ux_utility_memory_allocate_add_safe(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, hid_report -> ux_host_class_hid_report_byte_length, 1);
69 if (report_buffer == UX_NULL)
70 {
71
72 /* Return error code. */
73 return(UX_MEMORY_INSUFFICIENT);
74 }
75
76 /* Memorize the start of the real report buffer. */
77 current_report_buffer = report_buffer;
78
79 /* Check if there is a report ID to be inserted in front of the buffer. */
80 if (hid_report -> ux_host_class_hid_report_id != 0)
81 *current_report_buffer++ = (UCHAR)(hid_report -> ux_host_class_hid_report_id);
82
83 /* The report is in the client's buffer. It may be raw or or decompressed. If decompressed,
84 we need to create the report. */
85 if (client_report -> ux_host_class_hid_client_report_flags & UX_HOST_CLASS_HID_REPORT_RAW)
86 {
87
88 /* Ensure the user is not trying to overflow the report buffer. */
89 if (hid_report -> ux_host_class_hid_report_byte_length >= client_report -> ux_host_class_hid_client_report_length)
90 {
91
92 /* We have enough memory to store the raw buffer. */
93 _ux_utility_memory_copy(current_report_buffer, client_report -> ux_host_class_hid_client_report_buffer, hid_report -> ux_host_class_hid_report_byte_length); /* Use case of memcpy is verified. */
94 }
95 else
96 {
97
98 /* Free allocated buffer. */
99 _ux_utility_memory_free(report_buffer);
100
101 /* Return error code. */
102 return(UX_HOST_CLASS_HID_REPORT_OVERFLOW);
103 }
104 }
105 else
106 {
107
108 /* The report buffer has to be compressed. */
109 _ux_host_class_hid_report_compress(hid, client_report, current_report_buffer, client_report -> ux_host_class_hid_client_report_length);
110 }
111
112 /* Buffer is allocated and report data copied. */
113 *allocated = report_buffer;
114 return(UX_SUCCESS);
115 }
116
117 /**************************************************************************/
118 /* */
119 /* FUNCTION RELEASE */
120 /* */
121 /* _ux_host_class_hid_report_set PORTABLE C */
122 /* 6.1.10 */
123 /* AUTHOR */
124 /* */
125 /* Chaoqiong Xiao, Microsoft Corporation */
126 /* */
127 /* DESCRIPTION */
128 /* */
129 /* This function sets a report (input/output/feature) to the device. */
130 /* The report can be either decompressed by the stack or raw. */
131 /* */
132 /* INPUT */
133 /* */
134 /* hid Pointer to HID class */
135 /* client_report Pointer to client report */
136 /* */
137 /* OUTPUT */
138 /* */
139 /* Completion Status */
140 /* */
141 /* CALLS */
142 /* */
143 /* _ux_host_class_hid_report_compress Compress HID report */
144 /* _ux_host_stack_class_instance_verify Verify the instance is valid */
145 /* _ux_host_stack_transfer_request Process transfer request */
146 /* _ux_utility_memory_allocate Allocate memory block */
147 /* _ux_utility_memory_copy Copy memory block */
148 /* _ux_utility_memory_free Release memory block */
149 /* _ux_host_semaphore_get Get protection semaphore */
150 /* _ux_host_semaphore_put Release protection semaphore */
151 /* */
152 /* CALLED BY */
153 /* */
154 /* Application */
155 /* HID Class */
156 /* */
157 /* RELEASE HISTORY */
158 /* */
159 /* DATE NAME DESCRIPTION */
160 /* */
161 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
162 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
163 /* verified memset and memcpy */
164 /* cases, */
165 /* resulting in version 6.1 */
166 /* 01-31-2022 Xiuwen Cai, CQ Xiao Modified comment(s), */
167 /* added interrupt OUT support,*/
168 /* added standalone support, */
169 /* refined code sequence, */
170 /* resulting in version 6.1.10 */
171 /* */
172 /**************************************************************************/
_ux_host_class_hid_report_set(UX_HOST_CLASS_HID * hid,UX_HOST_CLASS_HID_CLIENT_REPORT * client_report)173 UINT _ux_host_class_hid_report_set(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report)
174 {
175 #if defined(UX_HOST_STANDALONE)
176 UINT status;
177 do
178 {
179 status = _ux_host_class_hid_report_set_run(hid, client_report);
180 } while(status == UX_STATE_WAIT || status == UX_STATE_LOCK);
181 return(hid -> ux_host_class_hid_status);
182 #else
183
184 UX_ENDPOINT *control_endpoint;
185 UX_TRANSFER *transfer_request;
186 UCHAR *report_buffer;
187 UX_HOST_CLASS_HID_REPORT *hid_report;
188 UINT status;
189
190 /* If trace is enabled, insert this event into the trace buffer. */
191 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_HID_REPORT_SET, hid, client_report, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
192
193 /* Ensure the instance is valid. */
194 if (_ux_host_stack_class_instance_verify(_ux_system_host_class_hid_name, (VOID *) hid) != UX_SUCCESS)
195 {
196
197 /* Error trap. */
198 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
199
200 /* If trace is enabled, insert this event into the trace buffer. */
201 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
202
203 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
204 }
205
206 /* Protect thread reentry to this instance. */
207 _ux_host_class_hid_lock_fail_return(hid);
208
209 /* Get the report pointer from the caller. */
210 hid_report = client_report -> ux_host_class_hid_client_report;
211 #if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
212
213 /* Check if there is an interrupt OUT endpoint. */
214 if (hid -> ux_host_class_hid_interrupt_out_endpoint != UX_NULL)
215 {
216
217 /* Transfer the report by using the interrupt OUT endpoint. */
218 transfer_request = &hid -> ux_host_class_hid_interrupt_out_endpoint -> ux_endpoint_transfer_request;
219 }
220 else
221 {
222 #endif
223 /* We need to get the default control endpoint transfer request pointer. */
224 control_endpoint = &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
225 transfer_request = &control_endpoint -> ux_endpoint_transfer_request;
226
227 /* Protect the control endpoint semaphore here. It will be unprotected in the
228 transfer request function. */
229 status = _ux_host_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
230
231 /* Check for status. */
232 if (status != UX_SUCCESS)
233 {
234
235 /* Something went wrong. */
236 /* Unprotect thread reentry to this instance. */
237 _ux_host_class_hid_unlock(hid);
238 return(status);
239 }
240 #if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
241 }
242 #endif
243 /* Build the report buffer for SET_REPORT request. */
244 status = ux_host_class_hid_report_set_buffer_allocate(hid, client_report, &report_buffer);
245 if (status != UX_SUCCESS)
246 {
247
248 /* Unlock device control endpoint. */
249 _ux_host_semaphore_put(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore);
250
251 /* Unprotect thread reentry to this instance. */
252 _ux_host_class_hid_unlock(hid);
253
254 /* Error trap. */
255 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
256
257 /* If trace is enabled, insert this event into the trace buffer. */
258 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, status, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
259
260 return(status);
261 }
262
263 /* Create a transfer request for the SET_REPORT request. */
264 transfer_request -> ux_transfer_request_data_pointer = report_buffer;
265 transfer_request -> ux_transfer_request_requested_length = hid_report -> ux_host_class_hid_report_byte_length;
266 transfer_request -> ux_transfer_request_function = UX_HOST_CLASS_HID_SET_REPORT;
267 transfer_request -> ux_transfer_request_type = UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
268 transfer_request -> ux_transfer_request_value = (UINT)((USHORT) hid_report -> ux_host_class_hid_report_id | (USHORT) hid_report -> ux_host_class_hid_report_type << 8);
269 transfer_request -> ux_transfer_request_index = hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber;
270
271 /* Send request to HCD layer. */
272 status = _ux_host_stack_transfer_request(transfer_request);
273 #if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
274
275 /* Check if interrupt OUT endpoint is used. */
276 if ((hid -> ux_host_class_hid_interrupt_out_endpoint != UX_NULL) && (status == UX_SUCCESS))
277 {
278
279 /* We need to wait for the completion of the transfer request. */
280 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_HID_REPORT_TRANSFER_TIMEOUT));
281 }
282 #endif
283
284 /* Check for correct transfer and the actual transfer length. */
285 if ((status != UX_SUCCESS) || (transfer_request -> ux_transfer_request_actual_length != hid_report -> ux_host_class_hid_report_byte_length))
286 {
287 #if defined(UX_HOST_CLASS_HID_INTERRUPT_OUT_SUPPORT)
288
289 /* Check if interrupt OUT endpoint is used. */
290 if ((hid -> ux_host_class_hid_interrupt_out_endpoint != UX_NULL) && (status != UX_SUCCESS))
291 {
292
293 /* We need to abort the transfer request. */
294 _ux_host_stack_transfer_request_abort(transfer_request);
295 }
296 #endif
297
298 /* Error trap. */
299 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_HID_REPORT_ERROR);
300
301 /* If trace is enabled, insert this event into the trace buffer. */
302 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_HID_REPORT_ERROR, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
303
304 status = UX_HOST_CLASS_HID_REPORT_ERROR;
305 }
306
307 /* Free all resources. */
308 _ux_utility_memory_free(report_buffer);
309
310 /* Unprotect thread reentry to this instance. */
311 _ux_host_class_hid_unlock(hid);
312
313 /* Return the function status */
314 return(status);
315 #endif
316 }
317
318