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