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 /** USBX Component */
14 /** */
15 /** Device CDC Class */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19
20 #define UX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "ux_api.h"
26 #include "ux_device_class_cdc_acm.h"
27 #include "ux_device_stack.h"
28
29
30 #if UX_OVERFLOW_CHECK_MULC_ULONG(UX_THREAD_STACK_SIZE, 2)
31 #error UX_THREAD_STACK_SIZE too large
32 #endif
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _ux_device_class_cdc_acm_initialize PORTABLE C */
39 /* 6.3.0 */
40 /* AUTHOR */
41 /* */
42 /* Chaoqiong Xiao, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function initializes the USB CDC device. */
47 /* */
48 /* INPUT */
49 /* */
50 /* command Pointer to cdc_acm command */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* Completion Status */
55 /* */
56 /* CALLS */
57 /* */
58 /* _ux_utility_memory_allocate Allocate memory */
59 /* _ux_utility_memory_free Free memory */
60 /* _ux_utility_mutex_create Create mutex */
61 /* _ux_device_mutex_delete Delete mutex */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* USBX Source Code */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
72 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
73 /* resulting in version 6.1 */
74 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
75 /* added macro to disable */
76 /* transmission support, */
77 /* moved transmission resource */
78 /* allocate to here (init), */
79 /* resulting in version 6.1.6 */
80 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
81 /* added standalone support, */
82 /* resulting in version 6.1.10 */
83 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
84 /* resulting in version 6.1.11 */
85 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
86 /* fixed parameter/variable */
87 /* names conflict C++ keyword, */
88 /* resulting in version 6.1.12 */
89 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
90 /* added zero copy support, */
91 /* added a new mode to manage */
92 /* endpoint buffer in classes, */
93 /* resulting in version 6.3.0 */
94 /* */
95 /**************************************************************************/
_ux_device_class_cdc_acm_initialize(UX_SLAVE_CLASS_COMMAND * command)96 UINT _ux_device_class_cdc_acm_initialize(UX_SLAVE_CLASS_COMMAND *command)
97 {
98
99 UX_SLAVE_CLASS_CDC_ACM *cdc_acm;
100 UX_SLAVE_CLASS_CDC_ACM_PARAMETER *cdc_acm_parameter;
101 UX_SLAVE_CLASS *class_ptr;
102 #if !defined(UX_DEVICE_STANDALONE)
103 UINT status;
104 #endif
105
106 /* Get the class container. */
107 class_ptr = command -> ux_slave_class_command_class_ptr;
108
109 /* Create an instance of the device cdc_acm class. */
110 cdc_acm = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_CDC_ACM));
111
112 /* Check for successful allocation. */
113 if (cdc_acm == UX_NULL)
114 return(UX_MEMORY_INSUFFICIENT);
115
116 /* Save the address of the CDC instance inside the CDC container. */
117 class_ptr -> ux_slave_class_instance = (VOID *) cdc_acm;
118
119 /* Get the pointer to the application parameters for the cdc_acm class. */
120 cdc_acm_parameter = command -> ux_slave_class_command_parameter;
121
122 /* Store the start and stop signals if needed by the application. */
123 cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_instance_activate = cdc_acm_parameter -> ux_slave_class_cdc_acm_instance_activate;
124 cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_instance_deactivate = cdc_acm_parameter -> ux_slave_class_cdc_acm_instance_deactivate;
125 cdc_acm -> ux_slave_class_cdc_acm_parameter.ux_slave_class_cdc_acm_parameter_change = cdc_acm_parameter -> ux_slave_class_cdc_acm_parameter_change;
126
127 #if defined(UX_DEVICE_CLASS_CDC_ACM_OWN_ENDPOINT_BUFFER)
128
129 /* Allocate the buffer for the CDC ACM endpoints. */
130 UX_ASSERT(!UX_DEVICE_CLASS_CDC_ACM_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW);
131 cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY,
132 UX_DEVICE_CLASS_CDC_ACM_ENDPOINT_BUFFER_SIZE);
133 if (cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer == UX_NULL)
134 {
135
136 /* Free the resources. */
137 _ux_utility_memory_free(cdc_acm);
138
139 /* Return fatal error. */
140 return(UX_MEMORY_INSUFFICIENT);
141 }
142 #endif
143
144 #if !defined(UX_DEVICE_STANDALONE)
145
146 /* Create the Mutex for each endpoint as multiple threads cannot access each pipe at the same time. */
147 status = _ux_utility_mutex_create(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_in_mutex, "ux_slave_class_cdc_acm_in_mutex");
148
149 /* Check Mutex creation error. */
150 if(status != UX_SUCCESS)
151 {
152
153 /* Free the resources. */
154 #if defined(UX_DEVICE_CLASS_CDC_ACM_OWN_ENDPOINT_BUFFER)
155 _ux_utility_memory_free(cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer);
156 #endif
157 _ux_utility_memory_free(cdc_acm);
158
159 /* Return fatal error. */
160 return(UX_MUTEX_ERROR);
161 }
162
163 /* Out Mutex. */
164 status = _ux_utility_mutex_create(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex, "ux_slave_class_cdc_acm_out_mutex");
165
166 /* Check Mutex creation error. */
167 if(status != UX_SUCCESS)
168 {
169
170 /* Delete the endpoint IN mutex. */
171 _ux_device_mutex_delete(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_in_mutex);
172
173 /* Free the resources. */
174 #if defined(UX_DEVICE_CLASS_CDC_ACM_OWN_ENDPOINT_BUFFER)
175 _ux_utility_memory_free(cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer);
176 #endif
177 _ux_utility_memory_free(cdc_acm);
178
179 /* Return fatal error. */
180 return(UX_MUTEX_ERROR);
181 }
182
183 #endif
184
185 /* Update the line coding fields with default values. */
186 cdc_acm -> ux_slave_class_cdc_acm_baudrate = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_BAUDRATE;
187 cdc_acm -> ux_slave_class_cdc_acm_stop_bit = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_STOP_BIT;
188 cdc_acm -> ux_slave_class_cdc_acm_parity = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_PARITY;
189 cdc_acm -> ux_slave_class_cdc_acm_data_bit = UX_SLAVE_CLASS_CDC_ACM_LINE_CODING_DATA_BIT;
190
191 #ifndef UX_DEVICE_CLASS_CDC_ACM_TRANSMISSION_DISABLE
192
193 #if defined(UX_DEVICE_STANDALONE)
194
195 /* Set task function. */
196 class_ptr -> ux_slave_class_task_function = _ux_device_class_cdc_acm_tasks_run;
197 #else
198
199 /* We need to prepare the 2 threads for sending and receiving. */
200 /* Allocate some memory for the bulk out and in thread stack. */
201 cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack =
202 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE * 2);
203
204 /* Check for successful allocation. */
205 if (cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack == UX_NULL)
206
207 /* Return the status to the caller. */
208 status = (UX_MEMORY_INSUFFICIENT);
209
210 /* If success, go on to create event flags. */
211 if (status == UX_SUCCESS)
212 {
213
214 /* Allocate some memory for the bulk in thread stack. */
215 cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread_stack =
216 cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack + UX_THREAD_STACK_SIZE;
217
218 /* Create a event flag group for the cdc_acm class to synchronize with the application writing event . */
219 status = _ux_utility_event_flags_create(
220 &cdc_acm -> ux_slave_class_cdc_acm_event_flags_group,
221 "ux_device_class_cdc_acm_event_flag");
222
223 /* Check status. */
224 if (status != UX_SUCCESS)
225 {
226 status = (UX_EVENT_ERROR);
227 }
228 }
229
230 /* If success, go on to create bulkin thread. */
231 if (status == UX_SUCCESS)
232 {
233
234 /* Bulk endpoint treatment needs to be running in a different thread. So start
235 a new thread. We pass a pointer to the cdc_acm instance to the new thread. This thread
236 does not start until we have a instance of the class. */
237 status = _ux_utility_thread_create(
238 &cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread,
239 "ux_slave_class_cdc_acm_bulkin_thread",
240 _ux_device_class_cdc_acm_bulkin_thread,
241 (ULONG) (ALIGN_TYPE) cdc_acm,
242 (VOID *) cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread_stack,
243 UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
244 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
245
246 /* Check the creation of this thread. */
247 if (status != UX_SUCCESS)
248 {
249 status = (UX_THREAD_ERROR);
250 }
251 else
252 {
253 UX_THREAD_EXTENSION_PTR_SET(
254 &(cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread), cdc_acm)
255 }
256 }
257
258 /* If success, go on to create bulkout thread. */
259 if (status == UX_SUCCESS)
260 {
261
262 /* Bulk endpoint treatment needs to be running in a different thread. So start
263 a new thread. We pass a pointer to the cdc_acm instance to the new thread. This thread
264 does not start until we have a instance of the class. */
265 status = _ux_utility_thread_create(
266 &cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread,
267 "ux_slave_class_cdc_acm_bulkout_thread",
268 _ux_device_class_cdc_acm_bulkout_thread,
269 (ULONG) (ALIGN_TYPE) cdc_acm,
270 (VOID *) cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack,
271 UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
272 UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
273
274 /* Check the creation of this thread. */
275 if (status != UX_SUCCESS)
276 {
277 status = (UX_THREAD_ERROR);
278 }
279 else
280 {
281 UX_THREAD_EXTENSION_PTR_SET(
282 &(cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread), cdc_acm)
283 }
284 }
285
286 /* Check error. */
287 if (status != UX_SUCCESS)
288 {
289
290 /* Free resources and return error. */
291 if (cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread.tx_thread_id)
292 _ux_utility_thread_delete(&cdc_acm -> ux_slave_class_cdc_acm_bulkin_thread);
293 if (cdc_acm -> ux_slave_class_cdc_acm_event_flags_group.tx_event_flags_group_id)
294 _ux_utility_event_flags_delete(&cdc_acm -> ux_slave_class_cdc_acm_event_flags_group);
295 if (cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack)
296 _ux_utility_memory_free(cdc_acm -> ux_slave_class_cdc_acm_bulkout_thread_stack);
297 _ux_device_mutex_delete(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_in_mutex);
298 _ux_device_mutex_delete(&cdc_acm -> ux_slave_class_cdc_acm_endpoint_out_mutex);
299 #if defined(UX_DEVICE_CLASS_CDC_ACM_OWN_ENDPOINT_BUFFER)
300 _ux_utility_memory_free(cdc_acm -> ux_device_class_cdc_acm_endpoint_buffer);
301 #endif
302 _ux_utility_memory_free(cdc_acm);
303 return(status);
304 }
305
306 #endif
307 #endif
308
309 /* Return completion status. */
310 return(UX_SUCCESS);
311 }
312
313