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 #if !defined(UX_HOST_STANDALONE)
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_host_class_cdc_ecm_deactivate PORTABLE C */
38 /* 6.2.0 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function is called when this instance of the cdc_ecm has been */
46 /* removed from the bus either directly or indirectly. The bulk in\out */
47 /* and interrupt pipes will be destroyed and the instance */
48 /* removed. */
49 /* */
50 /* INPUT */
51 /* */
52 /* command CDC ECM class command pointer */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* Completion Status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _ux_host_stack_class_instance_destroy Destroy the class instance */
61 /* _ux_host_stack_endpoint_transfer_abort Abort endpoint transfer */
62 /* _ux_utility_memory_free Free memory block */
63 /* _ux_host_semaphore_get Get protection semaphore */
64 /* _ux_host_semaphore_delete Delete protection semaphore */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* _ux_host_class_cdc_ecm_entry Entry of cdc_ecm class */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
75 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
76 /* used UX prefix to refer to */
77 /* TX symbols instead of using */
78 /* them directly, */
79 /* resulting in version 6.1 */
80 /* 02-02-2021 Xiuwen Cai Modified comment(s), added */
81 /* compile option for using */
82 /* packet pool from NetX, */
83 /* resulting in version 6.1.4 */
84 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
85 /* refined macros names, */
86 /* resulting in version 6.1.10 */
87 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
88 /* internal clean up, */
89 /* fixed standalone compile, */
90 /* resulting in version 6.1.11 */
91 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
92 /* deprecated ECM pool option, */
93 /* supported NX packet chain, */
94 /* resulting in version 6.2.0 */
95 /* */
96 /**************************************************************************/
_ux_host_class_cdc_ecm_deactivate(UX_HOST_CLASS_COMMAND * command)97 UINT _ux_host_class_cdc_ecm_deactivate(UX_HOST_CLASS_COMMAND *command)
98 {
99
100 UX_INTERRUPT_SAVE_AREA
101
102 UX_HOST_CLASS_CDC_ECM *cdc_ecm;
103 UX_TRANSFER *transfer_request;
104
105 /* This must be the data interface, since the control interface doesn't have
106 a class instance. */
107
108 /* Get the control instance for this class. */
109 cdc_ecm = (UX_HOST_CLASS_CDC_ECM *) command -> ux_host_class_command_instance;
110
111 /* The cdc_ecm is being shut down. */
112 cdc_ecm -> ux_host_class_cdc_ecm_state = UX_HOST_CLASS_INSTANCE_SHUTDOWN;
113
114 /* If the interrupt endpoint is defined, abort transfers so the link state
115 doesn't change. */
116 if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL)
117 {
118
119 /* Get the transfer request. */
120 transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request;
121
122 /* Abort any transfers. */
123 _ux_host_stack_transfer_request_abort(transfer_request);
124 }
125
126 /* Check if link was up to see if we should clean the transmit queue. If
127 the link is pending down, that means the CDC-ECM thread is in the process
128 of cleaning the transmit queue. */
129 if (cdc_ecm -> ux_host_class_cdc_ecm_link_state == UX_HOST_CLASS_CDC_ECM_LINK_STATE_UP)
130
131 _ux_host_class_cdc_ecm_transmit_queue_clean(cdc_ecm);
132
133 /* Get the bulk in transfer request. */
134 transfer_request = &cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_endpoint -> ux_endpoint_transfer_request;
135
136 /* Now abort all transfers. It's possible we're executing right before the transfer
137 is armed. If this is the case, then the transfer will not be aborted if we do the abort right now; instead,
138 we should wait until after the transfer is armed. We must look at the CDC-ECM thread's state. */
139
140 /* Disable interrupts while we check the link state and possibly set our state. */
141 UX_DISABLE
142
143 /* Is it in the process of checking the link state and arming the transfer? */
144 if (cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_check_and_arm_in_process == UX_TRUE)
145 {
146
147 /* Yes. We must wait for it to finish arming the transfer. */
148
149 /* Let the CDC-ECM thread know we're waiting so it can wake us up. */
150 cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish = UX_TRUE;
151
152 /* Restore interrupts. */
153 UX_RESTORE
154
155 /* Wait for the transfer to be armed, or possibly an error. The CDC-ECM thread will wake us up. */
156 _ux_host_semaphore_get_norc(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore, UX_WAIT_FOREVER);
157
158 /* We're no longer waiting. */
159 cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish = UX_FALSE;
160 }
161 else
162 {
163
164 /* Restore interrupts. */
165 UX_RESTORE
166 }
167
168 /* Now we can abort the transfer. */
169 _ux_host_stack_transfer_request_abort(transfer_request);
170
171 /* De-register this interface to the NetX USB interface broker. */
172 _ux_network_driver_deactivate((VOID *) cdc_ecm, cdc_ecm -> ux_host_class_cdc_ecm_network_handle);
173
174 /* Destroy the control instance. */
175 _ux_host_stack_class_instance_destroy(cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
176
177 /* Now wait for all threads to leave the instance before freeing the resources. */
178 _ux_host_thread_schedule_other(UX_THREAD_PRIORITY_ENUM);
179
180 /* Free the memory used by the interrupt endpoint. */
181 if (cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint != UX_NULL)
182 _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
183
184 /* Destroy the link monitoring thread. We should do this before destroying
185 the notification semaphore so that it does not run due to semaphore deletion. */
186 _ux_utility_thread_delete(&cdc_ecm -> ux_host_class_cdc_ecm_thread);
187
188 /* Free the CDC-ECM thread's stack memory. */
189 _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_thread_stack);
190
191 /* Destroy the bulk semaphores. */
192 _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_out_transfer_waiting_for_check_and_arm_to_finish_semaphore);
193 _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_bulk_in_transfer_waiting_for_check_and_arm_to_finish_semaphore);
194
195 /* Destroy the notification semaphore. */
196 _ux_host_semaphore_delete(&cdc_ecm -> ux_host_class_cdc_ecm_interrupt_notification_semaphore);
197
198 #ifdef UX_HOST_CLASS_CDC_ECM_PACKET_CHAIN_SUPPORT
199
200 /* Free packet transmission memories. */
201 if (cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer)
202 _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_receive_buffer);
203 if (cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer)
204 _ux_utility_memory_free(cdc_ecm -> ux_host_class_cdc_ecm_xmit_buffer);
205 #endif
206
207 /* Before we free the device resources, we need to inform the application
208 that the device is removed. */
209 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
210
211 /* Inform the application the device is removed. */
212 _ux_system_host -> ux_system_host_change_function(UX_DEVICE_REMOVAL, cdc_ecm -> ux_host_class_cdc_ecm_class, (VOID *) cdc_ecm);
213
214 /* If trace is enabled, insert this event into the trace buffer. */
215 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_CDC_ECM_DEACTIVATE, cdc_ecm, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
216
217 /* If trace is enabled, unregister this object. */
218 UX_TRACE_OBJECT_UNREGISTER(cdc_ecm);
219
220 /* Free the cdc_ecm control instance memory. */
221 _ux_utility_memory_free(cdc_ecm);
222
223 /* Return successful status. */
224 return(UX_SUCCESS);
225 }
226 #endif
227