1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 /**************************************************************************/
12 /**************************************************************************/
13 /**                                                                       */
14 /** USBX Component                                                        */
15 /**                                                                       */
16 /**   Device HID Class                                                    */
17 /**                                                                       */
18 /**************************************************************************/
19 /**************************************************************************/
20 
21 #define UX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "ux_api.h"
27 #include "ux_device_class_hid.h"
28 #include "ux_device_stack.h"
29 
30 
31 #if !defined(UX_DEVICE_STANDALONE)
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_device_class_hid_read                           PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function reads from the HID class.                             */
45 /*    This function must not be used with receiver related functions.     */
46 /*    This function is for RTOS mode.                                     */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    hid                                   Address of hid class          */
51 /*                                              instance                  */
52 /*    buffer                                Pointer to buffer to save     */
53 /*                                              received data             */
54 /*    requested_length                      Length of bytes to read       */
55 /*    actual_length                         Pointer to save number of     */
56 /*                                              bytes read                */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    None                                                                */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _ux_device_stack_transfer_request     Transfer request              */
65 /*    _ux_utility_memory_copy               Copy memory                   */
66 /*    _ux_device_mutex_off                  Release mutex                 */
67 /*                                                                        */
68 /*  CALLED BY                                                             */
69 /*                                                                        */
70 /*    Application                                                         */
71 /*                                                                        */
72 /*  RELEASE HISTORY                                                       */
73 /*                                                                        */
74 /*    DATE              NAME                      DESCRIPTION             */
75 /*                                                                        */
76 /*  01-31-2022     Chaoqiong Xiao           Initial Version 6.1.10        */
77 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            fixed standalone compile,   */
79 /*                                            resulting in version 6.1.11 */
80 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            resulting in version 6.1.12 */
82 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            added zero copy support,    */
84 /*                                            resulting in version 6.3.0  */
85 /*                                                                        */
86 /**************************************************************************/
_ux_device_class_hid_read(UX_SLAVE_CLASS_HID * hid,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)87 UINT _ux_device_class_hid_read(UX_SLAVE_CLASS_HID *hid, UCHAR *buffer,
88                                 ULONG requested_length, ULONG *actual_length)
89 {
90 #if !defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
91     UX_PARAMETER_NOT_USED(hid);
92     UX_PARAMETER_NOT_USED(buffer);
93     UX_PARAMETER_NOT_USED(requested_length);
94     UX_PARAMETER_NOT_USED(actual_length);
95     return(UX_FUNCTION_NOT_SUPPORTED);
96 #else
97 
98 UX_SLAVE_ENDPOINT           *endpoint;
99 UX_SLAVE_DEVICE             *device;
100 UX_SLAVE_TRANSFER           *transfer_request;
101 UINT                        status= UX_SUCCESS;
102 ULONG                       local_requested_length;
103 
104 
105     /* If trace is enabled, insert this event into the trace buffer.  */
106     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_HID_READ, hid, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
107 
108     /* Get the pointer to the device.  */
109     device =  &_ux_system_slave -> ux_system_slave_device;
110 
111     /* As long as the device is in the CONFIGURED state.  */
112     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
113     {
114 
115         /* Error trap. */
116         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
117 
118         /* If trace is enabled, insert this event into the trace buffer.  */
119         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
120 
121         /* Cannot proceed with command, the interface is down.  */
122         return(UX_CONFIGURATION_HANDLE_UNKNOWN);
123     }
124 
125     /* Protect this thread.  */
126     _ux_device_mutex_on(&hid -> ux_device_class_hid_read_mutex);
127 
128     /* Locate the endpoint.  */
129     endpoint =  hid -> ux_device_class_hid_read_endpoint;
130 
131     /* All HID reading  are on the endpoint OUT, from the host.  */
132     transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
133 
134 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
135 
136     /* Directly use buffer from application.  */
137     transfer_request -> ux_slave_transfer_request_data_pointer = buffer;
138 
139     /* Send the request to the device controller.  */
140     local_requested_length = requested_length;
141     status =  _ux_device_stack_transfer_request(transfer_request, local_requested_length, local_requested_length);
142 
143     /* Save actual length.  */
144     *actual_length = transfer_request -> ux_slave_transfer_request_actual_length;
145 
146 #else
147 
148     /* Reset the actual length.  */
149     *actual_length =  0;
150 
151     /* Check if we need more transactions.  */
152     while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED && requested_length != 0)
153     {
154 
155         /* Check if we have enough in the local buffer.  */
156         if (requested_length > transfer_request -> ux_slave_transfer_request_transfer_length)
157 
158             /* We have too much to transfer.  */
159             local_requested_length = transfer_request -> ux_slave_transfer_request_transfer_length;
160 
161         else
162 
163             /* We can proceed with the demanded length.  */
164             local_requested_length = requested_length;
165 
166         /* Send the request to the device controller.  */
167         status =  _ux_device_stack_transfer_request(transfer_request, local_requested_length, local_requested_length);
168 
169         /* Check the status */
170         if (status == UX_SUCCESS)
171         {
172 
173             /* We need to copy the buffer locally.  */
174             _ux_utility_memory_copy(buffer, transfer_request -> ux_slave_transfer_request_data_pointer,
175                             transfer_request -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */
176 
177             /* Next buffer address.  */
178             buffer += transfer_request -> ux_slave_transfer_request_actual_length;
179 
180             /* Set the length actually received. */
181             *actual_length += transfer_request -> ux_slave_transfer_request_actual_length;
182 
183             /* Decrement what left has to be done.  */
184             requested_length -= transfer_request -> ux_slave_transfer_request_actual_length;
185 
186             /* Is this a short packet or a ZLP indicating we are done with this transfer ?  */
187             if (transfer_request -> ux_slave_transfer_request_actual_length < endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize)
188             {
189 
190                 /* We are done.  */
191                 /* Free Mutex resource.  */
192                 _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
193 
194                 /* Return with success.  */
195                 return(UX_SUCCESS);
196             }
197         }
198         else
199         {
200 
201             /* Free Mutex resource.  */
202             _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
203 
204             /* We got an error.  */
205             return(status);
206         }
207     }
208 
209 #endif
210 
211     /* Free Mutex resource.  */
212     _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
213 
214     /* Check why we got here, either completion or device was extracted.  */
215     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
216     {
217 
218         /* Error trap. */
219         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER);
220 
221         /* If trace is enabled, insert this event into the trace buffer.  */
222         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_NO_ANSWER, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
223 
224         /* Device must have been extracted.  */
225         return (UX_TRANSFER_NO_ANSWER);
226     }
227     else
228 
229         /* Simply return the last transaction result.  */
230         return(status);
231 #endif
232 }
233 
234 
235 /**************************************************************************/
236 /*                                                                        */
237 /*  FUNCTION                                               RELEASE        */
238 /*                                                                        */
239 /*    _uxe_device_class_hid_read                          PORTABLE C      */
240 /*                                                           6.3.0        */
241 /*  AUTHOR                                                                */
242 /*                                                                        */
243 /*    Chaoqiong Xiao, Microsoft Corporation                               */
244 /*                                                                        */
245 /*  DESCRIPTION                                                           */
246 /*                                                                        */
247 /*    This function checks errors in HID read function call.              */
248 /*                                                                        */
249 /*  INPUT                                                                 */
250 /*                                                                        */
251 /*    hid                                   Pointer to hid instance       */
252 /*    buffer                                Pointer to receive buffer     */
253 /*    requested_length                      Receive buffer size in bytes  */
254 /*    actual_length                         Actual num bytes received     */
255 /*                                                                        */
256 /*  OUTPUT                                                                */
257 /*                                                                        */
258 /*    None                                                                */
259 /*                                                                        */
260 /*  CALLS                                                                 */
261 /*                                                                        */
262 /*    _ux_device_class_hid_read             Read data                     */
263 /*                                                                        */
264 /*  CALLED BY                                                             */
265 /*                                                                        */
266 /*    Application                                                         */
267 /*                                                                        */
268 /*  RELEASE HISTORY                                                       */
269 /*                                                                        */
270 /*    DATE              NAME                      DESCRIPTION             */
271 /*                                                                        */
272 /*  10-31-2023     Chaoqiong Xiao           Initial Version 6.3.0         */
273 /*                                                                        */
274 /**************************************************************************/
_uxe_device_class_hid_read(UX_SLAVE_CLASS_HID * hid,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)275 UINT _uxe_device_class_hid_read(UX_SLAVE_CLASS_HID *hid, UCHAR *buffer,
276                                    ULONG requested_length, ULONG *actual_length)
277 {
278 
279     /* Sanity checks.  */
280     if ((hid == UX_NULL) ||
281         (buffer == UX_NULL) || (requested_length == 0) ||
282         (actual_length == UX_NULL))
283     {
284         return(UX_INVALID_PARAMETER);
285     }
286 
287     /* Invoke function to read data.  */
288     return(_ux_device_class_hid_read(hid, buffer, requested_length, actual_length));
289 }
290 #endif
291