GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_cdc_ecm_activate.c Lines: 74 74 100.0 %
Date: 2026-03-06 18:57:10 Branches: 45 46 97.8 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
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
/**************************************************************************/
80
247
UINT  _ux_host_class_cdc_ecm_activate(UX_HOST_CLASS_COMMAND *command)
81
{
82
83
UX_INTERFACE                        *interface_ptr;
84
UX_HOST_CLASS_CDC_ECM               *cdc_ecm;
85
UINT                                status;
86
UX_TRANSFER                         *transfer_request;
87
247
ULONG                               physical_address_msw = 0;
88
247
ULONG                               physical_address_lsw = 0;
89
UX_INTERFACE                        *control_interface;
90
UX_INTERFACE                        *cur_interface;
91
92
    /* The CDC ECM class is always activated by the interface descriptor and not the
93
       device descriptor.  */
94
247
    interface_ptr =  (UX_INTERFACE *) command -> ux_host_class_command_container;
95
96
    /* Is this the control interface?  */
97
247
    if (interface_ptr -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
98
    {
99
100
        /* We ignore the control interface. All activation is performed when
101
           we receive the data interface.  */
102
122
        return(UX_SUCCESS);
103
    }
104
105
    /* Obtain memory for this class instance.  */
106
125
    cdc_ecm =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, sizeof(UX_HOST_CLASS_CDC_ECM));
107
125
    if (cdc_ecm == UX_NULL)
108
1
        return(UX_MEMORY_INSUFFICIENT);
109
110
    /* Store the class container into this instance.  */
111
124
    cdc_ecm -> ux_host_class_cdc_ecm_class =  command -> ux_host_class_command_class_ptr;
112
113
    /* Store the device container into the cdc_ecm class instance.  */
114
124
    cdc_ecm -> ux_host_class_cdc_ecm_device =  interface_ptr -> ux_interface_configuration -> ux_configuration_device;
115
116
    /* Store the interface container into the cdc_acm class instance.  */
117
124
    cdc_ecm -> ux_host_class_cdc_ecm_interface_data =  interface_ptr;
118
119
    /* We need to link the data and control interfaces together. In order
120
       to do this, we first need to find the control interface. Per the spec,
121
       it should be behind this one.  */
122
123
    /* Set the current interface to the second interface. */
124
124
    cur_interface =  interface_ptr -> ux_interface_configuration -> ux_configuration_first_interface;
125
126
    /* Initialize to null. */
127
124
    control_interface =  UX_NULL;
128
129
    /* Loop through all the interfaces until we find the current data interface.  */
130
246
    while (cur_interface != interface_ptr)
131
    {
132
133
        /* Is this a control interface?  */
134
122
        if (cur_interface -> ux_interface_descriptor.bInterfaceClass == UX_HOST_CLASS_CDC_CONTROL_CLASS)
135
        {
136
137
            /* Is this the right one before current interface?  */
138
121
            if (cur_interface -> ux_interface_next_interface == interface_ptr)
139
            {
140
141
                /* Save it.  */
142
121
                control_interface =  cur_interface;
143
            }
144
        }
145
146
        /* Advance current interface.  */
147
122
        cur_interface =  cur_interface -> ux_interface_next_interface;
148
    }
149
150
    /* Did we not find the control interface?  */
151
124
    if (control_interface == UX_NULL)
152
    {
153
154
        /* This in an invalid descriptor.  */
155
156
        /* Error trap.  */
157
3
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
158
159
        /* If trace is enabled, insert this event into the trace buffer.  */
160
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
161
162
        /* Return error.  */
163
3
        status =  UX_DESCRIPTOR_CORRUPTED;
164
    }
165
    else
166
    {
167
168
        /* We found the control interface.  */
169
121
        status =  UX_SUCCESS;
170
    }
171
172
124
    if (status == UX_SUCCESS)
173
    {
174
175
        /* Save the control interface.  */
176
121
        cdc_ecm -> ux_host_class_cdc_ecm_interface_control =  (UX_INTERFACE *) control_interface;
177
178
        /* Get the cdc_ecm endpoint(s) on the interface. */
179
121
        status =  _ux_host_class_cdc_ecm_endpoints_get(cdc_ecm);
180
    }
181
182
124
    if (status == UX_SUCCESS)
183
    {
184
185
        /* Allocate a Thread stack.  */
186
88
        cdc_ecm -> ux_host_class_cdc_ecm_thread_stack =
187
88
                    _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
188
88
        if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack == UX_NULL)
189
1
            status =  UX_MEMORY_INSUFFICIENT;
190
    }
191
192
124
    if (status == UX_SUCCESS)
193
    {
194
195
        /* Create the semaphore for aborting bulk in transfers.  */
196
87
        status =  _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore,
197
                                               "host CDC-ECM bulk in wait semaphore", 0);
198
87
        if (status == UX_SUCCESS)
199
        {
200
201
            /* Create the semaphore for aborting bulk out transfers.  */
202
84
            status =  _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish_semaphore,
203
                                                   "host CDC-ECM bulk out wait semaphore", 0);
204
84
            if (status == UX_SUCCESS)
205
            {
206
207
                /* Create the semaphore to wake up the CDC ECM thread.  */
208
81
                status =  _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore, "host CDC-ECM interrupt notification semaphore", 0);
209
81
                if (status == UX_SUCCESS)
