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