GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_device_classes/src/ux_device_class_cdc_ecm_bulkin_thread.c Lines: 39 39 100.0 %
Date: 2026-03-06 18:57:10 Branches: 18 18 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
/** USBX Component                                                        */
16
/**                                                                       */
17
/**   Device CDC_ECM Class                                                */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define UX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "ux_api.h"
28
#include "ux_device_class_cdc_ecm.h"
29
#include "ux_device_stack.h"
30
31
32
#if !defined(UX_DEVICE_STANDALONE)
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _ux_device_class_cdc_ecm_bulkin_thread              PORTABLE C      */
38
/*                                                           6.3.0        */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Chaoqiong Xiao, Microsoft Corporation                               */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function is the thread of the cdc_ecm bulkin endpoint. The bulk*/
46
/*    IN endpoint is used when the device wants to write data to be sent  */
47
/*    to the host.                                                        */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    cdc_ecm_class                             Address of cdc_ecm class  */
52
/*                                                container               */
53
/*                                                                        */
54
/*  OUTPUT                                                                */
55
/*                                                                        */
56
/*    None                                                                */
57
/*                                                                        */
58
/*  CALLS                                                                 */
59
/*                                                                        */
60
/*    _ux_device_stack_transfer_request     Request transfer              */
61
/*    _ux_utility_event_flags_get           Get event flags               */
62
/*    _ux_device_mutex_on                   Take mutex                    */
63
/*    _ux_device_mutex_off                  Free mutex                    */
64
/*                                                                        */
65
/*  CALLED BY                                                             */
66
/*                                                                        */
67
/*    ThreadX                                                             */
68
/*                                                                        */
69
/**************************************************************************/
70
47
VOID  _ux_device_class_cdc_ecm_bulkin_thread(ULONG cdc_ecm_class)
71
{
72
73
UX_SLAVE_CLASS                  *class_ptr;
74
UX_SLAVE_CLASS_CDC_ECM          *cdc_ecm;
75
UX_SLAVE_DEVICE                 *device;
76
UX_SLAVE_TRANSFER               *transfer_request;
77
UINT                            status;
78
ULONG                           actual_flags;
79
NX_PACKET                       *current_packet;
80
ULONG                           transfer_length;
81
ULONG                           copied;
82
#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY) && !defined(NX_DISABLE_PACKET_CHAIN)
83
NX_PACKET                       *packet;
84
#endif
85
86
    /* Cast properly the cdc_ecm instance.  */
87
47
    UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, cdc_ecm_class)
88
89
    /* Get the cdc_ecm instance from this class container.  */
90
47
    cdc_ecm =  (UX_SLAVE_CLASS_CDC_ECM *) class_ptr -> ux_slave_class_instance;
91
92
    /* Get the pointer to the device.  */
93
47
    device =  &_ux_system_slave -> ux_system_slave_device;
94
95
    /* This thread runs forever but can be suspended or resumed.  */
96
48
    while (1)
