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_rh_device_insertion PORTABLE C */
37 /* 6.1.11 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function handles a device insertion on a downstream port of */
45 /* the root hub pointed by HCD. */
46 /* */
47 /* INPUT */
48 /* */
49 /* HCD Pointer to HCD structure */
50 /* port_index Port index of insertion */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* Completion Status */
55 /* */
56 /* CALLS */
57 /* */
58 /* _ux_utility_delay_ms Thread sleep */
59 /* _ux_host_stack_new_device_create New device create */
60 /* _ux_host_stack_device_remove Device remove */
61 /* (hcd_entry_function) Entry function of HCD driver */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* USBX Components */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
72 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
73 /* checked HCD status before */
74 /* retrying enumeration, */
75 /* resulting in version 6.1 */
76 /* 02-02-2021 Chaoqiong Xiao Modified comment(s), */
77 /* handled more fail cases, */
78 /* updated internal call, */
79 /* added notification for */
80 /* device connection, */
81 /* added disconnection check */
82 /* in enumeration retries, */
83 /* resulting in version 6.1.4 */
84 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
85 /* added standalone support, */
86 /* resulting in version 6.1.10 */
87 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
88 /* internal clean up, */
89 /* resulting in version 6.1.11 */
90 /* */
91 /**************************************************************************/
_ux_host_stack_rh_device_insertion(UX_HCD * hcd,UINT port_index)92 UINT _ux_host_stack_rh_device_insertion(UX_HCD *hcd, UINT port_index)
93 {
94 #if defined(UX_HOST_STANDALONE)
95 UX_DEVICE *device;
96 UINT status;
97
98
99 /* If trace is enabled, insert this event into the trace buffer. */
100 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_RH_DEVICE_INSERTION, hcd, port_index, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
101
102 /* Anyway there is device connected. */
103 hcd -> ux_hcd_rh_device_connection |= (ULONG)(1 << port_index);
104
105 /* Create a new device slot for enumeration. */
106 status = _ux_host_stack_new_device_create(hcd, UX_NULL, port_index,
107 UX_FULL_SPEED_DEVICE, UX_MAX_SELF_POWER,
108 &device);
109
110 /* Link the device in enumeration list. */
111 if (status == UX_SUCCESS)
112 {
113
114 /* Set enumeration flag to process enumeration sequence. */
115 device -> ux_device_flags |= UX_DEVICE_FLAG_ENUM;
116
117 /* Done success. */
118 return(UX_SUCCESS);
119 }
120
121 #else
122 UX_DEVICE *device = UX_NULL;
123 UINT index_loop;
124 UINT device_speed;
125 ULONG port_status;
126 UINT status;
127
128 /* If trace is enabled, insert this event into the trace buffer. */
129 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_RH_DEVICE_INSERTION, hcd, port_index, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
130
131 /* Perform a PORT_ENABLE command. */
132 port_status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_ENABLE_PORT, (VOID *)((ALIGN_TYPE)port_index));
133
134 /* Check return status. */
135 if (port_status == UX_PORT_INDEX_UNKNOWN)
136 return(port_status);
137
138 /* A debounce interval with a minimum duration of 100 ms on attach. */
139 _ux_utility_delay_ms(100);
140
141 /* The first attempts to do a device enumeration may fail.
142 Typically, after the port is reset and the first command is sent to
143 the device, there is no answer. In this case, we reset the port again
144 and retry. Usually that does the trick! */
145 for (index_loop = 0; index_loop < UX_RH_ENUMERATION_RETRY; index_loop++)
146 {
147
148 /* Now we have to do a PORT_RESET command. */
149 port_status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_RESET_PORT, (VOID *)((ALIGN_TYPE)port_index));
150 if (port_status == UX_SUCCESS)
151 {
152
153 /* The port reset phase was successful. Before we invoke the device enumeration function,
154 we need to know the speed of the device. */
155 port_status = hcd -> ux_hcd_entry_function(hcd, UX_HCD_GET_PORT_STATUS, (VOID *)((ALIGN_TYPE)port_index));
156
157 /* Check return status. */
158 if (port_status == UX_PORT_INDEX_UNKNOWN)
159 {
160
161 /* Error trap. */
162 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE);
163
164 /* If trace is enabled, insert this event into the trace buffer. */
165 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DEVICE_ENUMERATION_FAILURE, port_index, 0, 0, UX_TRACE_ERRORS, 0, 0)
166
167 return(UX_DEVICE_ENUMERATION_FAILURE);
168 }
169
170 /* Check if device is still connected. */
171 if ((port_status & UX_PS_CCS) == 0)
172 {
173
174 /* Device disconnected during enumeration retries. */
175 return(UX_DEVICE_ENUMERATION_FAILURE);
176 }
177
178 /* Set the device speed. */
179 device_speed = port_status >> UX_PS_DS;
180
181 /* Ask the USB stack to enumerate this device. A root hub is considered self
182 powered. */
183 status = _ux_host_stack_new_device_create(hcd, UX_NULL, port_index, device_speed, UX_MAX_SELF_POWER, &device);
184
185 /* Check return status. */
186 if (status == UX_SUCCESS)
187 {
188
189 /* Successful device create. */
190
191 /* The device has been mounted properly, we have to remember this
192 so when the device is removed, we have to invoke the enumeration
193 function again */
194 hcd -> ux_hcd_rh_device_connection |= (ULONG)(1 << port_index);
195
196 /* If the device instance is ready, notify application for connection. */
197 if (_ux_system_host -> ux_system_host_change_function)
198 {
199 _ux_system_host -> ux_system_host_change_function(UX_DEVICE_CONNECTION, UX_NULL, (VOID*)device);
200 }
201
202 /* Return success to the caller. */
203 return(UX_SUCCESS);
204 }
205 else
206 {
207
208 /* Return error if HCD is dead. */
209 if (hcd -> ux_hcd_status != UX_HCD_STATUS_OPERATIONAL)
210 return(UX_CONTROLLER_DEAD);
211
212 /* No retry if there are too many devices. */
213 if (status == UX_TOO_MANY_DEVICES)
214 break;
215
216 /* No retry if there is no class found. */
217 if (status == UX_NO_CLASS_MATCH)
218 break;
219
220 /* Simulate remove to free allocated resources if retry. */
221 if (index_loop < UX_RH_ENUMERATION_RETRY - 1)
222 _ux_host_stack_device_remove(hcd, UX_NULL, port_index);
223 }
224 }
225
226 /* We get here if something did not go well. Either the port did not respond
227 well to the ENABLE\RESET phases or the device did not enumerate well
228 so we try again ! */
229 _ux_utility_delay_ms(UX_RH_ENUMERATION_RETRY_DELAY);
230 }
231 #endif /* defined(UX_HOST_STANDALONE) */
232
233 /* If we get here, the device did not enumerate completely.
234 The device is still attached to the root hub and therefore
235 there could be a physical connection with a unconfigured device. */
236 hcd -> ux_hcd_rh_device_connection |= (ULONG)(1 << port_index);
237
238 /* Notify application for a physical connection failed to be enumed.
239 Device instance NULL indicates too many devices.
240 Device state unconfigured indicates enumeration fail. */
241 if (_ux_system_host -> ux_system_host_change_function)
242 {
243 _ux_system_host -> ux_system_host_change_function(UX_DEVICE_CONNECTION, UX_NULL, (VOID*)device);
244 }
245
246 /* Error trap. */
247 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE);
248
249 /* If trace is enabled, insert this event into the trace buffer. */
250 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DEVICE_ENUMERATION_FAILURE, port_index, 0, 0, UX_TRACE_ERRORS, 0, 0)
251
252 /* Return a failed enumeration. */
253 return(UX_DEVICE_ENUMERATION_FAILURE);
254 }
255