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