97
    {
98
99
        /* For as long we are configured.  */
100
        while (1)
101
        {
102
103
            /* Wait until either a new packet has been added to the xmit queue,
104
               or until there has been a change in the device state (i.e. disconnection).  */
105
241
            _ux_utility_event_flags_get(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, (UX_DEVICE_CLASS_CDC_ECM_NEW_BULKIN_EVENT |
106
                                                                                               UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT),
107
                                                                                              UX_OR_CLEAR, &actual_flags, UX_WAIT_FOREVER);
108
109
            /* Check the completion code and the actual flags returned.  */
110
232
            if ((actual_flags & UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT) == 0)
111
            {
112
113
                /* Get the transfer request for the bulk IN pipe.  */
114
139
                transfer_request =  &cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint -> ux_slave_endpoint_transfer_request;
115
116
                /* Parse all packets.  */
117
1220
                while (cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue != UX_NULL)
118
                {
119
120
                    /* Ensure no other threads are modifying the xmit queue.  */
121
1081
                    _ux_device_mutex_on(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
122
123
                    /* Get the current packet in the list.  */
124
1081
                    current_packet =  cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue;
125
126
                    /* Set the next packet (or a NULL value) as the head of the xmit queue. */
127
1081
                    cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue =  current_packet -> nx_packet_queue_next;
128
129
                    /* Free Mutex resource.  */
130
1081
                    _ux_device_mutex_off(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
131
132
                    /* If the link is down no need to rearm a packet. */
133
1081
                    if (cdc_ecm -> ux_slave_class_cdc_ecm_link_state == UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP)
134
                    {
135
#if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
136
137
                        /* Default to success.  */
138
                        status = UX_SUCCESS;
139
140
#ifndef NX_DISABLE_PACKET_CHAIN
141
142
                        /* Check if packet is chained, allocate a new packet to fill the total data.  */
143
                        if (current_packet -> nx_packet_next)
144
                        {
145
146
                            /* Check if collection of chained data can fit in one packet.  */
147
                            if (current_packet -> nx_packet_length >
148
                                current_packet -> nx_packet_pool_owner -> nx_packet_pool_payload_size)
149
                                status = UX_TRANSFER_BUFFER_OVERFLOW;
150
                            else
151
                            {
152
153
                                /* Allocate a new packet for chain data collection.  */
154
                                status = nx_packet_allocate(cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool, &packet,
155
                                            NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT));
156
                                if (status == UX_SUCCESS)
157
                                {
158
159
                                    /* Copy the packet to the buffer.  */
160
                                    status = nx_packet_data_extract_offset(current_packet, 0,
161
                                            packet -> nx_packet_prepend_ptr,
162
                                            current_packet -> nx_packet_length, &copied);
163
                                    if (status == NX_SUCCESS)
164
                                    {
165
                                        packet -> nx_packet_length = current_packet -> nx_packet_length;
166
167
                                        /* Release the chained packet.  */
168
                                        nx_packet_transmit_release(current_packet);
169
170
                                        /* Use copied packet instead.  */
171
                                        current_packet = packet;
172
                                    }
173
                                }
174
                            }
175
176
177
                            /* Can not copy/buffer issue.  */
178
                            if (status != UX_SUCCESS)
179
                                status = UX_TRANSFER_BUFFER_OVERFLOW;
180
181
                        }
182
#endif
183
                        if (status == UX_SUCCESS)
184
                        {
185
186
                            /* Set the transfer request data pointer to the packet buffer.  */
187
                            transfer_request -> ux_slave_transfer_request_data_pointer = current_packet -> nx_packet_prepend_ptr;
188
189
                            /* Calculate the transfer length.  */
190
                            transfer_length =  current_packet -> nx_packet_length;
191
192
                            /* If trace is enabled, insert this event into the trace buffer.  */
193
                            UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_PACKET_TRANSMIT, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
194
195
                            /* Send the request to the device controller.  */
196
                            status =  _ux_device_stack_transfer_request(transfer_request, transfer_length, transfer_length + 1);
197
                        }
198
199
                        /* Check error code. */
200
                        if (status != UX_SUCCESS)
201
                        {
202
203
                            /* Is this not a transfer abort? (this is expected to happen)  */
204
                            if (status != UX_TRANSFER_BUS_RESET)
205
                            {
206
207
                                /* Error trap. */
208
                                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
209
                            }
210
                        }
211
#else
212
213
                        /* Can the packet fit in the transfer requests data buffer?  */
214
1080
                        if (current_packet -> nx_packet_length <= UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER_SIZE)
215
                        {
216
217
                            /* Copy the packet in the transfer descriptor buffer.  */
218
1078
                            status = nx_packet_data_extract_offset(current_packet, 0,
219
1078
                                    transfer_request -> ux_slave_transfer_request_data_pointer,
220
1078
                                    current_packet -> nx_packet_length, &copied);
221
1078
                            if (status == UX_SUCCESS)
222
                            {
223
224
                                /* Calculate the transfer length.  */
225
1076
                                transfer_length =  current_packet -> nx_packet_length;
226
227
                                /* If trace is enabled, insert this event into the trace buffer.  */
228
                                UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_PACKET_TRANSMIT, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
229
230
                                /* Send the request to the device controller.  */
231
1076
                                status =  _ux_device_stack_transfer_request(transfer_request, transfer_length, UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER_SIZE + 1);
232
                            }
233
234
                            /* Check error code. */
235
1078
                            if (status != UX_SUCCESS)
236
                            {
237
238
                                /* Is this not a transfer abort? (this is expected to happen)  */
239
7
                                if (status != UX_TRANSFER_BUS_RESET)
240
                                {
241
242
                                    /* Error trap. */
243
4
                                    _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
244
                                }
245
                            }
246
                        }
247
                        else
248
                        {
249
250
                            /* Packet is too large.  */
251
252
                            /* Report error to application.  */
253
2
                            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_BUFFER_OVERFLOW);
254
                        }
255
#endif
256
                    }
257
258
                    /* Free the packet that was just sent.  First do some housekeeping.  */
259
1081
                    current_packet -> nx_packet_prepend_ptr =  current_packet -> nx_packet_prepend_ptr + UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
260
1081
                    current_packet -> nx_packet_length =  current_packet -> nx_packet_length - UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
261
262
                    /* And ask Netx to release it.  */
263
1081
                    nx_packet_transmit_release(current_packet);
264
                }
265
            }
266
            else
267
            {
268
269
                /* We need to ensure nobody is adding to the queue, so get the mutex protection. */
270
93
                _ux_device_mutex_on(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
271
272
                /* Since we got the mutex, we know no one is trying to modify the queue; we also know
273
                   no one can start modifying the queue since the link state is down, so we can just
274
                   release the mutex.  */
275
93
                _ux_device_mutex_off(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
276
277
                /* We get here when the link is down. All packets pending must be freed.  */
278
95
                while (cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue != UX_NULL)
279
                {
280
281
                    /* Get the current packet in the list.  */
282
2
                    current_packet =  cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue;
283
284
                    /* Set the next packet (or a NULL value) as the head of the xmit queue. */
285
2
                    cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue =  current_packet -> nx_packet_queue_next;
286
287
                    /* Free the packet.  */
288
2
                    current_packet -> nx_packet_prepend_ptr =  current_packet -> nx_packet_prepend_ptr + UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
289
2
                    current_packet -> nx_packet_length =  current_packet -> nx_packet_length - UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
290
291
                    /* And ask Netx to release it.  */
292
2
                    nx_packet_transmit_release(current_packet);
293
                }
294
295
                /* Was the change in the device state caused by a disconnection?  */
296
93
                if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
297
                {
298
299
                    /* Yes. Break out of the loop and suspend ourselves, waiting for the next configuration.  */
300
86
                    break;
301
                }
302
            }
303
        }
304
305
        /* We need to suspend ourselves. We will be resumed by the device enumeration module or when a change of alternate setting happens.  */
306
86
        _ux_device_thread_suspend(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread);
307
    }
308
}
309
#endif