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