GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_host_stack_bandwidth_check.c Lines: 45 45 100.0 %
Date: 2026-03-06 18:57:10 Branches: 28 28 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
/**   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
#if UX_MAX_DEVICES > 1
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _ux_host_stack_bandwidth_check                      PORTABLE C      */
38
/*                                                           6.1          */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    Chaoqiong Xiao, Microsoft Corporation                               */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function will check if there is enough bandwidth on the USB    */
46
/*    for the specified endpoint. The bandwidth requirement is calculated */
47
/*    by the MaxPacketSize field of endpoint and the speed of the         */
48
/*    endpoint. If the device is on a 1.1 bus or it is a 1.1 device       */
49
/*    behind a 2.0 hub on a 2.0 bus, the device bandwidth must be         */
50
/*    multiplied by 8 on the 1.1 segment.                                 */
51
/*                                                                        */
52
/*    This algorithm takes into account both TT bandwidth and HCD         */
53
/*    bandwidth. The TTs are attached to the device structure and not     */
54
/*    the hub structure in order to make the stack agnostic of the hub    */
55
/*    class.                                                              */
56
/*                                                                        */
57
/*  INPUT                                                                 */
58
/*                                                                        */
59
/*    HCD                                   Pointer to HCD                */
60
/*    endpoint                              Pointer to endpoint           */
61
/*                                                                        */
62
/*  OUTPUT                                                                */
63
/*                                                                        */
64
/*    Completion Status                                                   */
65
/*                                                                        */
66
/*  CALLS                                                                 */
67
/*                                                                        */
68
/*    None                                                                */
69
/*                                                                        */
70
/*  CALLED BY                                                             */
71
/*                                                                        */
72
/*    USBX Components                                                     */
73
/*                                                                        */
74
/**************************************************************************/
75
1197
UINT  _ux_host_stack_bandwidth_check(UX_HCD *hcd, UX_ENDPOINT *endpoint)
76
{
77
78
UX_DEVICE       *device;
79
UX_DEVICE       *parent_device;
80
USHORT          hcd_bandwidth_claimed;
81
USHORT          max_packet_size;
82
LONG            packet_size;
83
1197
USHORT          tt_bandwidth_claimed =  0;
84
ULONG           port_index;
85
ULONG           port_map;
86
ULONG           tt_index;
87
1197
const UCHAR     overheads[4][3] = {
88
/*   LS  FS   HS   */
89
    {63, 45, 173}, /* Control */
90
    { 0,  9,  38}, /* Isochronous */
91
    { 0, 13,  55}, /* Bulk */
92
    {19, 13,  55}  /* Interrupt */
93
};
94
95
    /* Get the pointer to the device.  */
96
1197
    device =  endpoint -> ux_endpoint_device;
97
98
    /* Calculate the bandwidth. From USB spec.
99
     *
100
     * The frame unit consumed per byte is like follow:
101
     *              Bytes/FrameUnit     FrameUnit/byte  FrameUnit/byte
102
     *              (Overhead included) (HS baseline)   (FS baseline)
103
     * Low Speed       187.5                40             8
104
     * Full Speed     1500                   5             1
105
     * High Speed     7500                   1            1/5
106
     *
107
     * The overhead is like follow:
108
     *               Control Isochronous Bulk Interrupt
109
     * bmAttribute     (0)       (1)     (2)     (3)
110
     * Low Speed        63       --      --      19
111
     * Full Speed       45        9      13      13
112
     * High Speed      173       38      55      55
113
     *
114
     * Worst case bit stuffing is calculated as 1.1667 (7/6) times the raw time.
115
     */
116
117
    /* Get maximum packet size.  */
118
1197
    max_packet_size  = endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_PACKET_SIZE_MASK;
119
120
    /* Rough time for possible Bit Stuffing.  */
121
1197
    packet_size = (max_packet_size * 7 + 5) / 6;
122
123
    /* Add overhead.  */
124
1197
    packet_size += overheads[endpoint -> ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE][device -> ux_device_speed];
125
1197
    max_packet_size = (USHORT)packet_size;
126
127
    /* Check for high-speed endpoint.  */
128
1197
    if (device -> ux_device_speed == UX_HIGH_SPEED_DEVICE)
129
    {
130
131
        /* Get number of transactions.  */
132
63
        max_packet_size = (USHORT)(max_packet_size *
133
63
                    (((endpoint -> ux_endpoint_descriptor.wMaxPacketSize & UX_MAX_NUMBER_OF_TRANSACTIONS_MASK) >>
134
63
                        UX_MAX_NUMBER_OF_TRANSACTIONS_SHIFT) + 1));
135
    }
136
137
    /* Calculate the bandwidth claimed by this endpoint for the main bus.  */
138
1197
    if (hcd -> ux_hcd_version != 0x200)
139
    {
140
141
1174
        if (device -> ux_device_speed == UX_LOW_SPEED_DEVICE)
142
            /* Low speed transfer takes 40x more units than high speed. */
143
4
            hcd_bandwidth_claimed =  (USHORT)(max_packet_size * 8 * 5);
144
        else
145
        {
146
147
1170
            if (device -> ux_device_speed == UX_FULL_SPEED_DEVICE)
148
                /* Full speed transfer takes 5x more units than high speed. */
149
1111
                hcd_bandwidth_claimed =  (USHORT)(max_packet_size * 5);
150
            else
151
                /* Use high speed timing as base for bus bandwidth calculation. */
152
59
                hcd_bandwidth_claimed =  (USHORT)max_packet_size;
153
        }
154
    }
155
    else
156
    {
157
158
23
        hcd_bandwidth_claimed =  (USHORT)max_packet_size;
159
23
        if (device -> ux_device_speed == UX_LOW_SPEED_DEVICE)
160
            /* Low speed transfer takes 8x more units than full speed. */
161
4
            tt_bandwidth_claimed =  (USHORT)(max_packet_size * 8);
162
        else
163
            /* Use full speed timing as base for TT bandwidth calculation. */
164
19
            tt_bandwidth_claimed =  (USHORT)max_packet_size;
165
    }
166
167
    /* Do we have enough on the bus for this new endpoint?  */
168
1197
    if (hcd -> ux_hcd_available_bandwidth < hcd_bandwidth_claimed)
169
    {
170
171
        /* If trace is enabled, insert this event into the trace buffer.  */
172
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_BANDWIDTH_AVAILABLE, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0)
173
174
        /* Error trap. */
175
7
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_NO_BANDWIDTH_AVAILABLE);
176
177
7
        return(UX_NO_BANDWIDTH_AVAILABLE);
