GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hub_port_change_connection_process.c Lines: 49 49 100.0 %
Date: 2026-03-06 18:57:10 Branches: 32 32 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
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
/**************************************************************************/
72
24
VOID  _ux_host_class_hub_port_change_connection_process(UX_HOST_CLASS_HUB *hub, UINT port, UINT port_status)
73
{
74
75
UX_HCD      *hcd;
76
#if !defined(UX_HOST_STANDALONE)
77
24
UX_DEVICE   *device = UX_NULL;
78
UINT        device_speed;
79
UINT        device_enumeration_retry;
80
USHORT      port_power;
81
UINT        status;
82
USHORT      local_port_status;
83
USHORT      local_port_change;
84
#endif
85
86
    /* If trace is enabled, insert this event into the trace buffer.  */
87
    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)
88
89
    /* Get the HCD used by this instance.  */
90
24
    hcd = UX_DEVICE_HCD_GET(hub -> ux_host_class_hub_device);
91
92
    /* If there is a device attached on this HUB, there is a new device and it should
93
       be enumerated.  */
94
24
    if (port_status & UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION)
95
    {
96
97
        /* Check if there was a previous device already attached on this port. This may happen when a device
98
           disconnects and reconnect very quickly before the hub has a chance to poll the port state. In this
99
           case we do a device removal before doing a device connection.  */
100
20
        if (hub -> ux_host_class_hub_port_state & (UINT)(1 << port))
101
        {
102
103
            /* There was a device attached previously. Perform a removal.  */
104
4
            _ux_host_stack_device_remove(hcd, hub -> ux_host_class_hub_device, port);
105
106
        }
107
        else
108
109
            /* Mark device connection.  */
110
16
            hub -> ux_host_class_hub_port_state |= (UINT)(1 << port);
111
112
#if defined(UX_HOST_STANDALONE)
113
        /* Port operations are done outside.  */
114
#else
115
116
        /* Tell the hub to clear the change bit for this port so that we do
117
           not process the same change event again.  */
118
20
        _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_C_PORT_CONNECTION);
119
120
        /* Some devices are known to fail on the first try.  */
121
29
        for (device_enumeration_retry = 0; device_enumeration_retry < UX_HOST_CLASS_HUB_ENUMERATION_RETRY; device_enumeration_retry++)
