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_write                        PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function writes to the printer interface. The call is blocking */
46 /*    and only returns when there is either an error or when the transfer */
47 /*    is complete.                                                        */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    printer                               Pointer to printer class      */
52 /*    data_pointer                          Pointer to data to write      */
53 /*    requested_length                      Length of data to write       */
54 /*    actual_length                         Actual length of data written */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    Completion Status                                                   */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _ux_host_stack_transfer_request       Process transfer request      */
63 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
64 /*    _ux_host_semaphore_get                Get protection semaphore      */
65 /*    _ux_host_semaphore_put                Release protection semaphore  */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    Application                                                         */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
76 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            prefixed UX to MS_TO_TICK,  */
78 /*                                            resulting in version 6.1    */
79 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            fixed ZLP sending issue,    */
81 /*                                            resulting in version 6.1.9  */
82 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            added standalone support,   */
84 /*                                            resulting in version 6.1.10 */
85 /*                                                                        */
86 /**************************************************************************/
_ux_host_class_printer_write(UX_HOST_CLASS_PRINTER * printer,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)87 UINT  _ux_host_class_printer_write(UX_HOST_CLASS_PRINTER *printer, UCHAR * data_pointer,
88                                     ULONG requested_length, ULONG *actual_length)
89 {
90 
91 #if defined(UX_HOST_STANDALONE)
92 UX_INTERRUPT_SAVE_AREA
93 ULONG           transfer_flags;
94 #endif
95 UX_TRANSFER     *transfer_request;
96 UINT            status;
97 ULONG           transfer_request_length;
98 
99     /* If trace is enabled, insert this event into the trace buffer.  */
100     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PRINTER_WRITE, printer, data_pointer, requested_length, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
101 
102     /* Ensure the instance is valid.  */
103     if (printer -> ux_host_class_printer_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
104     {
105 
106         /* Error trap. */
107         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
108 
109         /* If trace is enabled, insert this event into the trace buffer.  */
110         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, printer, 0, 0, UX_TRACE_ERRORS, 0, 0)
111 
112         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
113     }
114 
115 #if defined(UX_HOST_STANDALONE)
116     UX_DISABLE
117     if (printer -> ux_host_class_printer_flags & UX_HOST_CLASS_PRINTER_FLAG_LOCK)
118     {
119         UX_RESTORE
120         return(UX_BUSY);
121     }
122     printer -> ux_host_class_printer_flags |= UX_HOST_CLASS_PRINTER_FLAG_LOCK;
123     UX_RESTORE
124 #else
125 
126     /* Protect thread reentry to this instance.  */
127     status =  _ux_host_semaphore_get(&printer -> ux_host_class_printer_semaphore, UX_WAIT_FOREVER);
128     if (status != UX_SUCCESS)
129 
130         /* Return error.  */
131         return(status);
132 #endif
133 
134     /* Start by resetting the actual length of the transfer.  */
135     *actual_length =  0;
136 
137     /* Get the pointer to the bulk out endpoint transfer request.  */
138     transfer_request =  &printer -> ux_host_class_printer_bulk_out_endpoint -> ux_endpoint_transfer_request;
139 
140 #if defined(UX_HOST_STANDALONE)
141 
142     /* Enable blocking transfer flags.  */
143     transfer_flags = transfer_request -> ux_transfer_request_flags;
144     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
145 #endif
146 
147     /* Perform a transfer on the bulk out endpoint until either the transfer is
148        completed or when there is an error.  */
149     do
150     {
151 
152         /* Program the maximum authorized length for this transfer_request.  */
153         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
154             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
155         else
156             transfer_request_length =  requested_length;
157 
158         /* Initialize the transfer_request.  */
159         transfer_request -> ux_transfer_request_data_pointer =  data_pointer;
160         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
161 
162         /* Perform the transfer.  */
163         status =  _ux_host_stack_transfer_request(transfer_request);
164 
165         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
166         if (status == UX_SUCCESS)
167         {
168 #if !defined(UX_HOST_STANDALONE)
169 
170             /* Wait for the completion of the transfer request.  */
171             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_HOST_CLASS_PRINTER_CLASS_TRANSFER_TIMEOUT));
172 
173             /* If the semaphore did not succeed we probably have a time out.  */
174             if (status != UX_SUCCESS)
175             {
176 
177                 /* All transfers pending need to abort. There may have been a partial transfer.  */
178                 _ux_host_stack_transfer_request_abort(transfer_request);
179 
180                 /* Update the length of the actual data transferred. We do this after the
181                    abort of the transfer_request in case some data actually went out.  */
182                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
183 
184                 /* Unprotect thread reentry to this instance.  */
185                 _ux_host_class_printer_unlock(printer);
186 
187                 /* Set the completion code.  */
188                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
189 
190                 /* Error trap. */
191                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
192 
193                 /* If trace is enabled, insert this event into the trace buffer.  */
194                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
195 
196                 /* There was an error, return to the caller.  */
197                 return(UX_TRANSFER_TIMEOUT);
198             }
199 #endif
200         }
201         else
202         {
203 #if defined(UX_HOST_STANDALONE)
204 
205             /* Restore transfer options.  */
206             transfer_request -> ux_transfer_request_flags = transfer_flags;
207 #endif
208 
209             /* Unprotect thread reentry to this instance.  */
210             _ux_host_class_printer_unlock(printer);
211 
212             /* There was a non transfer error, no partial transfer to be checked */
213             return(status);
214         }
215 
216         /* Update the length of the transfer. Normally all the data has to be sent.  */
217         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
218 
219         /* Check for completion of transfer. If the transfer is partial, return to caller.
220            The transfer is marked as successful but the caller will need to check the length
221            actually sent and determine if a partial transfer is OK. */
222         if (transfer_request_length !=  transfer_request -> ux_transfer_request_actual_length)
223         {
224 #if defined(UX_HOST_STANDALONE)
225 
226             /* Restore transfer options.  */
227             transfer_request -> ux_transfer_request_flags = transfer_flags;
228 #endif
229 
230             /* Unprotect thread reentry to this instance.  */
231             _ux_host_class_printer_unlock(printer);
232 
233             /* Return success.  */
234             return(UX_SUCCESS);
235         }
236 
237         /* Update the data pointer for next transfer.  */
238         data_pointer +=  transfer_request_length;
239 
240         /* Update what is left to send out.  */
241         requested_length -=  transfer_request_length;
242     } while (requested_length);
243 
244 #if defined(UX_HOST_STANDALONE)
245 
246     /* Restore transfer options.  */
247     transfer_request -> ux_transfer_request_flags = transfer_flags;
248 #endif
249 
250     /* Unprotect thread reentry to this instance.  */
251     _ux_host_class_printer_unlock(printer);
252 
253     /* We get here when all the transfers went through without errors.  */
254     return(UX_SUCCESS);
255 }
256 
257