GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_cdc_ecm_thread.c Lines: 66 66 100.0 %
Date: 2026-03-06 18:57:10 Branches: 32 32 100.0 %

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
33
#if !defined(UX_HOST_STANDALONE)
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _ux_host_class_cdc_ecm_thread                       PORTABLE C      */
39
/*                                                           6.2.0        */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Chaoqiong Xiao, Microsoft Corporation                               */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This is the CDC ECM thread that monitors the link change flag,      */
47
/*    receives data from the device, and passes the data to the NetX-USB  */
48
/*    broker.                                                             */
49
/*                                                                        */
50
/*  INPUT                                                                 */
51
/*                                                                        */
52
/*    cdc_ecm                               CDC ECM instance              */
53
/*                                                                        */
54
/*  OUTPUT                                                                */
55
/*                                                                        */
56
/*    Completion Status                                                   */
57
/*                                                                        */
58
/*  CALLS                                                                 */
59
/*                                                                        */
60
/*    _ux_host_class_cdc_ecm_transmit_queue_clean                         */
61
/*                                          Clean transmit queue          */
62
/*    _ux_host_stack_transfer_request       Transfer request              */
63
/*    _ux_host_semaphore_get                Get semaphore                 */
64
/*    _ux_host_semaphore_put                Put semaphore                 */
65
/*    _ux_utility_short_get_big_endian      Get 16-bit big endian         */
66
/*    _ux_network_driver_link_up            Set state link up             */
67
/*    _ux_network_driver_link_down          Set state link down           */
68
/*    _ux_network_driver_packet_received    Process received packet       */
69
/*    nx_packet_allocate                    Allocate NetX packet          */
70
/*    nx_packet_release                     Free NetX packet              */
71
/*                                                                        */
72
/*  CALLED BY                                                             */
73
/*                                                                        */
74
/*    CDC ECM class initialization                                        */
75
/*                                                                        */
76
/**************************************************************************/
77
54
VOID  _ux_host_class_cdc_ecm_thread(ULONG parameter)
78
{
79
80
UX_HOST_CLASS_CDC_ECM       *cdc_ecm;
81
UX_TRANSFER                 *transfer_request;
82
NX_PACKET                   *packet;
83
UINT                        status;
84
USB_NETWORK_DEVICE_TYPE     *usb_network_device_ptr;
85
ULONG                       packet_buffer_size;
86
87
88
    /* Cast the parameter passed in the thread into the cdc_ecm pointer.  */
89
54
    UX_THREAD_EXTENSION_PTR_GET(cdc_ecm, UX_HOST_CLASS_CDC_ECM, parameter)
90
91
    /* Loop forever waiting for changes signaled through the semaphore. */
92
    while (1)
93
    {
94
95
        /* Wait for the semaphore to be put by the cdc_ecm interrupt event.  */
96
109
        _ux_host_semaphore_get_norc(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore, UX_WAIT_FOREVER);
97
98
        /* Check the link state. It is either pending up or down.  */
99
57
        if (cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_UP)
100
        {
101
102
            /* Now the link is up.  */
103
49
            cdc_ecm -> ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP;
104
105
            /* Communicate the state with the network driver.  */
106
49
            _ux_network_driver_link_up(cdc_ecm -> ux_host_class_cdc_ecm_network_handle);
107
108
            /* As long as we are connected, configured and link up ... do some work.... */
109
2226
            while ((cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP) &&
110
2218
                   (cdc_ecm -> ux_host_class_cdc_ecm_device -> ux_device_state == UX_DEVICE_CONFIGURED))
111
            {
112
113
                /* Check if we have packet pool available.  */
114
2179
                if (cdc_ecm -> ux_host_class_cdc_ecm_packet_pool == UX_NULL)
115
                {
116
117
                    /* Get the network device handle.  */
118
58
                    usb_network_device_ptr = (USB_NETWORK_DEVICE_TYPE *)(cdc_ecm -> ux_host_class_cdc_ecm_network_handle);
119
120
                    /* Check if IP instance is available.  */
121
58
                    if (usb_network_device_ptr -> ux_network_device_ip_instance != UX_NULL)
122
                    {
123
124
                        /* Get the packet pool from IP instance.  */
125
45
                        cdc_ecm -> ux_host_class_cdc_ecm_packet_pool = usb_network_device_ptr -> ux_network_device_ip_instance -> nx_ip_default_packet_pool;
126
                    }
127
                    else
128
                    {
129
130
                        /* IP instance is not available, wait for application to attach the interface.  */
131
13
                        _ux_utility_delay_ms(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_INSTANCE_WAIT);
132
                    }
133
57
                    continue;
134
                }
135
136
                /* We can accept reception. Get a NX Packet. */
137
2121
                status =  nx_packet_allocate(cdc_ecm -> ux_host_class_cdc_ecm_packet_pool, &packet,
138
                                             NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT));
139
140
2121
                if (status == NX_SUCCESS)
141
                {
142
143
                    /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header.  */
144
2120
                    packet -> nx_packet_prepend_ptr += sizeof(USHORT);
145
146
                    /* We have a packet.  Link this packet to the reception transfer request on the bulk in endpoint. */
147
2120
                    transfer_request =  &cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint -> ux_endpoint_transfer_request;
148
149
#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
150
151
                    /* Check packet buffer size, if too small chain is used.  */
152
2120
                    packet_buffer_size = (ULONG)(packet -> nx_packet_data_end - packet -> nx_packet_prepend_ptr);
153
2120
                    if (packet_buffer_size < UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE)
154
                    {
155
1051
                        if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer == UX_NULL)
156
                        {
157
5
                            cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer =
158
5
                                    _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY,
159
                                                            UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE);
160
5
                            if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer == UX_NULL)
161
                            {
162
163
                                /* Memory allocation fail.  */
164
1
                                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
165
166
                                /* Release packet.  */
167
1
                                nx_packet_release(packet);
168
169
                                /* Delay to let other threads to run.  */
170
1
                                _ux_utility_delay_ms(1);
171
1
                                continue;
172
                            }
173
174
                        }
175
176
                        /* Set the data pointer.  */
177
1050
                        transfer_request -> ux_transfer_request_data_pointer = cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer;
178
                    }
179
                    else
180
#endif
181
                    {
182
183
                        /* Set the data pointer.  */
184
1069
                        transfer_request -> ux_transfer_request_data_pointer =  packet -> nx_packet_prepend_ptr;
185
186
                    }
187
188
                    /* And length.  */
189
2119
                    transfer_request -> ux_transfer_request_requested_length =  UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE;
190
2119
                    transfer_request -> ux_transfer_request_actual_length =     0;
191
192
                    /* Store the packet that owns this transaction.  */
193
2119
                    transfer_request -> ux_transfer_request_user_specific = packet;
194
195
                    /* Reset the queue pointer of this packet.  */
196
2119
                    packet -> nx_packet_queue_next =  UX_NULL;
197
198
                    /* We're arming the transfer now.  */
199
2119
                    cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process =  UX_TRUE;
200
201
                    /* Is the link up?  */
202
2119
                    if (cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)
203
                    {
204
205
                        /* Ask USB to schedule a reception.  */
206
2117
                        status =  _ux_host_stack_transfer_request(transfer_request);
207
208
                        /* Signal that we are done arming and resume waiting thread if necessary.  */
209
2117
                        cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process =  UX_FALSE;
210
2117
                        if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish == UX_TRUE)
211
2
                            _ux_host_semaphore_put(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore);
212
213
                        /* Check if the transaction was armed successfully.  */
214
2117
                        if (status == UX_SUCCESS)
215
                        {
216
217
                            /* Wait for the completion of the transfer request.  */
218
2116
                            _ux_host_semaphore_get_norc(&transfer_request -> ux_transfer_request_semaphore, UX_WAIT_FOREVER);
219
220
                            /* Check the transfer status. If there is a transport error, we ignore the packet
221
                               and restart it. */
222
2115
                            if (transfer_request -> ux_transfer_request_completion_code == UX_SUCCESS)
223
                            {
224
225
#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
226
227
                                /* Check if transfer buffer is used.  */
228
2071
                                if (packet -> nx_packet_prepend_ptr !=
229
2071
                                    transfer_request -> ux_transfer_request_data_pointer)
230
                                {
231
232
                                    /* Adjust append_ptr for copy.  */
233
1046
                                    packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr;
234
235
                                    /* Append data to packet.  */
236
1046
                                    status = nx_packet_data_append(packet,
237
1046
                                            transfer_request -> ux_transfer_request_data_pointer,
238
                                            transfer_request -> ux_transfer_request_actual_length,
239
                                            cdc_ecm -> ux_host_class_cdc_ecm_packet_pool,
240
                                            UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT));
241
1046
                                    if (status != NX_SUCCESS)
242
                                    {
243
244
                                        /* Release packet.  */
245
1
                                        nx_packet_release(packet);
246
247
                                        /* Error trap.  */
248
1
                                        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_ERROR);
249
1
                                        continue;
250
                                    }
251
                                }
252
                                else
253
#endif
254
                                {
255
256
                                    /* Get the packet length. */
257
1025
                                    packet -> nx_packet_length = transfer_request -> ux_transfer_request_actual_length;
258
259
                                    /* Adjust the prepend, length, and append fields.  */
260
1025
                                    packet -> nx_packet_append_ptr =
261
1025
                                        packet->nx_packet_prepend_ptr + transfer_request -> ux_transfer_request_actual_length;
262
                                }
263
264
                                /* Send that packet to the NetX USB broker.  */
265
2070
                                _ux_network_driver_packet_received(cdc_ecm -> ux_host_class_cdc_ecm_network_handle, packet);
266
                            }
