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: 2024-12-12 17:16:36 Branches: 45 46 97.8 %

Line Branch Exec Source
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
/**************************************************************************/
112
247
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
247
ULONG                               physical_address_msw = 0;
120
247
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
247
    interface_ptr =  (UX_INTERFACE *) command -> ux_host_class_command_container;
127
128
    /* Is this the control interface?  */
129
247
    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
122
        return(UX_SUCCESS);
135
    }
136
137
    /* Obtain memory for this class instance.  */
138
125
    cdc_ecm =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, sizeof(UX_HOST_CLASS_CDC_ECM));
139
125
    if (cdc_ecm == UX_NULL)
140
1
        return(UX_MEMORY_INSUFFICIENT);
141
142
    /* Store the class container into this instance.  */
143
124
    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
124
    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
124
    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
124
    cur_interface =  interface_ptr -> ux_interface_configuration -> ux_configuration_first_interface;
157
158
    /* Initialize to null. */
159
124
    control_interface =  UX_NULL;
160
161
    /* Loop through all the interfaces until we find the current data interface.  */
162
246
    while (cur_interface != interface_ptr)
163
    {
164
165
        /* Is this a control interface?  */
166
122
        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
121
            if (cur_interface -> ux_interface_next_interface == interface_ptr)
171
            {
172
173
                /* Save it.  */
174
121
                control_interface =  cur_interface;
175
            }
176
        }
177
178
        /* Advance current interface.  */
179
122
        cur_interface =  cur_interface -> ux_interface_next_interface;
180
    }
181
182
    /* Did we not find the control interface?  */
183
124
    if (control_interface == UX_NULL)
184
    {
185
186
        /* This in an invalid descriptor.  */
187
188
        /* Error trap.  */
189
3
        _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
3
        status =  UX_DESCRIPTOR_CORRUPTED;
196
    }
197
    else
198
    {
199
200
        /* We found the control interface.  */
201
121
        status =  UX_SUCCESS;
202
    }
203
204
124
    if (status == UX_SUCCESS)
205
    {
206
207
        /* Save the control interface.  */
208
121
        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
121
        status =  _ux_host_class_cdc_ecm_endpoints_get(cdc_ecm);
212
    }
213
214
124
    if (status == UX_SUCCESS)
215
    {
216
217
        /* Allocate a Thread stack.  */
218
88
        cdc_ecm -> ux_host_class_cdc_ecm_thread_stack =
219
88
                    _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_THREAD_STACK_SIZE);
220
88
        if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack == UX_NULL)
221
1
            status =  UX_MEMORY_INSUFFICIENT;
222
    }
223
224
124
    if (status == UX_SUCCESS)
225
    {
226
227
        /* Create the semaphore for aborting bulk in transfers.  */
228
87
        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
87
        if (status == UX_SUCCESS)
231
        {
232
233
            /* Create the semaphore for aborting bulk out transfers.  */
234
84
            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
84
            if (status == UX_SUCCESS)
237
            {
238
239
                /* Create the semaphore to wake up the CDC ECM thread.  */
240
81
                status =  _ux_host_semaphore_create(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore, "host CDC-ECM interrupt notification semaphore", 0);
241
81
                if (status == UX_SUCCESS)
242
                {
243
244
                    /* Create the cdc_ecm class thread. We do not start it yet.  */
245
78
                    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
78
                                            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
78
                    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
75
                        status =  _ux_host_class_cdc_ecm_mac_address_get(cdc_ecm);
261
262
75
                        if (status == UX_SUCCESS)
263
                        {
264
265
                            /* Setup the physical address of this IP instance.  */
266
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]));
267
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) |
268
57
                                                                                (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
57
                            cdc_ecm -> ux_host_class_cdc_ecm_link_state =  UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN;
272
                        }
273
274
75
                        if (status == UX_SUCCESS)
275
                        {
276
277
                            /* Register this interface to the NetX USB interface broker.  */
278
57
                            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
75
                        if (status == UX_SUCCESS)
284
                        {
285
286
                            /* Mark the cdc_ecm data instance as live now.  */
287
57
                            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
57
                            interface_ptr -> ux_interface_class_instance =  (VOID *) cdc_ecm;
291
292
                            /* Create this class instance.  */
293
57
                            _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
57
                            if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL)
297
                            {
298
299
                                /* Obtain the transfer request from the interrupt endpoint.  */
300
54
                                transfer_request =  &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request;
301
54
                                status =  _ux_host_stack_transfer_request(transfer_request);
302
                            }
303
304
57
                            if (status == UX_SUCCESS)
305
                            {
306
307
                                /* Activation is complete.  */
308
309
                                /* Now we can start the CDC-ECM thread.  */
310
54
                                _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
54
                                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
50
                                    _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
54
                                return(UX_SUCCESS);
332
                            }
333
334
                            /* Error starting interrupt endpoint.  */
335
336
                            /* Destroy this class instance.  */
337
3
                            _ux_host_stack_class_instance_destroy(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
338
339
                            /* Unmount instance.  */
340
3
                            interface_ptr -> ux_interface_class_instance =  UX_NULL;
341
                        }
342
343
                        /* Delete CDC-ECM thread.  */
344
21
                        _ux_utility_thread_delete(&cdc_ecm -> ux_host_class_cdc_ecm_thread);
345
                    }
346
347
                    /* Delete interrupt notification semaphore.  */
348
24
                    _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore);
349
                }
350
351
                /* Delete class-level bulk out semaphore.  */
352
27
                _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
30
            _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
70
    if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL &&
363
35
        cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer != UX_NULL)
364
34
        _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
365
366
70
    if (cdc_ecm -> ux_host_class_cdc_ecm_thread_stack != UX_NULL)
367
33
        _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_thread_stack);
368
369
70
    _ux_utility_memory_free(cdc_ecm);
370
371
    /* Return completion status.  */
372
70
    return(status);
373
}
374
#endif