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 /** Host Data Pump 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_dpump.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_dpump_write PORTABLE C */
37 /* 6.1.11 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function writes to the dpump interface. The call is blocking */
45 /* and only returns when there is either an error or when the transfer */
46 /* is complete. */
47 /* */
48 /* INPUT */
49 /* */
50 /* dpump Pointer to dpump class */
51 /* data_pointer Pointer to data to write */
52 /* requested_length Length of data to write */
53 /* actual_length Actual length of data written */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* Completion Status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _ux_host_stack_class_instance_verify Verify the class instance */
62 /* _ux_host_stack_transfer_request Process transfer request */
63 /* _ux_host_stack_transfer_request_abort Abort transfer request */
64 /* _ux_utility_semaphore_get Get protection semaphore */
65 /* _ux_utility_semaphore_put Release protection semaphore */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* Application */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
76 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
77 /* resulting in version 6.1 */
78 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
79 /* added standalone support, */
80 /* resulting in version 6.1.10 */
81 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
82 /* internal clean up, */
83 /* resulting in version 6.1.11 */
84 /* */
85 /**************************************************************************/
_ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP * dpump,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)86 UINT _ux_host_class_dpump_write(UX_HOST_CLASS_DPUMP *dpump, UCHAR * data_pointer,
87 ULONG requested_length, ULONG *actual_length)
88 {
89
90 #if defined(UX_HOST_STANDALONE)
91 UX_INTERRUPT_SAVE_AREA
92 #endif
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_DPUMP_WRITE, dpump, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
99
100 /* Ensure the instance is valid. */
101 if(_ux_host_stack_class_instance_verify((UCHAR *) _ux_system_host_class_dpump_name, (VOID *) dpump) != UX_SUCCESS)
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, dpump, 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 #if defined(UX_HOST_STANDALONE)
115 UX_DISABLE
116 if (dpump -> ux_host_class_dpump_flags & UX_HOST_CLASS_DPUMP_WRITE_LOCK)
117 {
118 UX_RESTORE
119 return(UX_BUSY);
120 }
121 dpump -> ux_host_class_dpump_flags |= UX_HOST_CLASS_DPUMP_WRITE_LOCK;
122 UX_RESTORE
123 #else
124 status = _ux_host_semaphore_get(&dpump -> ux_host_class_dpump_semaphore, UX_WAIT_FOREVER);
125 if (status != UX_SUCCESS)
126 return(status);
127 #endif
128
129 /* Start by resetting the actual length of the transfer. */
130 *actual_length = 0;
131
132 /* Get the pointer to the bulk out endpoint transfer request. */
133 transfer_request = &dpump -> ux_host_class_dpump_bulk_out_endpoint -> ux_endpoint_transfer_request;
134
135 #if defined(UX_HOST_STANDALONE)
136
137 /* Here wait blocking mode is used. */
138 transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
139 #endif
140
141 /* Perform a transfer on the bulk out endpoint until either the transfer is
142 completed or when there is an error. */
143 while (requested_length)
144 {
145
146 /* Program the maximum authorized length for this transfer_request. */
147 if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
148 transfer_request_length = transfer_request -> ux_transfer_request_maximum_length;
149 else
150 transfer_request_length = requested_length;
151
152 /* Initialize the transfer_request. */
153 transfer_request -> ux_transfer_request_data_pointer = data_pointer;
154 transfer_request -> ux_transfer_request_requested_length = transfer_request_length;
155
156 /* Perform the transfer. */
157 status = _ux_host_stack_transfer_request(transfer_request);
158
159 #if defined(UX_HOST_STANDALONE)
160
161 /* If the transfer is not success, return error. */
162 if (status != UX_SUCCESS)
163 {
164 dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_WRITE_LOCK;
165 return(status);
166 }
167 #else
168 /* If the transfer is successful, we need to wait for the transfer request to be completed. */
169 if (status == UX_SUCCESS)
170 {
171
172 /* Wait for the completion of the transfer request. */
173 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_HOST_CLASS_DPUMP_CLASS_TRANSFER_TIMEOUT);
174
175 /* If the semaphore did not succeed we probably have a time out. */
176 if (status != UX_SUCCESS)
177 {
178
179 /* All transfers pending need to abort. There may have been a partial transfer. */
180 _ux_host_stack_transfer_request_abort(transfer_request);
181
182 /* Update the length of the actual data transferred. We do this after the
183 abort of the transfer_request in case some data actually went out. */
184 *actual_length += transfer_request -> ux_transfer_request_actual_length;
185
186 /* Unprotect thread reentry to this instance. */
187 _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
188
189 /* Set the completion code. */
190 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT;
191
192 /* Error trap. */
193 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
194
195 /* If trace is enabled, insert this event into the trace buffer. */
196 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
197
198 /* There was an error, return to the caller. */
199 return(UX_TRANSFER_TIMEOUT);
200 }
201 }
202 else
203 {
204
205 /* Unprotect thread reentry to this instance. */
206 status = _ux_host_semaphore_put_rc(&dpump -> ux_host_class_dpump_semaphore);
207
208 /* There was a non transfer error, no partial transfer to be checked */
209 return(status);
210 }
211 #endif
212
213 /* Update the length of the transfer. Normally all the data has to be sent. */
214 *actual_length += transfer_request -> ux_transfer_request_actual_length;
215
216 /* Check for completion of transfer. If the transfer is partial, return to caller.
217 The transfer is marked as successful but the caller will need to check the length
218 actually sent and determine if a partial transfer is OK. */
219 if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
220 {
221
222 /* Unprotect thread reentry to this instance. */
223 _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
224
225 /* Return success. */
226 return(UX_SUCCESS);
227 }
228
229 /* Update the data pointer for next transfer. */
230 data_pointer += transfer_request_length;
231
232 /* Update what is left to send out. */
233 requested_length -= transfer_request_length;
234 }
235
236 /* Unprotect thread reentry to this instance. */
237 #if defined(UX_HOST_STANDALONE)
238 dpump -> ux_host_class_dpump_flags &= ~UX_HOST_CLASS_DPUMP_WRITE_LOCK;
239 #else
240 _ux_host_semaphore_put(&dpump -> ux_host_class_dpump_semaphore);
241 #endif
242
243 /* We get here when all the transfers went through without errors. */
244 return(UX_SUCCESS);
245 }
246
247