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 /** Host Stack */
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_stack.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_host_stack_device_resources_free PORTABLE C */
36 /* 6.1.12 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function will free all the device resources allocated. */
44 /* */
45 /* INPUT */
46 /* */
47 /* device Device pointer */
48 /* */
49 /* OUTPUT */
50 /* */
51 /* Completion Status */
52 /* */
53 /* CALLS */
54 /* */
55 /* _ux_host_stack_endpoint_transfer_abort */
56 /* Abort transfer */
57 /* _ux_host_stack_endpoint_instance_delete */
58 /* Delete endpoint instance */
59 /* _ux_utility_memory_free Free memory block */
60 /* _ux_utility_memory_set Set memory with a value */
61 /* _ux_utility_semaphore_delete Semaphore delete */
62 /* _ux_utility_thread_schedule_other Sleep thread to let others */
63 /* run */
64 /* (ux_hcd_entry_function) HCD entry function */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* USBX Components */
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 /* optimized based on compile */
77 /* definitions, verified */
78 /* memset and memcpy cases, */
79 /* resulting in version 6.1 */
80 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
81 /* added standalone support, */
82 /* resulting in version 6.1.10 */
83 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
84 /* fixed parameter/variable */
85 /* names conflict C++ keyword, */
86 /* fixed standalone enum free, */
87 /* freed shared device config */
88 /* descriptor for enum scan, */
89 /* resulting in version 6.1.12 */
90 /* */
91 /**************************************************************************/
_ux_host_stack_device_resources_free(UX_DEVICE * device)92 UINT _ux_host_stack_device_resources_free(UX_DEVICE *device)
93 {
94
95 UX_CONFIGURATION *configuration;
96 UX_INTERFACE *interface_ptr;
97 UX_ENDPOINT *endpoint;
98 VOID *container;
99 ULONG current_alternate_setting;
100 UX_HCD *hcd;
101 #if UX_MAX_DEVICES > 1
102 UINT device_address_byte_index;
103 UINT device_address_bit_index;
104 UCHAR device_address_byte;
105 #endif
106 #if defined(UX_HOST_STANDALONE)
107 UX_DEVICE *enum_next;
108 #endif
109
110 /* If trace is enabled, insert this event into the trace buffer. */
111 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_DEVICE_RESOURCE_FREE, device, 0, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
112
113 #if defined(UX_HOST_STANDALONE)
114
115 /* Free possible allocated enumeration resources. */
116 if (device -> ux_device_flags & UX_DEVICE_FLAG_ENUM)
117 {
118
119 /* If transfer buffer is not freed, free it. */
120 if (device -> ux_device_enum_trans &&
121 device -> ux_device_enum_trans -> ux_transfer_request_data_pointer)
122 {
123 _ux_utility_memory_free(device -> ux_device_enum_trans ->
124 ux_transfer_request_data_pointer);
125 }
126
127 /* If configuration is not attached, free it. */
128 if ((device -> ux_device_enum_state == UX_HOST_STACK_ENUM_CONFIG_DESCR_PARSE) ||
129 ((device -> ux_device_enum_state == UX_HOST_STACK_ENUM_TRANS_WAIT) &&
130 (device -> ux_device_enum_next_state == UX_HOST_STACK_ENUM_CONFIG_DESCR_PARSE)))
131 {
132 if (device -> ux_device_enum_inst.configuration &&
133 device -> ux_device_enum_inst.configuration ->
134 ux_configuration_device == UX_NULL)
135 {
136 _ux_utility_memory_free(device -> ux_device_enum_inst.ptr);
137 }
138 }
139 }
140
141 /* Reset device flags. */
142 device -> ux_device_flags = 0;
143
144 #endif
145
146 /* Set the alternate setting to zero. */
147 current_alternate_setting = 0;
148
149 /* Get the first configuration registered to the device. */
150 configuration = device -> ux_device_first_configuration;
151
152 /* Parse all the configurations, remove all resources for the possible configuration. */
153 while (configuration != UX_NULL)
154 {
155
156 /* We have the correct configuration, search the interface(s). */
157 interface_ptr = configuration -> ux_configuration_first_interface;
158
159 /* Parse all the interfaces. */
160 while (interface_ptr != UX_NULL)
161 {
162
163 /* The alternate setting 0 has the selected alternate setting value. */
164 if (interface_ptr -> ux_interface_descriptor.bAlternateSetting == 0)
165 current_alternate_setting = interface_ptr -> ux_interface_current_alternate_setting;
166
167 /* If this is the selected interface, we need to free all the endpoints
168 attached to the alternate setting for this interface. */
169 endpoint = interface_ptr -> ux_interface_first_endpoint;
170
171 /* Parse all the endpoints. */
172 while (endpoint != UX_NULL)
173 {
174
175 /* Check if this is the selected interface. */
176 if (interface_ptr -> ux_interface_descriptor.bAlternateSetting == current_alternate_setting)
177 {
178
179 /* Delete the endpoint instance first. */
180 _ux_host_stack_endpoint_instance_delete(endpoint);
181 }
182
183 /* Memorize the endpoint container address. */
184 container = (VOID *) endpoint;
185
186 /* Get the next endpoint. */
187 endpoint = endpoint -> ux_endpoint_next_endpoint;
188
189 /* Delete the endpoint container. */
190 _ux_utility_memory_free(container);
191 }
192
193
194 /* Memorize the interface container address. */
195 container = (VOID *) interface_ptr;
196
197 /* Get the next interface. */
198 interface_ptr = interface_ptr -> ux_interface_next_interface;
199
200 /* Delete the interface container. */
201 _ux_utility_memory_free(container);
202 }
203
204 /* Memorize this configuration address before we free it. */
205 container = (VOID *) configuration;
206
207 /* Move to the next configuration in the list. */
208 configuration = configuration -> ux_configuration_next_configuration;
209
210 /* Free the configuration. */
211 _ux_utility_memory_free(container);
212 }
213
214 /* If there was a copy of packed descriptor, free it. */
215 if (device -> ux_device_packed_configuration)
216 {
217 _ux_utility_memory_free(device -> ux_device_packed_configuration);
218
219 /* Pointer and keep count is set NULL later while reseting instance memory. */
220 }
221
222 /* We need the HCD address for the control endpoint removal and to free
223 the device address. */
224 hcd = UX_DEVICE_HCD_GET(device);
225
226 /* Was the control endpoint already created ? */
227 if (device -> ux_device_control_endpoint.ux_endpoint_state != 0)
228 {
229
230 /* There may be pending transactions on the control endpoint. They need to be aborted. */
231 _ux_host_stack_endpoint_transfer_abort(&device -> ux_device_control_endpoint);
232
233 /* The enumeration thread needs to sleep a while to allow the application or the class that may be using
234 the control endpoint to exit properly. */
235 _ux_host_thread_schedule_other(UX_THREAD_PRIORITY_ENUM);
236
237 /* The control endpoint should be destroyed at the HCD level. */
238 hcd -> ux_hcd_entry_function(hcd, UX_HCD_DESTROY_ENDPOINT, (VOID *) &device -> ux_device_control_endpoint);
239 }
240
241 /* The semaphore attached to the control endpoint must be destroyed. */
242 _ux_host_semaphore_delete(&device -> ux_device_control_endpoint.ux_endpoint_transfer_request.ux_transfer_request_semaphore);
243
244 #if UX_MAX_DEVICES > 1
245 /* Check if the device had an assigned address. */
246 if (device -> ux_device_address != 0)
247 {
248
249 /* The USB address of this device can now be returned to the pool
250 We need the HCD pointer for this operation. */
251
252 /* Calculate in which byte index the device address belongs. */
253 device_address_byte_index = (UINT) (device -> ux_device_address-1)/8;
254
255 /* Now calculate the amount left in the byte index in bit. */
256 device_address_bit_index = (UINT) (device -> ux_device_address-1)%8;
257
258 /* Build the mask for the address. */
259 device_address_byte = (UCHAR)(1 << device_address_bit_index);
260
261 /* Free the address. */
262 hcd -> ux_hcd_address[device_address_byte_index] &= (UCHAR)~device_address_byte;
263 }
264 #endif
265
266 /* The semaphore for endpoint 0 protection must be destroyed. */
267 _ux_host_semaphore_delete(&device -> ux_device_protection_semaphore);
268
269 /* Now this device can be free and its container return to the pool. */
270 #if defined(UX_HOST_STANDALONE)
271 enum_next = device -> ux_device_enum_next;
272 _ux_utility_memory_set(device, 0, sizeof(UX_DEVICE)); /* Use case of memset is verified. */
273 device -> ux_device_enum_next = enum_next;
274 #else
275
276 _ux_utility_memory_set(device, 0, sizeof(UX_DEVICE)); /* Use case of memset is verified. */
277 #endif
278
279 /* Mark the device handle as unused. */
280 device -> ux_device_handle = UX_UNUSED;
281
282 /* Return successful completion. */
283 return(UX_SUCCESS);
284 }
285
286