1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** Printer Class */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_host_class_printer.h"
30 #include "ux_host_stack.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_printer_read PORTABLE C */
38 /* 6.1.10 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function reads from the printer interface. The call is */
46 /* blocking and only returns when there is either an error or when */
47 /* the transfer is complete. */
48 /* */
49 /* A read is only allowed on bidirectional printers. */
50 /* */
51 /* INPUT */
52 /* */
53 /* printer Pointer to printer class */
54 /* data_pointer Pointer to buffer */
55 /* requested_length Requested data read */
56 /* actual_length Actual data read */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* Completion Status */
61 /* */
62 /* CALLS */
63 /* */
64 /* _ux_host_stack_class_instance_verify Verify the class instance */
65 /* _ux_host_stack_transfer_request Process transfer request */
66 /* _ux_host_stack_transfer_request_abort Abort transfer request */
67 /* _ux_host_semaphore_get Get protection semaphore */
68 /* _ux_host_semaphore_put Release protection semaphore */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* Application */
73 /* */
74 /* RELEASE HISTORY */
75 /* */
76 /* DATE NAME DESCRIPTION */
77 /* */
78 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
79 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
80 /* prefixed UX to MS_TO_TICK, */
81 /* resulting in version 6.1 */
82 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
83 /* added standalone support, */
84 /* adjusted bi-dir check, */
85 /* resulting in version 6.1.10 */
86 /* */
87 /**************************************************************************/
_ux_host_class_printer_read(UX_HOST_CLASS_PRINTER * printer,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)88 UINT _ux_host_class_printer_read (UX_HOST_CLASS_PRINTER *printer, UCHAR *data_pointer,
89 ULONG requested_length, ULONG *actual_length)
90 {
91
92 #if defined(UX_HOST_STANDALONE)
93 UX_INTERRUPT_SAVE_AREA
94 ULONG transfer_flags;
95 #endif
96 UX_TRANSFER *transfer_request;
97 UINT status;
98 ULONG transfer_request_length;
99
100 /* If trace is enabled, insert this event into the trace buffer. */
101 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PRINTER_READ, printer, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
102
103 /* Ensure the instance is valid. */
104 if (printer -> ux_host_class_printer_state != UX_HOST_CLASS_INSTANCE_LIVE)
105 {
106
107 /* Error trap. */
108 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
109
110 /* If trace is enabled, insert this event into the trace buffer. */
111 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, printer, 0, 0, UX_TRACE_ERRORS, 0, 0)
112
113 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
114 }
115
116 /* Check if the printer is bidirectional. */
117 if ((printer -> ux_host_class_printer_interface -> ux_interface_descriptor.bInterfaceProtocol !=
118 UX_HOST_CLASS_PRINTER_PROTOCOL_BI_DIRECTIONAL) &&
119 (printer -> ux_host_class_printer_interface -> ux_interface_descriptor.bInterfaceProtocol !=
120 UX_HOST_CLASS_PRINTER_PROTOCOL_IEEE_1284_4_BI_DIR))
121 {
122
123 /* Error trap. */
124 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
125
126 /* If trace is enabled, insert this event into the trace buffer. */
127 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
128
129 /* Return an error. */
130 return(UX_FUNCTION_NOT_SUPPORTED);
131 }
132
133 /* Protect thread reentry to this instance. */
134 #if defined(UX_HOST_STANDALONE)
135 UX_DISABLE
136 if (printer -> ux_host_class_printer_flags & UX_HOST_CLASS_PRINTER_FLAG_LOCK)
137 {
138 UX_RESTORE
139 return(UX_BUSY);
140 }
141 printer -> ux_host_class_printer_flags |= UX_HOST_CLASS_PRINTER_FLAG_LOCK;
142 UX_RESTORE
143 #else
144 status = _ux_host_semaphore_get(&printer -> ux_host_class_printer_semaphore, UX_WAIT_FOREVER);
145 if (status != UX_SUCCESS)
146
147 /* Return error. */
148 return(status);
149 #endif
150
151 /* Start by resetting the actual length of the transfer to zero. */
152 *actual_length = 0;
153
154 /* Get the pointer to the bulk in endpoint in the transfer_request. */
155 transfer_request = &printer -> ux_host_class_printer_bulk_in_endpoint -> ux_endpoint_transfer_request;
156
157 #if defined(UX_HOST_STANDALONE)
158
159 /* Enable blocking transfer flags. */
160 transfer_flags = transfer_request -> ux_transfer_request_flags;
161 transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
162 #endif
163
164 /* Perform a transfer on the bulk in endpoint until either the transfer is
165 completed or until there is an error. */
166 while (requested_length)
167 {
168
169 /* Program the maximum authorized length for this transfer request. */
170 if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
171 transfer_request_length = transfer_request -> ux_transfer_request_maximum_length;
172 else
173 transfer_request_length = requested_length;
174
175 /* Initialize the transfer request. */
176 transfer_request -> ux_transfer_request_data_pointer = data_pointer;
177 transfer_request -> ux_transfer_request_requested_length = transfer_request_length;
178
179 /* Perform the transfer. */
180 status = _ux_host_stack_transfer_request(transfer_request);
181
182 /* If the transfer is successful, we need to wait for the transfer request to be completed. */
183 if (status == UX_SUCCESS)
184 {
185 #if !defined(UX_HOST_STANDALONE)
186
187 /* Wait for the completion of the transfer_request. */
188 status = _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PRINTER_CLASS_TRANSFER_TIMEOUT));
189
190 /* If the semaphore did not succeed we probably have a time out. */
191 if (status != UX_SUCCESS)
192 {
193
194 /* All transfers pending need to abort. There may have been a partial transfer. */
195 _ux_host_stack_transfer_request_abort(transfer_request);
196
197 /* Update the length of the actual data transferred. We do this after the
198 abort of the transfer request in case some data was actually received. */
199 *actual_length += transfer_request -> ux_transfer_request_actual_length;
200
201 /* Unprotect thread reentry to this instance. */
202 _ux_host_class_printer_unlock(printer);
203
204 /* Set the completion code. */
205 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_TIMEOUT;
206
207 /* Error trap. */
208 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
209
210 /* If trace is enabled, insert this event into the trace buffer. */
211 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
212
213 /* There was an error, return to the caller */
214 return(UX_TRANSFER_TIMEOUT);
215 }
216 #endif
217 }
218 else
219 {
220 #if defined(UX_HOST_STANDALONE)
221
222 /* Restore transfer options. */
223 transfer_request -> ux_transfer_request_flags = transfer_flags;
224 #endif
225
226 /* Unprotect thread reentry to this instance. */
227 _ux_host_class_printer_unlock(printer);
228
229 /* There was a non transfer error, no partial transfer to be checked. */
230 return(status);
231 }
232
233 /* Update the length of the transfer. Normally all the data has to be received. */
234 *actual_length += transfer_request -> ux_transfer_request_actual_length;
235
236 /* Check for completion of transfer. If the transfer is partial, return to caller.
237 The transfer is marked as successful but the caller will need to check the length
238 actually received and determine if a partial transfer is OK. */
239 if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
240 {
241 #if defined(UX_HOST_STANDALONE)
242
243 /* Restore transfer options. */
244 transfer_request -> ux_transfer_request_flags = transfer_flags;
245 #endif
246
247 /* Unprotect thread reentry to this instance. */
248 _ux_host_class_printer_unlock(printer);
249
250 /* Return success to caller. */
251 return(UX_SUCCESS);
252 }
253
254 /* Update the data pointer for next transfer. */
255 data_pointer += transfer_request_length;
256
257 /* Update what is left to receive. */
258 requested_length -= transfer_request_length;
259 }
260
261 #if defined(UX_HOST_STANDALONE)
262
263 /* Restore transfer options. */
264 transfer_request -> ux_transfer_request_flags = transfer_flags;
265 #endif
266
267 /* Unprotect thread reentry to this instance. */
268 _ux_host_class_printer_unlock(printer);
269
270 /* We get here when all the transfers went through without errors. */
271 return(UX_SUCCESS);
272 }
273
274