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 /**   HUB Class                                                           */
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_class_hub.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_class_hub_port_change_connection_process   PORTABLE C      */
38 /*                                                           6.1.12       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function will process a connection change on the port. This    */
46 /*    indicates that a device has been attached to the port.              */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    hub                                   Pointer to HUB class          */
51 /*    port                                  Port number                   */
52 /*    port_status                           Port status                   */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    None                                                                */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _ux_host_class_hub_feature            Set HUB feature               */
61 /*    _ux_host_class_hub_port_reset         Reset port                    */
62 /*    _ux_host_class_hub_status_get         Get status                    */
63 /*    _ux_host_stack_new_device_create      Create new device             */
64 /*    _ux_host_stack_device_remove          Remove device                 */
65 /*    _ux_utility_delay_ms                  Thread sleep                  */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    HUB Class                                                           */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
76 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            optimized based on compile  */
78 /*                                            definitions,                */
79 /*                                            resulting in version 6.1    */
80 /*  02-02-2021     Chaoqiong Xiao           Modified comment(s),          */
81 /*                                            handled more fail cases,    */
82 /*                                            updated internal call,      */
83 /*                                            added notification for      */
84 /*                                            device connection,          */
85 /*                                            added disconnection check   */
86 /*                                            in enumeration retries,     */
87 /*                                            resulting in version 6.1.4  */
88 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            added standalone support,   */
90 /*                                            resulting in version 6.1.12 */
91 /*                                                                        */
92 /**************************************************************************/
_ux_host_class_hub_port_change_connection_process(UX_HOST_CLASS_HUB * hub,UINT port,UINT port_status)93 VOID  _ux_host_class_hub_port_change_connection_process(UX_HOST_CLASS_HUB *hub, UINT port, UINT port_status)
94 {
95 
96 UX_HCD      *hcd;
97 #if !defined(UX_HOST_STANDALONE)
98 UX_DEVICE   *device = UX_NULL;
99 UINT        device_speed;
100 UINT        device_enumeration_retry;
101 USHORT      port_power;
102 UINT        status;
103 USHORT      local_port_status;
104 USHORT      local_port_change;
105 #endif
106 
107     /* If trace is enabled, insert this event into the trace buffer.  */
108     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_HUB_PORT_CHANGE_CONNECTION_PROCESS, hub, port, port_status, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
109 
110     /* Get the HCD used by this instance.  */
111     hcd = UX_DEVICE_HCD_GET(hub -> ux_host_class_hub_device);
112 
113     /* If there is a device attached on this HUB, there is a new device and it should
114        be enumerated.  */
115     if (port_status & UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION)
116     {
117 
118         /* Check if there was a previous device already attached on this port. This may happen when a device
119            disconnects and reconnect very quickly before the hub has a chance to poll the port state. In this
120            case we do a device removal before doing a device connection.  */
121         if (hub -> ux_host_class_hub_port_state & (UINT)(1 << port))
122         {
123 
124             /* There was a device attached previously. Perform a removal.  */
125             _ux_host_stack_device_remove(hcd, hub -> ux_host_class_hub_device, port);
126 
127         }
128         else
129 
130             /* Mark device connection.  */
131             hub -> ux_host_class_hub_port_state |= (UINT)(1 << port);
132 
133 #if defined(UX_HOST_STANDALONE)
134         /* Port operations are done outside.  */
135 #else
136 
137         /* Tell the hub to clear the change bit for this port so that we do
138            not process the same change event again.  */
139         _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_C_PORT_CONNECTION);
140 
141         /* Some devices are known to fail on the first try.  */
142         for (device_enumeration_retry = 0; device_enumeration_retry < UX_HOST_CLASS_HUB_ENUMERATION_RETRY; device_enumeration_retry++)
143         {
144 
145             /* Wait for debounce.  */
146             _ux_utility_delay_ms(UX_HOST_CLASS_HUB_ENUMERATION_DEBOUNCE_DELAY);
147 
148             /* The port must be reset.  */
149             status =  _ux_host_class_hub_port_reset(hub, port);
150             if (status != UX_SUCCESS)
151                 return;
152 
153             /* Reset succeeded, so perform a new port status after reset to force speed reevaluation.  */
154             status =  _ux_host_class_hub_status_get(hub, port, &local_port_status, &local_port_change);
155             if (status != UX_SUCCESS)
156                 return;
157 
158             /* Check if device is still connected.  */
159             if ((local_port_status & UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION) == 0)
160                 return;
161 
162             /* Device connected. Get the device speed.  */
163             if (local_port_status & UX_HOST_CLASS_HUB_PORT_STATUS_LOW_SPEED)
164                 device_speed =  UX_LOW_SPEED_DEVICE;
165             else
166             {
167 
168                 if (local_port_status & UX_HOST_CLASS_HUB_PORT_STATUS_HIGH_SPEED)
169                     device_speed =  UX_HIGH_SPEED_DEVICE;
170                 else
171                     device_speed =  UX_FULL_SPEED_DEVICE;
172             }
173 
174             /* Decide how much power this device can draw. This depends if the HUB is self
175                powered or bus powered.  */
176             if (hub -> ux_host_class_hub_device -> ux_device_power_source == UX_DEVICE_BUS_POWERED)
177 
178                 /* Hub is bus powered.  */
179                 port_power =  UX_MAX_BUS_POWER;
180             else
181 
182                 /* Hub is self powered.  */
183                 port_power =  UX_MAX_SELF_POWER;
184 
185             /* Wait for reset recovery.  */
186             _ux_utility_delay_ms(UX_HOST_CLASS_HUB_ENUMERATION_RESET_RECOVERY_DELAY);
187 
188             /* Perform the device creation.  */
189             status =  _ux_host_stack_new_device_create(UX_DEVICE_HCD_GET(hub -> ux_host_class_hub_device),
190                                             hub -> ux_host_class_hub_device,
191                                             port, device_speed, port_power,
192                                             &device);
193 
194             /* Check return status.  */
195             if (status == UX_SUCCESS)
196             {
197 
198                 /* Successful device creation.  */
199 
200                 /* If the device instance is ready, notify application for unconfigured device.  */
201                 if (_ux_system_host -> ux_system_host_change_function)
202                 {
203                     _ux_system_host -> ux_system_host_change_function(UX_DEVICE_CONNECTION, UX_NULL, (VOID*)device);
204                 }
205 
206                 /* Just return.  */
207                 return;
208             }
209             else
210             {
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                 if (device_enumeration_retry < UX_HOST_CLASS_HUB_ENUMERATION_RETRY - 1)
221                 {
222 
223                     /* Simulate remove to free allocated resources before retry.  */
224                     _ux_host_stack_device_remove(hcd, hub -> ux_host_class_hub_device, port);
225 
226                     /* Wait for a while.  */
227                     _ux_utility_delay_ms(UX_HOST_CLASS_HUB_ENUMERATION_RETRY_DELAY);
228                 }
229             }
230         }
231 
232         /* If we get here, the device did not enumerate completely.
233            The device is still attached to the hub and therefore there is a
234            physical connection with a unenumerated device. */
235 
236         /* If the device instance is ready, notify application for unconfigured device.  */
237         if (_ux_system_host -> ux_system_host_change_function)
238         {
239             _ux_system_host -> ux_system_host_change_function(UX_DEVICE_CONNECTION, UX_NULL, (VOID*)device);
240         }
241 
242         /* Error trap. */
243         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE);
244 
245         /* If trace is enabled, insert this event into the trace buffer.  */
246         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DEVICE_ENUMERATION_FAILURE, port, 0, 0, UX_TRACE_ERRORS, 0, 0)
247 #endif
248     }
249     else
250     {
251 
252         /* Check if there was a no previous device attached on this port. */
253         if ((hub -> ux_host_class_hub_port_state & (UINT)(1 << port)))
254         {
255             /* Mark device disconnection.  */
256             hub -> ux_host_class_hub_port_state &= (UINT)~(1 << port);
257 
258             /* We get here when there is a device extraction.  */
259             _ux_host_stack_device_remove(hcd, hub -> ux_host_class_hub_device, port);
260         }
261 
262 #if defined(UX_HOST_STANDALONE)
263         /* Port operations are done outside.  */
264 #else
265 
266         /* The port should be disabled now. Power is still applied.  */
267         status =  _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_PORT_ENABLE);
268 
269         /* We must clear the enable change condition so that we don't get awaken again.  */
270         _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_C_PORT_ENABLE);
271 
272         /* We must clear the connection change condition so that we don't get awaken again.  */
273         _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_C_PORT_CONNECTION);
274 #endif
275     }
276 
277     /* Return to caller.  */
278     return;
279 }
280 
281