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 /** */
15 /** USBX Component */
16 /** */
17 /** CDC-ECM Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_cdc_ecm.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_cdc_ecm_transmission_callback PORTABLE C */
37 /* 6.2.0 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is the callback from the USBX transfer functions, */
45 /* it is called when a full or partial transfer has been done for a */
46 /* bulk out transfer. */
47 /* */
48 /* INPUT */
49 /* */
50 /* transfer_request Pointer to transfer request */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* None */
55 /* */
56 /* CALLS */
57 /* */
58 /* _ux_host_stack_transfer_request Process transfer request */
59 /* nx_packet_transmit_release Release NetX packet */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* Application */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
70 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
71 /* resulting in version 6.1 */
72 /* 02-02-2021 Chaoqiong Xiao Modified comment(s), fixed */
73 /* ZLP issue for transmission, */
74 /* resulting in version 6.1.4 */
75 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
76 /* use pre-calculated value */
77 /* instead of wMaxPacketSize, */
78 /* resulting in version 6.1.9 */
79 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
80 /* fixed standalone compile, */
81 /* resulting in version 6.1.11 */
82 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
83 /* supported NX packet chain, */
84 /* resulting in version 6.2.0 */
85 /* */
86 /**************************************************************************/
_ux_host_class_cdc_ecm_transmission_callback(UX_TRANSFER * transfer_request)87 VOID _ux_host_class_cdc_ecm_transmission_callback(UX_TRANSFER *transfer_request)
88 {
89 #if defined(UX_HOST_STANDALONE)
90 UX_PARAMETER_NOT_USED(transfer_request);
91 #else
92
93 UX_HOST_CLASS_CDC_ECM *cdc_ecm;
94 NX_PACKET *current_packet;
95 NX_PACKET *next_packet;
96 UCHAR *packet_header;
97 #ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
98 ULONG copied;
99 #endif
100
101 /* Get the data and control class instances for this transfer request. */
102 cdc_ecm = (UX_HOST_CLASS_CDC_ECM *) transfer_request -> ux_transfer_request_class_instance;
103
104 /* Is the link not up, or the class is shutting down? */
105 if (cdc_ecm -> ux_host_class_cdc_ecm_link_state != UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP ||
106 cdc_ecm -> ux_host_class_cdc_ecm_state == UX_HOST_CLASS_INSTANCE_SHUTDOWN)
107
108 /* The CDC-ECM thread or deactivation routine is in the process of freeing
109 the queue. Just return so we are not simultaneously accessing it. */
110 return;
111
112 /* Get the packet associated with this transfer. */
113 current_packet = cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_head;
114
115 /* Do a sanity check on the packet. */
116 if (current_packet == UX_NULL)
117 {
118
119 /* Error trap. */
120 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FATAL_ERROR);
121
122 /* If trace is enabled, insert this event into the trace buffer. */
123 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_INTERFACE_HANDLE_UNKNOWN, cdc_ecm, 0, 0, UX_FATAL_ERROR, 0, 0)
124
125 /* Something went terribly wrong. Do not proceed. */
126 return;
127 }
128
129 /* Check the state of the transfer. */
130 if (transfer_request -> ux_transfer_request_completion_code == UX_SUCCESS)
131 {
132
133 /* Check if the transfer length is not zero and it is multiple of MPS (validated on device enum). */
134 if ((transfer_request -> ux_transfer_request_requested_length != 0) &&
135 (transfer_request -> ux_transfer_request_requested_length % transfer_request -> ux_transfer_request_packet_length) == 0)
136 {
137
138 /* Set transfer request length to zero. */
139 transfer_request -> ux_transfer_request_requested_length = 0;
140
141 /* Send the transfer. */
142 _ux_host_stack_transfer_request(transfer_request);
143
144 /* Finished processing. */
145 return;
146 }
147
148 /* Get the next packet associated with the first packet. */
149 next_packet = current_packet -> nx_packet_queue_next;
150
151 /* Set the next packet (or a NULL value) as the head of the xmit queue. */
152 cdc_ecm -> ux_host_class_cdc_ecm_xmit_queue_head = next_packet;
153
154 /* If there is nothing else or if the link is down no need to rearm a packet. */
155 if (next_packet != UX_NULL)
156 {
157
158 #ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
159
160 if (next_packet -> nx_packet_next != UX_NULL)
161 {
162
163 /* Put packet to continuous buffer to transfer. */
164 packet_header = cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer;
165 nx_packet_data_extract_offset(next_packet, 0, packet_header, next_packet -> nx_packet_length, &copied);
166 }
167 else
168 #endif
169 {
170
171 /* Load the address of the current packet header at the physical header. */
172 packet_header = next_packet -> nx_packet_prepend_ptr;
173 }
174
175 /* Prepare the values for this new transmission. */
176 transfer_request -> ux_transfer_request_data_pointer = packet_header;
177 transfer_request -> ux_transfer_request_requested_length = next_packet -> nx_packet_length;
178
179 /* Store the packet that owns this transaction. */
180 transfer_request -> ux_transfer_request_user_specific = next_packet;
181
182 /* If error log is enabled, insert this message into the log buffer. */
183 UX_DEBUG_LOG("_ux_host_class_cdc_ecm_transmission_callback", "Sending packet", next_packet, next_packet, _ux_system -> ux_system_mutex.tx_mutex_suspended_count)
184
185 /* If there is an error, the system will hang up. Not much we can do to
186 fix this. */
187 _ux_host_stack_transfer_request(transfer_request);
188 }
189
190 /* If error log is enabled, insert this message into the log buffer. */
191 UX_DEBUG_LOG("_ux_host_class_cdc_ecm_transmission_callback", "Freeing transmitted packet", 0, transfer_request, current_packet)
192
193 /* Free the packet that was just sent. First do some housekeeping. */
194 current_packet -> nx_packet_prepend_ptr = current_packet -> nx_packet_prepend_ptr + UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
195 current_packet -> nx_packet_length = current_packet -> nx_packet_length - UX_HOST_CLASS_CDC_ECM_ETHERNET_SIZE;
196
197 /* And ask Netx to release it. */
198 nx_packet_transmit_release(current_packet);
199 }
200 else
201 {
202
203 /* The transfer failed. Retry it. Note that this can't be a transfer
204 abort, because otherwise the link is either down or the class is in
205 shutdown, both of which are checked for at the beginning. */
206 _ux_host_stack_transfer_request(transfer_request);
207 }
208
209 /* There is no status to be reported back to the stack. */
210 return;
211 #endif
212 }
213