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