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