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