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_thread PORTABLE C */
39 /* 6.2.0 */
40 /* AUTHOR */
41 /* */
42 /* Chaoqiong Xiao, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This is the CDC ECM thread that monitors the link change flag, */
47 /* receives data from the device, and passes the data to the NetX-USB */
48 /* broker. */
49 /* */
50 /* INPUT */
51 /* */
52 /* cdc_ecm CDC ECM instance */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* Completion Status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _ux_host_class_cdc_ecm_transmit_queue_clean */
61 /* Clean transmit queue */
62 /* _ux_host_stack_transfer_request Transfer request */
63 /* _ux_host_semaphore_get Get semaphore */
64 /* _ux_host_semaphore_put Put semaphore */
65 /* _ux_utility_short_get_big_endian Get 16-bit big endian */
66 /* _ux_network_driver_link_up Set state link up */
67 /* _ux_network_driver_link_down Set state link down */
68 /* _ux_network_driver_packet_received Process received packet */
69 /* nx_packet_allocate Allocate NetX packet */
70 /* nx_packet_release Free NetX packet */
71 /* */
72 /* CALLED BY */
73 /* */
74 /* CDC ECM class initialization */
75 /* */
76 /* RELEASE HISTORY */
77 /* */
78 /* DATE NAME DESCRIPTION */
79 /* */
80 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
81 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
82 /* prefixed UX to MS_TO_TICK, */
83 /* used UX prefix to refer to */
84 /* TX symbols instead of using */
85 /* them directly, */
86 /* resulting in version 6.1 */
87 /* 02-02-2021 Xiuwen Cai Modified comment(s), added */
88 /* compile option for using */
89 /* packet pool from NetX, */
90 /* resulting in version 6.1.4 */
91 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
92 /* refined macros names, */
93 /* resulting in version 6.1.10 */
94 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
95 /* fixed standalone compile, */
96 /* resulting in version 6.1.11 */
97 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
98 /* no length from IP header, */
99 /* deprecated ECM pool option, */
100 /* supported NX packet chain, */
101 /* resulting in version 6.2.0 */
102 /* */
103 /**************************************************************************/
_ux_host_class_cdc_ecm_thread(ULONG parameter)104 VOID _ux_host_class_cdc_ecm_thread(ULONG parameter)
105 {
106
107 UX_HOST_CLASS_CDC_ECM *cdc_ecm;
108 UX_TRANSFER *transfer_request;
109 NX_PACKET *packet;
110 UINT status;
111 USB_NETWORK_DEVICE_TYPE *usb_network_device_ptr;
112 ULONG packet_buffer_size;
113
114
115 /* Cast the parameter passed in the thread into the cdc_ecm pointer. */
116 UX_THREAD_EXTENSION_PTR_GET(cdc_ecm, UX_HOST_CLASS_CDC_ECM, parameter)
117
118 /* Loop forever waiting for changes signaled through the semaphore. */
119 while (1)
120 {
121
122 /* Wait for the semaphore to be put by the cdc_ecm interrupt event. */
123 _ux_host_semaphore_get_norc(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore, UX_WAIT_FOREVER);
124
125 /* Check the link state. It is either pending up or down. */
126 if (cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_PENDING_UP)
127 {
128
129 /* Now the link is up. */
130 cdc_ecm -> ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP;
131
132 /* Communicate the state with the network driver. */
133 _ux_network_driver_link_up(cdc_ecm -> ux_host_class_cdc_ecm_network_handle);
134
135 /* As long as we are connected, configured and link up ... do some work.... */
136 while ((cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP) &&
137 (cdc_ecm -> ux_host_class_cdc_ecm_device -> ux_device_state == UX_DEVICE_CONFIGURED))
138 {
139
140 /* Check if we have packet pool available. */
141 if (cdc_ecm -> ux_host_class_cdc_ecm_packet_pool == UX_NULL)
142 {
143
144 /* Get the network device handle. */
145 usb_network_device_ptr = (USB_NETWORK_DEVICE_TYPE *)(cdc_ecm -> ux_host_class_cdc_ecm_network_handle);
146
147 /* Check if IP instance is available. */
148 if (usb_network_device_ptr -> ux_network_device_ip_instance != UX_NULL)
149 {
150
151 /* Get the packet pool from IP instance. */
152 cdc_ecm -> ux_host_class_cdc_ecm_packet_pool = usb_network_device_ptr -> ux_network_device_ip_instance -> nx_ip_default_packet_pool;
153 }
154 else
155 {
156
157 /* IP instance is not available, wait for application to attach the interface. */
158 _ux_utility_delay_ms(UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_INSTANCE_WAIT));
159 }
160 continue;
161 }
162
163 /* We can accept reception. Get a NX Packet. */
164 status = nx_packet_allocate(cdc_ecm -> ux_host_class_cdc_ecm_packet_pool, &packet,
165 NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT));
166
167 if (status == NX_SUCCESS)
168 {
169
170 /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header. */
171 packet -> nx_packet_prepend_ptr += sizeof(USHORT);
172
173 /* We have a packet. Link this packet to the reception transfer request on the bulk in endpoint. */
174 transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint -> ux_endpoint_transfer_request;
175
176 #ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
177
178 /* Check packet buffer size, if too small chain is used. */
179 packet_buffer_size = (ULONG)(packet -> nx_packet_data_end - packet -> nx_packet_prepend_ptr);
180 if (packet_buffer_size < UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE)
181 {
182 if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer == UX_NULL)
183 {
184 cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer =
185 _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY,
186 UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE);
187 if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer == UX_NULL)
188 {
189
190 /* Memory allocation fail. */
191 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
192
193 /* Release packet. */
194 nx_packet_release(packet);
195
196 /* Delay to let other threads to run. */
197 _ux_utility_delay_ms(1);
198 continue;
199 }
200
201 }
202
203 /* Set the data pointer. */
204 transfer_request -> ux_transfer_request_data_pointer = cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer;
205 }
206 else
207 #endif
208 {
209
210 /* Set the data pointer. */
211 transfer_request -> ux_transfer_request_data_pointer = packet -> nx_packet_prepend_ptr;
212
213 }
214
215 /* And length. */
216 transfer_request -> ux_transfer_request_requested_length = UX_HOST_CLASS_CDC_ECM_NX_PAYLOAD_SIZE;
217 transfer_request -> ux_transfer_request_actual_length = 0;
218
219 /* Store the packet that owns this transaction. */
220 transfer_request -> ux_transfer_request_user_specific = packet;
221
222 /* Reset the queue pointer of this packet. */
223 packet -> nx_packet_queue_next = UX_NULL;
224
225 /* We're arming the transfer now. */
226 cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process = UX_TRUE;
227
228 /* Is the link up? */
229 if (cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)
230 {
231
232 /* Ask USB to schedule a reception. */
233 status = _ux_host_stack_transfer_request(transfer_request);
234
235 /* Signal that we are done arming and resume waiting thread if necessary. */
236 cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process = UX_FALSE;
237 if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish == UX_TRUE)
238 _ux_host_semaphore_put(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore);
239
240 /* Check if the transaction was armed successfully. */
241 if (status == UX_SUCCESS)
242 {
243
244 /* Wait for the completion of the transfer request. */
245 _ux_host_semaphore_get_norc(&transfer_request -> ux_transfer_request_semaphore, UX_WAIT_FOREVER);
246
247 /* Check the transfer status. If there is a transport error, we ignore the packet
248 and restart it. */
249 if (transfer_request -> ux_transfer_request_completion_code == UX_SUCCESS)
250 {
251
252 #ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
253
254 /* Check if transfer buffer is used. */
255 if (packet -> nx_packet_prepend_ptr !=
256 transfer_request -> ux_transfer_request_data_pointer)
257 {
258
259 /* Adjust append_ptr for copy. */
260 packet -> nx_packet_append_ptr = packet -> nx_packet_prepend_ptr;
261
262 /* Append data to packet. */
263 status = nx_packet_data_append(packet,
264 transfer_request -> ux_transfer_request_data_pointer,
265 transfer_request -> ux_transfer_request_actual_length,
266 cdc_ecm -> ux_host_class_cdc_ecm_packet_pool,
267 UX_MS_TO_TICK(UX_HOST_CLASS_CDC_ECM_PACKET_POOL_WAIT));
268 if (status != NX_SUCCESS)
269 {
270
271 /* Release packet. */
272 nx_packet_release(packet);
273
274 /* Error trap. */
275 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_ERROR);
276 continue;
277 }
278 }
279 else
280 #endif
281 {
282
283 /* Get the packet length. */
284 packet -> nx_packet_length = transfer_request -> ux_transfer_request_actual_length;
285
286 /* Adjust the prepend, length, and append fields. */
287 packet -> nx_packet_append_ptr =
288 packet->nx_packet_prepend_ptr + transfer_request -> ux_transfer_request_actual_length;
289 }
290
291 /* Send that packet to the NetX USB broker. */
292 _ux_network_driver_packet_received(cdc_ecm -> ux_host_class_cdc_ecm_network_handle, packet);
293 }
294 else
295 {
296
297 /* Free the packet that was not successfully received. */
298 nx_packet_release(packet);
299 }
300 }
301 else
302 {
303
304 /* Error arming transfer. */
305
306 /* Release packet. */
307 nx_packet_release(packet);
308 }
309 }
310 else
311 {
312
313 /* Link is down. */
314
315 /* Signal that we are done arming and resume waiting thread if necessary. */
316 cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process = UX_FALSE;
317 if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish == UX_TRUE)
318 _ux_host_semaphore_put(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore);
319
320 /* Release packet. */
321 nx_packet_release(packet);
322 }
323 }
324 else
325 {
326
327 /* Packet allocation timed out. Note that the timeout value is
328 configurable. */
329
330 /* Error trap. No need for trace, since NetX does it. */
331 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
332 }
333 }
334 }
335 else
336 {
337
338 /* The link state is pending down. We need to free the xmit queue. */
339 _ux_host_class_cdc_ecm_transmit_queue_clean(cdc_ecm);
340
341 /* Link state can now be set to down. */
342
343 /* Notify the network driver. */
344 _ux_network_driver_link_down(cdc_ecm -> ux_host_class_cdc_ecm_network_handle);
345
346 /* Set the link state. */
347 cdc_ecm -> ux_host_class_cdc_ecm_link_state = UX_HOST_CLASS_CDC_ECM_LINK_STATE_DOWN;
348 }
349 }
350 }
351 #endif
352