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