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