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_remove                        PORTABLE C      */
36 /*                                                           6.1.12       */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function will remove a USB device from the bus.                */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    HCD                                   Pointer to the HCD            */
48 /*    parent                                The parent device address     */
49 /*    port_index                            Index of the port on which the*/
50 /*                                            change of status occurred   */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    Completion Status                                                   */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _ux_host_stack_device_resources_free  Free all device resources     */
59 /*                                                                        */
60 /*  CALLED BY                                                             */
61 /*                                                                        */
62 /*    USBX Components                                                     */
63 /*                                                                        */
64 /*  RELEASE HISTORY                                                       */
65 /*                                                                        */
66 /*    DATE              NAME                      DESCRIPTION             */
67 /*                                                                        */
68 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
69 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
70 /*                                            optimized based on compile  */
71 /*                                            definitions,                */
72 /*                                            resulting in version 6.1    */
73 /*  02-02-2021     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            used pointer for current    */
75 /*                                            selected configuration,     */
76 /*                                            added notification for      */
77 /*                                            device disconnection,       */
78 /*                                            resulting in version 6.1.4  */
79 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            added standalone support,   */
81 /*                                            resulting in version 6.1.10 */
82 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
83 /*                                            fixed parameter/variable    */
84 /*                                            names conflict C++ keyword, */
85 /*                                            resulting in version 6.1.12 */
86 /*                                                                        */
87 /**************************************************************************/
_ux_host_stack_device_remove(UX_HCD * hcd,UX_DEVICE * parent,UINT port_index)88 UINT  _ux_host_stack_device_remove(UX_HCD *hcd, UX_DEVICE *parent, UINT port_index)
89 {
90 
91 #if UX_MAX_DEVICES > 1
92 ULONG                       container_index;
93 #endif
94 UX_DEVICE                   *device;
95 UX_CONFIGURATION            *configuration;
96 UX_INTERFACE                *interface_ptr;
97 UX_HOST_CLASS_COMMAND       command;
98 
99     /* We need to find the device descriptor for the removed device. We can find it
100        with the parent device and the port it was attached to. Start with the first device.  */
101     device =  _ux_system_host -> ux_system_host_device_array;
102 
103 #if UX_MAX_DEVICES > 1
104     /* Start at the beginning of the list.  */
105     container_index =  0;
106 
107     /* Search the list until the end.  */
108     while (container_index++ < _ux_system_host -> ux_system_host_max_devices)
109     {
110 
111         /* Until we have found a used entry.  */
112         if (device -> ux_device_handle != UX_UNUSED)
113         {
114 
115             /* Check for the parent device and the port location and the controller.  */
116             if( UX_DEVICE_PARENT_MATCH(device, parent) &&
117                 UX_DEVICE_PORT_LOCATION_MATCH(device, port_index) &&
118                 UX_DEVICE_HCD_MATCH(device, hcd))
119                 break;
120         }
121 
122         /* Move to the next device entry.  */
123         device++;
124     }
125 
126     /* Device not found.  */
127     if (container_index > _ux_system_host -> ux_system_host_max_devices)
128 #else
129     UX_PARAMETER_NOT_USED(parent);
130     UX_PARAMETER_NOT_USED(port_index);
131 
132     /* Device is available and HCD is expected.  */
133     if (device -> ux_device_handle == UX_UNUSED ||
134         !UX_DEVICE_HCD_MATCH(device, hcd))
135 #endif
136     {
137 
138         /* Error trap. */
139         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DEVICE_HANDLE_UNKNOWN);
140 
141         /* If trace is enabled, insert this event into the trace buffer.  */
142         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DEVICE_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
143 
144         /* We get here when we could not find the device.  */
145         return(UX_DEVICE_HANDLE_UNKNOWN);
146     }
147 
148     /* If trace is enabled, insert this event into the trace buffer.  */
149     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_DEVICE_REMOVE, hcd, parent, port_index, device, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
150 
151     /* If trace is enabled, unregister this object.  */
152     UX_TRACE_OBJECT_UNREGISTER(device);
153 
154     /* We have found the device to be removed. */
155     device -> ux_device_state = UX_DEVICE_REMOVED;
156 
157     /* We have found the device to be removed. Initialize the class
158         command with the generic parameters.  */
159     command.ux_host_class_command_request =  UX_HOST_CLASS_COMMAND_DEACTIVATE;
160 
161     /* The device may have a class associated with the device container or its interfaces.  */
162     if (device -> ux_device_class_instance != UX_NULL)
163     {
164 
165         /* We need to stop the class instance for the device.  */
166         command.ux_host_class_command_instance =  device -> ux_device_class_instance;
167 
168         /* Call the class.  */
169         device -> ux_device_class -> ux_host_class_entry_function(&command);
170     }
171     else
172     {
173 
174         /* Search for the active configuration.  */
175         configuration =  device -> ux_device_current_configuration;
176 
177         /* If configuration is activated.  */
178         if (configuration != UX_NULL)
179         {
180 
181             /* We have the correct configuration, search the interface(s).  */
182             interface_ptr =  configuration -> ux_configuration_first_interface;
183 
184             /* Loop to perform the search.  */
185             while (interface_ptr != UX_NULL)
186             {
187 
188                 /* Check if an instance of the interface is present.  */
189                 if (interface_ptr -> ux_interface_class_instance != UX_NULL)
190                 {
191 
192                     /* We need to stop the class instance for the device.  */
193                     command.ux_host_class_command_instance =  interface_ptr -> ux_interface_class_instance;
194 
195                     /* Call the class.  */
196                     interface_ptr -> ux_interface_class -> ux_host_class_entry_function(&command);
197                 }
198 
199                 /* Move to next interface.  */
200                 interface_ptr =  interface_ptr -> ux_interface_next_interface;
201             }
202         }
203     }
204 
205     /* Notify application for disconnection of existing physical device.  */
206     if (_ux_system_host -> ux_system_host_change_function)
207     {
208         _ux_system_host -> ux_system_host_change_function(UX_DEVICE_DISCONNECTION, UX_NULL, (VOID*)device);
209     }
210 
211     /* Now all the resources for this device must be free.  */
212     _ux_host_stack_device_resources_free(device);
213 
214     /* Decrement the number of devices on this bus.  */
215     hcd -> ux_hcd_nb_devices--;
216 
217     /* We are done with this device removal.  */
218     return(UX_SUCCESS);
219 }
220