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_activate                   PORTABLE C      */
35 /*                                                           6.3.0        */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Chaoqiong Xiao, Microsoft Corporation                               */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function activates 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 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLED BY                                                             */
57 /*                                                                        */
58 /*    USBX Source Code                                                    */
59 /*                                                                        */
60 /*  RELEASE HISTORY                                                       */
61 /*                                                                        */
62 /*    DATE              NAME                      DESCRIPTION             */
63 /*                                                                        */
64 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
65 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
66 /*                                            verified memset and memcpy  */
67 /*                                            cases, used UX prefix to    */
68 /*                                            refer to TX symbols instead */
69 /*                                            of using them directly,     */
70 /*                                            resulting in version 6.1    */
71 /*  08-02-2021     Wen Wang                 Modified comment(s),          */
72 /*                                            fixed spelling error,       */
73 /*                                            resulting in version 6.1.8  */
74 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            refined macros names,       */
76 /*                                            resulting in version 6.1.10 */
77 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            fixed standalone compile,   */
79 /*                                            resulting in version 6.1.11 */
80 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            fixed parameter/variable    */
82 /*                                            names conflict C++ keyword, */
83 /*                                            resulting in version 6.1.12 */
84 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            added zero copy support,    */
86 /*                                            added a new mode to manage  */
87 /*                                            endpoint buffer in classes, */
88 /*                                            resulting in version 6.3.0  */
89 /*                                                                        */
90 /**************************************************************************/
_ux_device_class_cdc_ecm_activate(UX_SLAVE_CLASS_COMMAND * command)91 UINT  _ux_device_class_cdc_ecm_activate(UX_SLAVE_CLASS_COMMAND *command)
92 {
93 #if defined(UX_DEVICE_STANDALONE)
94     UX_PARAMETER_NOT_USED(command);
95     return(UX_FUNCTION_NOT_SUPPORTED);
96 #else
97 
98 UX_SLAVE_INTERFACE          *interface_ptr;
99 UX_SLAVE_CLASS              *class_ptr;
100 UX_SLAVE_CLASS_CDC_ECM      *cdc_ecm;
101 UX_SLAVE_ENDPOINT           *endpoint;
102 ULONG                       physical_address_msw;
103 ULONG                       physical_address_lsw;
104 
105     /* Get the class container.  */
106     class_ptr =  command -> ux_slave_class_command_class_ptr;
107 
108     /* Get the class instance in the container.  */
109     cdc_ecm = (UX_SLAVE_CLASS_CDC_ECM *) class_ptr -> ux_slave_class_instance;
110 
111     /* Get the interface that owns this instance.  */
112     interface_ptr =  (UX_SLAVE_INTERFACE  *) command -> ux_slave_class_command_interface;
113 
114     /* Check if this is the Control or Data interface.  */
115     if (command -> ux_slave_class_command_class == UX_DEVICE_CLASS_CDC_ECM_CLASS_COMMUNICATION_CONTROL)
116     {
117 
118         /* Store the class instance into the interface.  */
119         interface_ptr -> ux_slave_interface_class_instance =  (VOID *)cdc_ecm;
120 
121         /* Now the opposite, store the interface in the class instance.  */
122         cdc_ecm -> ux_slave_class_cdc_ecm_interface =  interface_ptr;
123 
124         /* Locate the interrupt endpoint. */
125         endpoint =  interface_ptr -> ux_slave_interface_first_endpoint;
126 
127         /* Parse all endpoints.  */
128         while (endpoint != UX_NULL)
129         {
130 
131             /* Check the endpoint direction, and type.  */
132             if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
133             {
134 
135                 /* Look at type.  */
136                 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT)
137                 {
138 
139                     /* We have found the interrupt endpoint, save it.  */
140                     cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_endpoint =  endpoint;
141 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
142 
143                     /* Set the endpoint buffer to the endpoint.  */
144                     endpoint -> ux_slave_endpoint_transfer_request.
145                         ux_slave_transfer_request_data_pointer =
146                                 UX_DEVICE_CLASS_CDC_ECM_INTERRUPTIN_BUFFER(cdc_ecm);
147 #endif
148 
149                     /* Reset the endpoint buffers.  */
150                     _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_endpoint -> ux_slave_endpoint_transfer_request.
151                                         ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_INTERRUPTIN_BUFFER_SIZE); /* Use case of memset is verified. */
152 
153                     /* Resume the interrupt endpoint threads.  */
154                     _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread);
155 
156                 }
157 
158             }
159 
160             /* Next endpoint.  */
161             endpoint =  endpoint -> ux_slave_endpoint_next_endpoint;
162         }
163 
164     }
165     else
166 
167         /* This is the DATA Class, only store the cdc_ecm instance in the interface.  */
168         interface_ptr -> ux_slave_interface_class_instance =  (VOID *)cdc_ecm;
169 
170     /* Reset the CDC ECM alternate setting to 0.  */
171     cdc_ecm -> ux_slave_class_cdc_ecm_current_alternate_setting =  0;
172 
173     /* Check if this is the Control or Data interface.  */
174     if (command -> ux_slave_class_command_class == UX_DEVICE_CLASS_CDC_ECM_CLASS_COMMUNICATION_DATA)
175     {
176 
177         /* Reset endpoint instance pointers.  */
178         cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint = UX_NULL;
179         cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint = UX_NULL;
180 
181         /* Does the data class have bulk endpoint declared ? If yes we need to start link.
182            If not, the host will change the alternate setting at a later stage.  */
183         if (interface_ptr -> ux_slave_interface_descriptor.bNumEndpoints != 0)
184         {
185 
186             /* Locate the endpoints.  Control and Bulk in/out for Data Interface.  */
187             endpoint =  interface_ptr -> ux_slave_interface_first_endpoint;
188 
189             /* Parse all endpoints.  */
190             while (endpoint != UX_NULL)
191             {
192 
193                 /* Check the endpoint direction, and type.  */
194                 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
195                 {
196 
197                     /* Look at type.  */
198                     if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
199                     {
200 
201                         /* We have found the bulk in endpoint, save it.  */
202                         cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint =  endpoint;
203 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
204                         endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
205                                 UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER(cdc_ecm);
206 #endif
207                     }
208 
209                 }
210                 else
211                 {
212                     /* Look at type for out endpoint.  */
213                     if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
214                     {
215 
216                         /* We have found the bulk out endpoint, save it.  */
217                         cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint =  endpoint;
218 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
219                         endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
220                                 UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER(cdc_ecm);
221 #endif
222                     }
223                 }
224 
225                 /* Next endpoint.  */
226                 endpoint =  endpoint -> ux_slave_endpoint_next_endpoint;
227             }
228 
229 
230             /* Now check if all endpoints have been found.  */
231             if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint == UX_NULL || cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint == UX_NULL)
232 
233                 /* Not all endpoints have been found. Major error, do not proceed.  */
234                 return(UX_ERROR);
235 
236             /* Declare the link to be up. That may need to change later to make it dependent on the
237                WAN/Wireless modem.  */
238             cdc_ecm -> ux_slave_class_cdc_ecm_link_state = UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP;
239 
240             /* Wake up the Interrupt thread and send a network notification to the host.  */
241             _ux_device_event_flags_set(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, UX_OR);
242 
243 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
244 
245             /* There is no endpoint buffer.  */
246 #else
247 
248             /* Reset the endpoint buffers.  */
249             _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint -> ux_slave_endpoint_transfer_request.
250                                             ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER_SIZE); /* Use case of memset is verified. */
251             _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint -> ux_slave_endpoint_transfer_request.
252                                             ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER_SIZE); /* Use case of memset is verified. */
253 #endif
254 
255             /* Resume the endpoint threads.  */
256             _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread);
257             _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread);
258 
259         }
260 
261         /* Setup the physical address of this IP instance.  */
262         physical_address_msw =  (ULONG)((cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[0] << 8) | (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[1]));
263         physical_address_lsw =  (ULONG)((cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[2] << 24) | (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[3] << 16) |
264                                                        (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[4] << 8) | (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[5]));
265 
266         /* Register this interface to the NetX USB interface broker.  */
267         _ux_network_driver_activate((VOID *) cdc_ecm, _ux_device_class_cdc_ecm_write,
268                                         &cdc_ecm -> ux_slave_class_cdc_ecm_network_handle,
269                                         physical_address_msw,
270                                         physical_address_lsw);
271 
272         /* Check Link.  */
273         if (cdc_ecm -> ux_slave_class_cdc_ecm_link_state == UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP)
274         {
275 
276             /* Communicate the state with the network driver.  */
277             _ux_network_driver_link_up(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle);
278 
279             /* If there is an activate function call it.  */
280             if (cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate != UX_NULL)
281 
282                 /* Invoke the application.  */
283                 cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate(cdc_ecm);
284         }
285     }
286 
287     /* If trace is enabled, insert this event into the trace buffer.  */
288     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_ACTIVATE, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
289 
290     /* If trace is enabled, register this object.  */
291     UX_TRACE_OBJECT_REGISTER(UX_TRACE_DEVICE_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0)
292 
293     /* Return completion status.  */
294     return(UX_SUCCESS);
295 #endif
296 }
297