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