122
        {
123
124
            /* Wait for debounce.  */
125
26
            _ux_utility_delay_ms(UX_HOST_CLASS_HUB_ENUMERATION_DEBOUNCE_DELAY);
126
127
            /* The port must be reset.  */
128
26
            status =  _ux_host_class_hub_port_reset(hub, port);
129
26
            if (status != UX_SUCCESS)
130
3
                return;
131
132
            /* Reset succeeded, so perform a new port status after reset to force speed reevaluation.  */
133
23
            status =  _ux_host_class_hub_status_get(hub, port, &local_port_status, &local_port_change);
134
23
            if (status != UX_SUCCESS)
135
1
                return;
136
137
            /* Check if device is still connected.  */
138
22
            if ((local_port_status & UX_HOST_CLASS_HUB_PORT_STATUS_CONNECTION) == 0)
139
1
                return;
140
141
            /* Device connected. Get the device speed.  */
142
21
            if (local_port_status & UX_HOST_CLASS_HUB_PORT_STATUS_LOW_SPEED)
143
1
                device_speed =  UX_LOW_SPEED_DEVICE;
144
            else
145
            {
146
147
20
                if (local_port_status & UX_HOST_CLASS_HUB_PORT_STATUS_HIGH_SPEED)
148
12
                    device_speed =  UX_HIGH_SPEED_DEVICE;
149
                else
150
8
                    device_speed =  UX_FULL_SPEED_DEVICE;
151
            }
152
153
            /* Decide how much power this device can draw. This depends if the HUB is self
154
               powered or bus powered.  */
155
21
            if (hub -> ux_host_class_hub_device -> ux_device_power_source == UX_DEVICE_BUS_POWERED)
156
157
                /* Hub is bus powered.  */
158
6
                port_power =  UX_MAX_BUS_POWER;
159
            else
160
161
                /* Hub is self powered.  */
162
15
                port_power =  UX_MAX_SELF_POWER;
163
164
            /* Wait for reset recovery.  */
165
21
            _ux_utility_delay_ms(UX_HOST_CLASS_HUB_ENUMERATION_RESET_RECOVERY_DELAY);
166
167
            /* Perform the device creation.  */
168
21
            status =  _ux_host_stack_new_device_create(UX_DEVICE_HCD_GET(hub -> ux_host_class_hub_device),
169
                                            hub -> ux_host_class_hub_device,
170
                                            port, device_speed, port_power,
171
                                            &device);
172
173
            /* Check return status.  */
174
21
            if (status == UX_SUCCESS)
175
            {
176
177
                /* Successful device creation.  */
178
179
                /* If the device instance is ready, notify application for unconfigured device.  */
180
10
                if (_ux_system_host -> ux_system_host_change_function)
181
                {
182
9
                    _ux_system_host -> ux_system_host_change_function(UX_DEVICE_CONNECTION, UX_NULL, (VOID*)device);
183
                }
184
185
                /* Just return.  */
186
10
                return;
187
            }
188
            else
189
            {
190
191
                /* No retry if there are too many devices.  */
192
11
                if (status == UX_TOO_MANY_DEVICES)
193
1
                    break;
194
195
                /* No retry if there is no class found.  */
196
10
                if (status == UX_NO_CLASS_MATCH)
197
1
                    break;
198
199
9
                if (device_enumeration_retry < UX_HOST_CLASS_HUB_ENUMERATION_RETRY - 1)
200
                {
201
202
                    /* Simulate remove to free allocated resources before retry.  */
203
6
                    _ux_host_stack_device_remove(hcd, hub -> ux_host_class_hub_device, port);
204
205
                    /* Wait for a while.  */
206
6
                    _ux_utility_delay_ms(UX_HOST_CLASS_HUB_ENUMERATION_RETRY_DELAY);
207
                }
208
            }
209
        }
210
211
        /* If we get here, the device did not enumerate completely.
212
           The device is still attached to the hub and therefore there is a
213
           physical connection with a unenumerated device. */
214
215
        /* If the device instance is ready, notify application for unconfigured device.  */
216
5
        if (_ux_system_host -> ux_system_host_change_function)
217
        {
218
4
            _ux_system_host -> ux_system_host_change_function(UX_DEVICE_CONNECTION, UX_NULL, (VOID*)device);
219
        }
220
221
        /* Error trap. */
222
5
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ROOT_HUB, UX_DEVICE_ENUMERATION_FAILURE);
223
224
        /* If trace is enabled, insert this event into the trace buffer.  */
225
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DEVICE_ENUMERATION_FAILURE, port, 0, 0, UX_TRACE_ERRORS, 0, 0)
226
#endif
227
    }
228
    else
229
    {
230
231
        /* Check if there was a no previous device attached on this port. */
232
4
        if ((hub -> ux_host_class_hub_port_state & (UINT)(1 << port)))
233
        {
234
            /* Mark device disconnection.  */
235
3
            hub -> ux_host_class_hub_port_state &= (UINT)~(1 << port);
236
237
            /* We get here when there is a device extraction.  */
238
3
            _ux_host_stack_device_remove(hcd, hub -> ux_host_class_hub_device, port);
239
        }
240
241
#if defined(UX_HOST_STANDALONE)
242
        /* Port operations are done outside.  */
243
#else
244
245
        /* The port should be disabled now. Power is still applied.  */
246
4
        status =  _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_PORT_ENABLE);
247
248
        /* We must clear the enable change condition so that we don't get awaken again.  */
249
4
        _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_C_PORT_ENABLE);
250
251
        /* We must clear the connection change condition so that we don't get awaken again.  */
252
4
        _ux_host_class_hub_feature(hub, port, UX_CLEAR_FEATURE, UX_HOST_CLASS_HUB_C_PORT_CONNECTION);
253
#endif
254
    }
255
256
    /* Return to caller.  */
257
9
    return;
258
}
259