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: 2024-12-12 17:16:36 Branches: 32 32 100.0 %

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