1 |
|
|
/*************************************************************************** |
2 |
|
|
* Copyright (c) 2024 Microsoft Corporation |
3 |
|
|
* Copyright (c) 2026-present Eclipse ThreadX contributors |
4 |
|
|
* |
5 |
|
|
* This program and the accompanying materials are made available under the |
6 |
|
|
* terms of the MIT License which is available at |
7 |
|
|
* https://opensource.org/licenses/MIT. |
8 |
|
|
* |
9 |
|
|
* SPDX-License-Identifier: MIT |
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 |
|
|
/**************************************************************************/ |
34 |
|
|
/* */ |
35 |
|
|
/* FUNCTION RELEASE */ |
36 |
|
|
/* */ |
37 |
|
|
/* _ux_host_class_cdc_ecm_endpoints_get PORTABLE C */ |
38 |
|
|
/* 6.3.0 */ |
39 |
|
|
/* AUTHOR */ |
40 |
|
|
/* */ |
41 |
|
|
/* Chaoqiong Xiao, Microsoft Corporation */ |
42 |
|
|
/* */ |
43 |
|
|
/* DESCRIPTION */ |
44 |
|
|
/* */ |
45 |
|
|
/* This function distinguishes for either the Data or Control Class. */ |
46 |
|
|
/* For the data class, we mount the bulk in and bulk out endpoints. */ |
47 |
|
|
/* For the control class, we mount the optional interrupt endpoint. */ |
48 |
|
|
/* */ |
49 |
|
|
/* INPUT */ |
50 |
|
|
/* */ |
51 |
|
|
/* cdc_ecm Pointer to cdc_ecm class */ |
52 |
|
|
/* */ |
53 |
|
|
/* OUTPUT */ |
54 |
|
|
/* */ |
55 |
|
|
/* Completion Status */ |
56 |
|
|
/* */ |
57 |
|
|
/* CALLS */ |
58 |
|
|
/* */ |
59 |
|
|
/* _ux_host_stack_interface_endpoint_get Get interface endpoint */ |
60 |
|
|
/* */ |
61 |
|
|
/* CALLED BY */ |
62 |
|
|
/* */ |
63 |
|
|
/* _ux_host_class_cdc_ecm_activate Activate cdc_ecm class */ |
64 |
|
|
/* */ |
65 |
|
|
/**************************************************************************/ |
66 |
|
121 |
UINT _ux_host_class_cdc_ecm_endpoints_get(UX_HOST_CLASS_CDC_ECM *cdc_ecm) |
67 |
|
|
{ |
68 |
|
|
|
69 |
|
|
UINT status; |
70 |
|
|
UINT endpoint_index; |
71 |
|
|
UX_ENDPOINT *endpoint; |
72 |
|
|
UX_TRANSFER *transfer_request; |
73 |
|
|
UX_INTERFACE *data_interface; |
74 |
|
|
|
75 |
|
|
|
76 |
|
|
/* Get the endpoints from the data interface. */ |
77 |
|
|
|
78 |
|
|
/* Default data interface. */ |
79 |
|
121 |
data_interface = cdc_ecm -> ux_host_class_cdc_ecm_interface_data; |
80 |
|
|
|
81 |
|
|
/* Some versions of cdc-ecm contain a default interface for data with 0 endpoints. Check if this the case and if so, |
82 |
|
|
look for the next interface that has the 2 bulk endpoints. */ |
83 |
|
|
|
84 |
✓✓ |
121 |
if (data_interface -> ux_interface_descriptor.bNumEndpoints == 0) |
85 |
|
|
{ |
86 |
|
|
|
87 |
|
|
/* We are in the case where the interface has the default set to 0 endpoints. */ |
88 |
|
114 |
data_interface = data_interface -> ux_interface_next_interface; |
89 |
|
|
|
90 |
|
|
/* Check if invalid. */ |
91 |
✓✓ |
114 |
if (data_interface == UX_NULL || |
92 |
✓✓ |
111 |
data_interface -> ux_interface_descriptor.bInterfaceClass != UX_HOST_CLASS_CDC_DATA_CLASS || |
93 |
✓✓ |
108 |
data_interface -> ux_interface_descriptor.bAlternateSetting != 1) |
94 |
|
|
{ |
95 |
|
|
|
96 |
|
|
/* Error trap. */ |
97 |
|
9 |
_ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED); |
98 |
|
|
|
99 |
|
|
/* If trace is enabled, insert this event into the trace buffer. */ |
100 |
|
|
UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, cdc_ecm -> ux_host_class_cdc_ecm_interface_data, 0, 0, UX_TRACE_ERRORS, 0, 0) |
101 |
|
|
|
102 |
|
|
/* Descriptor is corrupted. */ |
103 |
|
9 |
return(UX_DESCRIPTOR_CORRUPTED); |
104 |
|
|
} |
105 |
|
|
|
106 |
|
|
/* We have found the right alternate setting. Now we need to select it. */ |
107 |
|
105 |
status = _ux_host_stack_interface_setting_select(data_interface); |
108 |
|
|
|
109 |
|
|
/* Check status. We don't continue if there is a problem with the selection. */ |
110 |
✓✓ |
105 |
if (status != UX_SUCCESS) |
111 |
|
|
|
112 |
|
|
/* Something went wrong. */ |
113 |
|
13 |
return(status); |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
/* Search the bulk OUT endpoint. It is attached to the interface container. */ |
117 |
✓✓ |
112 |
for (endpoint_index = 0; endpoint_index < data_interface -> ux_interface_descriptor.bNumEndpoints; |
118 |
|
13 |
endpoint_index++) |
119 |
|
|
{ |
120 |
|
|
|
121 |
|
|
/* Get interface endpoint. */ |
122 |
|
107 |
status = _ux_host_stack_interface_endpoint_get(data_interface, endpoint_index, &endpoint); |
123 |
|
|
|
124 |
|
|
/* Check status. */ |
125 |
✗✓ |
107 |
if (status != UX_SUCCESS) |
126 |
|
|
continue; |
127 |
|
|
|
128 |
|
|
/* Check if endpoint is bulk and OUT. */ |
129 |
✓✓ |
107 |
if (((endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_OUT) && |
130 |
✓✓ |
97 |
((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)) |
131 |
|
|
{ |
132 |
|
|
|
133 |
|
|
/* This transfer_request always have the OUT direction. */ |
134 |
|
94 |
endpoint -> ux_endpoint_transfer_request.ux_transfer_request_type = UX_REQUEST_OUT; |
135 |
|
|
|
136 |
|
|
/* There is a callback function associated with the transfer request, so we need the class instance. */ |
137 |
|
94 |
endpoint -> ux_endpoint_transfer_request.ux_transfer_request_class_instance = (VOID *) cdc_ecm; |
138 |
|
|
|
139 |
|
|
/* The transfer request has a callback function. */ |
140 |
|
94 |
endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_function = _ux_host_class_cdc_ecm_transmission_callback; |
141 |
|
|
|
142 |
|
|
/* We have found the bulk endpoint, save it. */ |
143 |
|
94 |
cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_endpoint = endpoint; |
144 |
|
|
|
145 |
|
94 |
break; |
146 |
|
|
} |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
/* The bulk out endpoint is mandatory. */ |
150 |
✓✓ |
99 |
if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_endpoint == UX_NULL) |
151 |
|
|
{ |
152 |
|
|
|
153 |
|
|
/* Error trap. */ |
154 |
|
5 |
_ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN); |
155 |
|
|
|
156 |
|
|
/* If trace is enabled, insert this event into the trace buffer. */ |
157 |
|
|
UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_ENDPOINT_HANDLE_UNKNOWN, cdc_ecm, 0, 0, UX_TRACE_ERRORS, 0, 0) |
158 |
|
|
|
159 |
|
5 |
return(UX_ENDPOINT_HANDLE_UNKNOWN); |
160 |
|
|
} |
161 |
|
|
|
162 |
|
|
/* Search the bulk IN endpoint. It is attached to the interface container. */ |
163 |
✓✓ |
194 |
for (endpoint_index = 0; endpoint_index < data_interface -> ux_interface_descriptor.bNumEndpoints; |
164 |
|
100 |
endpoint_index++) |
165 |
|
|
{ |
166 |
|
|
|
167 |
|
|
/* Get the endpoint handle. */ |
168 |
|
189 |
status = _ux_host_stack_interface_endpoint_get(data_interface, endpoint_index, &endpoint); |
169 |
|
|
|
170 |
|
|
/* Check status. */ |
171 |
✗✓ |
189 |
if (status != UX_SUCCESS) |
172 |
|
|
continue; |
173 |
|
|
|
174 |
|
|
/* Check if endpoint is bulk and IN. */ |
175 |
✓✓ |
189 |
if (((endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN) && |
176 |
✓✓ |
92 |
((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)) |
177 |
|
|
{ |
178 |
|
|
|
179 |
|
|
/* This transfer_request always have the IN direction. */ |
180 |
|
89 |
endpoint -> ux_endpoint_transfer_request.ux_transfer_request_type = UX_REQUEST_IN; |
181 |
|
|
|
182 |
|
|
/* Set the class instance in the transfer request. */ |
183 |
|
89 |
endpoint -> ux_endpoint_transfer_request.ux_transfer_request_class_instance = (VOID *) cdc_ecm; |
184 |
|
|
|
185 |
|
|
/* The transfer request has NO callback function. */ |
186 |
|
89 |
endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_function = UX_NULL; |
187 |
|
|
|
188 |
|
|
/* We have found the bulk endpoint, save it. */ |
189 |
|
89 |
cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint = endpoint; |
190 |
|
|
|
191 |
|
89 |
break; |
192 |
|
|
} |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
/* The bulk in endpoint is mandatory. */ |
196 |
✓✓ |
94 |
if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint == UX_NULL) |
197 |
|
|
{ |
198 |
|
|
|
199 |
|
|
/* Error trap. */ |
200 |
|
5 |
_ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN); |
201 |
|
|
|
202 |
|
|
/* If trace is enabled, insert this event into the trace buffer. */ |
203 |
|
|
UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_ENDPOINT_HANDLE_UNKNOWN, cdc_ecm, 0, 0, UX_TRACE_ERRORS, 0, 0) |
204 |
|
|
|
205 |
|
5 |
return(UX_ENDPOINT_HANDLE_UNKNOWN); |
206 |
|
|
} |
207 |
|
|
|
208 |
|
|
/* Now get the endpoints from the control interface. */ |
209 |
|
|
|
210 |
|
|
/* Search the Interrupt endpoint. It is NOT mandatory. */ |
211 |
✓✓ |
93 |
for (endpoint_index = 0; endpoint_index < cdc_ecm -> ux_host_class_cdc_ecm_interface_control -> ux_interface_descriptor.bNumEndpoints; |
212 |
|
4 |
endpoint_index++) |
213 |
|
|
{ |
214 |
|
|
|
215 |
|
|
/* Get the endpoint handle. */ |
216 |
|
90 |
status = _ux_host_stack_interface_endpoint_get(cdc_ecm -> ux_host_class_cdc_ecm_interface_control, endpoint_index, &endpoint); |
217 |
|
|
|
218 |
|
|
/* Check status. */ |
219 |
✗✓ |
90 |
if (status != UX_SUCCESS) |
220 |
|
|
continue; |
221 |
|
|
|
222 |
|
|
/* Check if endpoint is Interrupt and IN. */ |
223 |
✓✓ |
90 |
if (((endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN) && |
224 |
✓✓ |
88 |
((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT)) |
225 |
|
|
{ |
226 |
|
|
|
227 |
|
|
/* This transfer_request always have the IN direction. */ |
228 |
|
86 |
endpoint -> ux_endpoint_transfer_request.ux_transfer_request_type = UX_REQUEST_IN; |
229 |
|
|
|
230 |
|
|
/* We have found the interrupt endpoint, save it. */ |
231 |
|
86 |
cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint = endpoint; |
232 |
|
|
|
233 |
|
|
/* The endpoint is correct, Fill in the transfer request with the length requested for this endpoint. */ |
234 |
|
86 |
transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request; |
235 |
|
86 |
transfer_request -> ux_transfer_request_requested_length = transfer_request -> ux_transfer_request_packet_length; |
236 |
|
86 |
transfer_request -> ux_transfer_request_actual_length = 0; |
237 |
|
|
|
238 |
|
|
/* The direction is always IN for the CDC interrupt endpoint. */ |
239 |
|
86 |
transfer_request -> ux_transfer_request_type = UX_REQUEST_IN; |
240 |
|
|
|
241 |
|
|
/* There is a callback function associated with the transfer request, so we need the class instance. */ |
242 |
|
86 |
transfer_request -> ux_transfer_request_class_instance = (VOID *) cdc_ecm; |
243 |
|
|
|
244 |
|
|
/* Interrupt transactions have a completion routine. */ |
245 |
|
86 |
transfer_request -> ux_transfer_request_completion_function = _ux_host_class_cdc_ecm_interrupt_notification; |
246 |
|
|
|
247 |
|
|
/* Obtain a buffer for this transaction. The buffer will always be reused. */ |
248 |
|
86 |
transfer_request -> ux_transfer_request_data_pointer = _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, |
249 |
|
|
transfer_request -> ux_transfer_request_requested_length); |
250 |
|
|
|
251 |
|
|
/* If the endpoint is available and we have memory, we start the interrupt endpoint. */ |
252 |
✓✓ |
86 |
if (transfer_request -> ux_transfer_request_data_pointer == UX_NULL) |
253 |
|
|
{ |
254 |
|
|
|
255 |
|
|
/* Error trap. */ |
256 |
|
1 |
_ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN); |
257 |
|
|
|
258 |
|
|
/* If trace is enabled, insert this event into the trace buffer. */ |
259 |
|
|
UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_ENDPOINT_HANDLE_UNKNOWN, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0) |
260 |
|
|
|
261 |
|
|
/* We must return an error. */ |
262 |
|
1 |
return(UX_ENDPOINT_HANDLE_UNKNOWN); |
263 |
|
|
} |
264 |
|
|
|
265 |
|
85 |
break; |
266 |
|
|
} |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
/* All endpoints have been mounted. */ |
270 |
|
88 |
return(UX_SUCCESS); |
271 |
|
|
} |
272 |
|
|
|