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 /**   CDC ACM 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_cdc_acm.h"
29 #include "ux_host_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_host_class_cdc_acm_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 cdc_acm 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 /*    cdc_acm                               Pointer to cdc_acm 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 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    Application                                                         */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
74 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            resulting in version 6.1    */
76 /*  12-31-2020     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            fixed ZLP sending,          */
78 /*                                            resulting in version 6.1.3  */
79 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            added standalone support,   */
81 /*                                            resulting in version 6.1.10 */
82 /*                                                                        */
83 /**************************************************************************/
_ux_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM * cdc_acm,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)84 UINT  _ux_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM *cdc_acm, UCHAR *data_pointer,
85                                     ULONG requested_length, ULONG *actual_length)
86 {
87 
88 UX_TRANSFER     *transfer_request;
89 UINT            status;
90 ULONG           transfer_request_length;
91 #if defined(UX_HOST_STANDALONE)
92 ULONG           transfer_flags;
93 #endif
94 
95     /* If trace is enabled, insert this event into the trace buffer.  */
96     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ACM_WRITE, cdc_acm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
97 
98     /* Ensure the instance is valid.  */
99     if (cdc_acm -> ux_host_class_cdc_acm_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
100     {
101 
102         /* Error trap. */
103         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
104 
105         /* If trace is enabled, insert this event into the trace buffer.  */
106         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, cdc_acm, 0, 0, UX_TRACE_ERRORS, 0, 0)
107 
108         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
109     }
110 
111     /* As further protection, we must ensure this instance of the interface is the data interface and not
112        the control interface !  */
113     if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass != UX_HOST_CLASS_CDC_DATA_CLASS)
114     {
115 
116         /* Error trap. */
117         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
118 
119         /* If trace is enabled, insert this event into the trace buffer.  */
120         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, cdc_acm, 0, 0, UX_TRACE_ERRORS, 0, 0)
121 
122         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
123     }
124 
125 #if defined(UX_HOST_STANDALONE)
126     if (cdc_acm -> ux_host_class_cdc_acm_write_state == UX_STATE_WAIT)
127         return(UX_BUSY);
128     cdc_acm -> ux_host_class_cdc_acm_write_state = UX_STATE_WAIT;
129 #endif
130 
131     /* Start by resetting the actual length of the transfer.  */
132     *actual_length =  0;
133 
134     /* Get the pointer to the bulk out endpoint transfer request.  */
135     transfer_request =  &cdc_acm -> ux_host_class_cdc_acm_bulk_out_endpoint -> ux_endpoint_transfer_request;
136 
137 #if defined(UX_HOST_STANDALONE)
138 
139     /* Enable auto wait.  */
140     transfer_flags = transfer_request -> ux_transfer_request_flags;
141     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
142 #endif
143 
144     /* Perform a transfer on the bulk out endpoint until either the transfer is
145        completed or when there is an error.  */
146     do
147     {
148 
149         /* Program the maximum authorized length for this transfer_request.  */
150         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
151             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
152         else
153             transfer_request_length =  requested_length;
154 
155         /* Initialize the transfer_request.  */
156         transfer_request -> ux_transfer_request_data_pointer =  data_pointer;
157         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
158 
159         /* Perform the transfer.  */
160         status =  _ux_host_stack_transfer_request(transfer_request);
161 
162         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
163         if (status == UX_SUCCESS)
164         {
165 
166 #if !defined(UX_HOST_STANDALONE)
167             /* Wait for the completion of the transfer request.  */
168             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore,
169                                              transfer_request -> ux_transfer_request_timeout_value);
170 
171             /* If the semaphore did not succeed we probably have a time out.  */
172             if (status != UX_SUCCESS)
173             {
174 
175                 /* All transfers pending need to abort. There may have been a partial transfer.  */
176                 _ux_host_stack_transfer_request_abort(transfer_request);
177 
178                 /* Update the length of the actual data transferred. We do this after the
179                    abort of the transfer_request in case some data actually went out.  */
180                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
181 
182                 /* Set the completion code.  */
183                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
184 
185                 /* Error trap. */
186                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
187 
188                 /* If trace is enabled, insert this event into the trace buffer.  */
189                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
190 
191                 /* There was an error, return to the caller.  */
192                 return(UX_TRANSFER_TIMEOUT);
193             }
194 #endif
195         }
196         else
197         {
198 
199 #if defined(UX_HOST_STANDALONE)
200 
201             /* Update the length of the actual data transferred. We do this after the
202                 abort of the transfer request in case some data was actually received.  */
203             *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
204 
205             /* Restore previous setting.  */
206             transfer_request -> ux_transfer_request_flags = transfer_flags;
207 
208             /* Not busy any more.  */
209             cdc_acm -> ux_host_class_cdc_acm_write_state = UX_STATE_RESET;
210 #endif
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 
225             /* Return success.  */
226             return(UX_SUCCESS);
227         }
228 
229         /* Update the data pointer for next transfer.  */
230         data_pointer +=  transfer_request_length;
231 
232         /* Update what is left to send out.  */
233         requested_length -=  transfer_request_length;
234 
235     } while (requested_length);
236 
237 #if defined(UX_HOST_STANDALONE)
238 
239     /* Restore previous setting.  */
240     transfer_request -> ux_transfer_request_flags = transfer_flags;
241 
242     /* Not busy any more.  */
243     cdc_acm -> ux_host_class_cdc_acm_write_state = UX_STATE_RESET;
244 #endif
245 
246     /* We get here when all the transfers went through without errors.  */
247     return(UX_SUCCESS);
248 }
249 
250 
251 /**************************************************************************/
252 /*                                                                        */
253 /*  FUNCTION                                               RELEASE        */
254 /*                                                                        */
255 /*    _uxe_host_class_cdc_acm_write                       PORTABLE C      */
256 /*                                                           6.3.0        */
257 /*  AUTHOR                                                                */
258 /*                                                                        */
259 /*    Chaoqiong Xiao, Microsoft Corporation                               */
260 /*                                                                        */
261 /*  DESCRIPTION                                                           */
262 /*                                                                        */
263 /*    This function checks errors in CDC ACM write function call.         */
264 /*                                                                        */
265 /*  INPUT                                                                 */
266 /*                                                                        */
267 /*    cdc_acm                               Pointer to CDC ACM class      */
268 /*    data_pointer                          Pointer to data to write      */
269 /*    requested_length                      Length of data to write       */
270 /*    actual_length                         Actual length of data written */
271 /*                                                                        */
272 /*  OUTPUT                                                                */
273 /*                                                                        */
274 /*    Status                                                              */
275 /*                                                                        */
276 /*  CALLS                                                                 */
277 /*                                                                        */
278 /*    _ux_host_class_cdc_acm_write          CDC ACM write                 */
279 /*                                                                        */
280 /*  CALLED BY                                                             */
281 /*                                                                        */
282 /*    Application                                                         */
283 /*                                                                        */
284 /*  RELEASE HISTORY                                                       */
285 /*                                                                        */
286 /*    DATE              NAME                      DESCRIPTION             */
287 /*                                                                        */
288 /*  10-31-2023     Chaoqiong Xiao           Initial Version 6.3.0         */
289 /*                                                                        */
290 /**************************************************************************/
_uxe_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM * cdc_acm,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)291 UINT  _uxe_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM *cdc_acm, UCHAR *data_pointer,
292                                     ULONG requested_length, ULONG *actual_length)
293 {
294 
295     /* Sanity checks.  */
296     if ((cdc_acm == UX_NULL) ||
297         ((data_pointer == UX_NULL) && (requested_length != 0)) ||
298         (actual_length == UX_NULL))
299     {
300         return(UX_INVALID_PARAMETER);
301     }
302 
303     /* Invoke CDC ACM write function.  */
304     return(_ux_host_class_cdc_acm_write(cdc_acm, data_pointer, requested_length, actual_length));
305 }
306