1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** USBX Component                                                        */
17 /**                                                                       */
18 /**   Printer Class                                                       */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 
24 /* Include necessary system files.  */
25 
26 #define UX_SOURCE_CODE
27 
28 #include "ux_api.h"
29 #include "ux_host_class_printer.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_class_printer_read                         PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function reads from the printer interface. The call is         */
46 /*    blocking and only returns when there is either an error or when     */
47 /*    the transfer is complete.                                           */
48 /*                                                                        */
49 /*    A read is only allowed on bidirectional printers.                   */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    printer                               Pointer to printer class      */
54 /*    data_pointer                          Pointer to buffer             */
55 /*    requested_length                      Requested data read           */
56 /*    actual_length                         Actual data read              */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    Completion Status                                                   */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _ux_host_stack_class_instance_verify  Verify the class instance     */
65 /*    _ux_host_stack_transfer_request       Process transfer request      */
66 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
67 /*    _ux_host_semaphore_get                Get protection semaphore      */
68 /*    _ux_host_semaphore_put                Release protection semaphore  */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    Application                                                         */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
79 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            prefixed UX to MS_TO_TICK,  */
81 /*                                            resulting in version 6.1    */
82 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            added standalone support,   */
84 /*                                            adjusted bi-dir check,      */
85 /*                                            resulting in version 6.1.10 */
86 /*                                                                        */
87 /**************************************************************************/
_ux_host_class_printer_read(UX_HOST_CLASS_PRINTER * printer,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)88 UINT  _ux_host_class_printer_read (UX_HOST_CLASS_PRINTER *printer, UCHAR *data_pointer,
89                                    ULONG requested_length, ULONG *actual_length)
90 {
91 
92 #if defined(UX_HOST_STANDALONE)
93 UX_INTERRUPT_SAVE_AREA
94 ULONG           transfer_flags;
95 #endif
96 UX_TRANSFER     *transfer_request;
97 UINT            status;
98 ULONG           transfer_request_length;
99 
100     /* If trace is enabled, insert this event into the trace buffer.  */
101     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PRINTER_READ, printer, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
102 
103     /* Ensure the instance is valid.  */
104     if (printer -> ux_host_class_printer_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
105     {
106 
107         /* Error trap. */
108         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
109 
110         /* If trace is enabled, insert this event into the trace buffer.  */
111         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, printer, 0, 0, UX_TRACE_ERRORS, 0, 0)
112 
113         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
114     }
115 
116     /* Check if the printer is bidirectional.  */
117     if ((printer -> ux_host_class_printer_interface -> ux_interface_descriptor.bInterfaceProtocol !=
118                                                 UX_HOST_CLASS_PRINTER_PROTOCOL_BI_DIRECTIONAL) &&
119         (printer -> ux_host_class_printer_interface -> ux_interface_descriptor.bInterfaceProtocol !=
120                                                 UX_HOST_CLASS_PRINTER_PROTOCOL_IEEE_1284_4_BI_DIR))
121     {
122 
123         /* Error trap. */
124         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
125 
126         /* If trace is enabled, insert this event into the trace buffer.  */
127         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
128 
129         /* Return an error.  */
130         return(UX_FUNCTION_NOT_SUPPORTED);
131     }
132 
133     /* Protect thread reentry to this instance.  */
134 #if defined(UX_HOST_STANDALONE)
135     UX_DISABLE
136     if (printer -> ux_host_class_printer_flags & UX_HOST_CLASS_PRINTER_FLAG_LOCK)
137     {
138         UX_RESTORE
139         return(UX_BUSY);
140     }
141     printer -> ux_host_class_printer_flags |= UX_HOST_CLASS_PRINTER_FLAG_LOCK;
142     UX_RESTORE
143 #else
144     status =  _ux_host_semaphore_get(&printer -> ux_host_class_printer_semaphore, UX_WAIT_FOREVER);
145     if (status != UX_SUCCESS)
146 
147         /* Return error.  */
148         return(status);
149 #endif
150 
151     /* Start by resetting the actual length of the transfer to zero.  */
152     *actual_length =  0;
153 
154     /* Get the pointer to the bulk in endpoint in the transfer_request.  */
155     transfer_request =  &printer -> ux_host_class_printer_bulk_in_endpoint -> ux_endpoint_transfer_request;
156 
157 #if defined(UX_HOST_STANDALONE)
158 
159     /* Enable blocking transfer flags.  */
160     transfer_flags = transfer_request -> ux_transfer_request_flags;
161     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
162 #endif
163 
164     /* Perform a transfer on the bulk in endpoint until either the transfer is
165        completed or until there is an error.  */
166     while (requested_length)
167     {
168 
169         /* Program the maximum authorized length for this transfer request.  */
170         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
171             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
172         else
173             transfer_request_length =  requested_length;
174 
175         /* Initialize the transfer request.  */
176         transfer_request -> ux_transfer_request_data_pointer =      data_pointer;
177         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
178 
179         /* Perform the transfer.  */
180         status =  _ux_host_stack_transfer_request(transfer_request);
181 
182         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
183         if (status == UX_SUCCESS)
184         {
185 #if !defined(UX_HOST_STANDALONE)
186 
187             /* Wait for the completion of the transfer_request.  */
188             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PRINTER_CLASS_TRANSFER_TIMEOUT));
189 
190             /* If the semaphore did not succeed we probably have a time out.  */
191             if (status != UX_SUCCESS)
192             {
193 
194                 /* All transfers pending need to abort. There may have been a partial transfer.  */
195                 _ux_host_stack_transfer_request_abort(transfer_request);
196 
197                 /* Update the length of the actual data transferred. We do this after the
198                    abort of the transfer request in case some data was actually received.  */
199                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
200 
201                 /* Unprotect thread reentry to this instance.  */
202                 _ux_host_class_printer_unlock(printer);
203 
204                 /* Set the completion code.  */
205                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
206 
207                 /* Error trap. */
208                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
209 
210                 /* If trace is enabled, insert this event into the trace buffer.  */
211                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
212 
213                 /* There was an error, return to the caller */
214                 return(UX_TRANSFER_TIMEOUT);
215             }
216 #endif
217         }
218         else
219         {
220 #if defined(UX_HOST_STANDALONE)
221 
222             /* Restore transfer options.  */
223             transfer_request -> ux_transfer_request_flags = transfer_flags;
224 #endif
225 
226             /* Unprotect thread reentry to this instance.  */
227             _ux_host_class_printer_unlock(printer);
228 
229             /* There was a non transfer error, no partial transfer to be checked.  */
230             return(status);
231         }
232 
233         /* Update the length of the transfer. Normally all the data has to be received.  */
234         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
235 
236         /* Check for completion of transfer. If the transfer is partial, return to caller.
237            The transfer is marked as successful but the caller will need to check the length
238            actually received and determine if a partial transfer is OK.  */
239         if (transfer_request_length != transfer_request -> ux_transfer_request_actual_length)
240         {
241 #if defined(UX_HOST_STANDALONE)
242 
243             /* Restore transfer options.  */
244             transfer_request -> ux_transfer_request_flags = transfer_flags;
245 #endif
246 
247             /* Unprotect thread reentry to this instance.  */
248             _ux_host_class_printer_unlock(printer);
249 
250             /* Return success to caller.  */
251             return(UX_SUCCESS);
252         }
253 
254         /* Update the data pointer for next transfer. */
255         data_pointer +=  transfer_request_length;
256 
257         /* Update what is left to receive.  */
258         requested_length -=  transfer_request_length;
259     }
260 
261 #if defined(UX_HOST_STANDALONE)
262 
263     /* Restore transfer options.  */
264     transfer_request -> ux_transfer_request_flags = transfer_flags;
265 #endif
266 
267     /* Unprotect thread reentry to this instance.  */
268     _ux_host_class_printer_unlock(printer);
269 
270     /* We get here when all the transfers went through without errors.  */
271     return(UX_SUCCESS);
272 }
273 
274