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