267
                            else
268
                            {
269
270
                                /* Free the packet that was not successfully received.  */
271
44
                                nx_packet_release(packet);
272
                            }
273
                        }
274
                        else
275
                        {
276
277
                            /* Error arming transfer.  */
278
279
                            /* Release packet.  */
280
1
                            nx_packet_release(packet);
281
                        }
282
                    }
283
                    else
284
                    {
285
286
                        /* Link is down.  */
287
288
                        /* Signal that we are done arming and resume waiting thread if necessary.  */
289
2
                        cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process =  UX_FALSE;
290
2
                        if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish == UX_TRUE)
291
1
                            _ux_host_semaphore_put(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore);
292
293
                        /* Release packet.  */
294
2
                        nx_packet_release(packet);
295
                    }
296
                }
297
                else
298
                {
299
300
                    /* Packet allocation timed out. Note that the timeout value is
301
                       configurable.  */
302
303
                    /* Error trap. No need for trace, since NetX does it.  */
304
1
                    _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
305
                }
306
            }
307
        }
308
        else
309
        {
310
311
            /* The link state is pending down. We need to free the xmit queue.  */
312
8
            _ux_host_class_cdc_ecm_transmit_queue_clean(cdc_ecm);
313
314
            /* Link state can now be set to down.  */
315
316
            /* Notify the network driver.  */
317
8
            _ux_network_driver_link_down(cdc_ecm -> ux_host_class_cdc_ecm_network_handle);
318
319
            /* Set the link state.  */
320
8
            cdc_ecm -> ux_host_class_cdc_ecm_link_state =  UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN;
321
        }
322
    }
323
}
324
#endif