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