178
    }
179
180
    /* We need to take care of the case where the endpoint belongs to a USB 1.1
181
       device that sits behind a 2.0 hub. We ignore cases where the device
182
       is either high speed or the bus is 1.1.  */
183

1190
    if ((device -> ux_device_speed == UX_HIGH_SPEED_DEVICE) || (hcd -> ux_hcd_version != 0x200))
184
    {
185
186
        /* The device is high speed, therefore no need for TT.  */
187
1173
        return(UX_SUCCESS);
188
    }
189
190
    /* We have a 1.1 device, check if the parent is a 2.0 hub.  */
191
17
    parent_device =  device -> ux_device_parent;
192
17
    if (parent_device == UX_NULL)
193
    {
194
195
        /* We are at the root, this controller must support 1.1 then! */
196
6
        return(UX_SUCCESS);
197
    }
198
199
    /* We get here when the parent is a hub. The problem occurs when the hub is itself
200
       connected to a chain of hubs. We need to find the first 2.0 hub parent to this
201
       chain to check the TT. We need to remember the port on which the first 1.1
202
       device is hooked to.  */
203
11
    port_index =  device -> ux_device_port_location - 1;
204
205
    /* Scan the chain of hubs upward.  */
206
38
    while (parent_device != UX_NULL)
207
    {
208
209
        /* Determine if the device is high speed.  */
210
33
        if (parent_device -> ux_device_speed == UX_HIGH_SPEED_DEVICE)
211
        {
212
213
            /* The device is a high speed hub, find the TT that manages the port.
214
               The first 1.1 device is connected to. First we calculate the port
215
               mapping bit.  */
216
6
            port_map = (ULONG)(1 << port_index);
217
218
            /* Parse all the TTs attached to the hub.  */
219
26
            for (tt_index = 0; tt_index < UX_MAX_TT; tt_index++)
220
            {
221
222
                /* Check if this TT owns the port where the device is attached.  */
223
24
                if ((parent_device -> ux_device_hub_tt[tt_index].ux_hub_tt_port_mapping & port_map) != 0)
224
                {
225
226
                    /* We have found the port, check if the tt can give us the bandwidth
227
                       we want to claim.  */
228
4
                    if (parent_device -> ux_device_hub_tt[tt_index].ux_hub_tt_max_bandwidth < tt_bandwidth_claimed)
229
                    {
230
231
                        /* If trace is enabled, insert this event into the trace buffer.  */
232
                        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_BANDWIDTH_AVAILABLE, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0)
233
234
                        /* Error trap. */
235
1
                        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_NO_BANDWIDTH_AVAILABLE);
236
237
1
                        return(UX_NO_BANDWIDTH_AVAILABLE);
238
                    }
239
240
                    else
241
3
                        return(UX_SUCCESS);
242
                }
243
            }
244
245
            /* If trace is enabled, insert this event into the trace buffer.  */
246
            UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_BANDWIDTH_AVAILABLE, endpoint, 0, 0, UX_TRACE_ERRORS, 0, 0)
247
248
            /* Error trap. */
249
2
            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_NO_BANDWIDTH_AVAILABLE);
250
251
            /* We should never get here !!!!! */
252
2
            return(UX_NO_BANDWIDTH_AVAILABLE);
253
        }
254
255
        /* We now remember where this hub is located on the parent.  */
256
27
        port_index =  parent_device -> ux_device_port_location - 1;
257
258
        /* We go up one level in the hub chain.  */
259
27
        parent_device =  parent_device -> ux_device_parent;
260
    }
261
262
    /* We get here when we have not found a 2.0 hub in the list and we got to the root port.  */
263
5
    return(UX_SUCCESS);
264
}
265
#endif /* #if UX_MAX_DEVICES > 1 */