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 /** USBX Component */
14 /** */
15 /** Device CDC_ECM Class */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19
20 #define UX_SOURCE_CODE
21
22
23 /* Include necessary system files. */
24
25 #include "ux_api.h"
26 #include "ux_device_class_cdc_ecm.h"
27 #include "ux_device_stack.h"
28
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _ux_device_class_cdc_ecm_activate PORTABLE C */
35 /* 6.3.0 */
36 /* AUTHOR */
37 /* */
38 /* Chaoqiong Xiao, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function activates the USB CDC_ECM device. */
43 /* */
44 /* INPUT */
45 /* */
46 /* command Pointer to cdc_ecm command */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* Completion Status */
51 /* */
52 /* CALLS */
53 /* */
54 /* None */
55 /* */
56 /* CALLED BY */
57 /* */
58 /* USBX Source Code */
59 /* */
60 /* RELEASE HISTORY */
61 /* */
62 /* DATE NAME DESCRIPTION */
63 /* */
64 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
65 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
66 /* verified memset and memcpy */
67 /* cases, used UX prefix to */
68 /* refer to TX symbols instead */
69 /* of using them directly, */
70 /* resulting in version 6.1 */
71 /* 08-02-2021 Wen Wang Modified comment(s), */
72 /* fixed spelling error, */
73 /* resulting in version 6.1.8 */
74 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
75 /* refined macros names, */
76 /* resulting in version 6.1.10 */
77 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
78 /* fixed standalone compile, */
79 /* resulting in version 6.1.11 */
80 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
81 /* fixed parameter/variable */
82 /* names conflict C++ keyword, */
83 /* resulting in version 6.1.12 */
84 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
85 /* added zero copy support, */
86 /* added a new mode to manage */
87 /* endpoint buffer in classes, */
88 /* resulting in version 6.3.0 */
89 /* */
90 /**************************************************************************/
_ux_device_class_cdc_ecm_activate(UX_SLAVE_CLASS_COMMAND * command)91 UINT _ux_device_class_cdc_ecm_activate(UX_SLAVE_CLASS_COMMAND *command)
92 {
93 #if defined(UX_DEVICE_STANDALONE)
94 UX_PARAMETER_NOT_USED(command);
95 return(UX_FUNCTION_NOT_SUPPORTED);
96 #else
97
98 UX_SLAVE_INTERFACE *interface_ptr;
99 UX_SLAVE_CLASS *class_ptr;
100 UX_SLAVE_CLASS_CDC_ECM *cdc_ecm;
101 UX_SLAVE_ENDPOINT *endpoint;
102 ULONG physical_address_msw;
103 ULONG physical_address_lsw;
104
105 /* Get the class container. */
106 class_ptr = command -> ux_slave_class_command_class_ptr;
107
108 /* Get the class instance in the container. */
109 cdc_ecm = (UX_SLAVE_CLASS_CDC_ECM *) class_ptr -> ux_slave_class_instance;
110
111 /* Get the interface that owns this instance. */
112 interface_ptr = (UX_SLAVE_INTERFACE *) command -> ux_slave_class_command_interface;
113
114 /* Check if this is the Control or Data interface. */
115 if (command -> ux_slave_class_command_class == UX_DEVICE_CLASS_CDC_ECM_CLASS_COMMUNICATION_CONTROL)
116 {
117
118 /* Store the class instance into the interface. */
119 interface_ptr -> ux_slave_interface_class_instance = (VOID *)cdc_ecm;
120
121 /* Now the opposite, store the interface in the class instance. */
122 cdc_ecm -> ux_slave_class_cdc_ecm_interface = interface_ptr;
123
124 /* Locate the interrupt endpoint. */
125 endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
126
127 /* Parse all endpoints. */
128 while (endpoint != UX_NULL)
129 {
130
131 /* Check the endpoint direction, and type. */
132 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
133 {
134
135 /* Look at type. */
136 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_INTERRUPT_ENDPOINT)
137 {
138
139 /* We have found the interrupt endpoint, save it. */
140 cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_endpoint = endpoint;
141 #if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
142
143 /* Set the endpoint buffer to the endpoint. */
144 endpoint -> ux_slave_endpoint_transfer_request.
145 ux_slave_transfer_request_data_pointer =
146 UX_DEVICE_CLASS_CDC_ECM_INTERRUPTIN_BUFFER(cdc_ecm);
147 #endif
148
149 /* Reset the endpoint buffers. */
150 _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_endpoint -> ux_slave_endpoint_transfer_request.
151 ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_INTERRUPTIN_BUFFER_SIZE); /* Use case of memset is verified. */
152
153 /* Resume the interrupt endpoint threads. */
154 _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_interrupt_thread);
155
156 }
157
158 }
159
160 /* Next endpoint. */
161 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
162 }
163
164 }
165 else
166
167 /* This is the DATA Class, only store the cdc_ecm instance in the interface. */
168 interface_ptr -> ux_slave_interface_class_instance = (VOID *)cdc_ecm;
169
170 /* Reset the CDC ECM alternate setting to 0. */
171 cdc_ecm -> ux_slave_class_cdc_ecm_current_alternate_setting = 0;
172
173 /* Check if this is the Control or Data interface. */
174 if (command -> ux_slave_class_command_class == UX_DEVICE_CLASS_CDC_ECM_CLASS_COMMUNICATION_DATA)
175 {
176
177 /* Reset endpoint instance pointers. */
178 cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint = UX_NULL;
179 cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint = UX_NULL;
180
181 /* Does the data class have bulk endpoint declared ? If yes we need to start link.
182 If not, the host will change the alternate setting at a later stage. */
183 if (interface_ptr -> ux_slave_interface_descriptor.bNumEndpoints != 0)
184 {
185
186 /* Locate the endpoints. Control and Bulk in/out for Data Interface. */
187 endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
188
189 /* Parse all endpoints. */
190 while (endpoint != UX_NULL)
191 {
192
193 /* Check the endpoint direction, and type. */
194 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
195 {
196
197 /* Look at type. */
198 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
199 {
200
201 /* We have found the bulk in endpoint, save it. */
202 cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint = endpoint;
203 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
204 endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
205 UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER(cdc_ecm);
206 #endif
207 }
208
209 }
210 else
211 {
212 /* Look at type for out endpoint. */
213 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
214 {
215
216 /* We have found the bulk out endpoint, save it. */
217 cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint = endpoint;
218 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
219 endpoint -> ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer =
220 UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER(cdc_ecm);
221 #endif
222 }
223 }
224
225 /* Next endpoint. */
226 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
227 }
228
229
230 /* Now check if all endpoints have been found. */
231 if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint == UX_NULL || cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint == UX_NULL)
232
233 /* Not all endpoints have been found. Major error, do not proceed. */
234 return(UX_ERROR);
235
236 /* Declare the link to be up. That may need to change later to make it dependent on the
237 WAN/Wireless modem. */
238 cdc_ecm -> ux_slave_class_cdc_ecm_link_state = UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP;
239
240 /* Wake up the Interrupt thread and send a network notification to the host. */
241 _ux_device_event_flags_set(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NETWORK_NOTIFICATION_EVENT, UX_OR);
242
243 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
244
245 /* There is no endpoint buffer. */
246 #else
247
248 /* Reset the endpoint buffers. */
249 _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint -> ux_slave_endpoint_transfer_request.
250 ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER_SIZE); /* Use case of memset is verified. */
251 _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint -> ux_slave_endpoint_transfer_request.
252 ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER_SIZE); /* Use case of memset is verified. */
253 #endif
254
255 /* Resume the endpoint threads. */
256 _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread);
257 _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread);
258
259 }
260
261 /* Setup the physical address of this IP instance. */
262 physical_address_msw = (ULONG)((cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[0] << 8) | (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[1]));
263 physical_address_lsw = (ULONG)((cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[2] << 24) | (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[3] << 16) |
264 (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[4] << 8) | (cdc_ecm -> ux_slave_class_cdc_ecm_local_node_id[5]));
265
266 /* Register this interface to the NetX USB interface broker. */
267 _ux_network_driver_activate((VOID *) cdc_ecm, _ux_device_class_cdc_ecm_write,
268 &cdc_ecm -> ux_slave_class_cdc_ecm_network_handle,
269 physical_address_msw,
270 physical_address_lsw);
271
272 /* Check Link. */
273 if (cdc_ecm -> ux_slave_class_cdc_ecm_link_state == UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP)
274 {
275
276 /* Communicate the state with the network driver. */
277 _ux_network_driver_link_up(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle);
278
279 /* If there is an activate function call it. */
280 if (cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate != UX_NULL)
281
282 /* Invoke the application. */
283 cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate(cdc_ecm);
284 }
285 }
286
287 /* If trace is enabled, insert this event into the trace buffer. */
288 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_ACTIVATE, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
289
290 /* If trace is enabled, register this object. */
291 UX_TRACE_OBJECT_REGISTER(UX_TRACE_DEVICE_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0)
292
293 /* Return completion status. */
294 return(UX_SUCCESS);
295 #endif
296 }
297