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