GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_host_stack_new_device_create.c Lines: 51 51 100.0 %
Date: 2026-03-06 18:57:10 Branches: 24 24 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
/**************************************************************************/
33
/*                                                                        */
34
/*  FUNCTION                                               RELEASE        */
35
/*                                                                        */
36
/*    _ux_host_stack_new_device_create                    PORTABLE C      */
37
/*                                                           6.1.12       */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    Chaoqiong Xiao, Microsoft Corporation                               */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    This function creates a new device on the USB. It may be called     */
45
/*    either by a hub or by the root hub.                                 */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    HCD                                   HCD that owns that device     */
50
/*    device_owner                          Either a root hub instance    */
51
/*                                            or a hub instance           */
52
/*    port_index                            Port the new device is mounted*/
53
/*    device_speed                          Speed at which the device is  */
54
/*                                            running (low, full, high)   */
55
/*    port_power_available                  Power available on the root   */
56
/*                                            or hub port. This value is  */
57
/*                                            used to ensure that the     */
58
/*                                            device can be configured    */
59
/*                                            without creating an         */
60
/*                                            OVER_CURRENT condition on   */
61
/*                                            the bus                     */
62
/*    created_device                        Destination to fill created   */
63
/*                                            device instance             */
64
/*                                                                        */
65
/*  OUTPUT                                                                */
66
/*                                                                        */
67
/*    Completion Status                                                   */
68
/*                                                                        */
69
/*    An Error code could be an indication that the device could not be   */
70
/*    created in which case the error is fatal to the enumeration and     */
71
/*    will not be retried. The error code can also indicate a failure     */
72
/*    for the device to respond to the GET_DEVICE_DESCRIPTOR. This error  */
73
/*    is not fatal and the caller should retry the enumeration process    */
74
/*    after the port to which the device is attached has been reset.      */
75
/*                                                                        */
76
/*  CALLS                                                                 */
77
/*                                                                        */
78
/*    _ux_host_stack_class_device_scan      Scan class devices            */
79
/*    _ux_host_stack_class_interface_scan   Scan class interfaces         */
80
/*    _ux_host_stack_device_address_set     Set device address            */
81
/*    _ux_host_stack_device_descriptor_read Read device descriptor        */
82
/*    _ux_host_stack_configuration_enumerate                              */
83
/*                                          Enumerate device config       */
84
/*    _ux_host_stack_new_device_get         Get new device                */
85
/*    _ux_utility_semaphore_create          Create a semaphore            */
86
/*    (ux_hcd_entry_function)               HCD entry function            */
87
/*                                                                        */
88
/*  CALLED BY                                                             */
89
/*                                                                        */
90
/*    USBX Components                                                     */
91
/*                                                                        */
92
/**************************************************************************/
93
1530
UINT  _ux_host_stack_new_device_create(UX_HCD *hcd, UX_DEVICE *device_owner,
94
                                UINT port_index, UINT device_speed,
95
                                UINT port_max_power,
96
                                UX_DEVICE **created_device)
97
{
98
99
UX_DEVICE           *device;
100
UINT                status;
101
UX_ENDPOINT         *control_endpoint;
102
103
104
#if UX_MAX_DEVICES > 1
105
    /* Verify the number of devices attached to the HCD already. Normally a HCD
106
       can have up to 127 devices but that can be tailored.  */
107
1530
    if (hcd -> ux_hcd_nb_devices > UX_MAX_USB_DEVICES)
108
    {
109
110
        /* Error trap. */
111
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_TOO_MANY_DEVICES);
112
113
        /* If trace is enabled, insert this event into the trace buffer.  */
114
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TOO_MANY_DEVICES, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
115
116
1
        return(UX_TOO_MANY_DEVICES);
117
    }
118
#endif
119
120
    /* Get a new device container to store this new device.  */
121
1529
    device =  _ux_host_stack_new_device_get();
122
1529
    if (device == UX_NULL)
123
    {
124
125
        /* Error trap. */
126
3
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_TOO_MANY_DEVICES);
127
128
        /* If trace is enabled, insert this event into the trace buffer.  */
129
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TOO_MANY_DEVICES, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
130
131
3
        return(UX_TOO_MANY_DEVICES);
132
    }
133
134
    /* Store the device instance.  */
135
1526
    *created_device = device;
136
137
    /* Increment the number of devices on this bus.  */
138
1526
    hcd -> ux_hcd_nb_devices++;
139
140
    /* If trace is enabled, insert this event into the trace buffer.  */
141
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_NEW_DEVICE_CREATE, hcd, device_owner, port_index, device, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
142
143
    /* At this stage the device is attached but not configured.
144
       we don't have to worry about power consumption yet.
145
       Initialize the device structure.  */
146
1526
    device -> ux_device_handle =         (ULONG) (ALIGN_TYPE) device;
147
1526
    device -> ux_device_state =          UX_DEVICE_ATTACHED;
148
1526
    device -> ux_device_address =        0;
149
1526
    device -> ux_device_speed =          device_speed;
150
1526
    UX_DEVICE_MAX_POWER_SET(device, port_max_power);
151
1526
    UX_DEVICE_PARENT_SET(device, device_owner);
152
1526
    UX_DEVICE_HCD_SET(device, hcd);
153
1526
    UX_DEVICE_PORT_LOCATION_SET(device, port_index);
154
1526
    device -> ux_device_power_source =   UX_DEVICE_BUS_POWERED;
155
156
    /* Create a semaphore for the device. This is to protect endpoint 0 mostly for OTG HNP polling. The initial count is 1 as
157
       a mutex mechanism.  */
