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: 2024-12-12 17:16:36 Branches: 32 32 100.0 %

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