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 #if defined(UX_DEVICE_STANDALONE)
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_device_class_printer_write_run                   PORTABLE C     */
38 /*                                                           6.3.0        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Yajun Xia, Microsoft Corporation                                    */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function writes to the Printer class.                          */
46 /*                                                                        */
47 /*    It's for standalone mode.                                           */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    printer                               Address of printer class      */
52 /*                                            instance                    */
53 /*    buffer                                Pointer to data to write      */
54 /*    requested_length                      Length of bytes to write,     */
55 /*                                            set to 0 to issue ZLP       */
56 /*    actual_length                         Pointer to save number of     */
57 /*                                            bytes written               */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    State machine Status to check                                       */
62 /*    UX_STATE_NEXT                         Transfer done, to next state  */
63 /*    UX_STATE_EXIT                         Abnormal, to reset state      */
64 /*    (others)                              Keep running, waiting         */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _ux_device_stack_transfer_run         Run Transfer state machine    */
69 /*    _ux_utility_memory_copy               Copy memory                   */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    Application                                                         */
74 /*                                                                        */
75 /*  RELEASE HISTORY                                                       */
76 /*                                                                        */
77 /*    DATE              NAME                      DESCRIPTION             */
78 /*                                                                        */
79 /*  10-31-2022         Yajun Xia            Initial Version 6.2.0         */
80 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            added a new mode to manage  */
82 /*                                            endpoint buffer in classes, */
83 /*                                            resulting in version 6.3.0  */
84 /*                                                                        */
85 /**************************************************************************/
_ux_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)86 UINT _ux_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
87                                 ULONG requested_length, ULONG *actual_length)
88 {
89 
90 UX_SLAVE_ENDPOINT           *endpoint;
91 UX_SLAVE_DEVICE             *device;
92 UX_SLAVE_TRANSFER           *transfer_request;
93 UINT                        status = 0;
94 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER != 1) || !defined(UX_DEVICE_CLASS_CDC_ACM_ZERO_COPY)
95 UINT                        zlp = UX_FALSE;
96 #endif
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         printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
116         printer -> ux_device_class_printer_write_status = UX_CONFIGURATION_HANDLE_UNKNOWN;
117 
118         return(UX_STATE_EXIT);
119     }
120 
121     /* Locate the endpoints.  */
122     endpoint = printer -> ux_device_class_printer_endpoint_in;
123 
124     /* Check if it's available.  */
125     if (endpoint == UX_NULL)
126     {
127         /* Error trap. */
128         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN);
129 
130         printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
131         printer -> ux_device_class_printer_write_status = UX_ENDPOINT_HANDLE_UNKNOWN;
132 
133         return(UX_STATE_EXIT);
134     }
135 
136     /* We are writing to the IN endpoint.  */
137     transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
138 
139 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_PRINTER_ZERO_COPY)
140 
141     /* Run the transfer state machine.  */
142     if (printer -> ux_device_class_printer_write_state == UX_STATE_RESET)
143     {
144 
145         /* Set the state to WRITE_WAIT.  */
146         printer -> ux_device_class_printer_write_state = UX_DEVICE_CLASS_PRINTER_WRITE_WAIT;
147         printer -> ux_device_class_printer_write_status = UX_TRANSFER_NO_ANSWER;
148         transfer_request -> ux_slave_transfer_request_data_pointer = buffer;
149         UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
150     }
151 
152     /* Issue the transfer request.  */
153 #if defined(UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP)
154     status = _ux_device_stack_transfer_run(transfer_request, requested_length, requested_length + 1);
155 #else
156     status = _ux_device_stack_transfer_run(transfer_request, requested_length, requested_length);
157 #endif
158 
159     /* Error case.  */
160     if (status < UX_STATE_NEXT)
161     {
162 
163         printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
164         printer -> ux_device_class_printer_write_status =
165                 transfer_request -> ux_slave_transfer_request_completion_code;
166         return(UX_STATE_ERROR);
167     }
168 
169     /* Success case.  */
170     if (status == UX_STATE_NEXT)
171     {
172 
173         /* Last transfer status.  */
174         printer -> ux_device_class_printer_write_status =
175                 transfer_request -> ux_slave_transfer_request_completion_code;
176 
177         /* Update actual length.  */
178         *actual_length = transfer_request -> ux_slave_transfer_request_actual_length;
179 
180         /* It's done.  */
181         printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
182     }
183     return(status);
184 
185 #else
186 
187     /* Handle state cases.  */
188     switch(printer -> ux_device_class_printer_write_state)
189     {
190     case UX_STATE_RESET:
191         printer -> ux_device_class_printer_write_state = UX_DEVICE_CLASS_PRINTER_WRITE_START;
192         printer -> ux_device_class_printer_write_status = UX_TRANSFER_NO_ANSWER;
193         printer -> ux_device_class_printer_write_buffer = buffer;
194         printer -> ux_device_class_printer_write_requested_length = requested_length;
195         printer -> ux_device_class_printer_write_actual_length = 0;
196         printer -> ux_device_class_printer_write_host_length = UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE;
197         if (requested_length == 0)
198             zlp = UX_TRUE;
199 
200         /* Fall through.  */
201     case UX_DEVICE_CLASS_PRINTER_WRITE_START:
202 
203         /* Get remaining requested length.  */
204         requested_length = printer -> ux_device_class_printer_write_requested_length -
205                         printer -> ux_device_class_printer_write_actual_length;
206 
207         /* There is no remaining, we are done.  */
208         if (requested_length == 0 && !zlp)
209         {
210             *actual_length = printer -> ux_device_class_printer_write_actual_length;
211             printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
212             printer -> ux_device_class_printer_write_status = UX_SUCCESS;
213             return(UX_STATE_NEXT);
214         }
215 
216         /* Check if we have enough in the local buffer.  */
217         if (requested_length > UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE)
218 
219             /* We have too much to transfer.  */
220             printer -> ux_device_class_printer_write_transfer_length =
221                                             UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE;
222 
223         else
224         {
225 
226             /* We can proceed with the demanded length.  */
227             printer -> ux_device_class_printer_write_transfer_length = requested_length;
228 
229 #if !defined(UX_DEVICE_CLASS_PRINTER_WRITE_AUTO_ZLP)
230 
231             /* Assume expected length and transfer length match.  */
232             printer -> ux_device_class_printer_write_host_length = requested_length;
233 #else
234 
235             /* Assume expected more than transfer to let stack append ZLP if needed.  */
236             printer -> ux_device_class_printer_write_host_length = UX_DEVICE_CLASS_PRINTER_WRITE_BUFFER_SIZE + 1;
237 #endif
238         }
239 
240 
241         /* On a out, we copy the buffer to the caller. Not very efficient but it makes the API
242            easier.  */
243         _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
244                             printer -> ux_device_class_printer_write_buffer,
245                             printer -> ux_device_class_printer_write_transfer_length); /* Use case of memcpy is verified. */
246 
247         /* Next state.  */
248         printer -> ux_device_class_printer_write_state = UX_DEVICE_CLASS_PRINTER_WRITE_WAIT;
249         UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
250 
251         /* Fall through.  */
252     case UX_DEVICE_CLASS_PRINTER_WRITE_WAIT:
253 
254         /* Send the request to the device controller.  */
255         status =  _ux_device_stack_transfer_run(transfer_request,
256                             printer -> ux_device_class_printer_write_transfer_length,
257                             printer -> ux_device_class_printer_write_host_length);
258 
259         /* Error case.  */
260         if (status < UX_STATE_NEXT)
261         {
262 
263             printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
264             printer -> ux_device_class_printer_write_status =
265                 transfer_request -> ux_slave_transfer_request_completion_code;
266             return(UX_STATE_ERROR);
267         }
268 
269         /* Success case.  */
270         if (status == UX_STATE_NEXT)
271         {
272 
273             /* Next buffer address.  */
274             printer -> ux_device_class_printer_write_buffer +=
275                     transfer_request -> ux_slave_transfer_request_actual_length;
276 
277             /* Set the length actually received. */
278             printer -> ux_device_class_printer_write_actual_length +=
279                     transfer_request -> ux_slave_transfer_request_actual_length;
280 
281             /* Last transfer status.  */
282             printer -> ux_device_class_printer_write_status =
283                 transfer_request -> ux_slave_transfer_request_completion_code;
284 
285             /* Update actual done length.  */
286             *actual_length = printer -> ux_device_class_printer_write_actual_length;
287 
288             /* Check ZLP case.  */
289             if (printer -> ux_device_class_printer_write_requested_length == 0)
290             {
291                 printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
292                 return(UX_STATE_NEXT);
293             }
294 
295             /* Next state.  */
296             printer -> ux_device_class_printer_write_state = UX_DEVICE_CLASS_PRINTER_WRITE_START;
297         }
298 
299         /* Keep waiting.  */
300         return(UX_STATE_WAIT);
301 
302     default: /* Error.  */
303         printer -> ux_device_class_printer_write_state = UX_STATE_RESET;
304         break;
305     }
306 #endif
307 
308     /* Error case.  */
309     return(UX_STATE_EXIT);
310 }
311 
312 /**************************************************************************/
313 /*                                                                        */
314 /*  FUNCTION                                               RELEASE        */
315 /*                                                                        */
316 /*    _uxe_device_class_printer_write_run                 PORTABLE C      */
317 /*                                                           6.3.0        */
318 /*  AUTHOR                                                                */
319 /*                                                                        */
320 /*    Yajun Xia, Microsoft Corporation                                    */
321 /*                                                                        */
322 /*  DESCRIPTION                                                           */
323 /*                                                                        */
324 /*    This function checks errors in printer write function call.         */
325 /*                                                                        */
326 /*    It's for standalone mode.                                           */
327 /*                                                                        */
328 /*  INPUT                                                                 */
329 /*                                                                        */
330 /*    printer                               Address of printer class      */
331 /*                                            instance                    */
332 /*    buffer                                Pointer to data to write      */
333 /*    requested_length                      Length of bytes to write,     */
334 /*                                            set to 0 to issue ZLP       */
335 /*    actual_length                         Pointer to save number of     */
336 /*                                            bytes written               */
337 /*                                                                        */
338 /*  OUTPUT                                                                */
339 /*                                                                        */
340 /*    State machine Status to check                                       */
341 /*    UX_STATE_NEXT                         Transfer done, to next state  */
342 /*    UX_STATE_EXIT                         Abnormal, to reset state      */
343 /*    UX_STATE_ERROR                        Error occurred                */
344 /*    (others)                              Keep running, waiting         */
345 /*                                                                        */
346 /*  CALLS                                                                 */
347 /*                                                                        */
348 /*    _ux_device_class_printer_write_run    Printer class write process   */
349 /*                                                                        */
350 /*  CALLED BY                                                             */
351 /*                                                                        */
352 /*    Application                                                         */
353 /*                                                                        */
354 /*  RELEASE HISTORY                                                       */
355 /*                                                                        */
356 /*    DATE              NAME                      DESCRIPTION             */
357 /*                                                                        */
358 /*  10-31-2023        Yajun xia             Initial Version 6.3.0         */
359 /*                                                                        */
360 /**************************************************************************/
_uxe_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)361 UINT _uxe_device_class_printer_write_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
362                                 ULONG requested_length, ULONG *actual_length)
363 {
364 
365     /* Sanity check.  */
366     if ((printer == UX_NULL) || ((buffer == UX_NULL) && (requested_length > 0)) || (actual_length == UX_NULL))
367     {
368         return (UX_STATE_ERROR);
369     }
370 
371     return(_ux_device_class_printer_write_run(printer, buffer, requested_length, actual_length));
372 }
373 
374 #endif
375