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