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 /** */
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.1.9 */
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 /* 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 /* 10-15-2021 Chaoqiong Xiao Modified comment(s), */
73 /* use pre-calculated value */
74 /* instead of wMaxPacketSize, */
75 /* resulting in version 6.1.9 */
76 /* */
77 /**************************************************************************/
_ux_host_class_cdc_ecm_endpoints_get(UX_HOST_CLASS_CDC_ECM * cdc_ecm)78 UINT _ux_host_class_cdc_ecm_endpoints_get(UX_HOST_CLASS_CDC_ECM *cdc_ecm)
79 {
80
81 UINT status;
82 UINT endpoint_index;
83 UX_ENDPOINT *endpoint;
84 UX_TRANSFER *transfer_request;
85 UX_INTERFACE *data_interface;
86
87
88 /* Get the endpoints from the data interface. */
89
90 /* Default data interface. */
91 data_interface = cdc_ecm -> ux_host_class_cdc_ecm_interface_data;
92
93 /* Some versions of cdc-ecm contain a default interface for data with 0 endpoints. Check if this the case and if so,
94 look for the next interface that has the 2 bulk endpoints. */
95
96 if (data_interface -> ux_interface_descriptor.bNumEndpoints == 0)
97 {
98
99 /* We are in the case where the interface has the default set to 0 endpoints. */
100 data_interface = data_interface -> ux_interface_next_interface;
101
102 /* Check if invalid. */
103 if (data_interface == UX_NULL ||
104 data_interface -> ux_interface_descriptor.bInterfaceClass != UX_HOST_CLASS_CDC_DATA_CLASS ||
105 data_interface -> ux_interface_descriptor.bAlternateSetting != 1)
106 {
107
108 /* Error trap. */
109 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
110
111 /* If trace is enabled, insert this event into the trace buffer. */
112 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)
113
114 /* Descriptor is corrupted. */
115 return(UX_DESCRIPTOR_CORRUPTED);
116 }
117
118 /* We have found the right alternate setting. Now we need to select it. */
119 status = _ux_host_stack_interface_setting_select(data_interface);
120
121 /* Check status. We don't continue if there is a problem with the selection. */
122 if (status != UX_SUCCESS)
123
124 /* Something went wrong. */
125 return(status);
126 }
127
128 /* Search the bulk OUT endpoint. It is attached to the interface container. */
129 for (endpoint_index = 0; endpoint_index < data_interface -> ux_interface_descriptor.bNumEndpoints;
130 endpoint_index++)
131 {
132
133 /* Get interface endpoint. */
134 _ux_host_stack_interface_endpoint_get(data_interface, endpoint_index, &endpoint);
135
136 /* Check if endpoint is bulk and OUT. */
137 if (((endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_OUT) &&
138 ((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT))
139 {
140
141 /* This transfer_request always have the OUT direction. */
142 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_type = UX_REQUEST_OUT;
143
144 /* There is a callback function associated with the transfer request, so we need the class instance. */
145 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_class_instance = (VOID *) cdc_ecm;
146
147 /* The transfer request has a callback function. */
148 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_function = _ux_host_class_cdc_ecm_transmission_callback;
149
150 /* We have found the bulk endpoint, save it. */
151 cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_endpoint = endpoint;
152
153 break;
154 }
155 }
156
157 /* The bulk out endpoint is mandatory. */
158 if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_endpoint == UX_NULL)
159 {
160
161 /* Error trap. */
162 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN);
163
164 /* If trace is enabled, insert this event into the trace buffer. */
165 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_ENDPOINT_HANDLE_UNKNOWN, cdc_ecm, 0, 0, UX_TRACE_ERRORS, 0, 0)
166
167 return(UX_ENDPOINT_HANDLE_UNKNOWN);
168 }
169
170 /* Search the bulk IN endpoint. It is attached to the interface container. */
171 for (endpoint_index = 0; endpoint_index < data_interface -> ux_interface_descriptor.bNumEndpoints;
172 endpoint_index++)
173 {
174
175 /* Get the endpoint handle. */
176 _ux_host_stack_interface_endpoint_get(data_interface, endpoint_index, &endpoint);
177
178 /* Check if endpoint is bulk and IN. */
179 if (((endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN) &&
180 ((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT))
181 {
182
183 /* This transfer_request always have the IN direction. */
184 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_type = UX_REQUEST_IN;
185
186 /* Set the class instance in the transfer request. */
187 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_class_instance = (VOID *) cdc_ecm;
188
189 /* The transfer request has NO callback function. */
190 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_completion_function = UX_NULL;
191
192 /* We have found the bulk endpoint, save it. */
193 cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint = endpoint;
194
195 break;
196 }
197 }
198
199 /* The bulk in endpoint is mandatory. */
200 if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint == UX_NULL)
201 {
202
203 /* Error trap. */
204 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN);
205
206 /* If trace is enabled, insert this event into the trace buffer. */
207 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_ENDPOINT_HANDLE_UNKNOWN, cdc_ecm, 0, 0, UX_TRACE_ERRORS, 0, 0)
208
209 return(UX_ENDPOINT_HANDLE_UNKNOWN);
210 }
211
212 /* Now get the endpoints from the control interface. */
213
214 /* Search the Interrupt endpoint. It is NOT mandatory. */
215 for (endpoint_index = 0; endpoint_index < cdc_ecm -> ux_host_class_cdc_ecm_interface_control -> ux_interface_descriptor.bNumEndpoints;
216 endpoint_index++)
217 {
218
219 /* Get the endpoint handle. */
220 _ux_host_stack_interface_endpoint_get(cdc_ecm -> ux_host_class_cdc_ecm_interface_control, endpoint_index, &endpoint);
221
222 /* Check if endpoint is Interrupt and IN. */
223 if (((endpoint -> ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN) &&
224 ((endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT))
225 {
226
227 /* This transfer_request always have the IN direction. */
228 endpoint -> ux_endpoint_transfer_request.ux_transfer_request_type = UX_REQUEST_IN;
229
230 /* We have found the interrupt endpoint, save it. */
231 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 transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request;
235 transfer_request -> ux_transfer_request_requested_length = transfer_request -> ux_transfer_request_packet_length;
236 transfer_request -> ux_transfer_request_actual_length = 0;
237
238 /* The direction is always IN for the CDC interrupt endpoint. */
239 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 transfer_request -> ux_transfer_request_class_instance = (VOID *) cdc_ecm;
243
244 /* Interrupt transactions have a completion routine. */
245 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 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 if (transfer_request -> ux_transfer_request_data_pointer == UX_NULL)
253 {
254
255 /* Error trap. */
256 _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 return(UX_ENDPOINT_HANDLE_UNKNOWN);
263 }
264
265 break;
266 }
267 }
268
269 /* All endpoints have been mounted. */
270 return(UX_SUCCESS);
271 }
272
273