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_change PORTABLE C */
35 /* 6.3.0 */
36 /* AUTHOR */
37 /* */
38 /* Chaoqiong Xiao, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function changes the interface of the 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 /* _ux_network_driver_link_up Link status up */
55 /* _ux_network_driver_link_down Link status down */
56 /* _ux_utility_memory_set Set memory */
57 /* _ux_device_thread_resume Resume thread */
58 /* _ux_device_event_flags_set Set event flags */
59 /* _ux_device_stack_transfer_all_request_abort */
60 /* Abort transfer */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* USBX Source Code */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
71 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
72 /* verified memset and memcpy */
73 /* cases, used UX prefix to */
74 /* refer to TX symbols instead */
75 /* of using them directly, */
76 /* resulting in version 6.1 */
77 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
78 /* refined macros names, */
79 /* resulting in version 6.1.10 */
80 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
81 /* fixed standalone compile, */
82 /* resulting in version 6.1.11 */
83 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
84 /* fixed parameter/variable */
85 /* names conflict C++ keyword, */
86 /* resulting in version 6.1.12 */
87 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
88 /* added zero copy support, */
89 /* added a new mode to manage */
90 /* endpoint buffer in classes, */
91 /* resulting in version 6.3.0 */
92 /* */
93 /**************************************************************************/
_ux_device_class_cdc_ecm_change(UX_SLAVE_CLASS_COMMAND * command)94 UINT _ux_device_class_cdc_ecm_change(UX_SLAVE_CLASS_COMMAND *command)
95 {
96
97 UX_SLAVE_INTERFACE *interface_ptr;
98 UX_SLAVE_CLASS *class_ptr;
99 UX_SLAVE_CLASS_CDC_ECM *cdc_ecm;
100 UX_SLAVE_ENDPOINT *endpoint;
101
102 /* Get the class container. */
103 class_ptr = command -> ux_slave_class_command_class_ptr;
104
105 /* Get the class instance in the container. */
106 cdc_ecm = (UX_SLAVE_CLASS_CDC_ECM *) class_ptr -> ux_slave_class_instance;
107
108 /* Get the interface that owns this instance. */
109 interface_ptr = (UX_SLAVE_INTERFACE *) command -> ux_slave_class_command_interface;
110
111 /* Locate the endpoints. Control and Bulk in/out for Data Interface. */
112 endpoint = interface_ptr -> ux_slave_interface_first_endpoint;
113
114 /* If the interface to mount has a non zero alternate setting, the class is really active with
115 the endpoints active. If the interface reverts to alternate setting 0, it needs to have
116 the pending transactions terminated. */
117 if (interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting != 0)
118 {
119
120 /* Parse all endpoints. */
121 while (endpoint != UX_NULL)
122 {
123
124 /* Check the endpoint direction, and type. */
125 if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
126 {
127
128 /* Look at type. */
129 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
130
131 /* We have found the bulk in endpoint, save it. */
132 cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint = endpoint;
133 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
134 endpoint -> ux_slave_endpoint_transfer_request.
135 ux_slave_transfer_request_data_pointer =
136 UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER(cdc_ecm);
137 #endif
138 }
139 else
140 {
141 /* Look at type for out endpoint. */
142 if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
143
144 /* We have found the bulk out endpoint, save it. */
145 cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint = endpoint;
146 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && !defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
147 endpoint -> ux_slave_endpoint_transfer_request.
148 ux_slave_transfer_request_data_pointer =
149 UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER(cdc_ecm);
150 #endif
151 }
152
153 /* Next endpoint. */
154 endpoint = endpoint -> ux_slave_endpoint_next_endpoint;
155 }
156
157 /* Now check if all endpoints have been found. */
158 if (cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint == UX_NULL || cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint == UX_NULL)
159
160 /* Not all endpoints have been found. Major error, do not proceed. */
161 return(UX_ERROR);
162
163 /* Declare the link to be up. */
164 cdc_ecm -> ux_slave_class_cdc_ecm_link_state = UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_UP;
165
166 /* Communicate the state with the network driver. */
167 _ux_network_driver_link_up(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle);
168
169 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_CDC_ECM_ZERO_COPY)
170
171 /* There is no endpoint buffer. */
172 #else
173
174 /* Reset the endpoint buffers. */
175 _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_endpoint -> ux_slave_endpoint_transfer_request.
176 ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKOUT_BUFFER_SIZE); /* Use case of memset is verified. */
177 _ux_utility_memory_set(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint -> ux_slave_endpoint_transfer_request.
178 ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_CDC_ECM_BULKIN_BUFFER_SIZE); /* Use case of memset is verified. */
179 #endif
180
181 /* Resume the endpoint threads. */
182 _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkout_thread);
183 _ux_device_thread_resume(&cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_thread);
184
185 /* Wake up the Interrupt thread and send a network notification to the host. */
186 _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);
187
188 /* If there is an activate function call it. */
189 if (cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate != UX_NULL)
190
191 /* Invoke the application. */
192 cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_activate(cdc_ecm);
193 }
194 else
195 {
196
197 /* In this case, we are reverting to the Alternate Setting 0. */
198
199 /* Declare the link to be down. */
200 cdc_ecm -> ux_slave_class_cdc_ecm_link_state = UX_DEVICE_CLASS_CDC_ECM_LINK_STATE_DOWN;
201
202 /* Communicate the state with the network driver. */
203 _ux_network_driver_link_down(cdc_ecm -> ux_slave_class_cdc_ecm_network_handle);
204
205 /* Terminate the transactions pending on the bulk in endpoint. If there is a transfer on the
206 bulk out endpoint, we simply let it finish and let NetX throw it away. */
207 _ux_device_stack_transfer_all_request_abort(cdc_ecm -> ux_slave_class_cdc_ecm_bulkin_endpoint, UX_TRANSFER_APPLICATION_RESET);
208
209 /* Notify the thread waiting for network notification events. In this case,
210 the event is that the link state has been switched to down. */
211 _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);
212
213 /* Wake up the bulk in thread so that it can clean up the xmit queue. */
214 _ux_device_event_flags_set(&cdc_ecm -> ux_slave_class_cdc_ecm_event_flags_group, UX_DEVICE_CLASS_CDC_ECM_NEW_DEVICE_STATE_CHANGE_EVENT, UX_OR);
215
216 /* If there is a deactivate function call it. */
217 if (cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate != UX_NULL)
218
219 /* Invoke the application. */
220 cdc_ecm -> ux_slave_class_cdc_ecm_parameter.ux_slave_class_cdc_ecm_instance_deactivate(cdc_ecm);
221 }
222
223 /* Set the CDC ECM alternate setting to the new one. */
224 cdc_ecm -> ux_slave_class_cdc_ecm_current_alternate_setting = interface_ptr -> ux_slave_interface_descriptor.bAlternateSetting;
225
226 /* If trace is enabled, insert this event into the trace buffer. */
227 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_CDC_ECM_CHANGE, cdc_ecm, 0, 0, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
228
229 /* If trace is enabled, register this object. */
230 UX_TRACE_OBJECT_REGISTER(UX_TRACE_DEVICE_OBJECT_TYPE_INTERFACE, cdc_ecm, 0, 0, 0)
231
232 /* Return completion status. */
233 return(UX_SUCCESS);
234 }
235
236