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 /**************************************************************************/
14 /**                                                                       */
15 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   CDC ECM Class                                                       */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 /* Include necessary system files.  */
24 
25 #define UX_SOURCE_CODE
26 
27 #include "ux_api.h"
28 #include "ux_host_class_cdc_ecm.h"
29 #include "ux_host_stack.h"
30 
31 UX_HOST_CLASS_CDC_ECM_NX_ETHERNET_POOL_ALLOCSIZE_ASSERT
32 
33 #if !defined(UX_HOST_STANDALONE)
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _ux_host_class_cdc_ecm_activate                     PORTABLE C      */
39 /*                                                           6.2.0        */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Chaoqiong Xiao, Microsoft Corporation                               */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function creates the cdc_ecm instance, configure the device.   */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    command                             CDC ECM class command pointer   */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    Completion Status                                                   */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _ux_host_stack_transfer_request          Transfer request           */
59 /*    _ux_host_class_cdc_ecm_endpoints_get     Get endpoints of cdc_ecm   */
60 /*    _ux_host_class_cdc_ecm_mac_address_get   Get MAC address */
61 /*    _ux_host_stack_class_instance_create     Create class instance      */
62 /*    _ux_host_stack_class_instance_destroy    Destroy the class instance */
63 /*    _ux_utility_memory_allocate              Allocate memory block      */
64 /*    _ux_utility_memory_free                  Free memory block          */
65 /*    _ux_host_semaphore_create                Create semaphore           */
66 /*    _ux_host_semaphore_delete                Delete semaphore           */
67 /*    _ux_utility_thread_create                Create thread              */
68 /*    _ux_utility_thread_delete                Delete thread              */
69 /*    _ux_utility_thread_resume                Resume thread              */
70 /*    _ux_network_driver_activate              Activate NetX USB interface*/
71 /*    nx_packet_pool_create                    Create NetX packet pool    */
72 /*    nx_packet_pool_delete                    Delete NetX packet pool    */
73 /*                                                                        */
74 /*  CALLED BY                                                             */
75 /*                                                                        */
76 /*    _ux_host_class_cdc_ecm_entry             Entry of cdc_ecm class     */
77 /*                                                                        */
78 /*  RELEASE HISTORY                                                       */
79 /*                                                                        */
80 /*    DATE              NAME                      DESCRIPTION             */
81 /*                                                                        */
82 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
83 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
84 /*                                            used UX prefix to refer to  */
85 /*                                            TX symbols instead of using */
86 /*                                            them directly,              */
87 /*                                            resulting in version 6.1    */
88 /*  02-02-2021     Xiuwen Cai               Modified comment(s), added    */
89 /*                                            compile option for using    */
90 /*                                            packet pool from NetX,      */
91 /*                                            resulting in version 6.1.4  */
92 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
93 /*                                            refined macros names,       */
94 /*                                            resulting in version 6.1.10 */
95 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
96 /*                                            fixed standalone compile,   */
97 /*                                            resulting in version 6.1.11 */
98 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
99 /*                                            fixed parameter/variable    */
100 /*                                            names conflict C++ keyword, */
101 /*                                            resulting in version 6.1.12 */
102 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
103 /*                                            deprecated ECM pool option, */
104 /*                                            supported NX packet chain,  */
105 /*                                            resulting in version 6.2.0  */
106 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
107 /*                                            rejected the CDC ECM data   */
108 /*                                            interface not next to ctrl, */
109 /*                                            resulting in version 6.3.0  */
110 /*                                                                        */
111 /**************************************************************************/
_ux_host_class_cdc_ecm_activate(UX_HOST_CLASS_COMMAND * command)112 UINT  _ux_host_class_cdc_ecm_activate(UX_HOST_CLASS_COMMAND *command)
113 {
114 
115 UX_INTERFACE                        *interface_ptr;
116 UX_HOST_CLASS_CDC_ECM               *cdc_ecm;
117 UINT                                status;
118 UX_TRANSFER                         *transfer_request;
119 ULONG                               physical_address_msw = 0;
120 ULONG                               physical_address_lsw = 0;
121 UX_INTERFACE                        *control_interface;
122 UX_INTERFACE                        *cur_interface;
123 
124     /* The CDC ECM class is always activated by the interface descriptor and not the
125        device descriptor.  */
126     interface_ptr =  (UX_INTERFACE *) command -> ux_host_class_command_container;
127 
128     /* Is this the control interface?  */
129     if (interface_ptr -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
130     {
131 
132         /* We ignore the control interface. All activation is performed when
133            we receive the data interface.  */
134         return(UX_SUCCESS);
135     }
136 
137     /* Obtain memory for this class instance.  */
138     cdc_ecm =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, sizeof(UX_HOST_CLASS_CDC_ECM));
139     if (cdc_ecm == UX_NULL)
140         return(UX_MEMORY_INSUFFICIENT);
141 
142     /* Store the class container into this instance.  */
143     cdc_ecm -> ux_host_class_cdc_ecm_class =  command -> ux_host_class_command_class_ptr;
144 
145     /* Store the device container into the cdc_ecm class instance.  */
146     cdc_ecm -> ux_host_class_cdc_ecm_device =  interface_ptr -> ux_interface_configuration -> ux_configuration_device;
147 
148     /* Store the interface container into the cdc_acm class instance.  */
149     cdc_ecm -> ux_host_class_cdc_ecm_interface_data =  interface_ptr;
150 
151     /* We need to link the data and control interfaces together. In order
152        to do this, we first need to find the control interface. Per the spec,
153        it should be behind this one.  */
154 
155     /* Set the current interface to the second interface. */
156     cur_interface =  interface_ptr -> ux_interface_configuration -> ux_configuration_first_interface;
157 
158     /* Initialize to null. */
159     control_interface =  UX_NULL;
160 
161     /* Loop through all the interfaces until we find the current data interface.  */
162     while (cur_interface != interface_ptr)
163     {
164 
165         /* Is this a control interface?  */
166         if (cur_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
167         {
168 
169             /* Is this the right one before current interface?  */
170             if (cur_interface -> ux_interface_next_interface == interface_ptr)
171             {
172 
173                 /* Save it.  */
174                 control_interface =  cur_interface;
175             }
176         }
177 
178         /* Advance current interface.  */
179         cur_interface =  cur_interface -> ux_interface_next_interface;
180     }
181 
182     /* Did we not find the control interface?  */
183     if (control_interface == UX_NULL)
184     {
185 
186         /* This in an invalid descriptor.  */
187 
188         /* Error trap.  */
189         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
190 
191         /* If trace is enabled, insert this event into the trace buffer.  */
192         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
193 
194         /* Return error.  */
195         status =  UX_DESCRIPTOR_CORRUPTED;
196     }
197     else
198     {
199 
200         /* We found the control interface.  */
201         status =  UX_SUCCESS;
202     }
203 
204     if (status == UX_SUCCESS)
205     {
206 
207         /* Save the control interface.  */
208         cdc_ecm -> ux_host_class_cdc_ecm_interface_control =  (UX_INTERFACE *) control_interface;
209 
210         /* Get the cdc_ecm endpoint(s) on the interface. */
211         status =  _ux_host_class_cdc_ecm_endpoints_get(cdc_ecm);
212     }
213 
214     if (status == UX_SUCCESS)
215     {
216 
217         /* Allocate a Thread stack.  */
218         cdc_ecm -> ux_host_class_cdc_ecm_thread_stack =
219                     _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
220         if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack == UX_NULL)
221             status =  UX_MEMORY_INSUFFICIENT;
222     }
223 
224     if (status == UX_SUCCESS)
225     {
226 
227         /* Create the semaphore for aborting bulk in transfers.  */
228         status =  _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore,
229                                                "host CDC-ECM bulk in wait semaphore", 0);
230         if (status == UX_SUCCESS)
231         {
232 
233             /* Create the semaphore for aborting bulk out transfers.  */
234             status =  _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish_semaphore,
235                                                    "host CDC-ECM bulk out wait semaphore", 0);
236             if (status == UX_SUCCESS)
237             {
238 
239                 /* Create the semaphore to wake up the CDC ECM thread.  */
240                 status =  _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore, "host CDC-ECM interrupt notification semaphore", 0);
241                 if (status == UX_SUCCESS)
242                 {
243 
244                     /* Create the cdc_ecm class thread. We do not start it yet.  */
245                     status =  _ux_utility_thread_create(&cdc_ecm -> ux_host_class_cdc_ecm_thread,
246                                             "ux_host_cdc_ecm_thread", _ux_host_class_cdc_ecm_thread,
247                                             (ULONG) (ALIGN_TYPE) cdc_ecm,
248                                             cdc_ecm -> ux_host_class_cdc_ecm_thread_stack,
249                                             UX_THREAD_STACK_SIZE,
250                                             UX_THREAD_PRIORITY_CLASS,
251                                             UX_THREAD_PRIORITY_CLASS,
252                                             UX_NO_TIME_SLICE, UX_DONT_START);
253                     if (status == UX_SUCCESS)
254                     {
255 
256                         UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_host_class_cdc_ecm_thread), cdc_ecm)
257 
258                         /* We now need to retrieve the MAC address of the node which is embedded in the ECM descriptor.
259                             We will parse the entire configuration descriptor of the device and look for the ECM Ethernet Networking Functional Descriptor.  */
260                         status =  _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm);
261 
262                         if (status == UX_SUCCESS)
263                         {
264 
265                             /* Setup the physical address of this IP instance.  */
266                             physical_address_msw =  (ULONG)((cdc_ecm -> ux_host_class_cdc_ecm_node_id[0] << 8) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[1]));
267                             physical_address_lsw =  (ULONG)((cdc_ecm -> ux_host_class_cdc_ecm_node_id[2] << 24) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[3] << 16) |
268                                                                                 (cdc_ecm -> ux_host_class_cdc_ecm_node_id[4] << 8) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[5]));
269 
270                             /* The ethernet link is down by default.  */
271                             cdc_ecm -> ux_host_class_cdc_ecm_link_state =  UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN;
272                         }
273 
274                         if (status == UX_SUCCESS)
275                         {
276 
277                             /* Register this interface to the NetX USB interface broker.  */
278                             status =  _ux_network_driver_activate((VOID *) cdc_ecm, _ux_host_class_cdc_ecm_write,
279                                                                     &cdc_ecm -> ux_host_class_cdc_ecm_network_handle,
280                                                                     physical_address_msw, physical_address_lsw);
281                         }
282 
283                         if (status == UX_SUCCESS)
284                         {
285 
286                             /* Mark the cdc_ecm data instance as live now.  */
287                             cdc_ecm -> ux_host_class_cdc_ecm_state =  UX_HOST_CLASS_INSTANCE_LIVE;
288 
289                             /* This instance of the device must also be stored in the interface container.  */
290                             interface_ptr -> ux_interface_class_instance =  (VOID *) cdc_ecm;
291 
292                             /* Create this class instance.  */
293                             _ux_host_stack_class_instance_create(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
294 
295                             /* Start the interrupt pipe now if it exists.  */
296                             if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL)
297                             {
298 
299                                 /* Obtain the transfer request from the interrupt endpoint.  */
300                                 transfer_request =  &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request;
301                                 status =  _ux_host_stack_transfer_request(transfer_request);
302                             }
303 
304                             if (status == UX_SUCCESS)
305                             {
306 
307                                 /* Activation is complete.  */
308 
309                                 /* Now we can start the CDC-ECM thread.  */
310                                 _ux_utility_thread_resume(&cdc_ecm -> ux_host_class_cdc_ecm_thread);
311 
312                                 /* We need to inform the application if a function has been programmed
313                                     in the system structure. */
314                                 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
315                                 {
316 
317                                     /* Call system change function. Note that the application should
318                                         wait until the link state is up until using this instance. The
319                                         link state is changed to up by the CDC-ECM thread, which isn't
320                                         started until after the data interface has been processed.  */
321                                     _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
322                                 }
323 
324                                 /* If trace is enabled, insert this event into the trace buffer.  */
325                                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ECM_ACTIVATE, cdc_ecm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
326 
327                                 /* If trace is enabled, register this object.  */
328                                 UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0)
329 
330                                 /* Activation was successful.  */
331                                 return(UX_SUCCESS);
332                             }
333 
334                             /* Error starting interrupt endpoint.  */
335 
336                             /* Destroy this class instance.  */
337                             _ux_host_stack_class_instance_destroy(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
338 
339                             /* Unmount instance.  */
340                             interface_ptr -> ux_interface_class_instance =  UX_NULL;
341                         }
342 
343                         /* Delete CDC-ECM thread.  */
344                         _ux_utility_thread_delete(&cdc_ecm -> ux_host_class_cdc_ecm_thread);
345                     }
346 
347                     /* Delete interrupt notification semaphore.  */
348                     _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore);
349                 }
350 
351                 /* Delete class-level bulk out semaphore.  */
352                 _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish_semaphore);
353             }
354 
355             /* Delete class-level bulk in semaphore.  */
356             _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore);
357         }
358     }
359 
360     /* An error occurred. We must clean up resources.  */
361 
362     if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL &&
363         cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer != UX_NULL)
364         _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
365 
366     if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack != UX_NULL)
367         _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_thread_stack);
368 
369     _ux_utility_memory_free(cdc_ecm);
370 
371     /* Return completion status.  */
372     return(status);
373 }
374 #endif
375