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_run                       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 standalone 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 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    Application                                                         */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  07-29-2022     Chaoqiong Xiao           Initial Version 6.1.12        */
76 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            added zero copy support,    */
78 /*                                            resulting in version 6.3.0  */
79 /*                                                                        */
80 /**************************************************************************/
_ux_device_class_hid_read_run(UX_SLAVE_CLASS_HID * hid,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)81 UINT _ux_device_class_hid_read_run(UX_SLAVE_CLASS_HID *hid, UCHAR *buffer,
82                                    ULONG requested_length, ULONG *actual_length)
83 {
84 #if !defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
85     UX_PARAMETER_NOT_USED(hid);
86     UX_PARAMETER_NOT_USED(buffer);
87     UX_PARAMETER_NOT_USED(requested_length);
88     UX_PARAMETER_NOT_USED(actual_length);
89     return(UX_FUNCTION_NOT_SUPPORTED);
90 #else
91 
92 UX_SLAVE_ENDPOINT           *endpoint;
93 UX_SLAVE_DEVICE             *device;
94 UX_SLAVE_TRANSFER           *transfer_request;
95 UINT                        read_state;
96 UINT                        status= UX_SUCCESS;
97 
98 
99     /* If trace is enabled, insert this event into the trace buffer.  */
100     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_HID_READ, hid, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
101 
102     /* Get the pointer to the device.  */
103     device =  &_ux_system_slave -> ux_system_slave_device;
104 
105     /* As long as the device is in the CONFIGURED state.  */
106     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
107     {
108 
109         /* Error trap. */
110         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
111 
112         /* If trace is enabled, insert this event into the trace buffer.  */
113         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
114 
115         /* Cannot proceed with command, the interface is down.  */
116         hid -> ux_device_class_hid_read_state = UX_STATE_RESET;
117         hid -> ux_device_class_hid_read_status = UX_CONFIGURATION_HANDLE_UNKNOWN;
118         return(UX_STATE_EXIT);
119     }
120 
121     /* Locate the endpoint.  */
122     endpoint =  hid -> ux_device_class_hid_read_endpoint;
123 
124     /* Check endpoint. If NULL, we have not yet received the proper SET_INTERFACE command.  */
125     if (endpoint == UX_NULL)
126     {
127         /* Error trap. */
128         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN);
129 
130         hid -> ux_device_class_hid_read_state = UX_STATE_RESET;
131         hid -> ux_device_class_hid_read_status = UX_CONFIGURATION_HANDLE_UNKNOWN;
132         return(UX_STATE_EXIT);
133     }
134 
135     /* All HID reading  are on the endpoint OUT, from the host.  */
136     transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
137 
138     /* Handle state cases.  */
139     read_state = hid -> ux_device_class_hid_read_state;
140 
141 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
142 
143     if (read_state == UX_STATE_RESET)
144     {
145 
146         /* Initialize read states.  */
147         hid -> ux_device_class_hid_read_state = UX_DEVICE_CLASS_HID_READ_START;
148         hid -> ux_device_class_hid_read_status = UX_TRANSFER_NO_ANSWER;
149 
150         /* Set the data pointer to the buffer.  */
151         transfer_request -> ux_slave_transfer_request_data_pointer = buffer;
152 
153         /* Reset request state.  */
154         UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
155     }
156 
157     /* Send the request to the device controller.  */
158     status =  _ux_device_stack_transfer_run(transfer_request, requested_length, requested_length);
159 
160     /* Error/success case.  */
161     if (status <= UX_STATE_NEXT)
162     {
163 
164         /* Update actual length.  */
165         *actual_length = transfer_request -> ux_slave_transfer_request_actual_length;
166 
167         /* Last transfer status.  */
168         hid -> ux_device_class_hid_read_status =
169             transfer_request -> ux_slave_transfer_request_completion_code;
170 
171         /* Reset read state.  */
172         hid -> ux_device_class_hid_read_state = UX_STATE_RESET;
173     }
174 
175     /* Return status indicator.  */
176     return(status);
177 
178 #else
179     switch(read_state)
180     {
181     case UX_STATE_RESET:
182         hid -> ux_device_class_hid_read_state = UX_DEVICE_CLASS_HID_READ_START;
183         hid -> ux_device_class_hid_read_status = UX_TRANSFER_NO_ANSWER;
184         hid -> ux_device_class_hid_read_buffer = buffer;
185         hid -> ux_device_class_hid_read_requested_length = requested_length;
186         hid -> ux_device_class_hid_read_actual_length = 0;
187 
188         /* Fall through.  */
189     case UX_DEVICE_CLASS_HID_READ_START:
190 
191         /* Get remaining requested length.  */
192         requested_length = hid -> ux_device_class_hid_read_requested_length -
193                         hid -> ux_device_class_hid_read_actual_length;
194 
195         /* There is no remaining, we are done.  */
196         if (requested_length == 0)
197         {
198             *actual_length = hid -> ux_device_class_hid_read_actual_length;
199             hid -> ux_device_class_hid_read_state = UX_STATE_RESET;
200             hid -> ux_device_class_hid_read_status = UX_SUCCESS;
201             return(UX_STATE_NEXT);
202         }
203 
204         /* Check if we have enough in the local buffer.  */
205         if (requested_length > UX_SLAVE_REQUEST_DATA_MAX_LENGTH)
206 
207             /* We have too much to transfer.  */
208             hid -> ux_device_class_hid_read_transfer_length = UX_SLAVE_REQUEST_DATA_MAX_LENGTH;
209 
210         else
211 
212             /* We can proceed with the demanded length.  */
213             hid -> ux_device_class_hid_read_transfer_length = requested_length;
214 
215         /* Next state.  */
216         hid -> ux_device_class_hid_read_state = UX_DEVICE_CLASS_HID_READ_WAIT;
217         UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
218 
219         /* Fall through.  */
220     case UX_DEVICE_CLASS_HID_READ_WAIT:
221 
222         /* Send the request to the device controller.  */
223         status =  _ux_device_stack_transfer_run(transfer_request,
224                             hid -> ux_device_class_hid_read_transfer_length,
225                             hid -> ux_device_class_hid_read_transfer_length);
226 
227         /* Error case.  */
228         if (status < UX_STATE_NEXT)
229         {
230 
231             hid -> ux_device_class_hid_read_state = UX_STATE_RESET;
232             hid -> ux_device_class_hid_read_status =
233                 transfer_request -> ux_slave_transfer_request_completion_code;
234             return(UX_STATE_EXIT);
235         }
236 
237         /* Success case.  */
238         if (status == UX_STATE_NEXT)
239         {
240 
241             /* We need to copy the buffer locally.  */
242             _ux_utility_memory_copy(hid -> ux_device_class_hid_read_buffer,
243                     transfer_request -> ux_slave_transfer_request_data_pointer,
244                     transfer_request -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */
245 
246             /* Next buffer address.  */
247             hid -> ux_device_class_hid_read_buffer +=
248                     transfer_request -> ux_slave_transfer_request_actual_length;
249 
250             /* Set the length actually received. */
251             hid -> ux_device_class_hid_read_actual_length +=
252                     transfer_request -> ux_slave_transfer_request_actual_length;
253 
254             /* Last transfer status.  */
255             hid -> ux_device_class_hid_read_status =
256                 transfer_request -> ux_slave_transfer_request_completion_code;
257 
258             /* Update actual length.  */
259             *actual_length = hid -> ux_device_class_hid_read_actual_length;
260 
261             /* Check short packet.  */
262             if (transfer_request -> ux_slave_transfer_request_actual_length <
263                 transfer_request -> ux_slave_transfer_request_requested_length)
264             {
265 
266                 /* It's done.  */
267                 hid -> ux_device_class_hid_read_state = UX_STATE_RESET;
268                 return(UX_STATE_NEXT);
269             }
270 
271             /* Next state.  */
272             hid -> ux_device_class_hid_read_state = UX_DEVICE_CLASS_HID_READ_START;
273         }
274 
275         /* Keep waiting.  */
276         return(UX_STATE_WAIT);
277 
278     /* Receiver running states.  */
279     case UX_DEVICE_CLASS_HID_RECEIVER_START:    /* Fall through.  */
280     case UX_DEVICE_CLASS_HID_RECEIVER_WAIT:     /* Fall through.  */
281     case UX_DEVICE_CLASS_HID_RECEIVER_ERROR:
282 
283         /* Receiver running.  */
284         return(UX_STATE_ERROR);
285 
286     default: /* Error.  */
287         hid -> ux_device_class_hid_read_status = UX_INVALID_STATE;
288         hid -> ux_device_class_hid_read_state = UX_STATE_RESET;
289         break;
290     }
291 
292     /* Error case.  */
293     return(UX_STATE_EXIT);
294 #endif
295 #endif
296 }
297 
298 
299 /**************************************************************************/
300 /*                                                                        */
301 /*  FUNCTION                                               RELEASE        */
302 /*                                                                        */
303 /*    _uxe_device_class_hid_read_run                      PORTABLE C      */
304 /*                                                           6.3.0        */
305 /*  AUTHOR                                                                */
306 /*                                                                        */
307 /*    Chaoqiong Xiao, Microsoft Corporation                               */
308 /*                                                                        */
309 /*  DESCRIPTION                                                           */
310 /*                                                                        */
311 /*    This function checks errors in HID read function call.              */
312 /*                                                                        */
313 /*  INPUT                                                                 */
314 /*                                                                        */
315 /*    hid                                   Pointer to hid instance       */
316 /*    buffer                                Pointer to receive buffer     */
317 /*    requested_length                      Receive buffer size in bytes  */
318 /*    actual_length                         Actual num bytes received     */
319 /*                                                                        */
320 /*  OUTPUT                                                                */
321 /*                                                                        */
322 /*    None                                                                */
323 /*                                                                        */
324 /*  CALLS                                                                 */
325 /*                                                                        */
326 /*    _ux_device_class_hid_read_run         Run read state machine once   */
327 /*                                                                        */
328 /*  CALLED BY                                                             */
329 /*                                                                        */
330 /*    Application                                                         */
331 /*                                                                        */
332 /*  RELEASE HISTORY                                                       */
333 /*                                                                        */
334 /*    DATE              NAME                      DESCRIPTION             */
335 /*                                                                        */
336 /*  10-31-2023     Chaoqiong Xiao           Initial Version 6.3.0         */
337 /*                                                                        */
338 /**************************************************************************/
_uxe_device_class_hid_read_run(UX_SLAVE_CLASS_HID * hid,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)339 UINT _uxe_device_class_hid_read_run(UX_SLAVE_CLASS_HID *hid, UCHAR *buffer,
340                                    ULONG requested_length, ULONG *actual_length)
341 {
342 
343     /* Sanity checks.  */
344     if ((hid == UX_NULL) ||
345         (buffer == UX_NULL) || (requested_length == 0) ||
346         (actual_length == UX_NULL))
347     {
348         return(UX_STATE_ERROR);
349     }
350 
351     /* Invoke function to run reading state machine.  */
352     return(_ux_device_class_hid_read_run(hid, buffer, requested_length, actual_length));
353 }
354 #endif
355