210
                {
211
212
                    /* Create the cdc_ecm class thread. We do not start it yet.  */
213
78
                    status =  _ux_utility_thread_create(&cdc_ecm -> ux_host_class_cdc_ecm_thread,
214
                                            "ux_host_cdc_ecm_thread", _ux_host_class_cdc_ecm_thread,
215
                                            (ULONG) (ALIGN_TYPE) cdc_ecm,
216
78
                                            cdc_ecm -> ux_host_class_cdc_ecm_thread_stack,
217
                                            UX_THREAD_STACK_SIZE,
218
                                            UX_THREAD_PRIORITY_CLASS,
219
                                            UX_THREAD_PRIORITY_CLASS,
220
                                            UX_NO_TIME_SLICE, UX_DONT_START);
221
78
                    if (status == UX_SUCCESS)
222
                    {
223
224
                        UX_THREAD_EXTENSION_PTR_SET(&(cdc_ecm -> ux_host_class_cdc_ecm_thread), cdc_ecm)
225
226
                        /* We now need to retrieve the MAC address of the node which is embedded in the ECM descriptor.
227
                            We will parse the entire configuration descriptor of the device and look for the ECM Ethernet Networking Functional Descriptor.  */
228
75
                        status =  _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm);
229
230
75
                        if (status == UX_SUCCESS)
231
                        {
232
233
                            /* Setup the physical address of this IP instance.  */
234
57
                            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]));
235
57
                            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) |
236
57
                                                                                (cdc_ecm -> ux_host_class_cdc_ecm_node_id[4] << 8) | (cdc_ecm -> ux_host_class_cdc_ecm_node_id[5]));
237
238
                            /* The ethernet link is down by default.  */
239
57
                            cdc_ecm -> ux_host_class_cdc_ecm_link_state =  UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN;
240
                        }
241
242
75
                        if (status == UX_SUCCESS)
243
                        {
244
245
                            /* Register this interface to the NetX USB interface broker.  */
246
57
                            status =  _ux_network_driver_activate((VOID *) cdc_ecm, _ux_host_class_cdc_ecm_write,
247
                                                                    &cdc_ecm -> ux_host_class_cdc_ecm_network_handle,
248
                                                                    physical_address_msw, physical_address_lsw);
249
                        }
250
251
75
                        if (status == UX_SUCCESS)
252
                        {
253
254
                            /* Mark the cdc_ecm data instance as live now.  */
255
57
                            cdc_ecm -> ux_host_class_cdc_ecm_state =  UX_HOST_CLASS_INSTANCE_LIVE;
256
257
                            /* This instance of the device must also be stored in the interface container.  */
258
57
                            interface_ptr -> ux_interface_class_instance =  (VOID *) cdc_ecm;
259
260
                            /* Create this class instance.  */
261
57
                            _ux_host_stack_class_instance_create(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
262
263
                            /* Start the interrupt pipe now if it exists.  */
264
57
                            if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL)
265
                            {
266
267
                                /* Obtain the transfer request from the interrupt endpoint.  */
268
54
                                transfer_request =  &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request;
269
54
                                status =  _ux_host_stack_transfer_request(transfer_request);
270
                            }
271
272
57
                            if (status == UX_SUCCESS)
273
                            {
274
275
                                /* Activation is complete.  */
276
277
                                /* Now we can start the CDC-ECM thread.  */
278
54
                                _ux_utility_thread_resume(&cdc_ecm -> ux_host_class_cdc_ecm_thread);
279
280
                                /* We need to inform the application if a function has been programmed
281
                                    in the system structure. */
282
54
                                if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
283
                                {
284
285
                                    /* Call system change function. Note that the application should
286
                                        wait until the link state is up until using this instance. The
287
                                        link state is changed to up by the CDC-ECM thread, which isn't
288
                                        started until after the data interface has been processed.  */
289
50
                                    _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
290
                                }
291
292
                                /* If trace is enabled, insert this event into the trace buffer.  */
293
                                UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ECM_ACTIVATE, cdc_ecm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
294
295
                                /* If trace is enabled, register this object.  */
296
                                UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0)
297
298
                                /* Activation was successful.  */
299
54
                                return(UX_SUCCESS);
300
                            }
301
302
                            /* Error starting interrupt endpoint.  */
303
304
                            /* Destroy this class instance.  */
305
3
                            _ux_host_stack_class_instance_destroy(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
306
307
                            /* Unmount instance.  */
308
3
                            interface_ptr -> ux_interface_class_instance =  UX_NULL;
309
                        }
310
311
                        /* Delete CDC-ECM thread.  */
312
21
                        _ux_utility_thread_delete(&cdc_ecm -> ux_host_class_cdc_ecm_thread);
313
                    }
314
315
                    /* Delete interrupt notification semaphore.  */
316
24
                    _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore);
317
                }
318
319
                /* Delete class-level bulk out semaphore.  */
320
27
                _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish_semaphore);
321
            }
322
323
            /* Delete class-level bulk in semaphore.  */
324
30
            _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore);
325
        }
326
    }
327
328
    /* An error occurred. We must clean up resources.  */
329
330
70
    if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL &&
331
35
        cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer != UX_NULL)
332
34
        _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
333
334
70
    if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack != UX_NULL)
335
33
        _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_thread_stack);
336
337
70
    _ux_utility_memory_free(cdc_ecm);
338
339
    /* Return completion status.  */
340
70
    return(status);
341
}
342
#endif