GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hub_descriptor_get.c Lines: 49 49 100.0 %
Date: 2026-03-06 18:57:10 Branches: 18 18 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
#if UX_MAX_DEVICES > 1
34
35
#if defined(UX_HOST_STANDALONE)
36
UINT _ux_host_class_hub_descriptor_parse(UX_HOST_CLASS_HUB *hub, UCHAR *descriptor);
37
UINT
38
#else
39
static inline UINT
40
#endif
41
59
_ux_host_class_hub_descriptor_parse(UX_HOST_CLASS_HUB *hub, UCHAR *descriptor)
42
{
43
59
UINT            status = UX_SUCCESS;
44
ULONG           tt_protocols; /* (bDeviceProtocol << 8) | bInterfaceProtocol  */
45
ULONG           port_index;
46
47
    /* Parse the device descriptor and create the local descriptor.  */
48
59
    _ux_utility_descriptor_parse(descriptor, _ux_system_hub_descriptor_structure, UX_HUB_DESCRIPTOR_ENTRIES,
49
59
                                                            (UCHAR *) &hub -> ux_host_class_hub_descriptor);
50
51
    /* Check the protocol used by the HUB. This will indicate if the HUB supports multiple TTs in high speed mode.  */
52
59
    tt_protocols = ((ULONG)hub -> ux_host_class_hub_device -> ux_device_descriptor.bDeviceProtocol << 8) |
53
59
                    hub -> ux_host_class_hub_interface -> ux_interface_descriptor.bInterfaceProtocol;
54

59
    switch(tt_protocols)
55
    {
56
57
    /* 1. A hub operating at full-/low-speed has a device descriptor with a bDeviceProtocol field set to zero(0)
58
     *    and an interface descriptor with a bInterfaceProtocol field set to zero(0).
59
     */
60
1
    case (UX_HOST_CLASS_HUB_PROTOCOL_FS << 8):
61
62
        /* In the case of full speed hub, there are no TTs to declare */
63
1
        break;
64
65
    /* 2. A hub that has a single TT must set the bDeviceProtocol field of the device descriptor to one(1) and
66
     *    the interface descriptor bInterfaceProtocol field set to 0.
67
     * 3. A multiple TT hub must set the bDeviceProtocol field of the device descriptor to two (2).
68
     *    The first interface descriptor has the bInterfaceProtocol field set to one(1).
69
     */
70
53
    case (UX_HOST_CLASS_HUB_PROTOCOL_SINGLE_TT << 8): /* Fall through.  */
71
    case (UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT << 8) | UX_HOST_CLASS_HUB_PROTOCOL_SINGLE_TT:
72
73
        /* Single TT hub or single TT interface.  */
74
        /* Check if current setting supports this Hub.  */
75
53
        if (hub -> ux_host_class_hub_descriptor.bNbPorts > UX_MAX_TT)
76
        {
77
78
6
            status = UX_TOO_MANY_HUB_PORTS;
79
6
            break;
80
        }
81
82
        /* In a single TT state, all the downstream ports report to the same
83
           TT and share the 1.1 USB segment bandwidth. This is a very crude
84
           but working method, we simply set all the ports bits to the first
85
           TT.  */
86
47
        hub -> ux_host_class_hub_device -> ux_device_hub_tt[0].ux_hub_tt_port_mapping =   UX_TT_MASK;
87
47
        hub -> ux_host_class_hub_device -> ux_device_hub_tt[0].ux_hub_tt_max_bandwidth =  UX_TT_BANDWIDTH;
88
47
        break;
89
90
    /* 3. A multiple TT hub must set the bDeviceProtocol field of the device descriptor to two (2).
91
        *    The first interface descriptor has the bInterfaceProtocol field set to one(1).
92
        *    Such a hub also has a second interface descriptor where the bInterfaceProtocol is set to two(2).
93
        */
94
2
    case (UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT << 8) | UX_HOST_CLASS_HUB_PROTOCOL_MULTIPLE_TT:
95
96
        /* Multiple TTs.  */
97
        /* Check if current setting supports this Hub.  */
98
2
        if (hub -> ux_host_class_hub_descriptor.bNbPorts > UX_MAX_TT)
99
        {
100
101
1
            status = UX_TOO_MANY_HUB_PORTS;
102
1
            break;
103
        }
104
105
        /* In the case of multiple TTs, each downstream port can sustain the USB 1.1
106
            max bandwidth and therefore we allocate one TT per port with that bandwidth.  */
107
2
        for (port_index = 0; port_index < hub -> ux_host_class_hub_descriptor.bNbPorts; port_index++)
108
        {
109
110
1
            hub -> ux_host_class_hub_device -> ux_device_hub_tt[port_index].ux_hub_tt_port_mapping =   (ULONG)(1 << port_index);
111
1
            hub -> ux_host_class_hub_device -> ux_device_hub_tt[port_index].ux_hub_tt_max_bandwidth =  UX_TT_BANDWIDTH;
112
        }
113
1
        break;
114
115
3
    default: /* Invalid bDeviceProtocol and bInterfaceProtocol pair.  */
116
117
        /* We should never get here. In this case the protocol value of the HUB is illegal.  */
118
3
        status =  UX_DESCRIPTOR_CORRUPTED;
119
    }
120
121
    /* Return status.  */
122
59
    return(status);
123
}
124
#endif
125
126
127
/**************************************************************************/
128
/*                                                                        */
129
/*  FUNCTION                                               RELEASE        */
130
/*                                                                        */
131
/*    _ux_host_class_hub_descriptor_get                   PORTABLE C      */
132
/*                                                           6.3.0        */
133
/*  AUTHOR                                                                */
134
/*                                                                        */
135
/*    Chaoqiong Xiao, Microsoft Corporation                               */
136
/*                                                                        */
137
/*  DESCRIPTION                                                           */
138
/*                                                                        */
139
/*    This function obtains the HUB descriptor. This descriptor contains  */
140
/*    the number of downstream ports and the power characteristics of the */
141
/*    HUB (self powered or bus powered).                                  */
142
/*                                                                        */
143
/*  INPUT                                                                 */
144
/*                                                                        */
145
/*    hub                                   Pointer to HUB                */
146
/*                                                                        */
147
/*  OUTPUT                                                                */
148
/*                                                                        */
149
/*    Completion Status                                                   */
150
/*                                                                        */
151
/*  CALLS                                                                 */
152
/*                                                                        */
153
/*    _ux_host_stack_transfer_request       Process transfer request      */
154
/*    _ux_utility_memory_allocate           Allocate memory block         */
155
/*    _ux_utility_memory_free               Release memory block          */
156
/*    _ux_utility_descriptor_parse          Parse descriptor              */
157
/*                                                                        */
158
/*  CALLED BY                                                             */
159
/*                                                                        */
160
/*    HUB Class                                                           */
161
/*                                                                        */
162
/**************************************************************************/
163
66
UINT  _ux_host_class_hub_descriptor_get(UX_HOST_CLASS_HUB *hub)
164
{
165
166
UCHAR           *descriptor;
167
UX_ENDPOINT     *control_endpoint;
168
UX_TRANSFER     *transfer_request;
169
UINT            status;
170
171
172
    /* We need to get the default control endpoint transfer request pointer.  */
173
66
    control_endpoint =  &hub -> ux_host_class_hub_device -> ux_device_control_endpoint;
174
66
    transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
175
176
    /* Need to allocate memory for the descriptor.  */
177
66
    descriptor =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HUB_DESCRIPTOR_LENGTH);
