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_read                       PORTABLE C      */
36 /*                                                           6.1.11       */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function reads from the Printer class.                         */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    printer                               Address of printer class      */
48 /*                                            instance                    */
49 /*    buffer                                Pointer to buffer to save     */
50 /*                                            received data               */
51 /*    requested_length                      Length of bytes to read       */
52 /*    actual_length                         Pointer to save number of     */
53 /*                                            bytes read                  */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    None                                                                */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _ux_device_stack_transfer_request     Transfer request              */
62 /*    _ux_utility_memory_copy               Copy memory                   */
63 /*    _ux_device_mutex_off                  Release mutex                 */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    Application                                                         */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  01-31-2022     Chaoqiong Xiao           Initial Version 6.1.10        */
74 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            fixed standalone compile,   */
76 /*                                            resulting in version 6.1.11 */
77 /*                                                                        */
78 /**************************************************************************/
_ux_device_class_printer_read(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)79 UINT _ux_device_class_printer_read(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
80                                 ULONG requested_length, ULONG *actual_length)
81 {
82 
83 UX_SLAVE_ENDPOINT           *endpoint;
84 UX_SLAVE_DEVICE             *device;
85 UX_SLAVE_TRANSFER           *transfer_request;
86 UINT                        status= UX_SUCCESS;
87 ULONG                       local_requested_length;
88 
89     /* If trace is enabled, insert this event into the trace buffer.  */
90     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_READ, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
91 
92     /* Get the pointer to the device.  */
93     device =  &_ux_system_slave -> ux_system_slave_device;
94 
95     /* As long as the device is in the CONFIGURED state.  */
96     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
97     {
98 
99         /* Error trap. */
100         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
101 
102         /* If trace is enabled, insert this event into the trace buffer.  */
103         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
104 
105         /* Cannot proceed with command, the interface is down.  */
106         return(UX_CONFIGURATION_HANDLE_UNKNOWN);
107     }
108 
109     /* Locate the endpoint.  */
110     endpoint = printer -> ux_device_class_printer_endpoint_out;
111 
112     /* Protect this thread.  */
113     _ux_device_mutex_on(&printer -> ux_device_class_printer_endpoint_out_mutex);
114 
115     /* All Printer reading  are on the endpoint OUT, from the host.  */
116     transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
117 
118 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_PRINTER_ZERO_COPY)
119 
120     /* Check if device is configured.  */
121     if (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
122     {
123 
124         /* Issue the transfer request.  */
125         local_requested_length = requested_length;
126         transfer_request -> ux_slave_transfer_request_data_pointer = buffer;
127         status =  _ux_device_stack_transfer_request(transfer_request,
128                                 local_requested_length, local_requested_length);
129         *actual_length = transfer_request -> ux_slave_transfer_request_actual_length;
130     }
131 #else
132 
133     /* Reset the actual length.  */
134     *actual_length =  0;
135 
136     /* Check if we need more transactions.  */
137     while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED && requested_length != 0)
138     {
139 
140         /* Check if we have enough in the local buffer.  */
141         if (requested_length > endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize)
142 
143             /* We have too much to transfer.  */
144             local_requested_length = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize;
145 
146         else
147 
148             /* We can proceed with the demanded length.  */
149             local_requested_length = requested_length;
150 
151         /* Send the request to the device controller.  */
152         status =  _ux_device_stack_transfer_request(transfer_request,
153                                 local_requested_length, local_requested_length);
154 
155         /* Check the status */
156         if (status == UX_SUCCESS)
157         {
158 
159             /* We need to copy the buffer locally.  */
160             _ux_utility_memory_copy(buffer,
161                     transfer_request -> ux_slave_transfer_request_data_pointer,
162                     transfer_request -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */
163 
164             /* Next buffer address.  */
165             buffer += transfer_request -> ux_slave_transfer_request_actual_length;
166 
167             /* Set the length actually received. */
168             *actual_length += transfer_request -> ux_slave_transfer_request_actual_length;
169 
170             /* Decrement what left has to be done.  */
171             requested_length -= transfer_request -> ux_slave_transfer_request_actual_length;
172 
173             /* Is this a short packet or a ZLP indicating we are done with this transfer ?  */
174             if (transfer_request -> ux_slave_transfer_request_actual_length <
175                 endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize)
176             {
177 
178                 /* We are done.  */
179                 /* Free Mutex resource.  */
180                 _ux_device_mutex_off(&printer -> ux_device_class_printer_endpoint_out_mutex);
181 
182                 /* Return with success.  */
183                 return(UX_SUCCESS);
184             }
185         }
186         else
187         {
188 
189             /* Free Mutex resource.  */
190             _ux_device_mutex_off(&printer -> ux_device_class_printer_endpoint_out_mutex);
191 
192             /* We got an error.  */
193             return(status);
194         }
195     }
196 #endif
197 
198     /* Free Mutex resource.  */
199     _ux_device_mutex_off(&printer -> ux_device_class_printer_endpoint_out_mutex);
200 
201     /* Check why we got here, either completion or device was extracted.  */
202     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
203     {
204 
205         /* Error trap. */
206         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_NO_ANSWER);
207 
208         /* If trace is enabled, insert this event into the trace buffer.  */
209         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_NO_ANSWER, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
210 
211         /* Device must have been extracted.  */
212         return (UX_TRANSFER_NO_ANSWER);
213     }
214     else
215 
216         /* Simply return the last transaction result.  */
217         return(status);
218 }
219 
220 /**************************************************************************/
221 /*                                                                        */
222 /*  FUNCTION                                               RELEASE        */
223 /*                                                                        */
224 /*    _uxe_device_class_printer_read                       PORTABLE C     */
225 /*                                                           6.3.0        */
226 /*  AUTHOR                                                                */
227 /*                                                                        */
228 /*    Yajun Xia, Microsoft Corporation                                    */
229 /*                                                                        */
230 /*  DESCRIPTION                                                           */
231 /*                                                                        */
232 /*    This function checks errors in printer class read function          */
233 /*                                                                        */
234 /*  INPUT                                                                 */
235 /*                                                                        */
236 /*    printer                               Address of printer class      */
237 /*                                            instance                    */
238 /*    buffer                                Pointer to buffer to save     */
239 /*                                            received data               */
240 /*    requested_length                      Length of bytes to read       */
241 /*    actual_length                         Pointer to save number of     */
242 /*                                            bytes read                  */
243 /*                                                                        */
244 /*  OUTPUT                                                                */
245 /*                                                                        */
246 /*    None                                                                */
247 /*                                                                        */
248 /*  CALLS                                                                 */
249 /*                                                                        */
250 /*    _ux_device_class_printer_read         Printer class read function   */
251 /*                                                                        */
252 /*  CALLED BY                                                             */
253 /*                                                                        */
254 /*    Application                                                         */
255 /*                                                                        */
256 /*  RELEASE HISTORY                                                       */
257 /*                                                                        */
258 /*    DATE              NAME                      DESCRIPTION             */
259 /*                                                                        */
260 /*  03-08-2023     Yajun Xia                Initial Version 6.2.1         */
261 /*  10-31-2023     Yajun Xia                Modified comment(s),          */
262 /*                                            fixed error checking issue, */
263 /*                                            resulting in version 6.3.0  */
264 /*                                                                        */
265 /**************************************************************************/
_uxe_device_class_printer_read(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)266 UINT _uxe_device_class_printer_read(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
267                                     ULONG requested_length, ULONG *actual_length)
268 {
269 
270     /* Sanity checks.  */
271     if ((printer == UX_NULL) || ((buffer == UX_NULL) && (requested_length > 0)) || (actual_length == UX_NULL))
272     {
273         return (UX_INVALID_PARAMETER);
274     }
275 
276     return (_ux_device_class_printer_read(printer, buffer, requested_length, actual_length));
277 }