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: 2024-12-12 17:16:36 Branches: 8 8 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
/**   HUB Class                                                           */
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_class_hub.h"
29
#include "ux_host_stack.h"
30
31
32
#if defined(UX_HOST_STANDALONE)
33
extern UINT _ux_host_class_hub_descriptor_parse(UX_HOST_CLASS_HUB *hub, UCHAR *descriptor);
34
static inline UINT _ux_host_class_hub_activate_wait(UX_HOST_CLASS_COMMAND *command);
35
#endif
36
37
38
/**************************************************************************/
39
/*                                                                        */
40
/*  FUNCTION                                               RELEASE        */
41
/*                                                                        */
42
/*    _ux_host_class_hub_entry                            PORTABLE C      */
43
/*                                                           6.3.0        */
44
/*  AUTHOR                                                                */
45
/*                                                                        */
46
/*    Chaoqiong Xiao, Microsoft Corporation                               */
47
/*                                                                        */
48
/*  DESCRIPTION                                                           */
49
/*                                                                        */
50
/*    This function is the entry point of the HUB class. It will be       */
51
/*    called by the USBX stack enumeration module when there is a new     */
52
/*    device on the bus or when there is a device extraction.             */
53
/*                                                                        */
54
/*  INPUT                                                                 */
55
/*                                                                        */
56
/*    command                               Pointer to command            */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    Completion Status                                                   */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _ux_host_class_hub_activate           Activate HUB class            */
65
/*    _ux_host_class_hub_deactivate         Deactivate HUB class          */
66
/*                                                                        */
67
/*  CALLED BY                                                             */
68
/*                                                                        */
69
/*    Host Stack                                                          */
70
/*                                                                        */
71
/*  RELEASE HISTORY                                                       */
72
/*                                                                        */
73
/*    DATE              NAME                      DESCRIPTION             */
74
/*                                                                        */
75
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
76
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
77
/*                                            used query usage of device  */
78
/*                                            ClassSubclassProtocol,      */
79
/*                                            resulting in version 6.1    */
80
/*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
81
/*                                            added standalone support,   */
82
/*                                            resulting in version 6.1.12 */
83
/*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
84
/*                                            fixed power on delay calc,  */
85
/*                                            resulting in version 6.2.0  */
86
/*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
87
/*                                            fixed fail code sequence,   */
88
/*                                            fixed compile warnings,     */
89
/*                                            resulting in version 6.3.0  */
90
/*                                                                        */
91
/**************************************************************************/
92
280
UINT  _ux_host_class_hub_entry(UX_HOST_CLASS_COMMAND *command)
93
{
94
95
UINT    status;
96
97
98
    /* The command request will tell us we need to do here, either a enumeration
99
       query, an activation or a deactivation.  */
100

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