GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_cdc_ecm_write.c Lines: 53 53 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
/**                                                                       */
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_write                        PORTABLE C      */
39
/*                                                           6.2.0        */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Chaoqiong Xiao, Microsoft Corporation                               */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function writes to the cdc_ecm interface. The call is          */
47
/*    non-blocking and queues the packet if there is an on-going write.   */
48
/*                                                                        */
49
/*  INPUT                                                                 */
50
/*                                                                        */
51
/*    cdc_ecm                               Pointer to cdc_ecm class      */
52
/*    packet                                Packet to write or queue      */
53
/*                                                                        */
54
/*  OUTPUT                                                                */
55
/*                                                                        */
56
/*    Completion Status                                                   */
57
/*                                                                        */
58
/*  CALLS                                                                 */
59
/*                                                                        */
60
/*    _ux_host_stack_transfer_request       Process transfer request      */
61
/*    _ux_host_semaphore_put                Release protection semaphore  */
62
/*    nx_packet_transmit_release            Release NetX packet           */
63
/*                                                                        */
64
/*  CALLED BY                                                             */
65
/*                                                                        */
66
/*    Application                                                         */
67
/*                                                                        */
68
/**************************************************************************/
69
2139
UINT  _ux_host_class_cdc_ecm_write(VOID *cdc_ecm_class, NX_PACKET *packet)
70
{
71
72
UX_INTERRUPT_SAVE_AREA
73
74
UX_TRANSFER             *transfer_request;
75
UINT                    status;
76
UCHAR                   *packet_header;
77
UX_HOST_CLASS_CDC_ECM   *cdc_ecm;
78
#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
79
ULONG                   copied;
80
#endif
81
82
    /* Get the instance.  */
83
2139
    cdc_ecm = (UX_HOST_CLASS_CDC_ECM *) cdc_ecm_class;
84
85
    /* If trace is enabled, insert this event into the trace buffer.  */
86
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ECM_WRITE, cdc_ecm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
87
88
    /* We're arming transfer now.  */
89
2139
    cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_check_and_arm_in_process =  UX_TRUE;
90
91
    /* We need to disable interrupts here because we need to make sure that if the xmit
92
       queue is non-null, it remains non-null until we have queued the packet.
93
       Note that we do not have to worry about the case where the queue is null,
94
       because we are the only ones that can change it from null to non-null.  */
95
2139
    UX_DISABLE
96
97
    /* Ensure the instance is valid.  */
98
2139
    if (cdc_ecm -> ux_host_class_cdc_ecm_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
99
    {
100
101
        /* Restore interrupts.  */
102
1
        UX_RESTORE
103
104
        /* Error trap.  */
105
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
106
107
        /* If trace is enabled, insert this event into the trace buffer.  */
108
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, cdc_ecm, 0, 0, UX_TRACE_ERRORS, 0, 0)
109
110
1
        return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
111
    }
112
113
    /* Validate packet length.  */
114
2138
    if (packet -> nx_packet_length > UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE)
115
    {
116
117
        /* Restore interrupts.  */
118
1
        UX_RESTORE
119
120
        /* Error trap.  */
121
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_SIZE_ERROR);
122
123
        /* If trace is enabled, insert this event into the trace buffer.  */
124
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CLASS_ETH_SIZE_ERROR, cdc_ecm, packet -> nx_packet_length, 0, UX_TRACE_ERRORS, 0, 0)
125
126
1
        return(UX_CLASS_ETH_SIZE_ERROR);
127
    }
128
129
    /* Are we in a valid state?  */
130
2137
    if (cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)
131
    {
132
133
        /* Check the queue. See if there is something that is being sent.  */
134
2136
        if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_head == UX_NULL)
