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