158
1526
    status =  _ux_host_semaphore_create(&device -> ux_device_protection_semaphore, "ux_host_endpoint0_semaphore", 1);
159
160
    /* Check semaphore creation.  */
161
1526
    if (status != UX_SUCCESS)
162
    {
163
164
        /* Return error. Device resources that have been allocated until this
165
           point should be freed by the caller via _ux_host_stack_device_resources_free.  */
166
20
        return(UX_SEMAPHORE_ERROR);
167
    }
168
169
    /* Initialize the default control endpoint permanently attached
170
       to the device.  */
171
1506
    control_endpoint =                               &device -> ux_device_control_endpoint;
172
1506
    control_endpoint -> ux_endpoint =                (ULONG) (ALIGN_TYPE) control_endpoint;
173
1506
    control_endpoint -> ux_endpoint_next_endpoint =  UX_NULL;
174
1506
    control_endpoint -> ux_endpoint_interface =      UX_NULL;
175
1506
    control_endpoint -> ux_endpoint_device =         device;
176
1506
    control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_endpoint = control_endpoint;
177
178
    /* Create a semaphore for this endpoint to be attached to its transfer request.  */
179
1506
    status =  _ux_host_semaphore_create(&control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_semaphore, "ux_host_transfer_request_semaphore", 0);
180
181
    /* Check semaphore creation.  */
182
1506
    if (status != UX_SUCCESS)
183
    {
184
185
        /* Return error. Device resources that have been allocated until this
186
           point should be freed by the caller via _ux_host_stack_device_resources_free.  */
187
1
        return(UX_SEMAPHORE_ERROR);
188
    }
189
190
    /* If the device is running in high speed the default max packet size for the control endpoint is 64.
191
       All other speeds the size is 8.  */
192
1505
    if (device_speed == UX_HIGH_SPEED_DEVICE)
193
113
        control_endpoint -> ux_endpoint_descriptor.wMaxPacketSize =  UX_DEFAULT_HS_MPS;
194
    else
195
1392
        control_endpoint -> ux_endpoint_descriptor.wMaxPacketSize =  UX_DEFAULT_MPS;
196
197
    /* Create the default control endpoint at the HCD level.  */
198
1505
    status =  hcd -> ux_hcd_entry_function(hcd, UX_HCD_CREATE_ENDPOINT, (VOID *) control_endpoint);
199
200
#if defined(UX_HOST_STANDALONE)
201
    if (status == UX_SUCCESS)
202
    {
203
204
        /* Now control endpoint is ready, set state to running. */
205
        control_endpoint -> ux_endpoint_state =          UX_ENDPOINT_RUNNING;
206
207
        /* Setup default control request timeout.  */
208
        control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_timeout_value =
209
                            UX_MS_TO_TICK_NON_ZERO(UX_CONTROL_TRANSFER_TIMEOUT);
210
211
        /* Set default control request mode to wait.  */
212
        control_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_flags |=
213
                                                    UX_TRANSFER_FLAG_AUTO_WAIT;
214
    }
215
216
    /* Enumeration steps will be done in task state machine.  */
217
218
#else
219
220
    /* Going on to do enumeration (requests).  */
221
1505
    if (status == UX_SUCCESS)
222
    {
223
224
        /* Now control endpoint is ready, set state to running. */
225
1502
        control_endpoint -> ux_endpoint_state =          UX_ENDPOINT_RUNNING;
226
227
        /* Set the address of the device. The first time a USB device is
228
           accessed, it responds to the address 0. We need to change the address
229
           to a free device address between 1 and 127 ASAP.  */
230
1502
        status =  _ux_host_stack_device_address_set(device);
231
1502
        if (status == UX_SUCCESS)
232
        {
233
234
            /* Get the device descriptor.  */
235
1085
            status =  _ux_host_stack_device_descriptor_read(device);
236
1084
            if (status == UX_SUCCESS)
237
            {
238
239
                /* Get the configuration descriptor(s) for the device
240
                   and parse all the configuration, interface, endpoints...  */
241
1067
                status =  _ux_host_stack_configuration_enumerate(device);
242
            }
243
        }
244
    }
245
246
    /* Check the status of the previous operations. If there was an
247
       error during any of the phases, the device resources must be
248
       freed based on if we want to retry.  */
249
1504
    if (status == UX_SUCCESS)
250
    {
251
252
        /* The device, configuration(s), interface(s), endpoint(s) are
253
           now in order for this device to work. No configuration is set
254
           yet. First we need to find a class driver that wants to own
255
           it. There is no need to have an orphan device in a configured state.   */
256
924
        status =  _ux_host_stack_class_device_scan(device);
257
924
        if (status == UX_NO_CLASS_MATCH)
258
        {
259
260
839
            status =  _ux_host_stack_class_interface_scan(device);
261
262
        }
263
264
        /* Check if there is unnecessary resource to free.  */
265
923
        if (device -> ux_device_packed_configuration &&
266
369
            device -> ux_device_packed_configuration_keep_count == 0)
267
        {
268
361
            _ux_utility_memory_free(device -> ux_device_packed_configuration);
269
361
            device -> ux_device_packed_configuration = UX_NULL;
270
        }
271
272
        /* If trace is enabled, register this object.  */
273
        UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_DEVICE, hcd, device_owner, port_index, 0);
274
    }
275
#endif
276
277
    /* Return status. If there's an error, device resources that have been
278
       allocated until this point should be freed by the caller via _ux_host_stack_device_resources_free.  */
279
1503
    return(status);
280
}