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