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