178
66
    if (descriptor == UX_NULL)
179
3
        return(UX_MEMORY_INSUFFICIENT);
180
181
    /* Create a transfer request for the GET_DESCRIPTOR request.  */
182
63
    transfer_request -> ux_transfer_request_data_pointer =      descriptor;
183
63
    transfer_request -> ux_transfer_request_requested_length =  UX_HUB_DESCRIPTOR_LENGTH;
184
63
    transfer_request -> ux_transfer_request_function =          UX_HOST_CLASS_HUB_GET_DESCRIPTOR;
185
63
    transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_DEVICE;
186
63
    transfer_request -> ux_transfer_request_value =             (UX_HUB_DESCRIPTOR_ITEM << 8);
187
63
    transfer_request -> ux_transfer_request_index =             0;
188
189
#if defined(UX_HOST_STANDALONE)
190
191
    /* Save allocated buffer pointer.  */
192
    hub -> ux_host_class_hub_allocated = descriptor;
193
194
    /* Link to running transfer.  */
195
    UX_TRANSFER_STATE_RESET(transfer_request);
196
    hub -> ux_host_class_hub_transfer = transfer_request;
197
    status = UX_SUCCESS;
198
#else
199
200
    /* Send request to HCD layer.  */
201
63
    status =  _ux_host_stack_transfer_request(transfer_request);
202
203
    /* Did the transfer succeed?  */
204
63
    if (status == UX_SUCCESS)
205
    {
206
207
        /* Is the length valid?  */
208
62
        if (transfer_request -> ux_transfer_request_actual_length == UX_HUB_DESCRIPTOR_LENGTH)
209
        {
210
211
#if UX_MAX_DEVICES > 1
212
59
            status = _ux_host_class_hub_descriptor_parse(hub, descriptor);
213
59
            if (status != UX_SUCCESS)
214
            {
215
216
                /* Error trap. */
217
10
                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, status);
218
219
                /* If trace is enabled, insert this event into the trace buffer.  */
220
                UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, status, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
221
            }
222
#endif
223
        }
224
        else
225
        {
226
227
            /* Error trap. */
228
3
            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HUB, UX_DESCRIPTOR_CORRUPTED);
229
230
            /* If trace is enabled, insert this event into the trace buffer.  */
231
            UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
232
233
            /* The descriptor must be corrupted if we got an invalid length.  */
234
3
            status =  UX_DESCRIPTOR_CORRUPTED;
235
        }
236
    }
237
238
    /* Free the memory for the descriptor.  */
239
63
    _ux_utility_memory_free(descriptor);
240
#endif
241
242
    /* Return completion status.  */
243
63
    return(status);
244
}