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