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