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 /**   CDC ACM 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_cdc_acm.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_class_cdc_acm_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 cdc_acm 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 /*    cdc_acm                               Pointer to cdc_acm 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 /*                                                                        */
66 /*  CALLED BY                                                             */
67 /*                                                                        */
68 /*    Application                                                         */
69 /*                                                                        */
70 /*  RELEASE HISTORY                                                       */
71 /*                                                                        */
72 /*    DATE              NAME                      DESCRIPTION             */
73 /*                                                                        */
74 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
75 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            resulting in version 6.1    */
77 /*  12-31-2020     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            fixed ZLP sending,          */
79 /*                                            resulting in version 6.1.3  */
80 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            added standalone support,   */
82 /*                                            resulting in version 6.1.10 */
83 /*                                                                        */
84 /**************************************************************************/
_ux_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM * cdc_acm,UCHAR * data_pointer,ULONG requested_length,ULONG * actual_length)85 UINT  _ux_host_class_cdc_acm_write(UX_HOST_CLASS_CDC_ACM *cdc_acm, UCHAR *data_pointer,
86                                     ULONG requested_length, ULONG *actual_length)
87 {
88 
89 UX_TRANSFER     *transfer_request;
90 UINT            status;
91 ULONG           transfer_request_length;
92 #if defined(UX_HOST_STANDALONE)
93 ULONG           transfer_flags;
94 #endif
95 
96     /* If trace is enabled, insert this event into the trace buffer.  */
97     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ACM_WRITE, cdc_acm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
98 
99     /* Ensure the instance is valid.  */
100     if (cdc_acm -> ux_host_class_cdc_acm_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
101     {
102 
103         /* Error trap. */
104         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
105 
106         /* If trace is enabled, insert this event into the trace buffer.  */
107         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, cdc_acm, 0, 0, UX_TRACE_ERRORS, 0, 0)
108 
109         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
110     }
111 
112     /* As further protection, we must ensure this instance of the interface is the data interface and not
113        the control interface !  */
114     if (cdc_acm -> ux_host_class_cdc_acm_interface -> ux_interface_descriptor.bInterfaceClass != UX_HOST_CLASS_CDC_DATA_CLASS)
115     {
116 
117         /* Error trap. */
118         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
119 
120         /* If trace is enabled, insert this event into the trace buffer.  */
121         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, cdc_acm, 0, 0, UX_TRACE_ERRORS, 0, 0)
122 
123         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
124     }
125 
126 #if defined(UX_HOST_STANDALONE)
127     if (cdc_acm -> ux_host_class_cdc_acm_write_state == UX_STATE_WAIT)
128         return(UX_BUSY);
129     cdc_acm -> ux_host_class_cdc_acm_write_state = UX_STATE_WAIT;
130 #endif
131 
132     /* Start by resetting the actual length of the transfer.  */
133     *actual_length =  0;
134 
135     /* Get the pointer to the bulk out endpoint transfer request.  */
136     transfer_request =  &cdc_acm -> ux_host_class_cdc_acm_bulk_out_endpoint -> ux_endpoint_transfer_request;
137 
138 #if defined(UX_HOST_STANDALONE)
139 
140     /* Enable auto wait.  */
141     transfer_flags = transfer_request -> ux_transfer_request_flags;
142     transfer_request -> ux_transfer_request_flags |= UX_TRANSFER_FLAG_AUTO_WAIT;
143 #endif
144 
145     /* Perform a transfer on the bulk out endpoint until either the transfer is
146        completed or when there is an error.  */
147     do
148     {
149 
150         /* Program the maximum authorized length for this transfer_request.  */
151         if (requested_length > transfer_request -> ux_transfer_request_maximum_length)
152             transfer_request_length =  transfer_request -> ux_transfer_request_maximum_length;
153         else
154             transfer_request_length =  requested_length;
155 
156         /* Initialize the transfer_request.  */
157         transfer_request -> ux_transfer_request_data_pointer =  data_pointer;
158         transfer_request -> ux_transfer_request_requested_length =  transfer_request_length;
159 
160         /* Perform the transfer.  */
161         status =  _ux_host_stack_transfer_request(transfer_request);
162 
163         /* If the transfer is successful, we need to wait for the transfer request to be completed.  */
164         if (status == UX_SUCCESS)
165         {
166 
167 #if !defined(UX_HOST_STANDALONE)
168             /* Wait for the completion of the transfer request.  */
169             status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore,
170                                              transfer_request -> ux_transfer_request_timeout_value);
171 
172             /* If the semaphore did not succeed we probably have a time out.  */
173             if (status != UX_SUCCESS)
174             {
175 
176                 /* All transfers pending need to abort. There may have been a partial transfer.  */
177                 _ux_host_stack_transfer_request_abort(transfer_request);
178 
179                 /* Update the length of the actual data transferred. We do this after the
180                    abort of the transfer_request in case some data actually went out.  */
181                 *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
182 
183                 /* Set the completion code.  */
184                 transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
185 
186                 /* Error trap. */
187                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT);
188 
189                 /* If trace is enabled, insert this event into the trace buffer.  */
190                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
191 
192                 /* There was an error, return to the caller.  */
193                 return(UX_TRANSFER_TIMEOUT);
194             }
195 #endif
196         }
197         else
198         {
199 
200 #if defined(UX_HOST_STANDALONE)
201 
202             /* Update the length of the actual data transferred. We do this after the
203                 abort of the transfer request in case some data was actually received.  */
204             *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
205 
206             /* Restore previous setting.  */
207             transfer_request -> ux_transfer_request_flags = transfer_flags;
208 
209             /* Not busy any more.  */
210             cdc_acm -> ux_host_class_cdc_acm_write_state = UX_STATE_RESET;
211 #endif
212 
213             /* There was a non transfer error, no partial transfer to be checked */
214             return(status);
215         }
216 
217         /* Update the length of the transfer. Normally all the data has to be sent.  */
218         *actual_length +=  transfer_request -> ux_transfer_request_actual_length;
219 
220         /* Check for completion of transfer. If the transfer is partial, return to caller.
221            The transfer is marked as successful but the caller will need to check the length
222            actually sent and determine if a partial transfer is OK. */
223         if (transfer_request_length !=  transfer_request -> ux_transfer_request_actual_length)
224         {
225 
226             /* Return success.  */
227             return(UX_SUCCESS);
228         }
229 
230         /* Update the data pointer for next transfer.  */
231         data_pointer +=  transfer_request_length;
232 
233         /* Update what is left to send out.  */
234         requested_length -=  transfer_request_length;
235 
236     } while (requested_length);
237 
238 #if defined(UX_HOST_STANDALONE)
239 
240     /* Restore previous setting.  */
241     transfer_request -> ux_transfer_request_flags = transfer_flags;
242 
243     /* Not busy any more.  */
244     cdc_acm -> ux_host_class_cdc_acm_write_state = UX_STATE_RESET;
245 #endif
246 
247     /* We get here when all the transfers went through without errors.  */
248     return(UX_SUCCESS);
249 }
250 
251