GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_hub_entry.c Lines: 16 16 100.0 %
Date: 2026-03-06 18:57:10 Branches: 8 8 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 defined(UX_HOST_STANDALONE)
34
extern UINT _ux_host_class_hub_descriptor_parse(UX_HOST_CLASS_HUB *hub, UCHAR *descriptor);
35
static inline UINT _ux_host_class_hub_activate_wait(UX_HOST_CLASS_COMMAND *command);
36
#endif
37
38
39
/**************************************************************************/
40
/*                                                                        */
41
/*  FUNCTION                                               RELEASE        */
42
/*                                                                        */
43
/*    _ux_host_class_hub_entry                            PORTABLE C      */
44
/*                                                           6.3.0        */
45
/*  AUTHOR                                                                */
46
/*                                                                        */
47
/*    Chaoqiong Xiao, Microsoft Corporation                               */
48
/*                                                                        */
49
/*  DESCRIPTION                                                           */
50
/*                                                                        */
51
/*    This function is the entry point of the HUB class. It will be       */
52
/*    called by the USBX stack enumeration module when there is a new     */
53
/*    device on the bus or when there is a device extraction.             */
54
/*                                                                        */
55
/*  INPUT                                                                 */
56
/*                                                                        */
57
/*    command                               Pointer to command            */
58
/*                                                                        */
59
/*  OUTPUT                                                                */
60
/*                                                                        */
61
/*    Completion Status                                                   */
62
/*                                                                        */
63
/*  CALLS                                                                 */
64
/*                                                                        */
65
/*    _ux_host_class_hub_activate           Activate HUB class            */
66
/*    _ux_host_class_hub_deactivate         Deactivate HUB class          */
67
/*                                                                        */
68
/*  CALLED BY                                                             */
69
/*                                                                        */
70
/*    Host Stack                                                          */
71
/*                                                                        */
72
/**************************************************************************/
73
280
UINT  _ux_host_class_hub_entry(UX_HOST_CLASS_COMMAND *command)
74
{
75
76
UINT    status;
77
78
79
    /* The command request will tell us we need to do here, either a enumeration
80
       query, an activation or a deactivation.  */
81

280
    switch (command -> ux_host_class_command_request)
82
    {
83
84
173
    case UX_HOST_CLASS_COMMAND_QUERY:
85
86
        /* The query command is used to let the stack enumeration process know if we want to own
87
           this device or not.  */
88
173
        if ((command -> ux_host_class_command_usage == UX_HOST_CLASS_COMMAND_USAGE_DCSP) &&
89
81
            (command -> ux_host_class_command_class == UX_HOST_CLASS_HUB_CLASS))
90
70
            return(UX_SUCCESS);
91
        else
92
103
            return(UX_NO_CLASS_MATCH);
93
94
95
70
    case UX_HOST_CLASS_COMMAND_ACTIVATE:
96
97
        /* The activate command is used when the device inserted has found a parent and
98
           is ready to complete the enumeration.  */
99
70
        status =  _ux_host_class_hub_activate(command);
100
101
        /* Return completion status.  */
102
70
        return(status);
103
104
#if defined(UX_HOST_STANDALONE)
105
    case UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT:
106
        status = _ux_host_class_hub_activate_wait(command);
107
        return(status);
108
#endif
109
110
36
    case UX_HOST_CLASS_COMMAND_DEACTIVATE:
111
112
        /* The deactivate command is used when the device has been extracted either
113
           directly or when its parents has been extracted */
114
36
        status =  _ux_host_class_hub_deactivate(command);
115
116
        /* Return completion status.  */
117
36
        return(status);
118
119
1
    default:
120
121
        /* Error trap. */
122
1
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED);
123
124
        /* If trace is enabled, insert this event into the trace buffer.  */
125
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
126
127
        /* Return error status.  */
128
1
        return(UX_FUNCTION_NOT_SUPPORTED);
129
    }
