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 /** USBX Component */
15 /** */
16 /** Device Printer Class */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "ux_api.h"
27 #include "ux_device_class_printer.h"
28 #include "ux_device_stack.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_class_printer_write PORTABLE C */
36 /* 6.3.0 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function writes to the Printer class. */
44 /* */
45 /* INPUT */
46 /* */
47 /* printer Address of printer class */
48 /* instance */
49 /* buffer Pointer to data to write */
50 /* requested_length Length of bytes to write, */
51 /* set to 0 to issue ZLP */
52 /* actual_length Pointer to save number of */
53 /* bytes written */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* None */
58 /* */
59 /* CALLS */
60 /* */
61 /* _ux_utility_memory_copy Copy memory */
62 /* _ux_device_stack_transfer_request Transfer request */
63 /* _ux_device_mutex_on Take Mutex */
64 /* _ux_device_mutex_off Release Mutex */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* Application */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
75 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
76 /* fixed standalone compile, */
77 /* resulting in version 6.1.11 */
78 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
79 /* added auto ZLP support, */
80 /* resulting in version 6.1.12 */
81 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
82 /* added a new mode to manage */
83 /* endpoint buffer in classes, */
84 /* resulting in version 6.3.0 */
85 /* */
86 /**************************************************************************/
_ux_device_class_printer_write(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)87 UINT _ux_device_class_printer_write(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
88 ULONG requested_length, ULONG *actual_length)
89 {
90
91 UX_SLAVE_ENDPOINT *endpoint;
92 UX_SLAVE_DEVICE *device;
93 UX_SLAVE_TRANSFER *transfer_request;
94 ULONG local_requested_length;
95 ULONG local_host_length;
96 UINT status = 0;
97
98 /* If trace is enabled, insert this event into the trace buffer. */
99 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_WRITE, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
100
101 /* Get the pointer to the device. */
102 device = &_ux_system_slave -> ux_system_slave_device;
103
104 /* As long as the device is in the CONFIGURED state. */
105 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
106 {
107
108 /* Error trap. */
109 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
110
111 /* If trace is enabled, insert this event into the trace buffer. */
112 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
113
114 /* Cannot proceed with command, the interface is down. */
115 return(UX_CONFIGURATION_HANDLE_UNKNOWN);
116 }
117
118 /* Locate the endpoints. */
119 endpoint = printer -> ux_device_class_printer_endpoint_in;
120
121 /* Check if it's available. */
122 if (endpoint == UX_NULL)
123 return(UX_FUNCTION_NOT_SUPPORTED);
124
125 /* Protect this thread. */
126 _ux_device_mutex_on(&printer -> ux_device_class_printer_endpoint_in_mutex);
127
128 /* We are writing to the IN endpoint. */
129 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
130
131 /* Reset the actual length. */
132 *actual_length = 0;
133
134 /* Check if the application forces a 0 length packet. */
135 if (requested_length == 0)
136 {
137
138 /* Send the request for 0 byte packet to the device controller. */
139 status = _ux_device_stack_transfer_request(transfer_request, 0, 0);
140
141 /* Free Mutex resource. */
142 _ux_device_mutex_off(&printer -> ux_device_class_printer_endpoint_in_mutex);
143
144 /* Return the status. */
145 return(status);
146 }
147
148 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_PRINTER_ZERO_COPY)
149
150 /* Check if device is configured. */
151 if (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
152 {
153
154 #if defined(UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP)
155
156 /* Issue with larger host length to append zlp if necessary. */
157 local_host_length = requested_length + 1;
158 #else
159 local_host_length = requested_length;
160 #endif
161 local_requested_length = requested_length;
162
163 /* Issue the transfer request. */
164 transfer_request -> ux_slave_transfer_request_data_pointer = buffer;
165 status = _ux_device_stack_transfer_request(transfer_request, local_requested_length, local_host_length);
166 *actual_length = transfer_request -> ux_slave_transfer_request_actual_length;
167 }
168 #else
169
170 /* Check if we need more transactions. */
171 local_host_length = UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE;
172 while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED &&
173 requested_length != 0)
174 {
175
176 /* Check if we have enough in the local buffer. */
177 if (requested_length > UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE)
178
179 /* We have too much to transfer. */
180 local_requested_length = UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE;
181
182 else
183 {
184
185 /* We can proceed with the demanded length. */
186 local_requested_length = requested_length;
187
188 #if !defined(UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP)
189
190 /* Assume expected length matches. */
191 local_host_length = requested_length;
192 #else
193
194 /* Assume expected more so stack appends ZLP if needed. */
195 local_host_length = UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE + 1;
196 #endif
197 }
198
199 /* On a out, we copy the buffer to the caller. Not very efficient but it makes the API
200 easier. */
201 _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
202 buffer, local_requested_length); /* Use case of memcpy is verified. */
203
204 /* Send the request to the device controller. */
205 status = _ux_device_stack_transfer_request(transfer_request,
206 local_requested_length, local_host_length);
207
208 /* Check the status */
209 if (status == UX_SUCCESS)
210 {
211
212 /* Next buffer address. */
213 buffer += transfer_request -> ux_slave_transfer_request_actual_length;
214
215 /* Set the length actually received. */
216 *actual_length += transfer_request -> ux_slave_transfer_request_actual_length;
217
218 /* Decrement what left has to be done. */
219 requested_length -= transfer_request -> ux_slave_transfer_request_actual_length;
220 }
221 else
222 {
223
224 /* Free Mutex resource. */
225 _ux_device_mutex_off(&printer -> ux_device_class_printer_endpoint_in_mutex);
226
227 /* We had an error, abort. */
228 return(status);
229 }
230 }
231 #endif
232
233 /* Free Mutex resource. */
234 _ux_device_mutex_off(&printer -> ux_device_class_printer_endpoint_in_mutex);
235
236 /* Check why we got here, either completion or device was extracted. */
237 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
238 {
239
240 /* Error trap. */
241 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER);
242
243 /* If trace is enabled, insert this event into the trace buffer. */
244 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_NO_ANSWER, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
245
246 /* Device must have been extracted. */
247 return (UX_TRANSFER_NO_ANSWER);
248 }
249 else
250
251 /* Simply return the last transaction result. */
252 return(status);
253 }
254
255 /**************************************************************************/
256 /* */
257 /* FUNCTION RELEASE */
258 /* */
259 /* _uxe_device_class_printer_write PORTABLE C */
260 /* 6.3.0 */
261 /* AUTHOR */
262 /* */
263 /* Yajun Xia, Microsoft Corporation */
264 /* */
265 /* DESCRIPTION */
266 /* */
267 /* This function checks errors in printer class write function */
268 /* */
269 /* INPUT */
270 /* */
271 /* printer Address of printer class */
272 /* instance */
273 /* buffer Pointer to data to write */
274 /* requested_length Length of bytes to write, */
275 /* set to 0 to issue ZLP */
276 /* actual_length Pointer to save number of */
277 /* bytes written */
278 /* */
279 /* OUTPUT */
280 /* */
281 /* None */
282 /* */
283 /* CALLS */
284 /* */
285 /* _ux_device_class_printer_write Printer class write function */
286 /* */
287 /* CALLED BY */
288 /* */
289 /* Application */
290 /* */
291 /* RELEASE HISTORY */
292 /* */
293 /* DATE NAME DESCRIPTION */
294 /* */
295 /* 03-08-2023 Yajun Xia Initial Version 6.2.1 */
296 /* 10-31-2023 Yajun Xia Modified comment(s), */
297 /* fixed error checking issue, */
298 /* resulting in version 6.3.0 */
299 /* */
300 /**************************************************************************/
_uxe_device_class_printer_write(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)301 UINT _uxe_device_class_printer_write(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
302 ULONG requested_length, ULONG *actual_length)
303 {
304
305 /* Sanity checks. */
306 if ((printer == UX_NULL) || ((buffer == UX_NULL) && (requested_length > 0)) || (actual_length == UX_NULL))
307 {
308 return (UX_INVALID_PARAMETER);
309 }
310
311 return (_ux_device_class_printer_write(printer, buffer, requested_length, actual_length));
312 }