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