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 /**************************************************************************/
_ux_host_class_cdc_ecm_write(VOID * cdc_ecm_class,NX_PACKET * packet)88 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     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     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     UX_DISABLE
115 
116     /* Ensure the instance is valid.  */
117     if (cdc_ecm -> ux_host_class_cdc_ecm_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
118     {
119 
120         /* Restore interrupts.  */
121         UX_RESTORE
122 
123         /* Error trap.  */
124         _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         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
130     }
131 
132     /* Validate packet length.  */
133     if (packet -> nx_packet_length > UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE)
134     {
135 
136         /* Restore interrupts.  */
137         UX_RESTORE
138 
139         /* Error trap.  */
140         _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         return(UX_CLASS_ETH_SIZE_ERROR);
146     }
147 
148     /* Are we in a valid state?  */
149     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         if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_head == UX_NULL)
154         {
155 
156             /* Reset the queue pointer of this packet.  */
157             packet -> nx_packet_queue_next =  UX_NULL;
158 
159             /* Memorize this packet at the beginning of the queue.  */
160             cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_head =  packet;
161             cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_tail =  packet;
162 
163             /* Restore interrupts.  */
164             UX_RESTORE
165 
166             /* Now we need to arm the transfer.  */
167 
168             /* Get the pointer to the bulk out endpoint transfer request.  */
169             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             if (packet -> nx_packet_next != UX_NULL)
174             {
175 
176                 /* Create buffer.  */
177                 if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer == UX_NULL)
178                 {
179                     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                     if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer == UX_NULL)
182                     {
183                         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
184                         return(UX_MEMORY_INSUFFICIENT);
185                     }
186                 }
187 
188                 /* Put packet to continuous buffer to transfer.  */
189                 packet_header = cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer;
190                 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                 packet_header =  packet -> nx_packet_prepend_ptr;
198 
199             }
200 
201             /* Setup the transaction parameters.  */
202             transfer_request -> ux_transfer_request_data_pointer     =  packet_header;
203             transfer_request -> ux_transfer_request_requested_length =  packet -> nx_packet_length;
204 
205             /* Store the packet that owns this transaction.  */
206             transfer_request -> ux_transfer_request_user_specific =  packet;
207 
208             /* Arm the transfer request.  */
209             status =  _ux_host_stack_transfer_request(transfer_request);
210 
211             /* Did we successfully arm the transfer?  */
212             if (status != UX_SUCCESS)
213             {
214 
215                 /* Clear the queue. No need to clear the tail.  */
216                 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                 packet -> nx_packet_prepend_ptr =  packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
221                 packet -> nx_packet_length =  packet -> nx_packet_length - UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
222 
223                 /* And ask Netx to release it.  */
224                 nx_packet_transmit_release(packet);
225 
226                 /* Could not arm this transfer.  */
227                 status =  UX_ERROR;
228             }
229         }
230         else
231         {
232 
233             /* The packet to be sent is the last in the chain.  */
234             packet -> nx_packet_queue_next =  NX_NULL;
235 
236             /* Memorize the packet to be sent.  */
237             cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_tail -> nx_packet_queue_next =  packet;
238 
239             /* Set the tail.  */
240             cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_tail =  packet;
241 
242             /* Restore interrupts.  */
243             UX_RESTORE
244 
245             /* Successfully added to queue.  */
246             status =  UX_SUCCESS;
247         }
248     }
249     else
250     {
251 
252         /* Link was down.  */
253 
254         /* Restore interrupts.  */
255         UX_RESTORE
256 
257         /* Release the packet.  */
258         packet -> nx_packet_prepend_ptr =  packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
259         packet -> nx_packet_length =  packet -> nx_packet_length - UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
260         nx_packet_transmit_release(packet);
261 
262         /* Report error to application.  */
263         _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         status =  UX_ERROR;
267     }
268 
269     /* Signal that we are done arming and resume waiting thread if necessary.  */
270     cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_check_and_arm_in_process =  UX_FALSE;
271     if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish == UX_TRUE)
272         _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     return(status);
276 }
277 #endif
278