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 /** USBX Component                                                        */
15 /**                                                                       */
16 /**   Device CDC_ECM Class                                                */
17 /**                                                                       */
18 /**************************************************************************/
19 /**************************************************************************/
20 
21 #define UX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "ux_api.h"
27 #include "ux_device_class_cdc_ecm.h"
28 #include "ux_device_stack.h"
29 
30 
31 #if !defined(UX_DEVICE_STANDALONE)
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_device_class_cdc_ecm_bulkout_thread             PORTABLE C      */
37 /*                                                           6.3.0        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function is the thread of the cdc_ecm bulk out endpoint. It    */
45 /*    is waiting for the host to send data on the bulk out endpoint to    */
46 /*    the device.                                                         */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    cdc_ecm_class                             Address of cdc_ecm class  */
51 /*                                                container               */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _ux_device_stack_transfer_request     Request transfer              */
60 /*    _ux_utility_memory_copy               Copy memory                   */
61 /*    nx_packet_allocate                    Allocate NetX packet          */
62 /*    nx_packet_release                     Free NetX packet              */
63 /*    _ux_device_thread_suspend             Suspend thread                */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    ThreadX                                                             */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
74 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            prefixed UX to MS_TO_TICK,  */
76 /*                                            verified memset and memcpy  */
77 /*                                            cases,                      */
78 /*                                            resulting in version 6.1    */
79 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            refined macros names,       */
81 /*                                            resulting in version 6.1.10 */
82 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            fixed standalone compile,   */
84 /*                                            resulting in version 6.1.11 */
85 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
86 /*                                            fixed EP not ready issue,   */
87 /*                                            used pool from NX IP inst,  */
88 /*                                            used NX API to copy data,   */
89 /*                                            resulting in version 6.2.0  */
90 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
91 /*                                            added zero copy support,    */
92 /*                                            added a new mode to manage  */
93 /*                                            endpoint buffer in classes, */
94 /*                                            resulting in version 6.3.0  */
95 /*                                                                        */
96 /**************************************************************************/
_ux_device_class_cdc_ecm_bulkout_thread(ULONG cdc_ecm_class)97 VOID  _ux_device_class_cdc_ecm_bulkout_thread(ULONG cdc_ecm_class)
98 {
99 
100 UX_SLAVE_CLASS                  *class_ptr;
101 UX_SLAVE_CLASS_CDC_ECM          *cdc_ecm;
102 UX_SLAVE_DEVICE                 *device;
103 UX_SLAVE_TRANSFER               *transfer_request;
104 UINT                            status;
105 NX_PACKET                       *packet;
106 USB_NETWORK_DEVICE_TYPE         *ux_nx_device;
107 
108     /* Cast properly the cdc_ecm instance.  */
109     UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, cdc_ecm_class)
110 
111     /* Get the cdc_ecm instance from this class container.  */
112     cdc_ecm =  (UX_SLAVE_CLASS_CDC_ECM *) class_ptr -> ux_slave_class_instance;
113 
114     /* Get the pointer to the device.  */
115     device =  &_ux_system_slave -> ux_system_slave_device;
116 
117     /* This thread runs forever but can be suspended or resumed.  */
118     while (1)
119     {
120 
121         /* As long as the device is in the CONFIGURED state.  */
122         while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
123         {
124 
125             /* Check if packet pool is ready.  */
126             if (cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool == UX_NULL)
127             {
128 
129                 /* Get the network device handle.  */
130                 ux_nx_device = (USB_NETWORK_DEVICE_TYPE *)(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle);
131 
132                 /* Get packet pool from IP instance (if available).  */
133                 if (ux_nx_device -> ux_network_device_ip_instance != UX_NULL)
134                 {
135                     cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool = ux_nx_device -> ux_network_device_ip_instance -> nx_ip_default_packet_pool;
136                 }
137                 else
138                 {
139 
140                     /* Error trap.  */
141                     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_ETH_PACKET_POOL_ERROR);
142 
143                     _ux_utility_delay_ms(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_INST_WAIT);
144                     continue;
145                 }
146             }
147 
148             /* Check if Bulk OUT endpoint is ready.  */
149             if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint == UX_NULL)
150             {
151                 _ux_utility_delay_ms(UX_DEVICE_CLASS_CDC_ECM_LINK_CHECK_WAIT);
152                 continue;
153             }
154 
155             /* We can accept new reception. Get a NX Packet */
156             status =  nx_packet_allocate(cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool, &packet,
157                                          NX_RECEIVE_PACKET, UX_MS_TO_TICK(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT));
158 
159             if (status == NX_SUCCESS)
160             {
161 
162                 /* Select the transfer request associated with BULK OUT endpoint.   */
163                 transfer_request =  &cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint -> ux_slave_endpoint_transfer_request;
164 
165                 /* And length.  */
166                 transfer_request -> ux_slave_transfer_request_requested_length =  UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER_SIZE;
167                 transfer_request -> ux_slave_transfer_request_actual_length =     0;
168 
169                 /* Memorize this packet at the beginning of the queue.  */
170                 cdc_ecm -> ux_slave_class_cdc_ecm_receive_queue = packet;
171 
172                 /* Reset the queue pointer of this packet.  */
173                 packet -> nx_packet_queue_next = UX_NULL;
174 
175 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
176 
177                 /* Send the request to the device controller.  */
178                 transfer_request -> ux_slave_transfer_request_data_pointer = packet -> nx_packet_prepend_ptr + sizeof(USHORT);
179                 status =  _ux_device_stack_transfer_request(transfer_request,
180                         packet -> nx_packet_pool_owner -> nx_packet_pool_payload_size - sizeof(USHORT),
181                         packet -> nx_packet_pool_owner -> nx_packet_pool_payload_size - sizeof(USHORT));
182 #else
183 
184                 /* Send the request to the device controller.  */
185                 status =  _ux_device_stack_transfer_request(transfer_request, UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER_SIZE,
186                                                                     UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER_SIZE);
187 #endif
188 
189                 /* Check the completion code. */
190                 if (status == UX_SUCCESS)
191                 {
192 
193                     /* We only proceed with packets that are received OK, if error, ignore the packet. */
194                     /* If trace is enabled, insert this event into the trace buffer.  */
195                     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_PACKET_RECEIVE, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
196 
197                     /* Adjust the prepend pointer to take into account the non 3 bit alignment of the ethernet header.  */
198                     packet -> nx_packet_prepend_ptr += sizeof(USHORT);
199                     packet -> nx_packet_append_ptr += sizeof(USHORT);
200 
201 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
202 
203                     /* Data already in packet.  */
204                     packet -> nx_packet_length = transfer_request -> ux_slave_transfer_request_actual_length;
205 
206                     /* Send that packet to the NetX USB broker.  */
207                     _ux_network_driver_packet_received(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle, packet);
208 #else
209 
210                     /* Copy the received packet in the IP packet data area.  */
211                     status = nx_packet_data_append(packet,
212                             transfer_request -> ux_slave_transfer_request_data_pointer,
213                             transfer_request -> ux_slave_transfer_request_actual_length,
214                             cdc_ecm -> ux_slave_class_cdc_ecm_packet_pool,
215                             UX_MS_TO_TICK(UX_DEVICE_CLASS_CDC_ECM_PACKET_POOL_WAIT));
216                     if (status == NX_SUCCESS)
217                     {
218 
219                         /* Send that packet to the NetX USB broker.  */
220                         _ux_network_driver_packet_received(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle, packet);
221                     }
222                     else
223                     {
224 
225                         /* We received a malformed packet. Report to application.  */
226                         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CLASS_MALFORMED_PACKET_RECEIVED_ERROR);
227                         nx_packet_release(packet);
228                     }
229 #endif
230                 }
231                 else
232 
233                     /* Free the packet that was not successfully received.  */
234                     nx_packet_release(packet);
235             }
236             else
237             {
238 
239                 /* Packet allocation timed out. Note that the timeout value is
240                    configurable.  */
241 
242                 /* Error trap. No need for trace, since NetX does it.  */
243                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
244             }
245         }
246 
247         /* We need to suspend ourselves. We will be resumed by the device enumeration module.  */
248         _ux_device_thread_suspend(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread);
249     }
250 }
251 #endif
252