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 /**   Asix 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_asix.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_class_asix_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 asix interface. The call is blocking    */
46 /*    and only returns when there is either an error or when the transfer */
47 /*    is complete.                                                        */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    asix                                  Pointer to asix 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_utility_short_put                 Put 16-bit value              */
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 /*                                            resulting in version 6.1    */
74 /*  08-02-2021     Wen Wang                 Modified comment(s),          */
75 /*                                            fixed spelling error,       */
76 /*                                            resulting in version 6.1.8  */
77 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
78 /*                                            fixed standalone compile,   */
79 /*                                            resulting in version 6.1.11 */
80 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            supported NX packet chain,  */
82 /*                                            added queue modify protect, */
83 /*                                            improved error check,       */
84 /*                                            resulting in version 6.2.0  */
85 /*                                                                        */
86 /**************************************************************************/
_ux_host_class_asix_write(VOID * asix_class,NX_PACKET * packet)87 UINT  _ux_host_class_asix_write(VOID *asix_class, NX_PACKET *packet)
88 {
89 #if defined(UX_HOST_STANDALONE)
90     UX_PARAMETER_NOT_USED(asix_class);
91     UX_PARAMETER_NOT_USED(packet);
92     return(UX_FUNCTION_NOT_SUPPORTED);
93 #else
94 
95 UX_INTERRUPT_SAVE_AREA
96 UX_TRANSFER         *transfer_request;
97 UINT                status;
98 NX_PACKET           *current_packet;
99 NX_PACKET           *next_packet;
100 UCHAR               *packet_header;
101 UX_HOST_CLASS_ASIX  *asix;
102 ULONG               adjusted_length;
103 #ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT
104 ULONG               copied;
105 #endif
106 
107     /* Proper class casting.  */
108     asix = (UX_HOST_CLASS_ASIX *) asix_class;
109 
110     /* If trace is enabled, insert this event into the trace buffer.  */
111     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_ASIX_WRITE, asix, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
112 
113     /* Critical enter.  */
114     UX_DISABLE
115 
116     /* Ensure the instance is valid.  */
117     if (asix -> ux_host_class_asix_state !=  UX_HOST_CLASS_INSTANCE_LIVE)
118     {
119 
120         /* Error trap. */
121         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
122 
123         /* If trace is enabled, insert this event into the trace buffer.  */
124         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, asix, 0, 0, UX_TRACE_ERRORS, 0, 0)
125 
126         /* Critical exit.  */
127         UX_RESTORE;
128         return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
129     }
130 
131     /* Ensure link state is OK.  */
132     if (asix -> ux_host_class_asix_link_state != UX_HOST_CLASS_ASIX_LINK_STATE_UP)
133     {
134 
135         /* Critical exit.  */
136         UX_RESTORE;
137 
138         /* Release the packet.  */
139         packet -> nx_packet_prepend_ptr =  packet -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE;
140         packet -> nx_packet_length =  packet -> nx_packet_length - NX_ETHERNET_SIZE;
141         nx_packet_transmit_release(packet);
142 
143         /* Report error to application.  */
144         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_LINK_STATE_DOWN_ERROR);
145         return(UX_CLASS_ETH_LINK_STATE_DOWN_ERROR);
146     }
147 
148     /* Load the address of the current packet header at the physical header.  */
149     packet_header =  packet -> nx_packet_prepend_ptr;
150 
151     /* Subtract 2 USHORT to store length of the packet.  */
152     packet_header -= sizeof(USHORT) * 2;
153 
154 #if defined(UX_HOST_CLASS_ASIX_HEADER_CHECK_ENABLE)
155 
156     /* Check packet compatibility to avoid writing to unexpected area.  */
157     if (packet_header < packet -> nx_packet_data_start)
158     {
159 
160         /* Error trap.  */
161         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEMORY_ERROR);
162 
163         UX_RESTORE;
164         return(UX_HOST_CLASS_MEMORY_ERROR);
165     }
166 #endif
167 
168     /* Packet length validation.  */
169     if (UX_OVERFLOW_CHECK_ADD_ULONG(packet -> nx_packet_length, sizeof(USHORT) * 2))
170     {
171 
172         /* Error trap.  */
173         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MATH_OVERFLOW);
174         UX_RESTORE
175         return(UX_MATH_OVERFLOW);
176     }
177     adjusted_length = packet -> nx_packet_length + sizeof(USHORT) * 2;
178     if (adjusted_length > UX_HOST_CLASS_ASIX_TRANSMIT_BUFFER_SIZE)
179     {
180 
181         /* Error trap.  */
182         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_SIZE_ERROR);
183         UX_RESTORE
184         return(UX_CLASS_ETH_SIZE_ERROR);
185     }
186 
187     /* Store the length of the payload in the first USHORT.  */
188     _ux_utility_short_put(packet_header, (USHORT)(packet -> nx_packet_length));
189 
190     /* Store the negative length of the payload in the first USHORT.  */
191     _ux_utility_short_put(packet_header + sizeof(USHORT), (USHORT)(~packet -> nx_packet_length));
192 
193     /* Check the queue. See if there is something that is being sent. */
194     if (asix -> ux_host_class_asix_xmit_queue == UX_NULL)
195     {
196 
197         /* Reset the queue pointer of this packet.  */
198         packet -> nx_packet_queue_next = UX_NULL;
199 
200         /* Memorize this packet at the beginning of the queue.  */
201         asix -> ux_host_class_asix_xmit_queue = packet;
202 
203         UX_RESTORE
204 
205         /* Nothing is in the queue. We need to arm this transfer. */
206         /* Get the pointer to the bulk out endpoint transfer request.  */
207         transfer_request =  &asix -> ux_host_class_asix_bulk_out_endpoint -> ux_endpoint_transfer_request;
208 
209 #ifdef UX_HOST_CLASS_ASIX_PACKET_CHAIN_SUPPORT
210 
211         /* Check if the packets are chained.  */
212         if (packet -> nx_packet_next)
213         {
214 
215             /* Create buffer.  */
216             if (asix -> ux_host_class_asix_xmit_buffer == UX_NULL)
217             {
218                 asix -> ux_host_class_asix_xmit_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN,
219                                     UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_ASIX_TRANSMIT_BUFFER_SIZE);
220                 if (asix -> ux_host_class_asix_xmit_buffer == UX_NULL)
221                 {
222                     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
223                     return(UX_MEMORY_INSUFFICIENT);
224                 }
225             }
226 
227             packet -> nx_packet_length = adjusted_length;
228             packet -> nx_packet_prepend_ptr -= sizeof(USHORT) * 2;
229             nx_packet_data_extract_offset(packet, 0, asix -> ux_host_class_asix_xmit_buffer, packet -> nx_packet_length, &copied);
230 
231             /* Setup the transaction parameters.  */
232             transfer_request -> ux_transfer_request_requested_length =  packet -> nx_packet_length;
233             transfer_request -> ux_transfer_request_data_pointer = asix -> ux_host_class_asix_xmit_buffer;
234 
235             /* Restore packet status.  */
236             packet -> nx_packet_length -= sizeof(USHORT) * 2;
237             packet -> nx_packet_prepend_ptr += sizeof(USHORT) * 2;
238         }
239         else
240 #endif
241         {
242 
243             /* Setup the transaction parameters.  */
244             transfer_request -> ux_transfer_request_data_pointer     =  packet_header;
245             transfer_request -> ux_transfer_request_requested_length =  adjusted_length;
246         }
247 
248         /* Store the packet that owns this transaction.  */
249         transfer_request -> ux_transfer_request_user_specific = packet;
250 
251         /* Perform the transfer.  */
252         status =  _ux_host_stack_transfer_request(transfer_request);
253 
254         /* Check if the transaction was armed successfully. We do not wait for the packet to be sent here. */
255         if (status != UX_SUCCESS)
256         {
257 
258             /* Could not arm this transfer.  */
259             asix -> ux_host_class_asix_xmit_queue = UX_NULL;
260             return(UX_ERROR);
261         }
262     }
263 
264     else
265 
266     {
267 
268         /* We get here when there is something in the queue.  */
269         current_packet =  asix -> ux_host_class_asix_xmit_queue;
270 
271         /* Get the next packet associated with the first packet.  */
272         next_packet = current_packet -> nx_packet_queue_next;
273 
274         /* Parse the current chain for the end.  */
275         while (next_packet != NX_NULL)
276         {
277             /* Remember the current packet.  */
278             current_packet = next_packet;
279 
280             /* See what the next packet in the chain is.  */
281             next_packet = current_packet -> nx_packet_queue_next;
282         }
283 
284         /* Memorize the packet to be sent.  */
285         current_packet -> nx_packet_queue_next = packet;
286 
287         /* The packet to be sent is the last in the chain.  */
288         packet -> nx_packet_queue_next = NX_NULL;
289 
290 
291         UX_RESTORE
292     }
293 
294     /* We are done here.  */
295     return(UX_SUCCESS);
296 #endif
297 }
298