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