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