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 }