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 /** Printer 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_printer.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_printer_write PORTABLE C */
37 /* 6.1.10 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function writes to the printer 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 /* printer Pointer to printer 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_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 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
79 /* fixed ZLP sending issue, */
80 /* resulting in version 6.1.9 */
81 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
82 /* added standalone support, */
83 /* resulting in version 6.1.10 */
84 /* */
85 /**************************************************************************/
_ux_host_class_printer_write(UX_HOST_CLASS_PRINTER * printer,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)86 UINT _ux_host_class_printer_write(UX_HOST_CLASS_PRINTER *printer, UCHAR * data_pointer,
87 ULONG requested_length, ULONG *actual_length)
88 {
89
90 #if defined(UX_HOST_STANDALONE)
91 UX_INTERRUPT_SAVE_AREA
92 ULONG transfer_flags;
93 #endif
94 UX_TRANSFER *transfer_request;
95 UINT status;
96 ULONG transfer_request_length;
97
98 /* If trace is enabled, insert this event into the trace buffer. */
99 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PRINTER_WRITE, printer, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
100
101 /* Ensure the instance is valid. */
102 if (printer -> ux_host_class_printer_state != UX_HOST_CLASS_INSTANCE_LIVE)
103 {
104
105 /* Error trap. */
106 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
107
108 /* If trace is enabled, insert this event into the trace buffer. */
109 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, printer, 0, 0, UX_TRACE_ERRORS, 0, 0)
110
111 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
112 }
113
114 #if defined(UX_HOST_STANDALONE)
115 UX_DISABLE
116 if (printer -> ux_host_class_printer_flags & UX_HOST_CLASS_PRINTER_FLAG_LOCK)
117 {
118 UX_RESTORE
119 return(UX_BUSY);
120 }
121 printer -> ux_host_class_printer_flags |= UX_HOST_CLASS_PRINTER_FLAG_LOCK;
122 UX_RESTORE
123 #else
124
125 /* Protect thread reentry to this instance. */
126 status = _ux_host_semaphore_get(&printer -> ux_host_class_printer_semaphore, UX_WAIT_FOREVER);
127 if (status != UX_SUCCESS)
128
129 /* Return error. */
130 return(status);
131 #endif
132
133 /* Start by resetting the actual length of the transfer. */
134 *actual_length = 0;
135
136 /* Get the pointer to the bulk out endpoint transfer request. */
137 transfer_request = &printer -> ux_host_class_printer_bulk_out_endpoint -> ux_endpoint_transfer_request;
138
139 #if defined(UX_HOST_STANDALONE)
140
141 /* Enable blocking transfer flags. */
142 transfer_flags = transfer_request -> ux_transfer_request_flags;
143 transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
144 #endif
145
146 /* Perform a transfer on the bulk out endpoint until either the transfer is
147 completed or when there is an error. */
148 do
149 {
150
151 /* Program the maximum authorized length for this transfer_request. */
152 if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
153 transfer_request_length = transfer_request -> ux_transfer_request_maximum_length;
154 else
155 transfer_request_length = requested_length;
156
157 /* Initialize the transfer_request. */
158 transfer_request -> ux_transfer_request_data_pointer = data_pointer;
159 transfer_request -> ux_transfer_request_requested_length = transfer_request_length;
160
161 /* Perform the transfer. */
162 status = _ux_host_stack_transfer_request(transfer_request);
163
164 /* If the transfer is successful, we need to wait for the transfer request to be completed. */
165 if (status == UX_SUCCESS)
166 {
167 #if !defined(UX_HOST_STANDALONE)
168
169 /* Wait for the completion of the transfer request. */
170 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PRINTER_CLASS_TRANSFER_TIMEOUT));
171
172 /* If the semaphore did not succeed we probably have a time out. */
173 if (status != UX_SUCCESS)
174 {
175
176 /* All transfers pending need to abort. There may have been a partial transfer. */
177 _ux_host_stack_transfer_request_abort(transfer_request);
178
179 /* Update the length of the actual data transferred. We do this after the
180 abort of the transfer_request in case some data actually went out. */
181 *actual_length += transfer_request -> ux_transfer_request_actual_length;
182
183 /* Unprotect thread reentry to this instance. */
184 _ux_host_class_printer_unlock(printer);
185
186 /* Set the completion code. */
187 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT;
188
189 /* Error trap. */
190 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
191
192 /* If trace is enabled, insert this event into the trace buffer. */
193 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
194
195 /* There was an error, return to the caller. */
196 return(UX_TRANSFER_TIMEOUT);
197 }
198 #endif
199 }
200 else
201 {
202 #if defined(UX_HOST_STANDALONE)
203
204 /* Restore transfer options. */
205 transfer_request -> ux_transfer_request_flags = transfer_flags;
206 #endif
207
208 /* Unprotect thread reentry to this instance. */
209 _ux_host_class_printer_unlock(printer);
210
211 /* There was a non transfer error, no partial transfer to be checked */
212 return(status);
213 }
214
215 /* Update the length of the transfer. Normally all the data has to be sent. */
216 *actual_length += transfer_request -> ux_transfer_request_actual_length;
217
218 /* Check for completion of transfer. If the transfer is partial, return to caller.
219 The transfer is marked as successful but the caller will need to check the length
220 actually sent and determine if a partial transfer is OK. */
221 if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
222 {
223 #if defined(UX_HOST_STANDALONE)
224
225 /* Restore transfer options. */
226 transfer_request -> ux_transfer_request_flags = transfer_flags;
227 #endif
228
229 /* Unprotect thread reentry to this instance. */
230 _ux_host_class_printer_unlock(printer);
231
232 /* Return success. */
233 return(UX_SUCCESS);
234 }
235
236 /* Update the data pointer for next transfer. */
237 data_pointer += transfer_request_length;
238
239 /* Update what is left to send out. */
240 requested_length -= transfer_request_length;
241 } while (requested_length);
242
243 #if defined(UX_HOST_STANDALONE)
244
245 /* Restore transfer options. */
246 transfer_request -> ux_transfer_request_flags = transfer_flags;
247 #endif
248
249 /* Unprotect thread reentry to this instance. */
250 _ux_host_class_printer_unlock(printer);
251
252 /* We get here when all the transfers went through without errors. */
253 return(UX_SUCCESS);
254 }
255
256 /**************************************************************************/
257 /* */
258 /* FUNCTION RELEASE */
259 /* */
260 /* _uxe_host_class_printer_write PORTABLE C */
261 /* 6.3.0 */
262 /* AUTHOR */
263 /* */
264 /* Yajun Xia, Microsoft Corporation */
265 /* */
266 /* DESCRIPTION */
267 /* */
268 /* This function checks errors in printer write function call. */
269 /* */
270 /* INPUT */
271 /* */
272 /* printer Pointer to printer class */
273 /* data_pointer Pointer to data to write */
274 /* requested_length Length of data to write */
275 /* actual_length Actual length of data written */
276 /* */
277 /* OUTPUT */
278 /* */
279 /* Completion Status */
280 /* */
281 /* CALLS */
282 /* */
283 /* _ux_host_class_printer_write Printer write */
284 /* */
285 /* CALLED BY */
286 /* */
287 /* Application */
288 /* */
289 /* RELEASE HISTORY */
290 /* */
291 /* DATE NAME DESCRIPTION */
292 /* */
293 /* 10-31-2023 Yajun xia Initial Version 6.3.0 */
294 /* */
295 /**************************************************************************/
_uxe_host_class_printer_write(UX_HOST_CLASS_PRINTER * printer,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)296 UINT _uxe_host_class_printer_write(UX_HOST_CLASS_PRINTER *printer, UCHAR * data_pointer,
297 ULONG requested_length, ULONG *actual_length)
298 {
299
300 /* Sanity checks. */
301 if ((printer == UX_NULL) ||
302 ((data_pointer == UX_NULL) && (requested_length > 0)) ||
303 (actual_length == UX_NULL))
304 {
305 return(UX_INVALID_PARAMETER);
306 }
307
308 /* Call the actual printer write function. */
309 return(_ux_host_class_printer_write(printer, data_pointer, requested_length, actual_length));
310 }
311