135
        {
136
137
            /* Reset the queue pointer of this packet.  */
138
194
            packet -> nx_packet_queue_next =  UX_NULL;
139
140
            /* Memorize this packet at the beginning of the queue.  */
141
194
            cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_head =  packet;
142
194
            cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_tail =  packet;
143
144
            /* Restore interrupts.  */
145
194
            UX_RESTORE
146
147
            /* Now we need to arm the transfer.  */
148
149
            /* Get the pointer to the bulk out endpoint transfer request.  */
150
194
            transfer_request =  &cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_endpoint -> ux_endpoint_transfer_request;
151
152
#ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
153
154
194
            if (packet -> nx_packet_next != UX_NULL)
155
            {
156
157
                /* Create buffer.  */
158
6
                if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer == UX_NULL)
159
                {
160
2
                    cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN,
161
                                        UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE);
162
2
                    if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer == UX_NULL)
163
                    {
164
1
                        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
165
1
                        return(UX_MEMORY_INSUFFICIENT);
166
                    }
167
                }
168
169
                /* Put packet to continuous buffer to transfer.  */
170
5
                packet_header = cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer;
171
5
                nx_packet_data_extract_offset(packet, 0, packet_header, packet -> nx_packet_length, &copied);
172
            }
173
            else
174
#endif
175
            {
176
177
                /* Load the address of the current packet header at the physical header.  */
178
188
                packet_header =  packet -> nx_packet_prepend_ptr;
179
180
            }
181
182
            /* Setup the transaction parameters.  */
183
193
            transfer_request -> ux_transfer_request_data_pointer     =  packet_header;
184
193
            transfer_request -> ux_transfer_request_requested_length =  packet -> nx_packet_length;
185
186
            /* Store the packet that owns this transaction.  */
187
193
            transfer_request -> ux_transfer_request_user_specific =  packet;
188
189
            /* Arm the transfer request.  */
190
193
            status =  _ux_host_stack_transfer_request(transfer_request);
191
192
            /* Did we successfully arm the transfer?  */
193
193
            if (status != UX_SUCCESS)
194
            {
195
196
                /* Clear the queue. No need to clear the tail.  */
197
1
                cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_head =  UX_NULL;
198
199
                /* We cleared the queue, so we must free the packet. First
200
                   we need to clean it before passing it to NetX.  */
201
1
                packet -> nx_packet_prepend_ptr =  packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
202
1
                packet -> nx_packet_length =  packet -> nx_packet_length - UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
203
204
                /* And ask Netx to release it.  */
205
1
                nx_packet_transmit_release(packet);
206
207
                /* Could not arm this transfer.  */
208
1
                status =  UX_ERROR;
209
            }
210
        }
211
        else
212
        {
213
214
            /* The packet to be sent is the last in the chain.  */
215
1942
            packet -> nx_packet_queue_next =  NX_NULL;
216
217
            /* Memorize the packet to be sent.  */
218
1942
            cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_tail -> nx_packet_queue_next =  packet;
219
220
            /* Set the tail.  */
221
1942
            cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_tail =  packet;
222
223
            /* Restore interrupts.  */
224
1942
            UX_RESTORE
225
226
            /* Successfully added to queue.  */
227
1942
            status =  UX_SUCCESS;
228
        }
229
    }
230
    else
231
    {
232
233
        /* Link was down.  */
234
235
        /* Restore interrupts.  */
236
1
        UX_RESTORE
237
238
        /* Release the packet.  */
239
1
        packet -> nx_packet_prepend_ptr =  packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
240
1
        packet -> nx_packet_length =  packet -> nx_packet_length - UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
241
1
        nx_packet_transmit_release(packet);
242
243
        /* Report error to application.  */
244
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_CDC_ECM_LINK_STATE_DOWN_ERROR);
245
246
        /* Return error.  */
247
1
        status =  UX_ERROR;
248
    }
249
250
    /* Signal that we are done arming and resume waiting thread if necessary.  */
251
2136
    cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_check_and_arm_in_process =  UX_FALSE;
252
2136
    if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish == UX_TRUE)
253
1
        _ux_host_semaphore_put(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish_semaphore);
254
255
    /* We are done here.  */
256
2136
    return(status);
257
}
258
#endif