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_get                       PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function gets a report (input/output/feature) from the device. */
46 /*    The report can be either decompressed by the stack or raw.          */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    hid                                   Pointer to HID class          */
51 /*    client_report                         Pointer to client report      */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    Completion Status                                                   */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _ux_host_class_hid_report_decompress  Decompress HID report         */
60 /*    _ux_host_stack_class_instance_verify  Verify the instance is valid  */
61 /*    _ux_host_stack_transfer_request       Process transfer request      */
62 /*    _ux_utility_memory_allocate           Allocate memory block         */
63 /*    _ux_utility_memory_copy               Copy memory block             */
64 /*    _ux_utility_memory_free               Release memory block          */
65 /*    _ux_host_semaphore_get                Get protection semaphore      */
66 /*    _ux_host_semaphore_put                Release protection semaphore  */
67 /*                                                                        */
68 /*  CALLED BY                                                             */
69 /*                                                                        */
70 /*    Application                                                         */
71 /*    HID Class                                                           */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
78 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            verified memset and memcpy  */
80 /*                                            cases, accepted both INPUT  */
81 /*                                            and FEATURE reports,        */
82 /*                                            resulting in version 6.1    */
83 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
84 /*                                            added standalone support,   */
85 /*                                            resulting in version 6.1.10 */
86 /*                                                                        */
87 /**************************************************************************/
_ux_host_class_hid_report_get(UX_HOST_CLASS_HID * hid,UX_HOST_CLASS_HID_CLIENT_REPORT * client_report)88 UINT  _ux_host_class_hid_report_get(UX_HOST_CLASS_HID *hid, UX_HOST_CLASS_HID_CLIENT_REPORT *client_report)
89 {
90 #if defined(UX_HOST_STANDALONE)
91 UX_INTERRUPT_SAVE_AREA
92 #endif
93 UX_ENDPOINT                     *control_endpoint;
94 UX_TRANSFER                     *transfer_request;
95 UCHAR                           *report_buffer;
96 UX_HOST_CLASS_HID_REPORT        *hid_report;
97 UINT                            status;
98 
99     /* If trace is enabled, insert this event into the trace buffer.  */
100     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_HID_REPORT_GET, hid, client_report, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
101 
102     /* Ensure the instance is valid.  */
103     if (_ux_host_stack_class_instance_verify(_ux_system_host_class_hid_name, (VOID *) hid) != UX_SUCCESS)
104     {
105 
106         /* Error trap. */
107         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
108 
109         /* If trace is enabled, insert this event into the trace buffer.  */
110         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
111 
112         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
113     }
114 
115     /* Protect thread reentry to this instance.  */
116     _ux_host_class_hid_lock_fail_return(hid);
117 
118     /* Get the report pointer from the caller.  */
119     hid_report =  client_report -> ux_host_class_hid_client_report;
120 
121     /* Ensure this is a INPUT report or FEATURE report.  */
122     if (hid_report -> ux_host_class_hid_report_type != UX_HOST_CLASS_HID_REPORT_TYPE_INPUT &&
123         hid_report -> ux_host_class_hid_report_type != UX_HOST_CLASS_HID_REPORT_TYPE_FEATURE)
124     {
125 
126         /* Unprotect thread reentry to this instance.  */
127         _ux_host_class_hid_unlock(hid);
128 
129         /* If trace is enabled, insert this event into the trace buffer.  */
130         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_HID_REPORT_ERROR, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
131 
132         /* Return error.  */
133         return(UX_HOST_CLASS_HID_REPORT_ERROR);
134     }
135 
136     /* Check the report length, if 0, we don't need to do anything.  */
137     if (hid_report -> ux_host_class_hid_report_byte_length == 0)
138     {
139 
140         /* Unprotect thread reentry to this instance.  */
141         _ux_host_class_hid_unlock(hid);
142 
143         /* Error trap. */
144         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_HID_REPORT_ERROR);
145 
146         /* If trace is enabled, insert this event into the trace buffer.  */
147         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_HID_REPORT_ERROR, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
148 
149         /* Return error code.  */
150         return(UX_HOST_CLASS_HID_REPORT_ERROR);
151     }
152 
153     /* Get some memory for reading the report.  */
154     report_buffer =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, hid_report -> ux_host_class_hid_report_byte_length);
155     if (report_buffer == UX_NULL)
156     {
157 
158         /* Unprotect thread reentry to this instance.  */
159         _ux_host_class_hid_unlock(hid);
160 
161         /* Return error code.  */
162         return(UX_MEMORY_INSUFFICIENT);
163     }
164 
165     /* We need to get the default control endpoint transfer request pointer.  */
166     control_endpoint =  &hid -> ux_host_class_hid_device -> ux_device_control_endpoint;
167     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
168 
169     /* Protect the control endpoint semaphore here.  It will be unprotected in the
170        transfer request function.  */
171 #if defined(UX_HOST_STANDALONE)
172     UX_DISABLE
173     if (hid -> ux_host_class_hid_device -> ux_device_flags & UX_DEVICE_FLAG_LOCK)
174     {
175         _ux_utility_memory_free(report_buffer);
176         hid -> ux_host_class_hid_flags &= ~UX_HOST_CLASS_HID_FLAG_LOCK;
177         UX_RESTORE
178         return(UX_BUSY);
179     }
180     hid -> ux_host_class_hid_device -> ux_device_flags |= UX_DEVICE_FLAG_LOCK;
181     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_DEVICE_UNLOCK;
182     UX_TRANSFER_STATE_RESET(transfer_request);
183     UX_RESTORE
184 #else
185     status =  _ux_host_semaphore_get(&hid -> ux_host_class_hid_device -> ux_device_protection_semaphore, UX_WAIT_FOREVER);
186 
187     /* Check for status.  */
188     if (status != UX_SUCCESS)
189     {
190 
191         /* Something went wrong. */
192 
193         /* Free all resources.  */
194         _ux_utility_memory_free(report_buffer);
195 
196         /* Unprotect thread reentry to this instance.  */
197         _ux_host_class_hid_unlock(hid);
198 
199         return(status);
200     }
201 #endif
202 
203     /* Create a transfer request for the GET_REPORT request.  */
204     transfer_request -> ux_transfer_request_data_pointer =      report_buffer;
205     transfer_request -> ux_transfer_request_requested_length =  hid_report -> ux_host_class_hid_report_byte_length;
206     transfer_request -> ux_transfer_request_function =          UX_HOST_CLASS_HID_GET_REPORT;
207     transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
208     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);
209     transfer_request -> ux_transfer_request_index =             hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber;
210 
211     /* Send request to HCD layer.  */
212     status =  _ux_host_stack_transfer_request(transfer_request);
213 
214     /* Check for correct transfer and entire descriptor returned.  */
215     if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == hid_report -> ux_host_class_hid_report_byte_length))
216     {
217 
218         /* The report is now in memory in a raw format. The application may desire to keep it that way!  */
219         if (client_report -> ux_host_class_hid_client_report_flags & UX_HOST_CLASS_HID_REPORT_RAW)
220         {
221 
222             /* Ensure the user has given us enough memory for the raw buffer.  */
223             if (client_report -> ux_host_class_hid_client_report_length >= transfer_request -> ux_transfer_request_actual_length)
224             {
225 
226                 /* We have enough memory to store the raw buffer.  */
227                 _ux_utility_memory_copy(client_report -> ux_host_class_hid_client_report_buffer, report_buffer, transfer_request -> ux_transfer_request_actual_length); /* Use case of memcpy is verified. */
228 
229                 /* Set status to success.  */
230                 status =  UX_SUCCESS;
231             }
232             else
233             {
234 
235                 /* Error trap. */
236                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW);
237 
238                 /* If trace is enabled, insert this event into the trace buffer.  */
239                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_BUFFER_OVERFLOW, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
240 
241                 /* Set overflow status.  */
242                 status =  UX_BUFFER_OVERFLOW;
243             }
244         }
245         else
246         {
247 
248             /* The report buffer must be parsed and decompressed.  */
249             status =  _ux_host_class_hid_report_decompress(hid, client_report, report_buffer, transfer_request -> ux_transfer_request_actual_length);
250         }
251     }
252     else
253     {
254 
255         /* Error trap. */
256         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_HID_REPORT_ERROR);
257 
258         /* If trace is enabled, insert this event into the trace buffer.  */
259         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_HID_REPORT_ERROR, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
260 
261         /* Set report error status.  */
262         status =  UX_HOST_CLASS_HID_REPORT_ERROR;
263     }
264 
265     /* Free all resources.  */
266     _ux_utility_memory_free(report_buffer);
267 
268     /* Unprotect thread reentry to this instance.  */
269     _ux_host_class_hid_unlock(hid);
270 
271     /* Return the completion status.  */
272     return(status);
273 }
274 
275