130
}
131
132
#if defined(UX_HOST_STANDALONE)
133
#define UX_HOST_STACK_ENUM_TRANS_ERROR(t)       (                               \
134
    (t)->ux_transfer_request_completion_code != UX_SUCCESS ||                   \
135
    (t)->ux_transfer_request_actual_length !=                                   \
136
        (t)->ux_transfer_request_requested_length)
137
138
static inline UINT _ux_host_class_hub_enum_get_status(UX_HOST_CLASS_HUB *hub, UX_TRANSFER *trans)
139
{
140
    hub -> ux_host_class_hub_allocated = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, 2);
141
    if (hub -> ux_host_class_hub_allocated == UX_NULL)
142
        return(UX_MEMORY_INSUFFICIENT);
143
144
    trans -> ux_transfer_request_requested_length =  2;
145
    trans -> ux_transfer_request_data_pointer =      hub -> ux_host_class_hub_allocated;
146
    trans -> ux_transfer_request_function =          UX_GET_STATUS;
147
    trans -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
148
    trans -> ux_transfer_request_value =             0;
149
    trans -> ux_transfer_request_index =             0;
150
    return(UX_SUCCESS);
151
}
152
static inline VOID _ux_host_class_hub_enum_set_config(UX_HOST_CLASS_HUB *hub, UX_TRANSFER *trans, UX_CONFIGURATION *configuration)
153
{
154
    UX_PARAMETER_NOT_USED(hub);
155
    trans -> ux_transfer_request_requested_length =  0;
156
    trans -> ux_transfer_request_function =          UX_SET_CONFIGURATION;
157
    trans -> ux_transfer_request_type =              UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
158
    trans -> ux_transfer_request_value =             (USHORT) configuration -> ux_configuration_descriptor.bConfigurationValue;
159
    trans -> ux_transfer_request_index =             0;
160
}
161
static inline UINT _ux_host_class_hub_activate_wait(UX_HOST_CLASS_COMMAND *command)
162
{
163
UX_DEVICE               *device;
164
UX_ENDPOINT             *ep0;
165
UX_TRANSFER             *trans0, *trans;
166
UX_HOST_CLASS_HUB       *hub;
167
UINT                    status;
168
ULONG                   current_ms, elapsed_ms;
169
170
    /* Get the instance for this class.  */
171
    device = (UX_DEVICE *)command -> ux_host_class_command_container;
172
    hub =  (UX_HOST_CLASS_HUB *) device -> ux_device_class_instance;
173
174
    /* Get endpoint 0 and transfer request.  */
175
    ep0 = &device -> ux_device_control_endpoint;
176
    trans0 = &ep0 -> ux_endpoint_transfer_request;
177
178
    /* Get current transfer request.  */
179
    trans = hub -> ux_host_class_hub_transfer;
180
181
    /* Immediate state change: continue.
182
        Wait/pending state   : return.  */
183
    while(1)
184
    {
185
186
        /* Run initialize state machine.  */
187
        switch(hub -> ux_host_class_hub_enum_state)
188
        {
189
190
        case UX_HOST_CLASS_HUB_ENUM_GET_STATUS       :
191
            status = _ux_host_class_hub_enum_get_status(hub, trans0);
192
            if (status != UX_SUCCESS)
193
            {
194
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
195
                hub -> ux_host_class_hub_run_status = status;
196
                continue;
197
            }
198
199
            UX_TRANSFER_STATE_RESET(trans0);
200
            hub -> ux_host_class_hub_transfer = trans0;
201
            hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_TRANS_WAIT;
202
            hub -> ux_host_class_hub_next_state = UX_HOST_CLASS_HUB_ENUM_POWER_CHECK;
203
            continue;
204
205
        case UX_HOST_CLASS_HUB_ENUM_POWER_CHECK      :
206
207
            /* Transfer request error check.  */
208
            if (UX_HOST_STACK_ENUM_TRANS_ERROR(trans))
209
            {
210
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
211
                hub -> ux_host_class_hub_run_status = UX_CONNECTION_INCOMPATIBLE;
212
                continue;
213
            }
214
215
            /* Save power source setting.  */
216
            if (hub -> ux_host_class_hub_allocated[0] & UX_STATUS_DEVICE_SELF_POWERED)
217
                device -> ux_device_power_source = UX_DEVICE_SELF_POWERED;
218
            else
219
                device -> ux_device_power_source = UX_DEVICE_BUS_POWERED;
220
221
            /* Free allocated buffer.  */
222
            _ux_utility_memory_free(hub -> ux_host_class_hub_allocated);
223
            hub -> ux_host_class_hub_allocated = UX_NULL;
224
225
#if UX_MAX_DEVICES > 1
226
227
            /* Check the HUB power source and check the parent power source.  */
228
            if (device -> ux_device_power_source == UX_DEVICE_BUS_POWERED)
229
            {
230
231
                /* Check parent power.  */
232
                if (device -> ux_device_parent != UX_NULL)
233
                {
234
                    if (device -> ux_device_parent -> ux_device_power_source == UX_DEVICE_BUS_POWERED)
235
                    {
236
                        hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
237
                        hub -> ux_host_class_hub_run_status = UX_CONNECTION_INCOMPATIBLE;
238
                        continue;
239
                    }
240
                }
241
            }
242
#endif
243
            /* Fall through.  */
244
        case UX_HOST_CLASS_HUB_ENUM_SET_CONFIG       :
245
            _ux_host_class_hub_enum_set_config(hub, trans0,
246
                                    device -> ux_device_first_configuration);
247
248
            UX_TRANSFER_STATE_RESET(trans0);
249
            hub -> ux_host_class_hub_transfer = trans0;
250
            hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_TRANS_WAIT;
251
            hub -> ux_host_class_hub_next_state = UX_HOST_CLASS_HUB_ENUM_SET_CONFIG_DONE;
252
            continue;
253
254
        case UX_HOST_CLASS_HUB_ENUM_SET_CONFIG_DONE  :
255
256
            /* Transfer request error check.  */
257
            if (UX_HOST_STACK_ENUM_TRANS_ERROR(trans))
258
            {
259
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
260
                hub -> ux_host_class_hub_run_status = UX_CONNECTION_INCOMPATIBLE;
261
                continue;
262
            }
263
264
            /* Create configuration instance.  */
265
            status = _ux_host_stack_configuration_instance_create(device -> ux_device_first_configuration);
266
            if (status != UX_SUCCESS)
267
            {
268
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
269
                hub -> ux_host_class_hub_run_status = status;
270
                continue;
271
            }
272
273
            /* Change device state.  */
274
            device -> ux_device_state = UX_DEVICE_CONFIGURED;
275
            device -> ux_device_current_configuration = device -> ux_device_first_configuration;
276
277
            /* Fall through.  */
278
        case UX_HOST_CLASS_HUB_ENUM_GET_HUB_DESC     :
279
            status = _ux_host_class_hub_descriptor_get(hub);
280
            if (UX_SUCCESS != status)
281
            {
282
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
283
                hub -> ux_host_class_hub_run_status = status;
284
                continue;
285
            }
286
287
            /* Request already updated, to transfer state.  */
288
            hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_TRANS_WAIT;
289
            hub -> ux_host_class_hub_next_state = UX_HOST_CLASS_HUB_ENUM_GET_HUB_DESC_DONE;
290
            continue;
291
292
        case UX_HOST_CLASS_HUB_ENUM_GET_HUB_DESC_DONE:
293
294
            /* Transfer request error check.  */
295
            if (UX_HOST_STACK_ENUM_TRANS_ERROR(trans))
296
            {
297
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
298
                hub -> ux_host_class_hub_run_status = UX_DESCRIPTOR_CORRUPTED;
299
                continue;
300
            }
301
302
            /* Parse descriptor.  */
303
            status = _ux_host_class_hub_descriptor_parse(hub, hub -> ux_host_class_hub_allocated);
304
            if (status != UX_SUCCESS)
305
            {
306
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
307
                hub -> ux_host_class_hub_run_status = status;
308
                continue;
309
            }
310
311
            /* Free the allocated descriptor.  */
312
            _ux_utility_memory_free(hub -> ux_host_class_hub_allocated);
313
            hub -> ux_host_class_hub_allocated = UX_NULL;
314
315
            /* Initialize for port power ON.  */
316
            hub -> ux_host_class_hub_run_port = 1;
317
318
            /* Fall through.  */
319
        case UX_HOST_CLASS_HUB_ENUM_PORT_POWER       :
320
321
            /* Prepare for SetPortFeature(POWER).  */
322
            status = _ux_host_class_hub_feature(hub,
323
                                hub -> ux_host_class_hub_run_port,
324
                                UX_SET_FEATURE, UX_HOST_CLASS_HUB_PORT_POWER);
325
326
            /* Request already updated, to transfer state.  */
327
            hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_TRANS_WAIT;
328
            hub -> ux_host_class_hub_next_state = UX_HOST_CLASS_HUB_ENUM_PORT_POWER_DELAY;
329
            continue;
330
331
        case UX_HOST_CLASS_HUB_ENUM_PORT_POWER_DELAY :
332
333
            /* Transfer request error check.  */
334
            if (UX_HOST_STACK_ENUM_TRANS_ERROR(trans))
335
            {
336
337
                /* Set the HUB status to not powered.  */
338
                hub -> ux_host_class_hub_port_power &=
339
                            (UINT)~(1u << hub -> ux_host_class_hub_run_port);
340
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_PORT_NEXT;
341
                continue;
342
            }
343
344
            /* Delay a while (as described by hub descriptor).  */
345
            hub -> ux_host_class_hub_wait_start = _ux_utility_time_get();
346
            hub -> ux_host_class_hub_wait_ms = UX_MS_TO_TICK_NON_ZERO((ULONG)hub -> ux_host_class_hub_descriptor.bPwrOn2PwrGood << 1);
347
348
            hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_TRANS_WAIT;
349
            hub -> ux_host_class_hub_next_state = UX_HOST_CLASS_HUB_ENUM_PORT_POWER_ON;
350
            continue;
351
352
        case UX_HOST_CLASS_HUB_ENUM_PORT_POWER_ON:
353
            hub -> ux_host_class_hub_port_power |= (UINT)(1u << hub -> ux_host_class_hub_run_port);
354
355
            /* Fall through.  */
356
        case UX_HOST_CLASS_HUB_ENUM_PORT_NEXT        :
357
358
            /* Check if the last port is powered.  */
359
            if (hub -> ux_host_class_hub_run_port <
360
                hub -> ux_host_class_hub_descriptor.bNbPorts)
361
            {
362
363
                /* Start another port power.  */
364
                hub -> ux_host_class_hub_run_port ++;
365
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_PORT_POWER;
366
                continue;
367
            }
368
369
            /* All port is powered.  */
370
371
            /* Fall through.  */
372
        case UX_HOST_CLASS_HUB_ENUM_INTERRUPT_START  :
373
            status = _ux_host_class_hub_interrupt_endpoint_start(hub);
374
            if (status != UX_SUCCESS)
375
                hub -> ux_host_class_hub_run_status = status;
376
377
            /* Fall through.  */
378
        case UX_HOST_CLASS_HUB_ENUM_DONE             :
379
380
            /* Free buffer allocated while enumerating.  */
381
            if (hub -> ux_host_class_hub_allocated)
382
            {
383
                _ux_utility_memory_free(hub -> ux_host_class_hub_allocated);
384
                hub -> ux_host_class_hub_allocated = UX_NULL;
385
            }
386
387
            /* Error cases.  */
388
            if (hub -> ux_host_class_hub_run_status != UX_SUCCESS)
389
            {
390
391
                /* Unlink from device.  */
392
                device -> ux_device_class_instance = UX_NULL;
393
394
                /* Error trap. */
395
                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, hub -> ux_host_class_hub_run_status);
396
397
                /* If trace is enabled, insert this event into the trace buffer.  */
398
                UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, hub -> ux_host_class_hub_run_status, hub, 0, 0, UX_TRACE_ERRORS, 0, 0)
399
400
                /* Free hub.  */
401
                _ux_utility_memory_free(hub);
402
                return(UX_STATE_ERROR);
403
            }
404
405
            /* Done success.  */
406
407
            /* Create this class instance.  */
408
            _ux_host_stack_class_instance_create(hub -> ux_host_class_hub_class, (VOID *) hub);
409
410
            /* Store the instance in the device container, this is for the USBX stack
411
                when it needs to invoke the class.  */
412
            device -> ux_device_class_instance =  (VOID *) hub;
413
414
            /* Mark the HUB as live now.  */
415
            hub -> ux_host_class_hub_state =  UX_HOST_CLASS_INSTANCE_LIVE;
416
417
            /* If all is fine and the device is mounted, we may need to inform the application
418
                if a function has been programmed in the system structure.  */
419
            if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
420
            {
421
422
                /* Call system change function.  */
423
                _ux_system_host ->  ux_system_host_change_function(UX_DEVICE_INSERTION, hub -> ux_host_class_hub_class, (VOID *) hub);
424
            }
425
426
            /* Next state: CHANGE_CHECK.  */
427
            hub -> ux_host_class_hub_enum_state = UX_STATE_IDLE;
428
            hub -> ux_host_class_hub_run_state = UX_HOST_CLASS_HUB_CHANGE_CHECK;
429
            hub -> ux_host_class_hub_run_port = 0;
430
431
            /* Done activate.  */
432
            return(UX_STATE_NEXT);
433
434
        case UX_HOST_CLASS_HUB_ENUM_TRANS_WAIT:
435
436
            /* Poll transfer task.  */
437
            status = _ux_host_stack_transfer_run(hub -> ux_host_class_hub_transfer);
438
            hub -> ux_host_class_hub_run_status = hub -> ux_host_class_hub_transfer ->
439
                                            ux_transfer_request_completion_code;
440
441
            /* Transfer done - next state.  */
442
            if (status == UX_STATE_NEXT || status == UX_STATE_IDLE)
443
            {
444
                hub -> ux_host_class_hub_enum_state = hub -> ux_host_class_hub_next_state;
445
                continue;
446
            }
447
448
            /* Check error.  */
449
            if (status < UX_STATE_NEXT)
450
            {
451
452
                /* Fail.  */
453
                hub -> ux_host_class_hub_enum_state = UX_HOST_CLASS_HUB_ENUM_DONE;
454
                continue;
455
            }
456
457
            /* Transfer in progress, wait.  */
458
            return(UX_STATE_WAIT);
459
460
        case UX_HOST_CLASS_HUB_ENUM_DELAY_WAIT:
461
            current_ms = _ux_utility_time_get();
462
            elapsed_ms = _ux_utility_time_elapsed(current_ms,
463
                                        hub -> ux_host_class_hub_wait_start);
464
            if (elapsed_ms < hub -> ux_host_class_hub_wait_ms)
465
            {
466
467
                /* Keep waiting.  */
468
                return(UX_STATE_WAIT);
469
            }
470
471
            /* Next state.  */
472
            hub -> ux_host_class_hub_enum_state = hub -> ux_host_class_hub_next_state;
473
            continue;
474
475
        default:
476
            return(UX_STATE_NEXT);
477
        }
478
    }
479
}
480
#endif