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