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_ECM 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_ecm.h"
27 #include "ux_device_stack.h"
28 
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _ux_device_class_cdc_ecm_initialize                 PORTABLE C      */
35 /*                                                           6.3.0        */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Chaoqiong Xiao, Microsoft Corporation                               */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function initializes the USB CDC_ECM device.                   */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    command                               Pointer to cdc_ecm command    */
47 /*                                                                        */
48 /*  OUTPUT                                                                */
49 /*                                                                        */
50 /*    Completion Status                                                   */
51 /*                                                                        */
52 /*  CALLS                                                                 */
53 /*                                                                        */
54 /*    _ux_utility_memory_allocate           Allocate memory               */
55 /*    _ux_utility_memory_free               Free memory                   */
56 /*    _ux_utility_mutex_create              Create Mutex                  */
57 /*    _ux_device_mutex_delete               Delete Mutex                  */
58 /*    _ux_utility_event_flags_create        Create Flag group             */
59 /*    _ux_utility_event_flags_delete        Delete Flag group             */
60 /*    _ux_device_thread_create              Create Thread                 */
61 /*    _ux_device_thread_delete              Delete Thread                 */
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 /*                                            verified memset and memcpy  */
74 /*                                            cases, used UX prefix to    */
75 /*                                            refer to TX symbols instead */
76 /*                                            of using them directly,     */
77 /*                                            resulting in version 6.1    */
78 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
79 /*                                            refined macros names,       */
80 /*                                            resulting in version 6.1.10 */
81 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
82 /*                                            fixed standalone compile,   */
83 /*                                            resulting in version 6.1.11 */
84 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            fixed parameter/variable    */
86 /*                                            names conflict C++ keyword, */
87 /*                                            resulting in version 6.1.12 */
88 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            removed internal NX pool,   */
90 /*                                            resulting in version 6.2.0  */
91 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
92 /*                                            added a new mode to manage  */
93 /*                                            endpoint buffer in classes, */
94 /*                                            resulting in version 6.3.0  */
95 /*                                                                        */
96 /**************************************************************************/
_ux_device_class_cdc_ecm_initialize(UX_SLAVE_CLASS_COMMAND * command)97 UINT  _ux_device_class_cdc_ecm_initialize(UX_SLAVE_CLASS_COMMAND *command)
98 {
99 #if defined(UX_DEVICE_STANDALONE)
100     UX_PARAMETER_NOT_USED(command);
101     return(UX_FUNCTION_NOT_SUPPORTED);
102 #else
103 
104 UX_SLAVE_CLASS_CDC_ECM                          *cdc_ecm;
105 UX_SLAVE_CLASS_CDC_ECM_PARAMETER                *cdc_ecm_parameter;
106 UX_SLAVE_CLASS                                  *class_ptr;
107 UINT                                            status;
108 
109 
110     /* Get the class container.  */
111     class_ptr =  command -> ux_slave_class_command_class_ptr;
112 
113     /* Create an instance of the device cdc_ecm class.  */
114     cdc_ecm =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_SLAVE_CLASS_CDC_ECM));
115 
116     /* Check for successful allocation.  */
117     if (cdc_ecm == UX_NULL)
118         return(UX_MEMORY_INSUFFICIENT);
119 
120     /* Create a mutex to protect the CDC_ECM thread and the application messing up the transmit queue.  */
121     status =  _ux_utility_mutex_create(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex, "ux_slave_class_cdc_ecm_mutex");
122     if (status != UX_SUCCESS)
123     {
124         _ux_utility_memory_free(cdc_ecm);
125         return(UX_MUTEX_ERROR);
126     }
127 
128     /* Assume good result.  */
129     status = UX_SUCCESS;
130 
131 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
132 
133     /* Allocate buffer for endpoints.  */
134     UX_ASSERT(!UX_DEVICE_CLASS_CDC_ECM_ENDPOINT_BUFFER_SIZE_CALC_OVERFLOW);
135     cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer =
136             _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY,
137                                         UX_DEVICE_CLASS_CDC_ECM_ENDPOINT_BUFFER_SIZE);
138     if (cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer == UX_NULL)
139         status = (UX_MEMORY_INSUFFICIENT);
140 #endif
141 
142     /* Allocate some memory for the bulk out thread stack. */
143     cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack =
144             _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
145     if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack == UX_NULL)
146         status = (UX_MEMORY_INSUFFICIENT);
147 
148     /* Allocate some memory for the interrupt thread stack. */
149     if (status == UX_SUCCESS)
150     {
151         cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack =
152                 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
153 
154         /* Check for successful allocation.  */
155         if (cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack  == UX_NULL)
156             status = (UX_MEMORY_INSUFFICIENT);
157     }
158 
159     /* Allocate some memory for the bulk in thread stack. */
160     if (status == UX_SUCCESS)
161     {
162         cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack =
163                 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
164 
165         /* Check for successful allocation.  */
166         if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack == UX_NULL)
167             status = (UX_MEMORY_INSUFFICIENT);
168     }
169 
170     /* Interrupt endpoint treatment needs to be running in a different thread. So start
171        a new thread. We pass a pointer to the cdc_ecm instance to the new thread.  This thread
172        does not start until we have a instance of the class. */
173     if (status == UX_SUCCESS)
174     {
175         status =  _ux_device_thread_create(&cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread , "ux_slave_class_cdc_ecm_interrupt_thread",
176                     _ux_device_class_cdc_ecm_interrupt_thread,
177                     (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack ,
178                     UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
179                     UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
180         if (status != UX_SUCCESS)
181             status = (UX_THREAD_ERROR);
182     }
183 
184     UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread), class_ptr)
185 
186     /* Check the creation of this thread.  */
187     if (status == UX_SUCCESS)
188     {
189 
190         /* Bulk endpoint treatment needs to be running in a different thread. So start
191         a new thread. We pass a pointer to the cdc_ecm instance to the new thread.  This thread
192         does not start until we have a instance of the class. */
193         status =  _ux_device_thread_create(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread , "ux_slave_class_cdc_ecm_bulkout_thread",
194                     _ux_device_class_cdc_ecm_bulkout_thread,
195                     (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack ,
196                     UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
197                     UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
198         if (status != UX_SUCCESS)
199             status = (UX_THREAD_ERROR);
200         else
201         {
202 
203             UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread), class_ptr)
204 
205             /* Bulk endpoint treatment needs to be running in a different thread. So start
206             a new thread. We pass a pointer to the cdc_ecm instance to the new thread.  This thread
207             does not start until we have a instance of the class. */
208             status =  _ux_device_thread_create(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread , "ux_slave_class_cdc_ecm_bulkin_thread",
209                         _ux_device_class_cdc_ecm_bulkin_thread,
210                         (ULONG) (ALIGN_TYPE) class_ptr, (VOID *) cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack ,
211                         UX_THREAD_STACK_SIZE, UX_THREAD_PRIORITY_CLASS,
212                         UX_THREAD_PRIORITY_CLASS, UX_NO_TIME_SLICE, UX_DONT_START);
213             if (status != UX_SUCCESS)
214                 status = (UX_THREAD_ERROR);
215             else
216             {
217 
218                 UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread), class_ptr)
219 
220                 /* Create a event flag group for the cdc_ecm class to synchronize with the event interrupt thread.  */
221                 status =  _ux_utility_event_flags_create(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, "ux_device_class_cdc_ecm_event_flag");
222                 if (status != UX_SUCCESS)
223                     status = (UX_EVENT_ERROR);
224                 else
225                 {
226 
227                     /* Save the address of the CDC_ECM instance inside the CDC_ECM container.  */
228                     class_ptr -> ux_slave_class_instance = (VOID *) cdc_ecm;
229 
230                     /* Get the pointer to the application parameters for the cdc_ecm class.  */
231                     cdc_ecm_parameter =  command -> ux_slave_class_command_parameter;
232 
233                     /* Store the start and stop signals if needed by the application.  */
234                     cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate = cdc_ecm_parameter -> ux_slave_class_cdc_ecm_instance_activate;
235                     cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate = cdc_ecm_parameter -> ux_slave_class_cdc_ecm_instance_deactivate;
236 
237                     /* Copy the local node ID.  */
238                     _ux_utility_memory_copy(cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id, cdc_ecm_parameter -> ux_slave_class_cdc_ecm_parameter_local_node_id,
239                                             UX_DEVICE_CLASS_CDC_ECM_NODE_ID_LENGTH); /* Use case of memcpy is verified. */
240 
241                     /* Copy the remote node ID.  */
242                     _ux_utility_memory_copy(cdc_ecm -> ux_slave_class_cdc_ecm_remote_node_id, cdc_ecm_parameter -> ux_slave_class_cdc_ecm_parameter_remote_node_id,
243                                             UX_DEVICE_CLASS_CDC_ECM_NODE_ID_LENGTH); /* Use case of memcpy is verified. */
244 
245                     /* Store the rest of the parameters as they are in the local instance.  */
246                     _ux_utility_memory_copy(&cdc_ecm -> ux_slave_class_cdc_ecm_parameter, cdc_ecm_parameter, sizeof (UX_SLAVE_CLASS_CDC_ECM_PARAMETER)); /* Use case of memcpy is verified. */
247 
248                     return(UX_SUCCESS);
249                 }
250 
251                 _ux_device_thread_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread);
252             }
253 
254             _ux_device_thread_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread);
255         }
256 
257         _ux_device_thread_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread);
258     }
259 
260     /* Free allocated resources.  */
261 
262     if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack)
263         _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread_stack);
264     if (cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack)
265         _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread_stack);
266     if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack)
267         _ux_utility_memory_free(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread_stack);
268 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
269     if (cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer)
270         _ux_utility_memory_free(cdc_ecm -> ux_device_class_cdc_ecm_endpoint_buffer);
271 #endif
272     _ux_device_mutex_delete(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
273     _ux_utility_memory_free(cdc_ecm);
274 
275     /* Return completion status.  */
276     return(status);
277 #endif
278 }
279