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 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   Device CDC_ECM Class                                                */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define UX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "ux_api.h"
28 #include "ux_device_class_cdc_ecm.h"
29 #include "ux_device_stack.h"
30 
31 
32 #if !defined(UX_DEVICE_STANDALONE)
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_device_class_cdc_ecm_bulkin_thread              PORTABLE C      */
38 /*                                                           6.2.0        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function is the thread of the cdc_ecm bulkin endpoint. The bulk*/
46 /*    IN endpoint is used when the device wants to write data to be sent  */
47 /*    to the host.                                                        */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    cdc_ecm_class                             Address of cdc_ecm class  */
52 /*                                                container               */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    None                                                                */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _ux_device_stack_transfer_request     Request transfer              */
61 /*    _ux_utility_event_flags_get           Get event flags               */
62 /*    _ux_device_mutex_on                   Take mutex                    */
63 /*    _ux_device_mutex_off                  Free mutex                    */
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 /*                                            verified memset and memcpy  */
76 /*                                            cases, used UX prefix to    */
77 /*                                            refer to TX symbols instead */
78 /*                                            of using them directly,     */
79 /*                                            resulting in version 6.1    */
80 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            refined macros names,       */
82 /*                                            resulting in version 6.1.10 */
83 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
84 /*                                            fixed standalone compile,   */
85 /*                                            resulting in version 6.1.11 */
86 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
87 /*                                            used NX API to copy data,   */
88 /*                                            resulting in version 6.2.0  */
89 /*                                                                        */
90 /**************************************************************************/
_ux_device_class_cdc_ecm_bulkin_thread(ULONG cdc_ecm_class)91 VOID  _ux_device_class_cdc_ecm_bulkin_thread(ULONG cdc_ecm_class)
92 {
93 
94 UX_SLAVE_CLASS                  *class_ptr;
95 UX_SLAVE_CLASS_CDC_ECM          *cdc_ecm;
96 UX_SLAVE_DEVICE                 *device;
97 UX_SLAVE_TRANSFER               *transfer_request;
98 UINT                            status;
99 ULONG                           actual_flags;
100 NX_PACKET                       *current_packet;
101 ULONG                           transfer_length;
102 ULONG                           copied;
103 
104     /* Cast properly the cdc_ecm instance.  */
105     UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, cdc_ecm_class)
106 
107     /* Get the cdc_ecm instance from this class container.  */
108     cdc_ecm =  (UX_SLAVE_CLASS_CDC_ECM *) class_ptr -> ux_slave_class_instance;
109 
110     /* Get the pointer to the device.  */
111     device =  &_ux_system_slave -> ux_system_slave_device;
112 
113     /* This thread runs forever but can be suspended or resumed.  */
114     while (1)
115     {
116 
117         /* For as long we are configured.  */
118         while (1)
119         {
120 
121             /* Wait until either a new packet has been added to the xmit queue,
122                or until there has been a change in the device state (i.e. disconnection).  */
123             _ux_utility_event_flags_get(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, (UX_DEVICE_CLASS_CDC_ECM_NEW_BULKIN_EVENT |
124                                                                                                UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT),
125                                                                                               UX_OR_CLEAR, &actual_flags, UX_WAIT_FOREVER);
126 
127             /* Check the completion code and the actual flags returned.  */
128             if ((actual_flags & UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT) == 0)
129             {
130 
131                 /* Get the transfer request for the bulk IN pipe.  */
132                 transfer_request =  &cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint -> ux_slave_endpoint_transfer_request;
133 
134                 /* Parse all packets.  */
135                 while (cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue != UX_NULL)
136                 {
137 
138                     /* Ensure no other threads are modifying the xmit queue.  */
139                     _ux_device_mutex_on(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
140 
141                     /* Get the current packet in the list.  */
142                     current_packet =  cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue;
143 
144                     /* Set the next packet (or a NULL value) as the head of the xmit queue. */
145                     cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue =  current_packet -> nx_packet_queue_next;
146 
147                     /* Free Mutex resource.  */
148                     _ux_device_mutex_off(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
149 
150                     /* If the link is down no need to rearm a packet. */
151                     if (cdc_ecm -> ux_slave_class_cdc_ecm_link_state == UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP)
152                     {
153 
154                         /* Can the packet fit in the transfer requests data buffer?  */
155                         if (current_packet -> nx_packet_length <= UX_SLAVE_REQUEST_DATA_MAX_LENGTH)
156                         {
157 
158                             /* Copy the packet in the transfer descriptor buffer.  */
159                             status = nx_packet_data_extract_offset(current_packet, 0,
160                                     transfer_request -> ux_slave_transfer_request_data_pointer,
161                                     current_packet -> nx_packet_length, &copied);
162                             if (status == UX_SUCCESS)
163                             {
164 
165                                 /* Calculate the transfer length.  */
166                                 transfer_length =  current_packet -> nx_packet_length;
167 
168                                 /* If trace is enabled, insert this event into the trace buffer.  */
169                                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_PACKET_TRANSMIT, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
170 
171                                 /* Send the request to the device controller.  */
172                                 status =  _ux_device_stack_transfer_request(transfer_request, transfer_length, UX_DEVICE_CLASS_CDC_ECM_ETHERNET_PACKET_SIZE + 1);
173                             }
174 
175                             /* Check error code. */
176                             if (status != UX_SUCCESS)
177                             {
178 
179                                 /* Is this not a transfer abort? (this is expected to happen)  */
180                                 if (status != UX_TRANSFER_BUS_RESET)
181                                 {
182 
183                                     /* Error trap. */
184                                     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
185                                 }
186                             }
187                         }
188                         else
189                         {
190 
191                             /* Packet is too large.  */
192 
193                             /* Report error to application.  */
194                             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_BUFFER_OVERFLOW);
195                         }
196                     }
197 
198                     /* Free the packet that was just sent.  First do some housekeeping.  */
199                     current_packet -> nx_packet_prepend_ptr =  current_packet -> nx_packet_prepend_ptr + UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
200                     current_packet -> nx_packet_length =  current_packet -> nx_packet_length - UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
201 
202                     /* And ask Netx to release it.  */
203                     nx_packet_transmit_release(current_packet);
204                 }
205             }
206             else
207             {
208 
209                 /* We need to ensure nobody is adding to the queue, so get the mutex protection. */
210                 _ux_device_mutex_on(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
211 
212                 /* Since we got the mutex, we know no one is trying to modify the queue; we also know
213                    no one can start modifying the queue since the link state is down, so we can just
214                    release the mutex.  */
215                 _ux_device_mutex_off(&cdc_ecm -> ux_slave_class_cdc_ecm_mutex);
216 
217                 /* We get here when the link is down. All packets pending must be freed.  */
218                 while (cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue != UX_NULL)
219                 {
220 
221                     /* Get the current packet in the list.  */
222                     current_packet =  cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue;
223 
224                     /* Set the next packet (or a NULL value) as the head of the xmit queue. */
225                     cdc_ecm -> ux_slave_class_cdc_ecm_xmit_queue =  current_packet -> nx_packet_queue_next;
226 
227                     /* Free the packet.  */
228                     current_packet -> nx_packet_prepend_ptr =  current_packet -> nx_packet_prepend_ptr + UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
229                     current_packet -> nx_packet_length =  current_packet -> nx_packet_length - UX_DEVICE_CLASS_CDC_ECM_ETHERNET_SIZE;
230 
231                     /* And ask Netx to release it.  */
232                     nx_packet_transmit_release(current_packet);
233                 }
234 
235                 /* Was the change in the device state caused by a disconnection?  */
236                 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
237                 {
238 
239                     /* Yes. Break out of the loop and suspend ourselves, waiting for the next configuration.  */
240                     break;
241                 }
242             }
243         }
244 
245         /* We need to suspend ourselves. We will be resumed by the device enumeration module or when a change of alternate setting happens.  */
246         _ux_device_thread_suspend(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread);
247     }
248 }
249 #endif
250