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 /** */
15 /** USBX Component */
16 /** */
17 /** Generic Serial Host module class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_gser.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_gser_read PORTABLE C */
37 /* 6.1.11 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function reads from the gser interface. The call is */
45 /* blocking and only returns when there is either an error or when */
46 /* the transfer is complete. */
47 /* */
48 /* INPUT */
49 /* */
50 /* gser Pointer to gser class */
51 /* data_pointer Pointer to buffer */
52 /* requested_length Requested data read */
53 /* actual_length Actual data read */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* Completion Status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _ux_host_stack_transfer_request Process transfer request */
62 /* _ux_host_stack_transfer_request_abort Abort transfer request */
63 /* _ux_host_semaphore_get Get protection semaphore */
64 /* _ux_host_semaphore_put Release protection semaphore */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* Application */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
75 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
76 /* prefixed UX to MS_TO_TICK, */
77 /* resulting in version 6.1 */
78 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
79 /* refined macros names, */
80 /* resulting in version 6.1.10 */
81 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
82 /* fixed standalone compile, */
83 /* resulting in version 6.1.11 */
84 /* */
85 /**************************************************************************/
_ux_host_class_gser_read(UX_HOST_CLASS_GSER * gser,ULONG interface_index,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)86 UINT _ux_host_class_gser_read(UX_HOST_CLASS_GSER *gser,
87 ULONG interface_index,
88 UCHAR *data_pointer,
89 ULONG requested_length,
90 ULONG *actual_length)
91 {
92
93 UX_TRANSFER *transfer_request;
94 UINT status;
95 ULONG transfer_request_length;
96
97 /* If trace is enabled, insert this event into the trace buffer. */
98 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_GSER_READ, gser, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
99
100 /* Ensure the instance is valid. */
101 if (gser -> ux_host_class_gser_state != UX_HOST_CLASS_INSTANCE_LIVE)
102 {
103
104 /* Error trap. */
105 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
106
107 /* If trace is enabled, insert this event into the trace buffer. */
108 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, gser, 0, 0, UX_TRACE_ERRORS, 0, 0)
109
110 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
111 }
112
113 /* Protect thread reentry to this instance. */
114 status = _ux_host_semaphore_get(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore, UX_WAIT_FOREVER);
115 if (status != UX_SUCCESS)
116 return(status);
117
118 /* Start by resetting the actual length of the transfer to zero. */
119 *actual_length = 0;
120
121 /* Get the pointer to the bulk in endpoint in the transfer_request. */
122 transfer_request = &gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_bulk_in_endpoint -> ux_endpoint_transfer_request;
123
124 /* Save the interface number in the Transfer Request. */
125 transfer_request -> ux_transfer_request_user_specific = (VOID *)(ALIGN_TYPE)interface_index;
126
127 /* Perform a transfer on the bulk in endpoint until either the transfer is
128 completed or until there is an error. */
129 while (requested_length)
130 {
131
132 /* Program the maximum authorized length for this transfer request. */
133 if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
134 transfer_request_length = transfer_request -> ux_transfer_request_maximum_length;
135 else
136 transfer_request_length = requested_length;
137
138 /* Initialize the transfer request. */
139 transfer_request -> ux_transfer_request_data_pointer = data_pointer;
140 transfer_request -> ux_transfer_request_requested_length = transfer_request_length;
141
142 /* Perform the transfer. */
143 status = _ux_host_stack_transfer_request(transfer_request);
144
145 /* If the transfer is successful, we need to wait for the transfer request to be completed. */
146 if (status == UX_SUCCESS)
147 {
148
149 /* Wait for the completion of the transfer_request. */
150 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_GSER_CLASS_TRANSFER_TIMEOUT));
151
152 /* If the semaphore did not succeed we probably have a time out. */
153 if (status != UX_SUCCESS)
154 {
155
156 /* All transfers pending need to abort. There may have been a partial transfer. */
157 _ux_host_stack_transfer_request_abort(transfer_request);
158
159 /* Update the length of the actual data transferred. We do this after the
160 abort of the transfer request in case some data was actually received. */
161 *actual_length += transfer_request -> ux_transfer_request_actual_length;
162
163 /* Unprotect thread reentry to this instance. */
164 _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
165
166 /* Set the completion code. */
167 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT;
168
169 /* Error trap. */
170 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
171
172 /* If trace is enabled, insert this event into the trace buffer. */
173 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
174
175 /* There was an error, return to the caller */
176 return(UX_TRANSFER_TIMEOUT);
177 }
178 }
179 else
180 {
181
182 /* Unprotect thread reentry to this instance. */
183 _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
184
185 /* There was a non transfer error, no partial transfer to be checked. */
186 return(status);
187 }
188
189 /* Update the length of the transfer. Normally all the data has to be received. */
190 *actual_length += transfer_request -> ux_transfer_request_actual_length;
191
192 /* Check for completion of transfer. If the transfer is partial, return to caller.
193 The transfer is marked as successful but the caller will need to check the length
194 actually received and determine if a partial transfer is OK. */
195 if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
196 {
197
198 /* Unprotect thread reentry to this instance. */
199 _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
200
201 /* Return success to caller. */
202 return(UX_SUCCESS);
203 }
204
205 /* Update the data pointer for next transfer. */
206 data_pointer += transfer_request_length;
207
208 /* Update what is left to receive. */
209 requested_length -= transfer_request_length;
210 }
211
212 /* Unprotect thread reentry to this instance. */
213 _ux_host_semaphore_put(&gser -> ux_host_class_gser_interface_array[interface_index].ux_host_class_gser_semaphore);
214
215 /* We get here when all the transfers went through without errors. */
216 return(UX_SUCCESS);
217 }
218
219
220 /**************************************************************************/
221 /* */
222 /* FUNCTION RELEASE */
223 /* */
224 /* _uxe_host_class_gser_read PORTABLE C */
225 /* 6.3.0 */
226 /* AUTHOR */
227 /* */
228 /* Chaoqiong Xiao, Microsoft Corporation */
229 /* */
230 /* DESCRIPTION */
231 /* */
232 /* This function checks errors in GSER read function call. */
233 /* */
234 /* INPUT */
235 /* */
236 /* gser Pointer to GSER class */
237 /* data_pointer Pointer to buffer */
238 /* requested_length Requested data read */
239 /* actual_length Actual data read */
240 /* */
241 /* OUTPUT */
242 /* */
243 /* Status */
244 /* */
245 /* CALLS */
246 /* */
247 /* _ux_host_class_gser_read GSER read */
248 /* */
249 /* CALLED BY */
250 /* */
251 /* Application */
252 /* */
253 /* RELEASE HISTORY */
254 /* */
255 /* DATE NAME DESCRIPTION */
256 /* */
257 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
258 /* */
259 /**************************************************************************/
_uxe_host_class_gser_read(UX_HOST_CLASS_GSER * gser,ULONG interface_index,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)260 UINT _uxe_host_class_gser_read(UX_HOST_CLASS_GSER *gser,
261 ULONG interface_index,
262 UCHAR *data_pointer,
263 ULONG requested_length,
264 ULONG *actual_length)
265 {
266
267 /* Sanity checks. */
268 if ((gser == UX_NULL) || (data_pointer == UX_NULL) || (actual_length == UX_NULL))
269 {
270 return(UX_INVALID_PARAMETER);
271 }
272
273 /* Invoke GSER read function. */
274 return(_ux_host_class_gser_read(gser, interface_index, data_pointer, requested_length, actual_length));
275 }
276