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