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